diff options
Diffstat (limited to 'servers/rendering/renderer_rd')
33 files changed, 4849 insertions, 3740 deletions
diff --git a/servers/rendering/renderer_rd/effects/fsr.cpp b/servers/rendering/renderer_rd/effects/fsr.cpp index 5fde24a926..92b34ede0e 100644 --- a/servers/rendering/renderer_rd/effects/fsr.cpp +++ b/servers/rendering/renderer_rd/effects/fsr.cpp @@ -29,7 +29,8 @@ /*************************************************************************/ #include "fsr.h" -#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h" +#include "../storage_rd/material_storage.h" +#include "../uniform_set_cache_rd.h" using namespace RendererRD; diff --git a/servers/rendering/renderer_rd/effects/fsr.h b/servers/rendering/renderer_rd/effects/fsr.h index 1adfba527a..69088e526a 100644 --- a/servers/rendering/renderer_rd/effects/fsr.h +++ b/servers/rendering/renderer_rd/effects/fsr.h @@ -31,11 +31,10 @@ #ifndef FSR_RD_H #define FSR_RD_H -#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" -#include "servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl.gen.h" -#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h" +#include "../pipeline_cache_rd.h" +#include "../shaders/effects/fsr_upscale.glsl.gen.h" +#include "../storage_rd/render_scene_buffers_rd.h" #include "servers/rendering/renderer_scene_render.h" - #include "servers/rendering_server.h" namespace RendererRD { diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp index 582c5abbdd..1cbc52dec3 100644 --- a/servers/rendering/renderer_rd/effects/ss_effects.cpp +++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp @@ -30,6 +30,7 @@ #include "ss_effects.h" +#include "core/config/project_settings.h" #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #include "servers/rendering/renderer_rd/storage_rd/material_storage.h" #include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h" @@ -50,8 +51,8 @@ static _FORCE_INLINE_ void store_camera(const Projection &p_mtx, float *p_array) SSEffects::SSEffects() { singleton = this; + // Initialize depth buffer for screen space effects { - // Initialize depth buffer for screen space effects Vector<String> downsampler_modes; downsampler_modes.push_back("\n"); downsampler_modes.push_back("\n#define USE_HALF_SIZE\n"); @@ -100,6 +101,7 @@ SSEffects::SSEffects() { } // Initialize Screen Space Indirect Lighting (SSIL) + ssil_set_quality(RS::EnvironmentSSILQuality(int(GLOBAL_GET("rendering/environment/ssil/quality"))), GLOBAL_GET("rendering/environment/ssil/half_size"), GLOBAL_GET("rendering/environment/ssil/adaptive_target"), GLOBAL_GET("rendering/environment/ssil/blur_passes"), GLOBAL_GET("rendering/environment/ssil/fadeout_from"), GLOBAL_GET("rendering/environment/ssil/fadeout_to")); { Vector<String> ssil_modes; @@ -175,9 +177,10 @@ SSEffects::SSEffects() { } } - { - // Initialize Screen Space Ambient Occlusion (SSAO) + // Initialize Screen Space Ambient Occlusion (SSAO) + ssao_set_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to")); + { RD::SamplerState sampler; sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; @@ -276,9 +279,10 @@ SSEffects::SSEffects() { ss_effects.mirror_sampler = RD::get_singleton()->sampler_create(sampler); } - { - // Screen Space Reflections + // Screen Space Reflections + ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/environment/screen_space_reflection/roughness_quality"))); + { Vector<RD::PipelineSpecializationConstant> specialization_constants; { @@ -336,6 +340,10 @@ SSEffects::SSEffects() { } // Subsurface scattering + sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality"))); + sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale"); + sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale"); + { Vector<String> sss_modes; sss_modes.push_back("\n#define USE_11_SAMPLES\n"); @@ -403,7 +411,7 @@ SSEffects::~SSEffects() { /* SS Downsampler */ -void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const Projection &p_projection) { +void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, bool p_invalidate_uniform_set, Size2i p_full_screen_size, const Projection &p_projection) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -413,9 +421,9 @@ void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); int downsample_mode = SS_EFFECTS_DOWNSAMPLE; - bool use_mips = p_ssao_quality > RS::ENV_SSAO_QUALITY_MEDIUM || p_ssil_quality > RS::ENV_SSIL_QUALITY_MEDIUM; + bool use_mips = ssao_quality > RS::ENV_SSAO_QUALITY_MEDIUM || ssil_quality > RS::ENV_SSIL_QUALITY_MEDIUM; - if (p_ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW && p_ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW && ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { downsample_mode = SS_EFFECTS_DOWNSAMPLE_HALF; } else if (use_mips) { downsample_mode = SS_EFFECTS_DOWNSAMPLE_MIPMAP; @@ -424,10 +432,10 @@ void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_ bool use_half_size = false; bool use_full_mips = false; - if (p_ssao_half_size && p_ssil_half_size) { + if (ssao_half_size && ssil_half_size) { downsample_mode++; use_half_size = true; - } else if (p_ssao_half_size != p_ssil_half_size) { + } else if (ssao_half_size != ssil_half_size) { if (use_mips) { downsample_mode = SS_EFFECTS_DOWNSAMPLE_FULL_MIPS; use_full_mips = true; @@ -526,12 +534,21 @@ void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_ /* SSIL */ +void SSEffects::ssil_set_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { + ssil_quality = p_quality; + ssil_half_size = p_half_size; + ssil_adaptive_target = p_adaptive_target; + ssil_blur_passes = p_blur_passes; + ssil_fadeout_from = p_fadeout_from; + ssil_fadeout_to = p_fadeout_to; +} + void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> p_ssil_slices, const Vector<RID> p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0); - if ((p_settings.quality == RS::ENV_SSIL_QUALITY_ULTRA) && !p_adaptive_base_pass) { + if ((ssil_quality == RS::ENV_SSIL_QUALITY_ULTRA) && !p_adaptive_base_pass) { RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 1); } RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_projection_uniform_set, 3); @@ -539,7 +556,7 @@ void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> RID shader = ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 0); for (int i = 0; i < 4; i++) { - if ((p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + if ((ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { continue; } @@ -554,7 +571,7 @@ void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, uniform_set_cache->get_cache(shader, 2, u_ssil_slice, u_edges_slice), 2); RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssil.gather_push_constant, sizeof(SSILGatherPushConstant)); - Size2i size = Size2i(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)); + Size2i size = Size2i(p_settings.full_screen_size.x >> (ssil_half_size ? 2 : 1), p_settings.full_screen_size.y >> (ssil_half_size ? 2 : 1)); RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1); } @@ -562,11 +579,11 @@ void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> } void SSEffects::ssil_allocate_buffers(SSILRenderBuffers &p_ssil_buffers, const SSILSettings &p_settings, RID p_linear_depth) { - if (p_ssil_buffers.half_size != p_settings.half_size) { + if (p_ssil_buffers.half_size != ssil_half_size) { ssil_free(p_ssil_buffers); } - if (p_settings.half_size) { + if (ssil_half_size) { p_ssil_buffers.buffer_width = (p_settings.full_screen_size.x + 3) / 4; p_ssil_buffers.buffer_height = (p_settings.full_screen_size.y + 3) / 4; p_ssil_buffers.half_buffer_width = (p_settings.full_screen_size.x + 7) / 8; @@ -580,7 +597,7 @@ void SSEffects::ssil_allocate_buffers(SSILRenderBuffers &p_ssil_buffers, const S if (p_ssil_buffers.ssil_final.is_null()) { { - p_ssil_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, p_settings.half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY); + p_ssil_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, ssil_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY); } { RD::TextureFormat tf; @@ -665,7 +682,7 @@ void SSEffects::ssil_allocate_buffers(SSILRenderBuffers &p_ssil_buffers, const S p_ssil_buffers.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); RD::get_singleton()->set_resource_name(p_ssil_buffers.importance_map[1], "SSIL Importance Map Pong"); } - p_ssil_buffers.half_size = p_settings.half_size; + p_ssil_buffers.half_size = ssil_half_size; } } @@ -711,26 +728,26 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers ssil.gather_push_constant.radius = p_settings.radius; float radius_near_limit = (p_settings.radius * 1.2f); - if (p_settings.quality <= RS::ENV_SSIL_QUALITY_LOW) { + if (ssil_quality <= RS::ENV_SSIL_QUALITY_LOW) { radius_near_limit *= 1.50f; - if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + if (ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { ssil.gather_push_constant.radius *= 0.8f; } } radius_near_limit /= tan_half_fov_y; ssil.gather_push_constant.intensity = p_settings.intensity * Math_PI; - ssil.gather_push_constant.fade_out_mul = -1.0 / (p_settings.fadeout_to - p_settings.fadeout_from); - ssil.gather_push_constant.fade_out_add = p_settings.fadeout_from / (p_settings.fadeout_to - p_settings.fadeout_from) + 1.0; + ssil.gather_push_constant.fade_out_mul = -1.0 / (ssil_fadeout_to - ssil_fadeout_from); + ssil.gather_push_constant.fade_out_add = ssil_fadeout_from / (ssil_fadeout_to - ssil_fadeout_from) + 1.0; ssil.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit; ssil.gather_push_constant.neg_inv_radius = -1.0 / ssil.gather_push_constant.radius; ssil.gather_push_constant.normal_rejection_amount = p_settings.normal_rejection; ssil.gather_push_constant.load_counter_avg_div = 9.0 / float((p_ssil_buffers.half_buffer_width) * (p_ssil_buffers.half_buffer_height) * 255); - ssil.gather_push_constant.adaptive_sample_limit = p_settings.adaptive_target; + ssil.gather_push_constant.adaptive_sample_limit = ssil_adaptive_target; - ssil.gather_push_constant.quality = MAX(0, p_settings.quality - 1); - ssil.gather_push_constant.size_multiplier = p_settings.half_size ? 2 : 1; + ssil.gather_push_constant.quality = MAX(0, ssil_quality - 1); + ssil.gather_push_constant.size_multiplier = ssil_half_size ? 2 : 1; if (p_ssil_buffers.projection_uniform_set.is_null()) { Vector<RD::Uniform> uniforms; @@ -806,7 +823,7 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers p_ssil_buffers.importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 2), 1); } - if (p_settings.quality == RS::ENV_SSIL_QUALITY_ULTRA) { + if (ssil_quality == RS::ENV_SSIL_QUALITY_ULTRA) { RD::get_singleton()->draw_command_begin_label("Generate Importance Map"); ssil.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssil_buffers.buffer_width; ssil.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssil_buffers.buffer_height; @@ -865,13 +882,13 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers ssil.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssil_buffers.buffer_width; ssil.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssil_buffers.buffer_height; - int blur_passes = p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW ? p_settings.blur_passes : 1; + int blur_passes = ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW ? ssil_blur_passes : 1; shader = ssil.blur_shader.version_get_shader(ssil.blur_shader_version, 0); for (int pass = 0; pass < blur_passes; pass++) { int blur_pipeline = SSIL_BLUR_PASS; - if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW) { + if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW) { blur_pipeline = SSIL_BLUR_PASS_SMART; if (pass < blur_passes - 2) { blur_pipeline = SSIL_BLUR_PASS_WIDE; @@ -879,13 +896,13 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers } for (int i = 0; i < 4; i++) { - if ((p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + if ((ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { continue; } RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[blur_pipeline]); if (pass % 2 == 0) { - if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + if (ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { RD::Uniform u_ssil_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.deinterleaved_slices[i] })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ssil_slice), 0); } else { @@ -896,7 +913,7 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers RD::Uniform u_ssil_pong_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_buffers.pong_slices[i] })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ssil_pong_slice), 1); } else { - if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + if (ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { RD::Uniform u_ssil_pong_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.pong_slices[i] })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ssil_pong_slice), 0); } else { @@ -913,11 +930,11 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.blur_push_constant, sizeof(SSILBlurPushConstant)); - int x_groups = (p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1)); - int y_groups = (p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)); + int x_groups = (p_settings.full_screen_size.x >> (ssil_half_size ? 2 : 1)); + int y_groups = (p_settings.full_screen_size.y >> (ssil_half_size ? 2 : 1)); RD::get_singleton()->compute_list_dispatch_threads(compute_list, x_groups, y_groups, 1); - if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW) { + if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW) { RD::get_singleton()->compute_list_add_barrier(compute_list); } } @@ -931,12 +948,12 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers ssil.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness; ssil.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; ssil.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; - ssil.interleave_push_constant.size_modifier = uint32_t(p_settings.half_size ? 4 : 2); + ssil.interleave_push_constant.size_modifier = uint32_t(ssil_half_size ? 4 : 2); int interleave_pipeline = SSIL_INTERLEAVE_HALF; - if (p_settings.quality == RS::ENV_SSIL_QUALITY_LOW) { + if (ssil_quality == RS::ENV_SSIL_QUALITY_LOW) { interleave_pipeline = SSIL_INTERLEAVE; - } else if (p_settings.quality >= RS::ENV_SSIL_QUALITY_MEDIUM) { + } else if (ssil_quality >= RS::ENV_SSIL_QUALITY_MEDIUM) { interleave_pipeline = SSIL_INTERLEAVE_SMART; } @@ -947,7 +964,7 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers RD::Uniform u_destination(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_buffers.ssil_final })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_destination), 0); - if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW && p_settings.blur_passes % 2 == 0) { + if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW && ssil_blur_passes % 2 == 0) { RD::Uniform u_ssil(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.deinterleaved })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ssil), 1); } else { @@ -1003,19 +1020,28 @@ void SSEffects::ssil_free(SSILRenderBuffers &p_ssil_buffers) { /* SSAO */ +void SSEffects::ssao_set_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { + ssao_quality = p_quality; + ssao_half_size = p_half_size; + ssao_adaptive_target = p_adaptive_target; + ssao_blur_passes = p_blur_passes; + ssao_fadeout_from = p_fadeout_from; + ssao_fadeout_to = p_fadeout_to; +} + void SSEffects::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0); - if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) { + if ((ssao_quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) { RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 0); } RID shader = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 1); // for (int i = 0; i < 4; i++) { - if ((p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + if ((ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { continue; } @@ -1029,7 +1055,7 @@ void SSEffects::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, uniform_set_cache->get_cache(shader, 2, u_ao_slice), 2); RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssao.gather_push_constant, sizeof(SSAOGatherPushConstant)); - Size2i size = Size2i(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)); + Size2i size = Size2i(p_settings.full_screen_size.x >> (ssao_half_size ? 2 : 1), p_settings.full_screen_size.y >> (ssao_half_size ? 2 : 1)); RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1); } @@ -1037,11 +1063,11 @@ void SSEffects::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> } void SSEffects::ssao_allocate_buffers(SSAORenderBuffers &p_ssao_buffers, const SSAOSettings &p_settings, RID p_linear_depth) { - if (p_ssao_buffers.half_size != p_settings.half_size) { + if (p_ssao_buffers.half_size != ssao_half_size) { ssao_free(p_ssao_buffers); } - if (p_settings.half_size) { + if (ssao_half_size) { p_ssao_buffers.buffer_width = (p_settings.full_screen_size.x + 3) / 4; p_ssao_buffers.buffer_height = (p_settings.full_screen_size.y + 3) / 4; p_ssao_buffers.half_buffer_width = (p_settings.full_screen_size.x + 7) / 8; @@ -1055,7 +1081,7 @@ void SSEffects::ssao_allocate_buffers(SSAORenderBuffers &p_ssao_buffers, const S if (p_ssao_buffers.ao_deinterleaved.is_null()) { { - p_ssao_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, p_settings.half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY); + p_ssao_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, ssao_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY); } { RD::TextureFormat tf; @@ -1111,7 +1137,7 @@ void SSEffects::ssao_allocate_buffers(SSAORenderBuffers &p_ssao_buffers, const S p_ssao_buffers.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView()); RD::get_singleton()->set_resource_name(p_ssao_buffers.ao_final, "SSAO Final"); } - p_ssao_buffers.half_size = p_settings.half_size; + p_ssao_buffers.half_size = ssao_half_size; } } @@ -1151,10 +1177,10 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu ssao.gather_push_constant.radius = p_settings.radius; float radius_near_limit = (p_settings.radius * 1.2f); - if (p_settings.quality <= RS::ENV_SSAO_QUALITY_LOW) { + if (ssao_quality <= RS::ENV_SSAO_QUALITY_LOW) { radius_near_limit *= 1.50f; - if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { + if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { ssao.gather_push_constant.radius *= 0.8f; } } @@ -1162,18 +1188,18 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu ssao.gather_push_constant.intensity = p_settings.intensity; ssao.gather_push_constant.shadow_power = p_settings.power; ssao.gather_push_constant.shadow_clamp = 0.98; - ssao.gather_push_constant.fade_out_mul = -1.0 / (p_settings.fadeout_to - p_settings.fadeout_from); - ssao.gather_push_constant.fade_out_add = p_settings.fadeout_from / (p_settings.fadeout_to - p_settings.fadeout_from) + 1.0; + ssao.gather_push_constant.fade_out_mul = -1.0 / (ssao_fadeout_to - ssao_fadeout_from); + ssao.gather_push_constant.fade_out_add = ssao_fadeout_from / (ssao_fadeout_to - ssao_fadeout_from) + 1.0; ssao.gather_push_constant.horizon_angle_threshold = p_settings.horizon; ssao.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit; ssao.gather_push_constant.neg_inv_radius = -1.0 / ssao.gather_push_constant.radius; ssao.gather_push_constant.load_counter_avg_div = 9.0 / float((p_ssao_buffers.half_buffer_width) * (p_ssao_buffers.half_buffer_height) * 255); - ssao.gather_push_constant.adaptive_sample_limit = p_settings.adaptive_target; + ssao.gather_push_constant.adaptive_sample_limit = ssao_adaptive_target; ssao.gather_push_constant.detail_intensity = p_settings.detail; - ssao.gather_push_constant.quality = MAX(0, p_settings.quality - 1); - ssao.gather_push_constant.size_multiplier = p_settings.half_size ? 2 : 1; + ssao.gather_push_constant.quality = MAX(0, ssao_quality - 1); + ssao.gather_push_constant.size_multiplier = ssao_half_size ? 2 : 1; if (p_ssao_buffers.gather_uniform_set.is_null()) { Vector<RD::Uniform> uniforms; @@ -1231,7 +1257,7 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu RD::get_singleton()->set_resource_name(p_ssao_buffers.importance_map_uniform_set, "SSAO Importance Map Uniform Set"); } - if (p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) { + if (ssao_quality == RS::ENV_SSAO_QUALITY_ULTRA) { RD::get_singleton()->draw_command_begin_label("Generate Importance Map"); ssao.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssao_buffers.buffer_width; ssao.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssao_buffers.buffer_height; @@ -1299,13 +1325,13 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu ssao.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssao_buffers.buffer_width; ssao.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssao_buffers.buffer_height; - int blur_passes = p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW ? p_settings.blur_passes : 1; + int blur_passes = ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW ? ssao_blur_passes : 1; shader = ssao.blur_shader.version_get_shader(ssao.blur_shader_version, 0); for (int pass = 0; pass < blur_passes; pass++) { int blur_pipeline = SSAO_BLUR_PASS; - if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { + if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { blur_pipeline = SSAO_BLUR_PASS_SMART; if (pass < blur_passes - 2) { blur_pipeline = SSAO_BLUR_PASS_WIDE; @@ -1315,13 +1341,13 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu } for (int i = 0; i < 4; i++) { - if ((p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + if ((ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { continue; } RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[blur_pipeline]); if (pass % 2 == 0) { - if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { + if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { RD::Uniform u_ao_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.ao_deinterleaved_slices[i] })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ao_slices_with_sampler), 0); } else { @@ -1332,7 +1358,7 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu RD::Uniform u_ao_pong_slices(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssao_buffers.ao_pong_slices[i] })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ao_pong_slices), 1); } else { - if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { + if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { RD::Uniform u_ao_pong_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.ao_pong_slices[i] })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ao_pong_slices_with_sampler), 0); } else { @@ -1345,11 +1371,11 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu } RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); - Size2i size(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)); + Size2i size(p_settings.full_screen_size.x >> (ssao_half_size ? 2 : 1), p_settings.full_screen_size.y >> (ssao_half_size ? 2 : 1)); RD::get_singleton()->compute_list_dispatch_threads(compute_list, size.x, size.y, 1); } - if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { + if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { RD::get_singleton()->compute_list_add_barrier(compute_list); } } @@ -1364,14 +1390,14 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu ssao.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness; ssao.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; ssao.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; - ssao.interleave_push_constant.size_modifier = uint32_t(p_settings.half_size ? 4 : 2); + ssao.interleave_push_constant.size_modifier = uint32_t(ssao_half_size ? 4 : 2); shader = ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, 0); int interleave_pipeline = SSAO_INTERLEAVE_HALF; - if (p_settings.quality == RS::ENV_SSAO_QUALITY_LOW) { + if (ssao_quality == RS::ENV_SSAO_QUALITY_LOW) { interleave_pipeline = SSAO_INTERLEAVE; - } else if (p_settings.quality >= RS::ENV_SSAO_QUALITY_MEDIUM) { + } else if (ssao_quality >= RS::ENV_SSAO_QUALITY_MEDIUM) { interleave_pipeline = SSAO_INTERLEAVE_SMART; } @@ -1380,7 +1406,7 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu RD::Uniform u_upscale_buffer(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssao_buffers.ao_final })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_upscale_buffer), 0); - if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW && p_settings.blur_passes % 2 == 0) { + if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW && ssao_blur_passes % 2 == 0) { RD::Uniform u_ao(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.ao_deinterleaved })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ao), 1); } else { @@ -1425,7 +1451,11 @@ void SSEffects::ssao_free(SSAORenderBuffers &p_ssao_buffers) { /* Screen Space Reflection */ -void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const Size2i &p_screen_size, const uint32_t p_view_count) { +void SSEffects::ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { + ssr_roughness_quality = p_quality; +} + +void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, const Size2i &p_screen_size, const uint32_t p_view_count) { // As we are processing one view at a time, we can reuse buffers, only our output needs to have layers for each view. if (p_ssr_buffers.depth_scaled.is_null()) { @@ -1446,7 +1476,7 @@ void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const Rend RD::get_singleton()->set_resource_name(p_ssr_buffers.normal_scaled, "SSR Normal Scaled"); } - if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED && !p_ssr_buffers.blur_radius[0].is_valid()) { + if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED && !p_ssr_buffers.blur_radius[0].is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8_UNORM; tf.width = p_screen_size.x; @@ -1490,7 +1520,7 @@ void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const Rend } } -void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const RID *p_metallic_slices, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets) { +void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, const RID *p_metallic_slices, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -1586,7 +1616,7 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R push_constant.proj_info[2] = (1.0f - p_projections[v].matrix[0][2]) / p_projections[v].matrix[0][0]; push_constant.proj_info[3] = (1.0f + p_projections[v].matrix[1][2]) / p_projections[v].matrix[1][1]; - ScreenSpaceReflectionMode mode = (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL; + ScreenSpaceReflectionMode mode = (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL; RID shader = ssr.shader.version_get_shader(ssr.shader_version, mode); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[pipeline_specialization][mode]); @@ -1598,7 +1628,7 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.depth_scaled })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_output_blur, u_scale_depth), 0); - if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) { + if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) { RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.intermediate })); RD::Uniform u_blur_radius(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.blur_radius[0] })); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_intermediate, u_blur_radius), 1); @@ -1619,7 +1649,7 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R RD::get_singleton()->draw_command_end_label(); } - if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) { + if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) { RD::get_singleton()->draw_command_begin_label("SSR filter"); //blur @@ -1634,10 +1664,10 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R push_constant.proj_info[2] = (1.0f - p_projections[v].matrix[0][2]) / p_projections[v].matrix[0][0]; push_constant.proj_info[3] = (1.0f + p_projections[v].matrix[1][2]) / p_projections[v].matrix[1][1]; push_constant.vertical = 0; - if (p_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_LOW) { + if (ssr_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_LOW) { push_constant.steps = p_max_steps / 3; push_constant.increment = 3; - } else if (p_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_MEDIUM) { + } else if (ssr_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_MEDIUM) { push_constant.steps = p_max_steps / 2; push_constant.increment = 2; } else { @@ -1740,7 +1770,20 @@ void SSEffects::ssr_free(SSRRenderBuffers &p_ssr_buffers) { /* Subsurface scattering */ -void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) { +void SSEffects::sss_set_quality(RS::SubSurfaceScatteringQuality p_quality) { + sss_quality = p_quality; +} + +RS::SubSurfaceScatteringQuality SSEffects::sss_get_quality() const { + return sss_quality; +} + +void SSEffects::sss_set_scale(float p_scale, float p_depth_scale) { + sss_scale = p_scale; + sss_depth_scale = p_depth_scale; +} + +void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -1769,11 +1812,11 @@ void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffer sss.push_constant.screen_size[0] = p_screen_size.x; sss.push_constant.screen_size[1] = p_screen_size.y; sss.push_constant.vertical = false; - sss.push_constant.scale = p_scale; - sss.push_constant.depth_scale = p_depth_scale; + sss.push_constant.scale = sss_scale; + sss.push_constant.depth_scale = sss_depth_scale; - RID shader = sss.shader.version_get_shader(sss.shader_version, p_quality - 1); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[p_quality - 1]); + RID shader = sss.shader.version_get_shader(sss.shader_version, sss_quality - 1); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[sss_quality - 1]); RD::Uniform u_diffuse_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_diffuse })); RD::Uniform u_diffuse(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_diffuse })); diff --git a/servers/rendering/renderer_rd/effects/ss_effects.h b/servers/rendering/renderer_rd/effects/ss_effects.h index d50319c46f..7c264b4d76 100644 --- a/servers/rendering/renderer_rd/effects/ss_effects.h +++ b/servers/rendering/renderer_rd/effects/ss_effects.h @@ -64,9 +64,10 @@ public: /* SS Downsampler */ - void downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const Projection &p_projection); + void downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, bool p_invalidate_uniform_set, Size2i p_full_screen_size, const Projection &p_projection); /* SSIL */ + void ssil_set_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to); struct SSILRenderBuffers { bool half_size = false; @@ -99,13 +100,6 @@ public: float sharpness = 0.98; float normal_rejection = 1.0; - RS::EnvironmentSSILQuality quality = RS::ENV_SSIL_QUALITY_MEDIUM; - bool half_size = true; - float adaptive_target = 0.5; - int blur_passes = 4; - float fadeout_from = 50.0; - float fadeout_to = 300.0; - Size2i full_screen_size = Size2i(); }; @@ -114,6 +108,7 @@ public: void ssil_free(SSILRenderBuffers &p_ssil_buffers); /* SSAO */ + void ssao_set_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to); struct SSAORenderBuffers { bool half_size = false; @@ -142,13 +137,6 @@ public: float horizon = 0.06; float sharpness = 0.98; - RS::EnvironmentSSAOQuality quality = RS::ENV_SSAO_QUALITY_MEDIUM; - bool half_size = false; - float adaptive_target = 0.5; - int blur_passes = 2; - float fadeout_from = 50.0; - float fadeout_to = 300.0; - Size2i full_screen_size = Size2i(); }; @@ -157,6 +145,7 @@ public: void ssao_free(SSAORenderBuffers &p_ssao_buffers); /* Screen Space Reflection */ + void ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality); struct SSRRenderBuffers { RID normal_scaled; @@ -167,14 +156,40 @@ public: RID output_slices[RendererSceneRender::MAX_RENDER_VIEWS]; }; - void ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const Size2i &p_screen_size, const uint32_t p_view_count); - void screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, const RID *p_metallic_slices, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets); + void ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, const Size2i &p_screen_size, const uint32_t p_view_count); + void screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, const RID *p_metallic_slices, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets); void ssr_free(SSRRenderBuffers &p_ssr_buffers); /* subsurface scattering */ - void sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality); + void sss_set_quality(RS::SubSurfaceScatteringQuality p_quality); + RS::SubSurfaceScatteringQuality sss_get_quality() const; + void sss_set_scale(float p_scale, float p_depth_scale); + + void sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size); private: + /* Settings */ + + RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM; + bool ssao_half_size = false; + float ssao_adaptive_target = 0.5; + int ssao_blur_passes = 2; + float ssao_fadeout_from = 50.0; + float ssao_fadeout_to = 300.0; + + RS::EnvironmentSSILQuality ssil_quality = RS::ENV_SSIL_QUALITY_MEDIUM; + bool ssil_half_size = false; + float ssil_adaptive_target = 0.5; + int ssil_blur_passes = 4; + float ssil_fadeout_from = 50.0; + float ssil_fadeout_to = 300.0; + + RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW; + + RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM; + float sss_scale = 0.05; + float sss_depth_scale = 0.01; + /* SS Downsampler */ struct SSEffectsDownsamplePushConstant { diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 3390e9cf64..4c72f0a56e 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -57,12 +57,19 @@ void Fog::fog_volume_initialize(RID p_rid) { fog_volume_owner.initialize_rid(p_rid, FogVolume()); } -void Fog::fog_free(RID p_rid) { +void Fog::fog_volume_free(RID p_rid) { FogVolume *fog_volume = fog_volume_owner.get_or_null(p_rid); fog_volume->dependency.deleted_notify(p_rid); fog_volume_owner.free(p_rid); } +Dependency *Fog::fog_volume_get_dependency(RID p_fog_volume) const { + FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume); + ERR_FAIL_NULL_V(fog_volume, nullptr); + + return &fog_volume->dependency; +} + void Fog::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) { FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume); ERR_FAIL_COND(!fog_volume); diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h index 9ecd5699dc..0ade995758 100644 --- a/servers/rendering/renderer_rd/environment/fog.h +++ b/servers/rendering/renderer_rd/environment/fog.h @@ -46,7 +46,9 @@ namespace RendererRD { class Fog : public RendererFog { -public: +private: + static Fog *singleton; + /* FOG VOLUMES */ struct FogVolume { @@ -58,16 +60,14 @@ public: Dependency dependency; }; + mutable RID_Owner<FogVolume, true> fog_volume_owner; + struct FogVolumeInstance { RID volume; Transform3D transform; bool active = false; }; -private: - static Fog *singleton; - - mutable RID_Owner<FogVolume, true> fog_volume_owner; mutable RID_Owner<FogVolumeInstance> fog_volume_instance_owner; /* Volumetric Fog */ @@ -240,12 +240,12 @@ public: /* FOG VOLUMES */ - FogVolume *get_fog_volume(RID p_rid) { return fog_volume_owner.get_or_null(p_rid); }; bool owns_fog_volume(RID p_rid) { return fog_volume_owner.owns(p_rid); }; virtual RID fog_volume_allocate() override; virtual void fog_volume_initialize(RID p_rid) override; - virtual void fog_free(RID p_rid) override; + virtual void fog_volume_free(RID p_rid) override; + Dependency *fog_volume_get_dependency(RID p_fog_volume) const; virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override; virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override; @@ -257,12 +257,35 @@ public: /* FOG VOLUMES INSTANCE */ - FogVolumeInstance *get_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.get_or_null(p_rid); }; bool owns_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.owns(p_rid); }; RID fog_volume_instance_create(RID p_fog_volume); void fog_instance_free(RID p_rid); + void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) { + Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + ERR_FAIL_COND(!fvi); + fvi->transform = p_transform; + } + + void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) { + Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + ERR_FAIL_COND(!fvi); + fvi->active = p_active; + } + + RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const { + Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + ERR_FAIL_COND_V(!fvi, RID()); + return fvi->volume; + } + + Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const { + Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + ERR_FAIL_COND_V(!fvi, Vector3()); + return fvi->transform.get_origin(); + } + /* Volumetric FOG */ class VolumetricFog : public RenderBufferCustomDataRD { GDCLASS(VolumetricFog, RenderBufferCustomDataRD) diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index ced0f6380f..ee6e5c27f2 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -1644,8 +1644,8 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection RD::get_singleton()->compute_list_end(); } - Size2 rtsize = texture_storage->render_target_get_size(p_render_target); - copy_effects->copy_to_fb_rect(p_texture, texture_storage->render_target_get_rd_framebuffer(p_render_target), Rect2(Vector2(), rtsize), true, false, false, false, RID(), p_view_count > 1); + Size2i rtsize = texture_storage->render_target_get_size(p_render_target); + copy_effects->copy_to_fb_rect(p_texture, texture_storage->render_target_get_rd_framebuffer(p_render_target), Rect2i(Point2i(), rtsize), true, false, false, false, RID(), p_view_count > 1); } void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth) { @@ -1798,7 +1798,8 @@ void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, con RD::get_singleton()->draw_list_end(); } -void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render) { +void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); /* Update general SDFGI Buffer */ SDFGIData sdfgi_data; @@ -1881,40 +1882,43 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r SDFGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS]; uint32_t idx = 0; - for (uint32_t j = 0; j < (uint32_t)p_scene_render->render_state.sdfgi_update_data->directional_lights->size(); j++) { + for (uint32_t j = 0; j < (uint32_t)p_render_data->sdfgi_update_data->directional_lights->size(); j++) { if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { break; } - RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_scene_render->render_state.sdfgi_update_data->directional_lights->get(j)); - ERR_CONTINUE(!li); + RID light_instance = p_render_data->sdfgi_update_data->directional_lights->get(j); + ERR_CONTINUE(!light_storage->owns_light_instance(light_instance)); - if (RSG::light_storage->light_directional_get_sky_mode(li->light) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) { + RID light = light_storage->light_instance_get_base_light(light_instance); + Transform3D light_transform = light_storage->light_instance_get_base_transform(light_instance); + + if (RSG::light_storage->light_directional_get_sky_mode(light) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) { continue; } - Vector3 dir = -li->transform.basis.get_column(Vector3::AXIS_Z); + Vector3 dir = -light_transform.basis.get_column(Vector3::AXIS_Z); dir.y *= y_mult; dir.normalize(); lights[idx].direction[0] = dir.x; lights[idx].direction[1] = dir.y; lights[idx].direction[2] = dir.z; - Color color = RSG::light_storage->light_get_color(li->light); + Color color = RSG::light_storage->light_get_color(light); color = color.srgb_to_linear(); lights[idx].color[0] = color.r; lights[idx].color[1] = color.g; lights[idx].color[2] = color.b; lights[idx].type = RS::LIGHT_DIRECTIONAL; - lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY); - if (p_scene_render->is_using_physical_light_units()) { - lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY); + lights[idx].energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY); + if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) { + lights[idx].energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY); } if (p_render_data->camera_attributes.is_valid()) { lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); } - lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light); + lights[idx].has_shadow = RSG::light_storage->light_has_shadow(light); idx++; } @@ -1923,45 +1927,49 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascade.position)) * cascade.cell_size; cascade_aabb.size = Vector3(1, 1, 1) * cascade_size * cascade.cell_size; - for (uint32_t j = 0; j < p_scene_render->render_state.sdfgi_update_data->positional_light_count; j++) { + for (uint32_t j = 0; j < p_render_data->sdfgi_update_data->positional_light_count; j++) { if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { break; } - RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_scene_render->render_state.sdfgi_update_data->positional_light_instances[j]); - ERR_CONTINUE(!li); + RID light_instance = p_render_data->sdfgi_update_data->positional_light_instances[j]; + ERR_CONTINUE(!light_storage->owns_light_instance(light_instance)); + + RID light = light_storage->light_instance_get_base_light(light_instance); + AABB light_aabb = light_storage->light_instance_get_base_aabb(light_instance); + Transform3D light_transform = light_storage->light_instance_get_base_transform(light_instance); - uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(li->light); + uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(light); if (i > max_sdfgi_cascade) { continue; } - if (!cascade_aabb.intersects(li->aabb)) { + if (!cascade_aabb.intersects(light_aabb)) { continue; } - Vector3 dir = -li->transform.basis.get_column(Vector3::AXIS_Z); + Vector3 dir = -light_transform.basis.get_column(Vector3::AXIS_Z); //faster to not do this here //dir.y *= y_mult; //dir.normalize(); lights[idx].direction[0] = dir.x; lights[idx].direction[1] = dir.y; lights[idx].direction[2] = dir.z; - Vector3 pos = li->transform.origin; + Vector3 pos = light_transform.origin; pos.y *= y_mult; lights[idx].position[0] = pos.x; lights[idx].position[1] = pos.y; lights[idx].position[2] = pos.z; - Color color = RSG::light_storage->light_get_color(li->light); + Color color = RSG::light_storage->light_get_color(light); color = color.srgb_to_linear(); lights[idx].color[0] = color.r; lights[idx].color[1] = color.g; lights[idx].color[2] = color.b; - lights[idx].type = RSG::light_storage->light_get_type(li->light); + lights[idx].type = RSG::light_storage->light_get_type(light); - lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY); - if (p_scene_render->is_using_physical_light_units()) { - lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY); + lights[idx].energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY); + if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) { + lights[idx].energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY); // Convert from Luminous Power to Luminous Intensity if (lights[idx].type == RS::LIGHT_OMNI) { @@ -1977,11 +1985,11 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); } - lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light); - lights[idx].attenuation = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); - lights[idx].radius = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); - lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE))); - lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); + lights[idx].has_shadow = RSG::light_storage->light_has_shadow(light); + lights[idx].attenuation = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION); + lights[idx].radius = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_RANGE); + lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE))); + lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION); idx++; } @@ -1994,7 +2002,7 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r } } -void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render, float p_exposure_normalization) { +void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, float p_exposure_normalization) { //print_line("rendering region " + itos(p_region)); ERR_FAIL_COND(p_render_buffers.is_null()); // we wouldn't be here if this failed but... AABB bounds; @@ -2015,7 +2023,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_ } //print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(cascades[cascade].cell_size)); - p_scene_render->_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, render_albedo, render_emission, render_emission_aniso, render_geom_facing, p_exposure_normalization); + RendererSceneRenderRD::get_singleton()->_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, render_albedo, render_emission, render_emission_aniso, render_geom_facing, p_exposure_normalization); if (cascade_next != cascade) { RD::get_singleton()->draw_command_begin_label("SDFGI Pre-Process Cascade"); @@ -2353,9 +2361,11 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_ } } -void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render) { +void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result) { ERR_FAIL_COND(p_render_buffers.is_null()); // we wouldn't be here if this failed but... + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lights"); update_cascades(); @@ -2381,21 +2391,25 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen break; } - RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_positional_light_cull_result[i][j]); - ERR_CONTINUE(!li); + RID light_instance = p_positional_light_cull_result[i][j]; + ERR_CONTINUE(!light_storage->owns_light_instance(light_instance)); + + RID light = light_storage->light_instance_get_base_light(light_instance); + AABB light_aabb = light_storage->light_instance_get_base_aabb(light_instance); + Transform3D light_transform = light_storage->light_instance_get_base_transform(light_instance); - uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(li->light); + uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(light); if (p_cascade_indices[i] > max_sdfgi_cascade) { continue; } - if (!cascade_aabb.intersects(li->aabb)) { + if (!cascade_aabb.intersects(light_aabb)) { continue; } - lights[idx].type = RSG::light_storage->light_get_type(li->light); + lights[idx].type = RSG::light_storage->light_get_type(light); - Vector3 dir = -li->transform.basis.get_column(Vector3::AXIS_Z); + Vector3 dir = -light_transform.basis.get_column(Vector3::AXIS_Z); if (lights[idx].type == RS::LIGHT_DIRECTIONAL) { dir.y *= y_mult; //only makes sense for directional dir.normalize(); @@ -2403,20 +2417,20 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen lights[idx].direction[0] = dir.x; lights[idx].direction[1] = dir.y; lights[idx].direction[2] = dir.z; - Vector3 pos = li->transform.origin; + Vector3 pos = light_transform.origin; pos.y *= y_mult; lights[idx].position[0] = pos.x; lights[idx].position[1] = pos.y; lights[idx].position[2] = pos.z; - Color color = RSG::light_storage->light_get_color(li->light); + Color color = RSG::light_storage->light_get_color(light); color = color.srgb_to_linear(); lights[idx].color[0] = color.r; lights[idx].color[1] = color.g; lights[idx].color[2] = color.b; - lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY); - if (p_scene_render->is_using_physical_light_units()) { - lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY); + lights[idx].energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY); + if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) { + lights[idx].energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY); // Convert from Luminous Power to Luminous Intensity if (lights[idx].type == RS::LIGHT_OMNI) { @@ -2432,11 +2446,11 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); } - lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light); - lights[idx].attenuation = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); - lights[idx].radius = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); - lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE))); - lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); + lights[idx].has_shadow = RSG::light_storage->light_has_shadow(light); + lights[idx].attenuation = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION); + lights[idx].radius = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_RANGE); + lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE))); + lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION); idx++; } @@ -2492,7 +2506,8 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen //////////////////////////////////////////////////////////////////////////////// // VoxelGIInstance -void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) { +void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); uint32_t data_version = gi->voxel_gi_get_data_version(probe); @@ -2834,7 +2849,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID last_probe_data_version = data_version; p_update_light_instances = true; //just in case - p_scene_render->_base_uniforms_changed(); + RendererSceneRenderRD::get_singleton()->base_uniforms_changed(); } // UDPDATE TIME @@ -2857,7 +2872,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID for (uint32_t i = 0; i < light_count; i++) { VoxelGILight &l = gi->voxel_gi_lights[i]; RID light_instance = p_light_instances[i]; - RID light = p_scene_render->light_instance_get_base_light(light_instance); + RID light = light_storage->light_instance_get_base_light(light_instance); l.type = RSG::light_storage->light_get_type(light); if (l.type == RS::LIGHT_DIRECTIONAL && RSG::light_storage->light_directional_get_sky_mode(light) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) { @@ -2868,7 +2883,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID l.attenuation = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION); l.energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY); - if (p_scene_render->is_using_physical_light_units()) { + if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) { l.energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY); l.energy *= gi->voxel_gi_get_baked_exposure_normalization(probe); @@ -2892,7 +2907,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID l.cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE))); l.inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION); - Transform3D xform = p_scene_render->light_instance_get_base_transform(light_instance); + Transform3D xform = light_storage->light_instance_get_base_transform(light_instance); Vector3 pos = to_probe_xform.xform(xform.origin); Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_column(2)).normalized(); @@ -3087,17 +3102,17 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID Projection cm; cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]); - if (p_scene_render->cull_argument.size() == 0) { - p_scene_render->cull_argument.push_back(nullptr); + if (RendererSceneRenderRD::get_singleton()->cull_argument.size() == 0) { + RendererSceneRenderRD::get_singleton()->cull_argument.push_back(nullptr); } - p_scene_render->cull_argument[0] = instance; + RendererSceneRenderRD::get_singleton()->cull_argument[0] = instance; float exposure_normalization = 1.0; - if (p_scene_render->is_using_physical_light_units()) { + if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) { exposure_normalization = gi->voxel_gi_get_baked_exposure_normalization(probe); } - p_scene_render->_render_material(to_world_xform * xform, cm, true, p_scene_render->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size), exposure_normalization); + RendererSceneRenderRD::get_singleton()->_render_material(to_world_xform * xform, cm, true, RendererSceneRenderRD::get_singleton()->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size), exposure_normalization); VoxelGIDynamicPushConstant push_constant; memset(&push_constant, 0, sizeof(VoxelGIDynamicPushConstant)); @@ -3591,7 +3606,7 @@ Ref<GI::SDFGI> GI::create_sdfgi(RID p_env, const Vector3 &p_world_position, uint return sdfgi; } -void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render) { +void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used) { ERR_FAIL_COND(p_render_buffers.is_null()); RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); @@ -4051,11 +4066,11 @@ bool GI::voxel_gi_needs_update(RID p_probe) const { return voxel_gi->last_probe_version != voxel_gi_get_version(voxel_gi->probe); } -void GI::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) { +void GI::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects) { VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe); ERR_FAIL_COND(!voxel_gi); - voxel_gi->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render); + voxel_gi->update(p_update_light_instances, p_light_instances, p_dynamic_objects); } void GI::debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h index e567c67a3b..2182ca6a20 100644 --- a/servers/rendering/renderer_rd/environment/gi.h +++ b/servers/rendering/renderer_rd/environment/gi.h @@ -145,7 +145,7 @@ public: Transform3D transform; - void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render); + void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects); void debug(RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); void free_resources(); }; @@ -687,9 +687,9 @@ public: void debug_draw(uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture, const Vector<RID> &p_texture_views); void debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth); - void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render); - void render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render, float p_exposure_normalization); - void render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render); + void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data); + void render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, float p_exposure_normalization); + void render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result); }; RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16; @@ -812,13 +812,13 @@ public: Ref<SDFGI> create_sdfgi(RID p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size); - void setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render); + void setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used); void process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, RID p_environment, uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances); RID voxel_gi_instance_create(RID p_base); void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform); bool voxel_gi_needs_update(RID p_probe) const; - void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render); + void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects); void debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); }; diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index 307af99e91..21a15ed475 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -1200,18 +1200,17 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P // This can't be done in RenderSceneRenderRD::_setup lights because that needs to be called // after the depth prepass, but this runs before the depth prepass for (int i = 0; i < (int)p_lights.size(); i++) { - RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_lights[i]); - if (!li) { + if (!light_storage->owns_light_instance(p_lights[i])) { continue; } - RID base = li->light; + RID base = light_storage->light_instance_get_base_light(p_lights[i]); ERR_CONTINUE(base.is_null()); RS::LightType type = light_storage->light_get_type(base); if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) { SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[sky_scene_state.ubo.directional_light_count]; - Transform3D light_transform = li->transform; + Transform3D light_transform = light_storage->light_instance_get_base_transform(p_lights[i]); Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized(); sky_light_data.direction[0] = world_direction.x; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 3a9c695653..cf08949d99 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -110,9 +110,29 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::free_data() { render_buffers->clear_context(RB_SCOPE_FORWARD_CLUSTERED); } + if (cluster_builder) { + memdelete(cluster_builder); + cluster_builder = nullptr; + } + if (!render_sdfgi_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_sdfgi_uniform_set)) { RD::get_singleton()->free(render_sdfgi_uniform_set); } + + if (ss_effects_data.linear_depth.is_valid()) { + RD::get_singleton()->free(ss_effects_data.linear_depth); + ss_effects_data.linear_depth = RID(); + ss_effects_data.linear_depth_slices.clear(); + } + + if (ss_effects_data.downsample_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(ss_effects_data.downsample_uniform_set)) { + RD::get_singleton()->free(ss_effects_data.downsample_uniform_set); + ss_effects_data.downsample_uniform_set = RID(); + } + + RenderForwardClustered::get_singleton()->get_ss_effects()->ssao_free(ss_effects_data.ssao); + RenderForwardClustered::get_singleton()->get_ss_effects()->ssil_free(ss_effects_data.ssil); + RenderForwardClustered::get_singleton()->get_ss_effects()->ssr_free(ss_effects_data.ssr); } void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RenderSceneBuffersRD *p_render_buffers) { @@ -146,6 +166,14 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RenderS p_render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples); } + + if (cluster_builder == nullptr) { + cluster_builder = memnew(ClusterBuilderRD); + } + cluster_builder->set_shared(RenderForwardClustered::get_singleton()->get_cluster_builder_shared()); + + RID sampler = RendererRD::MaterialStorage::get_singleton()->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + cluster_builder->setup(p_render_buffers->get_internal_size(), p_render_buffers->get_max_cluster_elements(), p_render_buffers->get_depth_texture(), sampler, p_render_buffers->get_internal_texture()); } RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_only_fb() { @@ -580,9 +608,11 @@ void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_p } void RenderForwardClustered::_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) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers; RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID(); - RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID(); + RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID(); // May do this earlier in RenderSceneRenderRD::render_scene if (p_index >= (int)scene_state.uniform_buffers.size()) { @@ -1030,26 +1060,28 @@ void RenderForwardClustered::_setup_voxelgis(const PagedArray<RID> &p_voxelgis) } void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + scene_state.lightmaps_used = 0; for (int i = 0; i < (int)p_lightmaps.size(); i++) { if (i >= (int)scene_state.max_lightmaps) { break; } - RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]); + RID lightmap = light_storage->lightmap_instance_get_lightmap(p_lightmaps[i]); - Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis; + Basis to_lm = light_storage->lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis; to_lm = to_lm.inverse().transposed(); //will transform normals RendererRD::MaterialStorage::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform); scene_state.lightmaps[i].exposure_normalization = 1.0; if (p_render_data->camera_attributes.is_valid()) { - float baked_exposure = RendererRD::LightStorage::get_singleton()->lightmap_get_baked_exposure_normalization(lightmap); + float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap); float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); scene_state.lightmaps[i].exposure_normalization = enf / baked_exposure; } scene_state.lightmap_ids[i] = p_lightmaps[i]; - scene_state.lightmap_has_sh[i] = RendererRD::LightStorage::get_singleton()->lightmap_uses_spherical_harmonics(lightmap); + scene_state.lightmap_has_sh[i] = light_storage->lightmap_uses_spherical_harmonics(lightmap); scene_state.lightmaps_used++; } @@ -1058,7 +1090,452 @@ void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data, } } +/* SDFGI */ + +void RenderForwardClustered::_update_sdfgi(RenderDataRD *p_render_data) { + Ref<RenderSceneBuffersRD> rb; + if (p_render_data && p_render_data->render_buffers.is_valid()) { + rb = p_render_data->render_buffers; + } + + if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) { + Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); + float exposure_normalization = 1.0; + + if (p_render_data->camera_attributes.is_valid()) { + exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); + } + for (int i = 0; i < p_render_data->render_sdfgi_region_count; i++) { + sdfgi->render_region(rb, p_render_data->render_sdfgi_regions[i].region, p_render_data->render_sdfgi_regions[i].instances, exposure_normalization); + } + if (p_render_data->sdfgi_update_data->update_static) { + sdfgi->render_static_lights(p_render_data, rb, p_render_data->sdfgi_update_data->static_cascade_count, p_render_data->sdfgi_update_data->static_cascade_indices, p_render_data->sdfgi_update_data->static_positional_lights); + } + } +} + +/* Debug */ + +void RenderForwardClustered::_debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers) { + if (p_render_buffers.is_valid() && current_cluster_builder != nullptr) { + RS::ViewportDebugDraw dd = get_debug_draw_mode(); + + if (dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) { + ClusterBuilderRD::ElementType elem_type = ClusterBuilderRD::ELEMENT_TYPE_MAX; + switch (dd) { + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_OMNI_LIGHT; + break; + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_SPOT_LIGHT; + break; + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_DECAL; + break; + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_REFLECTION_PROBE; + break; + default: { + } + } + current_cluster_builder->debug(elem_type); + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// FOG SHADER + +void RenderForwardClustered::_update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes) { + ERR_FAIL_COND(p_render_buffers.is_null()); + + Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED); + + ERR_FAIL_COND(!p_render_buffers->has_custom_data(RB_SCOPE_GI)); + Ref<RendererRD::GI::RenderBuffersGI> rbgi = p_render_buffers->get_custom_data(RB_SCOPE_GI); + + Ref<RendererRD::GI::SDFGI> sdfgi; + if (p_render_buffers->has_custom_data(RB_SCOPE_SDFGI)) { + sdfgi = p_render_buffers->get_custom_data(RB_SCOPE_SDFGI); + } + + Size2i size = p_render_buffers->get_internal_size(); + float ratio = float(size.x) / float((size.x + size.y) / 2); + uint32_t target_width = uint32_t(float(get_volumetric_fog_size()) * ratio); + uint32_t target_height = uint32_t(float(get_volumetric_fog_size()) / ratio); + + if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) { + Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG); + //validate + if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment) || fog->width != target_width || fog->height != target_height || fog->depth != get_volumetric_fog_depth()) { + p_render_buffers->set_custom_data(RB_SCOPE_FOG, Ref<RenderBufferCustomDataRD>()); + } + } + + if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment)) { + //no reason to enable or update, bye + return; + } + + if (p_environment.is_valid() && environment_get_volumetric_fog_enabled(p_environment) && !p_render_buffers->has_custom_data(RB_SCOPE_FOG)) { + //required volumetric fog but not existing, create + Ref<RendererRD::Fog::VolumetricFog> fog; + + fog.instantiate(); + fog->init(Vector3i(target_width, target_height, get_volumetric_fog_depth()), sky.sky_shader.default_shader_rd); + + p_render_buffers->set_custom_data(RB_SCOPE_FOG, fog); + } + + if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) { + Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG); + + RendererRD::Fog::VolumetricFogSettings settings; + settings.rb_size = size; + settings.time = time; + settings.is_using_radiance_cubemap_array = is_using_radiance_cubemap_array(); + settings.max_cluster_elements = RendererRD::LightStorage::get_singleton()->get_max_cluster_elements(); + settings.volumetric_fog_filter_active = get_volumetric_fog_filter_active(); + + settings.shadow_sampler = shadow_sampler; + settings.shadow_atlas_depth = RendererRD::LightStorage::get_singleton()->owns_shadow_atlas(p_shadow_atlas) ? RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_shadow_atlas) : RID(); + settings.voxel_gi_buffer = rbgi->get_voxel_gi_buffer(); + settings.omni_light_buffer = RendererRD::LightStorage::get_singleton()->get_omni_light_buffer(); + settings.spot_light_buffer = RendererRD::LightStorage::get_singleton()->get_spot_light_buffer(); + settings.directional_shadow_depth = RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture(); + settings.directional_light_buffer = RendererRD::LightStorage::get_singleton()->get_directional_light_buffer(); + + settings.vfog = fog; + settings.cluster_builder = rb_data->cluster_builder; + settings.rbgi = rbgi; + settings.sdfgi = sdfgi; + settings.env = p_environment; + settings.sky = &sky; + settings.gi = &gi; + + RendererRD::Fog::get_singleton()->volumetric_fog_update(settings, p_cam_projection, p_cam_transform, p_prev_cam_inv_transform, p_shadow_atlas, p_directional_light_count, p_use_directional_shadows, p_positional_light_count, p_voxel_gi_count, p_fog_volumes); + } +} + +/* Lighting */ + +void RenderForwardClustered::setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_extents) { + if (current_cluster_builder != nullptr) { + current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, p_transform, p_half_extents); + } +} + +void RenderForwardClustered::setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) { + if (current_cluster_builder != nullptr) { + current_cluster_builder->add_light(p_type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, p_transform, p_radius, p_spot_aperture); + } +} + +void RenderForwardClustered::setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_extents) { + if (current_cluster_builder != nullptr) { + current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, p_transform, p_half_extents); + } +} + +/* Render scene */ + +void RenderForwardClustered::_process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection) { + ERR_FAIL_NULL(ss_effects); + ERR_FAIL_COND(p_render_buffers.is_null()); + ERR_FAIL_COND(p_environment.is_null()); + + Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED); + ERR_FAIL_COND(rb_data.is_null()); + + RENDER_TIMESTAMP("Process SSAO"); + + RendererRD::SSEffects::SSAOSettings settings; + settings.radius = environment_get_ssao_radius(p_environment); + settings.intensity = environment_get_ssao_intensity(p_environment); + settings.power = environment_get_ssao_power(p_environment); + settings.detail = environment_get_ssao_detail(p_environment); + settings.horizon = environment_get_ssao_horizon(p_environment); + settings.sharpness = environment_get_ssao_sharpness(p_environment); + settings.full_screen_size = p_render_buffers->get_internal_size(); + + ss_effects->ssao_allocate_buffers(rb_data->ss_effects_data.ssao, settings, rb_data->ss_effects_data.linear_depth); + ss_effects->generate_ssao(rb_data->ss_effects_data.ssao, p_normal_buffer, p_projection, settings); +} + +void RenderForwardClustered::_process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform) { + ERR_FAIL_NULL(ss_effects); + ERR_FAIL_COND(p_render_buffers.is_null()); + ERR_FAIL_COND(p_environment.is_null()); + + Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED); + ERR_FAIL_COND(rb_data.is_null()); + + RENDER_TIMESTAMP("Process SSIL"); + + RendererRD::SSEffects::SSILSettings settings; + settings.radius = environment_get_ssil_radius(p_environment); + settings.intensity = environment_get_ssil_intensity(p_environment); + settings.sharpness = environment_get_ssil_sharpness(p_environment); + settings.normal_rejection = environment_get_ssil_normal_rejection(p_environment); + settings.full_screen_size = p_render_buffers->get_internal_size(); + + Projection correction; + correction.set_depth_correction(true); + Projection projection = correction * p_projection; + Transform3D transform = p_transform; + transform.set_origin(Vector3(0.0, 0.0, 0.0)); + Projection last_frame_projection = rb_data->ss_effects_data.last_frame_projection * Projection(rb_data->ss_effects_data.last_frame_transform.affine_inverse()) * Projection(transform) * projection.inverse(); + + ss_effects->ssil_allocate_buffers(rb_data->ss_effects_data.ssil, settings, rb_data->ss_effects_data.linear_depth); + ss_effects->screen_space_indirect_lighting(rb_data->ss_effects_data.ssil, p_normal_buffer, p_projection, last_frame_projection, settings); + rb_data->ss_effects_data.last_frame_projection = projection; + rb_data->ss_effects_data.last_frame_transform = transform; +} + +void RenderForwardClustered::_copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers) { + ERR_FAIL_COND(p_render_buffers.is_null()); + + Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED); + ERR_FAIL_COND(rb_data.is_null()); + + if (rb_data->ss_effects_data.ssil.last_frame.is_valid()) { + Size2i size = p_render_buffers->get_internal_size(); + RID texture = p_render_buffers->get_internal_texture(); + copy_effects->copy_to_rect(texture, rb_data->ss_effects_data.ssil.last_frame, Rect2i(0, 0, size.x, size.y)); + + int width = size.x; + int height = size.y; + for (int i = 0; i < rb_data->ss_effects_data.ssil.last_frame_slices.size() - 1; i++) { + width = MAX(1, width >> 1); + height = MAX(1, height >> 1); + copy_effects->make_mipmap(rb_data->ss_effects_data.ssil.last_frame_slices[i], rb_data->ss_effects_data.ssil.last_frame_slices[i + 1], Size2i(width, height)); + } + } +} + +void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer) { + // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + + Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers; + Ref<RenderBufferDataForwardClustered> rb_data; + if (rb.is_valid()) { + rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED); + } + + if (rb.is_valid() && p_use_gi && rb->has_custom_data(RB_SCOPE_SDFGI)) { + Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); + sdfgi->store_probes(); + } + + p_render_data->cube_shadows.clear(); + p_render_data->shadows.clear(); + p_render_data->directional_shadows.clear(); + + Plane camera_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin); + float lod_distance_multiplier = p_render_data->scene_data->cam_projection.get_lod_multiplier(); + { + for (int i = 0; i < p_render_data->render_shadow_count; i++) { + RID li = p_render_data->render_shadows[i].light; + RID base = light_storage->light_instance_get_base_light(li); + + if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) { + p_render_data->directional_shadows.push_back(i); + } else if (light_storage->light_get_type(base) == RS::LIGHT_OMNI && light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) { + p_render_data->cube_shadows.push_back(i); + } else { + p_render_data->shadows.push_back(i); + } + } + + //cube shadows are rendered in their own way + for (uint32_t i = 0; i < p_render_data->cube_shadows.size(); i++) { + _render_shadow_pass(p_render_data->render_shadows[p_render_data->cube_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->cube_shadows[i]].pass, p_render_data->render_shadows[p_render_data->cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); + } + + if (p_render_data->directional_shadows.size()) { + //open the pass for directional shadows + light_storage->update_directional_shadow_atlas(); + 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); + RD::get_singleton()->draw_list_end(); + } + } + + // Render GI + + bool render_shadows = p_render_data->directional_shadows.size() || p_render_data->shadows.size(); + bool render_gi = rb.is_valid() && p_use_gi; + + if (render_shadows && render_gi) { + RENDER_TIMESTAMP("Render GI + Render Shadows (Parallel)"); + } else if (render_shadows) { + RENDER_TIMESTAMP("Render Shadows"); + } else if (render_gi) { + RENDER_TIMESTAMP("Render GI"); + } + + //prepare shadow rendering + if (render_shadows) { + _render_shadow_begin(); + + //render directional shadows + for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) { + _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); + } + //render positional shadows + for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) { + _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); + } + + _render_shadow_process(); + } + + //start GI + if (render_gi) { + gi.process_gi(rb, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, 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->voxel_gi_instances); + } + + //Do shadow rendering (in parallel with GI) + if (render_shadows) { + _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER); + } + + if (render_gi) { + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //use a later barrier + } + + if (rb_data.is_valid() && ss_effects) { + if (p_use_ssao || p_use_ssil) { + Size2i size = rb->get_internal_size(); + + bool invalidate_uniform_set = false; + if (rb_data->ss_effects_data.linear_depth.is_null()) { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16_SFLOAT; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = (size.x + 1) / 2; + tf.height = (size.y + 1) / 2; + tf.mipmaps = 5; + tf.array_layers = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb_data->ss_effects_data.linear_depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb_data->ss_effects_data.linear_depth, "SS Effects Depth"); + for (uint32_t i = 0; i < tf.mipmaps; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb_data->ss_effects_data.linear_depth, 0, i, 1, RD::TEXTURE_SLICE_2D_ARRAY); + rb_data->ss_effects_data.linear_depth_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SS Effects Depth Mip " + itos(i) + " "); + } + invalidate_uniform_set = true; + } + + RID depth_texture = rb->get_depth_texture(); + ss_effects->downsample_depth(depth_texture, rb_data->ss_effects_data.linear_depth_slices, invalidate_uniform_set, size, p_render_data->scene_data->cam_projection); + } + + if (p_use_ssao) { + // TODO make these proper stereo + _process_ssao(rb, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection); + } + + if (p_use_ssil) { + // TODO make these proper stereo + _process_ssil(rb, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform); + } + } + + //full barrier here, we need raster, transfer and compute and it depends from the previous work + RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL); + + if (current_cluster_builder) { + current_cluster_builder->begin(p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, !p_render_data->reflection_probe.is_valid()); + } + + bool using_shadows = true; + + if (p_render_data->reflection_probe.is_valid()) { + if (!RSG::light_storage->reflection_probe_renders_shadows(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { + using_shadows = false; + } + } else { + //do not render reflections when rendering a reflection probe + 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); + } + + uint32_t directional_light_count = 0; + uint32_t positional_light_count = 0; + 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); + texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse()); + + p_render_data->directional_light_count = directional_light_count; + + if (current_cluster_builder) { + current_cluster_builder->bake_cluster(); + } + + if (rb.is_valid()) { + bool directional_shadows = RendererRD::LightStorage::get_singleton()->has_directional_shadows(directional_light_count); + _update_volumetric_fog(rb, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, p_render_data->voxel_gi_count, *p_render_data->fog_volumes); + } +} + +void RenderForwardClustered::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive) { + ERR_FAIL_NULL(ss_effects); + ERR_FAIL_COND(p_render_buffers.is_null()); + + Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED); + ERR_FAIL_COND(rb_data.is_null()); + + Size2i internal_size = p_render_buffers->get_internal_size(); + bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8; + uint32_t view_count = p_render_buffers->get_view_count(); + + if (!can_use_effects) { + //just copy + copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), RID(), view_count); + return; + } + + ERR_FAIL_COND(p_environment.is_null()); + ERR_FAIL_COND(!environment_get_ssr_enabled(p_environment)); + + Size2i half_size = Size2i(internal_size.x / 2, internal_size.y / 2); + if (rb_data->ss_effects_data.ssr.output.is_null()) { + ss_effects->ssr_allocate_buffers(rb_data->ss_effects_data.ssr, _render_buffers_get_color_format(), half_size, view_count); + } + RID texture_slices[RendererSceneRender::MAX_RENDER_VIEWS]; + RID depth_slices[RendererSceneRender::MAX_RENDER_VIEWS]; + for (uint32_t v = 0; v < view_count; v++) { + texture_slices[v] = p_render_buffers->get_internal_texture(v); + depth_slices[v] = p_render_buffers->get_depth_texture(v); + } + ss_effects->screen_space_reflection(rb_data->ss_effects_data.ssr, texture_slices, p_normal_slices, p_metallic_slices, depth_slices, half_size, environment_get_ssr_max_steps(p_environment), environment_get_ssr_fade_in(p_environment), environment_get_ssr_fade_out(p_environment), environment_get_ssr_depth_tolerance(p_environment), view_count, p_projections, p_eye_offsets); + copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), rb_data->ss_effects_data.ssr.output, view_count); +} + +void RenderForwardClustered::_process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera) { + ERR_FAIL_COND(p_render_buffers.is_null()); + + Size2i internal_size = p_render_buffers->get_internal_size(); + bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8; + + if (!can_use_effects) { + //just copy + return; + } + + p_render_buffers->allocate_blur_textures(); + + for (uint32_t v = 0; v < p_render_buffers->get_view_count(); v++) { + RID internal_texture = p_render_buffers->get_internal_texture(v); + RID depth_texture = p_render_buffers->get_depth_texture(v); + ss_effects->sub_surface_scattering(p_render_buffers, internal_texture, depth_texture, p_camera, internal_size); + } +} + void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + Ref<RenderSceneBuffersRD> rb; Ref<RenderBufferDataForwardClustered> rb_data; if (p_render_data && p_render_data->render_buffers.is_valid()) { @@ -1070,6 +1547,54 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co //first of all, make a new render pass //fill up ubo + RENDER_TIMESTAMP("Prepare 3D Scene"); + + // sdfgi first + _update_sdfgi(p_render_data); + + // assign render indices to voxel_gi_instances + for (uint32_t i = 0; i < (uint32_t)p_render_data->voxel_gi_instances->size(); i++) { + RID voxel_gi_instance = (*p_render_data->voxel_gi_instances)[i]; + gi.voxel_gi_instance_set_render_index(voxel_gi_instance, i); + } + + // obtain cluster builder + if (rb_data.is_valid()) { + current_cluster_builder = rb_data->cluster_builder; + } else if (light_storage->owns_reflection_probe_instance(p_render_data->reflection_probe)) { + current_cluster_builder = light_storage->reflection_probe_instance_get_cluster_builder(p_render_data->reflection_probe, &cluster_builder_shared); + + if (p_render_data->camera_attributes.is_valid()) { + light_storage->reflection_probe_set_baked_exposure(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe), RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes)); + } + } else { + ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash + current_cluster_builder = nullptr; + } + + p_render_data->voxel_gi_count = 0; + + if (rb.is_valid()) { + if (rb->has_custom_data(RB_SCOPE_SDFGI)) { + Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); + if (sdfgi.is_valid()) { + sdfgi->update_cascades(); + sdfgi->pre_process_gi(p_render_data->scene_data->cam_transform, p_render_data); + sdfgi->update_light(); + } + } + + gi.setup_voxel_gi_instances(p_render_data, p_render_data->render_buffers, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances, p_render_data->voxel_gi_count); + } + + if (current_cluster_builder != nullptr) { + p_render_data->cluster_buffer = current_cluster_builder->get_cluster_buffer(); + p_render_data->cluster_size = current_cluster_builder->get_cluster_size(); + p_render_data->cluster_max_elements = current_cluster_builder->get_max_cluster_elements(); + } + + _update_vrs(rb); + RENDER_TIMESTAMP("Setup 3D Scene"); // check if we need motion vectors @@ -1153,15 +1678,15 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co color_framebuffer = rb_data->get_color_pass_fb(color_pass_flags); color_only_framebuffer = rb_data->get_color_only_fb(); } else if (p_render_data->reflection_probe.is_valid()) { - uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe); + uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe); screen_size.x = resolution; screen_size.y = resolution; - color_framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass); + color_framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass); color_only_framebuffer = color_framebuffer; - depth_framebuffer = reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass); + depth_framebuffer = light_storage->reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass); - if (RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { + if (light_storage->reflection_probe_is_interior(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { p_render_data->environment = RID(); //no environment on interiors } @@ -1188,7 +1713,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_end_label(); - bool using_sss = rb_data.is_valid() && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; + bool using_sss = rb_data.is_valid() && scene_state.used_sss && ss_effects->sss_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; if (using_sss && !using_separate_specular) { using_separate_specular = true; @@ -1538,6 +2063,229 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co _render_buffers_post_process_and_tonemap(p_render_data); } + + if (rb.is_valid()) { + _render_buffers_debug_draw(rb, p_render_data->shadow_atlas, p_render_data->occluder_debug_tex); + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb->has_custom_data(RB_SCOPE_SDFGI)) { + Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); + Vector<RID> view_rids; + + // SDFGI renders at internal resolution, need to check if our debug correctly supports outputting upscaled. + Size2i size = rb->get_internal_size(); + RID source_texture = rb->get_internal_texture(); + for (uint32_t v = 0; v < rb->get_view_count(); v++) { + view_rids.push_back(rb->get_internal_texture(v)); + } + + sdfgi->debug_draw(p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, size.x, size.y, rb->get_render_target(), source_texture, view_rids); + } + } +} + +void RenderForwardClustered::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) { + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + ERR_FAIL_COND(p_render_buffers.is_null()); + + Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED); + ERR_FAIL_COND(rb_data.is_null()); + + RendererSceneRenderRD::_render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occlusion_buffer); + + RID render_target = p_render_buffers->get_render_target(); + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb_data->ss_effects_data.ssao.ao_final.is_valid()) { + Size2i rtsize = texture_storage->render_target_get_size(render_target); + copy_effects->copy_to_fb_rect(rb_data->ss_effects_data.ssao.ao_final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, true); + } + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSIL && rb_data->ss_effects_data.ssil.ssil_final.is_valid()) { + Size2i rtsize = texture_storage->render_target_get_size(render_target); + copy_effects->copy_to_fb_rect(rb_data->ss_effects_data.ssil.ssil_final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false); + } + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && p_render_buffers->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT)) { + Size2i rtsize = texture_storage->render_target_get_size(render_target); + RID ambient_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT); + RID reflection_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION); + copy_effects->copy_to_fb_rect(ambient_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture, p_render_buffers->get_view_count() > 1); + } +} + +void RenderForwardClustered::_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) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + + ERR_FAIL_COND(!light_storage->owns_light_instance(p_light)); + + RID base = light_storage->light_instance_get_base_light(p_light); + + Rect2i atlas_rect; + uint32_t atlas_size = 1; + RID atlas_fb; + + bool using_dual_paraboloid = false; + bool using_dual_paraboloid_flip = false; + Vector2i dual_paraboloid_offset; + RID render_fb; + RID render_texture; + float zfar; + + bool use_pancake = false; + bool render_cubemap = false; + bool finalize_cubemap = false; + + bool flip_y = false; + + Projection light_projection; + Transform3D light_transform; + + if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) { + //set pssm stuff + uint64_t last_scene_shadow_pass = light_storage->light_instance_get_shadow_pass(p_light); + if (last_scene_shadow_pass != get_scene_pass()) { + light_storage->light_instance_set_directional_rect(p_light, light_storage->get_directional_shadow_rect()); + light_storage->directional_shadow_increase_current_light(); + light_storage->light_instance_set_shadow_pass(p_light, get_scene_pass()); + } + + use_pancake = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0; + light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass); + light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass); + + atlas_rect = light_storage->light_instance_get_directional_rect(p_light); + + if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { + atlas_rect.size.width /= 2; + atlas_rect.size.height /= 2; + + if (p_pass == 1) { + atlas_rect.position.x += atlas_rect.size.width; + } else if (p_pass == 2) { + atlas_rect.position.y += atlas_rect.size.height; + } else if (p_pass == 3) { + atlas_rect.position += atlas_rect.size; + } + } else if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { + atlas_rect.size.height /= 2; + + if (p_pass == 0) { + } else { + atlas_rect.position.y += atlas_rect.size.height; + } + } + + int directional_shadow_size = light_storage->directional_shadow_get_size(); + atlas_rect.position /= directional_shadow_size; + atlas_rect.size /= directional_shadow_size; + + light_storage->light_instance_set_directional_shadow_atlas_rect(p_light, p_pass, atlas_rect); + + zfar = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE); + + render_fb = light_storage->direction_shadow_get_fb(); + render_texture = RID(); + flip_y = true; + + } else { + //set from shadow atlas + + ERR_FAIL_COND(!light_storage->owns_shadow_atlas(p_shadow_atlas)); + ERR_FAIL_COND(!light_storage->shadow_atlas_owns_light_instance(p_shadow_atlas, p_light)); + + RSG::light_storage->shadow_atlas_update(p_shadow_atlas); + + uint32_t key = light_storage->shadow_atlas_get_light_instance_key(p_shadow_atlas, p_light); + + uint32_t quadrant = (key >> RendererRD::LightStorage::QUADRANT_SHIFT) & 0x3; + uint32_t shadow = key & RendererRD::LightStorage::SHADOW_INDEX_MASK; + uint32_t subdivision = light_storage->shadow_atlas_get_quadrant_subdivision(p_shadow_atlas, quadrant); + + ERR_FAIL_INDEX((int)shadow, light_storage->shadow_atlas_get_quadrant_shadow_size(p_shadow_atlas, quadrant)); + + uint32_t shadow_atlas_size = light_storage->shadow_atlas_get_size(p_shadow_atlas); + uint32_t quadrant_size = shadow_atlas_size >> 1; + + atlas_rect.position.x = (quadrant & 1) * quadrant_size; + atlas_rect.position.y = (quadrant >> 1) * quadrant_size; + + uint32_t shadow_size = (quadrant_size / subdivision); + atlas_rect.position.x += (shadow % subdivision) * shadow_size; + atlas_rect.position.y += (shadow / subdivision) * shadow_size; + + atlas_rect.size.width = shadow_size; + atlas_rect.size.height = shadow_size; + + zfar = light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE); + + if (light_storage->light_get_type(base) == RS::LIGHT_OMNI) { + bool wrap = (shadow + 1) % subdivision == 0; + dual_paraboloid_offset = wrap ? Vector2i(1 - subdivision, 1) : Vector2i(1, 0); + + if (light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) { + render_texture = light_storage->get_cubemap(shadow_size / 2); + render_fb = light_storage->get_cubemap_fb(shadow_size / 2, p_pass); + + light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass); + light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass); + render_cubemap = true; + finalize_cubemap = p_pass == 5; + atlas_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas); + + atlas_size = shadow_atlas_size; + + if (p_pass == 0) { + _render_shadow_begin(); + } + + } else { + atlas_rect.position.x += 1; + atlas_rect.position.y += 1; + atlas_rect.size.x -= 2; + atlas_rect.size.y -= 2; + + atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset; + + light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0); + light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0); + + using_dual_paraboloid = true; + using_dual_paraboloid_flip = p_pass == 1; + render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas); + flip_y = true; + } + + } else if (light_storage->light_get_type(base) == RS::LIGHT_SPOT) { + light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0); + light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0); + + render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas); + + flip_y = true; + } + } + + if (render_cubemap) { + //rendering to cubemap + _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); + if (finalize_cubemap) { + _render_shadow_process(); + _render_shadow_end(); + //reblit + Rect2 atlas_rect_norm = atlas_rect; + atlas_rect_norm.position /= float(atlas_size); + atlas_rect_norm.size /= float(atlas_size); + 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); + atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size; + 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); + + //restore transform so it can be properly used + light_storage->light_instance_set_shadow_transform(p_light, Projection(), light_storage->light_instance_get_base_transform(p_light), zfar, 0, 0, 0); + } + + } else { + //render shadow + _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); + } } void RenderForwardClustered::_render_shadow_begin() { @@ -1894,7 +2642,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu RD::get_singleton()->draw_command_end_label(); } -void RenderForwardClustered::_base_uniforms_changed() { +void RenderForwardClustered::base_uniforms_changed() { if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); } @@ -2010,14 +2758,14 @@ void RenderForwardClustered::_update_render_base_uniform_set() { RD::Uniform u; u.binding = 5; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.append_id(get_omni_light_buffer()); + u.append_id(RendererRD::LightStorage::get_singleton()->get_omni_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; u.binding = 6; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.append_id(get_spot_light_buffer()); + u.append_id(RendererRD::LightStorage::get_singleton()->get_spot_light_buffer()); uniforms.push_back(u); } @@ -2025,14 +2773,14 @@ void RenderForwardClustered::_update_render_base_uniform_set() { RD::Uniform u; u.binding = 7; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.append_id(get_reflection_probe_buffer()); + u.append_id(RendererRD::LightStorage::get_singleton()->get_reflection_probe_buffer()); uniforms.push_back(u); } { RD::Uniform u; u.binding = 8; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.append_id(get_directional_light_buffer()); + u.append_id(RendererRD::LightStorage::get_singleton()->get_directional_light_buffer()); uniforms.push_back(u); } { @@ -2069,7 +2817,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() { RD::Uniform u; u.binding = 13; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.append_id(get_decal_buffer()); + u.append_id(RendererRD::TextureStorage::get_singleton()->get_decal_buffer()); uniforms.push_back(u); } @@ -2147,7 +2895,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend uniforms.push_back(u); } { - RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID(); + 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(); RD::Uniform u; u.binding = 4; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; @@ -2164,7 +2912,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture; if (p_render_data && p_render_data->shadow_atlas.is_valid()) { - texture = shadow_atlas_get_texture(p_render_data->shadow_atlas); + texture = RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_render_data->shadow_atlas); } if (!texture.is_valid()) { texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH); @@ -2176,8 +2924,8 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend RD::Uniform u; u.binding = 6; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) { - u.append_id(directional_shadow_get_texture()); + if (p_use_directional_shadow_atlas && RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture().is_valid()) { + u.append_id(RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture()); } else { u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH)); } @@ -2191,7 +2939,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { if (p_render_data && i < p_render_data->lightmaps->size()) { - RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]); + RID base = light_storage->lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]); RID texture = light_storage->lightmap_get_texture(base); RID rd_texture = texture_storage->texture_get_rd_texture(texture); u.append_id(rd_texture); @@ -2267,7 +3015,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend RD::Uniform u; u.binding = 13; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID aot = rb_data.is_valid() ? rb->get_ao_texture() : RID(); + RID aot = rb_data.is_valid() ? rb_data->get_ao_texture() : RID(); RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); u.append_id(texture); uniforms.push_back(u); @@ -2353,7 +3101,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend RD::Uniform u; u.binding = 20; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID ssil = rb_data.is_valid() ? rb->get_ssil_texture() : RID(); + RID ssil = rb_data.is_valid() ? rb_data->get_ssil_texture() : RID(); RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); u.append_id(texture); uniforms.push_back(u); @@ -2512,6 +3260,26 @@ RID RenderForwardClustered::_render_buffers_get_velocity_texture(Ref<RenderScene return p_render_buffers->get_velocity_buffer(p_render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED); } +void RenderForwardClustered::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { + ss_effects->ssao_set_quality(p_quality, p_half_size, p_adaptive_target, p_blur_passes, p_fadeout_from, p_fadeout_to); +} + +void RenderForwardClustered::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { + ss_effects->ssil_set_quality(p_quality, p_half_size, p_adaptive_target, p_blur_passes, p_fadeout_from, p_fadeout_to); +} + +void RenderForwardClustered::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { + ss_effects->ssr_set_roughness_quality(p_quality); +} + +void RenderForwardClustered::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) { + ss_effects->sss_set_quality(p_quality); +} + +void RenderForwardClustered::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) { + ss_effects->sss_set_scale(p_scale, p_depth_scale); +} + RenderForwardClustered *RenderForwardClustered::singleton = nullptr; void RenderForwardClustered::GeometryInstanceForwardClustered::_mark_dirty() { @@ -2831,7 +3599,7 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p ginstance->store_transform_cache = store_transform; ginstance->can_sdfgi = false; - if (!lightmap_instance_is_valid(ginstance->lightmap_instance)) { + if (!RendererRD::LightStorage::get_singleton()->lightmap_instance_is_valid(ginstance->lightmap_instance)) { if (ginstance->voxel_gi_instances[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) { ginstance->can_sdfgi = true; } @@ -3013,7 +3781,7 @@ void RenderForwardClustered::_update_shader_quality_settings() { scene_shader.set_default_specialization_constants(spec_constants); - _base_uniforms_changed(); //also need this + base_uniforms_changed(); //also need this } RenderForwardClustered::RenderForwardClustered() { @@ -3056,15 +3824,31 @@ RenderForwardClustered::RenderForwardClustered() { scene_shader.init(defines); } + /* shadow sampler */ + { + RD::SamplerState sampler; + sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.enable_compare = true; + sampler.compare_op = RD::COMPARE_OP_LESS; + shadow_sampler = RD::get_singleton()->sampler_create(sampler); + } + render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances"); _update_shader_quality_settings(); resolve_effects = memnew(RendererRD::Resolve()); taa = memnew(RendererRD::TAA); + ss_effects = memnew(RendererRD::SSEffects); } RenderForwardClustered::~RenderForwardClustered() { + if (ss_effects != nullptr) { + memdelete(ss_effects); + ss_effects = nullptr; + } + if (taa != nullptr) { memdelete(taa); taa = nullptr; @@ -3075,7 +3859,8 @@ RenderForwardClustered::~RenderForwardClustered() { resolve_effects = nullptr; } - directional_shadow_atlas_set_size(0); + RD::get_singleton()->free(shadow_sampler); + RSG::light_storage->directional_shadow_atlas_set_size(0); { for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) { diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index cde241f231..55f1ef01af 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -32,7 +32,9 @@ #define RENDER_FORWARD_CLUSTERED_H #include "core/templates/paged_allocator.h" +#include "servers/rendering/renderer_rd/cluster_builder_rd.h" #include "servers/rendering/renderer_rd/effects/resolve.h" +#include "servers/rendering/renderer_rd/effects/ss_effects.h" #include "servers/rendering/renderer_rd/effects/taa.h" #include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h" #include "servers/rendering/renderer_rd/pipeline_cache_rd.h" @@ -99,7 +101,21 @@ class RenderForwardClustered : public RendererSceneRenderRD { RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1; public: - //for rendering, may be MSAAd + ClusterBuilderRD *cluster_builder = nullptr; + + struct SSEffectsData { + RID linear_depth; + Vector<RID> linear_depth_slices; + + RID downsample_uniform_set; + + Projection last_frame_projection; + Transform3D last_frame_transform; + + RendererRD::SSEffects::SSAORenderBuffers ssao; + RendererRD::SSEffects::SSILRenderBuffers ssil; + RendererRD::SSEffects::SSRRenderBuffers ssr; + } ss_effects_data; enum DepthFrameBufferType { DEPTH_FB, @@ -139,6 +155,9 @@ class RenderForwardClustered : public RendererSceneRenderRD { RID get_depth_fb(DepthFrameBufferType p_type = DEPTH_FB); RID get_specular_only_fb(); + RID get_ao_texture() const { return ss_effects_data.ssao.ao_final; } + RID get_ssil_texture() const { return ss_effects_data.ssil.ssil_final; } + virtual void configure(RenderSceneBuffersRD *p_render_buffers) override; virtual void free_data() override; }; @@ -149,10 +168,6 @@ class RenderForwardClustered : public RendererSceneRenderRD { uint64_t lightmap_texture_array_version = 0xFFFFFFFF; - virtual void _base_uniforms_changed() override; - virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override; - virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override; - bool base_uniform_set_updated = false; void _update_render_base_uniform_set(); RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); @@ -230,6 +245,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { float sh[9 * 4]; }; + // When changing any of these enums, remember to change the corresponding enums in the shader files as well. enum { INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4, INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5, @@ -557,16 +573,61 @@ class RenderForwardClustered : public RendererSceneRenderRD { virtual void _update_shader_quality_settings() override; + /* Effects */ + RendererRD::Resolve *resolve_effects = nullptr; RendererRD::TAA *taa = nullptr; + RendererRD::SSEffects *ss_effects = nullptr; + + /* Cluster builder */ + + ClusterBuilderSharedDataRD cluster_builder_shared; + ClusterBuilderRD *current_cluster_builder = nullptr; + + /* SDFGI */ + void _update_sdfgi(RenderDataRD *p_render_data); + + /* Volumetric fog */ + RID shadow_sampler; + + void _update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes); + + /* Render shadows */ + + void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_shadow_begin(); + void _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 = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_shadow_process(); + void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL); + + /* Render Scene */ + void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection); + void _process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform); + void _copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers); + void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer); + void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive); + void _process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera); + + /* Debug */ + void _debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers); protected: - virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override; + /* setup */ + + virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override; + virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override; + + virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; + virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; + virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override; - virtual void _render_shadow_begin() override; - virtual void _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 = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) override; - virtual void _render_shadow_process() override; - virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override; + virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override; + virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override; + + /* Rendering */ + + virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override; + virtual void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) override; virtual void _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) override; virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; @@ -576,6 +637,15 @@ protected: public: static RenderForwardClustered *get_singleton() { return singleton; } + ClusterBuilderSharedDataRD *get_cluster_builder_shared() { return &cluster_builder_shared; } + RendererRD::SSEffects *get_ss_effects() { return ss_effects; } + + /* callback from updating our lighting UBOs, used to populate cluster builder */ + virtual void setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_extents) override; + virtual void setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) override; + virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_extents) override; + + virtual void base_uniforms_changed() override; _FORCE_INLINE_ virtual void update_uniform_sets() override { base_uniform_set_updated = true; _update_render_base_uniform_set(); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index f458063aea..c3ce1b05f1 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -39,7 +39,7 @@ using namespace RendererSceneRenderImplementation; -RenderForwardMobile::ForwardID RenderForwardMobile::_allocate_forward_id(ForwardIDType p_type) { +RendererRD::ForwardID RenderForwardMobile::ForwardIDStorageMobile::allocate_forward_id(RendererRD::ForwardIDType p_type) { int32_t index = -1; for (uint32_t i = 0; i < forward_id_allocators[p_type].allocations.size(); i++) { if (forward_id_allocators[p_type].allocations[i] == false) { @@ -58,15 +58,66 @@ RenderForwardMobile::ForwardID RenderForwardMobile::_allocate_forward_id(Forward return index; } -void RenderForwardMobile::_free_forward_id(ForwardIDType p_type, ForwardID p_id) { - ERR_FAIL_INDEX(p_id, (ForwardID)forward_id_allocators[p_type].allocations.size()); +void RenderForwardMobile::ForwardIDStorageMobile::free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) { + ERR_FAIL_INDEX(p_id, (RendererRD::ForwardID)forward_id_allocators[p_type].allocations.size()); forward_id_allocators[p_type].allocations[p_id] = false; } -void RenderForwardMobile::_map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) { +void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) { forward_id_allocators[p_type].map[p_id] = p_index; } +void RenderForwardMobile::ForwardIDStorageMobile::fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) { + // first zero out our indices + + p_push_constant->omni_lights[0] = 0xFFFF; + p_push_constant->omni_lights[1] = 0xFFFF; + + p_push_constant->spot_lights[0] = 0xFFFF; + p_push_constant->spot_lights[1] = 0xFFFF; + + p_push_constant->decals[0] = 0xFFFF; + p_push_constant->decals[1] = 0xFFFF; + + p_push_constant->reflection_probes[0] = 0xFFFF; + p_push_constant->reflection_probes[1] = 0xFFFF; + + if (p_instance->omni_light_count == 0) { + spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS; + } + if (p_instance->spot_light_count == 0) { + spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS; + } + if (p_instance->reflection_probe_count == 0) { + spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES; + } + if (p_instance->decals_count == 0) { + spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS; + } + + for (uint32_t i = 0; i < MAX_RDL_CULL; i++) { + uint32_t ofs = i < 4 ? 0 : 1; + uint32_t shift = (i & 0x3) << 3; + uint32_t mask = ~(0xFF << shift); + if (i < p_instance->omni_light_count) { + p_push_constant->omni_lights[ofs] &= mask; + p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift; + } + if (i < p_instance->spot_light_count) { + p_push_constant->spot_lights[ofs] &= mask; + p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift; + } + if (i < p_instance->decals_count) { + p_push_constant->decals[ofs] &= mask; + p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift; + } + if (i < p_instance->reflection_probe_count) { + p_push_constant->reflection_probes[ofs] &= mask; + p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift; + } + } +} + /* Render buffer */ void RenderForwardMobile::RenderBufferDataForwardMobile::free_data() { @@ -300,6 +351,7 @@ bool RenderForwardMobile::_render_buffers_can_be_storage() { } RID 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) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); //there should always be enough uniform buffers for render passes, otherwise bugs @@ -340,7 +392,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ } { - RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID(); + 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(); RD::Uniform u; u.binding = 3; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; @@ -358,7 +410,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture; if (p_render_data && p_render_data->shadow_atlas.is_valid()) { - texture = shadow_atlas_get_texture(p_render_data->shadow_atlas); + texture = light_storage->shadow_atlas_get_texture(p_render_data->shadow_atlas); } if (!texture.is_valid()) { texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH); @@ -370,8 +422,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ RD::Uniform u; u.binding = 5; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) { - u.append_id(directional_shadow_get_texture()); + if (p_use_directional_shadow_atlas && light_storage->directional_shadow_get_texture().is_valid()) { + u.append_id(light_storage->directional_shadow_get_texture()); } else { u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH)); } @@ -387,8 +439,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { if (p_render_data && i < p_render_data->lightmaps->size()) { - RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]); - RID texture = RendererRD::LightStorage::get_singleton()->lightmap_get_texture(base); + RID base = light_storage->lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]); + RID texture = light_storage->lightmap_get_texture(base); RID rd_texture = texture_storage->texture_get_rd_texture(texture); u.append_id(rd_texture); } else { @@ -467,6 +519,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ } void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + // This probably needs to change... scene_state.lightmaps_used = 0; for (int i = 0; i < (int)p_lightmaps.size(); i++) { @@ -474,20 +528,20 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co break; } - RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]); + RID lightmap = light_storage->lightmap_instance_get_lightmap(p_lightmaps[i]); - Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis; + Basis to_lm = light_storage->lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis; to_lm = to_lm.inverse().transposed(); //will transform normals RendererRD::MaterialStorage::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform); scene_state.lightmaps[i].exposure_normalization = 1.0; if (p_render_data->camera_attributes.is_valid()) { - float baked_exposure = RendererRD::LightStorage::get_singleton()->lightmap_get_baked_exposure_normalization(lightmap); + float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap); float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); scene_state.lightmaps[i].exposure_normalization = enf / baked_exposure; } scene_state.lightmap_ids[i] = p_lightmaps[i]; - scene_state.lightmap_has_sh[i] = RendererRD::LightStorage::get_singleton()->lightmap_uses_spherical_harmonics(lightmap); + scene_state.lightmap_has_sh[i] = light_storage->lightmap_uses_spherical_harmonics(lightmap); scene_state.lightmaps_used++; } @@ -496,12 +550,103 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co } } +void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + + p_render_data->cube_shadows.clear(); + p_render_data->shadows.clear(); + p_render_data->directional_shadows.clear(); + + Plane camera_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin); + float lod_distance_multiplier = p_render_data->scene_data->cam_projection.get_lod_multiplier(); + { + for (int i = 0; i < p_render_data->render_shadow_count; i++) { + RID li = p_render_data->render_shadows[i].light; + RID base = light_storage->light_instance_get_base_light(li); + + if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) { + p_render_data->directional_shadows.push_back(i); + } else if (light_storage->light_get_type(base) == RS::LIGHT_OMNI && light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) { + p_render_data->cube_shadows.push_back(i); + } else { + p_render_data->shadows.push_back(i); + } + } + + //cube shadows are rendered in their own way + for (uint32_t i = 0; i < p_render_data->cube_shadows.size(); i++) { + _render_shadow_pass(p_render_data->render_shadows[p_render_data->cube_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->cube_shadows[i]].pass, p_render_data->render_shadows[p_render_data->cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); + } + + if (p_render_data->directional_shadows.size()) { + //open the pass for directional shadows + light_storage->update_directional_shadow_atlas(); + 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); + RD::get_singleton()->draw_list_end(); + } + } + + bool render_shadows = p_render_data->directional_shadows.size() || p_render_data->shadows.size(); + + if (render_shadows) { + RENDER_TIMESTAMP("Render Shadows"); + } + + //prepare shadow rendering + if (render_shadows) { + _render_shadow_begin(); + + //render directional shadows + for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) { + _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); + } + //render positional shadows + for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) { + _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); + } + + _render_shadow_process(); + + _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER); + } + + //full barrier here, we need raster, transfer and compute and it depends from the previous work + RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL); + + bool using_shadows = true; + + if (p_render_data->reflection_probe.is_valid()) { + if (!RSG::light_storage->reflection_probe_renders_shadows(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { + using_shadows = false; + } + } else { + //do not render reflections when rendering a reflection probe + 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); + } + + uint32_t directional_light_count = 0; + uint32_t positional_light_count = 0; + 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); + texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse()); + + p_render_data->directional_light_count = directional_light_count; +} + void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + + Ref<RenderSceneBuffersRD> rb; Ref<RenderBufferDataForwardMobile> rb_data; if (p_render_data->render_buffers.is_valid()) { - rb_data = p_render_data->render_buffers->get_custom_data(RB_SCOPE_MOBILE); + rb = p_render_data->render_buffers; + rb_data = rb->get_custom_data(RB_SCOPE_MOBILE); } + RENDER_TIMESTAMP("Prepare 3D Scene"); + + _update_vrs(rb); + RENDER_TIMESTAMP("Setup 3D Scene"); /* TODO @@ -532,9 +677,6 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color bool using_subpass_transparent = true; bool using_subpass_post_process = true; - bool using_ssr = false; // I don't think we support this in our mobile renderer so probably should phase it out - bool using_sss = false; // I don't think we support this in our mobile renderer so probably should phase it out - // fill our render lists early so we can find out if we use various features _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR); render_list[RENDER_LIST_OPAQUE].sort_by_key(); @@ -559,7 +701,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color using_subpass_post_process = false; } - if (using_ssr || using_sss || scene_state.used_screen_texture || scene_state.used_depth_texture) { + if (scene_state.used_screen_texture || scene_state.used_depth_texture) { // can't use our last two subpasses using_subpass_transparent = false; using_subpass_post_process = false; @@ -576,13 +718,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_TWO_SUBPASSES); } } else if (p_render_data->reflection_probe.is_valid()) { - uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe); + uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe); screen_size.x = resolution; screen_size.y = resolution; - framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass); + framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass); - if (RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { + if (light_storage->reflection_probe_is_interior(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { p_render_data->environment = RID(); //no environment on interiors } @@ -713,8 +855,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers } - RID nullrids[RendererSceneRender::MAX_RENDER_VIEWS]; - _pre_opaque_render(p_render_data, false, false, false, nullrids, RID()); + _pre_opaque_render(p_render_data); uint32_t spec_constant_base_flags = 0; @@ -758,8 +899,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true); - bool can_continue_color = !using_subpass_transparent && !scene_state.used_screen_texture && !using_ssr && !using_sss; - bool can_continue_depth = !using_subpass_transparent && !scene_state.used_depth_texture && !using_ssr && !using_sss; + bool can_continue_color = !using_subpass_transparent && !scene_state.used_screen_texture; + bool can_continue_depth = !using_subpass_transparent && !scene_state.used_depth_texture; { // regular forward for now @@ -917,10 +1058,190 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (rb_data.is_valid()) { _disable_clear_request(p_render_data); } + + if (rb.is_valid()) { + _render_buffers_debug_draw(rb, p_render_data->shadow_atlas, p_render_data->occluder_debug_tex); + } } /* these are being called from RendererSceneRenderRD::_pre_opaque_render */ +void 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) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + + ERR_FAIL_COND(!light_storage->owns_light_instance(p_light)); + + RID base = light_storage->light_instance_get_base_light(p_light); + + Rect2i atlas_rect; + uint32_t atlas_size = 1; + RID atlas_fb; + + bool using_dual_paraboloid = false; + bool using_dual_paraboloid_flip = false; + Vector2i dual_paraboloid_offset; + RID render_fb; + RID render_texture; + float zfar; + + bool use_pancake = false; + bool render_cubemap = false; + bool finalize_cubemap = false; + + bool flip_y = false; + + Projection light_projection; + Transform3D light_transform; + + if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) { + //set pssm stuff + uint64_t last_scene_shadow_pass = light_storage->light_instance_get_shadow_pass(p_light); + if (last_scene_shadow_pass != get_scene_pass()) { + light_storage->light_instance_set_directional_rect(p_light, light_storage->get_directional_shadow_rect()); + light_storage->directional_shadow_increase_current_light(); + light_storage->light_instance_set_shadow_pass(p_light, get_scene_pass()); + } + + use_pancake = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0; + light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass); + light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass); + + atlas_rect = light_storage->light_instance_get_directional_rect(p_light); + + if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { + atlas_rect.size.width /= 2; + atlas_rect.size.height /= 2; + + if (p_pass == 1) { + atlas_rect.position.x += atlas_rect.size.width; + } else if (p_pass == 2) { + atlas_rect.position.y += atlas_rect.size.height; + } else if (p_pass == 3) { + atlas_rect.position += atlas_rect.size; + } + } else if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { + atlas_rect.size.height /= 2; + + if (p_pass == 0) { + } else { + atlas_rect.position.y += atlas_rect.size.height; + } + } + + int directional_shadow_size = light_storage->directional_shadow_get_size(); + atlas_rect.position /= directional_shadow_size; + atlas_rect.size /= directional_shadow_size; + + light_storage->light_instance_set_directional_shadow_atlas_rect(p_light, p_pass, atlas_rect); + + zfar = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE); + + render_fb = light_storage->direction_shadow_get_fb(); + render_texture = RID(); + flip_y = true; + + } else { + //set from shadow atlas + + ERR_FAIL_COND(!light_storage->owns_shadow_atlas(p_shadow_atlas)); + ERR_FAIL_COND(!light_storage->shadow_atlas_owns_light_instance(p_shadow_atlas, p_light)); + + RSG::light_storage->shadow_atlas_update(p_shadow_atlas); + + uint32_t key = light_storage->shadow_atlas_get_light_instance_key(p_shadow_atlas, p_light); + + uint32_t quadrant = (key >> RendererRD::LightStorage::QUADRANT_SHIFT) & 0x3; + uint32_t shadow = key & RendererRD::LightStorage::SHADOW_INDEX_MASK; + uint32_t subdivision = light_storage->shadow_atlas_get_quadrant_subdivision(p_shadow_atlas, quadrant); + + ERR_FAIL_INDEX((int)shadow, light_storage->shadow_atlas_get_quadrant_shadow_size(p_shadow_atlas, quadrant)); + + uint32_t shadow_atlas_size = light_storage->shadow_atlas_get_size(p_shadow_atlas); + uint32_t quadrant_size = shadow_atlas_size >> 1; + + atlas_rect.position.x = (quadrant & 1) * quadrant_size; + atlas_rect.position.y = (quadrant >> 1) * quadrant_size; + + uint32_t shadow_size = (quadrant_size / subdivision); + atlas_rect.position.x += (shadow % subdivision) * shadow_size; + atlas_rect.position.y += (shadow / subdivision) * shadow_size; + + atlas_rect.size.width = shadow_size; + atlas_rect.size.height = shadow_size; + + zfar = light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE); + + if (light_storage->light_get_type(base) == RS::LIGHT_OMNI) { + bool wrap = (shadow + 1) % subdivision == 0; + dual_paraboloid_offset = wrap ? Vector2i(1 - subdivision, 1) : Vector2i(1, 0); + + if (light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) { + render_texture = light_storage->get_cubemap(shadow_size / 2); + render_fb = light_storage->get_cubemap_fb(shadow_size / 2, p_pass); + + light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass); + light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass); + render_cubemap = true; + finalize_cubemap = p_pass == 5; + atlas_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas); + + atlas_size = shadow_atlas_size; + + if (p_pass == 0) { + _render_shadow_begin(); + } + + } else { + atlas_rect.position.x += 1; + atlas_rect.position.y += 1; + atlas_rect.size.x -= 2; + atlas_rect.size.y -= 2; + + atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset; + + light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0); + light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0); + + using_dual_paraboloid = true; + using_dual_paraboloid_flip = p_pass == 1; + render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas); + flip_y = true; + } + + } else if (light_storage->light_get_type(base) == RS::LIGHT_SPOT) { + light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0); + light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0); + + render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas); + + flip_y = true; + } + } + + if (render_cubemap) { + //rendering to cubemap + _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); + if (finalize_cubemap) { + _render_shadow_process(); + _render_shadow_end(); + //reblit + Rect2 atlas_rect_norm = atlas_rect; + atlas_rect_norm.position /= float(atlas_size); + atlas_rect_norm.size /= float(atlas_size); + 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); + atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size; + 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); + + //restore transform so it can be properly used + light_storage->light_instance_set_shadow_transform(p_light, Projection(), light_storage->light_instance_get_base_transform(p_light), zfar, 0, 0, 0); + } + + } else { + //render shadow + _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); + } +} + void RenderForwardMobile::_render_shadow_begin() { scene_state.shadow_passes.clear(); RD::get_singleton()->draw_command_begin_label("Shadow Setup"); @@ -1146,7 +1467,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *> } void 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) { - // we don't do GI in low end.. + // we don't do SDFGI in low end.. } void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) { @@ -1189,7 +1510,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const RD::get_singleton()->draw_command_end_label(); } -void RenderForwardMobile::_base_uniforms_changed() { +void RenderForwardMobile::base_uniforms_changed() { if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); } @@ -1305,14 +1626,14 @@ void RenderForwardMobile::_update_render_base_uniform_set() { RD::Uniform u; u.binding = 5; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.append_id(get_omni_light_buffer()); + u.append_id(RendererRD::LightStorage::get_singleton()->get_omni_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; u.binding = 6; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.append_id(get_spot_light_buffer()); + u.append_id(RendererRD::LightStorage::get_singleton()->get_spot_light_buffer()); uniforms.push_back(u); } @@ -1320,14 +1641,14 @@ void RenderForwardMobile::_update_render_base_uniform_set() { RD::Uniform u; u.binding = 7; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.append_id(get_reflection_probe_buffer()); + u.append_id(RendererRD::LightStorage::get_singleton()->get_reflection_probe_buffer()); uniforms.push_back(u); } { RD::Uniform u; u.binding = 8; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.append_id(get_directional_light_buffer()); + u.append_id(RendererRD::LightStorage::get_singleton()->get_directional_light_buffer()); uniforms.push_back(u); } { @@ -1364,7 +1685,7 @@ void RenderForwardMobile::_update_render_base_uniform_set() { RD::Uniform u; u.binding = 13; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.append_id(get_decal_buffer()); + u.append_id(RendererRD::TextureStorage::get_singleton()->get_decal_buffer()); uniforms.push_back(u); } @@ -1584,7 +1905,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const void 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) { Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers; RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID(); - RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID(); + 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(); // May do this earlier in RenderSceneRenderRD::render_scene if (p_index >= (int)scene_state.uniform_buffers.size()) { @@ -1665,57 +1986,6 @@ void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_para } } -void RenderForwardMobile::_fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) { - // first zero out our indices - - p_push_constant->omni_lights[0] = 0xFFFF; - p_push_constant->omni_lights[1] = 0xFFFF; - - p_push_constant->spot_lights[0] = 0xFFFF; - p_push_constant->spot_lights[1] = 0xFFFF; - - p_push_constant->decals[0] = 0xFFFF; - p_push_constant->decals[1] = 0xFFFF; - - p_push_constant->reflection_probes[0] = 0xFFFF; - p_push_constant->reflection_probes[1] = 0xFFFF; - - if (p_instance->omni_light_count == 0) { - spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS; - } - if (p_instance->spot_light_count == 0) { - spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS; - } - if (p_instance->reflection_probe_count == 0) { - spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES; - } - if (p_instance->decals_count == 0) { - spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS; - } - - for (uint32_t i = 0; i < MAX_RDL_CULL; i++) { - uint32_t ofs = i < 4 ? 0 : 1; - uint32_t shift = (i & 0x3) << 3; - uint32_t mask = ~(0xFF << shift); - if (i < p_instance->omni_light_count) { - p_push_constant->omni_lights[ofs] &= mask; - p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift; - } - if (i < p_instance->spot_light_count) { - p_push_constant->spot_lights[ofs] &= mask; - p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift; - } - if (i < p_instance->decals_count) { - p_push_constant->decals[ofs] &= mask; - p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift; - } - if (i < p_instance->reflection_probe_count) { - p_push_constant->reflection_probes[ofs] &= mask; - p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift; - } - } -} - template <RenderForwardMobile::PassMode p_pass_mode> void 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) { RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); @@ -1797,7 +2067,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr if (inst->use_soft_shadow) { base_spec_constants |= 1 << SPEC_CONSTANT_USING_SOFT_SHADOWS; } - _fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst); + forward_id_storage_mobile->fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst); #ifdef DEBUG_ENABLED if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) { @@ -1989,17 +2259,17 @@ void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instances(co spot_light_count = 0; for (uint32_t i = 0; i < p_light_instance_count; i++) { - RS::LightType type = RenderForwardMobile::get_singleton()->light_instance_get_type(p_light_instances[i]); + RS::LightType type = RendererRD::LightStorage::get_singleton()->light_instance_get_type(p_light_instances[i]); switch (type) { case RS::LIGHT_OMNI: { if (omni_light_count < (uint32_t)MAX_RDL_CULL) { - omni_lights[omni_light_count] = RenderForwardMobile::get_singleton()->light_instance_get_forward_id(p_light_instances[i]); + omni_lights[omni_light_count] = RendererRD::LightStorage::get_singleton()->light_instance_get_forward_id(p_light_instances[i]); omni_light_count++; } } break; case RS::LIGHT_SPOT: { if (spot_light_count < (uint32_t)MAX_RDL_CULL) { - spot_lights[spot_light_count] = RenderForwardMobile::get_singleton()->light_instance_get_forward_id(p_light_instances[i]); + spot_lights[spot_light_count] = RendererRD::LightStorage::get_singleton()->light_instance_get_forward_id(p_light_instances[i]); spot_light_count++; } } break; @@ -2012,14 +2282,14 @@ void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instances(co void RenderForwardMobile::GeometryInstanceForwardMobile::pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) { reflection_probe_count = p_reflection_probe_instance_count < (uint32_t)MAX_RDL_CULL ? p_reflection_probe_instance_count : (uint32_t)MAX_RDL_CULL; for (uint32_t i = 0; i < reflection_probe_count; i++) { - reflection_probes[i] = RenderForwardMobile::get_singleton()->reflection_probe_instance_get_forward_id(p_reflection_probe_instances[i]); + reflection_probes[i] = RendererRD::LightStorage::get_singleton()->reflection_probe_instance_get_forward_id(p_reflection_probe_instances[i]); } } void RenderForwardMobile::GeometryInstanceForwardMobile::pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) { decals_count = p_decal_instance_count < (uint32_t)MAX_RDL_CULL ? p_decal_instance_count : (uint32_t)MAX_RDL_CULL; for (uint32_t i = 0; i < decals_count; i++) { - decals[i] = RenderForwardMobile::get_singleton()->decal_instance_get_forward_id(p_decal_instances[i]); + decals[i] = RendererRD::TextureStorage::get_singleton()->decal_instance_get_forward_id(p_decal_instances[i]); } } @@ -2387,10 +2657,6 @@ bool RenderForwardMobile::is_dynamic_gi_supported() const { return false; } -bool RenderForwardMobile::is_clustered_enabled() const { - return false; -} - bool RenderForwardMobile::is_volumetric_supported() const { return false; } @@ -2446,7 +2712,7 @@ void RenderForwardMobile::_update_shader_quality_settings() { scene_shader.set_default_specialization_constants(spec_constants); - _base_uniforms_changed(); //also need this + base_uniforms_changed(); //also need this } RenderForwardMobile::RenderForwardMobile() { @@ -2495,7 +2761,7 @@ RenderForwardMobile::RenderForwardMobile() { } RenderForwardMobile::~RenderForwardMobile() { - directional_shadow_atlas_set_size(0); + RSG::light_storage->directional_shadow_atlas_set_size(0); //clear base uniform set if still valid for (uint32_t i = 0; i < render_pass_uniform_sets.size(); i++) { diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 1b31d2749d..415bd79ad6 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -44,19 +44,12 @@ namespace RendererSceneRenderImplementation { class RenderForwardMobile : public RendererSceneRenderRD { friend SceneShaderForwardMobile; - struct ForwardIDAllocator { - LocalVector<bool> allocations; - LocalVector<uint8_t> map; - }; - - ForwardIDAllocator forward_id_allocators[FORWARD_ID_MAX]; +protected: + struct GeometryInstanceSurfaceDataCache; - virtual ForwardID _allocate_forward_id(ForwardIDType p_type) override; - virtual void _free_forward_id(ForwardIDType p_type, ForwardID p_id) override; - virtual void _map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) override; - virtual bool _uses_forward_ids() const override { return true; } +private: + static RenderForwardMobile *singleton; -protected: /* Scene Shader */ enum { @@ -157,8 +150,6 @@ protected: // PASS_MODE_SDF, }; - class GeometryInstanceForwardMobile; - struct GeometryInstanceSurfaceDataCache; struct RenderElementInfo; struct RenderListParameters { @@ -201,36 +192,27 @@ protected: } }; - virtual float _render_buffers_get_luminance_multiplier() override; - virtual RD::DataFormat _render_buffers_get_color_format() override; - virtual bool _render_buffers_can_be_storage() override; + /* Render shadows */ - RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0); - virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override; + void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_shadow_begin(); + void _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 = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_shadow_process(); + void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL); - virtual void _render_shadow_begin() override; - virtual void _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 = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) override; - virtual void _render_shadow_process() override; - virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override; + /* Render Scene */ - virtual void _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) override; - virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; - virtual void _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) override; - virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) override; + RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0); + void _pre_opaque_render(RenderDataRD *p_render_data); uint64_t lightmap_texture_array_version = 0xFFFFFFFF; - virtual void _base_uniforms_changed() override; void _update_render_base_uniform_set(); - virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override; - virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override; void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false); void _fill_element_info(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1); // void _update_instance_data_buffer(RenderListType p_render_list); - static RenderForwardMobile *singleton; - void _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 = false, bool p_pancake_shadows = false, int p_index = 0); void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform); @@ -369,9 +351,29 @@ protected: RenderList render_list[RENDER_LIST_MAX]; +protected: + /* setup */ + virtual void _update_shader_quality_settings() override; + + virtual float _render_buffers_get_luminance_multiplier() override; + virtual RD::DataFormat _render_buffers_get_color_format() override; + virtual bool _render_buffers_can_be_storage() override; + + virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override; + virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override; + + virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override{}; + virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override{}; + virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override{}; + + virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override{}; + virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override{}; + /* Geometry instance */ - // check which ones of these apply, probably all except GI and SDFGI + class GeometryInstanceForwardMobile; + + // When changing any of these enums, remember to change the corresponding enums in the shader files as well. enum { INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4, INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5, @@ -484,13 +486,13 @@ protected: // culled light info uint32_t reflection_probe_count = 0; - ForwardID reflection_probes[MAX_RDL_CULL]; + RendererRD::ForwardID reflection_probes[MAX_RDL_CULL]; uint32_t omni_light_count = 0; - ForwardID omni_lights[MAX_RDL_CULL]; + RendererRD::ForwardID omni_lights[MAX_RDL_CULL]; uint32_t spot_light_count = 0; - ForwardID spot_lights[MAX_RDL_CULL]; + RendererRD::ForwardID spot_lights[MAX_RDL_CULL]; uint32_t decals_count = 0; - ForwardID decals[MAX_RDL_CULL]; + RendererRD::ForwardID decals[MAX_RDL_CULL]; GeometryInstanceSurfaceDataCache *surface_caches = nullptr; @@ -513,9 +515,41 @@ protected: virtual void set_softshadow_projector_pairing(bool p_softshadow, bool p_projector) override; }; - _FORCE_INLINE_ void _fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance); + /* Rendering */ - void _update_shader_quality_settings() override; + virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override; + + virtual void _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) override; + virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; + virtual void _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) override; + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) override; + + /* Forward ID */ + + class ForwardIDStorageMobile : public RendererRD::ForwardIDStorage { + public: + struct ForwardIDAllocator { + LocalVector<bool> allocations; + LocalVector<uint8_t> map; + }; + + ForwardIDAllocator forward_id_allocators[RendererRD::FORWARD_ID_MAX]; + + public: + virtual RendererRD::ForwardID allocate_forward_id(RendererRD::ForwardIDType p_type) override; + virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) override; + virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) override; + virtual bool uses_forward_ids() const override { return true; } + + void fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance); + }; + + ForwardIDStorageMobile *forward_id_storage_mobile = nullptr; + + virtual RendererRD::ForwardIDStorage *create_forward_id_storage() override { + forward_id_storage_mobile = memnew(ForwardIDStorageMobile); + return forward_id_storage_mobile; + } public: static RenderForwardMobile *get_singleton() { return singleton; } @@ -544,8 +578,9 @@ public: virtual bool free(RID p_rid) override; + virtual void base_uniforms_changed() override; + virtual bool is_dynamic_gi_supported() const override; - virtual bool is_clustered_enabled() const override; virtual bool is_volumetric_supported() const override; virtual uint32_t get_max_elements() const override; diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index a50742f91a..dd3f62e509 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -44,13 +44,9 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID } for (int i = 0; i < p_amount; i++) { - RID texture = texture_storage->render_target_get_texture(p_render_targets[i].render_target); - ERR_CONTINUE(texture.is_null()); - RID rd_texture = texture_storage->texture_get_rd_texture(texture); + RID rd_texture = texture_storage->render_target_get_rd_texture(p_render_targets[i].render_target); ERR_CONTINUE(rd_texture.is_null()); - // TODO if keep_3d_linear was set when rendering to this render target we need to add a linear->sRGB conversion in. - if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) { Vector<RD::Uniform> uniforms; RD::Uniform u; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 74b8f0890f..6157d7d840 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -195,32 +195,6 @@ void RendererSceneRenderRD::environment_set_sdfgi_frames_to_update_light(RS::Env gi.sdfgi_frames_to_update_light = p_update; } -void RendererSceneRenderRD::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { - ssr_roughness_quality = p_quality; -} - -RS::EnvironmentSSRRoughnessQuality RendererSceneRenderRD::environment_get_ssr_roughness_quality() const { - return ssr_roughness_quality; -} - -void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { - ssao_quality = p_quality; - ssao_half_size = p_half_size; - ssao_adaptive_target = p_adaptive_target; - ssao_blur_passes = p_blur_passes; - ssao_fadeout_from = p_fadeout_from; - ssao_fadeout_to = p_fadeout_to; -} - -void RendererSceneRenderRD::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { - ssil_quality = p_quality; - ssil_half_size = p_half_size; - ssil_adaptive_target = p_adaptive_target; - ssil_blur_passes = p_blur_passes; - ssil_fadeout_from = p_fadeout_from; - ssil_fadeout_to = p_fadeout_to; -} - Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) { ERR_FAIL_COND_V(p_env.is_null(), Ref<Image>()); @@ -284,257 +258,7 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba } } -//////////////////////////////////////////////////////////// - -RID RendererSceneRenderRD::fog_volume_instance_create(RID p_fog_volume) { - return RendererRD::Fog::get_singleton()->fog_volume_instance_create(p_fog_volume); -} - -void RendererSceneRenderRD::fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) { - RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance); - ERR_FAIL_COND(!fvi); - fvi->transform = p_transform; -} -void RendererSceneRenderRD::fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) { - RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance); - ERR_FAIL_COND(!fvi); - fvi->active = p_active; -} - -RID RendererSceneRenderRD::fog_volume_instance_get_volume(RID p_fog_volume_instance) const { - RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance); - ERR_FAIL_COND_V(!fvi, RID()); - return fvi->volume; -} - -Vector3 RendererSceneRenderRD::fog_volume_instance_get_position(RID p_fog_volume_instance) const { - RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance); - ERR_FAIL_COND_V(!fvi, Vector3()); - - return fvi->transform.get_origin(); -} - -//////////////////////////////////////////////////////////// - -RID RendererSceneRenderRD::reflection_atlas_create() { - ReflectionAtlas ra; - ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count"); - ra.size = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_size"); - - if (is_clustered_enabled()) { - ra.cluster_builder = memnew(ClusterBuilderRD); - ra.cluster_builder->set_shared(&cluster_builder_shared); - ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID()); - } else { - ra.cluster_builder = nullptr; - } - - return reflection_atlas_owner.make_rid(ra); -} - -void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) { - ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas); - ERR_FAIL_COND(!ra); - - if (ra->size == p_reflection_size && ra->count == p_reflection_count) { - return; //no changes - } - - if (ra->cluster_builder) { - // only if we're using our cluster - ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID()); - } - - ra->size = p_reflection_size; - ra->count = p_reflection_count; - - if (ra->reflection.is_valid()) { - //clear and invalidate everything - RD::get_singleton()->free(ra->reflection); - ra->reflection = RID(); - RD::get_singleton()->free(ra->depth_buffer); - ra->depth_buffer = RID(); - for (int i = 0; i < ra->reflections.size(); i++) { - ra->reflections.write[i].data.clear_reflection_data(); - if (ra->reflections[i].owner.is_null()) { - continue; - } - reflection_probe_release_atlas_index(ra->reflections[i].owner); - //rp->atlasindex clear - } - - ra->reflections.clear(); - } -} - -int RendererSceneRenderRD::reflection_atlas_get_size(RID p_ref_atlas) const { - ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas); - ERR_FAIL_COND_V(!ra, 0); - - return ra->size; -} - -//////////////////////// -RID RendererSceneRenderRD::reflection_probe_instance_create(RID p_probe) { - ReflectionProbeInstance rpi; - rpi.probe = p_probe; - rpi.forward_id = _allocate_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE); - - return reflection_probe_instance_owner.make_rid(rpi); -} - -void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND(!rpi); - - rpi->transform = p_transform; - rpi->dirty = true; -} - -void RendererSceneRenderRD::reflection_probe_release_atlas_index(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND(!rpi); - - if (rpi->atlas.is_null()) { - return; //nothing to release - } - ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); - ERR_FAIL_COND(!atlas); - ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size()); - atlas->reflections.write[rpi->atlas_index].owner = RID(); - rpi->atlas_index = -1; - rpi->atlas = RID(); -} - -bool RendererSceneRenderRD::reflection_probe_instance_needs_redraw(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, false); - - if (rpi->rendering) { - return false; - } - - if (rpi->dirty) { - return true; - } - - if (RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) { - return true; - } - - return rpi->atlas_index == -1; -} - -bool RendererSceneRenderRD::reflection_probe_instance_has_reflection(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, false); - - return rpi->atlas.is_valid(); -} - -bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { - ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas); - - ERR_FAIL_COND_V(!atlas, false); - - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, false); - - RD::get_singleton()->draw_command_begin_label("Reflection probe render"); - - if (RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) { - WARN_PRINT("ReflectionProbes set to UPDATE_ALWAYS must have an atlas size of 256. Please update the atlas size in the ProjectSettings."); - reflection_atlas_set_size(p_reflection_atlas, 256, atlas->count); - } - - if (RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->reflections[0].data.layers[0].mipmaps.size() != 8) { - // Invalidate reflection atlas, need to regenerate - RD::get_singleton()->free(atlas->reflection); - atlas->reflection = RID(); - - for (int i = 0; i < atlas->reflections.size(); i++) { - if (atlas->reflections[i].owner.is_null()) { - continue; - } - reflection_probe_release_atlas_index(atlas->reflections[i].owner); - } - - atlas->reflections.clear(); - } - - if (atlas->reflection.is_null()) { - int mipmaps = MIN(sky.roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1); - mipmaps = RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS ? 8 : mipmaps; // always use 8 mipmaps with real time filtering - { - //reflection atlas was unused, create: - RD::TextureFormat tf; - tf.array_layers = 6 * atlas->count; - tf.format = _render_buffers_get_color_format(); - tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; - tf.mipmaps = mipmaps; - tf.width = atlas->size; - tf.height = atlas->size; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0); - - atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } - { - RD::TextureFormat tf; - tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; - tf.width = atlas->size; - tf.height = atlas->size; - tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - atlas->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } - atlas->reflections.resize(atlas->count); - for (int i = 0; i < atlas->count; i++) { - atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers, _render_buffers_get_color_format()); - for (int j = 0; j < 6; j++) { - atlas->reflections.write[i].fbs[j] = reflection_probe_create_framebuffer(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j], atlas->depth_buffer); - } - } - - Vector<RID> fb; - fb.push_back(atlas->depth_buffer); - atlas->depth_fb = RD::get_singleton()->framebuffer_create(fb); - } - - if (rpi->atlas_index == -1) { - for (int i = 0; i < atlas->reflections.size(); i++) { - if (atlas->reflections[i].owner.is_null()) { - rpi->atlas_index = i; - break; - } - } - //find the one used last - if (rpi->atlas_index == -1) { - //everything is in use, find the one least used via LRU - uint64_t pass_min = 0; - - for (int i = 0; i < atlas->reflections.size(); i++) { - ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.get_or_null(atlas->reflections[i].owner); - if (rpi2->last_pass < pass_min) { - pass_min = rpi2->last_pass; - rpi->atlas_index = i; - } - } - } - } - - if (rpi->atlas_index != -1) { // should we fail if this is still -1 ? - atlas->reflections.write[rpi->atlas_index].owner = p_instance; - } - - rpi->atlas = p_reflection_atlas; - rpi->rendering = true; - rpi->dirty = false; - rpi->processing_layer = 1; - rpi->processing_side = 0; - - RD::get_singleton()->draw_command_end_label(); - - return true; -} +/* REFLECTION PROBE */ RID RendererSceneRenderRD::reflection_probe_create_framebuffer(RID p_color, RID p_depth) { Vector<RID> fb; @@ -543,667 +267,39 @@ RID RendererSceneRenderRD::reflection_probe_create_framebuffer(RID p_color, RID return RD::get_singleton()->framebuffer_create(fb); } -bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, false); - ERR_FAIL_COND_V(!rpi->rendering, false); - ERR_FAIL_COND_V(rpi->atlas.is_null(), false); - - ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); - if (!atlas || rpi->atlas_index == -1) { - //does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering) - rpi->rendering = false; - return false; - } - - if (RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) { - // Using real time reflections, all roughness is done in one step - atlas->reflections.write[rpi->atlas_index].data.create_reflection_fast_filter(false); - rpi->rendering = false; - rpi->processing_side = 0; - rpi->processing_layer = 1; - return true; - } - - if (rpi->processing_layer > 1) { - atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(false, 10, rpi->processing_layer, sky.sky_ggx_samples_quality); - rpi->processing_layer++; - if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) { - rpi->rendering = false; - rpi->processing_side = 0; - rpi->processing_layer = 1; - return true; - } - return false; - - } else { - atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(false, rpi->processing_side, rpi->processing_layer, sky.sky_ggx_samples_quality); - } - - rpi->processing_side++; - if (rpi->processing_side == 6) { - rpi->processing_side = 0; - rpi->processing_layer++; - } - - return false; -} - -uint32_t RendererSceneRenderRD::reflection_probe_instance_get_resolution(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, 0); - - ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); - ERR_FAIL_COND_V(!atlas, 0); - return atlas->size; -} - -RID RendererSceneRenderRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, RID()); - ERR_FAIL_INDEX_V(p_index, 6, RID()); - - ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); - ERR_FAIL_COND_V(!atlas, RID()); - return atlas->reflections[rpi->atlas_index].fbs[p_index]; -} - -RID RendererSceneRenderRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, RID()); - ERR_FAIL_INDEX_V(p_index, 6, RID()); - - ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); - ERR_FAIL_COND_V(!atlas, RID()); - return atlas->depth_fb; -} - -/////////////////////////////////////////////////////////// - -RID RendererSceneRenderRD::shadow_atlas_create() { - return shadow_atlas_owner.make_rid(ShadowAtlas()); -} - -void RendererSceneRenderRD::_update_shadow_atlas(ShadowAtlas *shadow_atlas) { - if (shadow_atlas->size > 0 && shadow_atlas->depth.is_null()) { - RD::TextureFormat tf; - tf.format = shadow_atlas->use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT; - tf.width = shadow_atlas->size; - tf.height = shadow_atlas->size; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - - shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - Vector<RID> fb_tex; - fb_tex.push_back(shadow_atlas->depth); - shadow_atlas->fb = RD::get_singleton()->framebuffer_create(fb_tex); - } -} - -void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); - ERR_FAIL_COND(!shadow_atlas); - ERR_FAIL_COND(p_size < 0); - p_size = next_power_of_2(p_size); - - if (p_size == shadow_atlas->size && p_16_bits == shadow_atlas->use_16_bits) { - return; - } - - // erasing atlas - if (shadow_atlas->depth.is_valid()) { - RD::get_singleton()->free(shadow_atlas->depth); - shadow_atlas->depth = RID(); - } - for (int i = 0; i < 4; i++) { - //clear subdivisions - shadow_atlas->quadrants[i].shadows.clear(); - shadow_atlas->quadrants[i].shadows.resize(1 << shadow_atlas->quadrants[i].subdivision); - } - - //erase shadow atlas reference from lights - for (const KeyValue<RID, uint32_t> &E : shadow_atlas->shadow_owners) { - LightInstance *li = light_instance_owner.get_or_null(E.key); - ERR_CONTINUE(!li); - li->shadow_atlases.erase(p_atlas); - } - - //clear owners - shadow_atlas->shadow_owners.clear(); - - shadow_atlas->size = p_size; - shadow_atlas->use_16_bits = p_16_bits; -} - -void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); - ERR_FAIL_COND(!shadow_atlas); - ERR_FAIL_INDEX(p_quadrant, 4); - ERR_FAIL_INDEX(p_subdivision, 16384); - - uint32_t subdiv = next_power_of_2(p_subdivision); - if (subdiv & 0xaaaaaaaa) { //sqrt(subdiv) must be integer - subdiv <<= 1; - } - - subdiv = int(Math::sqrt((float)subdiv)); - - //obtain the number that will be x*x - - if (shadow_atlas->quadrants[p_quadrant].subdivision == subdiv) { - return; - } - - //erase all data from quadrant - for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) { - if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) { - shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); - LightInstance *li = light_instance_owner.get_or_null(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); - ERR_CONTINUE(!li); - li->shadow_atlases.erase(p_atlas); - } - } - - shadow_atlas->quadrants[p_quadrant].shadows.clear(); - shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv * subdiv); - shadow_atlas->quadrants[p_quadrant].subdivision = subdiv; - - //cache the smallest subdiv (for faster allocation in light update) - - shadow_atlas->smallest_subdiv = 1 << 30; - - for (int i = 0; i < 4; i++) { - if (shadow_atlas->quadrants[i].subdivision) { - shadow_atlas->smallest_subdiv = MIN(shadow_atlas->smallest_subdiv, shadow_atlas->quadrants[i].subdivision); - } - } - - if (shadow_atlas->smallest_subdiv == 1 << 30) { - shadow_atlas->smallest_subdiv = 0; - } - - //resort the size orders, simple bublesort for 4 elements.. - - int swaps = 0; - do { - swaps = 0; - - for (int i = 0; i < 3; i++) { - if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i + 1]].subdivision) { - SWAP(shadow_atlas->size_order[i], shadow_atlas->size_order[i + 1]); - swaps++; - } - } - } while (swaps > 0); -} - -bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) { - for (int i = p_quadrant_count - 1; i >= 0; i--) { - int qidx = p_in_quadrants[i]; - - if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) { - return false; - } - - //look for an empty space - int sc = shadow_atlas->quadrants[qidx].shadows.size(); - const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr(); - - int found_free_idx = -1; //found a free one - int found_used_idx = -1; //found existing one, must steal it - uint64_t min_pass = 0; // pass of the existing one, try to use the least recently used one (LRU fashion) - - for (int j = 0; j < sc; j++) { - if (!sarr[j].owner.is_valid()) { - found_free_idx = j; - break; - } - - LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner); - ERR_CONTINUE(!sli); - - if (sli->last_scene_pass != scene_pass) { - //was just allocated, don't kill it so soon, wait a bit.. - if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) { - continue; - } - - if (found_used_idx == -1 || sli->last_scene_pass < min_pass) { - found_used_idx = j; - min_pass = sli->last_scene_pass; - } - } - } - - if (found_free_idx == -1 && found_used_idx == -1) { - continue; //nothing found - } - - if (found_free_idx == -1 && found_used_idx != -1) { - found_free_idx = found_used_idx; - } - - r_quadrant = qidx; - r_shadow = found_free_idx; - - return true; - } - - return false; -} - -bool RendererSceneRenderRD::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) { - for (int i = p_quadrant_count - 1; i >= 0; i--) { - int qidx = p_in_quadrants[i]; - - if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) { - return false; - } - - //look for an empty space - int sc = shadow_atlas->quadrants[qidx].shadows.size(); - const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr(); - - int found_idx = -1; - uint64_t min_pass = 0; // sum of currently selected spots, try to get the least recently used pair - - for (int j = 0; j < sc - 1; j++) { - uint64_t pass = 0; - - if (sarr[j].owner.is_valid()) { - LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner); - ERR_CONTINUE(!sli); - - if (sli->last_scene_pass == scene_pass) { - continue; - } - - //was just allocated, don't kill it so soon, wait a bit.. - if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) { - continue; - } - pass += sli->last_scene_pass; - } - - if (sarr[j + 1].owner.is_valid()) { - LightInstance *sli = light_instance_owner.get_or_null(sarr[j + 1].owner); - ERR_CONTINUE(!sli); - - if (sli->last_scene_pass == scene_pass) { - continue; - } - - //was just allocated, don't kill it so soon, wait a bit.. - if (p_tick - sarr[j + 1].alloc_tick < shadow_atlas_realloc_tolerance_msec) { - continue; - } - pass += sli->last_scene_pass; - } - - if (found_idx == -1 || pass < min_pass) { - found_idx = j; - min_pass = pass; - - // we found two empty spots, no need to check the rest - if (pass == 0) { - break; - } - } - } - - if (found_idx == -1) { - continue; //nothing found - } - - r_quadrant = qidx; - r_shadow = found_idx; - - return true; - } - - return false; -} - -bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); - ERR_FAIL_COND_V(!shadow_atlas, false); - - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - ERR_FAIL_COND_V(!li, false); - - if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) { - return false; - } - - uint32_t quad_size = shadow_atlas->size >> 1; - int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage)); - - int valid_quadrants[4]; - int valid_quadrant_count = 0; - int best_size = -1; //best size found - int best_subdiv = -1; //subdiv for the best size - - //find the quadrants this fits into, and the best possible size it can fit into - for (int i = 0; i < 4; i++) { - int q = shadow_atlas->size_order[i]; - int sd = shadow_atlas->quadrants[q].subdivision; - if (sd == 0) { - continue; //unused - } - - int max_fit = quad_size / sd; - - if (best_size != -1 && max_fit > best_size) { - break; //too large - } - - valid_quadrants[valid_quadrant_count++] = q; - best_subdiv = sd; - - if (max_fit >= desired_fit) { - best_size = max_fit; - } - } - - ERR_FAIL_COND_V(valid_quadrant_count == 0, false); - - uint64_t tick = OS::get_singleton()->get_ticks_msec(); - - uint32_t old_key = ShadowAtlas::SHADOW_INVALID; - uint32_t old_quadrant = ShadowAtlas::SHADOW_INVALID; - uint32_t old_shadow = ShadowAtlas::SHADOW_INVALID; - int old_subdivision = -1; - - bool should_realloc = false; - bool should_redraw = false; - - if (shadow_atlas->shadow_owners.has(p_light_instance)) { - old_key = shadow_atlas->shadow_owners[p_light_instance]; - old_quadrant = (old_key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - old_shadow = old_key & ShadowAtlas::SHADOW_INDEX_MASK; - - should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec); - should_redraw = shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].version != p_light_version; - - if (!should_realloc) { - shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = p_light_version; - //already existing, see if it should redraw or it's just OK - return should_redraw; - } - - old_subdivision = shadow_atlas->quadrants[old_quadrant].subdivision; - } - - bool is_omni = li->light_type == RS::LIGHT_OMNI; - bool found_shadow = false; - int new_quadrant = -1; - int new_shadow = -1; - - if (is_omni) { - found_shadow = _shadow_atlas_find_omni_shadows(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow); - } else { - found_shadow = _shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow); - } - - if (found_shadow) { - if (old_quadrant != ShadowAtlas::SHADOW_INVALID) { - shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = 0; - shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].owner = RID(); - - if (old_key & ShadowAtlas::OMNI_LIGHT_FLAG) { - shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].version = 0; - shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].owner = RID(); - } - } - - uint32_t new_key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; - new_key |= new_shadow; - - ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; - _shadow_atlas_invalidate_shadow(sh, p_atlas, shadow_atlas, new_quadrant, new_shadow); - - sh->owner = p_light_instance; - sh->alloc_tick = tick; - sh->version = p_light_version; - - if (is_omni) { - new_key |= ShadowAtlas::OMNI_LIGHT_FLAG; - - int new_omni_shadow = new_shadow + 1; - ShadowAtlas::Quadrant::Shadow *extra_sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_omni_shadow]; - _shadow_atlas_invalidate_shadow(extra_sh, p_atlas, shadow_atlas, new_quadrant, new_omni_shadow); - - extra_sh->owner = p_light_instance; - extra_sh->alloc_tick = tick; - extra_sh->version = p_light_version; - } - - li->shadow_atlases.insert(p_atlas); - - //update it in map - shadow_atlas->shadow_owners[p_light_instance] = new_key; - //make it dirty, as it should redraw anyway - return true; - } - - return should_redraw; -} - -void RendererSceneRenderRD::_shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx) { - if (p_shadow->owner.is_valid()) { - LightInstance *sli = light_instance_owner.get_or_null(p_shadow->owner); - uint32_t old_key = p_shadow_atlas->shadow_owners[p_shadow->owner]; - - if (old_key & ShadowAtlas::OMNI_LIGHT_FLAG) { - uint32_t s = old_key & ShadowAtlas::SHADOW_INDEX_MASK; - uint32_t omni_shadow_idx = p_shadow_idx + (s == (uint32_t)p_shadow_idx ? 1 : -1); - RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *omni_shadow = &p_shadow_atlas->quadrants[p_quadrant].shadows.write[omni_shadow_idx]; - omni_shadow->version = 0; - omni_shadow->owner = RID(); - } - - p_shadow_atlas->shadow_owners.erase(p_shadow->owner); - p_shadow->version = 0; - p_shadow->owner = RID(); - sli->shadow_atlases.erase(p_atlas); - } -} - -void RendererSceneRenderRD::_update_directional_shadow_atlas() { - if (directional_shadow.depth.is_null() && directional_shadow.size > 0) { - RD::TextureFormat tf; - tf.format = directional_shadow.use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT; - tf.width = directional_shadow.size; - tf.height = directional_shadow.size; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - - directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - Vector<RID> fb_tex; - fb_tex.push_back(directional_shadow.depth); - directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb_tex); - } -} -void RendererSceneRenderRD::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) { - p_size = nearest_power_of_2_templated(p_size); - - if (directional_shadow.size == p_size && directional_shadow.use_16_bits == p_16_bits) { - return; - } - - directional_shadow.size = p_size; - directional_shadow.use_16_bits = p_16_bits; - - if (directional_shadow.depth.is_valid()) { - RD::get_singleton()->free(directional_shadow.depth); - directional_shadow.depth = RID(); - _base_uniforms_changed(); - } -} - -void RendererSceneRenderRD::set_directional_shadow_count(int p_count) { - directional_shadow.light_count = p_count; - directional_shadow.current_light = 0; -} - -static Rect2i _get_directional_shadow_rect(int p_size, int p_shadow_count, int p_shadow_index) { - int split_h = 1; - int split_v = 1; - - while (split_h * split_v < p_shadow_count) { - if (split_h == split_v) { - split_h <<= 1; - } else { - split_v <<= 1; - } - } - - Rect2i rect(0, 0, p_size, p_size); - rect.size.width /= split_h; - rect.size.height /= split_v; - - rect.position.x = rect.size.width * (p_shadow_index % split_h); - rect.position.y = rect.size.height * (p_shadow_index / split_h); - - return rect; -} - -int RendererSceneRenderRD::get_directional_light_shadow_size(RID p_light_intance) { - ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0); - - Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0); - - LightInstance *light_instance = light_instance_owner.get_or_null(p_light_intance); - ERR_FAIL_COND_V(!light_instance, 0); - - switch (RSG::light_storage->light_directional_get_shadow_mode(light_instance->light)) { - case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: - break; //none - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: - r.size.height /= 2; - break; - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: - r.size /= 2; - break; - } - - return MAX(r.size.width, r.size.height); -} - -////////////////////////////////////////////////// - -RID RendererSceneRenderRD::light_instance_create(RID p_light) { - RID li = light_instance_owner.make_rid(LightInstance()); - - LightInstance *light_instance = light_instance_owner.get_or_null(li); - - light_instance->self = li; - light_instance->light = p_light; - light_instance->light_type = RSG::light_storage->light_get_type(p_light); - if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) { - light_instance->forward_id = _allocate_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT); - } - - return li; -} - -void RendererSceneRenderRD::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) { - LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); - ERR_FAIL_COND(!light_instance); - - light_instance->transform = p_transform; -} - -void RendererSceneRenderRD::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) { - LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); - ERR_FAIL_COND(!light_instance); - - light_instance->aabb = p_aabb; -} - -void RendererSceneRenderRD::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { - LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); - ERR_FAIL_COND(!light_instance); - - ERR_FAIL_INDEX(p_pass, 6); +/* FOG VOLUME INSTANCE */ - light_instance->shadow_transform[p_pass].camera = p_projection; - light_instance->shadow_transform[p_pass].transform = p_transform; - light_instance->shadow_transform[p_pass].farplane = p_far; - light_instance->shadow_transform[p_pass].split = p_split; - light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale; - light_instance->shadow_transform[p_pass].range_begin = p_range_begin; - light_instance->shadow_transform[p_pass].shadow_texel_size = p_shadow_texel_size; - light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale; -} - -void RendererSceneRenderRD::light_instance_mark_visible(RID p_light_instance) { - LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); - ERR_FAIL_COND(!light_instance); - - light_instance->last_scene_pass = scene_pass; +RID RendererSceneRenderRD::fog_volume_instance_create(RID p_fog_volume) { + return RendererRD::Fog::get_singleton()->fog_volume_instance_create(p_fog_volume); } -RendererSceneRenderRD::ShadowCubemap *RendererSceneRenderRD::_get_shadow_cubemap(int p_size) { - if (!shadow_cubemaps.has(p_size)) { - ShadowCubemap sc; - { - RD::TextureFormat tf; - tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; - tf.width = p_size; - tf.height = p_size; - tf.texture_type = RD::TEXTURE_TYPE_CUBE; - tf.array_layers = 6; - tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - sc.cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } - - for (int i = 0; i < 6; i++) { - RID side_texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sc.cubemap, i, 0); - Vector<RID> fbtex; - fbtex.push_back(side_texture); - sc.side_fb[i] = RD::get_singleton()->framebuffer_create(fbtex); - } - - shadow_cubemaps[p_size] = sc; - } - - return &shadow_cubemaps[p_size]; +void RendererSceneRenderRD::fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) { + RendererRD::Fog::get_singleton()->fog_volume_instance_set_transform(p_fog_volume_instance, p_transform); } -////////////////////////// - -RID RendererSceneRenderRD::decal_instance_create(RID p_decal) { - DecalInstance di; - di.decal = p_decal; - di.forward_id = _allocate_forward_id(FORWARD_ID_TYPE_DECAL); - return decal_instance_owner.make_rid(di); +void RendererSceneRenderRD::fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) { + RendererRD::Fog::get_singleton()->fog_volume_instance_set_active(p_fog_volume_instance, p_active); } -void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) { - DecalInstance *di = decal_instance_owner.get_or_null(p_decal); - ERR_FAIL_COND(!di); - di->transform = p_transform; +RID RendererSceneRenderRD::fog_volume_instance_get_volume(RID p_fog_volume_instance) const { + return RendererRD::Fog::get_singleton()->fog_volume_instance_get_volume(p_fog_volume_instance); } -///////////////////////////////// - -RID RendererSceneRenderRD::lightmap_instance_create(RID p_lightmap) { - LightmapInstance li; - li.lightmap = p_lightmap; - return lightmap_instance_owner.make_rid(li); -} -void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) { - LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap); - ERR_FAIL_COND(!li); - li->transform = p_transform; +Vector3 RendererSceneRenderRD::fog_volume_instance_get_position(RID p_fog_volume_instance) const { + return RendererRD::Fog::get_singleton()->fog_volume_instance_get_position(p_fog_volume_instance); } -///////////////////////////////// +/* VOXEL GI */ RID RendererSceneRenderRD::voxel_gi_instance_create(RID p_base) { return gi.voxel_gi_instance_create(p_base); } void RendererSceneRenderRD::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) { + if (!is_dynamic_gi_supported()) { + return; + } + gi.voxel_gi_instance_set_transform_to_data(p_probe, p_xform); } @@ -1220,7 +316,7 @@ void RendererSceneRenderRD::voxel_gi_update(RID p_probe, bool p_update_light_ins return; } - gi.voxel_gi_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects, this); + gi.voxel_gi_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects); } void RendererSceneRenderRD::_debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth) { @@ -1243,9 +339,6 @@ Ref<RenderSceneBuffers> RendererSceneRenderRD::render_buffers_create() { rb->set_can_be_storage(_render_buffers_can_be_storage()); rb->set_max_cluster_elements(max_cluster_elements); rb->set_base_data_format(_render_buffers_get_color_format()); - if (ss_effects) { - rb->set_sseffects(ss_effects); - } if (vrs) { rb->set_vrs(vrs); } @@ -1306,136 +399,6 @@ void RendererSceneRenderRD::_allocate_luminance_textures(Ref<RenderSceneBuffersR } } -void RendererSceneRenderRD::_process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera) { - ERR_FAIL_COND(p_render_buffers.is_null()); - - Size2i internal_size = p_render_buffers->get_internal_size(); - bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8; - - if (!can_use_effects) { - //just copy - return; - } - - p_render_buffers->allocate_blur_textures(); - - for (uint32_t v = 0; v < p_render_buffers->get_view_count(); v++) { - RID internal_texture = p_render_buffers->get_internal_texture(v); - RID depth_texture = p_render_buffers->get_depth_texture(v); - ss_effects->sub_surface_scattering(p_render_buffers, internal_texture, depth_texture, p_camera, internal_size, sss_scale, sss_depth_scale, sss_quality); - } -} - -void RendererSceneRenderRD::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive) { - ERR_FAIL_NULL(ss_effects); - ERR_FAIL_COND(p_render_buffers.is_null()); - - Size2i internal_size = p_render_buffers->get_internal_size(); - bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8; - uint32_t view_count = p_render_buffers->get_view_count(); - - if (!can_use_effects) { - //just copy - copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), RID(), view_count); - return; - } - - ERR_FAIL_COND(p_environment.is_null()); - ERR_FAIL_COND(!environment_get_ssr_enabled(p_environment)); - - Size2i half_size = Size2i(internal_size.x / 2, internal_size.y / 2); - if (p_render_buffers->ssr.output.is_null()) { - ss_effects->ssr_allocate_buffers(p_render_buffers->ssr, _render_buffers_get_color_format(), ssr_roughness_quality, half_size, view_count); - } - RID texture_slices[RendererSceneRender::MAX_RENDER_VIEWS]; - RID depth_slices[RendererSceneRender::MAX_RENDER_VIEWS]; - for (uint32_t v = 0; v < view_count; v++) { - texture_slices[v] = p_render_buffers->get_internal_texture(v); - depth_slices[v] = p_render_buffers->get_depth_texture(v); - } - ss_effects->screen_space_reflection(p_render_buffers->ssr, texture_slices, p_normal_slices, ssr_roughness_quality, p_metallic_slices, depth_slices, half_size, environment_get_ssr_max_steps(p_environment), environment_get_ssr_fade_in(p_environment), environment_get_ssr_fade_out(p_environment), environment_get_ssr_depth_tolerance(p_environment), view_count, p_projections, p_eye_offsets); - copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), p_render_buffers->ssr.output, view_count); -} - -void RendererSceneRenderRD::_process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection) { - ERR_FAIL_NULL(ss_effects); - ERR_FAIL_COND(p_render_buffers.is_null()); - ERR_FAIL_COND(p_environment.is_null()); - - RENDER_TIMESTAMP("Process SSAO"); - - RendererRD::SSEffects::SSAOSettings settings; - settings.radius = environment_get_ssao_radius(p_environment); - settings.intensity = environment_get_ssao_intensity(p_environment); - settings.power = environment_get_ssao_power(p_environment); - settings.detail = environment_get_ssao_detail(p_environment); - settings.horizon = environment_get_ssao_horizon(p_environment); - settings.sharpness = environment_get_ssao_sharpness(p_environment); - - settings.quality = ssao_quality; - settings.half_size = ssao_half_size; - settings.adaptive_target = ssao_adaptive_target; - settings.blur_passes = ssao_blur_passes; - settings.fadeout_from = ssao_fadeout_from; - settings.fadeout_to = ssao_fadeout_to; - settings.full_screen_size = p_render_buffers->get_internal_size(); - - ss_effects->ssao_allocate_buffers(p_render_buffers->ss_effects.ssao, settings, p_render_buffers->ss_effects.linear_depth); - ss_effects->generate_ssao(p_render_buffers->ss_effects.ssao, p_normal_buffer, p_projection, settings); -} - -void RendererSceneRenderRD::_process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform) { - ERR_FAIL_NULL(ss_effects); - ERR_FAIL_COND(p_render_buffers.is_null()); - ERR_FAIL_COND(p_environment.is_null()); - - RENDER_TIMESTAMP("Process SSIL"); - - RendererRD::SSEffects::SSILSettings settings; - settings.radius = environment_get_ssil_radius(p_environment); - settings.intensity = environment_get_ssil_intensity(p_environment); - settings.sharpness = environment_get_ssil_sharpness(p_environment); - settings.normal_rejection = environment_get_ssil_normal_rejection(p_environment); - - settings.quality = ssil_quality; - settings.half_size = ssil_half_size; - settings.adaptive_target = ssil_adaptive_target; - settings.blur_passes = ssil_blur_passes; - settings.fadeout_from = ssil_fadeout_from; - settings.fadeout_to = ssil_fadeout_to; - settings.full_screen_size = p_render_buffers->get_internal_size(); - - Projection correction; - correction.set_depth_correction(true); - Projection projection = correction * p_projection; - Transform3D transform = p_transform; - transform.set_origin(Vector3(0.0, 0.0, 0.0)); - Projection last_frame_projection = p_render_buffers->ss_effects.last_frame_projection * Projection(p_render_buffers->ss_effects.last_frame_transform.affine_inverse()) * Projection(transform) * projection.inverse(); - - ss_effects->ssil_allocate_buffers(p_render_buffers->ss_effects.ssil, settings, p_render_buffers->ss_effects.linear_depth); - ss_effects->screen_space_indirect_lighting(p_render_buffers->ss_effects.ssil, p_normal_buffer, p_projection, last_frame_projection, settings); - p_render_buffers->ss_effects.last_frame_projection = projection; - p_render_buffers->ss_effects.last_frame_transform = transform; -} - -void RendererSceneRenderRD::_copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers) { - ERR_FAIL_COND(p_render_buffers.is_null()); - - if (p_render_buffers->ss_effects.ssil.last_frame.is_valid()) { - Size2i size = p_render_buffers->get_internal_size(); - RID texture = p_render_buffers->get_internal_texture(); - copy_effects->copy_to_rect(texture, p_render_buffers->ss_effects.ssil.last_frame, Rect2i(0, 0, size.x, size.y)); - - int width = size.x; - int height = size.y; - for (int i = 0; i < p_render_buffers->ss_effects.ssil.last_frame_slices.size() - 1; i++) { - width = MAX(1, width >> 1); - height = MAX(1, height >> 1); - copy_effects->make_mipmap(p_render_buffers->ss_effects.ssil.last_frame_slices[i], p_render_buffers->ss_effects.ssil.last_frame_slices[i + 1], Size2i(width, height)); - } - } -} - void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) { Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers; ERR_FAIL_COND(rb.is_null()); @@ -1851,7 +814,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD> if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) { if (p_shadow_atlas.is_valid()) { - RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas); + RID shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_shadow_atlas); if (shadow_atlas_texture.is_null()) { shadow_atlas_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); @@ -1863,9 +826,9 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD> } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS) { - if (directional_shadow_get_texture().is_valid()) { - RID shadow_atlas_texture = directional_shadow_get_texture(); - Size2 rtsize = texture_storage->render_target_get_size(render_target); + if (RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture().is_valid()) { + RID shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture(); + Size2i rtsize = texture_storage->render_target_get_size(render_target); copy_effects->copy_to_fb_rect(shadow_atlas_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize / 2), false, true); } @@ -1875,7 +838,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD> RID decal_atlas = RendererRD::TextureStorage::get_singleton()->decal_atlas_get_texture(); if (decal_atlas.is_valid()) { - Size2 rtsize = texture_storage->render_target_get_size(render_target); + Size2i rtsize = texture_storage->render_target_get_size(render_target); copy_effects->copy_to_fb_rect(decal_atlas, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize / 2), false, false, true); } @@ -1883,43 +846,26 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD> if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE) { if (p_render_buffers->luminance.current.is_valid()) { - Size2 rtsize = texture_storage->render_target_get_size(render_target); + Size2i rtsize = texture_storage->render_target_get_size(render_target); copy_effects->copy_to_fb_rect(p_render_buffers->luminance.current, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize / 8), false, true); } } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && p_render_buffers->ss_effects.ssao.ao_final.is_valid()) { - Size2 rtsize = texture_storage->render_target_get_size(render_target); - copy_effects->copy_to_fb_rect(p_render_buffers->ss_effects.ssao.ao_final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, true); - } - - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSIL && p_render_buffers->ss_effects.ssil.ssil_final.is_valid()) { - Size2 rtsize = texture_storage->render_target_get_size(render_target); - copy_effects->copy_to_fb_rect(p_render_buffers->ss_effects.ssil.ssil_final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false); - } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(p_render_buffers).is_valid()) { Size2 rtsize = texture_storage->render_target_get_size(render_target); copy_effects->copy_to_fb_rect(_render_buffers_get_normal_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false); } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && p_render_buffers->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT)) { - Size2 rtsize = texture_storage->render_target_get_size(render_target); - RID ambient_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT); - RID reflection_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION); - copy_effects->copy_to_fb_rect(ambient_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture, p_render_buffers->get_view_count() > 1); - } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS) { if (p_occlusion_buffer.is_valid()) { - Size2 rtsize = texture_storage->render_target_get_size(render_target); + Size2i rtsize = texture_storage->render_target_get_size(render_target); copy_effects->copy_to_fb_rect(texture_storage->texture_get_rd_texture(p_occlusion_buffer), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize), true, false); } } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS && _render_buffers_get_velocity_texture(p_render_buffers).is_valid()) { - Size2 rtsize = texture_storage->render_target_get_size(render_target); + Size2i rtsize = texture_storage->render_target_get_size(render_target); copy_effects->copy_to_fb_rect(_render_buffers_get_velocity_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false); } } @@ -1944,19 +890,6 @@ void RendererSceneRenderRD::gi_set_use_half_resolution(bool p_enable) { gi.half_resolution = p_enable; } -void RendererSceneRenderRD::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) { - sss_quality = p_quality; -} - -RS::SubSurfaceScatteringQuality RendererSceneRenderRD::sub_surface_scattering_get_quality() const { - return sss_quality; -} - -void RendererSceneRenderRD::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) { - sss_scale = p_scale; - sss_depth_scale = p_depth_scale; -} - void RendererSceneRenderRD::positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) { ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum"); @@ -2074,788 +1007,31 @@ bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const { return sky.sky_use_cubemap_array; } -void RendererSceneRenderRD::_setup_reflections(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment) { - RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); - cluster.reflection_count = 0; - - for (uint32_t i = 0; i < (uint32_t)p_reflections.size(); i++) { - if (cluster.reflection_count == cluster.max_reflections) { - break; - } +void RendererSceneRenderRD::_update_vrs(Ref<RenderSceneBuffersRD> p_render_buffers) { + if (p_render_buffers.is_valid() && vrs) { + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_reflections[i]); - if (!rpi) { - continue; - } - - cluster.reflection_sort[cluster.reflection_count].instance = rpi; - cluster.reflection_sort[cluster.reflection_count].depth = -p_camera_inverse_transform.xform(rpi->transform.origin).z; - cluster.reflection_count++; - } - - if (cluster.reflection_count > 0) { - SortArray<Cluster::InstanceSort<ReflectionProbeInstance>> sort_array; - sort_array.sort(cluster.reflection_sort, cluster.reflection_count); - } - - bool using_forward_ids = _uses_forward_ids(); - for (uint32_t i = 0; i < cluster.reflection_count; i++) { - ReflectionProbeInstance *rpi = cluster.reflection_sort[i].instance; - - if (using_forward_ids) { - _map_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id, i); - } - - RID base_probe = rpi->probe; - - Cluster::ReflectionData &reflection_ubo = cluster.reflections[i]; - - Vector3 extents = light_storage->reflection_probe_get_extents(base_probe); - - rpi->cull_mask = light_storage->reflection_probe_get_cull_mask(base_probe); - - reflection_ubo.box_extents[0] = extents.x; - reflection_ubo.box_extents[1] = extents.y; - reflection_ubo.box_extents[2] = extents.z; - reflection_ubo.index = rpi->atlas_index; - - Vector3 origin_offset = light_storage->reflection_probe_get_origin_offset(base_probe); - - reflection_ubo.box_offset[0] = origin_offset.x; - reflection_ubo.box_offset[1] = origin_offset.y; - reflection_ubo.box_offset[2] = origin_offset.z; - reflection_ubo.mask = light_storage->reflection_probe_get_cull_mask(base_probe); - - reflection_ubo.intensity = light_storage->reflection_probe_get_intensity(base_probe); - reflection_ubo.ambient_mode = light_storage->reflection_probe_get_ambient_mode(base_probe); - - reflection_ubo.exterior = !light_storage->reflection_probe_is_interior(base_probe); - reflection_ubo.box_project = light_storage->reflection_probe_is_box_projection(base_probe); - reflection_ubo.exposure_normalization = 1.0; - - if (p_render_data->camera_attributes.is_valid()) { - float exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); - reflection_ubo.exposure_normalization = exposure / light_storage->reflection_probe_get_baked_exposure(base_probe); - } - - Color ambient_linear = light_storage->reflection_probe_get_ambient_color(base_probe).srgb_to_linear(); - float interior_ambient_energy = light_storage->reflection_probe_get_ambient_color_energy(base_probe); - reflection_ubo.ambient[0] = ambient_linear.r * interior_ambient_energy; - reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy; - reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy; - - Transform3D transform = rpi->transform; - Transform3D proj = (p_camera_inverse_transform * transform).inverse(); - RendererRD::MaterialStorage::store_transform(proj, reflection_ubo.local_matrix); - - if (current_cluster_builder != nullptr) { - current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, transform, extents); - } - - rpi->last_pass = RSG::rasterizer->get_frame_number(); - } - - if (cluster.reflection_count) { - RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(Cluster::ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); - } -} - -void RendererSceneRenderRD::_setup_lights(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows) { - RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); - RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); - - Transform3D inverse_transform = p_camera_transform.affine_inverse(); - - r_directional_light_count = 0; - r_positional_light_count = 0; - - Plane camera_plane(-p_camera_transform.basis.get_column(Vector3::AXIS_Z).normalized(), p_camera_transform.origin); - - cluster.omni_light_count = 0; - cluster.spot_light_count = 0; - - r_directional_light_soft_shadows = false; - - for (int i = 0; i < (int)p_lights.size(); i++) { - LightInstance *li = light_instance_owner.get_or_null(p_lights[i]); - if (!li) { - continue; - } - RID base = li->light; - - ERR_CONTINUE(base.is_null()); - - RS::LightType type = light_storage->light_get_type(base); - switch (type) { - case RS::LIGHT_DIRECTIONAL: { - if (r_directional_light_count >= cluster.max_directional_lights || light_storage->light_directional_get_sky_mode(base) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) { - continue; - } - - Cluster::DirectionalLightData &light_data = cluster.directional_lights[r_directional_light_count]; - - Transform3D light_transform = li->transform; - - Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized(); - - light_data.direction[0] = direction.x; - light_data.direction[1] = direction.y; - light_data.direction[2] = direction.z; - - float sign = light_storage->light_is_negative(base) ? -1 : 1; - - light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY); - - if (is_using_physical_light_units()) { - light_data.energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY); - } else { - light_data.energy *= Math_PI; - } - - if (p_render_data->camera_attributes.is_valid()) { - light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); - } - - Color linear_col = light_storage->light_get_color(base).srgb_to_linear(); - light_data.color[0] = linear_col.r; - light_data.color[1] = linear_col.g; - light_data.color[2] = linear_col.b; - - light_data.specular = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR); - light_data.volumetric_fog_energy = light_storage->light_get_param(base, RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY); - light_data.mask = light_storage->light_get_cull_mask(base); - - float size = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); - - light_data.size = 1.0 - Math::cos(Math::deg_to_rad(size)); //angle to cosine offset - - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) { - WARN_PRINT_ONCE("The DirectionalLight3D PSSM splits debug draw mode is not reimplemented yet."); - } - - light_data.shadow_opacity = (p_using_shadows && light_storage->light_has_shadow(base)) - ? light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_OPACITY) - : 0.0; - - float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); - if (angular_diameter > 0.0) { - // I know tan(0) is 0, but let's not risk it with numerical precision. - // technically this will keep expanding until reaching the sun, but all we care - // is expand until we reach the radius of the near plane (there can't be more occluders than that) - angular_diameter = Math::tan(Math::deg_to_rad(angular_diameter)); - if (light_storage->light_has_shadow(base) && light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR) > 0.0) { - // Only enable PCSS-like soft shadows if blurring is enabled. - // Otherwise, performance would decrease with no visual difference. - r_directional_light_soft_shadows = true; - } - } else { - angular_diameter = 0.0; - } - - if (light_data.shadow_opacity > 0.001) { - RS::LightDirectionalShadowMode smode = light_storage->light_directional_get_shadow_mode(base); - - int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3); - light_data.blend_splits = (smode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && light_storage->light_directional_get_blend_splits(base); - for (int j = 0; j < 4; j++) { - Rect2 atlas_rect = li->shadow_transform[j].atlas_rect; - Projection matrix = li->shadow_transform[j].camera; - float split = li->shadow_transform[MIN(limit, j)].split; - - Projection bias; - bias.set_light_bias(); - Projection rectm; - rectm.set_light_atlas_rect(atlas_rect); - - Transform3D modelview = (inverse_transform * li->shadow_transform[j].transform).inverse(); - - Projection shadow_mtx = rectm * bias * matrix * modelview; - light_data.shadow_split_offsets[j] = split; - float bias_scale = li->shadow_transform[j].bias_scale; - light_data.shadow_bias[j] = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0 * bias_scale; - light_data.shadow_normal_bias[j] = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * li->shadow_transform[j].shadow_texel_size; - light_data.shadow_transmittance_bias[j] = light_storage->light_get_transmittance_bias(base) * bias_scale; - light_data.shadow_z_range[j] = li->shadow_transform[j].farplane; - light_data.shadow_range_begin[j] = li->shadow_transform[j].range_begin; - RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrices[j]); - - Vector2 uv_scale = li->shadow_transform[j].uv_scale; - uv_scale *= atlas_rect.size; //adapt to atlas size - switch (j) { - case 0: { - light_data.uv_scale1[0] = uv_scale.x; - light_data.uv_scale1[1] = uv_scale.y; - } break; - case 1: { - light_data.uv_scale2[0] = uv_scale.x; - light_data.uv_scale2[1] = uv_scale.y; - } break; - case 2: { - light_data.uv_scale3[0] = uv_scale.x; - light_data.uv_scale3[1] = uv_scale.y; - } break; - case 3: { - light_data.uv_scale4[0] = uv_scale.x; - light_data.uv_scale4[1] = uv_scale.y; - } break; - } - } - - float fade_start = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_FADE_START); - light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep - light_data.fade_to = -light_data.shadow_split_offsets[3]; - - light_data.soft_shadow_scale = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); - light_data.softshadow_angle = angular_diameter; - light_data.bake_mode = light_storage->light_get_bake_mode(base); - - if (angular_diameter <= 0.0) { - light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF - } - } - - r_directional_light_count++; - } break; - case RS::LIGHT_OMNI: { - if (cluster.omni_light_count >= cluster.max_lights) { - continue; - } - - const real_t distance = camera_plane.distance_to(li->transform.origin); - - if (light_storage->light_is_distance_fade_enabled(li->light)) { - const float fade_begin = light_storage->light_get_distance_fade_begin(li->light); - const float fade_length = light_storage->light_get_distance_fade_length(li->light); - - if (distance > fade_begin) { - if (distance > fade_begin + fade_length) { - // Out of range, don't draw this light to improve performance. - continue; - } - } - } - - cluster.omni_light_sort[cluster.omni_light_count].instance = li; - cluster.omni_light_sort[cluster.omni_light_count].depth = distance; - cluster.omni_light_count++; - } break; - case RS::LIGHT_SPOT: { - if (cluster.spot_light_count >= cluster.max_lights) { - continue; - } - - const real_t distance = camera_plane.distance_to(li->transform.origin); - - if (light_storage->light_is_distance_fade_enabled(li->light)) { - const float fade_begin = light_storage->light_get_distance_fade_begin(li->light); - const float fade_length = light_storage->light_get_distance_fade_length(li->light); - - if (distance > fade_begin) { - if (distance > fade_begin + fade_length) { - // Out of range, don't draw this light to improve performance. - continue; - } - } - } - - cluster.spot_light_sort[cluster.spot_light_count].instance = li; - cluster.spot_light_sort[cluster.spot_light_count].depth = distance; - cluster.spot_light_count++; - } break; - } - - li->last_pass = RSG::rasterizer->get_frame_number(); - } - - if (cluster.omni_light_count) { - SortArray<Cluster::InstanceSort<LightInstance>> sorter; - sorter.sort(cluster.omni_light_sort, cluster.omni_light_count); - } - - if (cluster.spot_light_count) { - SortArray<Cluster::InstanceSort<LightInstance>> sorter; - sorter.sort(cluster.spot_light_sort, cluster.spot_light_count); - } - - ShadowAtlas *shadow_atlas = nullptr; - - if (p_shadow_atlas.is_valid() && p_using_shadows) { - shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); - } - - bool using_forward_ids = _uses_forward_ids(); - - for (uint32_t i = 0; i < (cluster.omni_light_count + cluster.spot_light_count); i++) { - uint32_t index = (i < cluster.omni_light_count) ? i : i - (cluster.omni_light_count); - Cluster::LightData &light_data = (i < cluster.omni_light_count) ? cluster.omni_lights[index] : cluster.spot_lights[index]; - RS::LightType type = (i < cluster.omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT; - LightInstance *li = (i < cluster.omni_light_count) ? cluster.omni_light_sort[index].instance : cluster.spot_light_sort[index].instance; - RID base = li->light; - - if (using_forward_ids) { - _map_forward_id(type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT, li->forward_id, index); - } - - Transform3D light_transform = li->transform; - - float sign = light_storage->light_is_negative(base) ? -1 : 1; - Color linear_col = light_storage->light_get_color(base).srgb_to_linear(); - - light_data.attenuation = light_storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION); - - // Reuse fade begin, fade length and distance for shadow LOD determination later. - float fade_begin = 0.0; - float fade_shadow = 0.0; - float fade_length = 0.0; - real_t distance = 0.0; - - float fade = 1.0; - float shadow_opacity_fade = 1.0; - if (light_storage->light_is_distance_fade_enabled(li->light)) { - fade_begin = light_storage->light_get_distance_fade_begin(li->light); - fade_shadow = light_storage->light_get_distance_fade_shadow(li->light); - fade_length = light_storage->light_get_distance_fade_length(li->light); - distance = camera_plane.distance_to(li->transform.origin); - - // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. - if (distance > fade_begin) { - fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length); - } - - if (distance > fade_shadow) { - shadow_opacity_fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_shadow) / fade_length); - } - } - - float energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * fade; - - if (is_using_physical_light_units()) { - energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY); - - // Convert from Luminous Power to Luminous Intensity - if (type == RS::LIGHT_OMNI) { - energy *= 1.0 / (Math_PI * 4.0); - } else { - // Spot Lights are not physically accurate, Luminous Intensity should change in relation to the cone angle. - // We make this assumption to keep them easy to control. - energy *= 1.0 / Math_PI; - } - } else { - energy *= Math_PI; - } - - if (p_render_data->camera_attributes.is_valid()) { - energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); - } - - light_data.color[0] = linear_col.r * energy; - light_data.color[1] = linear_col.g * energy; - light_data.color[2] = linear_col.b * energy; - light_data.specular_amount = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0; - light_data.volumetric_fog_energy = light_storage->light_get_param(base, RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY); - light_data.bake_mode = light_storage->light_get_bake_mode(base); - - float radius = MAX(0.001, light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE)); - light_data.inv_radius = 1.0 / radius; - - Vector3 pos = inverse_transform.xform(light_transform.origin); - - light_data.position[0] = pos.x; - light_data.position[1] = pos.y; - light_data.position[2] = pos.z; - - Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized(); - - light_data.direction[0] = direction.x; - light_data.direction[1] = direction.y; - light_data.direction[2] = direction.z; - - float size = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); - - light_data.size = size; - - light_data.inv_spot_attenuation = 1.0f / light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION); - float spot_angle = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE); - light_data.cos_spot_angle = Math::cos(Math::deg_to_rad(spot_angle)); - - light_data.mask = light_storage->light_get_cull_mask(base); - - light_data.atlas_rect[0] = 0; - light_data.atlas_rect[1] = 0; - light_data.atlas_rect[2] = 0; - light_data.atlas_rect[3] = 0; - - RID projector = light_storage->light_get_projector(base); - - if (projector.is_valid()) { - Rect2 rect = texture_storage->decal_atlas_get_texture_rect(projector); - - if (type == RS::LIGHT_SPOT) { - light_data.projector_rect[0] = rect.position.x; - light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped - light_data.projector_rect[2] = rect.size.width; - light_data.projector_rect[3] = -rect.size.height; - } else { - light_data.projector_rect[0] = rect.position.x; - light_data.projector_rect[1] = rect.position.y; - light_data.projector_rect[2] = rect.size.width; - light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half - } - } else { - light_data.projector_rect[0] = 0; - light_data.projector_rect[1] = 0; - light_data.projector_rect[2] = 0; - light_data.projector_rect[3] = 0; - } - - const bool needs_shadow = - shadow_atlas && - shadow_atlas->shadow_owners.has(li->self) && - p_using_shadows && - light_storage->light_has_shadow(base); - - bool in_shadow_range = true; - if (needs_shadow && light_storage->light_is_distance_fade_enabled(li->light)) { - if (distance > light_storage->light_get_distance_fade_shadow(li->light) + light_storage->light_get_distance_fade_length(li->light)) { - // Out of range, don't draw shadows to improve performance. - in_shadow_range = false; - } - } - - if (needs_shadow && in_shadow_range) { - // fill in the shadow information - - light_data.shadow_opacity = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_OPACITY) * shadow_opacity_fade; - - float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas); - light_data.shadow_normal_bias = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 10.0; - - if (type == RS::LIGHT_SPOT) { - light_data.shadow_bias = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0; - } else { //omni - light_data.shadow_bias = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS); - } - - light_data.transmittance_bias = light_storage->light_get_transmittance_bias(base); - - Vector2i omni_offset; - Rect2 rect = light_instance_get_shadow_atlas_rect(li->self, p_shadow_atlas, omni_offset); - - light_data.atlas_rect[0] = rect.position.x; - light_data.atlas_rect[1] = rect.position.y; - light_data.atlas_rect[2] = rect.size.width; - light_data.atlas_rect[3] = rect.size.height; - - light_data.soft_shadow_scale = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); - - if (type == RS::LIGHT_OMNI) { - Transform3D proj = (inverse_transform * light_transform).inverse(); - - RendererRD::MaterialStorage::store_transform(proj, light_data.shadow_matrix); - - if (size > 0.0 && light_data.soft_shadow_scale > 0.0) { - // Only enable PCSS-like soft shadows if blurring is enabled. - // Otherwise, performance would decrease with no visual difference. - light_data.soft_shadow_size = size; - } else { - light_data.soft_shadow_size = 0.0; - light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF - } - - light_data.direction[0] = omni_offset.x * float(rect.size.width); - light_data.direction[1] = omni_offset.y * float(rect.size.height); - } else if (type == RS::LIGHT_SPOT) { - Transform3D modelview = (inverse_transform * light_transform).inverse(); - Projection bias; - bias.set_light_bias(); - - Projection shadow_mtx = bias * li->shadow_transform[0].camera * modelview; - RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrix); - - if (size > 0.0 && light_data.soft_shadow_scale > 0.0) { - // Only enable PCSS-like soft shadows if blurring is enabled. - // Otherwise, performance would decrease with no visual difference. - Projection cm = li->shadow_transform[0].camera; - float half_np = cm.get_z_near() * Math::tan(Math::deg_to_rad(spot_angle)); - light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width; - } else { - light_data.soft_shadow_size = 0.0; - light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF - } - } - } else { - light_data.shadow_opacity = 0.0; - } - - li->cull_mask = light_storage->light_get_cull_mask(base); - - if (current_cluster_builder != nullptr) { - current_cluster_builder->add_light(type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle); - } - - r_positional_light_count++; - } - - //update without barriers - if (cluster.omni_light_count) { - RD::get_singleton()->buffer_update(cluster.omni_light_buffer, 0, sizeof(Cluster::LightData) * cluster.omni_light_count, cluster.omni_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); - } - - if (cluster.spot_light_count) { - RD::get_singleton()->buffer_update(cluster.spot_light_buffer, 0, sizeof(Cluster::LightData) * cluster.spot_light_count, cluster.spot_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); - } - - if (r_directional_light_count) { - RD::get_singleton()->buffer_update(cluster.directional_light_buffer, 0, sizeof(Cluster::DirectionalLightData) * r_directional_light_count, cluster.directional_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); - } -} - -void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform) { - RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); - - Transform3D uv_xform; - uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0)); - uv_xform.origin = Vector3(-1.0, 0.0, -1.0); - - uint32_t decal_count = p_decals.size(); - - cluster.decal_count = 0; - - for (uint32_t i = 0; i < decal_count; i++) { - if (cluster.decal_count == cluster.max_decals) { - break; - } - - DecalInstance *di = decal_instance_owner.get_or_null(p_decals[i]); - if (!di) { - continue; - } - RID decal = di->decal; - - Transform3D xform = di->transform; - - real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; - - if (texture_storage->decal_is_distance_fade_enabled(decal)) { - float fade_begin = texture_storage->decal_get_distance_fade_begin(decal); - float fade_length = texture_storage->decal_get_distance_fade_length(decal); - - if (distance > fade_begin) { - if (distance > fade_begin + fade_length) { - continue; // do not use this decal, its invisible - } - } - } - - cluster.decal_sort[cluster.decal_count].instance = di; - cluster.decal_sort[cluster.decal_count].depth = distance; - cluster.decal_count++; - } - - if (cluster.decal_count > 0) { - SortArray<Cluster::InstanceSort<DecalInstance>> sort_array; - sort_array.sort(cluster.decal_sort, cluster.decal_count); - } - - bool using_forward_ids = _uses_forward_ids(); - for (uint32_t i = 0; i < cluster.decal_count; i++) { - DecalInstance *di = cluster.decal_sort[i].instance; - RID decal = di->decal; - - if (using_forward_ids) { - _map_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id, i); - } - - di->cull_mask = texture_storage->decal_get_cull_mask(decal); - - Transform3D xform = di->transform; - float fade = 1.0; - - if (texture_storage->decal_is_distance_fade_enabled(decal)) { - const real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; - const float fade_begin = texture_storage->decal_get_distance_fade_begin(decal); - const float fade_length = texture_storage->decal_get_distance_fade_length(decal); - - if (distance > fade_begin) { - // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. - fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length); - } - } - - Cluster::DecalData &dd = cluster.decals[i]; - - Vector3 decal_extents = texture_storage->decal_get_extents(decal); - - Transform3D scale_xform; - scale_xform.basis.scale(decal_extents); - Transform3D to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse(); - RendererRD::MaterialStorage::store_transform(to_decal_xform, dd.xform); - - Vector3 normal = xform.basis.get_column(Vector3::AXIS_Y).normalized(); - normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine - - dd.normal[0] = normal.x; - dd.normal[1] = normal.y; - dd.normal[2] = normal.z; - dd.normal_fade = texture_storage->decal_get_normal_fade(decal); - - RID albedo_tex = texture_storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ALBEDO); - RID emission_tex = texture_storage->decal_get_texture(decal, RS::DECAL_TEXTURE_EMISSION); - if (albedo_tex.is_valid()) { - Rect2 rect = texture_storage->decal_atlas_get_texture_rect(albedo_tex); - dd.albedo_rect[0] = rect.position.x; - dd.albedo_rect[1] = rect.position.y; - dd.albedo_rect[2] = rect.size.x; - dd.albedo_rect[3] = rect.size.y; - } else { - if (!emission_tex.is_valid()) { - continue; //no albedo, no emission, no decal. - } - dd.albedo_rect[0] = 0; - dd.albedo_rect[1] = 0; - dd.albedo_rect[2] = 0; - dd.albedo_rect[3] = 0; - } - - RID normal_tex = texture_storage->decal_get_texture(decal, RS::DECAL_TEXTURE_NORMAL); + RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(p_render_buffers->get_render_target()); + if (vrs_mode != RS::VIEWPORT_VRS_DISABLED) { + RID vrs_texture = p_render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE); - if (normal_tex.is_valid()) { - Rect2 rect = texture_storage->decal_atlas_get_texture_rect(normal_tex); - dd.normal_rect[0] = rect.position.x; - dd.normal_rect[1] = rect.position.y; - dd.normal_rect[2] = rect.size.x; - dd.normal_rect[3] = rect.size.y; + // We use get_cache_multipass instead of get_cache_multiview because the default behavior is for + // our vrs_texture to be used as the VRS attachment. In this particular case we're writing to it + // so it needs to be set as our color attachment - Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized(); - RendererRD::MaterialStorage::store_basis_3x4(normal_xform, dd.normal_xform); - } else { - dd.normal_rect[0] = 0; - dd.normal_rect[1] = 0; - dd.normal_rect[2] = 0; - dd.normal_rect[3] = 0; - } + Vector<RID> textures; + textures.push_back(vrs_texture); - RID orm_tex = texture_storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ORM); - if (orm_tex.is_valid()) { - Rect2 rect = texture_storage->decal_atlas_get_texture_rect(orm_tex); - dd.orm_rect[0] = rect.position.x; - dd.orm_rect[1] = rect.position.y; - dd.orm_rect[2] = rect.size.x; - dd.orm_rect[3] = rect.size.y; - } else { - dd.orm_rect[0] = 0; - dd.orm_rect[1] = 0; - dd.orm_rect[2] = 0; - dd.orm_rect[3] = 0; - } + Vector<RD::FramebufferPass> passes; + RD::FramebufferPass pass; + pass.color_attachments.push_back(0); + passes.push_back(pass); - if (emission_tex.is_valid()) { - Rect2 rect = texture_storage->decal_atlas_get_texture_rect(emission_tex); - dd.emission_rect[0] = rect.position.x; - dd.emission_rect[1] = rect.position.y; - dd.emission_rect[2] = rect.size.x; - dd.emission_rect[3] = rect.size.y; - } else { - dd.emission_rect[0] = 0; - dd.emission_rect[1] = 0; - dd.emission_rect[2] = 0; - dd.emission_rect[3] = 0; - } + RID vrs_fb = FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, p_render_buffers->get_view_count()); - Color modulate = texture_storage->decal_get_modulate(decal); - dd.modulate[0] = modulate.r; - dd.modulate[1] = modulate.g; - dd.modulate[2] = modulate.b; - dd.modulate[3] = modulate.a * fade; - dd.emission_energy = texture_storage->decal_get_emission_energy(decal) * fade; - dd.albedo_mix = texture_storage->decal_get_albedo_mix(decal); - dd.mask = texture_storage->decal_get_cull_mask(decal); - dd.upper_fade = texture_storage->decal_get_upper_fade(decal); - dd.lower_fade = texture_storage->decal_get_lower_fade(decal); - - if (current_cluster_builder != nullptr) { - current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, xform, decal_extents); + vrs->update_vrs_texture(vrs_fb, p_render_buffers->get_render_target()); } } - - if (cluster.decal_count > 0) { - RD::get_singleton()->buffer_update(cluster.decal_buffer, 0, sizeof(Cluster::DecalData) * cluster.decal_count, cluster.decals, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// FOG SHADER - -void RendererSceneRenderRD::_update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes) { - ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered - ERR_FAIL_COND(p_render_buffers.is_null()); - - // These should be available for our clustered renderer, at some point _update_volumetric_fog should be called by the renderer implemetentation itself - ERR_FAIL_COND(!p_render_buffers->has_custom_data(RB_SCOPE_GI)); - Ref<RendererRD::GI::RenderBuffersGI> rbgi = p_render_buffers->get_custom_data(RB_SCOPE_GI); - - Ref<RendererRD::GI::SDFGI> sdfgi; - if (p_render_buffers->has_custom_data(RB_SCOPE_SDFGI)) { - sdfgi = p_render_buffers->get_custom_data(RB_SCOPE_SDFGI); - } - - Size2i size = p_render_buffers->get_internal_size(); - float ratio = float(size.x) / float((size.x + size.y) / 2); - uint32_t target_width = uint32_t(float(volumetric_fog_size) * ratio); - uint32_t target_height = uint32_t(float(volumetric_fog_size) / ratio); - - if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) { - Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG); - //validate - if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment) || fog->width != target_width || fog->height != target_height || fog->depth != volumetric_fog_depth) { - p_render_buffers->set_custom_data(RB_SCOPE_FOG, Ref<RenderBufferCustomDataRD>()); - } - } - - if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment)) { - //no reason to enable or update, bye - return; - } - - if (p_environment.is_valid() && environment_get_volumetric_fog_enabled(p_environment) && !p_render_buffers->has_custom_data(RB_SCOPE_FOG)) { - //required volumetric fog but not existing, create - Ref<RendererRD::Fog::VolumetricFog> fog; - - fog.instantiate(); - fog->init(Vector3i(target_width, target_height, volumetric_fog_depth), sky.sky_shader.default_shader_rd); - - p_render_buffers->set_custom_data(RB_SCOPE_FOG, fog); - } - - if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) { - Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG); - - RendererRD::Fog::VolumetricFogSettings settings; - settings.rb_size = size; - settings.time = time; - settings.is_using_radiance_cubemap_array = is_using_radiance_cubemap_array(); - settings.max_cluster_elements = max_cluster_elements; - settings.volumetric_fog_filter_active = volumetric_fog_filter_active; - - settings.shadow_sampler = shadow_sampler; - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); - settings.shadow_atlas_depth = shadow_atlas ? shadow_atlas->depth : RID(); - settings.voxel_gi_buffer = rbgi->get_voxel_gi_buffer(); - settings.omni_light_buffer = get_omni_light_buffer(); - settings.spot_light_buffer = get_spot_light_buffer(); - settings.directional_shadow_depth = directional_shadow.depth; - settings.directional_light_buffer = get_directional_light_buffer(); - - settings.vfog = fog; - settings.cluster_builder = p_render_buffers->cluster_builder; - settings.rbgi = rbgi; - settings.sdfgi = sdfgi; - settings.env = p_environment; - settings.sky = &sky; - settings.gi = &gi; - - RendererRD::Fog::get_singleton()->volumetric_fog_update(settings, p_cam_projection, p_cam_transform, p_prev_cam_inv_transform, p_shadow_atlas, p_directional_light_count, p_use_directional_shadows, p_positional_light_count, p_voxel_gi_count, p_fog_volumes); - } } bool RendererSceneRenderRD::_needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) { @@ -2886,175 +1062,8 @@ void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, boo } } -void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer) { - // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time - RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); - - if (p_render_data->render_buffers.is_valid() && p_use_gi && p_render_data->render_buffers->has_custom_data(RB_SCOPE_SDFGI)) { - Ref<RendererRD::GI::SDFGI> sdfgi = p_render_data->render_buffers->get_custom_data(RB_SCOPE_SDFGI); - sdfgi->store_probes(); - } - - render_state.cube_shadows.clear(); - render_state.shadows.clear(); - render_state.directional_shadows.clear(); - - Plane camera_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin); - float lod_distance_multiplier = p_render_data->scene_data->cam_projection.get_lod_multiplier(); - { - for (int i = 0; i < render_state.render_shadow_count; i++) { - LightInstance *li = light_instance_owner.get_or_null(render_state.render_shadows[i].light); - - if (light_storage->light_get_type(li->light) == RS::LIGHT_DIRECTIONAL) { - render_state.directional_shadows.push_back(i); - } else if (light_storage->light_get_type(li->light) == RS::LIGHT_OMNI && light_storage->light_omni_get_shadow_mode(li->light) == RS::LIGHT_OMNI_SHADOW_CUBE) { - render_state.cube_shadows.push_back(i); - } else { - render_state.shadows.push_back(i); - } - } - - //cube shadows are rendered in their own way - for (uint32_t i = 0; i < render_state.cube_shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); - } - - if (render_state.directional_shadows.size()) { - //open the pass for directional shadows - _update_directional_shadow_atlas(); - RD::get_singleton()->draw_list_begin(directional_shadow.fb, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE); - RD::get_singleton()->draw_list_end(); - } - } - - // Render GI - - bool render_shadows = render_state.directional_shadows.size() || render_state.shadows.size(); - bool render_gi = p_render_data->render_buffers.is_valid() && p_use_gi; - - if (render_shadows && render_gi) { - RENDER_TIMESTAMP("Render GI + Render Shadows (Parallel)"); - } else if (render_shadows) { - RENDER_TIMESTAMP("Render Shadows"); - } else if (render_gi) { - RENDER_TIMESTAMP("Render GI"); - } - - //prepare shadow rendering - if (render_shadows) { - _render_shadow_begin(); - - //render directional shadows - for (uint32_t i = 0; i < render_state.directional_shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false, p_render_data->render_info); - } - //render positional shadows - for (uint32_t i = 0; i < render_state.shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info); - } - - _render_shadow_process(); - } - - //start GI - if (render_gi) { - gi.process_gi(p_render_data->render_buffers, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, 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->voxel_gi_instances); - } - - //Do shadow rendering (in parallel with GI) - if (render_shadows) { - _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER); - } - - if (render_gi) { - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //use a later barrier - } - - if (p_render_data->render_buffers.is_valid() && ss_effects) { - if (p_use_ssao || p_use_ssil) { - Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers; - ERR_FAIL_COND(rb.is_null()); - Size2i size = rb->get_internal_size(); - - bool invalidate_uniform_set = false; - if (rb->ss_effects.linear_depth.is_null()) { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R16_SFLOAT; - tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; - tf.width = (size.x + 1) / 2; - tf.height = (size.y + 1) / 2; - tf.mipmaps = 5; - tf.array_layers = 4; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ss_effects.linear_depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ss_effects.linear_depth, "SS Effects Depth"); - for (uint32_t i = 0; i < tf.mipmaps; i++) { - RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.linear_depth, 0, i, 1, RD::TEXTURE_SLICE_2D_ARRAY); - rb->ss_effects.linear_depth_slices.push_back(slice); - RD::get_singleton()->set_resource_name(slice, "SS Effects Depth Mip " + itos(i) + " "); - } - invalidate_uniform_set = true; - } - - RID depth_texture = rb->get_depth_texture(); - ss_effects->downsample_depth(depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, size, p_render_data->scene_data->cam_projection); - } - - if (p_use_ssao) { - // TODO make these proper stereo - _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection); - } - - if (p_use_ssil) { - // TODO make these proper stereo - _process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform); - } - } - - //full barrier here, we need raster, transfer and compute and it depends from the previous work - RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL); - - if (current_cluster_builder) { - current_cluster_builder->begin(p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, !p_render_data->reflection_probe.is_valid()); - } - - bool using_shadows = true; - - if (p_render_data->reflection_probe.is_valid()) { - if (!RSG::light_storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { - using_shadows = false; - } - } else { - //do not render reflections when rendering a reflection probe - _setup_reflections(p_render_data, *p_render_data->reflection_probes, p_render_data->scene_data->cam_transform.affine_inverse(), p_render_data->environment); - } - - uint32_t directional_light_count = 0; - uint32_t positional_light_count = 0; - _setup_lights(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); - _setup_decals(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse()); - - p_render_data->directional_light_count = directional_light_count; - - if (current_cluster_builder) { - current_cluster_builder->bake_cluster(); - } - - if (p_render_data->render_buffers.is_valid()) { - bool directional_shadows = false; - for (uint32_t i = 0; i < directional_light_count; i++) { - if (cluster.directional_lights[i].shadow_opacity > 0.001) { - directional_shadows = true; - break; - } - } - if (is_volumetric_supported()) { - _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count, *p_render_data->fog_volumes); - } - } -} - void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RenderingMethod::RenderInfo *r_render_info) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); // getting this here now so we can direct call a bunch of things more easily @@ -3101,14 +1110,14 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render } if (p_shadow_atlas.is_valid()) { - Vector2 sas = shadow_atlas_get_size(p_shadow_atlas); - scene_data.shadow_atlas_pixel_size.x = 1.0 / sas.x; - scene_data.shadow_atlas_pixel_size.y = 1.0 / sas.y; + int shadow_atlas_size = light_storage->shadow_atlas_get_size(p_shadow_atlas); + scene_data.shadow_atlas_pixel_size.x = 1.0 / shadow_atlas_size; + scene_data.shadow_atlas_pixel_size.y = 1.0 / shadow_atlas_size; } { - Vector2 dss = directional_shadow_get_size(); - scene_data.directional_shadow_pixel_size.x = 1.0 / dss.x; - scene_data.directional_shadow_pixel_size.y = 1.0 / dss.y; + int directional_shadow_size = light_storage->directional_shadow_get_size(); + scene_data.directional_shadow_pixel_size.x = 1.0 / directional_shadow_size; + scene_data.directional_shadow_pixel_size.y = 1.0 / directional_shadow_size; } scene_data.time = time; @@ -3131,15 +1140,17 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render render_data.environment = p_environment; render_data.camera_attributes = p_camera_attributes; render_data.shadow_atlas = p_shadow_atlas; + render_data.occluder_debug_tex = p_occluder_debug_tex; render_data.reflection_atlas = p_reflection_atlas; render_data.reflection_probe = p_reflection_probe; render_data.reflection_probe_pass = p_reflection_probe_pass; - render_state.render_shadows = p_render_shadows; - render_state.render_shadow_count = p_render_shadow_count; - render_state.render_sdfgi_regions = p_render_sdfgi_regions; - render_state.render_sdfgi_region_count = p_render_sdfgi_region_count; - render_state.sdfgi_update_data = p_sdfgi_update_data; + render_data.render_shadows = p_render_shadows; + render_data.render_shadow_count = p_render_shadow_count; + render_data.render_sdfgi_regions = p_render_sdfgi_regions; + render_data.render_sdfgi_region_count = p_render_sdfgi_region_count; + render_data.sdfgi_update_data = p_sdfgi_update_data; + render_data.render_info = r_render_info; } @@ -3151,22 +1162,6 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render render_data.voxel_gi_instances = ∅ } - // sdfgi first - if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) { - Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); - float exposure_normalization = 1.0; - - if (p_camera_attributes.is_valid()) { - exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes); - } - for (int i = 0; i < render_state.render_sdfgi_region_count; i++) { - sdfgi->render_region(rb, render_state.render_sdfgi_regions[i].region, render_state.render_sdfgi_regions[i].instances, this, exposure_normalization); - } - if (render_state.sdfgi_update_data->update_static) { - sdfgi->render_static_lights(&render_data, rb, render_state.sdfgi_update_data->static_cascade_count, p_sdfgi_update_data->static_cascade_indices, render_state.sdfgi_update_data->static_positional_lights, this); - } - } - Color clear_color; if (p_render_buffers.is_valid()) { clear_color = texture_storage->render_target_get_clear_request_color(rb->get_render_target()); @@ -3174,297 +1169,8 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render clear_color = RSG::texture_storage->get_default_clear_color(); } - //assign render indices to voxel_gi_instances - if (is_dynamic_gi_supported()) { - for (uint32_t i = 0; i < (uint32_t)p_voxel_gi_instances.size(); i++) { - gi.voxel_gi_instance_set_render_index(p_voxel_gi_instances[i], i); - } - } - - if (rb.is_valid()) { - // render_data.render_buffers == p_render_buffers so we can use our already retrieved rb - current_cluster_builder = rb->cluster_builder; - } else if (reflection_probe_instance_owner.owns(render_data.reflection_probe)) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(render_data.reflection_probe); - ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(rpi->atlas); - if (!ra) { - ERR_PRINT("reflection probe has no reflection atlas! Bug?"); - current_cluster_builder = nullptr; - } else { - current_cluster_builder = ra->cluster_builder; - } - if (p_camera_attributes.is_valid()) { - RendererRD::LightStorage::get_singleton()->reflection_probe_set_baked_exposure(rpi->probe, RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes)); - } - } else { - ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash - current_cluster_builder = nullptr; - } - - render_state.voxel_gi_count = 0; - - if (rb.is_valid() && is_dynamic_gi_supported()) { - if (rb->has_custom_data(RB_SCOPE_SDFGI)) { - Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); - if (sdfgi.is_valid()) { - sdfgi->update_cascades(); - sdfgi->pre_process_gi(scene_data.cam_transform, &render_data, this); - sdfgi->update_light(); - } - } - - gi.setup_voxel_gi_instances(&render_data, render_data.render_buffers, scene_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this); - } - - render_state.depth_prepass_used = false; //calls _pre_opaque_render between depth pre-pass and opaque pass - if (current_cluster_builder != nullptr) { - render_data.cluster_buffer = current_cluster_builder->get_cluster_buffer(); - render_data.cluster_size = current_cluster_builder->get_cluster_size(); - render_data.cluster_max_elements = current_cluster_builder->get_max_cluster_elements(); - } - - if (rb.is_valid() && vrs) { - RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(rb->get_render_target()); - if (vrs_mode != RS::VIEWPORT_VRS_DISABLED) { - RID vrs_texture = rb->get_texture(RB_SCOPE_VRS, RB_TEXTURE); - - // We use get_cache_multipass instead of get_cache_multiview because the default behavior is for - // our vrs_texture to be used as the VRS attachment. In this particular case we're writing to it - // so it needs to be set as our color attachment - - Vector<RID> textures; - textures.push_back(vrs_texture); - - Vector<RD::FramebufferPass> passes; - RD::FramebufferPass pass; - pass.color_attachments.push_back(0); - passes.push_back(pass); - - RID vrs_fb = FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, rb->get_view_count()); - - vrs->update_vrs_texture(vrs_fb, rb->get_render_target()); - } - } - _render_scene(&render_data, clear_color); - - if (rb.is_valid()) { - _render_buffers_debug_draw(rb, p_shadow_atlas, p_occluder_debug_tex); - - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb->has_custom_data(RB_SCOPE_SDFGI)) { - Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); - Vector<RID> view_rids; - - // SDFGI renders at internal resolution, need to check if our debug correctly supports outputting upscaled. - Size2i size = rb->get_internal_size(); - RID source_texture = rb->get_internal_texture(); - for (uint32_t v = 0; v < rb->get_view_count(); v++) { - view_rids.push_back(rb->get_internal_texture(v)); - } - - sdfgi->debug_draw(scene_data.view_count, scene_data.view_projection, scene_data.cam_transform, size.x, size.y, rb->get_render_target(), source_texture, view_rids); - } - } -} - -void RendererSceneRenderRD::_debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers) { - if (p_render_buffers.is_valid() && current_cluster_builder != nullptr) { - RS::ViewportDebugDraw dd = get_debug_draw_mode(); - - if (dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) { - ClusterBuilderRD::ElementType elem_type = ClusterBuilderRD::ELEMENT_TYPE_MAX; - switch (dd) { - case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS: - elem_type = ClusterBuilderRD::ELEMENT_TYPE_OMNI_LIGHT; - break; - case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS: - elem_type = ClusterBuilderRD::ELEMENT_TYPE_SPOT_LIGHT; - break; - case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS: - elem_type = ClusterBuilderRD::ELEMENT_TYPE_DECAL; - break; - case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES: - elem_type = ClusterBuilderRD::ELEMENT_TYPE_REFLECTION_PROBE; - break; - default: { - } - } - current_cluster_builder->debug(elem_type); - } - } -} - -void RendererSceneRenderRD::_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) { - LightInstance *light_instance = light_instance_owner.get_or_null(p_light); - ERR_FAIL_COND(!light_instance); - - Rect2i atlas_rect; - uint32_t atlas_size = 1; - RID atlas_fb; - - bool using_dual_paraboloid = false; - bool using_dual_paraboloid_flip = false; - Vector2i dual_paraboloid_offset; - RID render_fb; - RID render_texture; - float zfar; - - bool use_pancake = false; - bool render_cubemap = false; - bool finalize_cubemap = false; - - bool flip_y = false; - - Projection light_projection; - Transform3D light_transform; - - if (RSG::light_storage->light_get_type(light_instance->light) == RS::LIGHT_DIRECTIONAL) { - //set pssm stuff - if (light_instance->last_scene_shadow_pass != scene_pass) { - light_instance->directional_rect = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, directional_shadow.current_light); - directional_shadow.current_light++; - light_instance->last_scene_shadow_pass = scene_pass; - } - - use_pancake = RSG::light_storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0; - light_projection = light_instance->shadow_transform[p_pass].camera; - light_transform = light_instance->shadow_transform[p_pass].transform; - - atlas_rect = light_instance->directional_rect; - - if (RSG::light_storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { - atlas_rect.size.width /= 2; - atlas_rect.size.height /= 2; - - if (p_pass == 1) { - atlas_rect.position.x += atlas_rect.size.width; - } else if (p_pass == 2) { - atlas_rect.position.y += atlas_rect.size.height; - } else if (p_pass == 3) { - atlas_rect.position += atlas_rect.size; - } - } else if (RSG::light_storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { - atlas_rect.size.height /= 2; - - if (p_pass == 0) { - } else { - atlas_rect.position.y += atlas_rect.size.height; - } - } - - light_instance->shadow_transform[p_pass].atlas_rect = atlas_rect; - - light_instance->shadow_transform[p_pass].atlas_rect.position /= directional_shadow.size; - light_instance->shadow_transform[p_pass].atlas_rect.size /= directional_shadow.size; - - zfar = RSG::light_storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE); - - render_fb = directional_shadow.fb; - render_texture = RID(); - flip_y = true; - - } else { - //set from shadow atlas - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); - ERR_FAIL_COND(!shadow_atlas); - ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); - - _update_shadow_atlas(shadow_atlas); - - uint32_t key = shadow_atlas->shadow_owners[p_light]; - - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - - ERR_FAIL_INDEX((int)shadow, shadow_atlas->quadrants[quadrant].shadows.size()); - - uint32_t quadrant_size = shadow_atlas->size >> 1; - - atlas_rect.position.x = (quadrant & 1) * quadrant_size; - atlas_rect.position.y = (quadrant >> 1) * quadrant_size; - - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - atlas_rect.position.x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - atlas_rect.position.y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - - atlas_rect.size.width = shadow_size; - atlas_rect.size.height = shadow_size; - - zfar = RSG::light_storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE); - - if (RSG::light_storage->light_get_type(light_instance->light) == RS::LIGHT_OMNI) { - bool wrap = (shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision == 0; - dual_paraboloid_offset = wrap ? Vector2i(1 - shadow_atlas->quadrants[quadrant].subdivision, 1) : Vector2i(1, 0); - - if (RSG::light_storage->light_omni_get_shadow_mode(light_instance->light) == RS::LIGHT_OMNI_SHADOW_CUBE) { - ShadowCubemap *cubemap = _get_shadow_cubemap(shadow_size / 2); - - render_fb = cubemap->side_fb[p_pass]; - render_texture = cubemap->cubemap; - - light_projection = light_instance->shadow_transform[p_pass].camera; - light_transform = light_instance->shadow_transform[p_pass].transform; - render_cubemap = true; - finalize_cubemap = p_pass == 5; - atlas_fb = shadow_atlas->fb; - - atlas_size = shadow_atlas->size; - - if (p_pass == 0) { - _render_shadow_begin(); - } - - } else { - atlas_rect.position.x += 1; - atlas_rect.position.y += 1; - atlas_rect.size.x -= 2; - atlas_rect.size.y -= 2; - - atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset; - - light_projection = light_instance->shadow_transform[0].camera; - light_transform = light_instance->shadow_transform[0].transform; - - using_dual_paraboloid = true; - using_dual_paraboloid_flip = p_pass == 1; - render_fb = shadow_atlas->fb; - flip_y = true; - } - - } else if (RSG::light_storage->light_get_type(light_instance->light) == RS::LIGHT_SPOT) { - light_projection = light_instance->shadow_transform[0].camera; - light_transform = light_instance->shadow_transform[0].transform; - - render_fb = shadow_atlas->fb; - - flip_y = true; - } - } - - if (render_cubemap) { - //rendering to cubemap - _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); - if (finalize_cubemap) { - _render_shadow_process(); - _render_shadow_end(); - //reblit - Rect2 atlas_rect_norm = atlas_rect; - atlas_rect_norm.position /= float(atlas_size); - atlas_rect_norm.size /= float(atlas_size); - 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); - atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size; - 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); - - //restore transform so it can be properly used - light_instance_set_shadow_transform(p_light, Projection(), light_instance->transform, zfar, 0, 0, 0); - } - - } else { - //render shadow - _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); - } } void RendererSceneRenderRD::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) { @@ -3495,58 +1201,11 @@ bool RendererSceneRenderRD::free(RID p_rid) { environment_free(p_rid); } else if (RSG::camera_attributes->owns_camera_attributes(p_rid)) { RSG::camera_attributes->camera_attributes_free(p_rid); - } else if (reflection_atlas_owner.owns(p_rid)) { - reflection_atlas_set_size(p_rid, 0, 0); - ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_rid); - if (ra->cluster_builder) { - memdelete(ra->cluster_builder); - } - reflection_atlas_owner.free(p_rid); - } else if (reflection_probe_instance_owner.owns(p_rid)) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_rid); - _free_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id); - reflection_probe_release_atlas_index(p_rid); - reflection_probe_instance_owner.free(p_rid); - } else if (decal_instance_owner.owns(p_rid)) { - DecalInstance *di = decal_instance_owner.get_or_null(p_rid); - _free_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id); - decal_instance_owner.free(p_rid); - } else if (lightmap_instance_owner.owns(p_rid)) { - lightmap_instance_owner.free(p_rid); } else if (gi.voxel_gi_instance_owns(p_rid)) { gi.voxel_gi_instance_free(p_rid); } else if (sky.sky_owner.owns(p_rid)) { sky.update_dirty_skys(); sky.free_sky(p_rid); - } else if (light_instance_owner.owns(p_rid)) { - LightInstance *light_instance = light_instance_owner.get_or_null(p_rid); - - //remove from shadow atlases.. - for (const RID &E : light_instance->shadow_atlases) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(E); - ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid)); - uint32_t key = shadow_atlas->shadow_owners[p_rid]; - uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; - - shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); - - if (key & ShadowAtlas::OMNI_LIGHT_FLAG) { - // Omni lights use two atlas spots, make sure to clear the other as well - shadow_atlas->quadrants[q].shadows.write[s + 1].owner = RID(); - } - - shadow_atlas->shadow_owners.erase(p_rid); - } - - if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) { - _free_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id); - } - light_instance_owner.free(p_rid); - - } else if (shadow_atlas_owner.owns(p_rid)) { - shadow_atlas_set_size(p_rid, 0); - shadow_atlas_owner.free(p_rid); } else if (RendererRD::Fog::get_singleton()->owns_fog_volume_instance(p_rid)) { RendererRD::Fog::get_singleton()->fog_instance_free(p_rid); } else { @@ -3694,27 +1353,6 @@ void RendererSceneRenderRD::sdfgi_set_debug_probe_select(const Vector3 &p_positi RendererSceneRenderRD *RendererSceneRenderRD::singleton = nullptr; -RID RendererSceneRenderRD::get_reflection_probe_buffer() { - return cluster.reflection_buffer; -} -RID RendererSceneRenderRD::get_omni_light_buffer() { - return cluster.omni_light_buffer; -} - -RID RendererSceneRenderRD::get_spot_light_buffer() { - return cluster.spot_light_buffer; -} - -RID RendererSceneRenderRD::get_directional_light_buffer() { - return cluster.directional_light_buffer; -} -RID RendererSceneRenderRD::get_decal_buffer() { - return cluster.decal_buffer; -} -int RendererSceneRenderRD::get_max_directional_lights() const { - return cluster.max_directional_lights; -} - bool RendererSceneRenderRD::is_vrs_supported() const { return RD::get_singleton()->has_feature(RD::SUPPORTS_ATTACHMENT_VRS); } @@ -3724,11 +1362,6 @@ bool RendererSceneRenderRD::is_dynamic_gi_supported() const { return true; } -bool RendererSceneRenderRD::is_clustered_enabled() const { - // used by default. - return true; -} - bool RendererSceneRenderRD::is_volumetric_supported() const { // usable by default (unless low end = true) return true; @@ -3744,9 +1377,10 @@ RendererSceneRenderRD::RendererSceneRenderRD() { void RendererSceneRenderRD::init() { max_cluster_elements = get_max_elements(); + RendererRD::LightStorage::get_singleton()->set_max_cluster_elements(max_cluster_elements); - directional_shadow.size = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/size"); - directional_shadow.use_16_bits = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/16_bits"); + /* Forward ID */ + forward_id_storage = create_forward_id_storage(); /* SKY SHADER */ @@ -3759,68 +1393,25 @@ void RendererSceneRenderRD::init() { } { //decals - cluster.max_decals = max_cluster_elements; - uint32_t decal_buffer_size = cluster.max_decals * sizeof(Cluster::DecalData); - cluster.decals = memnew_arr(Cluster::DecalData, cluster.max_decals); - cluster.decal_sort = memnew_arr(Cluster::InstanceSort<DecalInstance>, cluster.max_decals); - cluster.decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size); - } - - { //reflections - - cluster.max_reflections = max_cluster_elements; - cluster.reflections = memnew_arr(Cluster::ReflectionData, cluster.max_reflections); - cluster.reflection_sort = memnew_arr(Cluster::InstanceSort<ReflectionProbeInstance>, cluster.max_reflections); - cluster.reflection_buffer = RD::get_singleton()->storage_buffer_create(sizeof(Cluster::ReflectionData) * cluster.max_reflections); + RendererRD::TextureStorage::get_singleton()->set_max_decals(max_cluster_elements); } { //lights - cluster.max_lights = max_cluster_elements; - - uint32_t light_buffer_size = cluster.max_lights * sizeof(Cluster::LightData); - cluster.omni_lights = memnew_arr(Cluster::LightData, cluster.max_lights); - cluster.omni_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size); - cluster.omni_light_sort = memnew_arr(Cluster::InstanceSort<LightInstance>, cluster.max_lights); - cluster.spot_lights = memnew_arr(Cluster::LightData, cluster.max_lights); - cluster.spot_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size); - cluster.spot_light_sort = memnew_arr(Cluster::InstanceSort<LightInstance>, cluster.max_lights); - //defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(cluster.max_lights) + "\n"; - - cluster.max_directional_lights = MAX_DIRECTIONAL_LIGHTS; - uint32_t directional_light_buffer_size = cluster.max_directional_lights * sizeof(Cluster::DirectionalLightData); - cluster.directional_lights = memnew_arr(Cluster::DirectionalLightData, cluster.max_directional_lights); - cluster.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size); } if (is_volumetric_supported()) { - RendererRD::Fog::get_singleton()->init_fog_shader(cluster.max_directional_lights, get_roughness_layers(), is_using_radiance_cubemap_array()); - } - - { - RD::SamplerState sampler; - sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; - sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; - sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; - shadow_sampler = RD::get_singleton()->sampler_create(sampler); + RendererRD::Fog::get_singleton()->init_fog_shader(RendererRD::LightStorage::get_singleton()->get_max_directional_lights(), get_roughness_layers(), is_using_radiance_cubemap_array()); } RSG::camera_attributes->camera_attributes_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape")))); RSG::camera_attributes->camera_attributes_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_use_jitter")); use_physical_light_units = GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units"); - environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to")); screen_space_roughness_limiter = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/enabled"); screen_space_roughness_limiter_amount = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/amount"); screen_space_roughness_limiter_limit = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/limit"); glow_bicubic_upscale = int(GLOBAL_GET("rendering/environment/glow/upscale_mode")) > 0; glow_high_quality = GLOBAL_GET("rendering/environment/glow/use_high_quality"); - ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/environment/screen_space_reflection/roughness_quality"))); - sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality"))); - sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale"); - sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale"); - - environment_set_ssil_quality(RS::EnvironmentSSILQuality(int(GLOBAL_GET("rendering/environment/ssil/quality"))), GLOBAL_GET("rendering/environment/ssil/half_size"), GLOBAL_GET("rendering/environment/ssil/adaptive_target"), GLOBAL_GET("rendering/environment/ssil/blur_passes"), GLOBAL_GET("rendering/environment/ssil/fadeout_from"), GLOBAL_GET("rendering/environment/ssil/fadeout_to")); directional_penumbra_shadow_kernel = memnew_arr(float, 128); directional_soft_shadow_kernel = memnew_arr(float, 128); @@ -3844,11 +1435,14 @@ void RendererSceneRenderRD::init() { vrs = memnew(RendererRD::VRS); if (can_use_storage) { fsr = memnew(RendererRD::FSR); - ss_effects = memnew(RendererRD::SSEffects); } } RendererSceneRenderRD::~RendererSceneRenderRD() { + if (forward_id_storage) { + memdelete(forward_id_storage); + } + if (bokeh_dof) { memdelete(bokeh_dof); } @@ -3864,13 +1458,6 @@ RendererSceneRenderRD::~RendererSceneRenderRD() { if (fsr) { memdelete(fsr); } - if (ss_effects) { - memdelete(ss_effects); - } - - for (const KeyValue<int, ShadowCubemap> &E : shadow_cubemaps) { - RD::get_singleton()->free(E.value.cubemap); - } if (sky.sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky.sky_scene_state.uniform_set)) { RD::get_singleton()->free(sky.sky_scene_state.uniform_set); @@ -3889,25 +1476,6 @@ RendererSceneRenderRD::~RendererSceneRenderRD() { memdelete_arr(penumbra_shadow_kernel); memdelete_arr(soft_shadow_kernel); - { - RD::get_singleton()->free(cluster.directional_light_buffer); - RD::get_singleton()->free(cluster.omni_light_buffer); - RD::get_singleton()->free(cluster.spot_light_buffer); - RD::get_singleton()->free(cluster.reflection_buffer); - RD::get_singleton()->free(cluster.decal_buffer); - memdelete_arr(cluster.directional_lights); - memdelete_arr(cluster.omni_lights); - memdelete_arr(cluster.spot_lights); - memdelete_arr(cluster.omni_light_sort); - memdelete_arr(cluster.spot_light_sort); - memdelete_arr(cluster.reflections); - memdelete_arr(cluster.reflection_sort); - memdelete_arr(cluster.decals); - memdelete_arr(cluster.decal_sort); - } - - RD::get_singleton()->free(shadow_sampler); - - directional_shadow_atlas_set_size(0); + RSG::light_storage->directional_shadow_atlas_set_size(0); cull_argument.reset(); //avoid exit error } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 82dc2fd09f..2312603829 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -38,19 +38,21 @@ #include "servers/rendering/renderer_rd/effects/bokeh_dof.h" #include "servers/rendering/renderer_rd/effects/copy_effects.h" #include "servers/rendering/renderer_rd/effects/fsr.h" -#include "servers/rendering/renderer_rd/effects/ss_effects.h" #include "servers/rendering/renderer_rd/effects/tone_mapper.h" #include "servers/rendering/renderer_rd/effects/vrs.h" #include "servers/rendering/renderer_rd/environment/fog.h" #include "servers/rendering/renderer_rd/environment/gi.h" #include "servers/rendering/renderer_rd/environment/sky.h" #include "servers/rendering/renderer_rd/framebuffer_cache_rd.h" +#include "servers/rendering/renderer_rd/storage_rd/light_storage.h" #include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h" #include "servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h" #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" #include "servers/rendering/rendering_method.h" +// For RenderDataRD, possibly inherited from RefCounted and add proper getters for our implementation classes + struct RenderDataRD { Ref<RenderSceneBuffersRD> render_buffers; RenderSceneDataRD *scene_data; @@ -65,6 +67,7 @@ struct RenderDataRD { RID environment; RID camera_attributes; RID shadow_atlas; + RID occluder_debug_tex; RID reflection_atlas; RID reflection_probe; int reflection_probe_pass = 0; @@ -77,6 +80,21 @@ struct RenderDataRD { bool directional_light_soft_shadows = false; RenderingMethod::RenderInfo *render_info = nullptr; + + /* Shadow data */ + const RendererSceneRender::RenderShadowData *render_shadows = nullptr; + int render_shadow_count = 0; + + LocalVector<int> cube_shadows; + LocalVector<int> shadows; + LocalVector<int> directional_shadows; + + /* GI info */ + const RendererSceneRender::RenderSDFGIData *render_sdfgi_regions = nullptr; + int render_sdfgi_region_count = 0; + const RendererSceneRender::RenderSDFGIUpdateData *sdfgi_update_data = nullptr; + + uint32_t voxel_gi_count = 0; }; class RendererSceneRenderRD : public RendererSceneRender { @@ -84,6 +102,7 @@ class RendererSceneRenderRD : public RendererSceneRender { friend RendererRD::GI; protected: + RendererRD::ForwardIDStorage *forward_id_storage = nullptr; RendererRD::BokehDOF *bokeh_dof = nullptr; RendererRD::CopyEffects *copy_effects = nullptr; RendererRD::ToneMapper *tone_mapper = nullptr; @@ -92,18 +111,23 @@ protected: double time = 0.0; double time_step = 0.0; - virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) = 0; + /* ENVIRONMENT */ - void _setup_lights(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows); - void _setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform); - void _setup_reflections(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment); + bool glow_bicubic_upscale = false; + bool glow_high_quality = false; - virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0; + bool use_physical_light_units = false; + + //////////////////////////////// + + virtual RendererRD::ForwardIDStorage *create_forward_id_storage() { return memnew(RendererRD::ForwardIDStorage); }; - virtual void _render_shadow_begin() = 0; - virtual void _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 = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) = 0; - virtual void _render_shadow_process() = 0; - virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) = 0; + void _update_vrs(Ref<RenderSceneBuffersRD> p_render_buffers); + + virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) = 0; + + virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0; + virtual void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer); virtual void _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) = 0; virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; @@ -111,25 +135,14 @@ protected: virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) = 0; void _debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth); - void _debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers); - virtual void _base_uniforms_changed() = 0; virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0; virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0; - void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection); - void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive); - void _process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera); - void _process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform); - - void _copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers); - bool _needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi); void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi); void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi); - void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer); - void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data); void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data); void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data); @@ -140,26 +153,8 @@ protected: PagedArrayPool<RenderGeometryInstance *> cull_argument_pool; PagedArray<RenderGeometryInstance *> cull_argument; //need this to exist - RendererRD::SSEffects *ss_effects = nullptr; - RendererRD::GI gi; RendererRD::SkyRD sky; - - //used for mobile renderer mostly - - typedef int32_t ForwardID; - - enum ForwardIDType { - FORWARD_ID_TYPE_OMNI_LIGHT, - FORWARD_ID_TYPE_SPOT_LIGHT, - FORWARD_ID_TYPE_REFLECTION_PROBE, - FORWARD_ID_TYPE_DECAL, - FORWARD_ID_MAX, - }; - - virtual ForwardID _allocate_forward_id(ForwardIDType p_type) { return -1; } - virtual void _free_forward_id(ForwardIDType p_type, ForwardID p_id) {} - virtual void _map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) {} - virtual bool _uses_forward_ids() const { return false; } + RendererRD::GI gi; virtual void _update_shader_quality_settings() {} @@ -167,125 +162,7 @@ private: RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED; static RendererSceneRenderRD *singleton; - /* REFLECTION ATLAS */ - - struct ReflectionAtlas { - int count = 0; - int size = 0; - - RID reflection; - RID depth_buffer; - RID depth_fb; - - struct Reflection { - RID owner; - RendererRD::SkyRD::ReflectionData data; - RID fbs[6]; - }; - - Vector<Reflection> reflections; - - ClusterBuilderRD *cluster_builder = nullptr; - }; - - mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner; - - /* REFLECTION PROBE INSTANCE */ - - struct ReflectionProbeInstance { - RID probe; - int atlas_index = -1; - RID atlas; - - bool dirty = true; - bool rendering = false; - int processing_layer = 1; - int processing_side = 0; - - uint32_t render_step = 0; - uint64_t last_pass = 0; - uint32_t cull_mask = 0; - - ForwardID forward_id = -1; - - Transform3D transform; - }; - - mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner; - - /* DECAL INSTANCE */ - - struct DecalInstance { - RID decal; - Transform3D transform; - uint32_t cull_mask = 0; - ForwardID forward_id = -1; - }; - - mutable RID_Owner<DecalInstance> decal_instance_owner; - - /* LIGHTMAP INSTANCE */ - - struct LightmapInstance { - RID lightmap; - Transform3D transform; - }; - - mutable RID_Owner<LightmapInstance> lightmap_instance_owner; - - /* SHADOW ATLAS */ - - struct ShadowShrinkStage { - RID texture; - RID filter_texture; - uint32_t size = 0; - }; - - struct ShadowAtlas { - enum { - QUADRANT_SHIFT = 27, - OMNI_LIGHT_FLAG = 1 << 26, - SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1, - SHADOW_INVALID = 0xFFFFFFFF - }; - - struct Quadrant { - uint32_t subdivision = 0; - - struct Shadow { - RID owner; - uint64_t version = 0; - uint64_t fog_version = 0; // used for fog - uint64_t alloc_tick = 0; - - Shadow() {} - }; - - Vector<Shadow> shadows; - - Quadrant() {} - } quadrants[4]; - - int size_order[4] = { 0, 1, 2, 3 }; - uint32_t smallest_subdiv = 0; - - int size = 0; - bool use_16_bits = true; - - RID depth; - RID fb; //for copying - - HashMap<RID, uint32_t> shadow_owners; - }; - - RID_Owner<ShadowAtlas> shadow_atlas_owner; - - void _update_shadow_atlas(ShadowAtlas *shadow_atlas); - - void _shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx); - bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); - bool _shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); - + /* Shadow atlas */ RS::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set RS::ShadowQuality directional_shadow_quality = RS::SHADOW_QUALITY_MAX; float shadows_quality_radius = 1.0; @@ -302,299 +179,36 @@ private: RS::DecalFilter decals_filter = RS::DECAL_FILTER_LINEAR_MIPMAPS; RS::LightProjectorFilter light_projectors_filter = RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS; - /* DIRECTIONAL SHADOW */ - - struct DirectionalShadow { - RID depth; - RID fb; //when renderign direct - - int light_count = 0; - int size = 0; - bool use_16_bits = true; - int current_light = 0; - } directional_shadow; - - void _update_directional_shadow_atlas(); - - /* SHADOW CUBEMAPS */ - - struct ShadowCubemap { - RID cubemap; - RID side_fb[6]; - }; - - HashMap<int, ShadowCubemap> shadow_cubemaps; - ShadowCubemap *_get_shadow_cubemap(int p_size); - - void _create_shadow_cubemaps(); - - /* LIGHT INSTANCE */ - - struct LightInstance { - struct ShadowTransform { - Projection camera; - Transform3D transform; - float farplane; - float split; - float bias_scale; - float shadow_texel_size; - float range_begin; - Rect2 atlas_rect; - Vector2 uv_scale; - }; - - RS::LightType light_type = RS::LIGHT_DIRECTIONAL; - - ShadowTransform shadow_transform[6]; - - AABB aabb; - RID self; - RID light; - Transform3D transform; - - Vector3 light_vector; - Vector3 spot_vector; - float linear_att = 0.0; - - uint64_t shadow_pass = 0; - uint64_t last_scene_pass = 0; - uint64_t last_scene_shadow_pass = 0; - uint64_t last_pass = 0; - uint32_t cull_mask = 0; - uint32_t light_directional_index = 0; - - Rect2 directional_rect; - - HashSet<RID> shadow_atlases; //shadow atlases where this light is registered - - ForwardID forward_id = -1; - - LightInstance() {} - }; - - mutable RID_Owner<LightInstance> light_instance_owner; - - /* ENVIRONMENT */ - - RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM; - bool ssao_half_size = false; - float ssao_adaptive_target = 0.5; - int ssao_blur_passes = 2; - float ssao_fadeout_from = 50.0; - float ssao_fadeout_to = 300.0; - - RS::EnvironmentSSILQuality ssil_quality = RS::ENV_SSIL_QUALITY_MEDIUM; - bool ssil_half_size = false; - bool ssil_using_half_size = false; - float ssil_adaptive_target = 0.5; - int ssil_blur_passes = 4; - float ssil_fadeout_from = 50.0; - float ssil_fadeout_to = 300.0; - - bool glow_bicubic_upscale = false; - bool glow_high_quality = false; - RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW; - - RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM; - float sss_scale = 0.05; - float sss_depth_scale = 0.01; - - bool use_physical_light_units = false; - - /* Cluster builder */ - - ClusterBuilderSharedDataRD cluster_builder_shared; - ClusterBuilderRD *current_cluster_builder = nullptr; - /* RENDER BUFFERS */ + // TODO move into effects/luminance.h/cpp void _allocate_luminance_textures(Ref<RenderSceneBuffersRD> rb); - void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer); - /* GI */ bool screen_space_roughness_limiter = false; float screen_space_roughness_limiter_amount = 0.25; float screen_space_roughness_limiter_limit = 0.18; - /* Cluster */ - - struct Cluster { - /* Scene State UBO */ - - // !BAS! Most data here is not just used by our clustering logic but also by other lighting implementations. Maybe rename this struct to something more appropriate - - enum { - REFLECTION_AMBIENT_DISABLED = 0, - REFLECTION_AMBIENT_ENVIRONMENT = 1, - REFLECTION_AMBIENT_COLOR = 2, - }; - - struct ReflectionData { - float box_extents[3]; - float index; - float box_offset[3]; - uint32_t mask; - float ambient[3]; // ambient color, - float intensity; - uint32_t exterior; - uint32_t box_project; - uint32_t ambient_mode; - float exposure_normalization; - float local_matrix[16]; // up to here for spot and omni, rest is for directional - }; - - struct LightData { - float position[3]; - float inv_radius; - float direction[3]; // in omni, x and y are used for dual paraboloid offset - float size; - - float color[3]; - float attenuation; - - float inv_spot_attenuation; - float cos_spot_angle; - float specular_amount; - float shadow_opacity; - - float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv - float shadow_matrix[16]; - float shadow_bias; - float shadow_normal_bias; - float transmittance_bias; - float soft_shadow_size; - float soft_shadow_scale; - uint32_t mask; - float volumetric_fog_energy; - uint32_t bake_mode; - float projector_rect[4]; - }; - - struct DirectionalLightData { - float direction[3]; - float energy; - float color[3]; - float size; - float specular; - uint32_t mask; - float softshadow_angle; - float soft_shadow_scale; - uint32_t blend_splits; - float shadow_opacity; - float fade_from; - float fade_to; - uint32_t pad[2]; - uint32_t bake_mode; - float volumetric_fog_energy; - float shadow_bias[4]; - float shadow_normal_bias[4]; - float shadow_transmittance_bias[4]; - float shadow_z_range[4]; - float shadow_range_begin[4]; - float shadow_split_offsets[4]; - float shadow_matrices[4][16]; - float uv_scale1[2]; - float uv_scale2[2]; - float uv_scale3[2]; - float uv_scale4[2]; - }; - - struct DecalData { - float xform[16]; - float inv_extents[3]; - float albedo_mix; - float albedo_rect[4]; - float normal_rect[4]; - float orm_rect[4]; - float emission_rect[4]; - float modulate[4]; - float emission_energy; - uint32_t mask; - float upper_fade; - float lower_fade; - float normal_xform[12]; - float normal[3]; - float normal_fade; - }; - - template <class T> - struct InstanceSort { - float depth; - T *instance = nullptr; - bool operator<(const InstanceSort &p_sort) const { - return depth < p_sort.depth; - } - }; - - ReflectionData *reflections = nullptr; - InstanceSort<ReflectionProbeInstance> *reflection_sort; - uint32_t max_reflections; - RID reflection_buffer; - uint32_t max_reflection_probes_per_instance; - uint32_t reflection_count = 0; - - DecalData *decals = nullptr; - InstanceSort<DecalInstance> *decal_sort; - uint32_t max_decals; - RID decal_buffer; - uint32_t decal_count; - - LightData *omni_lights = nullptr; - LightData *spot_lights = nullptr; - - InstanceSort<LightInstance> *omni_light_sort; - InstanceSort<LightInstance> *spot_light_sort; - uint32_t max_lights; - RID omni_light_buffer; - RID spot_light_buffer; - uint32_t omni_light_count = 0; - uint32_t spot_light_count = 0; - - DirectionalLightData *directional_lights = nullptr; - uint32_t max_directional_lights; - RID directional_light_buffer; - - } cluster; - - struct RenderState { - const RendererSceneRender::RenderShadowData *render_shadows = nullptr; - int render_shadow_count = 0; - const RendererSceneRender::RenderSDFGIData *render_sdfgi_regions = nullptr; - int render_sdfgi_region_count = 0; - const RendererSceneRender::RenderSDFGIUpdateData *sdfgi_update_data = nullptr; - - uint32_t voxel_gi_count = 0; - - LocalVector<int> cube_shadows; - LocalVector<int> shadows; - LocalVector<int> directional_shadows; - - bool depth_prepass_used; // this does not seem used anywhere... - } render_state; - - RID shadow_sampler; + /* Light data */ uint64_t scene_pass = 0; - uint64_t shadow_atlas_realloc_tolerance_msec = 500; uint32_t max_cluster_elements = 512; - void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr); - /* Volumetric Fog */ uint32_t volumetric_fog_size = 128; uint32_t volumetric_fog_depth = 128; bool volumetric_fog_filter_active = true; - void _update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes); - public: static RendererSceneRenderRD *get_singleton() { return singleton; } - /* Cluster builder */ - ClusterBuilderSharedDataRD *get_cluster_builder_shared() { return &cluster_builder_shared; } + /* LIGHTING */ + + virtual void setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_extents){}; + virtual void setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture){}; + virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_extents){}; /* GI */ @@ -604,42 +218,6 @@ public: RendererRD::SkyRD *get_sky() { return &sky; } - /* SHADOW ATLAS API */ - - virtual RID shadow_atlas_create() override; - virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override; - virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override; - virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override; - _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) { - ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); - ERR_FAIL_COND_V(!atlas, false); - return atlas->shadow_owners.has(p_light_intance); - } - - _FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) { - ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); - ERR_FAIL_COND_V(!atlas, RID()); - return atlas->depth; - } - - _FORCE_INLINE_ Size2i shadow_atlas_get_size(RID p_atlas) { - ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); - ERR_FAIL_COND_V(!atlas, Size2i()); - return Size2(atlas->size, atlas->size); - } - - virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override; - virtual int get_directional_light_shadow_size(RID p_light_intance) override; - virtual void set_directional_shadow_count(int p_count) override; - - _FORCE_INLINE_ RID directional_shadow_get_texture() { - return directional_shadow.depth; - } - - _FORCE_INLINE_ Size2i directional_shadow_get_size() { - return Size2i(directional_shadow.size, directional_shadow.size); - } - /* SDFGI UPDATE */ virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override; @@ -666,266 +244,32 @@ public: virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override; virtual void environment_set_volumetric_fog_filter_active(bool p_enable) override; - virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; - - virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; - virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override; virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override; virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) override; - virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override; - RS::EnvironmentSSRRoughnessQuality environment_get_ssr_roughness_quality() const; - virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override; _FORCE_INLINE_ bool is_using_physical_light_units() { return use_physical_light_units; } - /* LIGHT INSTANCE API */ - - virtual RID light_instance_create(RID p_light) override; - virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override; - virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override; - virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override; - virtual void light_instance_mark_visible(RID p_light_instance) override; - - _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->light; - } - - _FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->transform; - } - - _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas, Vector2i &r_omni_offset) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - uint32_t key = shadow_atlas->shadow_owners[li->self]; - - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - - ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), Rect2()); - - uint32_t atlas_size = shadow_atlas->size; - uint32_t quadrant_size = atlas_size >> 1; - - uint32_t x = (quadrant & 1) * quadrant_size; - uint32_t y = (quadrant >> 1) * quadrant_size; - - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - - if (key & ShadowAtlas::OMNI_LIGHT_FLAG) { - if (((shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision) == 0) { - r_omni_offset.x = 1 - int(shadow_atlas->quadrants[quadrant].subdivision); - r_omni_offset.y = 1; - } else { - r_omni_offset.x = 1; - r_omni_offset.y = 0; - } - } - - uint32_t width = shadow_size; - uint32_t height = shadow_size; - - return Rect2(x / float(shadow_atlas->size), y / float(shadow_atlas->size), width / float(shadow_atlas->size), height / float(shadow_atlas->size)); - } - - _FORCE_INLINE_ Projection light_instance_get_shadow_camera(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].camera; - } - - _FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) { -#ifdef DEBUG_ENABLED - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0); -#endif - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); - ERR_FAIL_COND_V(!shadow_atlas, 0); -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0); -#endif - uint32_t key = shadow_atlas->shadow_owners[p_light_instance]; - - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - - uint32_t quadrant_size = shadow_atlas->size >> 1; - - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - - return float(1.0) / shadow_size; - } - - _FORCE_INLINE_ Transform3D - light_instance_get_shadow_transform(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].transform; - } - _FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].bias_scale; - } - _FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].farplane; - } - _FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].range_begin; - } - - _FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].uv_scale; - } - - _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].atlas_rect; - } - - _FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].split; - } - - _FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].shadow_texel_size; - } - - _FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - li->last_pass = p_pass; - } - - _FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->last_pass; - } - - _FORCE_INLINE_ ForwardID light_instance_get_forward_id(RID p_light_instance) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->forward_id; - } + /* REFLECTION PROBE */ - _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) { - LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->light_type; - } + virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth); /* FOG VOLUMES */ + uint32_t get_volumetric_fog_size() const { return volumetric_fog_size; } + uint32_t get_volumetric_fog_depth() const { return volumetric_fog_depth; } + bool get_volumetric_fog_filter_active() const { return volumetric_fog_filter_active; } + virtual RID fog_volume_instance_create(RID p_fog_volume) override; virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override; virtual void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override; virtual RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override; virtual Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override; - virtual RID reflection_atlas_create() override; - virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override; - virtual int reflection_atlas_get_size(RID p_ref_atlas) const override; - - _FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) { - ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_ref_atlas); - ERR_FAIL_COND_V(!atlas, RID()); - return atlas->reflection; - } - - virtual RID reflection_probe_instance_create(RID p_probe) override; - virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override; - virtual void reflection_probe_release_atlas_index(RID p_instance) override; - virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override; - virtual bool reflection_probe_instance_has_reflection(RID p_instance) override; - virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override; - virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth); - virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override; - - uint32_t reflection_probe_instance_get_resolution(RID p_instance); - RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index); - RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index); - - _FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, RID()); - - return rpi->probe; - } - - _FORCE_INLINE_ ForwardID reflection_probe_instance_get_forward_id(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, 0); - - return rpi->forward_id; - } - - _FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND(!rpi); - rpi->last_pass = p_render_pass; - } - - _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, 0); - - return rpi->last_pass; - } - - _FORCE_INLINE_ Transform3D reflection_probe_instance_get_transform(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, Transform3D()); - - return rpi->transform; - } - - _FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); - ERR_FAIL_COND_V(!rpi, -1); - - return rpi->atlas_index; - } - - virtual RID decal_instance_create(RID p_decal) override; - virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override; - - _FORCE_INLINE_ RID decal_instance_get_base(RID p_decal) const { - DecalInstance *decal = decal_instance_owner.get_or_null(p_decal); - return decal->decal; - } - - _FORCE_INLINE_ ForwardID decal_instance_get_forward_id(RID p_decal) const { - DecalInstance *decal = decal_instance_owner.get_or_null(p_decal); - return decal->forward_id; - } - - _FORCE_INLINE_ Transform3D decal_instance_get_transform(RID p_decal) const { - DecalInstance *decal = decal_instance_owner.get_or_null(p_decal); - return decal->transform; - } - - virtual RID lightmap_instance_create(RID p_lightmap) override; - virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override; - _FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) { - return lightmap_instance_owner.get_or_null(p_lightmap_instance) != nullptr; - } - - _FORCE_INLINE_ RID lightmap_instance_get_lightmap(RID p_lightmap_instance) { - LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance); - return li->lightmap; - } - _FORCE_INLINE_ Transform3D lightmap_instance_get_transform(RID p_lightmap_instance) { - LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance); - return li->transform; - } - /* gi light probes */ virtual RID voxel_gi_instance_create(RID p_base) override; @@ -944,6 +288,7 @@ public: RID render_buffers_get_default_voxel_gi_buffer(); + virtual void base_uniforms_changed() = 0; virtual void update_uniform_sets(){}; virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) override; @@ -964,10 +309,6 @@ public: virtual float screen_space_roughness_limiter_get_amount() const; virtual float screen_space_roughness_limiter_get_limit() const; - virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override; - RS::SubSurfaceScatteringQuality sub_surface_scattering_get_quality() const; - virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override; - virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override; virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override; @@ -1036,18 +377,10 @@ public: virtual void set_time(double p_time, double p_step) override; - RID get_reflection_probe_buffer(); - RID get_omni_light_buffer(); - RID get_spot_light_buffer(); - RID get_directional_light_buffer(); - RID get_decal_buffer(); - int get_max_directional_lights() const; - virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override; virtual bool is_vrs_supported() const; virtual bool is_dynamic_gi_supported() const; - virtual bool is_clustered_enabled() const; virtual bool is_volumetric_supported() const; virtual uint32_t get_max_elements() const; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl index e8e2dce990..0d36b98645 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl @@ -62,13 +62,14 @@ layout(set = 0, binding = 3) uniform sampler decal_sampler; layout(set = 0, binding = 4) uniform sampler light_projector_sampler; -#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 5) -#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6) -#define INSTANCE_FLAGS_USE_SDFGI (1 << 7) -#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8) -#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9) -#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10) -#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 11) +#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 4) +#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 5) +#define INSTANCE_FLAGS_USE_SDFGI (1 << 6) +#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 7) +#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 8) +#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 9) +#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 10) +#define INSTANCE_FLAGS_PARTICLES (1 << 11) #define INSTANCE_FLAGS_MULTIMESH (1 << 12) #define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13) #define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl index 5e4999fa0f..631ff0575b 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl @@ -55,13 +55,14 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler; layout(set = 0, binding = 3) uniform sampler decal_sampler; layout(set = 0, binding = 4) uniform sampler light_projector_sampler; -#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 5) -#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6) -#define INSTANCE_FLAGS_USE_SDFGI (1 << 7) -#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8) -#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9) -#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10) -#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 11) +#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 4) +#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 5) +#define INSTANCE_FLAGS_USE_SDFGI (1 << 6) +#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 7) +#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 8) +#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 9) +#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 10) +#define INSTANCE_FLAGS_PARTICLES (1 << 11) #define INSTANCE_FLAGS_MULTIMESH (1 << 12) #define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13) #define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) diff --git a/servers/rendering/renderer_rd/storage_rd/forward_id_storage.cpp b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.cpp new file mode 100644 index 0000000000..c7f106eba0 --- /dev/null +++ b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.cpp @@ -0,0 +1,43 @@ +/*************************************************************************/ +/* forward_id_storage.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "forward_id_storage.h" + +using namespace RendererRD; + +ForwardIDStorage *ForwardIDStorage::singleton = nullptr; + +ForwardIDStorage::ForwardIDStorage() { + singleton = this; +} + +ForwardIDStorage::~ForwardIDStorage() { + singleton = nullptr; +} diff --git a/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h new file mode 100644 index 0000000000..f6a74383d4 --- /dev/null +++ b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h @@ -0,0 +1,68 @@ +/*************************************************************************/ +/* forward_id_storage.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef FORWARD_ID_STORAGE_H +#define FORWARD_ID_STORAGE_H + +#include "servers/rendering/storage/utilities.h" + +class RendererSceneRenderRD; + +namespace RendererRD { + +typedef int32_t ForwardID; + +enum ForwardIDType { + FORWARD_ID_TYPE_OMNI_LIGHT, + FORWARD_ID_TYPE_SPOT_LIGHT, + FORWARD_ID_TYPE_REFLECTION_PROBE, + FORWARD_ID_TYPE_DECAL, + FORWARD_ID_MAX, +}; + +class ForwardIDStorage { +private: + static ForwardIDStorage *singleton; + +public: + static ForwardIDStorage *get_singleton() { return singleton; } + + ForwardIDStorage(); + virtual ~ForwardIDStorage(); + + virtual RendererRD::ForwardID allocate_forward_id(RendererRD::ForwardIDType p_type) { return -1; } + virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) {} + virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) {} + virtual bool uses_forward_ids() const { return false; } +}; + +} // namespace RendererRD + +#endif // FORWARD_ID_STORAGE_H diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 81b0661481..c83473ef07 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -30,6 +30,7 @@ #include "light_storage.h" #include "core/config/project_settings.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" #include "texture_storage.h" using namespace RendererRD; @@ -45,6 +46,9 @@ LightStorage::LightStorage() { TextureStorage *texture_storage = TextureStorage::get_singleton(); + directional_shadow.size = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/size"); + directional_shadow.use_16_bits = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/16_bits"); + using_lightmap_array = true; // high end if (using_lightmap_array) { uint64_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); @@ -56,7 +60,7 @@ LightStorage::LightStorage() { } for (int i = 0; i < lightmap_textures.size(); i++) { - lightmap_textures.write[i] = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + lightmap_textures.write[i] = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); } } @@ -64,9 +68,46 @@ LightStorage::LightStorage() { } LightStorage::~LightStorage() { + free_reflection_data(); + free_light_data(); + + for (const KeyValue<int, ShadowCubemap> &E : shadow_cubemaps) { + RD::get_singleton()->free(E.value.cubemap); + } + singleton = nullptr; } +bool LightStorage::free(RID p_rid) { + if (owns_reflection_probe(p_rid)) { + reflection_probe_free(p_rid); + return true; + } else if (owns_reflection_atlas(p_rid)) { + reflection_atlas_free(p_rid); + return true; + } else if (owns_reflection_probe_instance(p_rid)) { + reflection_probe_instance_free(p_rid); + return true; + } else if (owns_light(p_rid)) { + light_free(p_rid); + return true; + } else if (owns_light_instance(p_rid)) { + light_instance_free(p_rid); + return true; + } else if (owns_lightmap(p_rid)) { + lightmap_free(p_rid); + return true; + } else if (owns_lightmap_instance(p_rid)) { + lightmap_instance_free(p_rid); + return true; + } else if (owns_shadow_atlas(p_rid)) { + shadow_atlas_free(p_rid); + return true; + } + + return false; +} + /* LIGHT */ void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) { @@ -183,7 +224,7 @@ void LightStorage::light_set_shadow(RID p_light, bool p_enabled) { } void LightStorage::light_set_projector(RID p_light, RID p_texture) { - RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + TextureStorage *texture_storage = TextureStorage::get_singleton(); Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); @@ -375,6 +416,595 @@ Dependency *LightStorage::light_get_dependency(RID p_light) const { return &light->dependency; } +/* LIGHT INSTANCE API */ + +RID LightStorage::light_instance_create(RID p_light) { + RID li = light_instance_owner.make_rid(LightInstance()); + + LightInstance *light_instance = light_instance_owner.get_or_null(li); + + light_instance->self = li; + light_instance->light = p_light; + light_instance->light_type = light_get_type(p_light); + if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) { + light_instance->forward_id = ForwardIDStorage::get_singleton()->allocate_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT); + } + + return li; +} + +void LightStorage::light_instance_free(RID p_light) { + LightInstance *light_instance = light_instance_owner.get_or_null(p_light); + + //remove from shadow atlases.. + for (const RID &E : light_instance->shadow_atlases) { + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(E); + ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_light)); + uint32_t key = shadow_atlas->shadow_owners[p_light]; + uint32_t q = (key >> QUADRANT_SHIFT) & 0x3; + uint32_t s = key & SHADOW_INDEX_MASK; + + shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); + + if (key & OMNI_LIGHT_FLAG) { + // Omni lights use two atlas spots, make sure to clear the other as well + shadow_atlas->quadrants[q].shadows.write[s + 1].owner = RID(); + } + + shadow_atlas->shadow_owners.erase(p_light); + } + + if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) { + ForwardIDStorage::get_singleton()->free_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id); + } + light_instance_owner.free(p_light); +} + +void LightStorage::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) { + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); + ERR_FAIL_COND(!light_instance); + + light_instance->transform = p_transform; +} + +void LightStorage::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) { + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); + ERR_FAIL_COND(!light_instance); + + light_instance->aabb = p_aabb; +} + +void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); + ERR_FAIL_COND(!light_instance); + + ERR_FAIL_INDEX(p_pass, 6); + + light_instance->shadow_transform[p_pass].camera = p_projection; + light_instance->shadow_transform[p_pass].transform = p_transform; + light_instance->shadow_transform[p_pass].farplane = p_far; + light_instance->shadow_transform[p_pass].split = p_split; + light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale; + light_instance->shadow_transform[p_pass].range_begin = p_range_begin; + light_instance->shadow_transform[p_pass].shadow_texel_size = p_shadow_texel_size; + light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale; +} + +void LightStorage::light_instance_mark_visible(RID p_light_instance) { + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); + ERR_FAIL_COND(!light_instance); + + light_instance->last_scene_pass = RendererSceneRenderRD::get_singleton()->get_scene_pass(); +} + +/* LIGHT DATA */ + +void LightStorage::free_light_data() { + if (directional_light_buffer.is_valid()) { + RD::get_singleton()->free(directional_light_buffer); + directional_light_buffer = RID(); + } + + if (omni_light_buffer.is_valid()) { + RD::get_singleton()->free(omni_light_buffer); + omni_light_buffer = RID(); + } + + if (spot_light_buffer.is_valid()) { + RD::get_singleton()->free(spot_light_buffer); + spot_light_buffer = RID(); + } + + if (directional_lights != nullptr) { + memdelete_arr(directional_lights); + directional_lights = nullptr; + } + + if (omni_lights != nullptr) { + memdelete_arr(omni_lights); + omni_lights = nullptr; + } + + if (spot_lights != nullptr) { + memdelete_arr(spot_lights); + spot_lights = nullptr; + } + + if (omni_light_sort != nullptr) { + memdelete_arr(omni_light_sort); + omni_light_sort = nullptr; + } + + if (spot_light_sort != nullptr) { + memdelete_arr(spot_light_sort); + spot_light_sort = nullptr; + } +} + +void LightStorage::set_max_lights(const uint32_t p_max_lights) { + max_lights = p_max_lights; + + uint32_t light_buffer_size = max_lights * sizeof(LightData); + omni_lights = memnew_arr(LightData, max_lights); + omni_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size); + omni_light_sort = memnew_arr(LightInstanceDepthSort, max_lights); + spot_lights = memnew_arr(LightData, max_lights); + spot_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size); + spot_light_sort = memnew_arr(LightInstanceDepthSort, max_lights); + //defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(max_lights) + "\n"; + + max_directional_lights = RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; + uint32_t directional_light_buffer_size = max_directional_lights * sizeof(DirectionalLightData); + directional_lights = memnew_arr(DirectionalLightData, max_directional_lights); + directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size); +} + +void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows) { + ForwardIDStorage *forward_id_storage = ForwardIDStorage::get_singleton(); + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + + Transform3D inverse_transform = p_camera_transform.affine_inverse(); + + r_directional_light_count = 0; + r_positional_light_count = 0; + + Plane camera_plane(-p_camera_transform.basis.get_column(Vector3::AXIS_Z).normalized(), p_camera_transform.origin); + + omni_light_count = 0; + spot_light_count = 0; + + r_directional_light_soft_shadows = false; + + for (int i = 0; i < (int)p_lights.size(); i++) { + LightInstance *light_instance = light_instance_owner.get_or_null(p_lights[i]); + if (!light_instance) { + continue; + } + Light *light = light_owner.get_or_null(light_instance->light); + + ERR_CONTINUE(light == nullptr); + + switch (light->type) { + case RS::LIGHT_DIRECTIONAL: { + if (r_directional_light_count >= max_directional_lights || light->directional_sky_mode == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) { + continue; + } + + DirectionalLightData &light_data = directional_lights[r_directional_light_count]; + + Transform3D light_transform = light_instance->transform; + + Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized(); + + light_data.direction[0] = direction.x; + light_data.direction[1] = direction.y; + light_data.direction[2] = direction.z; + + float sign = light->negative ? -1 : 1; + + light_data.energy = sign * light->param[RS::LIGHT_PARAM_ENERGY]; + + if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) { + light_data.energy *= light->param[RS::LIGHT_PARAM_INTENSITY]; + } else { + light_data.energy *= Math_PI; + } + + if (p_render_data->camera_attributes.is_valid()) { + light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); + } + + Color linear_col = light->color.srgb_to_linear(); + light_data.color[0] = linear_col.r; + light_data.color[1] = linear_col.g; + light_data.color[2] = linear_col.b; + + light_data.specular = light->param[RS::LIGHT_PARAM_SPECULAR]; + light_data.volumetric_fog_energy = light->param[RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY]; + light_data.mask = light->cull_mask; + + float size = light->param[RS::LIGHT_PARAM_SIZE]; + + light_data.size = 1.0 - Math::cos(Math::deg_to_rad(size)); //angle to cosine offset + + if (RendererSceneRenderRD::get_singleton()->get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) { + WARN_PRINT_ONCE("The DirectionalLight3D PSSM splits debug draw mode is not reimplemented yet."); + } + + light_data.shadow_opacity = (p_using_shadows && light->shadow) + ? light->param[RS::LIGHT_PARAM_SHADOW_OPACITY] + : 0.0; + + float angular_diameter = light->param[RS::LIGHT_PARAM_SIZE]; + if (angular_diameter > 0.0) { + // I know tan(0) is 0, but let's not risk it with numerical precision. + // technically this will keep expanding until reaching the sun, but all we care + // is expand until we reach the radius of the near plane (there can't be more occluders than that) + angular_diameter = Math::tan(Math::deg_to_rad(angular_diameter)); + if (light->shadow && light->param[RS::LIGHT_PARAM_SHADOW_BLUR] > 0.0) { + // Only enable PCSS-like soft shadows if blurring is enabled. + // Otherwise, performance would decrease with no visual difference. + r_directional_light_soft_shadows = true; + } + } else { + angular_diameter = 0.0; + } + + if (light_data.shadow_opacity > 0.001) { + RS::LightDirectionalShadowMode smode = light->directional_shadow_mode; + + int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3); + light_data.blend_splits = (smode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && light->directional_blend_splits; + for (int j = 0; j < 4; j++) { + Rect2 atlas_rect = light_instance->shadow_transform[j].atlas_rect; + Projection matrix = light_instance->shadow_transform[j].camera; + float split = light_instance->shadow_transform[MIN(limit, j)].split; + + Projection bias; + bias.set_light_bias(); + Projection rectm; + rectm.set_light_atlas_rect(atlas_rect); + + Transform3D modelview = (inverse_transform * light_instance->shadow_transform[j].transform).inverse(); + + Projection shadow_mtx = rectm * bias * matrix * modelview; + light_data.shadow_split_offsets[j] = split; + float bias_scale = light_instance->shadow_transform[j].bias_scale; + light_data.shadow_bias[j] = light->param[RS::LIGHT_PARAM_SHADOW_BIAS] / 100.0 * bias_scale; + light_data.shadow_normal_bias[j] = light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * light_instance->shadow_transform[j].shadow_texel_size; + light_data.shadow_transmittance_bias[j] = light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] * bias_scale; + light_data.shadow_z_range[j] = light_instance->shadow_transform[j].farplane; + light_data.shadow_range_begin[j] = light_instance->shadow_transform[j].range_begin; + RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrices[j]); + + Vector2 uv_scale = light_instance->shadow_transform[j].uv_scale; + uv_scale *= atlas_rect.size; //adapt to atlas size + switch (j) { + case 0: { + light_data.uv_scale1[0] = uv_scale.x; + light_data.uv_scale1[1] = uv_scale.y; + } break; + case 1: { + light_data.uv_scale2[0] = uv_scale.x; + light_data.uv_scale2[1] = uv_scale.y; + } break; + case 2: { + light_data.uv_scale3[0] = uv_scale.x; + light_data.uv_scale3[1] = uv_scale.y; + } break; + case 3: { + light_data.uv_scale4[0] = uv_scale.x; + light_data.uv_scale4[1] = uv_scale.y; + } break; + } + } + + float fade_start = light->param[RS::LIGHT_PARAM_SHADOW_FADE_START]; + light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep + light_data.fade_to = -light_data.shadow_split_offsets[3]; + + light_data.soft_shadow_scale = light->param[RS::LIGHT_PARAM_SHADOW_BLUR]; + light_data.softshadow_angle = angular_diameter; + light_data.bake_mode = light->bake_mode; + + if (angular_diameter <= 0.0) { + light_data.soft_shadow_scale *= RendererSceneRenderRD::get_singleton()->directional_shadow_quality_radius_get(); // Only use quality radius for PCF + } + } + + r_directional_light_count++; + } break; + case RS::LIGHT_OMNI: { + if (omni_light_count >= max_lights) { + continue; + } + + Transform3D light_transform = light_instance->transform; + const real_t distance = camera_plane.distance_to(light_transform.origin); + + if (light->distance_fade) { + const float fade_begin = light->distance_fade_begin; + const float fade_length = light->distance_fade_length; + + if (distance > fade_begin) { + if (distance > fade_begin + fade_length) { + // Out of range, don't draw this light to improve performance. + continue; + } + } + } + + omni_light_sort[omni_light_count].light_instance = light_instance; + omni_light_sort[omni_light_count].light = light; + omni_light_sort[omni_light_count].depth = distance; + omni_light_count++; + } break; + case RS::LIGHT_SPOT: { + if (spot_light_count >= max_lights) { + continue; + } + + Transform3D light_transform = light_instance->transform; + const real_t distance = camera_plane.distance_to(light_transform.origin); + + if (light->distance_fade) { + const float fade_begin = light->distance_fade_begin; + const float fade_length = light->distance_fade_length; + + if (distance > fade_begin) { + if (distance > fade_begin + fade_length) { + // Out of range, don't draw this light to improve performance. + continue; + } + } + } + + spot_light_sort[spot_light_count].light_instance = light_instance; + spot_light_sort[spot_light_count].light = light; + spot_light_sort[spot_light_count].depth = distance; + spot_light_count++; + } break; + } + + light_instance->last_pass = RSG::rasterizer->get_frame_number(); + } + + if (omni_light_count) { + SortArray<LightInstanceDepthSort> sorter; + sorter.sort(omni_light_sort, omni_light_count); + } + + if (spot_light_count) { + SortArray<LightInstanceDepthSort> sorter; + sorter.sort(spot_light_sort, spot_light_count); + } + + bool using_forward_ids = forward_id_storage->uses_forward_ids(); + + for (uint32_t i = 0; i < (omni_light_count + spot_light_count); i++) { + uint32_t index = (i < omni_light_count) ? i : i - (omni_light_count); + LightData &light_data = (i < omni_light_count) ? omni_lights[index] : spot_lights[index]; + RS::LightType type = (i < omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT; + LightInstance *light_instance = (i < omni_light_count) ? omni_light_sort[index].light_instance : spot_light_sort[index].light_instance; + Light *light = (i < omni_light_count) ? omni_light_sort[index].light : spot_light_sort[index].light; + + if (using_forward_ids) { + forward_id_storage->map_forward_id(type == RS::LIGHT_OMNI ? RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT : RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id, index); + } + + Transform3D light_transform = light_instance->transform; + + float sign = light->negative ? -1 : 1; + Color linear_col = light->color.srgb_to_linear(); + + light_data.attenuation = light->param[RS::LIGHT_PARAM_ATTENUATION]; + + // Reuse fade begin, fade length and distance for shadow LOD determination later. + float fade_begin = 0.0; + float fade_shadow = 0.0; + float fade_length = 0.0; + real_t distance = 0.0; + + float fade = 1.0; + float shadow_opacity_fade = 1.0; + if (light->distance_fade) { + fade_begin = light->distance_fade_begin; + fade_shadow = light->distance_fade_shadow; + fade_length = light->distance_fade_length; + distance = camera_plane.distance_to(light_transform.origin); + + // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. + if (distance > fade_begin) { + fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length); + } + + if (distance > fade_shadow) { + shadow_opacity_fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_shadow) / fade_length); + } + } + + float energy = sign * light->param[RS::LIGHT_PARAM_ENERGY] * fade; + + if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) { + energy *= light->param[RS::LIGHT_PARAM_INTENSITY]; + + // Convert from Luminous Power to Luminous Intensity + if (type == RS::LIGHT_OMNI) { + energy *= 1.0 / (Math_PI * 4.0); + } else { + // Spot Lights are not physically accurate, Luminous Intensity should change in relation to the cone angle. + // We make this assumption to keep them easy to control. + energy *= 1.0 / Math_PI; + } + } else { + energy *= Math_PI; + } + + if (p_render_data->camera_attributes.is_valid()) { + energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); + } + + light_data.color[0] = linear_col.r * energy; + light_data.color[1] = linear_col.g * energy; + light_data.color[2] = linear_col.b * energy; + light_data.specular_amount = light->param[RS::LIGHT_PARAM_SPECULAR] * 2.0; + light_data.volumetric_fog_energy = light->param[RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY]; + light_data.bake_mode = light->bake_mode; + + float radius = MAX(0.001, light->param[RS::LIGHT_PARAM_RANGE]); + light_data.inv_radius = 1.0 / radius; + + Vector3 pos = inverse_transform.xform(light_transform.origin); + + light_data.position[0] = pos.x; + light_data.position[1] = pos.y; + light_data.position[2] = pos.z; + + Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized(); + + light_data.direction[0] = direction.x; + light_data.direction[1] = direction.y; + light_data.direction[2] = direction.z; + + float size = light->param[RS::LIGHT_PARAM_SIZE]; + + light_data.size = size; + + light_data.inv_spot_attenuation = 1.0f / light->param[RS::LIGHT_PARAM_SPOT_ATTENUATION]; + float spot_angle = light->param[RS::LIGHT_PARAM_SPOT_ANGLE]; + light_data.cos_spot_angle = Math::cos(Math::deg_to_rad(spot_angle)); + + light_data.mask = light->cull_mask; + + light_data.atlas_rect[0] = 0; + light_data.atlas_rect[1] = 0; + light_data.atlas_rect[2] = 0; + light_data.atlas_rect[3] = 0; + + RID projector = light->projector; + + if (projector.is_valid()) { + Rect2 rect = texture_storage->decal_atlas_get_texture_rect(projector); + + if (type == RS::LIGHT_SPOT) { + light_data.projector_rect[0] = rect.position.x; + light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped + light_data.projector_rect[2] = rect.size.width; + light_data.projector_rect[3] = -rect.size.height; + } else { + light_data.projector_rect[0] = rect.position.x; + light_data.projector_rect[1] = rect.position.y; + light_data.projector_rect[2] = rect.size.width; + light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half + } + } else { + light_data.projector_rect[0] = 0; + light_data.projector_rect[1] = 0; + light_data.projector_rect[2] = 0; + light_data.projector_rect[3] = 0; + } + + const bool needs_shadow = + p_using_shadows && + owns_shadow_atlas(p_shadow_atlas) && + shadow_atlas_owns_light_instance(p_shadow_atlas, light_instance->self) && + light->shadow; + + bool in_shadow_range = true; + if (needs_shadow && light->distance_fade) { + if (distance > light->distance_fade_shadow + light->distance_fade_length) { + // Out of range, don't draw shadows to improve performance. + in_shadow_range = false; + } + } + + if (needs_shadow && in_shadow_range) { + // fill in the shadow information + + light_data.shadow_opacity = light->param[RS::LIGHT_PARAM_SHADOW_OPACITY] * shadow_opacity_fade; + + float shadow_texel_size = light_instance_get_shadow_texel_size(light_instance->self, p_shadow_atlas); + light_data.shadow_normal_bias = light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * shadow_texel_size * 10.0; + + if (type == RS::LIGHT_SPOT) { + light_data.shadow_bias = light->param[RS::LIGHT_PARAM_SHADOW_BIAS] / 100.0; + } else { //omni + light_data.shadow_bias = light->param[RS::LIGHT_PARAM_SHADOW_BIAS]; + } + + light_data.transmittance_bias = light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS]; + + Vector2i omni_offset; + Rect2 rect = light_instance_get_shadow_atlas_rect(light_instance->self, p_shadow_atlas, omni_offset); + + light_data.atlas_rect[0] = rect.position.x; + light_data.atlas_rect[1] = rect.position.y; + light_data.atlas_rect[2] = rect.size.width; + light_data.atlas_rect[3] = rect.size.height; + + light_data.soft_shadow_scale = light->param[RS::LIGHT_PARAM_SHADOW_BLUR]; + + if (type == RS::LIGHT_OMNI) { + Transform3D proj = (inverse_transform * light_transform).inverse(); + + RendererRD::MaterialStorage::store_transform(proj, light_data.shadow_matrix); + + if (size > 0.0 && light_data.soft_shadow_scale > 0.0) { + // Only enable PCSS-like soft shadows if blurring is enabled. + // Otherwise, performance would decrease with no visual difference. + light_data.soft_shadow_size = size; + } else { + light_data.soft_shadow_size = 0.0; + light_data.soft_shadow_scale *= RendererSceneRenderRD::get_singleton()->shadows_quality_radius_get(); // Only use quality radius for PCF + } + + light_data.direction[0] = omni_offset.x * float(rect.size.width); + light_data.direction[1] = omni_offset.y * float(rect.size.height); + } else if (type == RS::LIGHT_SPOT) { + Transform3D modelview = (inverse_transform * light_transform).inverse(); + Projection bias; + bias.set_light_bias(); + + Projection cm = light_instance->shadow_transform[0].camera; + Projection shadow_mtx = bias * cm * modelview; + RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrix); + + if (size > 0.0 && light_data.soft_shadow_scale > 0.0) { + // Only enable PCSS-like soft shadows if blurring is enabled. + // Otherwise, performance would decrease with no visual difference. + float half_np = cm.get_z_near() * Math::tan(Math::deg_to_rad(spot_angle)); + light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width; + } else { + light_data.soft_shadow_size = 0.0; + light_data.soft_shadow_scale *= RendererSceneRenderRD::get_singleton()->shadows_quality_radius_get(); // Only use quality radius for PCF + } + } + } else { + light_data.shadow_opacity = 0.0; + } + + light_instance->cull_mask = light->cull_mask; + + // hook for subclass to do further processing. + RendererSceneRenderRD::get_singleton()->setup_added_light(type, light_transform, radius, spot_angle); + + r_positional_light_count++; + } + + //update without barriers + if (omni_light_count) { + RD::get_singleton()->buffer_update(omni_light_buffer, 0, sizeof(LightData) * omni_light_count, omni_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + } + + if (spot_light_count) { + RD::get_singleton()->buffer_update(spot_light_buffer, 0, sizeof(LightData) * spot_light_count, spot_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + } + + if (r_directional_light_count) { + RD::get_singleton()->buffer_update(directional_light_buffer, 0, sizeof(DirectionalLightData) * r_directional_light_count, directional_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + } +} + /* REFLECTION PROBE */ RID LightStorage::reflection_probe_allocate() { @@ -631,6 +1261,443 @@ Dependency *LightStorage::reflection_probe_get_dependency(RID p_probe) const { return &reflection_probe->dependency; } +/* REFLECTION ATLAS */ + +RID LightStorage::reflection_atlas_create() { + ReflectionAtlas ra; + ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count"); + ra.size = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_size"); + ra.cluster_builder = nullptr; + + return reflection_atlas_owner.make_rid(ra); +} + +void LightStorage::reflection_atlas_free(RID p_ref_atlas) { + reflection_atlas_set_size(p_ref_atlas, 0, 0); + ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas); + if (ra->cluster_builder) { + memdelete(ra->cluster_builder); + } + reflection_atlas_owner.free(p_ref_atlas); +} + +void LightStorage::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) { + ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas); + ERR_FAIL_COND(!ra); + + if (ra->size == p_reflection_size && ra->count == p_reflection_count) { + return; //no changes + } + + if (ra->cluster_builder) { + // only if we're using our cluster + ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID()); + } + + ra->size = p_reflection_size; + ra->count = p_reflection_count; + + if (ra->reflection.is_valid()) { + //clear and invalidate everything + RD::get_singleton()->free(ra->reflection); + ra->reflection = RID(); + RD::get_singleton()->free(ra->depth_buffer); + ra->depth_buffer = RID(); + for (int i = 0; i < ra->reflections.size(); i++) { + ra->reflections.write[i].data.clear_reflection_data(); + if (ra->reflections[i].owner.is_null()) { + continue; + } + reflection_probe_release_atlas_index(ra->reflections[i].owner); + //rp->atlasindex clear + } + + ra->reflections.clear(); + } +} + +int LightStorage::reflection_atlas_get_size(RID p_ref_atlas) const { + ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas); + ERR_FAIL_COND_V(!ra, 0); + + return ra->size; +} + +/* REFLECTION PROBE INSTANCE */ + +RID LightStorage::reflection_probe_instance_create(RID p_probe) { + ReflectionProbeInstance rpi; + rpi.probe = p_probe; + rpi.forward_id = ForwardIDStorage::get_singleton()->allocate_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE); + + return reflection_probe_instance_owner.make_rid(rpi); +} + +void LightStorage::reflection_probe_instance_free(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ForwardIDStorage::get_singleton()->free_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id); + reflection_probe_release_atlas_index(p_instance); + reflection_probe_instance_owner.free(p_instance); +} + +void LightStorage::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND(!rpi); + + rpi->transform = p_transform; + rpi->dirty = true; +} + +void LightStorage::reflection_probe_release_atlas_index(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND(!rpi); + + if (rpi->atlas.is_null()) { + return; //nothing to release + } + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); + ERR_FAIL_COND(!atlas); + ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size()); + atlas->reflections.write[rpi->atlas_index].owner = RID(); + rpi->atlas_index = -1; + rpi->atlas = RID(); +} + +bool LightStorage::reflection_probe_instance_needs_redraw(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, false); + + if (rpi->rendering) { + return false; + } + + if (rpi->dirty) { + return true; + } + + if (LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) { + return true; + } + + return rpi->atlas_index == -1; +} + +bool LightStorage::reflection_probe_instance_has_reflection(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, false); + + return rpi->atlas.is_valid(); +} + +bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas); + + ERR_FAIL_COND_V(!atlas, false); + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, false); + + RD::get_singleton()->draw_command_begin_label("Reflection probe render"); + + if (LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) { + WARN_PRINT("ReflectionProbes set to UPDATE_ALWAYS must have an atlas size of 256. Please update the atlas size in the ProjectSettings."); + reflection_atlas_set_size(p_reflection_atlas, 256, atlas->count); + } + + if (LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->reflections[0].data.layers[0].mipmaps.size() != 8) { + // Invalidate reflection atlas, need to regenerate + RD::get_singleton()->free(atlas->reflection); + atlas->reflection = RID(); + + for (int i = 0; i < atlas->reflections.size(); i++) { + if (atlas->reflections[i].owner.is_null()) { + continue; + } + reflection_probe_release_atlas_index(atlas->reflections[i].owner); + } + + atlas->reflections.clear(); + } + + if (atlas->reflection.is_null()) { + int mipmaps = MIN(RendererSceneRenderRD::get_singleton()->get_sky()->roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1); + mipmaps = LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS ? 8 : mipmaps; // always use 8 mipmaps with real time filtering + { + //reflection atlas was unused, create: + RD::TextureFormat tf; + tf.array_layers = 6 * atlas->count; + tf.format = RendererSceneRenderRD::get_singleton()->_render_buffers_get_color_format(); + tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.mipmaps = mipmaps; + tf.width = atlas->size; + tf.height = atlas->size; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0); + + atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + { + RD::TextureFormat tf; + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; + tf.width = atlas->size; + tf.height = atlas->size; + tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + atlas->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + atlas->reflections.resize(atlas->count); + for (int i = 0; i < atlas->count; i++) { + atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, RendererSceneRenderRD::get_singleton()->get_sky()->roughness_layers, RendererSceneRenderRD::get_singleton()->_render_buffers_get_color_format()); + for (int j = 0; j < 6; j++) { + atlas->reflections.write[i].fbs[j] = RendererSceneRenderRD::get_singleton()->reflection_probe_create_framebuffer(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j], atlas->depth_buffer); + } + } + + Vector<RID> fb; + fb.push_back(atlas->depth_buffer); + atlas->depth_fb = RD::get_singleton()->framebuffer_create(fb); + } + + if (rpi->atlas_index == -1) { + for (int i = 0; i < atlas->reflections.size(); i++) { + if (atlas->reflections[i].owner.is_null()) { + rpi->atlas_index = i; + break; + } + } + //find the one used last + if (rpi->atlas_index == -1) { + //everything is in use, find the one least used via LRU + uint64_t pass_min = 0; + + for (int i = 0; i < atlas->reflections.size(); i++) { + ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.get_or_null(atlas->reflections[i].owner); + if (rpi2->last_pass < pass_min) { + pass_min = rpi2->last_pass; + rpi->atlas_index = i; + } + } + } + } + + if (rpi->atlas_index != -1) { // should we fail if this is still -1 ? + atlas->reflections.write[rpi->atlas_index].owner = p_instance; + } + + rpi->atlas = p_reflection_atlas; + rpi->rendering = true; + rpi->dirty = false; + rpi->processing_layer = 1; + rpi->processing_side = 0; + + RD::get_singleton()->draw_command_end_label(); + + return true; +} + +bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, false); + ERR_FAIL_COND_V(!rpi->rendering, false); + ERR_FAIL_COND_V(rpi->atlas.is_null(), false); + + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); + if (!atlas || rpi->atlas_index == -1) { + //does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering) + rpi->rendering = false; + return false; + } + + if (LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) { + // Using real time reflections, all roughness is done in one step + atlas->reflections.write[rpi->atlas_index].data.create_reflection_fast_filter(false); + rpi->rendering = false; + rpi->processing_side = 0; + rpi->processing_layer = 1; + return true; + } + + if (rpi->processing_layer > 1) { + atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(false, 10, rpi->processing_layer, RendererSceneRenderRD::get_singleton()->get_sky()->sky_ggx_samples_quality); + rpi->processing_layer++; + if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) { + rpi->rendering = false; + rpi->processing_side = 0; + rpi->processing_layer = 1; + return true; + } + return false; + + } else { + atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(false, rpi->processing_side, rpi->processing_layer, RendererSceneRenderRD::get_singleton()->get_sky()->sky_ggx_samples_quality); + } + + rpi->processing_side++; + if (rpi->processing_side == 6) { + rpi->processing_side = 0; + rpi->processing_layer++; + } + + return false; +} + +uint32_t LightStorage::reflection_probe_instance_get_resolution(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, 0); + + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); + ERR_FAIL_COND_V(!atlas, 0); + return atlas->size; +} + +RID LightStorage::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, RID()); + ERR_FAIL_INDEX_V(p_index, 6, RID()); + + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); + ERR_FAIL_COND_V(!atlas, RID()); + return atlas->reflections[rpi->atlas_index].fbs[p_index]; +} + +RID LightStorage::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, RID()); + ERR_FAIL_INDEX_V(p_index, 6, RID()); + + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); + ERR_FAIL_COND_V(!atlas, RID()); + return atlas->depth_fb; +} + +ClusterBuilderRD *LightStorage::reflection_probe_instance_get_cluster_builder(RID p_instance, ClusterBuilderSharedDataRD *p_cluster_builder_shared) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(rpi->atlas); + if (!ra) { + ERR_PRINT("reflection probe has no reflection atlas! Bug?"); + return nullptr; + } else { + if (ra->cluster_builder == nullptr) { + ra->cluster_builder = memnew(ClusterBuilderRD); + ra->cluster_builder->set_shared(p_cluster_builder_shared); + ra->cluster_builder->setup(Size2i(ra->size, ra->size), get_max_cluster_elements(), RID(), RID(), RID()); + } + return ra->cluster_builder; + } +} + +/* REFLECTION DATA */ + +void LightStorage::free_reflection_data() { + if (reflection_buffer.is_valid()) { + RD::get_singleton()->free(reflection_buffer); + reflection_buffer = RID(); + } + + if (reflections != nullptr) { + memdelete_arr(reflections); + reflections = nullptr; + } + + if (reflection_sort != nullptr) { + memdelete_arr(reflection_sort); + reflection_sort = nullptr; + } +} + +void LightStorage::set_max_reflection_probes(const uint32_t p_max_reflection_probes) { + max_reflections = p_max_reflection_probes; + reflections = memnew_arr(ReflectionData, max_reflections); + reflection_sort = memnew_arr(ReflectionProbeInstanceSort, max_reflections); + reflection_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ReflectionData) * max_reflections); +} + +void LightStorage::update_reflection_probe_buffer(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment) { + ForwardIDStorage *forward_id_storage = ForwardIDStorage::get_singleton(); + + reflection_count = 0; + + for (uint32_t i = 0; i < (uint32_t)p_reflections.size(); i++) { + if (reflection_count == max_reflections) { + break; + } + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_reflections[i]); + if (!rpi) { + continue; + } + + Transform3D transform = rpi->transform; + + reflection_sort[reflection_count].probe_instance = rpi; + reflection_sort[reflection_count].depth = -p_camera_inverse_transform.xform(transform.origin).z; + reflection_count++; + } + + if (reflection_count > 0) { + SortArray<ReflectionProbeInstanceSort> sort_array; + sort_array.sort(reflection_sort, reflection_count); + } + + bool using_forward_ids = forward_id_storage->uses_forward_ids(); + for (uint32_t i = 0; i < reflection_count; i++) { + ReflectionProbeInstance *rpi = reflection_sort[i].probe_instance; + + if (using_forward_ids) { + forward_id_storage->map_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id, i); + } + + ReflectionProbe *probe = reflection_probe_owner.get_or_null(rpi->probe); + + ReflectionData &reflection_ubo = reflections[i]; + + Vector3 extents = probe->extents; + + rpi->cull_mask = probe->cull_mask; + + reflection_ubo.box_extents[0] = extents.x; + reflection_ubo.box_extents[1] = extents.y; + reflection_ubo.box_extents[2] = extents.z; + reflection_ubo.index = rpi->atlas_index; + + Vector3 origin_offset = probe->origin_offset; + + reflection_ubo.box_offset[0] = origin_offset.x; + reflection_ubo.box_offset[1] = origin_offset.y; + reflection_ubo.box_offset[2] = origin_offset.z; + reflection_ubo.mask = probe->cull_mask; + + reflection_ubo.intensity = probe->intensity; + reflection_ubo.ambient_mode = probe->ambient_mode; + + reflection_ubo.exterior = !probe->interior; + reflection_ubo.box_project = probe->box_projection; + reflection_ubo.exposure_normalization = 1.0; + + if (p_render_data->camera_attributes.is_valid()) { + float exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); + reflection_ubo.exposure_normalization = exposure / probe->baked_exposure; + } + + Color ambient_linear = probe->ambient_color.srgb_to_linear(); + float interior_ambient_energy = probe->ambient_color_energy; + reflection_ubo.ambient[0] = ambient_linear.r * interior_ambient_energy; + reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy; + reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy; + + Transform3D transform = rpi->transform; + Transform3D proj = (p_camera_inverse_transform * transform).inverse(); + MaterialStorage::store_transform(proj, reflection_ubo.local_matrix); + + // hook for subclass to do further processing. + RendererSceneRenderRD::get_singleton()->setup_added_reflection_probe(transform, extents); + + rpi->last_pass = RSG::rasterizer->get_frame_number(); + } + + if (reflection_count) { + RD::get_singleton()->buffer_update(reflection_buffer, 0, reflection_count * sizeof(ReflectionData), reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + } +} + /* LIGHTMAP API */ RID LightStorage::lightmap_allocate() { @@ -649,7 +1716,7 @@ void LightStorage::lightmap_free(RID p_rid) { } void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) { - RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + TextureStorage *texture_storage = TextureStorage::get_singleton(); Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND(!lm); @@ -658,17 +1725,17 @@ void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_use //erase lightmap users if (lm->light_texture.is_valid()) { - RendererRD::TextureStorage::Texture *t = RendererRD::TextureStorage::get_singleton()->get_texture(lm->light_texture); + TextureStorage::Texture *t = texture_storage->get_singleton()->get_texture(lm->light_texture); if (t) { t->lightmap_users.erase(p_lightmap); } } - RendererRD::TextureStorage::Texture *t = RendererRD::TextureStorage::get_singleton()->get_texture(p_light); + TextureStorage::Texture *t = texture_storage->get_singleton()->get_texture(p_light); lm->light_texture = p_light; lm->uses_spherical_harmonics = p_uses_spherical_haromics; - RID default_2d_array = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + RID default_2d_array = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); if (!t) { if (using_lightmap_array) { if (lm->array_index >= 0) { @@ -830,3 +1897,550 @@ AABB LightStorage::lightmap_get_aabb(RID p_lightmap) const { ERR_FAIL_COND_V(!lm, AABB()); return lm->bounds; } + +/* LIGHTMAP INSTANCE */ + +RID LightStorage::lightmap_instance_create(RID p_lightmap) { + LightmapInstance li; + li.lightmap = p_lightmap; + return lightmap_instance_owner.make_rid(li); +} + +void LightStorage::lightmap_instance_free(RID p_lightmap) { + lightmap_instance_owner.free(p_lightmap); +} + +void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) { + LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap); + ERR_FAIL_COND(!li); + li->transform = p_transform; +} + +/* SHADOW ATLAS API */ + +RID LightStorage::shadow_atlas_create() { + return shadow_atlas_owner.make_rid(ShadowAtlas()); +} + +void LightStorage::shadow_atlas_free(RID p_atlas) { + shadow_atlas_set_size(p_atlas, 0); + shadow_atlas_owner.free(p_atlas); +} + +void LightStorage::_update_shadow_atlas(ShadowAtlas *shadow_atlas) { + if (shadow_atlas->size > 0 && shadow_atlas->depth.is_null()) { + RD::TextureFormat tf; + tf.format = shadow_atlas->use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT; + tf.width = shadow_atlas->size; + tf.height = shadow_atlas->size; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + Vector<RID> fb_tex; + fb_tex.push_back(shadow_atlas->depth); + shadow_atlas->fb = RD::get_singleton()->framebuffer_create(fb_tex); + } +} + +void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) { + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); + ERR_FAIL_COND(!shadow_atlas); + ERR_FAIL_COND(p_size < 0); + p_size = next_power_of_2(p_size); + + if (p_size == shadow_atlas->size && p_16_bits == shadow_atlas->use_16_bits) { + return; + } + + // erasing atlas + if (shadow_atlas->depth.is_valid()) { + RD::get_singleton()->free(shadow_atlas->depth); + shadow_atlas->depth = RID(); + } + for (int i = 0; i < 4; i++) { + //clear subdivisions + shadow_atlas->quadrants[i].shadows.clear(); + shadow_atlas->quadrants[i].shadows.resize(1 << shadow_atlas->quadrants[i].subdivision); + } + + //erase shadow atlas reference from lights + for (const KeyValue<RID, uint32_t> &E : shadow_atlas->shadow_owners) { + LightInstance *li = light_instance_owner.get_or_null(E.key); + ERR_CONTINUE(!li); + li->shadow_atlases.erase(p_atlas); + } + + //clear owners + shadow_atlas->shadow_owners.clear(); + + shadow_atlas->size = p_size; + shadow_atlas->use_16_bits = p_16_bits; +} + +void LightStorage::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); + ERR_FAIL_COND(!shadow_atlas); + ERR_FAIL_INDEX(p_quadrant, 4); + ERR_FAIL_INDEX(p_subdivision, 16384); + + uint32_t subdiv = next_power_of_2(p_subdivision); + if (subdiv & 0xaaaaaaaa) { //sqrt(subdiv) must be integer + subdiv <<= 1; + } + + subdiv = int(Math::sqrt((float)subdiv)); + + //obtain the number that will be x*x + + if (shadow_atlas->quadrants[p_quadrant].subdivision == subdiv) { + return; + } + + //erase all data from quadrant + for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) { + if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) { + shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); + LightInstance *li = light_instance_owner.get_or_null(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); + ERR_CONTINUE(!li); + li->shadow_atlases.erase(p_atlas); + } + } + + shadow_atlas->quadrants[p_quadrant].shadows.clear(); + shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv * subdiv); + shadow_atlas->quadrants[p_quadrant].subdivision = subdiv; + + //cache the smallest subdiv (for faster allocation in light update) + + shadow_atlas->smallest_subdiv = 1 << 30; + + for (int i = 0; i < 4; i++) { + if (shadow_atlas->quadrants[i].subdivision) { + shadow_atlas->smallest_subdiv = MIN(shadow_atlas->smallest_subdiv, shadow_atlas->quadrants[i].subdivision); + } + } + + if (shadow_atlas->smallest_subdiv == 1 << 30) { + shadow_atlas->smallest_subdiv = 0; + } + + //resort the size orders, simple bublesort for 4 elements.. + + int swaps = 0; + do { + swaps = 0; + + for (int i = 0; i < 3; i++) { + if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i + 1]].subdivision) { + SWAP(shadow_atlas->size_order[i], shadow_atlas->size_order[i + 1]); + swaps++; + } + } + } while (swaps > 0); +} + +bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) { + for (int i = p_quadrant_count - 1; i >= 0; i--) { + int qidx = p_in_quadrants[i]; + + if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) { + return false; + } + + //look for an empty space + int sc = shadow_atlas->quadrants[qidx].shadows.size(); + const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr(); + + int found_free_idx = -1; //found a free one + int found_used_idx = -1; //found existing one, must steal it + uint64_t min_pass = 0; // pass of the existing one, try to use the least recently used one (LRU fashion) + + for (int j = 0; j < sc; j++) { + if (!sarr[j].owner.is_valid()) { + found_free_idx = j; + break; + } + + LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner); + ERR_CONTINUE(!sli); + + if (sli->last_scene_pass != RendererSceneRenderRD::get_singleton()->get_scene_pass()) { + //was just allocated, don't kill it so soon, wait a bit.. + if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) { + continue; + } + + if (found_used_idx == -1 || sli->last_scene_pass < min_pass) { + found_used_idx = j; + min_pass = sli->last_scene_pass; + } + } + } + + if (found_free_idx == -1 && found_used_idx == -1) { + continue; //nothing found + } + + if (found_free_idx == -1 && found_used_idx != -1) { + found_free_idx = found_used_idx; + } + + r_quadrant = qidx; + r_shadow = found_free_idx; + + return true; + } + + return false; +} + +bool LightStorage::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) { + for (int i = p_quadrant_count - 1; i >= 0; i--) { + int qidx = p_in_quadrants[i]; + + if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) { + return false; + } + + //look for an empty space + int sc = shadow_atlas->quadrants[qidx].shadows.size(); + const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr(); + + int found_idx = -1; + uint64_t min_pass = 0; // sum of currently selected spots, try to get the least recently used pair + + for (int j = 0; j < sc - 1; j++) { + uint64_t pass = 0; + + if (sarr[j].owner.is_valid()) { + LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner); + ERR_CONTINUE(!sli); + + if (sli->last_scene_pass == RendererSceneRenderRD::get_singleton()->get_scene_pass()) { + continue; + } + + //was just allocated, don't kill it so soon, wait a bit.. + if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) { + continue; + } + pass += sli->last_scene_pass; + } + + if (sarr[j + 1].owner.is_valid()) { + LightInstance *sli = light_instance_owner.get_or_null(sarr[j + 1].owner); + ERR_CONTINUE(!sli); + + if (sli->last_scene_pass == RendererSceneRenderRD::get_singleton()->get_scene_pass()) { + continue; + } + + //was just allocated, don't kill it so soon, wait a bit.. + if (p_tick - sarr[j + 1].alloc_tick < shadow_atlas_realloc_tolerance_msec) { + continue; + } + pass += sli->last_scene_pass; + } + + if (found_idx == -1 || pass < min_pass) { + found_idx = j; + min_pass = pass; + + // we found two empty spots, no need to check the rest + if (pass == 0) { + break; + } + } + } + + if (found_idx == -1) { + continue; //nothing found + } + + r_quadrant = qidx; + r_shadow = found_idx; + + return true; + } + + return false; +} + +bool LightStorage::shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) { + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); + ERR_FAIL_COND_V(!shadow_atlas, false); + + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + ERR_FAIL_COND_V(!li, false); + + if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) { + return false; + } + + uint32_t quad_size = shadow_atlas->size >> 1; + int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage)); + + int valid_quadrants[4]; + int valid_quadrant_count = 0; + int best_size = -1; //best size found + int best_subdiv = -1; //subdiv for the best size + + //find the quadrants this fits into, and the best possible size it can fit into + for (int i = 0; i < 4; i++) { + int q = shadow_atlas->size_order[i]; + int sd = shadow_atlas->quadrants[q].subdivision; + if (sd == 0) { + continue; //unused + } + + int max_fit = quad_size / sd; + + if (best_size != -1 && max_fit > best_size) { + break; //too large + } + + valid_quadrants[valid_quadrant_count++] = q; + best_subdiv = sd; + + if (max_fit >= desired_fit) { + best_size = max_fit; + } + } + + ERR_FAIL_COND_V(valid_quadrant_count == 0, false); + + uint64_t tick = OS::get_singleton()->get_ticks_msec(); + + uint32_t old_key = SHADOW_INVALID; + uint32_t old_quadrant = SHADOW_INVALID; + uint32_t old_shadow = SHADOW_INVALID; + int old_subdivision = -1; + + bool should_realloc = false; + bool should_redraw = false; + + if (shadow_atlas->shadow_owners.has(p_light_instance)) { + old_key = shadow_atlas->shadow_owners[p_light_instance]; + old_quadrant = (old_key >> QUADRANT_SHIFT) & 0x3; + old_shadow = old_key & SHADOW_INDEX_MASK; + + should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec); + should_redraw = shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].version != p_light_version; + + if (!should_realloc) { + shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = p_light_version; + //already existing, see if it should redraw or it's just OK + return should_redraw; + } + + old_subdivision = shadow_atlas->quadrants[old_quadrant].subdivision; + } + + bool is_omni = li->light_type == RS::LIGHT_OMNI; + bool found_shadow = false; + int new_quadrant = -1; + int new_shadow = -1; + + if (is_omni) { + found_shadow = _shadow_atlas_find_omni_shadows(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow); + } else { + found_shadow = _shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow); + } + + if (found_shadow) { + if (old_quadrant != SHADOW_INVALID) { + shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = 0; + shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].owner = RID(); + + if (old_key & OMNI_LIGHT_FLAG) { + shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].version = 0; + shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].owner = RID(); + } + } + + uint32_t new_key = new_quadrant << QUADRANT_SHIFT; + new_key |= new_shadow; + + ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; + _shadow_atlas_invalidate_shadow(sh, p_atlas, shadow_atlas, new_quadrant, new_shadow); + + sh->owner = p_light_instance; + sh->alloc_tick = tick; + sh->version = p_light_version; + + if (is_omni) { + new_key |= OMNI_LIGHT_FLAG; + + int new_omni_shadow = new_shadow + 1; + ShadowAtlas::Quadrant::Shadow *extra_sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_omni_shadow]; + _shadow_atlas_invalidate_shadow(extra_sh, p_atlas, shadow_atlas, new_quadrant, new_omni_shadow); + + extra_sh->owner = p_light_instance; + extra_sh->alloc_tick = tick; + extra_sh->version = p_light_version; + } + + li->shadow_atlases.insert(p_atlas); + + //update it in map + shadow_atlas->shadow_owners[p_light_instance] = new_key; + //make it dirty, as it should redraw anyway + return true; + } + + return should_redraw; +} + +void LightStorage::_shadow_atlas_invalidate_shadow(ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx) { + if (p_shadow->owner.is_valid()) { + LightInstance *sli = light_instance_owner.get_or_null(p_shadow->owner); + uint32_t old_key = p_shadow_atlas->shadow_owners[p_shadow->owner]; + + if (old_key & OMNI_LIGHT_FLAG) { + uint32_t s = old_key & SHADOW_INDEX_MASK; + uint32_t omni_shadow_idx = p_shadow_idx + (s == (uint32_t)p_shadow_idx ? 1 : -1); + ShadowAtlas::Quadrant::Shadow *omni_shadow = &p_shadow_atlas->quadrants[p_quadrant].shadows.write[omni_shadow_idx]; + omni_shadow->version = 0; + omni_shadow->owner = RID(); + } + + p_shadow_atlas->shadow_owners.erase(p_shadow->owner); + p_shadow->version = 0; + p_shadow->owner = RID(); + sli->shadow_atlases.erase(p_atlas); + } +} + +void LightStorage::shadow_atlas_update(RID p_atlas) { + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); + ERR_FAIL_COND(!shadow_atlas); + + _update_shadow_atlas(shadow_atlas); +} + +/* DIRECTIONAL SHADOW */ + +void LightStorage::update_directional_shadow_atlas() { + if (directional_shadow.depth.is_null() && directional_shadow.size > 0) { + RD::TextureFormat tf; + tf.format = directional_shadow.use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT; + tf.width = directional_shadow.size; + tf.height = directional_shadow.size; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + Vector<RID> fb_tex; + fb_tex.push_back(directional_shadow.depth); + directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb_tex); + } +} +void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) { + p_size = nearest_power_of_2_templated(p_size); + + if (directional_shadow.size == p_size && directional_shadow.use_16_bits == p_16_bits) { + return; + } + + directional_shadow.size = p_size; + directional_shadow.use_16_bits = p_16_bits; + + if (directional_shadow.depth.is_valid()) { + RD::get_singleton()->free(directional_shadow.depth); + directional_shadow.depth = RID(); + RendererSceneRenderRD::get_singleton()->base_uniforms_changed(); + } +} + +void LightStorage::set_directional_shadow_count(int p_count) { + directional_shadow.light_count = p_count; + directional_shadow.current_light = 0; +} + +static Rect2i _get_directional_shadow_rect(int p_size, int p_shadow_count, int p_shadow_index) { + int split_h = 1; + int split_v = 1; + + while (split_h * split_v < p_shadow_count) { + if (split_h == split_v) { + split_h <<= 1; + } else { + split_v <<= 1; + } + } + + Rect2i rect(0, 0, p_size, p_size); + rect.size.width /= split_h; + rect.size.height /= split_v; + + rect.position.x = rect.size.width * (p_shadow_index % split_h); + rect.position.y = rect.size.height * (p_shadow_index / split_h); + + return rect; +} + +Rect2i LightStorage::get_directional_shadow_rect() { + return _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, directional_shadow.current_light); +} + +int LightStorage::get_directional_light_shadow_size(RID p_light_intance) { + ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0); + + Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0); + + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_intance); + ERR_FAIL_COND_V(!light_instance, 0); + + switch (light_directional_get_shadow_mode(light_instance->light)) { + case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: + break; //none + case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: + r.size.height /= 2; + break; + case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: + r.size /= 2; + break; + } + + return MAX(r.size.width, r.size.height); +} + +/* SHADOW CUBEMAPS */ + +LightStorage::ShadowCubemap *LightStorage::_get_shadow_cubemap(int p_size) { + if (!shadow_cubemaps.has(p_size)) { + ShadowCubemap sc; + { + RD::TextureFormat tf; + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; + tf.width = p_size; + tf.height = p_size; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; + tf.array_layers = 6; + tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + sc.cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + + for (int i = 0; i < 6; i++) { + RID side_texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sc.cubemap, i, 0); + Vector<RID> fbtex; + fbtex.push_back(side_texture); + sc.side_fb[i] = RD::get_singleton()->framebuffer_create(fbtex); + } + + shadow_cubemaps[p_size] = sc; + } + + return &shadow_cubemaps[p_size]; +} + +RID LightStorage::get_cubemap(int p_size) { + ShadowCubemap *cubemap = _get_shadow_cubemap(p_size); + + return cubemap->cubemap; +} + +RID LightStorage::get_cubemap_fb(int p_size, int p_pass) { + ShadowCubemap *cubemap = _get_shadow_cubemap(p_size); + + return cubemap->side_fb[p_pass]; +} diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h index 4b34cc74cb..79006ad982 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -32,17 +32,32 @@ #define LIGHT_STORAGE_RD_H #include "core/templates/local_vector.h" +#include "core/templates/paged_array.h" #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" +#include "servers/rendering/renderer_rd/cluster_builder_rd.h" +#include "servers/rendering/renderer_rd/environment/sky.h" +#include "servers/rendering/renderer_rd/storage_rd/forward_id_storage.h" #include "servers/rendering/renderer_rd/storage_rd/texture_storage.h" #include "servers/rendering/storage/light_storage.h" #include "servers/rendering/storage/utilities.h" +struct RenderDataRD; + namespace RendererRD { class LightStorage : public RendererLightStorage { +public: + enum ShadowAtlastQuadrant { + QUADRANT_SHIFT = 27, + OMNI_LIGHT_FLAG = 1 << 26, + SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1, + SHADOW_INVALID = 0xFFFFFFFF + }; + private: static LightStorage *singleton; + uint32_t max_cluster_elements = 512; /* LIGHT */ struct Light { @@ -71,6 +86,135 @@ private: mutable RID_Owner<Light, true> light_owner; + /* LIGHT INSTANCE */ + + struct LightInstance { + struct ShadowTransform { + Projection camera; + Transform3D transform; + float farplane; + float split; + float bias_scale; + float shadow_texel_size; + float range_begin; + Rect2 atlas_rect; + Vector2 uv_scale; + }; + + RS::LightType light_type = RS::LIGHT_DIRECTIONAL; + + ShadowTransform shadow_transform[6]; + + AABB aabb; + RID self; + RID light; + Transform3D transform; + + Vector3 light_vector; + Vector3 spot_vector; + float linear_att = 0.0; + + uint64_t shadow_pass = 0; + uint64_t last_scene_pass = 0; + uint64_t last_scene_shadow_pass = 0; + uint64_t last_pass = 0; + uint32_t cull_mask = 0; + uint32_t light_directional_index = 0; + + Rect2 directional_rect; + + HashSet<RID> shadow_atlases; //shadow atlases where this light is registered + + ForwardID forward_id = -1; + + LightInstance() {} + }; + + mutable RID_Owner<LightInstance> light_instance_owner; + + /* OMNI/SPOT LIGHT DATA */ + + struct LightData { + float position[3]; + float inv_radius; + float direction[3]; // in omni, x and y are used for dual paraboloid offset + float size; + + float color[3]; + float attenuation; + + float inv_spot_attenuation; + float cos_spot_angle; + float specular_amount; + float shadow_opacity; + + float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv + float shadow_matrix[16]; + float shadow_bias; + float shadow_normal_bias; + float transmittance_bias; + float soft_shadow_size; + float soft_shadow_scale; + uint32_t mask; + float volumetric_fog_energy; + uint32_t bake_mode; + float projector_rect[4]; + }; + + struct LightInstanceDepthSort { + float depth; + LightInstance *light_instance; + Light *light; + bool operator<(const LightInstanceDepthSort &p_sort) const { + return depth < p_sort.depth; + } + }; + + uint32_t max_lights; + uint32_t omni_light_count = 0; + uint32_t spot_light_count = 0; + LightData *omni_lights = nullptr; + LightData *spot_lights = nullptr; + LightInstanceDepthSort *omni_light_sort = nullptr; + LightInstanceDepthSort *spot_light_sort = nullptr; + RID omni_light_buffer; + RID spot_light_buffer; + + /* DIRECTIONAL LIGHT DATA */ + + struct DirectionalLightData { + float direction[3]; + float energy; + float color[3]; + float size; + float specular; + uint32_t mask; + float softshadow_angle; + float soft_shadow_scale; + uint32_t blend_splits; + float shadow_opacity; + float fade_from; + float fade_to; + uint32_t pad[2]; + uint32_t bake_mode; + float volumetric_fog_energy; + float shadow_bias[4]; + float shadow_normal_bias[4]; + float shadow_transmittance_bias[4]; + float shadow_z_range[4]; + float shadow_range_begin[4]; + float shadow_split_offsets[4]; + float shadow_matrices[4][16]; + float uv_scale1[2]; + float uv_scale2[2]; + float uv_scale3[2]; + float uv_scale4[2]; + }; + + uint32_t max_directional_lights; + DirectionalLightData *directional_lights = nullptr; + RID directional_light_buffer; + /* REFLECTION PROBE */ struct ReflectionProbe { @@ -94,6 +238,89 @@ private: }; mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner; + /* REFLECTION ATLAS */ + + struct ReflectionAtlas { + int count = 0; + int size = 0; + + RID reflection; + RID depth_buffer; + RID depth_fb; + + struct Reflection { + RID owner; + RendererRD::SkyRD::ReflectionData data; + RID fbs[6]; + }; + + Vector<Reflection> reflections; + + ClusterBuilderRD *cluster_builder = nullptr; // only used if cluster builder is supported by the renderer. + }; + + mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner; + + /* REFLECTION PROBE INSTANCE */ + + struct ReflectionProbeInstance { + RID probe; + int atlas_index = -1; + RID atlas; + + bool dirty = true; + bool rendering = false; + int processing_layer = 1; + int processing_side = 0; + + uint32_t render_step = 0; + uint64_t last_pass = 0; + uint32_t cull_mask = 0; + + RendererRD::ForwardID forward_id = -1; + + Transform3D transform; + }; + + mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner; + + /* REFLECTION DATA */ + + enum { + REFLECTION_AMBIENT_DISABLED = 0, + REFLECTION_AMBIENT_ENVIRONMENT = 1, + REFLECTION_AMBIENT_COLOR = 2, + }; + + struct ReflectionData { + float box_extents[3]; + float index; + float box_offset[3]; + uint32_t mask; + float ambient[3]; // ambient color, + float intensity; + uint32_t exterior; + uint32_t box_project; + uint32_t ambient_mode; + float exposure_normalization; + float local_matrix[16]; // up to here for spot and omni, rest is for directional + }; + + struct ReflectionProbeInstanceSort { + float depth; + ReflectionProbeInstance *probe_instance; + bool operator<(const ReflectionProbeInstanceSort &p_sort) const { + return depth < p_sort.depth; + } + }; + + uint32_t max_reflections; + uint32_t reflection_count = 0; + // uint32_t max_reflection_probes_per_instance = 0; // seems unused + ReflectionData *reflections = nullptr; + ReflectionProbeInstanceSort *reflection_sort = nullptr; + RID reflection_buffer; + /* LIGHTMAP */ struct Lightmap { @@ -124,12 +351,101 @@ private: mutable RID_Owner<Lightmap, true> lightmap_owner; + /* LIGHTMAP INSTANCE */ + + struct LightmapInstance { + RID lightmap; + Transform3D transform; + }; + + mutable RID_Owner<LightmapInstance> lightmap_instance_owner; + + /* SHADOW ATLAS */ + + uint64_t shadow_atlas_realloc_tolerance_msec = 500; + + struct ShadowShrinkStage { + RID texture; + RID filter_texture; + uint32_t size = 0; + }; + + struct ShadowAtlas { + struct Quadrant { + uint32_t subdivision = 0; + + struct Shadow { + RID owner; + uint64_t version = 0; + uint64_t fog_version = 0; // used for fog + uint64_t alloc_tick = 0; + + Shadow() {} + }; + + Vector<Shadow> shadows; + + Quadrant() {} + } quadrants[4]; + + int size_order[4] = { 0, 1, 2, 3 }; + uint32_t smallest_subdiv = 0; + + int size = 0; + bool use_16_bits = true; + + RID depth; + RID fb; //for copying + + HashMap<RID, uint32_t> shadow_owners; + }; + + RID_Owner<ShadowAtlas> shadow_atlas_owner; + + void _update_shadow_atlas(ShadowAtlas *shadow_atlas); + + void _shadow_atlas_invalidate_shadow(ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx); + bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); + bool _shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); + + /* DIRECTIONAL SHADOW */ + + struct DirectionalShadow { + RID depth; + RID fb; //when renderign direct + + int light_count = 0; + int size = 0; + bool use_16_bits = true; + int current_light = 0; + } directional_shadow; + + /* SHADOW CUBEMAPS */ + + struct ShadowCubemap { + RID cubemap; + RID side_fb[6]; + }; + + HashMap<int, ShadowCubemap> shadow_cubemaps; + ShadowCubemap *_get_shadow_cubemap(int p_size); + public: static LightStorage *get_singleton(); LightStorage(); virtual ~LightStorage(); + bool free(RID p_rid); + + /* Settings */ + void set_max_cluster_elements(const uint32_t p_max_cluster_elements) { + max_cluster_elements = p_max_cluster_elements; + set_max_reflection_probes(p_max_cluster_elements); + set_max_lights(p_max_cluster_elements); + } + uint32_t get_max_cluster_elements() const { return max_cluster_elements; } + /* LIGHT */ bool owns_light(RID p_rid) { return light_owner.owns(p_rid); }; @@ -259,6 +575,205 @@ public: Dependency *light_get_dependency(RID p_light) const; + /* LIGHT INSTANCE API */ + + bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); }; + + virtual RID light_instance_create(RID p_light) override; + virtual void light_instance_free(RID p_light) override; + virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override; + virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override; + virtual void light_instance_mark_visible(RID p_light_instance) override; + + _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->light; + } + + _FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->transform; + } + + _FORCE_INLINE_ AABB light_instance_get_base_aabb(RID p_light_instance) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->aabb; + } + + _FORCE_INLINE_ void light_instance_set_cull_mask(RID p_light_instance, uint32_t p_cull_mask) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + li->cull_mask = p_cull_mask; + } + + _FORCE_INLINE_ uint32_t light_instance_get_cull_mask(RID p_light_instance) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->cull_mask; + } + + _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas, Vector2i &r_omni_offset) { + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + uint32_t key = shadow_atlas->shadow_owners[li->self]; + + uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3; + uint32_t shadow = key & SHADOW_INDEX_MASK; + + ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), Rect2()); + + uint32_t atlas_size = shadow_atlas->size; + uint32_t quadrant_size = atlas_size >> 1; + + uint32_t x = (quadrant & 1) * quadrant_size; + uint32_t y = (quadrant >> 1) * quadrant_size; + + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + + if (key & OMNI_LIGHT_FLAG) { + if (((shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision) == 0) { + r_omni_offset.x = 1 - int(shadow_atlas->quadrants[quadrant].subdivision); + r_omni_offset.y = 1; + } else { + r_omni_offset.x = 1; + r_omni_offset.y = 0; + } + } + + uint32_t width = shadow_size; + uint32_t height = shadow_size; + + return Rect2(x / float(shadow_atlas->size), y / float(shadow_atlas->size), width / float(shadow_atlas->size), height / float(shadow_atlas->size)); + } + + _FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) { +#ifdef DEBUG_ENABLED + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0); +#endif + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); + ERR_FAIL_COND_V(!shadow_atlas, 0); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0); +#endif + uint32_t key = shadow_atlas->shadow_owners[p_light_instance]; + + uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3; + + uint32_t quadrant_size = shadow_atlas->size >> 1; + + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + + return float(1.0) / shadow_size; + } + + _FORCE_INLINE_ Projection light_instance_get_shadow_camera(RID p_light_instance, int p_index) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->shadow_transform[p_index].camera; + } + + _FORCE_INLINE_ Transform3D + light_instance_get_shadow_transform(RID p_light_instance, int p_index) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->shadow_transform[p_index].transform; + } + _FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->shadow_transform[p_index].bias_scale; + } + _FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->shadow_transform[p_index].farplane; + } + _FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->shadow_transform[p_index].range_begin; + } + + _FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->shadow_transform[p_index].uv_scale; + } + + _FORCE_INLINE_ void light_instance_set_directional_shadow_atlas_rect(RID p_light_instance, int p_index, const Rect2 p_atlas_rect) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + li->shadow_transform[p_index].atlas_rect = p_atlas_rect; + } + + _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->shadow_transform[p_index].atlas_rect; + } + + _FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->shadow_transform[p_index].split; + } + + _FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->shadow_transform[p_index].shadow_texel_size; + } + + _FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + li->last_pass = p_pass; + } + + _FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->last_pass; + } + + _FORCE_INLINE_ void light_instance_set_shadow_pass(RID p_light_instance, uint64_t p_pass) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + li->last_scene_shadow_pass = p_pass; + } + + _FORCE_INLINE_ uint64_t light_instance_get_shadow_pass(RID p_light_instance) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->last_scene_shadow_pass; + } + + _FORCE_INLINE_ ForwardID light_instance_get_forward_id(RID p_light_instance) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->forward_id; + } + + _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->light_type; + } + + _FORCE_INLINE_ void light_instance_set_directional_rect(RID p_light_instance, const Rect2 &p_directional_rect) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + li->directional_rect = p_directional_rect; + } + + _FORCE_INLINE_ Rect2 light_instance_get_directional_rect(RID p_light_instance) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->directional_rect; + } + + /* LIGHT DATA */ + + void free_light_data(); + void set_max_lights(const uint32_t p_max_lights); + RID get_omni_light_buffer() { return omni_light_buffer; } + RID get_spot_light_buffer() { return spot_light_buffer; } + RID get_directional_light_buffer() { return directional_light_buffer; } + uint32_t get_max_directional_lights() { return max_directional_lights; } + bool has_directional_shadows(const uint32_t p_directional_light_count) { + for (uint32_t i = 0; i < p_directional_light_count; i++) { + if (directional_lights[i].shadow_opacity > 0.001) { + return true; + } + } + return false; + } + void update_light_buffers(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows); + /* REFLECTION PROBE */ bool owns_reflection_probe(RID p_rid) { return reflection_probe_owner.owns(p_rid); }; @@ -305,6 +820,94 @@ public: Dependency *reflection_probe_get_dependency(RID p_probe) const; + /* REFLECTION ATLAS */ + + bool owns_reflection_atlas(RID p_rid) { return reflection_atlas_owner.owns(p_rid); } + + virtual RID reflection_atlas_create() override; + virtual void reflection_atlas_free(RID p_ref_atlas) override; + virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override; + virtual int reflection_atlas_get_size(RID p_ref_atlas) const override; + + _FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) { + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_ref_atlas); + ERR_FAIL_COND_V(!atlas, RID()); + return atlas->reflection; + } + + /* REFLECTION PROBE INSTANCE */ + + bool owns_reflection_probe_instance(RID p_rid) { return reflection_probe_instance_owner.owns(p_rid); } + + virtual RID reflection_probe_instance_create(RID p_probe) override; + virtual void reflection_probe_instance_free(RID p_instance) override; + virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override; + virtual void reflection_probe_release_atlas_index(RID p_instance) override; + virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override; + virtual bool reflection_probe_instance_has_reflection(RID p_instance) override; + virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override; + virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override; + + uint32_t reflection_probe_instance_get_resolution(RID p_instance); + RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index); + RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index); + + _FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, RID()); + + return rpi->probe; + } + + _FORCE_INLINE_ RendererRD::ForwardID reflection_probe_instance_get_forward_id(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, 0); + + return rpi->forward_id; + } + + _FORCE_INLINE_ void reflection_probe_instance_set_cull_mask(RID p_instance, uint32_t p_render_pass) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND(!rpi); + rpi->cull_mask = p_render_pass; + } + + _FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND(!rpi); + rpi->last_pass = p_render_pass; + } + + _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, 0); + + return rpi->last_pass; + } + + _FORCE_INLINE_ Transform3D reflection_probe_instance_get_transform(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, Transform3D()); + + return rpi->transform; + } + + _FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_COND_V(!rpi, -1); + + return rpi->atlas_index; + } + + ClusterBuilderRD *reflection_probe_instance_get_cluster_builder(RID p_instance, ClusterBuilderSharedDataRD *p_cluster_builder_shared); + + /* REFLECTION DATA */ + + void free_reflection_data(); + void set_max_reflection_probes(const uint32_t p_max_reflection_probes); + RID get_reflection_probe_buffer() { return reflection_buffer; } + void update_reflection_probe_buffer(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment); + /* LIGHTMAP */ bool owns_lightmap(RID p_rid) { return lightmap_owner.owns(p_rid); }; @@ -366,6 +969,111 @@ public: ERR_FAIL_COND_V(!using_lightmap_array, lightmap_textures); //only for arrays return lightmap_textures; } + + /* LIGHTMAP INSTANCE */ + + bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); }; + + virtual RID lightmap_instance_create(RID p_lightmap) override; + virtual void lightmap_instance_free(RID p_lightmap) override; + virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override; + _FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) { + return lightmap_instance_owner.get_or_null(p_lightmap_instance) != nullptr; + } + + _FORCE_INLINE_ RID lightmap_instance_get_lightmap(RID p_lightmap_instance) { + LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance); + return li->lightmap; + } + _FORCE_INLINE_ Transform3D lightmap_instance_get_transform(RID p_lightmap_instance) { + LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance); + return li->transform; + } + + /* SHADOW ATLAS API */ + + bool owns_shadow_atlas(RID p_rid) { return shadow_atlas_owner.owns(p_rid); }; + + virtual RID shadow_atlas_create() override; + virtual void shadow_atlas_free(RID p_atlas) override; + + virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override; + virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override; + virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override; + _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) { + ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); + ERR_FAIL_COND_V(!atlas, false); + return atlas->shadow_owners.has(p_light_intance); + } + _FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_intance) { + ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); + ERR_FAIL_COND_V(!atlas, -1); + return atlas->shadow_owners[p_light_intance]; + } + + _FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) { + ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); + ERR_FAIL_COND_V(!atlas, RID()); + return atlas->depth; + } + + _FORCE_INLINE_ int shadow_atlas_get_size(RID p_atlas) { + ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); + ERR_FAIL_COND_V(!atlas, 0); + return atlas->size; + } + + _FORCE_INLINE_ int shadow_atlas_get_quadrant_shadow_size(RID p_atlas, uint32_t p_quadrant) { + ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); + ERR_FAIL_COND_V(!atlas, 0); + ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0); + return atlas->quadrants[p_quadrant].shadows.size(); + } + + _FORCE_INLINE_ uint32_t shadow_atlas_get_quadrant_subdivision(RID p_atlas, uint32_t p_quadrant) { + ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); + ERR_FAIL_COND_V(!atlas, 0); + ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0); + return atlas->quadrants[p_quadrant].subdivision; + } + + _FORCE_INLINE_ RID shadow_atlas_get_fb(RID p_atlas) { + ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); + ERR_FAIL_COND_V(!atlas, RID()); + return atlas->fb; + } + + virtual void shadow_atlas_update(RID p_atlas) override; + + /* DIRECTIONAL SHADOW */ + + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override; + virtual int get_directional_light_shadow_size(RID p_light_intance) override; + virtual void set_directional_shadow_count(int p_count) override; + + Rect2i get_directional_shadow_rect(); + void update_directional_shadow_atlas(); + + _FORCE_INLINE_ RID directional_shadow_get_texture() { + return directional_shadow.depth; + } + + _FORCE_INLINE_ int directional_shadow_get_size() { + return directional_shadow.size; + } + + _FORCE_INLINE_ RID direction_shadow_get_fb() { + return directional_shadow.fb; + } + + _FORCE_INLINE_ void directional_shadow_increase_current_light() { + directional_shadow.current_light++; + } + + /* SHADOW CUBEMAPS */ + + RID get_cubemap(int p_size); + RID get_cubemap_fb(int p_size, int p_pass); }; } // namespace RendererRD diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index 70243a9275..36f1bc0316 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -1528,6 +1528,18 @@ MaterialStorage::~MaterialStorage() { singleton = nullptr; } +bool MaterialStorage::free(RID p_rid) { + if (owns_shader(p_rid)) { + shader_free(p_rid); + return true; + } else if (owns_material(p_rid)) { + material_free(p_rid); + return true; + } + + return false; +} + /* Samplers */ void MaterialStorage::sampler_rd_configure_custom(float p_mipmap_bias) { diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h index 2ce6550cc1..d496eed17a 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h @@ -231,6 +231,8 @@ public: MaterialStorage(); virtual ~MaterialStorage(); + bool free(RID p_rid); + /* Helpers */ static _FORCE_INLINE_ void store_transform(const Transform3D &p_mtx, float *p_array) { diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index b089b96101..1e74d31383 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -197,6 +197,24 @@ MeshStorage::~MeshStorage() { singleton = nullptr; } +bool MeshStorage::free(RID p_rid) { + if (owns_mesh(p_rid)) { + mesh_free(p_rid); + return true; + } else if (owns_mesh_instance(p_rid)) { + mesh_instance_free(p_rid); + return true; + } else if (owns_multimesh(p_rid)) { + multimesh_free(p_rid); + return true; + } else if (owns_skeleton(p_rid)) { + skeleton_free(p_rid); + return true; + } + + return false; +} + /* MESH API */ RID MeshStorage::mesh_allocate() { diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h index 622f3911c7..c8a33bd4d7 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h @@ -308,6 +308,8 @@ public: MeshStorage(); virtual ~MeshStorage(); + bool free(RID p_rid); + RID get_default_rd_storage_buffer() const { return default_rd_storage_buffer; } /* MESH API */ diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index 4dca2233fe..18303ce870 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -208,6 +208,21 @@ ParticlesStorage::~ParticlesStorage() { singleton = nullptr; } +bool ParticlesStorage::free(RID p_rid) { + if (owns_particles(p_rid)) { + particles_free(p_rid); + return true; + } else if (owns_particles_collision(p_rid)) { + particles_collision_free(p_rid); + return true; + } else if (owns_particles_collision_instance(p_rid)) { + particles_collision_instance_free(p_rid); + return true; + } + + return false; +} + /* PARTICLES */ RID ParticlesStorage::particles_allocate() { diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h index af29f5022b..017844626f 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h @@ -405,6 +405,8 @@ public: ParticlesStorage(); virtual ~ParticlesStorage(); + bool free(RID p_rid); + /* PARTICLES */ bool owns_particles(RID p_rid) { return particles_owner.owns(p_rid); } diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp index 16fdbc07f5..0c2092f03e 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp @@ -40,11 +40,6 @@ RenderSceneBuffersRD::~RenderSceneBuffersRD() { cleanup(); data_buffers.clear(); - - // need to investigate if we can remove these things. - if (cluster_builder) { - memdelete(cluster_builder); - } } void RenderSceneBuffersRD::_bind_methods() { @@ -121,21 +116,6 @@ void RenderSceneBuffersRD::cleanup() { RD::get_singleton()->free(luminance.current); luminance.current = RID(); } - - if (ss_effects.linear_depth.is_valid()) { - RD::get_singleton()->free(ss_effects.linear_depth); - ss_effects.linear_depth = RID(); - ss_effects.linear_depth_slices.clear(); - } - - if (ss_effects.downsample_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(ss_effects.downsample_uniform_set)) { - RD::get_singleton()->free(ss_effects.downsample_uniform_set); - ss_effects.downsample_uniform_set = RID(); - } - - sse->ssao_free(ss_effects.ssao); - sse->ssil_free(ss_effects.ssil); - sse->ssr_free(ssr); } void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { @@ -179,14 +159,6 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna use_debanding = p_use_debanding; view_count = p_view_count; - /* may move this into our clustered renderer data object */ - if (can_be_storage) { - if (cluster_builder == nullptr) { - cluster_builder = memnew(ClusterBuilderRD); - } - cluster_builder->set_shared(RendererSceneRenderRD::get_singleton()->get_cluster_builder_shared()); - } - // cleanout any old buffers we had. cleanup(); @@ -206,7 +178,7 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna // Create our depth buffer { - // TODO If we have depth buffer supplied externally, pick this up + // TODO Lazy create this in case we've got an external depth buffer RD::DataFormat format; uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; @@ -233,11 +205,6 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna for (KeyValue<StringName, Ref<RenderBufferCustomDataRD>> &E : data_buffers) { E.value->configure(this); } - - if (cluster_builder) { - RID sampler = RendererRD::MaterialStorage::get_singleton()->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - cluster_builder->setup(internal_size, max_cluster_elements, get_depth_texture(), sampler, get_internal_texture()); - } } void RenderSceneBuffersRD::set_fsr_sharpness(float p_fsr_sharpness) { @@ -523,6 +490,28 @@ Ref<RenderBufferCustomDataRD> RenderSceneBuffersRD::get_custom_data(const String return ret; } +// Depth texture + +RID RenderSceneBuffersRD::get_depth_texture() { + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + RID depth = texture_storage->render_target_get_override_depth(render_target); + if (depth.is_valid()) { + return depth; + } else { + return get_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH); + } +} + +RID RenderSceneBuffersRD::get_depth_texture(const uint32_t p_layer) { + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + RID depth_slice = texture_storage->render_target_get_override_depth_slice(render_target, p_layer); + if (depth_slice.is_valid()) { + return depth_slice; + } else { + return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, p_layer, 0); + } +} + // Velocity texture. void RenderSceneBuffersRD::ensure_velocity() { @@ -549,6 +538,20 @@ void RenderSceneBuffersRD::ensure_velocity() { } } +bool RenderSceneBuffersRD::has_velocity_buffer(bool p_has_msaa) { + if (p_has_msaa) { + return has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA); + } else { + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + RID velocity = texture_storage->render_target_get_override_velocity(render_target); + if (velocity.is_valid()) { + return true; + } else { + return has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY); + } + } +} + RID RenderSceneBuffersRD::get_velocity_buffer(bool p_get_msaa) { if (p_get_msaa) { if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA)) { @@ -557,10 +560,28 @@ RID RenderSceneBuffersRD::get_velocity_buffer(bool p_get_msaa) { return get_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA); } } else { - if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY)) { + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + RID velocity = texture_storage->render_target_get_override_velocity(render_target); + if (velocity.is_valid()) { + return velocity; + } else if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY)) { return RID(); } else { return get_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY); } } } + +RID RenderSceneBuffersRD::get_velocity_buffer(bool p_get_msaa, uint32_t p_layer) { + if (p_get_msaa) { + return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA, p_layer, 0); + } else { + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + RID velocity_slice = texture_storage->render_target_get_override_velocity_slice(render_target, p_layer); + if (velocity_slice.is_valid()) { + return velocity_slice; + } else { + return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY, p_layer, 0); + } + } +} diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h index 1975eec7b0..6907f69b93 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h @@ -31,19 +31,14 @@ #ifndef RENDER_SCENE_BUFFERS_RD_H #define RENDER_SCENE_BUFFERS_RD_H +#include "../effects/vrs.h" +#include "../framebuffer_cache_rd.h" #include "core/templates/hash_map.h" -#include "servers/rendering/renderer_rd/effects/vrs.h" -#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h" -#include "servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h" +#include "render_buffer_custom_data_rd.h" #include "servers/rendering/rendering_device.h" #include "servers/rendering/rendering_method.h" #include "servers/rendering/storage/render_scene_buffers.h" -// These can be retired in due time -#include "servers/rendering/renderer_rd/cluster_builder_rd.h" -#include "servers/rendering/renderer_rd/effects/ss_effects.h" -#include "servers/rendering/renderer_rd/environment/fog.h" - #define RB_SCOPE_BUFFERS SNAME("render_buffers") #define RB_SCOPE_VRS SNAME("VRS") @@ -68,7 +63,6 @@ private: bool can_be_storage = true; uint32_t max_cluster_elements = 512; RD::DataFormat base_data_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - RendererRD::SSEffects *sse = nullptr; RendererRD::VRS *vrs = nullptr; uint64_t auto_exposure_version = 1; @@ -139,9 +133,9 @@ public: // info from our renderer void set_can_be_storage(const bool p_can_be_storage) { can_be_storage = p_can_be_storage; } void set_max_cluster_elements(const uint32_t p_max_elements) { max_cluster_elements = p_max_elements; } + uint32_t get_max_cluster_elements() { return max_cluster_elements; } void set_base_data_format(const RD::DataFormat p_base_data_format) { base_data_format = p_base_data_format; } RD::DataFormat get_base_data_format() const { return base_data_format; } - void set_sseffects(RendererRD::SSEffects *p_ss_effects) { sse = p_ss_effects; } void set_vrs(RendererRD::VRS *p_vrs) { vrs = p_vrs; } void cleanup(); @@ -195,12 +189,8 @@ public: return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_COLOR, p_layer, 0); } - _FORCE_INLINE_ RID get_depth_texture() const { - return get_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH); - } - _FORCE_INLINE_ RID get_depth_texture(const uint32_t p_layer) { - return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, p_layer, 0); - } + RID get_depth_texture(); + RID get_depth_texture(const uint32_t p_layer); // back buffer (color) RID get_back_buffer_texture() const { return has_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) ? get_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) : RID(); } // We (re)use our blur texture here. @@ -208,15 +198,13 @@ public: // Velocity, currently only used by TAA (Clustered) but we'll be using this in other places soon too. void ensure_velocity(); - bool has_velocity_buffer(bool p_has_msaa) { return has_texture(RB_SCOPE_BUFFERS, p_has_msaa ? RB_TEX_VELOCITY_MSAA : RB_TEX_VELOCITY); } + bool has_velocity_buffer(bool p_has_msaa); RID get_velocity_buffer(bool p_get_msaa); - RID get_velocity_buffer(bool p_get_msaa, uint32_t p_layer) { return get_texture_slice(RB_SCOPE_BUFFERS, p_get_msaa ? RB_TEX_VELOCITY_MSAA : RB_TEX_VELOCITY, p_layer, 0); } + RID get_velocity_buffer(bool p_get_msaa, uint32_t p_layer); //////////////////////////////////////////////////////////////////////////////////////////////////////////// // Everything after this needs to be re-evaluated, this is all old implementation - ClusterBuilderRD *cluster_builder = nullptr; - struct WeightBuffers { RID weight; RID fb; // FB with both texture and weight writing into one level lower @@ -233,24 +221,6 @@ public: Vector<RID> fb; RID current_fb; } luminance; - - struct SSEffects { - RID linear_depth; - Vector<RID> linear_depth_slices; - - RID downsample_uniform_set; - - Projection last_frame_projection; - Transform3D last_frame_transform; - - RendererRD::SSEffects::SSAORenderBuffers ssao; - RendererRD::SSEffects::SSILRenderBuffers ssil; - } ss_effects; - - RendererRD::SSEffects::SSRRenderBuffers ssr; - - RID get_ao_texture() const { return ss_effects.ssao.ao_final; } - RID get_ssil_texture() const { return ss_effects.ssil.ssil_final; } }; #endif // RENDER_SCENE_BUFFERS_RD_H diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 21811068cd..b3a7e05ff5 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -30,7 +30,9 @@ #include "texture_storage.h" #include "../effects/copy_effects.h" +#include "../framebuffer_cache_rd.h" #include "material_storage.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" using namespace RendererRD; @@ -457,6 +459,8 @@ TextureStorage::TextureStorage() { TextureStorage::~TextureStorage() { rt_sdf.shader.version_free(rt_sdf.shader_version); + free_decal_data(); + if (decal_atlas.textures.size()) { ERR_PRINT("Decal Atlas: " + itos(decal_atlas.textures.size()) + " textures were not removed from the atlas."); } @@ -475,6 +479,27 @@ TextureStorage::~TextureStorage() { singleton = nullptr; } +bool TextureStorage::free(RID p_rid) { + if (owns_texture(p_rid)) { + texture_free(p_rid); + return true; + } else if (owns_canvas_texture(p_rid)) { + canvas_texture_free(p_rid); + return true; + } else if (owns_decal(p_rid)) { + decal_free(p_rid); + return true; + } else if (owns_decal_instance(p_rid)) { + decal_instance_free(p_rid); + return true; + } else if (owns_render_target(p_rid)) { + render_target_free(p_rid); + return true; + } + + return false; +} + bool TextureStorage::can_create_resources_async() const { return true; } @@ -1888,7 +1913,7 @@ Dependency *TextureStorage::decal_get_dependency(RID p_decal) { } void TextureStorage::update_decal_atlas() { - RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); + CopyEffects *copy_effects = CopyEffects::get_singleton(); ERR_FAIL_NULL(copy_effects); if (!decal_atlas.dirty) { @@ -2112,12 +2137,249 @@ void TextureStorage::texture_remove_from_decal_atlas(RID p_texture, bool p_panor } } +/* DECAL INSTANCE API */ + +RID TextureStorage::decal_instance_create(RID p_decal) { + DecalInstance di; + di.decal = p_decal; + di.forward_id = ForwardIDStorage::get_singleton()->allocate_forward_id(FORWARD_ID_TYPE_DECAL); + return decal_instance_owner.make_rid(di); +} + +void TextureStorage::decal_instance_free(RID p_decal_instance) { + DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance); + ForwardIDStorage::get_singleton()->free_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id); + decal_instance_owner.free(p_decal_instance); +} + +void TextureStorage::decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) { + DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance); + ERR_FAIL_COND(!di); + di->transform = p_transform; +} + +/* DECAL DATA API */ + +void TextureStorage::free_decal_data() { + if (decal_buffer.is_valid()) { + RD::get_singleton()->free(decal_buffer); + decal_buffer = RID(); + } + + if (decals != nullptr) { + memdelete_arr(decals); + decals = nullptr; + } + + if (decal_sort != nullptr) { + memdelete_arr(decal_sort); + decal_sort = nullptr; + } +} + +void TextureStorage::set_max_decals(const uint32_t p_max_decals) { + max_decals = p_max_decals; + uint32_t decal_buffer_size = max_decals * sizeof(DecalData); + decals = memnew_arr(DecalData, max_decals); + decal_sort = memnew_arr(DecalInstanceSort, max_decals); + decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size); +} + +void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform) { + ForwardIDStorage *forward_id_storage = ForwardIDStorage::get_singleton(); + + Transform3D uv_xform; + uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0)); + uv_xform.origin = Vector3(-1.0, 0.0, -1.0); + + uint32_t decals_size = p_decals.size(); + + decal_count = 0; + + for (uint32_t i = 0; i < decals_size; i++) { + if (decal_count == max_decals) { + break; + } + + DecalInstance *decal_instance = decal_instance_owner.get_or_null(p_decals[i]); + if (!decal_instance) { + continue; + } + Decal *decal = decal_owner.get_or_null(decal_instance->decal); + + Transform3D xform = decal_instance->transform; + + real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; + + if (decal->distance_fade) { + float fade_begin = decal->distance_fade_begin; + float fade_length = decal->distance_fade_length; + + if (distance > fade_begin) { + if (distance > fade_begin + fade_length) { + continue; // do not use this decal, its invisible + } + } + } + + decal_sort[decal_count].decal_instance = decal_instance; + decal_sort[decal_count].decal = decal; + decal_sort[decal_count].depth = distance; + decal_count++; + } + + if (decal_count > 0) { + SortArray<DecalInstanceSort> sort_array; + sort_array.sort(decal_sort, decal_count); + } + + bool using_forward_ids = forward_id_storage->uses_forward_ids(); + for (uint32_t i = 0; i < decal_count; i++) { + DecalInstance *decal_instance = decal_sort[i].decal_instance; + Decal *decal = decal_sort[i].decal; + + if (using_forward_ids) { + forward_id_storage->map_forward_id(FORWARD_ID_TYPE_DECAL, decal_instance->forward_id, i); + } + + decal_instance->cull_mask = decal->cull_mask; + + Transform3D xform = decal_instance->transform; + float fade = 1.0; + + if (decal->distance_fade) { + const real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; + const float fade_begin = decal->distance_fade_begin; + const float fade_length = decal->distance_fade_length; + + if (distance > fade_begin) { + // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. + fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length); + } + } + + DecalData &dd = decals[i]; + + Vector3 decal_extents = decal->extents; + + Transform3D scale_xform; + scale_xform.basis.scale(decal_extents); + Transform3D to_decal_xform = (p_camera_inverse_xform * xform * scale_xform * uv_xform).affine_inverse(); + MaterialStorage::store_transform(to_decal_xform, dd.xform); + + Vector3 normal = xform.basis.get_column(Vector3::AXIS_Y).normalized(); + normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine + + dd.normal[0] = normal.x; + dd.normal[1] = normal.y; + dd.normal[2] = normal.z; + dd.normal_fade = decal->normal_fade; + + RID albedo_tex = decal->textures[RS::DECAL_TEXTURE_ALBEDO]; + RID emission_tex = decal->textures[RS::DECAL_TEXTURE_EMISSION]; + if (albedo_tex.is_valid()) { + Rect2 rect = decal_atlas_get_texture_rect(albedo_tex); + dd.albedo_rect[0] = rect.position.x; + dd.albedo_rect[1] = rect.position.y; + dd.albedo_rect[2] = rect.size.x; + dd.albedo_rect[3] = rect.size.y; + } else { + if (!emission_tex.is_valid()) { + continue; //no albedo, no emission, no decal. + } + dd.albedo_rect[0] = 0; + dd.albedo_rect[1] = 0; + dd.albedo_rect[2] = 0; + dd.albedo_rect[3] = 0; + } + + RID normal_tex = decal->textures[RS::DECAL_TEXTURE_NORMAL]; + + if (normal_tex.is_valid()) { + Rect2 rect = decal_atlas_get_texture_rect(normal_tex); + dd.normal_rect[0] = rect.position.x; + dd.normal_rect[1] = rect.position.y; + dd.normal_rect[2] = rect.size.x; + dd.normal_rect[3] = rect.size.y; + + Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized(); + MaterialStorage::store_basis_3x4(normal_xform, dd.normal_xform); + } else { + dd.normal_rect[0] = 0; + dd.normal_rect[1] = 0; + dd.normal_rect[2] = 0; + dd.normal_rect[3] = 0; + } + + RID orm_tex = decal->textures[RS::DECAL_TEXTURE_ORM]; + if (orm_tex.is_valid()) { + Rect2 rect = decal_atlas_get_texture_rect(orm_tex); + dd.orm_rect[0] = rect.position.x; + dd.orm_rect[1] = rect.position.y; + dd.orm_rect[2] = rect.size.x; + dd.orm_rect[3] = rect.size.y; + } else { + dd.orm_rect[0] = 0; + dd.orm_rect[1] = 0; + dd.orm_rect[2] = 0; + dd.orm_rect[3] = 0; + } + + if (emission_tex.is_valid()) { + Rect2 rect = decal_atlas_get_texture_rect(emission_tex); + dd.emission_rect[0] = rect.position.x; + dd.emission_rect[1] = rect.position.y; + dd.emission_rect[2] = rect.size.x; + dd.emission_rect[3] = rect.size.y; + } else { + dd.emission_rect[0] = 0; + dd.emission_rect[1] = 0; + dd.emission_rect[2] = 0; + dd.emission_rect[3] = 0; + } + + Color modulate = decal->modulate; + dd.modulate[0] = modulate.r; + dd.modulate[1] = modulate.g; + dd.modulate[2] = modulate.b; + dd.modulate[3] = modulate.a * fade; + dd.emission_energy = decal->emission_energy * fade; + dd.albedo_mix = decal->albedo_mix; + dd.mask = decal->cull_mask; + dd.upper_fade = decal->upper_fade; + dd.lower_fade = decal->lower_fade; + + // hook for subclass to do further processing. + RendererSceneRenderRD::get_singleton()->setup_added_decal(xform, decal_extents); + } + + if (decal_count > 0) { + RD::get_singleton()->buffer_update(decal_buffer, 0, sizeof(DecalData) * decal_count, decals, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + } +} + /* RENDER TARGET API */ +RID TextureStorage::RenderTarget::get_framebuffer() { + // Note that if we're using an overridden color buffer, we're likely cycling through a texture chain. + // this is where our framebuffer cache comes in clutch.. + + if (msaa != RS::VIEWPORT_MSAA_DISABLED) { + return FramebufferCacheRD::get_singleton()->get_cache_multiview(view_count, color_multisample, overridden.color.is_valid() ? overridden.color : color); + } else { + return FramebufferCacheRD::get_singleton()->get_cache_multiview(view_count, overridden.color.is_valid() ? overridden.color : color); + } +} + void TextureStorage::_clear_render_target(RenderTarget *rt) { - //free in reverse dependency order - if (rt->framebuffer.is_valid()) { - RD::get_singleton()->free(rt->framebuffer); + // clear overrides, we assume these are freed by the object that created them + rt->overridden.color = RID(); + rt->overridden.depth = RID(); + rt->overridden.velocity = RID(); + rt->overridden.cached_slices.clear(); // these are automatically freed when their parent textures are freed so just clear + + // free in reverse dependency order + if (rt->framebuffer_uniform_set.is_valid()) { rt->framebuffer_uniform_set = RID(); //chain deleted } @@ -2139,7 +2401,6 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) { _render_target_clear_sdf(rt); - rt->framebuffer = RID(); rt->color = RID(); rt->color_multisample = RID(); } @@ -2187,11 +2448,10 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { } } + // TODO see if we can lazy create this once we actually use it as we may not need to create this if we have an overridden color buffer... rt->color = RD::get_singleton()->texture_create(rd_color_attachment_format, rd_view); ERR_FAIL_COND(rt->color.is_null()); - Vector<RID> fb_textures; - if (rt->msaa != RS::VIEWPORT_MSAA_DISABLED) { // Use the texture format of the color attachment for the multisample color attachment. RD::TextureFormat rd_color_multisample_format = rd_color_attachment_format; @@ -2205,15 +2465,8 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { RD::TextureView rd_view_multisample; rd_color_multisample_format.is_resolve_buffer = false; rt->color_multisample = RD::get_singleton()->texture_create(rd_color_multisample_format, rd_view_multisample); - fb_textures.push_back(rt->color_multisample); ERR_FAIL_COND(rt->color_multisample.is_null()); } - fb_textures.push_back(rt->color); - rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures, RenderingDevice::INVALID_ID, rt->view_count); - if (rt->framebuffer.is_null()) { - _clear_render_target(rt); - ERR_FAIL_COND(rt->framebuffer.is_null()); - } { //update texture @@ -2323,6 +2576,11 @@ void TextureStorage::render_target_set_position(RID p_render_target, int p_x, in //unused for this render target } +Point2i TextureStorage::render_target_get_position(RID p_render_target) const { + //unused for this render target + return Point2i(); +} + void TextureStorage::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); @@ -2334,6 +2592,13 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in } } +Size2i TextureStorage::render_target_get_size(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, Size2i()); + + return rt->size; +} + RID TextureStorage::render_target_get_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); @@ -2341,7 +2606,84 @@ RID TextureStorage::render_target_get_texture(RID p_render_target) { return rt->texture; } -void TextureStorage::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { +void TextureStorage::render_target_set_override_color(RID p_render_target, RID p_texture) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + rt->overridden.color = p_texture; +} + +RID TextureStorage::render_target_get_override_color(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + return rt->overridden.color; +} + +void TextureStorage::render_target_set_override_depth(RID p_render_target, RID p_texture) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + rt->overridden.depth = p_texture; +} + +RID TextureStorage::render_target_get_override_depth(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + return rt->overridden.depth; +} + +RID TextureStorage::render_target_get_override_depth_slice(RID p_render_target, const uint32_t p_layer) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + if (rt->overridden.depth.is_null()) { + return RID(); + } else if (rt->view_count == 1) { + return rt->overridden.depth; + } else { + RenderTarget::RTOverridden::SliceKey key(rt->overridden.depth, p_layer); + + if (!rt->overridden.cached_slices.has(key)) { + rt->overridden.cached_slices[key] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->overridden.depth, p_layer, 0); + } + + return rt->overridden.cached_slices[key]; + } +} + +void TextureStorage::render_target_set_override_velocity(RID p_render_target, RID p_texture) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + rt->overridden.velocity = p_texture; +} + +RID TextureStorage::render_target_get_override_velocity(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + return rt->overridden.velocity; +} + +RID TextureStorage::render_target_get_override_velocity_slice(RID p_render_target, const uint32_t p_layer) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + if (rt->overridden.velocity.is_null()) { + return RID(); + } else if (rt->view_count == 1) { + return rt->overridden.velocity; + } else { + RenderTarget::RTOverridden::SliceKey key(rt->overridden.velocity, p_layer); + + if (!rt->overridden.cached_slices.has(key)) { + rt->overridden.cached_slices[key] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->overridden.velocity, p_layer, 0); + } + + return rt->overridden.cached_slices[key]; + } } void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_is_transparent) { @@ -2351,10 +2693,21 @@ void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_i _update_render_target(rt); } +bool TextureStorage::render_target_get_transparent(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, false); + + return rt->is_transparent; +} + void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_value) { } -bool TextureStorage::render_target_was_used(RID p_render_target) { +bool TextureStorage::render_target_get_direct_to_screen(RID p_render_target) const { + return false; +} + +bool TextureStorage::render_target_was_used(RID p_render_target) const { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, false); return rt->was_used; @@ -2377,25 +2730,29 @@ void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSA _update_render_target(rt); } -Size2 TextureStorage::render_target_get_size(RID p_render_target) { +RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) const { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND_V(!rt, Size2()); + ERR_FAIL_COND_V(!rt, RS::VIEWPORT_MSAA_DISABLED); - return rt->size; + return rt->msaa; } RID TextureStorage::render_target_get_rd_framebuffer(RID p_render_target) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); - return rt->framebuffer; + return rt->get_framebuffer(); } RID TextureStorage::render_target_get_rd_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); - return rt->color; + if (rt->overridden.color.is_valid()) { + return rt->overridden.color; + } else { + return rt->color; + } } RID TextureStorage::render_target_get_rd_texture_slice(RID p_render_target, uint32_t p_layer) { @@ -2466,7 +2823,7 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) { } Vector<Color> clear_colors; clear_colors.push_back(rt->clear_color); - RD::get_singleton()->draw_list_begin(rt->framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors); RD::get_singleton()->draw_list_end(); rt->clear_requested = false; } @@ -2895,18 +3252,18 @@ void TextureStorage::render_target_set_vrs_mode(RID p_render_target, RS::Viewpor rt->vrs_mode = p_mode; } -void TextureStorage::render_target_set_vrs_texture(RID p_render_target, RID p_texture) { +RS::ViewportVRSMode TextureStorage::render_target_get_vrs_mode(RID p_render_target) const { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); + ERR_FAIL_COND_V(!rt, RS::VIEWPORT_VRS_DISABLED); - rt->vrs_texture = p_texture; + return rt->vrs_mode; } -RS::ViewportVRSMode TextureStorage::render_target_get_vrs_mode(RID p_render_target) const { +void TextureStorage::render_target_set_vrs_texture(RID p_render_target, RID p_texture) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND_V(!rt, RS::VIEWPORT_VRS_DISABLED); + ERR_FAIL_COND(!rt); - return rt->vrs_mode; + rt->vrs_texture = p_texture; } RID TextureStorage::render_target_get_vrs_texture(RID p_render_target) const { diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index a3acad30f3..00b4e50737 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -31,8 +31,12 @@ #ifndef TEXTURE_STORAGE_RD_H #define TEXTURE_STORAGE_RD_H +#include "core/templates/local_vector.h" +#include "core/templates/paged_array.h" #include "core/templates/rid_owner.h" #include "servers/rendering/renderer_rd/shaders/canvas_sdf.glsl.gen.h" +#include "servers/rendering/renderer_rd/storage_rd/forward_id_storage.h" +#include "servers/rendering/rendering_server_default.h" #include "servers/rendering/storage/texture_storage.h" #include "servers/rendering/storage/utilities.h" @@ -245,14 +249,58 @@ private: }; mutable RID_Owner<Decal, true> decal_owner; - Decal *get_decal(RID p_rid) const { return decal_owner.get_or_null(p_rid); }; + + /* DECAL INSTANCE */ + + struct DecalInstance { + RID decal; + Transform3D transform; + uint32_t cull_mask = 0; + RendererRD::ForwardID forward_id = -1; + }; + + mutable RID_Owner<DecalInstance> decal_instance_owner; + + /* DECAL DATA (UBO) */ + + struct DecalData { + float xform[16]; + float inv_extents[3]; + float albedo_mix; + float albedo_rect[4]; + float normal_rect[4]; + float orm_rect[4]; + float emission_rect[4]; + float modulate[4]; + float emission_energy; + uint32_t mask; + float upper_fade; + float lower_fade; + float normal_xform[12]; + float normal[3]; + float normal_fade; + }; + + struct DecalInstanceSort { + float depth; + DecalInstance *decal_instance; + Decal *decal; + bool operator<(const DecalInstanceSort &p_sort) const { + return depth < p_sort.depth; + } + }; + + uint32_t max_decals = 0; + uint32_t decal_count = 0; + DecalData *decals = nullptr; + DecalInstanceSort *decal_sort = nullptr; + RID decal_buffer; /* RENDER TARGET API */ struct RenderTarget { Size2i size; uint32_t view_count; - RID framebuffer; RID color; Vector<RID> color_slices; RID color_multisample; // Needed when MSAA is enabled. @@ -290,6 +338,43 @@ private: RS::ViewportVRSMode vrs_mode = RS::VIEWPORT_VRS_DISABLED; RID vrs_texture; + // overridden textures + struct RTOverridden { + RID color; + RID depth; + RID velocity; + + // In a multiview scenario, which is the most likely where we + // override our destination textures, we need to obtain slices + // for each layer of these textures. + // These are likely changing every frame as we loop through + // texture chains hence we add a cache to manage these slices. + // For this we define a key using the RID of the texture and + // the layer for which we create a slice. + struct SliceKey { + RID rid; + uint32_t layer = 0; + + bool operator==(const SliceKey &p_val) const { + return (rid == p_val.rid) && (layer == p_val.layer); + } + + static uint32_t hash(const SliceKey &p_val) { + uint32_t h = hash_one_uint64(p_val.rid.get_id()); + h = hash_murmur3_one_32(p_val.layer, h); + return hash_fmix32(h); + } + + SliceKey() {} + SliceKey(RID p_rid, uint32_t p_layer) { + rid = p_rid; + layer = p_layer; + } + }; + + mutable HashMap<SliceKey, RID, SliceKey> cached_slices; + } overridden; + //texture generated for this owner (nor RD). RID texture; bool was_used; @@ -297,6 +382,8 @@ private: //clear request bool clear_requested; Color clear_color; + + RID get_framebuffer(); }; mutable RID_Owner<RenderTarget> render_target_owner; @@ -343,6 +430,8 @@ public: TextureStorage(); virtual ~TextureStorage(); + bool free(RID p_rid); + /* Canvas Texture API */ bool owns_canvas_texture(RID p_rid) { return canvas_texture_owner.owns(p_rid); }; @@ -545,6 +634,46 @@ public: virtual AABB decal_get_aabb(RID p_decal) const override; Dependency *decal_get_dependency(RID p_decal); + /* DECAL INSTANCE API */ + + bool owns_decal_instance(RID p_rid) const { return decal_instance_owner.owns(p_rid); } + + virtual RID decal_instance_create(RID p_decal) override; + virtual void decal_instance_free(RID p_decal_instance) override; + virtual void decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) override; + + _FORCE_INLINE_ RID decal_instance_get_base(RID p_decal_instance) const { + DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance); + return di->decal; + } + + _FORCE_INLINE_ RendererRD::ForwardID decal_instance_get_forward_id(RID p_decal_instance) const { + DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance); + return di->forward_id; + } + + _FORCE_INLINE_ Transform3D decal_instance_get_transform(RID p_decal_instance) const { + DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance); + return di->transform; + } + + _FORCE_INLINE_ ForwardID decal_instance_get_forward_id(RID p_decal_instance) { + DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance); + return di->forward_id; + } + + _FORCE_INLINE_ void decal_instance_set_cullmask(RID p_decal_instance, uint32_t p_cull_mask) const { + DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance); + di->cull_mask = p_cull_mask; + } + + /* DECAL DATA API */ + + void free_decal_data(); + void set_max_decals(const uint32_t p_max_decals); + RID get_decal_buffer() { return decal_buffer; } + void update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform); + /* RENDER TARGET API */ bool owns_render_target(RID p_rid) const { return render_target_owner.owns(p_rid); }; @@ -553,14 +682,17 @@ public: virtual void render_target_free(RID p_rid) override; virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override; + virtual Point2i render_target_get_position(RID p_render_target) const override; virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override; - virtual RID render_target_get_texture(RID p_render_target) override; - virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override; + virtual Size2i render_target_get_size(RID p_render_target) const override; virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override; + virtual bool render_target_get_transparent(RID p_render_target) const override; virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override; - virtual bool render_target_was_used(RID p_render_target) override; + virtual bool render_target_get_direct_to_screen(RID p_render_target) const override; + virtual bool render_target_was_used(RID p_render_target) const override; virtual void render_target_set_as_unused(RID p_render_target) override; virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override; + virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override; void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps); void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color); @@ -582,12 +714,21 @@ public: bool render_target_is_sdf_enabled(RID p_render_target) const; virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override; + virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const override; virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override; + virtual RID render_target_get_vrs_texture(RID p_render_target) const override; - RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const; - RID render_target_get_vrs_texture(RID p_render_target) const; + virtual void render_target_set_override_color(RID p_render_target, RID p_texture) override; + virtual RID render_target_get_override_color(RID p_render_target) const override; + virtual void render_target_set_override_depth(RID p_render_target, RID p_texture) override; + virtual RID render_target_get_override_depth(RID p_render_target) const override; + RID render_target_get_override_depth_slice(RID p_render_target, const uint32_t p_layer) const; + virtual void render_target_set_override_velocity(RID p_render_target, RID p_texture) override; + virtual RID render_target_get_override_velocity(RID p_render_target) const override; + RID render_target_get_override_velocity_slice(RID p_render_target, const uint32_t p_layer) const; + + virtual RID render_target_get_texture(RID p_render_target) override; - Size2 render_target_get_size(RID p_render_target); RID render_target_get_rd_framebuffer(RID p_render_target); RID render_target_get_rd_texture(RID p_render_target); RID render_target_get_rd_texture_slice(RID p_render_target, uint32_t p_layer); diff --git a/servers/rendering/renderer_rd/storage_rd/utilities.cpp b/servers/rendering/renderer_rd/storage_rd/utilities.cpp index b80bcd514f..e517186955 100644 --- a/servers/rendering/renderer_rd/storage_rd/utilities.cpp +++ b/servers/rendering/renderer_rd/storage_rd/utilities.cpp @@ -89,49 +89,28 @@ RS::InstanceType Utilities::get_base_type(RID p_rid) const { } bool Utilities::free(RID p_rid) { - if (RendererRD::TextureStorage::get_singleton()->owns_texture(p_rid)) { - RendererRD::TextureStorage::get_singleton()->texture_free(p_rid); - } else if (RendererRD::TextureStorage::get_singleton()->owns_canvas_texture(p_rid)) { - RendererRD::TextureStorage::get_singleton()->canvas_texture_free(p_rid); - } else if (RendererRD::MaterialStorage::get_singleton()->owns_shader(p_rid)) { - RendererRD::MaterialStorage::get_singleton()->shader_free(p_rid); - } else if (RendererRD::MaterialStorage::get_singleton()->owns_material(p_rid)) { - RendererRD::MaterialStorage::get_singleton()->material_free(p_rid); - } else if (RendererRD::MeshStorage::get_singleton()->owns_mesh(p_rid)) { - RendererRD::MeshStorage::get_singleton()->mesh_free(p_rid); - } else if (RendererRD::MeshStorage::get_singleton()->owns_mesh_instance(p_rid)) { - RendererRD::MeshStorage::get_singleton()->mesh_instance_free(p_rid); - } else if (RendererRD::MeshStorage::get_singleton()->owns_multimesh(p_rid)) { - RendererRD::MeshStorage::get_singleton()->multimesh_free(p_rid); - } else if (RendererRD::MeshStorage::get_singleton()->owns_skeleton(p_rid)) { - RendererRD::MeshStorage::get_singleton()->skeleton_free(p_rid); - } else if (RendererRD::LightStorage::get_singleton()->owns_reflection_probe(p_rid)) { - RendererRD::LightStorage::get_singleton()->reflection_probe_free(p_rid); - } else if (RendererRD::TextureStorage::get_singleton()->owns_decal(p_rid)) { - RendererRD::TextureStorage::get_singleton()->decal_free(p_rid); + if (RendererRD::LightStorage::get_singleton()->free(p_rid)) { + return true; + } else if (RendererRD::MaterialStorage::get_singleton()->free(p_rid)) { + return true; + } else if (RendererRD::MeshStorage::get_singleton()->free(p_rid)) { + return true; + } else if (RendererRD::ParticlesStorage::get_singleton()->free(p_rid)) { + return true; + } else if (RendererRD::TextureStorage::get_singleton()->free(p_rid)) { + return true; } else if (RendererRD::GI::get_singleton()->owns_voxel_gi(p_rid)) { RendererRD::GI::get_singleton()->voxel_gi_free(p_rid); - } else if (RendererRD::LightStorage::get_singleton()->owns_lightmap(p_rid)) { - RendererRD::LightStorage::get_singleton()->lightmap_free(p_rid); - } else if (RendererRD::LightStorage::get_singleton()->owns_light(p_rid)) { - RendererRD::LightStorage::get_singleton()->light_free(p_rid); - } else if (RendererRD::ParticlesStorage::get_singleton()->owns_particles(p_rid)) { - RendererRD::ParticlesStorage::get_singleton()->particles_free(p_rid); - } else if (RendererRD::ParticlesStorage::get_singleton()->owns_particles_collision(p_rid)) { - RendererRD::ParticlesStorage::get_singleton()->particles_collision_free(p_rid); + return true; + } else if (RendererRD::Fog::get_singleton()->owns_fog_volume(p_rid)) { + RendererRD::Fog::get_singleton()->fog_volume_free(p_rid); + return true; } else if (owns_visibility_notifier(p_rid)) { visibility_notifier_free(p_rid); - } else if (RendererRD::ParticlesStorage::get_singleton()->owns_particles_collision_instance(p_rid)) { - RendererRD::ParticlesStorage::get_singleton()->particles_collision_instance_free(p_rid); - } else if (RendererRD::Fog::get_singleton()->owns_fog_volume(p_rid)) { - RendererRD::Fog::get_singleton()->fog_free(p_rid); - } else if (RendererRD::TextureStorage::get_singleton()->owns_render_target(p_rid)) { - RendererRD::TextureStorage::get_singleton()->render_target_free(p_rid); + return true; } else { return false; } - - return true; } /* DEPENDENCIES */ @@ -170,8 +149,8 @@ void Utilities::base_update_dependency(RID p_base, DependencyTracker *p_instance Dependency *dependency = ParticlesStorage::get_singleton()->particles_collision_get_dependency(p_base); p_instance->update_dependency(dependency); } else if (Fog::get_singleton()->owns_fog_volume(p_base)) { - Fog::FogVolume *fv = Fog::get_singleton()->get_fog_volume(p_base); - p_instance->update_dependency(&fv->dependency); + Dependency *dependency = Fog::get_singleton()->fog_volume_get_dependency(p_base); + p_instance->update_dependency(dependency); } else if (owns_visibility_notifier(p_base)) { VisibilityNotifier *vn = get_visibility_notifier(p_base); p_instance->update_dependency(&vn->dependency); |