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 | |
36 | RenderSceneBuffersRD::RenderSceneBuffersRD() { |
37 | } |
38 | |
39 | RenderSceneBuffersRD::~RenderSceneBuffersRD() { |
40 | cleanup(); |
41 | |
42 | data_buffers.clear(); |
43 | } |
44 | |
45 | void 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 | |
71 | void 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 | |
85 | void 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 | |
93 | void 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 | |
106 | void 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 | |
217 | void 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 | |
241 | void RenderSceneBuffersRD::set_fsr_sharpness(float p_fsr_sharpness) { |
242 | fsr_sharpness = p_fsr_sharpness; |
243 | } |
244 | |
245 | void 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 | |
250 | void RenderSceneBuffersRD::set_use_debanding(bool p_use_debanding) { |
251 | use_debanding = p_use_debanding; |
252 | } |
253 | |
254 | // Named textures |
255 | |
256 | bool 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 | |
262 | RID 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 | |
286 | RID 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 | |
297 | RID 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 | |
325 | RID 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 | |
334 | RID 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 | |
364 | RID 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 | |
372 | Ref<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 | |
381 | const 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 | |
389 | RID 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 | |
433 | Size2i 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 | |
448 | void 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 |
466 | void 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 | |
534 | bool RenderSceneBuffersRD::has_custom_data(const StringName &p_name) { |
535 | return data_buffers.has(p_name); |
536 | } |
537 | |
538 | void 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 | |
546 | Ref<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 | |
556 | bool 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 | |
571 | RID 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 | |
586 | RID 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 | |
598 | void 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 | |
613 | bool 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 | |
627 | RID 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 | |
647 | RID 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 | |