1/**************************************************************************/
2/* render_scene_buffers_rd.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "render_scene_buffers_rd.h"
32#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
33#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
34#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
35
36RenderSceneBuffersRD::RenderSceneBuffersRD() {
37}
38
39RenderSceneBuffersRD::~RenderSceneBuffersRD() {
40 cleanup();
41
42 data_buffers.clear();
43}
44
45void RenderSceneBuffersRD::_bind_methods() {
46 ClassDB::bind_method(D_METHOD("has_texture", "context", "name"), &RenderSceneBuffersRD::has_texture);
47 ClassDB::bind_method(D_METHOD("create_texture", "context", "name", "data_format", "usage_bits", "texture_samples", "size", "layers", "mipmaps", "unique"), &RenderSceneBuffersRD::create_texture);
48 ClassDB::bind_method(D_METHOD("create_texture_from_format", "context", "name", "format", "view", "unique"), &RenderSceneBuffersRD::_create_texture_from_format);
49 ClassDB::bind_method(D_METHOD("create_texture_view", "context", "name", "view_name", "view"), &RenderSceneBuffersRD::_create_texture_view);
50 ClassDB::bind_method(D_METHOD("get_texture", "context", "name"), &RenderSceneBuffersRD::get_texture);
51 ClassDB::bind_method(D_METHOD("get_texture_format", "context", "name"), &RenderSceneBuffersRD::_get_texture_format);
52 ClassDB::bind_method(D_METHOD("get_texture_slice", "context", "name", "layer", "mipmap", "layers", "mipmaps"), &RenderSceneBuffersRD::get_texture_slice);
53 ClassDB::bind_method(D_METHOD("get_texture_slice_size", "context", "name", "mipmap"), &RenderSceneBuffersRD::get_texture_slice_size);
54 ClassDB::bind_method(D_METHOD("clear_context", "context"), &RenderSceneBuffersRD::clear_context);
55
56 // Access to some core buffers so users don't need to know their names.
57 ClassDB::bind_method(D_METHOD("get_color_texture"), &RenderSceneBuffersRD::_get_color_texture);
58 ClassDB::bind_method(D_METHOD("get_color_layer", "layer"), &RenderSceneBuffersRD::_get_color_layer);
59 ClassDB::bind_method(D_METHOD("get_depth_texture"), &RenderSceneBuffersRD::_get_depth_texture);
60 ClassDB::bind_method(D_METHOD("get_depth_layer", "layer"), &RenderSceneBuffersRD::_get_depth_layer);
61 ClassDB::bind_method(D_METHOD("get_velocity_texture"), &RenderSceneBuffersRD::_get_velocity_texture);
62 ClassDB::bind_method(D_METHOD("get_velocity_layer", "layer"), &RenderSceneBuffersRD::_get_velocity_layer);
63
64 // Expose a few properties we're likely to use externally
65 ClassDB::bind_method(D_METHOD("get_render_target"), &RenderSceneBuffersRD::get_render_target);
66 ClassDB::bind_method(D_METHOD("get_view_count"), &RenderSceneBuffersRD::get_view_count);
67 ClassDB::bind_method(D_METHOD("get_internal_size"), &RenderSceneBuffersRD::get_internal_size);
68 ClassDB::bind_method(D_METHOD("get_use_taa"), &RenderSceneBuffersRD::get_use_taa);
69}
70
71void RenderSceneBuffersRD::update_sizes(NamedTexture &p_named_texture) {
72 ERR_FAIL_COND(p_named_texture.texture.is_null());
73
74 p_named_texture.sizes.resize(p_named_texture.format.mipmaps);
75
76 Size2i mipmap_size = Size2i(p_named_texture.format.width, p_named_texture.format.height);
77 for (uint32_t mipmap = 0; mipmap < p_named_texture.format.mipmaps; mipmap++) {
78 p_named_texture.sizes.ptrw()[mipmap] = mipmap_size;
79
80 mipmap_size.width = MAX(1, mipmap_size.width >> 1);
81 mipmap_size.height = MAX(1, mipmap_size.height >> 1);
82 }
83}
84
85void RenderSceneBuffersRD::free_named_texture(NamedTexture &p_named_texture) {
86 if (p_named_texture.texture.is_valid()) {
87 RD::get_singleton()->free(p_named_texture.texture);
88 }
89 p_named_texture.texture = RID();
90 p_named_texture.slices.clear(); // slices should be freed automatically as dependents...
91}
92
93void RenderSceneBuffersRD::cleanup() {
94 // Free our data buffers (but don't destroy them)
95 for (KeyValue<StringName, Ref<RenderBufferCustomDataRD>> &E : data_buffers) {
96 E.value->free_data();
97 }
98
99 // Clear our named textures
100 for (KeyValue<NTKey, NamedTexture> &E : named_textures) {
101 free_named_texture(E.value);
102 }
103 named_textures.clear();
104}
105
106void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_config) {
107 RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
108 RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
109
110 render_target = p_config->get_render_target();
111 target_size = p_config->get_target_size();
112 internal_size = p_config->get_internal_size();
113 view_count = p_config->get_view_count();
114
115 scaling_3d_mode = p_config->get_scaling_3d_mode();
116 msaa_3d = p_config->get_msaa_3d();
117 screen_space_aa = p_config->get_screen_space_aa();
118
119 fsr_sharpness = p_config->get_fsr_sharpness();
120 texture_mipmap_bias = p_config->get_texture_mipmap_bias();
121 use_taa = p_config->get_use_taa();
122 use_debanding = p_config->get_use_debanding();
123
124 ERR_FAIL_COND_MSG(view_count == 0, "Must have at least 1 view");
125
126 if (use_taa) {
127 // Use negative mipmap LOD bias when TAA is enabled to compensate for loss of sharpness.
128 // This restores sharpness in still images to be roughly at the same level as without TAA,
129 // but moving scenes will still be blurrier.
130 texture_mipmap_bias -= 0.5;
131 }
132
133 if (screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) {
134 // Use negative mipmap LOD bias when FXAA is enabled to compensate for loss of sharpness.
135 // If both TAA and FXAA are enabled, combine their negative LOD biases together.
136 texture_mipmap_bias -= 0.25;
137 }
138
139 material_storage->sampler_rd_configure_custom(texture_mipmap_bias);
140
141 // need to check if we really need to do this here..
142 RendererSceneRenderRD::get_singleton()->update_uniform_sets();
143
144 // cleanout any old buffers we had.
145 cleanup();
146
147 // create our 3D render buffers
148 {
149 // Create our color buffer(s)
150 uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (can_be_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
151 usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT; // only needed when using subpasses in the mobile renderer
152
153 // our internal texture should have MSAA support if applicable
154 if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
155 usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
156 }
157
158 create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR, base_data_format, usage_bits);
159 }
160
161 // Create our depth buffer
162 {
163 // TODO Lazy create this in case we've got an external depth buffer
164
165 RD::DataFormat format;
166 uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
167
168 if (msaa_3d == RS::VIEWPORT_MSAA_DISABLED) {
169 usage_bits |= RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
170 format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, usage_bits) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
171 } else {
172 format = RD::DATA_FORMAT_R32_SFLOAT;
173 usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | (can_be_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
174 }
175
176 create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, format, usage_bits);
177 }
178
179 // Create our MSAA buffers
180 if (msaa_3d == RS::VIEWPORT_MSAA_DISABLED) {
181 texture_samples = RD::TEXTURE_SAMPLES_1;
182 } else {
183 RD::DataFormat format = base_data_format;
184 uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
185
186 const RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
187 RD::TEXTURE_SAMPLES_1,
188 RD::TEXTURE_SAMPLES_2,
189 RD::TEXTURE_SAMPLES_4,
190 RD::TEXTURE_SAMPLES_8,
191 };
192
193 texture_samples = ts[msaa_3d];
194
195 create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA, format, usage_bits, texture_samples);
196
197 usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
198 format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, usage_bits) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
199
200 create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples);
201 }
202
203 // VRS (note, our vrs object will only be set if VRS is supported)
204 RID vrs_texture;
205 RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(render_target);
206 if (vrs && vrs_mode != RS::VIEWPORT_VRS_DISABLED) {
207 uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
208 vrs_texture = create_texture(RB_SCOPE_VRS, RB_TEXTURE, RD::DATA_FORMAT_R8_UINT, usage_bits, RD::TEXTURE_SAMPLES_1, vrs->get_vrs_texture_size(internal_size));
209 }
210
211 // (re-)configure any named buffers
212 for (KeyValue<StringName, Ref<RenderBufferCustomDataRD>> &E : data_buffers) {
213 E.value->configure(this);
214 }
215}
216
217void RenderSceneBuffersRD::configure_for_reflections(const Size2i p_reflection_size) {
218 // For now our render buffers for reflections are only used for effects/environment (Sky/Fog/Etc)
219 // Possibly at some point move our entire reflection atlas buffer management into this class
220
221 target_size = p_reflection_size;
222 internal_size = p_reflection_size;
223 render_target = RID();
224 scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
225 fsr_sharpness = 0.0;
226 msaa_3d = RS::VIEWPORT_MSAA_DISABLED;
227 screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
228 use_taa = false;
229 use_debanding = false;
230 view_count = 1;
231
232 // cleanout any old buffers we had.
233 cleanup();
234
235 // (re-)configure any named buffers
236 for (KeyValue<StringName, Ref<RenderBufferCustomDataRD>> &E : data_buffers) {
237 E.value->configure(this);
238 }
239}
240
241void RenderSceneBuffersRD::set_fsr_sharpness(float p_fsr_sharpness) {
242 fsr_sharpness = p_fsr_sharpness;
243}
244
245void RenderSceneBuffersRD::set_texture_mipmap_bias(float p_texture_mipmap_bias) {
246 RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
247 material_storage->sampler_rd_configure_custom(p_texture_mipmap_bias);
248}
249
250void RenderSceneBuffersRD::set_use_debanding(bool p_use_debanding) {
251 use_debanding = p_use_debanding;
252}
253
254// Named textures
255
256bool RenderSceneBuffersRD::has_texture(const StringName &p_context, const StringName &p_texture_name) const {
257 NTKey key(p_context, p_texture_name);
258
259 return named_textures.has(key);
260}
261
262RID RenderSceneBuffersRD::create_texture(const StringName &p_context, const StringName &p_texture_name, const RD::DataFormat p_data_format, const uint32_t p_usage_bits, const RD::TextureSamples p_texture_samples, const Size2i p_size, const uint32_t p_layers, const uint32_t p_mipmaps, bool p_unique) {
263 // Keep some useful data, we use default values when these are 0.
264 Size2i size = p_size == Size2i(0, 0) ? internal_size : p_size;
265 uint32_t layers = p_layers == 0 ? view_count : p_layers;
266 uint32_t mipmaps = p_mipmaps == 0 ? 1 : p_mipmaps;
267
268 // Create our texture
269 RD::TextureFormat tf;
270 tf.format = p_data_format;
271 if (layers > 1) {
272 tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
273 }
274
275 tf.width = size.x;
276 tf.height = size.y;
277 tf.depth = 1;
278 tf.array_layers = layers;
279 tf.mipmaps = mipmaps;
280 tf.usage_bits = p_usage_bits;
281 tf.samples = p_texture_samples;
282
283 return create_texture_from_format(p_context, p_texture_name, tf, RD::TextureView(), p_unique);
284}
285
286RID RenderSceneBuffersRD::_create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const Ref<RDTextureFormat> &p_texture_format, const Ref<RDTextureView> &p_view, bool p_unique) {
287 ERR_FAIL_COND_V(p_texture_format.is_null(), RID());
288
289 RD::TextureView texture_view;
290 if (p_view.is_valid()) { // only use when supplied, else default.
291 texture_view = p_view->base;
292 }
293
294 return create_texture_from_format(p_context, p_texture_name, p_texture_format->base, texture_view, p_unique);
295}
296
297RID RenderSceneBuffersRD::create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const RD::TextureFormat &p_texture_format, RD::TextureView p_view, bool p_unique) {
298 // TODO p_unique, if p_unique is true, this is a texture that can be shared. This will be implemented later as an optimization.
299
300 NTKey key(p_context, p_texture_name);
301
302 // check if this is a known texture
303 if (named_textures.has(key)) {
304 return named_textures[key].texture;
305 }
306
307 // Add a new entry..
308 NamedTexture &named_texture = named_textures[key];
309 named_texture.format = p_texture_format;
310 named_texture.is_unique = p_unique;
311 named_texture.texture = RD::get_singleton()->texture_create(p_texture_format, p_view);
312
313 Array arr;
314 arr.push_back(p_context);
315 arr.push_back(p_texture_name);
316 RD::get_singleton()->set_resource_name(named_texture.texture, String("RenderBuffer {0}/{1}").format(arr));
317
318 update_sizes(named_texture);
319
320 // The rest is lazy created..
321
322 return named_texture.texture;
323}
324
325RID RenderSceneBuffersRD::_create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, const Ref<RDTextureView> p_view) {
326 RD::TextureView texture_view;
327 if (p_view.is_valid()) { // only use when supplied, else default.
328 texture_view = p_view->base;
329 }
330
331 return create_texture_view(p_context, p_texture_name, p_view_name, texture_view);
332}
333
334RID RenderSceneBuffersRD::create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, RD::TextureView p_view) {
335 NTKey view_key(p_context, p_view_name);
336
337 // check if this is a known texture
338 if (named_textures.has(view_key)) {
339 return named_textures[view_key].texture;
340 }
341
342 NTKey key(p_context, p_texture_name);
343
344 ERR_FAIL_COND_V(!named_textures.has(key), RID());
345
346 NamedTexture &named_texture = named_textures[key];
347 NamedTexture &view_texture = named_textures[view_key];
348
349 view_texture.format = named_texture.format;
350 view_texture.is_unique = named_texture.is_unique;
351
352 view_texture.texture = RD::get_singleton()->texture_create_shared(p_view, named_texture.texture);
353
354 Array arr;
355 arr.push_back(p_context);
356 arr.push_back(p_view_name);
357 RD::get_singleton()->set_resource_name(view_texture.texture, String("RenderBuffer View {0}/{1}").format(arr));
358
359 update_sizes(named_texture);
360
361 return view_texture.texture;
362}
363
364RID RenderSceneBuffersRD::get_texture(const StringName &p_context, const StringName &p_texture_name) const {
365 NTKey key(p_context, p_texture_name);
366
367 ERR_FAIL_COND_V(!named_textures.has(key), RID());
368
369 return named_textures[key].texture;
370}
371
372Ref<RDTextureFormat> RenderSceneBuffersRD::_get_texture_format(const StringName &p_context, const StringName &p_texture_name) const {
373 Ref<RDTextureFormat> tf;
374 tf.instantiate();
375
376 tf->base = get_texture_format(p_context, p_texture_name);
377
378 return tf;
379}
380
381const RD::TextureFormat RenderSceneBuffersRD::get_texture_format(const StringName &p_context, const StringName &p_texture_name) const {
382 NTKey key(p_context, p_texture_name);
383
384 ERR_FAIL_COND_V(!named_textures.has(key), RD::TextureFormat());
385
386 return named_textures[key].format;
387}
388
389RID RenderSceneBuffersRD::get_texture_slice(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap, const uint32_t p_layers, const uint32_t p_mipmaps) {
390 NTKey key(p_context, p_texture_name);
391
392 // check if this is a known texture
393 ERR_FAIL_COND_V(!named_textures.has(key), RID());
394 NamedTexture &named_texture = named_textures[key];
395 ERR_FAIL_COND_V(named_texture.texture.is_null(), RID());
396
397 // check if we're in bounds
398 ERR_FAIL_UNSIGNED_INDEX_V(p_layer, named_texture.format.array_layers, RID());
399 ERR_FAIL_COND_V(p_layers == 0, RID());
400 ERR_FAIL_COND_V(p_layer + p_layers > named_texture.format.array_layers, RID());
401 ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, named_texture.format.mipmaps, RID());
402 ERR_FAIL_COND_V(p_mipmaps == 0, RID());
403 ERR_FAIL_COND_V(p_mipmap + p_mipmaps > named_texture.format.mipmaps, RID());
404
405 // asking the whole thing? just return the original
406 if (p_layer == 0 && p_mipmap == 0 && named_texture.format.array_layers == p_layers && named_texture.format.mipmaps == p_mipmaps) {
407 return named_texture.texture;
408 }
409
410 // see if we have this
411 NTSliceKey slice_key(p_layer, p_layers, p_mipmap, p_mipmaps);
412 if (named_texture.slices.has(slice_key)) {
413 return named_texture.slices[slice_key];
414 }
415
416 // create our slice
417 RID &slice = named_texture.slices[slice_key];
418 slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), named_texture.texture, p_layer, p_mipmap, p_mipmaps, p_layers > 1 ? RD::TEXTURE_SLICE_2D_ARRAY : RD::TEXTURE_SLICE_2D, p_layers);
419
420 Array arr;
421 arr.push_back(p_context);
422 arr.push_back(p_texture_name);
423 arr.push_back(itos(p_layer));
424 arr.push_back(itos(p_layers));
425 arr.push_back(itos(p_mipmap));
426 arr.push_back(itos(p_mipmaps));
427 RD::get_singleton()->set_resource_name(slice, String("RenderBuffer {0}/{1}, layer {2}/{3}, mipmap {4}/{5}").format(arr));
428
429 // and return our slice
430 return slice;
431}
432
433Size2i RenderSceneBuffersRD::get_texture_slice_size(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_mipmap) {
434 NTKey key(p_context, p_texture_name);
435
436 // check if this is a known texture
437 ERR_FAIL_COND_V(!named_textures.has(key), Size2i());
438 NamedTexture &named_texture = named_textures[key];
439 ERR_FAIL_COND_V(named_texture.texture.is_null(), Size2i());
440
441 // check if we're in bounds
442 ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, named_texture.format.mipmaps, Size2i());
443
444 // return our size
445 return named_texture.sizes[p_mipmap];
446}
447
448void RenderSceneBuffersRD::clear_context(const StringName &p_context) {
449 Vector<NTKey> to_free; // free these
450
451 // Find all entries for our context, we don't want to free them yet or our loop fails.
452 for (KeyValue<NTKey, NamedTexture> &E : named_textures) {
453 if (E.key.context == p_context) {
454 to_free.push_back(E.key);
455 }
456 }
457
458 // Now free these and remove them from our textures
459 for (NTKey &key : to_free) {
460 free_named_texture(named_textures[key]);
461 named_textures.erase(key);
462 }
463}
464
465// Allocate shared buffers
466void RenderSceneBuffersRD::allocate_blur_textures() {
467 if (has_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0)) {
468 // already allocated...
469 return;
470 }
471
472 uint32_t mipmaps_required = Image::get_image_required_mipmaps(internal_size.x, internal_size.y, Image::FORMAT_RGBAH);
473
474 uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
475 if (can_be_storage) {
476 usage_bits += RD::TEXTURE_USAGE_STORAGE_BIT;
477 } else {
478 usage_bits += RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
479 }
480
481 create_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, internal_size, view_count, mipmaps_required);
482 create_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, Size2i(internal_size.x >> 1, internal_size.y >> 1), view_count, mipmaps_required - 1);
483
484 // if !can_be_storage we need a half width version
485 if (!can_be_storage) {
486 create_texture(RB_SCOPE_BUFFERS, RB_TEX_HALF_BLUR, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, Size2i(internal_size.x >> 1, internal_size.y), 1, mipmaps_required);
487 }
488
489 // TODO redo this:
490 if (!can_be_storage) {
491 // create 4 weight textures, 2 full size, 2 half size
492
493 RD::TextureFormat tf;
494 tf.format = RD::DATA_FORMAT_R16_SFLOAT; // We could probably use DATA_FORMAT_R8_SNORM if we don't pre-multiply by blur_size but that depends on whether we can remove DEPTH_GAP
495 tf.width = internal_size.x;
496 tf.height = internal_size.y;
497 tf.texture_type = RD::TEXTURE_TYPE_2D;
498 tf.array_layers = 1; // Our DOF effect handles one eye per turn
499 tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
500 tf.mipmaps = 1;
501 for (uint32_t i = 0; i < 4; i++) {
502 // associated blur texture
503 RID texture;
504 if (i == 1) {
505 texture = get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, 0, 0);
506 } else if (i == 2) {
507 texture = get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, 0, 0);
508 } else if (i == 3) {
509 texture = get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, 0, 1);
510 }
511
512 // create weight texture
513 weight_buffers[i].weight = RD::get_singleton()->texture_create(tf, RD::TextureView());
514
515 // create frame buffer
516 Vector<RID> fb;
517 if (i != 0) {
518 fb.push_back(texture);
519 }
520 fb.push_back(weight_buffers[i].weight);
521 weight_buffers[i].fb = RD::get_singleton()->framebuffer_create(fb);
522
523 if (i == 1) {
524 // next 2 are half size
525 tf.width = MAX(1u, tf.width >> 1);
526 tf.height = MAX(1u, tf.height >> 1);
527 }
528 }
529 }
530}
531
532// Data buffers
533
534bool RenderSceneBuffersRD::has_custom_data(const StringName &p_name) {
535 return data_buffers.has(p_name);
536}
537
538void RenderSceneBuffersRD::set_custom_data(const StringName &p_name, Ref<RenderBufferCustomDataRD> p_data) {
539 if (p_data.is_valid()) {
540 data_buffers[p_name] = p_data;
541 } else if (has_custom_data(p_name)) {
542 data_buffers.erase(p_name);
543 }
544}
545
546Ref<RenderBufferCustomDataRD> RenderSceneBuffersRD::get_custom_data(const StringName &p_name) const {
547 ERR_FAIL_COND_V(!data_buffers.has(p_name), Ref<RenderBufferCustomDataRD>());
548
549 Ref<RenderBufferCustomDataRD> ret = data_buffers[p_name];
550
551 return ret;
552}
553
554// Depth texture
555
556bool RenderSceneBuffersRD::has_depth_texture() {
557 if (render_target.is_null()) {
558 // not applicable when there is no render target (likely this is for a reflection probe)
559 return false;
560 }
561
562 RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
563 RID depth = texture_storage->render_target_get_override_depth(render_target);
564 if (depth.is_valid()) {
565 return true;
566 } else {
567 return has_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH);
568 }
569}
570
571RID RenderSceneBuffersRD::get_depth_texture() {
572 if (render_target.is_null()) {
573 // not applicable when there is no render target (likely this is for a reflection probe)
574 return RID();
575 }
576
577 RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
578 RID depth = texture_storage->render_target_get_override_depth(render_target);
579 if (depth.is_valid()) {
580 return depth;
581 } else {
582 return get_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH);
583 }
584}
585
586RID RenderSceneBuffersRD::get_depth_texture(const uint32_t p_layer) {
587 RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
588 RID depth_slice = texture_storage->render_target_get_override_depth_slice(render_target, p_layer);
589 if (depth_slice.is_valid()) {
590 return depth_slice;
591 } else {
592 return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, p_layer, 0);
593 }
594}
595
596// Velocity texture.
597
598void RenderSceneBuffersRD::ensure_velocity() {
599 if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY)) {
600 uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
601
602 if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
603 uint32_t msaa_usage_bits = usage_bits | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
604 usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
605
606 create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA, RD::DATA_FORMAT_R16G16_SFLOAT, msaa_usage_bits, texture_samples);
607 }
608
609 create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY, RD::DATA_FORMAT_R16G16_SFLOAT, usage_bits);
610 }
611}
612
613bool RenderSceneBuffersRD::has_velocity_buffer(bool p_has_msaa) {
614 if (p_has_msaa) {
615 return has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA);
616 } else {
617 RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
618 RID velocity = texture_storage->render_target_get_override_velocity(render_target);
619 if (velocity.is_valid()) {
620 return true;
621 } else {
622 return has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY);
623 }
624 }
625}
626
627RID RenderSceneBuffersRD::get_velocity_buffer(bool p_get_msaa) {
628 if (p_get_msaa) {
629 if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA)) {
630 return RID();
631 } else {
632 return get_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA);
633 }
634 } else {
635 RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
636 RID velocity = texture_storage->render_target_get_override_velocity(render_target);
637 if (velocity.is_valid()) {
638 return velocity;
639 } else if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY)) {
640 return RID();
641 } else {
642 return get_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY);
643 }
644 }
645}
646
647RID RenderSceneBuffersRD::get_velocity_buffer(bool p_get_msaa, uint32_t p_layer) {
648 if (p_get_msaa) {
649 return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA, p_layer, 0);
650 } else {
651 RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
652 RID velocity_slice = texture_storage->render_target_get_override_velocity_slice(render_target, p_layer);
653 if (velocity_slice.is_valid()) {
654 return velocity_slice;
655 } else {
656 return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY, p_layer, 0);
657 }
658 }
659}
660