1/**************************************************************************/
2/* render_forward_mobile.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_forward_mobile.h"
32#include "core/config/project_settings.h"
33#include "core/object/worker_thread_pool.h"
34#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
35#include "servers/rendering/renderer_rd/storage_rd/mesh_storage.h"
36#include "servers/rendering/renderer_rd/storage_rd/particles_storage.h"
37#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
38#include "servers/rendering/rendering_device.h"
39#include "servers/rendering/rendering_server_default.h"
40
41using namespace RendererSceneRenderImplementation;
42
43RendererRD::ForwardID RenderForwardMobile::ForwardIDStorageMobile::allocate_forward_id(RendererRD::ForwardIDType p_type) {
44 int32_t index = -1;
45 for (uint32_t i = 0; i < forward_id_allocators[p_type].allocations.size(); i++) {
46 if (forward_id_allocators[p_type].allocations[i] == false) {
47 index = i;
48 break;
49 }
50 }
51
52 if (index == -1) {
53 index = forward_id_allocators[p_type].allocations.size();
54 forward_id_allocators[p_type].allocations.push_back(true);
55 forward_id_allocators[p_type].map.push_back(0xFF);
56 } else {
57 forward_id_allocators[p_type].allocations[index] = true;
58 }
59
60 return index;
61}
62void RenderForwardMobile::ForwardIDStorageMobile::free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) {
63 ERR_FAIL_INDEX(p_id, (RendererRD::ForwardID)forward_id_allocators[p_type].allocations.size());
64 forward_id_allocators[p_type].allocations[p_id] = false;
65}
66
67void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) {
68 forward_id_allocators[p_type].map[p_id] = p_index;
69}
70
71void RenderForwardMobile::ForwardIDStorageMobile::fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) {
72 // first zero out our indices
73
74 p_push_constant->omni_lights[0] = 0xFFFFFFFF;
75 p_push_constant->omni_lights[1] = 0xFFFFFFFF;
76
77 p_push_constant->spot_lights[0] = 0xFFFFFFFF;
78 p_push_constant->spot_lights[1] = 0xFFFFFFFF;
79
80 p_push_constant->decals[0] = 0xFFFFFFFF;
81 p_push_constant->decals[1] = 0xFFFFFFFF;
82
83 p_push_constant->reflection_probes[0] = 0xFFFFFFFF;
84 p_push_constant->reflection_probes[1] = 0xFFFFFFFF;
85
86 if (p_instance->omni_light_count == 0) {
87 spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
88 }
89 if (p_instance->spot_light_count == 0) {
90 spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
91 }
92 if (p_instance->reflection_probe_count == 0) {
93 spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
94 }
95 if (p_instance->decals_count == 0) {
96 spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
97 }
98
99 for (uint32_t i = 0; i < MAX_RDL_CULL; i++) {
100 uint32_t ofs = i < 4 ? 0 : 1;
101 uint32_t shift = (i & 0x3) << 3;
102 uint32_t mask = ~(0xFF << shift);
103 if (i < p_instance->omni_light_count) {
104 p_push_constant->omni_lights[ofs] &= mask;
105 p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift;
106 }
107 if (i < p_instance->spot_light_count) {
108 p_push_constant->spot_lights[ofs] &= mask;
109 p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift;
110 }
111 if (i < p_instance->decals_count) {
112 p_push_constant->decals[ofs] &= mask;
113 p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift;
114 }
115 if (i < p_instance->reflection_probe_count) {
116 p_push_constant->reflection_probes[ofs] &= mask;
117 p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift;
118 }
119 }
120}
121
122/* Render buffer */
123
124void RenderForwardMobile::RenderBufferDataForwardMobile::free_data() {
125 // this should already be done but JIC..
126 if (render_buffers) {
127 render_buffers->clear_context(RB_SCOPE_MOBILE);
128 }
129}
130
131void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RenderSceneBuffersRD *p_render_buffers) {
132 if (render_buffers) {
133 // JIC
134 free_data();
135 }
136
137 render_buffers = p_render_buffers;
138 ERR_FAIL_NULL(render_buffers); // Huh? really?
139}
140
141RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(FramebufferConfigType p_config_type) {
142 ERR_FAIL_NULL_V(render_buffers, RID());
143
144 RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
145 ERR_FAIL_NULL_V(texture_storage, RID());
146
147 // We use our framebuffer cache here instead of building these in RenderBufferDataForwardMobile::configure
148 // This approach ensures we only build the framebuffers we actually need for this viewport.
149 // In the (near) future this means that if we cycle through a texture chain for our render target, we'll also support
150 // this.
151
152 RS::ViewportMSAA msaa_3d = render_buffers->get_msaa_3d();
153 bool use_msaa = msaa_3d != RS::VIEWPORT_MSAA_DISABLED;
154
155 uint32_t view_count = render_buffers->get_view_count();
156
157 RID vrs_texture;
158 if (render_buffers->has_texture(RB_SCOPE_VRS, RB_TEXTURE)) {
159 vrs_texture = render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
160 }
161
162 Vector<RID> textures;
163 int color_buffer_id = 0;
164 textures.push_back(use_msaa ? render_buffers->get_color_msaa() : render_buffers->get_internal_texture()); // 0 - color buffer
165 textures.push_back(use_msaa ? render_buffers->get_depth_msaa() : render_buffers->get_depth_texture()); // 1 - depth buffer
166 if (vrs_texture.is_valid()) {
167 textures.push_back(vrs_texture); // 2 - vrs texture
168 }
169 if (use_msaa) {
170 color_buffer_id = textures.size();
171 textures.push_back(render_buffers->get_internal_texture()); // color buffer for resolve
172
173 // TODO add support for resolving depth buffer!!!
174 }
175
176 // Now define our subpasses
177 Vector<RD::FramebufferPass> passes;
178
179 // Define our base pass, we'll be re-using this
180 RD::FramebufferPass pass;
181 pass.color_attachments.push_back(0);
182 pass.depth_attachment = 1;
183 if (vrs_texture.is_valid()) {
184 pass.vrs_attachment = 2;
185 }
186
187 switch (p_config_type) {
188 case FB_CONFIG_ONE_PASS: {
189 // just one pass
190 if (use_msaa) {
191 // Add resolve
192 pass.resolve_attachments.push_back(color_buffer_id);
193 }
194 passes.push_back(pass);
195
196 return FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, view_count);
197 } break;
198 case FB_CONFIG_TWO_SUBPASSES: {
199 // - opaque pass
200 passes.push_back(pass);
201
202 // - add sky pass
203 if (use_msaa) {
204 // add resolve
205 pass.resolve_attachments.push_back(color_buffer_id);
206 }
207 passes.push_back(pass);
208
209 return FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, view_count);
210 } break;
211 case FB_CONFIG_THREE_SUBPASSES: {
212 // - opaque pass
213 passes.push_back(pass);
214
215 // - add sky pass
216 passes.push_back(pass);
217
218 // - add alpha pass
219 if (use_msaa) {
220 // add resolve
221 pass.resolve_attachments.push_back(color_buffer_id);
222 }
223 passes.push_back(pass);
224
225 return FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, view_count);
226 } break;
227 case FB_CONFIG_FOUR_SUBPASSES: {
228 Size2i target_size = render_buffers->get_target_size();
229 Size2i internal_size = render_buffers->get_internal_size();
230
231 // can't do our blit pass if resolutions don't match, this should already have been checked.
232 ERR_FAIL_COND_V(target_size != internal_size, RID());
233
234 // - opaque pass
235 passes.push_back(pass);
236
237 // - add sky pass
238 passes.push_back(pass);
239
240 // - add alpha pass
241 if (use_msaa) {
242 // add resolve
243 pass.resolve_attachments.push_back(color_buffer_id);
244 }
245 passes.push_back(pass);
246
247 // - add blit to 2D pass
248 RID render_target = render_buffers->get_render_target();
249 ERR_FAIL_COND_V(render_target.is_null(), RID());
250 RID target_buffer;
251 if (texture_storage->render_target_get_msaa(render_target) == RS::VIEWPORT_MSAA_DISABLED) {
252 target_buffer = texture_storage->render_target_get_rd_texture(render_target);
253 } else {
254 target_buffer = texture_storage->render_target_get_rd_texture_msaa(render_target);
255 }
256 ERR_FAIL_COND_V(target_buffer.is_null(), RID());
257
258 int target_buffer_id = textures.size();
259 textures.push_back(target_buffer); // target buffer
260
261 RD::FramebufferPass blit_pass;
262 blit_pass.input_attachments.push_back(color_buffer_id); // Read from our (resolved) color buffer
263 blit_pass.color_attachments.push_back(target_buffer_id); // Write into our target buffer
264 // this doesn't need VRS
265 passes.push_back(blit_pass);
266
267 return FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, view_count);
268 } break;
269 default:
270 break;
271 };
272
273 return RID();
274}
275
276RID RenderForwardMobile::reflection_probe_create_framebuffer(RID p_color, RID p_depth) {
277 // Our attachments
278 Vector<RID> fb;
279 fb.push_back(p_color); // 0
280 fb.push_back(p_depth); // 1
281
282 // Now define our subpasses
283 Vector<RD::FramebufferPass> passes;
284 RD::FramebufferPass pass;
285
286 // re-using the same attachments
287 pass.color_attachments.push_back(0);
288 pass.depth_attachment = 1;
289
290 // - opaque pass
291 passes.push_back(pass);
292
293 // - sky pass
294 passes.push_back(pass);
295
296 // - alpha pass
297 passes.push_back(pass);
298
299 return RD::get_singleton()->framebuffer_create_multipass(fb, passes);
300}
301
302void RenderForwardMobile::setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) {
303 Ref<RenderBufferDataForwardMobile> data;
304 data.instantiate();
305
306 p_render_buffers->set_custom_data(RB_SCOPE_MOBILE, data);
307}
308
309bool RenderForwardMobile::free(RID p_rid) {
310 if (RendererSceneRenderRD::free(p_rid)) {
311 return true;
312 }
313 return false;
314}
315
316/* Render functions */
317
318float RenderForwardMobile::_render_buffers_get_luminance_multiplier() {
319 // On mobile renderer we need to multiply source colors by 2 due to using a UNORM buffer
320 // and multiplying by the output color during 3D rendering by 0.5
321 return 2.0;
322}
323
324RD::DataFormat RenderForwardMobile::_render_buffers_get_color_format() {
325 // Using 32bit buffers enables AFBC on mobile devices which should have a definite performance improvement (MALI G710 and newer support this on 64bit RTs)
326 return RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
327}
328
329bool RenderForwardMobile::_render_buffers_can_be_storage() {
330 // Using 32bit buffers enables AFBC on mobile devices which should have a definite performance improvement (MALI G710 and newer support this on 64bit RTs)
331 // Doesn't support storage
332 return false;
333}
334
335RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) {
336 RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
337 RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
338
339 //there should always be enough uniform buffers for render passes, otherwise bugs
340 ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID());
341
342 bool is_multiview = false;
343
344 Ref<RenderBufferDataForwardMobile> rb_data;
345 Ref<RenderSceneBuffersRD> rb;
346 if (p_render_data && p_render_data->render_buffers.is_valid()) {
347 rb = p_render_data->render_buffers;
348 is_multiview = rb->get_view_count() > 1;
349 if (rb->has_custom_data(RB_SCOPE_MOBILE)) {
350 // Our forward mobile custom data buffer will only be available when we're rendering our normal view.
351 // This will not be available when rendering reflection probes.
352 rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
353 }
354 }
355
356 // default render buffer and scene state uniform set
357 // loaded into set 1
358
359 Vector<RD::Uniform> uniforms;
360
361 {
362 RD::Uniform u;
363 u.binding = 0;
364 u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
365 u.append_id(scene_state.uniform_buffers[p_index]);
366 uniforms.push_back(u);
367 }
368
369 {
370 RID radiance_texture;
371 if (p_radiance_texture.is_valid()) {
372 radiance_texture = p_radiance_texture;
373 } else {
374 radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
375 }
376 RD::Uniform u;
377 u.binding = 2;
378 u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
379 u.append_id(radiance_texture);
380 uniforms.push_back(u);
381 }
382
383 {
384 RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? light_storage->reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
385 RD::Uniform u;
386 u.binding = 3;
387 u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
388 if (ref_texture.is_valid()) {
389 u.append_id(ref_texture);
390 } else {
391 u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK));
392 }
393 uniforms.push_back(u);
394 }
395
396 {
397 RD::Uniform u;
398 u.binding = 4;
399 u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
400 RID texture;
401 if (p_render_data && p_render_data->shadow_atlas.is_valid()) {
402 texture = light_storage->shadow_atlas_get_texture(p_render_data->shadow_atlas);
403 }
404 if (!texture.is_valid()) {
405 texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
406 }
407 u.append_id(texture);
408 uniforms.push_back(u);
409 }
410 {
411 RD::Uniform u;
412 u.binding = 5;
413 u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
414 if (p_use_directional_shadow_atlas && light_storage->directional_shadow_get_texture().is_valid()) {
415 u.append_id(light_storage->directional_shadow_get_texture());
416 } else {
417 u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH));
418 }
419 uniforms.push_back(u);
420 }
421
422 /* we have limited ability to keep textures like this so we're moving this to a set we change before drawing geometry and just pushing the needed texture in */
423 {
424 RD::Uniform u;
425 u.binding = 6;
426 u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
427
428 RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
429 for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
430 if (p_render_data && i < p_render_data->lightmaps->size()) {
431 RID base = light_storage->lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
432 RID texture = light_storage->lightmap_get_texture(base);
433 RID rd_texture = texture_storage->texture_get_rd_texture(texture);
434 u.append_id(rd_texture);
435 } else {
436 u.append_id(default_tex);
437 }
438 }
439
440 uniforms.push_back(u);
441 }
442
443 /*
444 {
445 RD::Uniform u;
446 u.binding = 7;
447 u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
448 u.ids.resize(MAX_VOXEL_GI_INSTANCESS);
449 RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
450 for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
451 if (i < (int)p_voxel_gi_instances.size()) {
452 RID tex = gi.voxel_gi_instance_get_texture(p_voxel_gi_instances[i]);
453 if (!tex.is_valid()) {
454 tex = default_tex;
455 }
456 u.ids.write[i] = tex;
457 } else {
458 u.ids.write[i] = default_tex;
459 }
460 }
461
462 uniforms.push_back(u);
463 }
464
465 {
466 RD::Uniform u;
467 u.binding = 8;
468 u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
469 RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer;
470 u.append_id(cb);
471 uniforms.push_back(u);
472 }
473 */
474
475 {
476 RD::Uniform u;
477 u.binding = 9;
478 u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
479 RID texture;
480 if (rb.is_valid() && rb->has_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH)) {
481 texture = rb->get_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH);
482 } else if (is_multiview) {
483 texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_DEPTH);
484 } else {
485 texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
486 }
487 u.append_id(texture);
488 uniforms.push_back(u);
489 }
490 {
491 RD::Uniform u;
492 u.binding = 10;
493 u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
494 RID texture = rb_data.is_valid() ? rb->get_back_buffer_texture() : RID();
495 if (texture.is_null()) {
496 if (is_multiview) {
497 texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_DEPTH);
498 } else {
499 texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
500 }
501 }
502 u.append_id(texture);
503 uniforms.push_back(u);
504 }
505
506 if (p_index >= (int)render_pass_uniform_sets.size()) {
507 render_pass_uniform_sets.resize(p_index + 1);
508 }
509
510 if (render_pass_uniform_sets[p_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[p_index])) {
511 RD::get_singleton()->free(render_pass_uniform_sets[p_index]);
512 }
513
514 render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET);
515 return render_pass_uniform_sets[p_index];
516}
517
518void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
519 RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
520
521 // This probably needs to change...
522 scene_state.lightmaps_used = 0;
523 for (int i = 0; i < (int)p_lightmaps.size(); i++) {
524 if (i >= (int)scene_state.max_lightmaps) {
525 break;
526 }
527
528 RID lightmap = light_storage->lightmap_instance_get_lightmap(p_lightmaps[i]);
529
530 Basis to_lm = light_storage->lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
531 to_lm = to_lm.inverse().transposed(); //will transform normals
532 RendererRD::MaterialStorage::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
533 scene_state.lightmaps[i].exposure_normalization = 1.0;
534 if (p_render_data->camera_attributes.is_valid()) {
535 float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap);
536 float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
537 scene_state.lightmaps[i].exposure_normalization = enf / baked_exposure;
538 }
539
540 scene_state.lightmap_ids[i] = p_lightmaps[i];
541 scene_state.lightmap_has_sh[i] = light_storage->lightmap_uses_spherical_harmonics(lightmap);
542
543 scene_state.lightmaps_used++;
544 }
545 if (scene_state.lightmaps_used > 0) {
546 RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, RD::BARRIER_MASK_RASTER);
547 }
548}
549
550void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) {
551 RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
552 RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
553
554 p_render_data->cube_shadows.clear();
555 p_render_data->shadows.clear();
556 p_render_data->directional_shadows.clear();
557
558 Plane camera_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin);
559 float lod_distance_multiplier = p_render_data->scene_data->cam_projection.get_lod_multiplier();
560 {
561 for (int i = 0; i < p_render_data->render_shadow_count; i++) {
562 RID li = p_render_data->render_shadows[i].light;
563 RID base = light_storage->light_instance_get_base_light(li);
564
565 if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) {
566 p_render_data->directional_shadows.push_back(i);
567 } else if (light_storage->light_get_type(base) == RS::LIGHT_OMNI && light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) {
568 p_render_data->cube_shadows.push_back(i);
569 } else {
570 p_render_data->shadows.push_back(i);
571 }
572 }
573
574 //cube shadows are rendered in their own way
575 for (const int &index : p_render_data->cube_shadows) {
576 _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info);
577 }
578
579 if (p_render_data->directional_shadows.size()) {
580 //open the pass for directional shadows
581 light_storage->update_directional_shadow_atlas();
582 RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE);
583 RD::get_singleton()->draw_list_end();
584 }
585 }
586
587 bool render_shadows = p_render_data->directional_shadows.size() || p_render_data->shadows.size();
588
589 //prepare shadow rendering
590 if (render_shadows) {
591 RENDER_TIMESTAMP("Render Shadows");
592
593 _render_shadow_begin();
594
595 //render directional shadows
596 for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) {
597 _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info);
598 }
599 //render positional shadows
600 for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) {
601 _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info);
602 }
603
604 _render_shadow_process();
605
606 _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER);
607 }
608
609 //full barrier here, we need raster, transfer and compute and it depends from the previous work
610 RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL_BARRIERS, RD::BARRIER_MASK_ALL_BARRIERS);
611
612 bool using_shadows = true;
613
614 if (p_render_data->reflection_probe.is_valid()) {
615 if (!RSG::light_storage->reflection_probe_renders_shadows(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
616 using_shadows = false;
617 }
618 } else {
619 //do not render reflections when rendering a reflection probe
620 light_storage->update_reflection_probe_buffer(p_render_data, *p_render_data->reflection_probes, p_render_data->scene_data->cam_transform.affine_inverse(), p_render_data->environment);
621 }
622
623 uint32_t directional_light_count = 0;
624 uint32_t positional_light_count = 0;
625 light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
626 texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform);
627
628 p_render_data->directional_light_count = directional_light_count;
629}
630
631void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) {
632 RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
633
634 ERR_FAIL_NULL(p_render_data);
635
636 Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
637 ERR_FAIL_COND(rb.is_null());
638
639 Ref<RenderBufferDataForwardMobile> rb_data;
640 if (rb->has_custom_data(RB_SCOPE_MOBILE)) {
641 // Our forward mobile custom data buffer will only be available when we're rendering our normal view.
642 // This will not be available when rendering reflection probes.
643 rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
644 }
645 bool is_reflection_probe = p_render_data->reflection_probe.is_valid();
646
647 RENDER_TIMESTAMP("Prepare 3D Scene");
648
649 _update_vrs(rb);
650
651 RENDER_TIMESTAMP("Setup 3D Scene");
652
653 /* TODO
654 // check if we need motion vectors
655 if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
656 p_render_data->scene_data->calculate_motion_vectors = true;
657 } else if (render target has velocity override) { // TODO
658 p_render_data->scene_data->calculate_motion_vectors = true;
659 } else {
660 p_render_data->scene_data->calculate_motion_vectors = false;
661 }
662 */
663 p_render_data->scene_data->calculate_motion_vectors = false; // for now, not yet supported...
664
665 p_render_data->scene_data->directional_light_count = 0;
666 p_render_data->scene_data->opaque_prepass_threshold = 0.0;
667
668 // We can only use our full subpass approach if we're:
669 // - not reading from SCREEN_TEXTURE/DEPTH_TEXTURE
670 // - not using ssr/sss (currently not supported)
671 // - not using glow or other post effects (can't do 4th subpass)
672 // - rendering to a half sized render buffer (can't do 4th subpass)
673 // We'll need to restrict how far we're going with subpasses based on this.
674
675 Size2i screen_size;
676 RID framebuffer;
677 bool reverse_cull = p_render_data->scene_data->cam_transform.basis.determinant() < 0;
678 bool using_subpass_transparent = true;
679 bool using_subpass_post_process = true;
680
681 // fill our render lists early so we can find out if we use various features
682 _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
683 render_list[RENDER_LIST_OPAQUE].sort_by_key();
684 render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
685 _fill_element_info(RENDER_LIST_OPAQUE);
686 _fill_element_info(RENDER_LIST_ALPHA);
687
688 if (p_render_data->render_info) {
689 p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_render_data->instances->size();
690 p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_render_data->instances->size();
691 }
692
693 if (is_reflection_probe) {
694 uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
695 screen_size.x = resolution;
696 screen_size.y = resolution;
697
698 framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
699
700 if (light_storage->reflection_probe_is_interior(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
701 p_render_data->environment = RID(); //no environment on interiors
702 }
703
704 reverse_cull = true;
705 using_subpass_transparent = true; // we ignore our screen/depth texture here
706 using_subpass_post_process = false; // not applicable at all for reflection probes.
707 } else if (rb_data.is_valid()) {
708 // setup rendering to render buffer
709 screen_size = p_render_data->render_buffers->get_internal_size();
710
711 if (rb->get_scaling_3d_mode() != RS::VIEWPORT_SCALING_3D_MODE_OFF) {
712 // can't do blit subpass because we're scaling
713 using_subpass_post_process = false;
714 } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes))) {
715 // can't do blit subpass because we're using post processes
716 using_subpass_post_process = false;
717 }
718
719 if (scene_state.used_screen_texture || scene_state.used_depth_texture) {
720 // can't use our last two subpasses because we're reading from screen texture or depth texture
721 using_subpass_transparent = false;
722 using_subpass_post_process = false;
723 }
724
725 if (using_subpass_post_process) {
726 // all as subpasses
727 framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES);
728 } else if (using_subpass_transparent) {
729 // our tonemap pass is separate
730 framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_THREE_SUBPASSES);
731 } else {
732 // only opaque and sky as subpasses
733 framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_TWO_SUBPASSES);
734 }
735 } else {
736 ERR_FAIL(); //bug?
737 }
738
739 p_render_data->scene_data->emissive_exposure_normalization = -1.0;
740
741 RD::get_singleton()->draw_command_begin_label("Render Setup");
742
743 _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform);
744 _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
745
746 _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
747
748 RD::get_singleton()->draw_command_end_label(); // Render Setup
749
750 // setup environment
751 RID radiance_texture;
752 bool draw_sky = false;
753 bool draw_sky_fog_only = false;
754 // We invert luminance_multiplier for sky so that we can combine it with exposure value.
755 float inverse_luminance_multiplier = 1.0 / _render_buffers_get_luminance_multiplier();
756 float sky_energy_multiplier = inverse_luminance_multiplier;
757
758 Color clear_color = p_default_bg_color;
759 bool keep_color = false;
760
761 if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
762 clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
763 } else if (is_environment(p_render_data->environment)) {
764 RS::EnvironmentBG bg_mode = environment_get_background(p_render_data->environment);
765 float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
766 bg_energy_multiplier *= environment_get_bg_intensity(p_render_data->environment);
767
768 if (p_render_data->camera_attributes.is_valid()) {
769 bg_energy_multiplier *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
770 }
771
772 switch (bg_mode) {
773 case RS::ENV_BG_CLEAR_COLOR: {
774 clear_color = p_default_bg_color;
775 clear_color.r *= bg_energy_multiplier;
776 clear_color.g *= bg_energy_multiplier;
777 clear_color.b *= bg_energy_multiplier;
778 if (environment_get_fog_enabled(p_render_data->environment)) {
779 draw_sky_fog_only = true;
780 RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
781 }
782 } break;
783 case RS::ENV_BG_COLOR: {
784 clear_color = environment_get_bg_color(p_render_data->environment);
785 clear_color.r *= bg_energy_multiplier;
786 clear_color.g *= bg_energy_multiplier;
787 clear_color.b *= bg_energy_multiplier;
788 if (environment_get_fog_enabled(p_render_data->environment)) {
789 draw_sky_fog_only = true;
790 RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
791 }
792 } break;
793 case RS::ENV_BG_SKY: {
794 draw_sky = true;
795 } break;
796 case RS::ENV_BG_CANVAS: {
797 if (rb_data.is_valid()) {
798 RID dest_framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS);
799 RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target());
800 bool convert_to_linear = !RendererRD::TextureStorage::get_singleton()->render_target_is_using_hdr(rb->get_render_target());
801 copy_effects->copy_to_fb_rect(texture, dest_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, convert_to_linear);
802 }
803 keep_color = true;
804 } break;
805 case RS::ENV_BG_KEEP: {
806 keep_color = true;
807 } break;
808 case RS::ENV_BG_CAMERA_FEED: {
809 } break;
810 default: {
811 }
812 }
813
814 // setup sky if used for ambient, reflections, or background
815 if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
816 RENDER_TIMESTAMP("Setup Sky");
817 RD::get_singleton()->draw_command_begin_label("Setup Sky");
818
819 // Setup our sky render information for this frame/viewport
820 if (is_reflection_probe) {
821 Vector3 eye_offset;
822 Projection correction;
823 correction.set_depth_correction(true);
824 Projection projection = correction * p_render_data->scene_data->cam_projection;
825
826 sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, this);
827 } else {
828 sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, screen_size, this);
829 }
830
831 sky_energy_multiplier *= bg_energy_multiplier;
832
833 RID sky_rid = environment_get_sky(p_render_data->environment);
834 if (sky_rid.is_valid()) {
835 sky.update_radiance_buffers(rb, p_render_data->environment, p_render_data->scene_data->cam_transform.origin, time, sky_energy_multiplier);
836 radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
837 } else {
838 // do not try to draw sky if invalid
839 draw_sky = false;
840 }
841
842 if (draw_sky || draw_sky_fog_only) {
843 // update sky half/quarter res buffers (if required)
844 sky.update_res_buffers(rb, p_render_data->environment, time, sky_energy_multiplier);
845 }
846 RD::get_singleton()->draw_command_end_label(); // Setup Sky
847 }
848 } else {
849 clear_color = p_default_bg_color;
850 }
851
852 _pre_opaque_render(p_render_data);
853
854 uint32_t spec_constant_base_flags = 0;
855
856 {
857 //figure out spec constants
858
859 if (p_render_data->directional_light_count > 0) {
860 if (p_render_data->directional_light_soft_shadows) {
861 spec_constant_base_flags |= 1 << SPEC_CONSTANT_USING_DIRECTIONAL_SOFT_SHADOWS;
862 }
863 } else {
864 spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS;
865 }
866
867 if (!is_environment(p_render_data->environment) || !environment_get_fog_enabled(p_render_data->environment)) {
868 spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_FOG;
869 }
870 }
871 {
872 if (rb_data.is_valid()) {
873 RD::get_singleton()->draw_command_begin_label("Render 3D Pass");
874 } else {
875 RD::get_singleton()->draw_command_begin_label("Render Reflection Probe Pass");
876 }
877
878 // opaque pass
879
880 RD::get_singleton()->draw_command_begin_label("Render Opaque Subpass");
881
882 p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count;
883
884 _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, p_render_data->render_buffers.is_valid());
885
886 if (using_subpass_transparent && using_subpass_post_process) {
887 RENDER_TIMESTAMP("Render Opaque + Transparent + Tonemap");
888 } else if (using_subpass_transparent) {
889 RENDER_TIMESTAMP("Render Opaque + Transparent");
890 } else {
891 RENDER_TIMESTAMP("Render Opaque");
892 }
893
894 RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
895
896 bool can_continue_color = !using_subpass_transparent && !scene_state.used_screen_texture;
897 bool can_continue_depth = !using_subpass_transparent && !scene_state.used_depth_texture;
898
899 {
900 // regular forward for now
901 Vector<Color> c;
902 {
903 Color cc = clear_color.srgb_to_linear() * inverse_luminance_multiplier;
904 if (rb_data.is_valid()) {
905 cc.a = 0; // For transparent viewport backgrounds.
906 }
907 c.push_back(cc); // Our render buffer.
908 if (rb_data.is_valid()) {
909 if (p_render_data->render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
910 c.push_back(clear_color.srgb_to_linear() * inverse_luminance_multiplier); // Our resolve buffer.
911 }
912 if (using_subpass_post_process) {
913 c.push_back(Color()); // Our 2D buffer we're copying into.
914 }
915 }
916 }
917
918 RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
919 RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
920 render_list_params.framebuffer_format = fb_format;
921 if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
922 // secondary command buffers need more testing at this time
923 //multi threaded
924 thread_draw_lists.resize(WorkerThreadPool::get_singleton()->get_thread_count());
925 RD::get_singleton()->draw_list_begin_split(framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
926
927 WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &RenderForwardMobile::_render_list_thread_function, &render_list_params, thread_draw_lists.size(), -1, true, SNAME("ForwardMobileRenderList"));
928 WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
929
930 } else {
931 //single threaded
932 RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
933 _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
934 }
935 }
936
937 RD::get_singleton()->draw_command_end_label(); //Render Opaque Subpass
938
939 if (draw_sky || draw_sky_fog_only) {
940 RD::get_singleton()->draw_command_begin_label("Draw Sky Subpass");
941
942 // Note, sky.setup should have been called up above and setup stuff we need.
943
944 RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
945
946 sky.draw_sky(draw_list, rb, p_render_data->environment, framebuffer, time, sky_energy_multiplier);
947
948 RD::get_singleton()->draw_command_end_label(); // Draw Sky Subpass
949
950 // note, if MSAA is used in 2-subpass approach we should get an automatic resolve here
951 } else {
952 // switch to subpass but we do nothing here so basically we skip (though this should trigger resolve with 2-subpass MSAA).
953 RD::get_singleton()->draw_list_switch_to_next_pass();
954 }
955
956 if (!using_subpass_transparent) {
957 // We're done with our subpasses so end our container pass
958 RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS);
959
960 RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
961 }
962
963 if (scene_state.used_screen_texture) {
964 // Copy screen texture to backbuffer so we can read from it
965 _render_buffers_copy_screen_texture(p_render_data);
966 }
967
968 if (scene_state.used_depth_texture) {
969 // Copy depth texture to backbuffer so we can read from it
970 _render_buffers_copy_depth_texture(p_render_data);
971 }
972
973 // transparent pass
974
975 RD::get_singleton()->draw_command_begin_label("Render Transparent Subpass");
976
977 rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true);
978
979 if (using_subpass_transparent) {
980 RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
981 RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR_TRANSPARENT, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
982 render_list_params.framebuffer_format = fb_format;
983 if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
984 // secondary command buffers need more testing at this time
985 //multi threaded
986 thread_draw_lists.resize(WorkerThreadPool::get_singleton()->get_thread_count());
987 RD::get_singleton()->draw_list_switch_to_next_pass_split(thread_draw_lists.size(), thread_draw_lists.ptr());
988 render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass();
989 WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &RenderForwardMobile::_render_list_thread_function, &render_list_params, thread_draw_lists.size(), -1, true, SNAME("ForwardMobileRenderSubpass"));
990 WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
991
992 } else {
993 //single threaded
994 RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
995 render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass();
996 _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
997 }
998
999 RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass
1000
1001 // note if we are using MSAA we should get an automatic resolve through our subpass configuration.
1002
1003 // blit to tonemap
1004 if (rb_data.is_valid() && using_subpass_post_process) {
1005 _post_process_subpass(p_render_data->render_buffers->get_internal_texture(), framebuffer, p_render_data);
1006 }
1007
1008 RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
1009
1010 RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS);
1011 } else {
1012 RENDER_TIMESTAMP("Render Transparent");
1013
1014 if (rb_data.is_valid()) {
1015 framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS);
1016 }
1017
1018 // this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation
1019 // _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
1020
1021 RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
1022 RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
1023 render_list_params.framebuffer_format = fb_format;
1024 if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
1025 // secondary command buffers need more testing at this time
1026 //multi threaded
1027 thread_draw_lists.resize(WorkerThreadPool::get_singleton()->get_thread_count());
1028 RD::get_singleton()->draw_list_begin_split(framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
1029 WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &RenderForwardMobile::_render_list_thread_function, &render_list_params, thread_draw_lists.size(), -1, true, SNAME("ForwardMobileRenderSubpass"));
1030 WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
1031
1032 RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS);
1033 } else {
1034 //single threaded
1035 RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
1036 _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
1037 RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS);
1038 }
1039
1040 RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass
1041 }
1042 }
1043
1044 if (rb_data.is_valid() && !using_subpass_post_process) {
1045 RD::get_singleton()->draw_command_begin_label("Post process pass");
1046
1047 // If we need extra effects we do this in its own pass
1048 RENDER_TIMESTAMP("Tonemap");
1049
1050 _render_buffers_post_process_and_tonemap(p_render_data);
1051
1052 RD::get_singleton()->draw_command_end_label(); // Post process pass
1053 }
1054
1055 if (rb_data.is_valid()) {
1056 _disable_clear_request(p_render_data);
1057 }
1058
1059 _render_buffers_debug_draw(p_render_data);
1060}
1061
1062/* these are being called from RendererSceneRenderRD::_pre_opaque_render */
1063
1064void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info) {
1065 RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
1066
1067 ERR_FAIL_COND(!light_storage->owns_light_instance(p_light));
1068
1069 RID base = light_storage->light_instance_get_base_light(p_light);
1070
1071 Rect2i atlas_rect;
1072 uint32_t atlas_size = 1;
1073 RID atlas_fb;
1074
1075 bool using_dual_paraboloid = false;
1076 bool using_dual_paraboloid_flip = false;
1077 Vector2i dual_paraboloid_offset;
1078 RID render_fb;
1079 RID render_texture;
1080 float zfar;
1081
1082 bool use_pancake = false;
1083 bool render_cubemap = false;
1084 bool finalize_cubemap = false;
1085
1086 bool flip_y = false;
1087
1088 Projection light_projection;
1089 Transform3D light_transform;
1090
1091 if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) {
1092 //set pssm stuff
1093 uint64_t last_scene_shadow_pass = light_storage->light_instance_get_shadow_pass(p_light);
1094 if (last_scene_shadow_pass != get_scene_pass()) {
1095 light_storage->light_instance_set_directional_rect(p_light, light_storage->get_directional_shadow_rect());
1096 light_storage->directional_shadow_increase_current_light();
1097 light_storage->light_instance_set_shadow_pass(p_light, get_scene_pass());
1098 }
1099
1100 use_pancake = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0;
1101 light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass);
1102 light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass);
1103
1104 atlas_rect = light_storage->light_instance_get_directional_rect(p_light);
1105
1106 if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
1107 atlas_rect.size.width /= 2;
1108 atlas_rect.size.height /= 2;
1109
1110 if (p_pass == 1) {
1111 atlas_rect.position.x += atlas_rect.size.width;
1112 } else if (p_pass == 2) {
1113 atlas_rect.position.y += atlas_rect.size.height;
1114 } else if (p_pass == 3) {
1115 atlas_rect.position += atlas_rect.size;
1116 }
1117 } else if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
1118 atlas_rect.size.height /= 2;
1119
1120 if (p_pass == 0) {
1121 } else {
1122 atlas_rect.position.y += atlas_rect.size.height;
1123 }
1124 }
1125
1126 float directional_shadow_size = light_storage->directional_shadow_get_size();
1127 Rect2 atlas_rect_norm = atlas_rect;
1128 atlas_rect_norm.position /= directional_shadow_size;
1129 atlas_rect_norm.size /= directional_shadow_size;
1130 light_storage->light_instance_set_directional_shadow_atlas_rect(p_light, p_pass, atlas_rect_norm);
1131
1132 zfar = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE);
1133
1134 render_fb = light_storage->direction_shadow_get_fb();
1135 render_texture = RID();
1136 flip_y = true;
1137
1138 } else {
1139 //set from shadow atlas
1140
1141 ERR_FAIL_COND(!light_storage->owns_shadow_atlas(p_shadow_atlas));
1142 ERR_FAIL_COND(!light_storage->shadow_atlas_owns_light_instance(p_shadow_atlas, p_light));
1143
1144 RSG::light_storage->shadow_atlas_update(p_shadow_atlas);
1145
1146 uint32_t key = light_storage->shadow_atlas_get_light_instance_key(p_shadow_atlas, p_light);
1147
1148 uint32_t quadrant = (key >> RendererRD::LightStorage::QUADRANT_SHIFT) & 0x3;
1149 uint32_t shadow = key & RendererRD::LightStorage::SHADOW_INDEX_MASK;
1150 uint32_t subdivision = light_storage->shadow_atlas_get_quadrant_subdivision(p_shadow_atlas, quadrant);
1151
1152 ERR_FAIL_INDEX((int)shadow, light_storage->shadow_atlas_get_quadrant_shadow_size(p_shadow_atlas, quadrant));
1153
1154 uint32_t shadow_atlas_size = light_storage->shadow_atlas_get_size(p_shadow_atlas);
1155 uint32_t quadrant_size = shadow_atlas_size >> 1;
1156
1157 atlas_rect.position.x = (quadrant & 1) * quadrant_size;
1158 atlas_rect.position.y = (quadrant >> 1) * quadrant_size;
1159
1160 uint32_t shadow_size = (quadrant_size / subdivision);
1161 atlas_rect.position.x += (shadow % subdivision) * shadow_size;
1162 atlas_rect.position.y += (shadow / subdivision) * shadow_size;
1163
1164 atlas_rect.size.width = shadow_size;
1165 atlas_rect.size.height = shadow_size;
1166
1167 zfar = light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE);
1168
1169 if (light_storage->light_get_type(base) == RS::LIGHT_OMNI) {
1170 bool wrap = (shadow + 1) % subdivision == 0;
1171 dual_paraboloid_offset = wrap ? Vector2i(1 - subdivision, 1) : Vector2i(1, 0);
1172
1173 if (light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) {
1174 render_texture = light_storage->get_cubemap(shadow_size / 2);
1175 render_fb = light_storage->get_cubemap_fb(shadow_size / 2, p_pass);
1176
1177 light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass);
1178 light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass);
1179 render_cubemap = true;
1180 finalize_cubemap = p_pass == 5;
1181 atlas_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
1182
1183 atlas_size = shadow_atlas_size;
1184
1185 if (p_pass == 0) {
1186 _render_shadow_begin();
1187 }
1188
1189 } else {
1190 atlas_rect.position.x += 1;
1191 atlas_rect.position.y += 1;
1192 atlas_rect.size.x -= 2;
1193 atlas_rect.size.y -= 2;
1194
1195 atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset;
1196
1197 light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0);
1198 light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0);
1199
1200 using_dual_paraboloid = true;
1201 using_dual_paraboloid_flip = p_pass == 1;
1202 render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
1203 flip_y = true;
1204 }
1205
1206 } else if (light_storage->light_get_type(base) == RS::LIGHT_SPOT) {
1207 light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0);
1208 light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0);
1209
1210 render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
1211
1212 flip_y = true;
1213 }
1214 }
1215
1216 if (render_cubemap) {
1217 //rendering to cubemap
1218 _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info);
1219 if (finalize_cubemap) {
1220 _render_shadow_process();
1221 _render_shadow_end(RD::BARRIER_MASK_FRAGMENT);
1222
1223 // reblit
1224 Rect2 atlas_rect_norm = atlas_rect;
1225 atlas_rect_norm.position /= float(atlas_size);
1226 atlas_rect_norm.size /= float(atlas_size);
1227 copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false, RD::BARRIER_MASK_NO_BARRIER);
1228 atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size;
1229 copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true, RD::BARRIER_MASK_NO_BARRIER);
1230
1231 //restore transform so it can be properly used
1232 light_storage->light_instance_set_shadow_transform(p_light, Projection(), light_storage->light_instance_get_base_transform(p_light), zfar, 0, 0, 0);
1233 }
1234
1235 } else {
1236 //render shadow
1237 _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info);
1238 }
1239}
1240
1241void RenderForwardMobile::_render_shadow_begin() {
1242 scene_state.shadow_passes.clear();
1243 RD::get_singleton()->draw_command_begin_label("Shadow Setup");
1244 _update_render_base_uniform_set();
1245
1246 render_list[RENDER_LIST_SECONDARY].clear();
1247}
1248
1249void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info) {
1250 uint32_t shadow_pass_index = scene_state.shadow_passes.size();
1251
1252 SceneState::ShadowPass shadow_pass;
1253
1254 if (p_render_info) {
1255 p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_instances.size();
1256 p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_instances.size();
1257 }
1258
1259 RenderSceneDataRD scene_data;
1260 scene_data.cam_projection = p_projection;
1261 scene_data.cam_transform = p_transform;
1262 scene_data.view_projection[0] = p_projection;
1263 scene_data.z_near = 0.0;
1264 scene_data.z_far = p_zfar;
1265 scene_data.lod_distance_multiplier = p_lod_distance_multiplier;
1266 scene_data.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
1267 scene_data.opaque_prepass_threshold = 0.1;
1268 scene_data.time = time;
1269 scene_data.time_step = time_step;
1270
1271 RenderDataRD render_data;
1272 render_data.scene_data = &scene_data;
1273 render_data.instances = &p_instances;
1274 render_data.render_info = p_render_info;
1275
1276 _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index);
1277
1278 if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
1279 scene_data.screen_mesh_lod_threshold = 0.0;
1280 } else {
1281 scene_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
1282 }
1283
1284 PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
1285
1286 uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size();
1287 _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, true);
1288 uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
1289 render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
1290 _fill_element_info(RENDER_LIST_SECONDARY, render_list_from, render_list_size);
1291
1292 {
1293 //regular forward for now
1294 bool flip_cull = p_use_dp_flip;
1295 if (p_flip_y) {
1296 flip_cull = !flip_cull;
1297 }
1298
1299 shadow_pass.element_from = render_list_from;
1300 shadow_pass.element_count = render_list_size;
1301 shadow_pass.flip_cull = flip_cull;
1302 shadow_pass.pass_mode = pass_mode;
1303
1304 shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete
1305 shadow_pass.camera_plane = p_camera_plane;
1306 shadow_pass.screen_mesh_lod_threshold = scene_data.screen_mesh_lod_threshold;
1307 shadow_pass.lod_distance_multiplier = scene_data.lod_distance_multiplier;
1308
1309 shadow_pass.framebuffer = p_framebuffer;
1310 shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE);
1311 shadow_pass.final_depth_action = p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE;
1312 shadow_pass.rect = p_rect;
1313
1314 scene_state.shadow_passes.push_back(shadow_pass);
1315 }
1316}
1317
1318void RenderForwardMobile::_render_shadow_process() {
1319 //render shadows one after the other, so this can be done un-barriered and the driver can optimize (as well as allow us to run compute at the same time)
1320
1321 for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
1322 //render passes need to be configured after instance buffer is done, since they need the latest version
1323 SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
1324 shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), false, i);
1325 }
1326
1327 RD::get_singleton()->draw_command_end_label();
1328}
1329
1330void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) {
1331 RD::get_singleton()->draw_command_begin_label("Shadow Render");
1332
1333 for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) {
1334 RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
1335 _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect);
1336 }
1337
1338 if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) {
1339 RD::get_singleton()->barrier(RD::BARRIER_MASK_FRAGMENT, p_barrier);
1340 }
1341 RD::get_singleton()->draw_command_end_label();
1342}
1343
1344/* */
1345
1346void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) {
1347 RENDER_TIMESTAMP("Setup Rendering 3D Material");
1348
1349 RD::get_singleton()->draw_command_begin_label("Render 3D Material");
1350
1351 _update_render_base_uniform_set();
1352
1353 RenderSceneDataRD scene_data;
1354 scene_data.cam_projection = p_cam_projection;
1355 scene_data.cam_transform = p_cam_transform;
1356 scene_data.view_projection[0] = p_cam_projection;
1357 scene_data.dual_paraboloid_side = 0;
1358 scene_data.material_uv2_mode = false;
1359 scene_data.opaque_prepass_threshold = 0.0f;
1360 scene_data.emissive_exposure_normalization = p_exposure_normalization;
1361 scene_data.time = time;
1362 scene_data.time_step = time_step;
1363
1364 RenderDataRD render_data;
1365 render_data.scene_data = &scene_data;
1366 render_data.instances = &p_instances;
1367
1368 _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
1369
1370 PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
1371 _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
1372 render_list[RENDER_LIST_SECONDARY].sort_by_key();
1373 _fill_element_info(RENDER_LIST_SECONDARY);
1374
1375 RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
1376
1377 RENDER_TIMESTAMP("Render 3D Material");
1378
1379 {
1380 RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, 0);
1381 //regular forward for now
1382 Vector<Color> clear = {
1383 Color(0, 0, 0, 0),
1384 Color(0, 0, 0, 0),
1385 Color(0, 0, 0, 0),
1386 Color(0, 0, 0, 0),
1387 Color(0, 0, 0, 0)
1388 };
1389 RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
1390 _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count);
1391 RD::get_singleton()->draw_list_end();
1392 }
1393
1394 RD::get_singleton()->draw_command_end_label();
1395}
1396
1397void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
1398 RENDER_TIMESTAMP("Setup Rendering UV2");
1399
1400 RD::get_singleton()->draw_command_begin_label("Render UV2");
1401
1402 _update_render_base_uniform_set();
1403
1404 RenderSceneDataRD scene_data;
1405 scene_data.dual_paraboloid_side = 0;
1406 scene_data.material_uv2_mode = true;
1407 scene_data.emissive_exposure_normalization = -1.0;
1408
1409 RenderDataRD render_data;
1410 render_data.scene_data = &scene_data;
1411 render_data.instances = &p_instances;
1412
1413 _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
1414
1415 PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
1416 _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
1417 render_list[RENDER_LIST_SECONDARY].sort_by_key();
1418 _fill_element_info(RENDER_LIST_SECONDARY);
1419
1420 RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
1421
1422 RENDER_TIMESTAMP("Render 3D Material");
1423
1424 {
1425 RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true, false);
1426 //regular forward for now
1427 Vector<Color> clear = {
1428 Color(0, 0, 0, 0),
1429 Color(0, 0, 0, 0),
1430 Color(0, 0, 0, 0),
1431 Color(0, 0, 0, 0),
1432 Color(0, 0, 0, 0)
1433 };
1434
1435 RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
1436
1437 const int uv_offset_count = 9;
1438 static const Vector2 uv_offsets[uv_offset_count] = {
1439 Vector2(-1, 1),
1440 Vector2(1, 1),
1441 Vector2(1, -1),
1442 Vector2(-1, -1),
1443 Vector2(-1, 0),
1444 Vector2(1, 0),
1445 Vector2(0, -1),
1446 Vector2(0, 1),
1447 Vector2(0, 0),
1448
1449 };
1450
1451 for (int i = 0; i < uv_offset_count; i++) {
1452 Vector2 ofs = uv_offsets[i];
1453 ofs.x /= p_region.size.width;
1454 ofs.y /= p_region.size.height;
1455 render_list_params.uv_offset = ofs;
1456 _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative
1457 }
1458 render_list_params.uv_offset = Vector2();
1459 _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles
1460
1461 RD::get_singleton()->draw_list_end();
1462 }
1463
1464 RD::get_singleton()->draw_command_end_label();
1465}
1466
1467void RenderForwardMobile::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) {
1468 // we don't do SDFGI in low end..
1469}
1470
1471void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) {
1472 RENDER_TIMESTAMP("Setup GPUParticlesCollisionHeightField3D");
1473
1474 RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
1475
1476 _update_render_base_uniform_set();
1477
1478 RenderSceneDataRD scene_data;
1479 scene_data.cam_projection = p_cam_projection;
1480 scene_data.cam_transform = p_cam_transform;
1481 scene_data.view_projection[0] = p_cam_projection;
1482 scene_data.z_near = 0.0;
1483 scene_data.z_far = p_cam_projection.get_z_far();
1484 scene_data.dual_paraboloid_side = 0;
1485 scene_data.opaque_prepass_threshold = 0.0;
1486 scene_data.time = time;
1487 scene_data.time_step = time_step;
1488
1489 RenderDataRD render_data;
1490 render_data.scene_data = &scene_data;
1491 render_data.instances = &p_instances;
1492
1493 _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false);
1494
1495 PassMode pass_mode = PASS_MODE_SHADOW;
1496
1497 _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
1498 render_list[RENDER_LIST_SECONDARY].sort_by_key();
1499 _fill_element_info(RENDER_LIST_SECONDARY);
1500
1501 RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
1502
1503 RENDER_TIMESTAMP("Render Collider Heightfield");
1504
1505 {
1506 //regular forward for now
1507 RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set, 0);
1508 _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ);
1509 }
1510 RD::get_singleton()->draw_command_end_label();
1511}
1512
1513void RenderForwardMobile::base_uniforms_changed() {
1514 if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
1515 RD::get_singleton()->free(render_base_uniform_set);
1516 }
1517 render_base_uniform_set = RID();
1518}
1519
1520void RenderForwardMobile::_update_render_base_uniform_set() {
1521 RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
1522 RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
1523
1524 if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != light_storage->lightmap_array_get_version())) {
1525 if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
1526 RD::get_singleton()->free(render_base_uniform_set);
1527 }
1528
1529 // This is all loaded into set 0
1530
1531 lightmap_texture_array_version = light_storage->lightmap_array_get_version();
1532
1533 Vector<RD::Uniform> uniforms;
1534
1535 {
1536 RD::Uniform u;
1537 u.binding = 2;
1538 u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
1539 u.append_id(scene_shader.shadow_sampler);
1540 uniforms.push_back(u);
1541 }
1542
1543 {
1544 RD::Uniform u;
1545 u.binding = 3;
1546 u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
1547 RID sampler;
1548 switch (decals_get_filter()) {
1549 case RS::DECAL_FILTER_NEAREST: {
1550 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1551 } break;
1552 case RS::DECAL_FILTER_LINEAR: {
1553 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1554 } break;
1555 case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
1556 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1557 } break;
1558 case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
1559 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1560 } break;
1561 case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
1562 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1563 } break;
1564 case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
1565 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1566 } break;
1567 }
1568
1569 u.append_id(sampler);
1570 uniforms.push_back(u);
1571 }
1572
1573 {
1574 RD::Uniform u;
1575 u.binding = 4;
1576 u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
1577 RID sampler;
1578 switch (light_projectors_get_filter()) {
1579 case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
1580 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1581 } break;
1582 case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
1583 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1584 } break;
1585 case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
1586 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1587 } break;
1588 case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
1589 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1590 } break;
1591 case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
1592 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1593 } break;
1594 case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
1595 sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
1596 } break;
1597 }
1598
1599 u.append_id(sampler);
1600 uniforms.push_back(u);
1601 }
1602
1603 {
1604 RD::Uniform u;
1605 u.binding = 5;
1606 u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
1607 u.append_id(RendererRD::LightStorage::get_singleton()->get_omni_light_buffer());
1608 uniforms.push_back(u);
1609 }
1610 {
1611 RD::Uniform u;
1612 u.binding = 6;
1613 u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
1614 u.append_id(RendererRD::LightStorage::get_singleton()->get_spot_light_buffer());
1615 uniforms.push_back(u);
1616 }
1617
1618 {
1619 RD::Uniform u;
1620 u.binding = 7;
1621 u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
1622 u.append_id(RendererRD::LightStorage::get_singleton()->get_reflection_probe_buffer());
1623 uniforms.push_back(u);
1624 }
1625 {
1626 RD::Uniform u;
1627 u.binding = 8;
1628 u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
1629 u.append_id(RendererRD::LightStorage::get_singleton()->get_directional_light_buffer());
1630 uniforms.push_back(u);
1631 }
1632 {
1633 RD::Uniform u;
1634 u.binding = 9;
1635 u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
1636 u.append_id(scene_state.lightmap_buffer);
1637 uniforms.push_back(u);
1638 }
1639 {
1640 RD::Uniform u;
1641 u.binding = 10;
1642 u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
1643 u.append_id(scene_state.lightmap_capture_buffer);
1644 uniforms.push_back(u);
1645 }
1646 {
1647 RD::Uniform u;
1648 u.binding = 11;
1649 u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
1650 RID decal_atlas = RendererRD::TextureStorage::get_singleton()->decal_atlas_get_texture();
1651 u.append_id(decal_atlas);
1652 uniforms.push_back(u);
1653 }
1654 {
1655 RD::Uniform u;
1656 u.binding = 12;
1657 u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
1658 RID decal_atlas = RendererRD::TextureStorage::get_singleton()->decal_atlas_get_texture_srgb();
1659 u.append_id(decal_atlas);
1660 uniforms.push_back(u);
1661 }
1662 {
1663 RD::Uniform u;
1664 u.binding = 13;
1665 u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
1666 u.append_id(RendererRD::TextureStorage::get_singleton()->get_decal_buffer());
1667 uniforms.push_back(u);
1668 }
1669
1670 {
1671 RD::Uniform u;
1672 u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
1673 u.binding = 14;
1674 u.append_id(RendererRD::MaterialStorage::get_singleton()->global_shader_uniforms_get_storage_buffer());
1675 uniforms.push_back(u);
1676 }
1677
1678 uniforms.append_array(material_storage->get_default_sampler_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
1679
1680 render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
1681 }
1682}
1683
1684RID RenderForwardMobile::_render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) {
1685 return RID();
1686}
1687
1688RID RenderForwardMobile::_render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) {
1689 return RID();
1690}
1691
1692_FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primitive, uint32_t p_indices) {
1693 static const uint32_t divisor[RS::PRIMITIVE_MAX] = { 1, 2, 1, 3, 1 };
1694 static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 };
1695 return (p_indices - subtractor[p_primitive]) / divisor[p_primitive];
1696}
1697
1698void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append) {
1699 RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
1700
1701 if (p_render_list == RENDER_LIST_OPAQUE) {
1702 scene_state.used_sss = false;
1703 scene_state.used_screen_texture = false;
1704 scene_state.used_normal_texture = false;
1705 scene_state.used_depth_texture = false;
1706 }
1707 uint32_t lightmap_captures_used = 0;
1708
1709 Plane near_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin);
1710 near_plane.d += p_render_data->scene_data->cam_projection.get_z_near();
1711 float z_max = p_render_data->scene_data->cam_projection.get_z_far() - p_render_data->scene_data->cam_projection.get_z_near();
1712
1713 RenderList *rl = &render_list[p_render_list];
1714
1715 // Parse any updates on our geometry, updates surface caches and such
1716 _update_dirty_geometry_instances();
1717
1718 if (!p_append) {
1719 rl->clear();
1720 if (p_render_list == RENDER_LIST_OPAQUE) {
1721 render_list[RENDER_LIST_ALPHA].clear(); //opaque fills alpha too
1722 }
1723 }
1724
1725 //fill list
1726
1727 for (int i = 0; i < (int)p_render_data->instances->size(); i++) {
1728 GeometryInstanceForwardMobile *inst = static_cast<GeometryInstanceForwardMobile *>((*p_render_data->instances)[i]);
1729
1730 Vector3 center = inst->transform.origin;
1731 if (p_render_data->scene_data->cam_orthogonal) {
1732 if (inst->use_aabb_center) {
1733 center = inst->transformed_aabb.get_support(-near_plane.normal);
1734 }
1735 inst->depth = near_plane.distance_to(center) - inst->sorting_offset;
1736 } else {
1737 if (inst->use_aabb_center) {
1738 center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5);
1739 }
1740 inst->depth = p_render_data->scene_data->cam_transform.origin.distance_to(center) - inst->sorting_offset;
1741 }
1742 uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15);
1743
1744 uint32_t flags = inst->base_flags; //fill flags if appropriate
1745
1746 if (inst->non_uniform_scale) {
1747 flags |= INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE;
1748 }
1749
1750 bool uses_lightmap = false;
1751 // bool uses_gi = false;
1752
1753 if (p_render_list == RENDER_LIST_OPAQUE) {
1754 if (inst->lightmap_instance.is_valid()) {
1755 int32_t lightmap_cull_index = -1;
1756 for (uint32_t j = 0; j < scene_state.lightmaps_used; j++) {
1757 if (scene_state.lightmap_ids[j] == inst->lightmap_instance) {
1758 lightmap_cull_index = j;
1759 break;
1760 }
1761 }
1762 if (lightmap_cull_index >= 0) {
1763 inst->gi_offset_cache = inst->lightmap_slice_index << 16;
1764 inst->gi_offset_cache |= lightmap_cull_index;
1765 flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP;
1766 if (scene_state.lightmap_has_sh[lightmap_cull_index]) {
1767 flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP;
1768 }
1769 uses_lightmap = true;
1770 } else {
1771 inst->gi_offset_cache = 0xFFFFFFFF;
1772 }
1773
1774 } else if (inst->lightmap_sh) {
1775 if (lightmap_captures_used < scene_state.max_lightmap_captures) {
1776 const Color *src_capture = inst->lightmap_sh->sh;
1777 LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used];
1778 for (int j = 0; j < 9; j++) {
1779 lcd.sh[j * 4 + 0] = src_capture[j].r;
1780 lcd.sh[j * 4 + 1] = src_capture[j].g;
1781 lcd.sh[j * 4 + 2] = src_capture[j].b;
1782 lcd.sh[j * 4 + 3] = src_capture[j].a;
1783 }
1784 flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE;
1785 inst->gi_offset_cache = lightmap_captures_used;
1786 lightmap_captures_used++;
1787 uses_lightmap = true;
1788 }
1789 }
1790 }
1791 inst->flags_cache = flags;
1792
1793 GeometryInstanceSurfaceDataCache *surf = inst->surface_caches;
1794
1795 while (surf) {
1796 surf->sort.uses_lightmap = 0;
1797
1798 // LOD
1799
1800 if (p_render_data->scene_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
1801 // Get the LOD support points on the mesh AABB.
1802 Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
1803 Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
1804
1805 // Get the distances to those points on the AABB from the camera origin.
1806 float distance_min = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_min);
1807 float distance_max = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_max);
1808
1809 float distance = 0.0;
1810
1811 if (distance_min * distance_max < 0.0) {
1812 //crossing plane
1813 distance = 0.0;
1814 } else if (distance_min >= 0.0) {
1815 distance = distance_min;
1816 } else if (distance_max <= 0.0) {
1817 distance = -distance_max;
1818 }
1819
1820 if (p_render_data->scene_data->cam_orthogonal) {
1821 distance = 1.0;
1822 }
1823
1824 uint32_t indices = 0;
1825 surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, indices);
1826 if (p_render_data->render_info) {
1827 indices = _indices_to_primitives(surf->primitive, indices);
1828 if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
1829 p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
1830 } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
1831 p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
1832 }
1833 }
1834 } else {
1835 surf->lod_index = 0;
1836 if (p_render_data->render_info) {
1837 uint32_t to_draw = mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
1838 to_draw = _indices_to_primitives(surf->primitive, to_draw);
1839 to_draw *= inst->instance_count;
1840 if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
1841 p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += to_draw;
1842 } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
1843 p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += to_draw;
1844 }
1845 }
1846 }
1847
1848 // ADD Element
1849 if (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
1850#ifdef DEBUG_ENABLED
1851 bool force_alpha = unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW);
1852#else
1853 bool force_alpha = false;
1854#endif
1855 if (!force_alpha && (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
1856 rl->add_element(surf);
1857 }
1858 if (force_alpha || (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) {
1859 render_list[RENDER_LIST_ALPHA].add_element(surf);
1860 }
1861
1862 if (uses_lightmap) {
1863 surf->sort.uses_lightmap = 1; // This needs to become our lightmap index but we'll do that in a separate PR.
1864 }
1865
1866 if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) {
1867 scene_state.used_sss = true;
1868 }
1869 if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) {
1870 scene_state.used_screen_texture = true;
1871 }
1872 if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE) {
1873 scene_state.used_normal_texture = true;
1874 }
1875 if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) {
1876 scene_state.used_depth_texture = true;
1877 }
1878
1879 } else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) {
1880 if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) {
1881 rl->add_element(surf);
1882 }
1883 } else {
1884 if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
1885 rl->add_element(surf);
1886 }
1887 }
1888
1889 surf->sort.depth_layer = depth_layer;
1890
1891 surf = surf->next;
1892 }
1893 }
1894}
1895
1896void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
1897 RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID();
1898 RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? RendererRD::LightStorage::get_singleton()->reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID();
1899
1900 // May do this earlier in RenderSceneRenderRD::render_scene
1901 if (p_index >= (int)scene_state.uniform_buffers.size()) {
1902 uint32_t from = scene_state.uniform_buffers.size();
1903 scene_state.uniform_buffers.resize(p_index + 1);
1904 for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) {
1905 scene_state.uniform_buffers[i] = p_render_data->scene_data->create_uniform_buffer();
1906 }
1907 }
1908
1909 p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers);
1910}
1911
1912void RenderForwardMobile::_fill_element_info(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements) {
1913 RenderList *rl = &render_list[p_render_list];
1914 uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
1915
1916 rl->element_info.resize(p_offset + element_total);
1917
1918 for (uint32_t i = 0; i < element_total; i++) {
1919 GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset];
1920 RenderElementInfo &element_info = rl->element_info[p_offset + i];
1921
1922 element_info.lod_index = surface->lod_index;
1923 element_info.uses_lightmap = surface->sort.uses_lightmap;
1924 }
1925}
1926
1927/// RENDERING ///
1928
1929void RenderForwardMobile::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
1930 //use template for faster performance (pass mode comparisons are inlined)
1931
1932 switch (p_params->pass_mode) {
1933 case PASS_MODE_COLOR: {
1934 _render_list_template<PASS_MODE_COLOR>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
1935 } break;
1936 case PASS_MODE_COLOR_TRANSPARENT: {
1937 _render_list_template<PASS_MODE_COLOR_TRANSPARENT>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
1938 } break;
1939 case PASS_MODE_SHADOW: {
1940 _render_list_template<PASS_MODE_SHADOW>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
1941 } break;
1942 case PASS_MODE_SHADOW_DP: {
1943 _render_list_template<PASS_MODE_SHADOW_DP>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
1944 } break;
1945 case PASS_MODE_DEPTH_MATERIAL: {
1946 _render_list_template<PASS_MODE_DEPTH_MATERIAL>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
1947 } break;
1948 }
1949}
1950
1951void RenderForwardMobile::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) {
1952 uint32_t render_total = p_params->element_count;
1953 uint32_t total_threads = WorkerThreadPool::get_singleton()->get_thread_count();
1954 uint32_t render_from = p_thread * render_total / total_threads;
1955 uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads);
1956 _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to);
1957}
1958
1959void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
1960 RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer);
1961 p_params->framebuffer_format = fb_format;
1962
1963 if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time
1964 //multi threaded
1965 thread_draw_lists.resize(WorkerThreadPool::get_singleton()->get_thread_count());
1966 RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
1967 WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &RenderForwardMobile::_render_list_thread_function, p_params, thread_draw_lists.size(), -1, true, SNAME("ForwardMobileRenderSubpass"));
1968 WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
1969
1970 RD::get_singleton()->draw_list_end(p_params->barrier);
1971 } else {
1972 //single threaded
1973 RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
1974 _render_list(draw_list, fb_format, p_params, 0, p_params->element_count);
1975 RD::get_singleton()->draw_list_end(p_params->barrier);
1976 }
1977}
1978
1979template <RenderForwardMobile::PassMode p_pass_mode>
1980void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
1981 RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
1982
1983 RD::DrawListID draw_list = p_draw_list;
1984 RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
1985
1986 //global scope bindings
1987 RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET);
1988 RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET);
1989 RD::get_singleton()->draw_list_bind_uniform_set(draw_list, scene_shader.default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET);
1990
1991 RID prev_material_uniform_set;
1992
1993 RID prev_vertex_array_rd;
1994 RID prev_index_array_rd;
1995 RID prev_pipeline_rd;
1996 RID prev_xforms_uniform_set;
1997 bool should_request_redraw = false;
1998
1999 bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP);
2000
2001 for (uint32_t i = p_from_element; i < p_to_element; i++) {
2002 const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i];
2003 const RenderElementInfo &element_info = p_params->element_info[i];
2004 const GeometryInstanceForwardMobile *inst = surf->owner;
2005
2006 if (inst->instance_count == 0) {
2007 continue;
2008 }
2009
2010 uint32_t base_spec_constants = p_params->spec_constant_base_flags;
2011
2012 // GeometryInstanceForwardMobile::PushConstant push_constant = inst->push_constant;
2013 GeometryInstanceForwardMobile::PushConstant push_constant;
2014
2015 if (inst->store_transform_cache) {
2016 RendererRD::MaterialStorage::store_transform(inst->transform, push_constant.transform);
2017
2018#ifdef REAL_T_IS_DOUBLE
2019 // Split the origin into two components, the float approximation and the missing precision
2020 // In the shader we will combine these back together to restore the lost precision.
2021 RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &push_constant.transform[12], &push_constant.transform[3]);
2022 RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &push_constant.transform[13], &push_constant.transform[7]);
2023 RendererRD::MaterialStorage::split_double(inst->transform.origin.z, &push_constant.transform[14], &push_constant.transform[11]);
2024#endif
2025 } else {
2026 RendererRD::MaterialStorage::store_transform(Transform3D(), push_constant.transform);
2027 }
2028
2029 push_constant.flags = inst->flags_cache;
2030 push_constant.gi_offset = inst->gi_offset_cache;
2031 push_constant.layer_mask = inst->layer_mask;
2032 push_constant.instance_uniforms_ofs = uint32_t(inst->shader_uniforms_offset);
2033
2034 if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) {
2035 // abuse lightmap_uv_scale[0] here, should not be needed here
2036 push_constant.lightmap_uv_scale[0] = p_params->uv_offset.x;
2037 push_constant.lightmap_uv_scale[1] = p_params->uv_offset.y;
2038 } else {
2039 push_constant.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x;
2040 push_constant.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y;
2041 push_constant.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
2042 push_constant.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
2043 };
2044
2045 RID material_uniform_set;
2046 SceneShaderForwardMobile::ShaderData *shader;
2047 void *mesh_surface;
2048
2049 if (shadow_pass) {
2050 material_uniform_set = surf->material_uniform_set_shadow;
2051 shader = surf->shader_shadow;
2052 mesh_surface = surf->surface_shadow;
2053
2054 } else {
2055 if (inst->use_projector) {
2056 base_spec_constants |= 1 << SPEC_CONSTANT_USING_PROJECTOR;
2057 }
2058 if (inst->use_soft_shadow) {
2059 base_spec_constants |= 1 << SPEC_CONSTANT_USING_SOFT_SHADOWS;
2060 }
2061 forward_id_storage_mobile->fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst);
2062
2063#ifdef DEBUG_ENABLED
2064 if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
2065 material_uniform_set = scene_shader.default_material_uniform_set;
2066 shader = scene_shader.default_material_shader_ptr;
2067 } else if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW)) {
2068 material_uniform_set = scene_shader.overdraw_material_uniform_set;
2069 shader = scene_shader.overdraw_material_shader_ptr;
2070 } else if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS)) {
2071 material_uniform_set = scene_shader.debug_shadow_splits_material_uniform_set;
2072 shader = scene_shader.debug_shadow_splits_material_shader_ptr;
2073 } else {
2074#endif
2075 material_uniform_set = surf->material_uniform_set;
2076 shader = surf->shader;
2077 surf->material->set_as_used();
2078#ifdef DEBUG_ENABLED
2079 }
2080#endif
2081 mesh_surface = surf->surface;
2082 }
2083
2084 if (!mesh_surface) {
2085 continue;
2086 }
2087
2088 //request a redraw if one of the shaders uses TIME
2089 if (shader->uses_time) {
2090 should_request_redraw = true;
2091 }
2092
2093 //find cull variant
2094 SceneShaderForwardMobile::ShaderData::CullVariant cull_variant;
2095
2096 if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
2097 cull_variant = SceneShaderForwardMobile::ShaderData::CULL_VARIANT_DOUBLE_SIDED;
2098 } else {
2099 bool mirror = surf->owner->mirror;
2100 if (p_params->reverse_cull) {
2101 mirror = !mirror;
2102 }
2103 cull_variant = mirror ? SceneShaderForwardMobile::ShaderData::CULL_VARIANT_REVERSED : SceneShaderForwardMobile::ShaderData::CULL_VARIANT_NORMAL;
2104 }
2105
2106 RS::PrimitiveType primitive = surf->primitive;
2107 RID xforms_uniform_set = surf->owner->transforms_uniform_set;
2108
2109 SceneShaderForwardMobile::ShaderVersion shader_version = SceneShaderForwardMobile::SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
2110
2111 switch (p_params->pass_mode) {
2112 case PASS_MODE_COLOR:
2113 case PASS_MODE_COLOR_TRANSPARENT: {
2114 if (element_info.uses_lightmap) {
2115 shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
2116 } else {
2117 shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS;
2118 }
2119 } break;
2120 case PASS_MODE_SHADOW: {
2121 shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS;
2122 } break;
2123 case PASS_MODE_SHADOW_DP: {
2124 ERR_FAIL_COND_MSG(p_params->view_count > 1, "Multiview not supported for shadow DP pass");
2125 shader_version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_DP;
2126 } break;
2127 case PASS_MODE_DEPTH_MATERIAL: {
2128 ERR_FAIL_COND_MSG(p_params->view_count > 1, "Multiview not supported for material pass");
2129 shader_version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
2130 } break;
2131 }
2132
2133 PipelineCacheRD *pipeline = nullptr;
2134
2135 pipeline = &shader->pipelines[cull_variant][primitive][shader_version];
2136
2137 RD::VertexFormatID vertex_format = -1;
2138 RID vertex_array_rd;
2139 RID index_array_rd;
2140
2141 //skeleton and blend shape
2142 if (surf->owner->mesh_instance.is_valid()) {
2143 mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), false, vertex_array_rd, vertex_format);
2144 } else {
2145 mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), false, vertex_array_rd, vertex_format);
2146 }
2147
2148 index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
2149
2150 if (prev_vertex_array_rd != vertex_array_rd) {
2151 RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd);
2152 prev_vertex_array_rd = vertex_array_rd;
2153 }
2154
2155 if (prev_index_array_rd != index_array_rd) {
2156 if (index_array_rd.is_valid()) {
2157 RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array_rd);
2158 }
2159 prev_index_array_rd = index_array_rd;
2160 }
2161
2162 RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, p_params->subpass, base_spec_constants);
2163
2164 if (pipeline_rd != prev_pipeline_rd) {
2165 // checking with prev shader does not make so much sense, as
2166 // the pipeline may still be different.
2167 RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline_rd);
2168 prev_pipeline_rd = pipeline_rd;
2169 }
2170
2171 if (xforms_uniform_set.is_valid() && prev_xforms_uniform_set != xforms_uniform_set) {
2172 RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, TRANSFORMS_UNIFORM_SET);
2173 prev_xforms_uniform_set = xforms_uniform_set;
2174 }
2175
2176 if (material_uniform_set != prev_material_uniform_set) {
2177 // Update uniform set.
2178 if (material_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set.
2179 RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET);
2180 }
2181
2182 prev_material_uniform_set = material_uniform_set;
2183 }
2184
2185 RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(GeometryInstanceForwardMobile::PushConstant));
2186
2187 uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : 1;
2188 if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) {
2189 instance_count /= surf->owner->trail_steps;
2190 }
2191
2192 RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
2193 }
2194
2195 // Make the actual redraw request
2196 if (should_request_redraw) {
2197 RenderingServerDefault::redraw_request();
2198 }
2199}
2200
2201/* Geometry instance */
2202
2203RenderGeometryInstance *RenderForwardMobile::geometry_instance_create(RID p_base) {
2204 RS::InstanceType type = RSG::utilities->get_base_type(p_base);
2205 ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr);
2206
2207 GeometryInstanceForwardMobile *ginstance = geometry_instance_alloc.alloc();
2208 ginstance->data = memnew(GeometryInstanceForwardMobile::Data);
2209
2210 ginstance->data->base = p_base;
2211 ginstance->data->base_type = type;
2212 ginstance->data->dependency_tracker.userdata = ginstance;
2213 ginstance->data->dependency_tracker.changed_callback = _geometry_instance_dependency_changed;
2214 ginstance->data->dependency_tracker.deleted_callback = _geometry_instance_dependency_deleted;
2215
2216 ginstance->_mark_dirty();
2217
2218 return ginstance;
2219}
2220
2221void RenderForwardMobile::GeometryInstanceForwardMobile::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
2222 lightmap_instance = p_lightmap_instance;
2223 lightmap_uv_scale = p_lightmap_uv_scale;
2224 lightmap_slice_index = p_lightmap_slice_index;
2225
2226 _mark_dirty();
2227}
2228
2229void RenderForwardMobile::GeometryInstanceForwardMobile::set_lightmap_capture(const Color *p_sh9) {
2230 if (p_sh9) {
2231 if (lightmap_sh == nullptr) {
2232 lightmap_sh = RenderForwardMobile::get_singleton()->geometry_instance_lightmap_sh.alloc();
2233 }
2234
2235 memcpy(lightmap_sh->sh, p_sh9, sizeof(Color) * 9);
2236 } else {
2237 if (lightmap_sh != nullptr) {
2238 RenderForwardMobile::get_singleton()->geometry_instance_lightmap_sh.free(lightmap_sh);
2239 lightmap_sh = nullptr;
2240 }
2241 }
2242 _mark_dirty();
2243}
2244
2245void RenderForwardMobile::geometry_instance_free(RenderGeometryInstance *p_geometry_instance) {
2246 GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
2247 ERR_FAIL_COND(!ginstance);
2248 if (ginstance->lightmap_sh != nullptr) {
2249 geometry_instance_lightmap_sh.free(ginstance->lightmap_sh);
2250 }
2251 GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches;
2252 while (surf) {
2253 GeometryInstanceSurfaceDataCache *next = surf->next;
2254 geometry_instance_surface_alloc.free(surf);
2255 surf = next;
2256 }
2257 memdelete(ginstance->data);
2258 geometry_instance_alloc.free(ginstance);
2259}
2260
2261uint32_t RenderForwardMobile::geometry_instance_get_pair_mask() {
2262 return ((1 << RS::INSTANCE_LIGHT) + (1 << RS::INSTANCE_REFLECTION_PROBE) + (1 << RS::INSTANCE_DECAL));
2263}
2264
2265void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) {
2266 omni_light_count = 0;
2267 spot_light_count = 0;
2268
2269 for (uint32_t i = 0; i < p_light_instance_count; i++) {
2270 RS::LightType type = RendererRD::LightStorage::get_singleton()->light_instance_get_type(p_light_instances[i]);
2271 switch (type) {
2272 case RS::LIGHT_OMNI: {
2273 if (omni_light_count < (uint32_t)MAX_RDL_CULL) {
2274 omni_lights[omni_light_count] = RendererRD::LightStorage::get_singleton()->light_instance_get_forward_id(p_light_instances[i]);
2275 omni_light_count++;
2276 }
2277 } break;
2278 case RS::LIGHT_SPOT: {
2279 if (spot_light_count < (uint32_t)MAX_RDL_CULL) {
2280 spot_lights[spot_light_count] = RendererRD::LightStorage::get_singleton()->light_instance_get_forward_id(p_light_instances[i]);
2281 spot_light_count++;
2282 }
2283 } break;
2284 default:
2285 break;
2286 }
2287 }
2288}
2289
2290void RenderForwardMobile::GeometryInstanceForwardMobile::pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
2291 reflection_probe_count = p_reflection_probe_instance_count < (uint32_t)MAX_RDL_CULL ? p_reflection_probe_instance_count : (uint32_t)MAX_RDL_CULL;
2292 for (uint32_t i = 0; i < reflection_probe_count; i++) {
2293 reflection_probes[i] = RendererRD::LightStorage::get_singleton()->reflection_probe_instance_get_forward_id(p_reflection_probe_instances[i]);
2294 }
2295}
2296
2297void RenderForwardMobile::GeometryInstanceForwardMobile::pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) {
2298 decals_count = p_decal_instance_count < (uint32_t)MAX_RDL_CULL ? p_decal_instance_count : (uint32_t)MAX_RDL_CULL;
2299 for (uint32_t i = 0; i < decals_count; i++) {
2300 decals[i] = RendererRD::TextureStorage::get_singleton()->decal_instance_get_forward_id(p_decal_instances[i]);
2301 }
2302}
2303
2304void RenderForwardMobile::GeometryInstanceForwardMobile::set_softshadow_projector_pairing(bool p_softshadow, bool p_projector) {
2305 use_projector = p_projector;
2306 use_soft_shadow = p_softshadow;
2307}
2308
2309void RenderForwardMobile::GeometryInstanceForwardMobile::_mark_dirty() {
2310 if (dirty_list_element.in_list()) {
2311 return;
2312 }
2313
2314 //clear surface caches
2315 GeometryInstanceSurfaceDataCache *surf = surface_caches;
2316
2317 while (surf) {
2318 GeometryInstanceSurfaceDataCache *next = surf->next;
2319 RenderForwardMobile::get_singleton()->geometry_instance_surface_alloc.free(surf);
2320 surf = next;
2321 }
2322
2323 surface_caches = nullptr;
2324
2325 RenderForwardMobile::get_singleton()->geometry_instance_dirty_list.add(&dirty_list_element);
2326}
2327
2328void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
2329 RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
2330
2331 bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
2332 bool has_base_alpha = p_material->shader_data->uses_alpha && (!p_material->shader_data->uses_alpha_clip || p_material->shader_data->uses_alpha_antialiasing);
2333 bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
2334 bool has_alpha = has_base_alpha || has_blend_alpha || has_read_screen_alpha;
2335
2336 uint32_t flags = 0;
2337
2338 if (p_material->shader_data->uses_sss) {
2339 flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING;
2340 }
2341
2342 if (p_material->shader_data->uses_screen_texture) {
2343 flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE;
2344 }
2345
2346 if (p_material->shader_data->uses_depth_texture) {
2347 flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE;
2348 }
2349
2350 if (p_material->shader_data->uses_normal_texture) {
2351 flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE;
2352 }
2353
2354 if (ginstance->data->cast_double_sided_shadows) {
2355 flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS;
2356 }
2357
2358 if (has_alpha || p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED) {
2359 //material is only meant for alpha pass
2360 flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA;
2361 if ((p_material->shader_data->uses_depth_prepass_alpha || p_material->shader_data->uses_alpha_antialiasing) && !(p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED)) {
2362 flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH;
2363 flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
2364 }
2365 } else {
2366 flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE;
2367 flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH;
2368 flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
2369 }
2370
2371 if (p_material->shader_data->uses_particle_trails) {
2372 flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS;
2373 }
2374
2375 SceneShaderForwardMobile::MaterialData *material_shadow = nullptr;
2376 void *surface_shadow = nullptr;
2377 if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing) {
2378 flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
2379 material_shadow = static_cast<SceneShaderForwardMobile::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
2380
2381 RID shadow_mesh = mesh_storage->mesh_get_shadow_mesh(p_mesh);
2382
2383 if (shadow_mesh.is_valid()) {
2384 surface_shadow = mesh_storage->mesh_get_surface(shadow_mesh, p_surface);
2385 }
2386
2387 } else {
2388 material_shadow = p_material;
2389 }
2390
2391 GeometryInstanceSurfaceDataCache *sdcache = geometry_instance_surface_alloc.alloc();
2392
2393 sdcache->flags = flags;
2394
2395 sdcache->shader = p_material->shader_data;
2396 sdcache->material = p_material;
2397 sdcache->material_uniform_set = p_material->uniform_set;
2398 sdcache->surface = mesh_storage->mesh_get_surface(p_mesh, p_surface);
2399 sdcache->primitive = mesh_storage->mesh_surface_get_primitive(sdcache->surface);
2400 sdcache->surface_index = p_surface;
2401
2402 if (ginstance->data->dirty_dependencies) {
2403 RSG::utilities->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker);
2404 }
2405
2406 //shadow
2407 sdcache->shader_shadow = material_shadow->shader_data;
2408 sdcache->material_uniform_set_shadow = material_shadow->uniform_set;
2409
2410 sdcache->surface_shadow = surface_shadow ? surface_shadow : sdcache->surface;
2411
2412 sdcache->owner = ginstance;
2413
2414 sdcache->next = ginstance->surface_caches;
2415 ginstance->surface_caches = sdcache;
2416
2417 //sortkey
2418
2419 sdcache->sort.sort_key1 = 0;
2420 sdcache->sort.sort_key2 = 0;
2421
2422 sdcache->sort.surface_index = p_surface;
2423 sdcache->sort.material_id_low = p_material_id & 0x0000FFFF;
2424 sdcache->sort.material_id_hi = p_material_id >> 16;
2425 sdcache->sort.shader_id = p_shader_id;
2426 sdcache->sort.geometry_id = p_mesh.get_local_index();
2427 // sdcache->sort.uses_forward_gi = ginstance->can_sdfgi;
2428 sdcache->sort.priority = p_material->priority;
2429}
2430
2431void RenderForwardMobile::_geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, RID p_mat_src, RID p_mesh) {
2432 SceneShaderForwardMobile::MaterialData *material = p_material;
2433 RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
2434
2435 _geometry_instance_add_surface_with_material(ginstance, p_surface, material, p_mat_src.get_local_index(), material_storage->material_get_shader_id(p_mat_src), p_mesh);
2436
2437 while (material->next_pass.is_valid()) {
2438 RID next_pass = material->next_pass;
2439 material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(next_pass, RendererRD::MaterialStorage::SHADER_TYPE_3D));
2440 if (!material || !material->shader_data->valid) {
2441 break;
2442 }
2443 if (ginstance->data->dirty_dependencies) {
2444 material_storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker);
2445 }
2446 _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), material_storage->material_get_shader_id(next_pass), p_mesh);
2447 }
2448}
2449
2450void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
2451 RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
2452 RID m_src;
2453
2454 m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material;
2455
2456 SceneShaderForwardMobile::MaterialData *material = nullptr;
2457
2458 if (m_src.is_valid()) {
2459 material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::MaterialStorage::SHADER_TYPE_3D));
2460 if (!material || !material->shader_data->valid) {
2461 material = nullptr;
2462 }
2463 }
2464
2465 if (material) {
2466 if (ginstance->data->dirty_dependencies) {
2467 material_storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
2468 }
2469 } else {
2470 material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
2471 m_src = scene_shader.default_material;
2472 }
2473
2474 ERR_FAIL_COND(!material);
2475
2476 _geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material, m_src, p_mesh);
2477
2478 if (ginstance->data->material_overlay.is_valid()) {
2479 m_src = ginstance->data->material_overlay;
2480
2481 material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::MaterialStorage::SHADER_TYPE_3D));
2482 if (material && material->shader_data->valid) {
2483 if (ginstance->data->dirty_dependencies) {
2484 material_storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
2485 }
2486
2487 _geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material, m_src, p_mesh);
2488 }
2489 }
2490}
2491
2492void RenderForwardMobile::_geometry_instance_update(RenderGeometryInstance *p_geometry_instance) {
2493 RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
2494 RendererRD::ParticlesStorage *particles_storage = RendererRD::ParticlesStorage::get_singleton();
2495 GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
2496
2497 if (ginstance->data->dirty_dependencies) {
2498 ginstance->data->dependency_tracker.update_begin();
2499 }
2500
2501 //add geometry for drawing
2502 switch (ginstance->data->base_type) {
2503 case RS::INSTANCE_MESH: {
2504 const RID *materials = nullptr;
2505 uint32_t surface_count;
2506 RID mesh = ginstance->data->base;
2507
2508 materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
2509 if (materials) {
2510 //if no materials, no surfaces.
2511 const RID *inst_materials = ginstance->data->surface_materials.ptr();
2512 uint32_t surf_mat_count = ginstance->data->surface_materials.size();
2513
2514 for (uint32_t j = 0; j < surface_count; j++) {
2515 RID material = (j < surf_mat_count && inst_materials[j].is_valid()) ? inst_materials[j] : materials[j];
2516 _geometry_instance_add_surface(ginstance, j, material, mesh);
2517 }
2518 }
2519
2520 ginstance->instance_count = 1;
2521
2522 } break;
2523
2524 case RS::INSTANCE_MULTIMESH: {
2525 RID mesh = mesh_storage->multimesh_get_mesh(ginstance->data->base);
2526 if (mesh.is_valid()) {
2527 const RID *materials = nullptr;
2528 uint32_t surface_count;
2529
2530 materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
2531 if (materials) {
2532 for (uint32_t j = 0; j < surface_count; j++) {
2533 _geometry_instance_add_surface(ginstance, j, materials[j], mesh);
2534 }
2535 }
2536
2537 ginstance->instance_count = mesh_storage->multimesh_get_instances_to_draw(ginstance->data->base);
2538 }
2539
2540 } break;
2541#if 0
2542 case RS::INSTANCE_IMMEDIATE: {
2543 RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.get_or_null(inst->base);
2544 ERR_CONTINUE(!immediate);
2545
2546 _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass);
2547
2548 } break;
2549#endif
2550 case RS::INSTANCE_PARTICLES: {
2551 int draw_passes = particles_storage->particles_get_draw_passes(ginstance->data->base);
2552
2553 for (int j = 0; j < draw_passes; j++) {
2554 RID mesh = particles_storage->particles_get_draw_pass_mesh(ginstance->data->base, j);
2555 if (!mesh.is_valid()) {
2556 continue;
2557 }
2558
2559 const RID *materials = nullptr;
2560 uint32_t surface_count;
2561
2562 materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
2563 if (materials) {
2564 for (uint32_t k = 0; k < surface_count; k++) {
2565 _geometry_instance_add_surface(ginstance, k, materials[k], mesh);
2566 }
2567 }
2568 }
2569
2570 ginstance->instance_count = particles_storage->particles_get_amount(ginstance->data->base, ginstance->trail_steps);
2571
2572 } break;
2573
2574 default: {
2575 }
2576 }
2577
2578 //Fill push constant
2579
2580 bool store_transform = true;
2581 ginstance->base_flags = 0;
2582
2583 if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
2584 ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
2585 if (mesh_storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
2586 ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
2587 }
2588 if (mesh_storage->multimesh_uses_colors(ginstance->data->base)) {
2589 ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
2590 }
2591 if (mesh_storage->multimesh_uses_custom_data(ginstance->data->base)) {
2592 ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
2593 }
2594
2595 ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
2596
2597 } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
2598 ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
2599 if (false) { // 2D particles
2600 ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
2601 }
2602
2603 ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
2604 ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
2605
2606 //for particles, stride is the trail size
2607 ginstance->base_flags |= (ginstance->trail_steps << INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT);
2608
2609 if (!particles_storage->particles_is_using_local_coords(ginstance->data->base)) {
2610 store_transform = false;
2611 }
2612 ginstance->transforms_uniform_set = particles_storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
2613
2614 if (particles_storage->particles_get_frame_counter(ginstance->data->base) == 0) {
2615 // Particles haven't been cleared or updated, update once now to ensure they are ready to render.
2616 particles_storage->update_particles();
2617 }
2618
2619 if (ginstance->data->dirty_dependencies) {
2620 particles_storage->particles_update_dependency(ginstance->data->base, &ginstance->data->dependency_tracker);
2621 }
2622 } else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
2623 if (mesh_storage->skeleton_is_valid(ginstance->data->skeleton)) {
2624 ginstance->transforms_uniform_set = mesh_storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
2625 if (ginstance->data->dirty_dependencies) {
2626 mesh_storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker);
2627 }
2628 } else {
2629 ginstance->transforms_uniform_set = RID();
2630 }
2631 }
2632
2633 ginstance->store_transform_cache = store_transform;
2634
2635 if (ginstance->data->dirty_dependencies) {
2636 ginstance->data->dependency_tracker.update_end();
2637 ginstance->data->dirty_dependencies = false;
2638 }
2639
2640 ginstance->dirty_list_element.remove_from_list();
2641}
2642
2643void RenderForwardMobile::_update_dirty_geometry_instances() {
2644 while (geometry_instance_dirty_list.first()) {
2645 _geometry_instance_update(geometry_instance_dirty_list.first()->self());
2646 }
2647}
2648
2649void RenderForwardMobile::_geometry_instance_dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker) {
2650 switch (p_notification) {
2651 case Dependency::DEPENDENCY_CHANGED_MATERIAL:
2652 case Dependency::DEPENDENCY_CHANGED_MESH:
2653 case Dependency::DEPENDENCY_CHANGED_PARTICLES:
2654 case Dependency::DEPENDENCY_CHANGED_MULTIMESH:
2655 case Dependency::DEPENDENCY_CHANGED_SKELETON_DATA: {
2656 static_cast<RenderGeometryInstance *>(p_tracker->userdata)->_mark_dirty();
2657 static_cast<GeometryInstanceForwardMobile *>(p_tracker->userdata)->data->dirty_dependencies = true;
2658 } break;
2659 case Dependency::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
2660 GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_tracker->userdata);
2661 if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
2662 ginstance->instance_count = RendererRD::MeshStorage::get_singleton()->multimesh_get_instances_to_draw(ginstance->data->base);
2663 }
2664 } break;
2665 default: {
2666 //rest of notifications of no interest
2667 } break;
2668 }
2669}
2670void RenderForwardMobile::_geometry_instance_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker) {
2671 static_cast<RenderGeometryInstance *>(p_tracker->userdata)->_mark_dirty();
2672 static_cast<GeometryInstanceForwardMobile *>(p_tracker->userdata)->data->dirty_dependencies = true;
2673}
2674
2675/* misc */
2676
2677bool RenderForwardMobile::is_dynamic_gi_supported() const {
2678 return false;
2679}
2680
2681bool RenderForwardMobile::is_volumetric_supported() const {
2682 return false;
2683}
2684
2685uint32_t RenderForwardMobile::get_max_elements() const {
2686 return 256;
2687}
2688
2689RenderForwardMobile *RenderForwardMobile::singleton = nullptr;
2690
2691void RenderForwardMobile::_update_shader_quality_settings() {
2692 Vector<RD::PipelineSpecializationConstant> spec_constants;
2693
2694 RD::PipelineSpecializationConstant sc;
2695 sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
2696
2697 sc.constant_id = SPEC_CONSTANT_SOFT_SHADOW_SAMPLES;
2698 sc.int_value = soft_shadow_samples_get();
2699
2700 spec_constants.push_back(sc);
2701
2702 sc.constant_id = SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES;
2703 sc.int_value = penumbra_shadow_samples_get();
2704
2705 spec_constants.push_back(sc);
2706
2707 sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES;
2708 sc.int_value = directional_soft_shadow_samples_get();
2709
2710 spec_constants.push_back(sc);
2711
2712 sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES;
2713 sc.int_value = directional_penumbra_shadow_samples_get();
2714
2715 spec_constants.push_back(sc);
2716
2717 sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
2718 sc.constant_id = SPEC_CONSTANT_DECAL_USE_MIPMAPS;
2719 sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS ||
2720 decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS ||
2721 decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
2722 decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
2723
2724 spec_constants.push_back(sc);
2725
2726 sc.constant_id = SPEC_CONSTANT_PROJECTOR_USE_MIPMAPS;
2727 sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS ||
2728 light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS ||
2729 light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
2730 light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
2731
2732 spec_constants.push_back(sc);
2733
2734 scene_shader.set_default_specialization_constants(spec_constants);
2735
2736 base_uniforms_changed(); //also need this
2737}
2738
2739RenderForwardMobile::RenderForwardMobile() {
2740 singleton = this;
2741
2742 sky.set_texture_format(_render_buffers_get_color_format());
2743
2744 String defines;
2745
2746 defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n";
2747 if (is_using_radiance_cubemap_array()) {
2748 defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
2749 }
2750 // defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
2751 defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
2752
2753 {
2754 //lightmaps
2755 scene_state.max_lightmaps = 2;
2756 defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n";
2757 defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n";
2758
2759 scene_state.lightmap_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapData) * scene_state.max_lightmaps);
2760 }
2761 {
2762 //captures
2763 scene_state.max_lightmap_captures = 2048;
2764 scene_state.lightmap_captures = memnew_arr(LightmapCaptureData, scene_state.max_lightmap_captures);
2765 scene_state.lightmap_capture_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapCaptureData) * scene_state.max_lightmap_captures);
2766 }
2767 {
2768 defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n";
2769 defines += "\n#define SAMPLERS_BINDING_FIRST_INDEX " + itos(SAMPLERS_BINDING_FIRST_INDEX) + "\n";
2770 }
2771#ifdef REAL_T_IS_DOUBLE
2772 {
2773 defines += "\n#define USE_DOUBLE_PRECISION \n";
2774 }
2775#endif
2776
2777 scene_shader.init(defines);
2778
2779 // !BAS! maybe we need a mobile version of this setting?
2780 render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
2781
2782 _update_shader_quality_settings();
2783}
2784
2785RenderForwardMobile::~RenderForwardMobile() {
2786 RSG::light_storage->directional_shadow_atlas_set_size(0);
2787
2788 //clear base uniform set if still valid
2789 for (uint32_t i = 0; i < render_pass_uniform_sets.size(); i++) {
2790 if (render_pass_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[i])) {
2791 RD::get_singleton()->free(render_pass_uniform_sets[i]);
2792 }
2793 }
2794
2795 {
2796 for (const RID &rid : scene_state.uniform_buffers) {
2797 RD::get_singleton()->free(rid);
2798 }
2799 RD::get_singleton()->free(scene_state.lightmap_buffer);
2800 RD::get_singleton()->free(scene_state.lightmap_capture_buffer);
2801 memdelete_arr(scene_state.lightmap_captures);
2802 }
2803}
2804