diff options
Diffstat (limited to 'servers/rendering/renderer_scene_cull.h')
-rw-r--r-- | servers/rendering/renderer_scene_cull.h | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index e3e20b8502..a09823b008 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -46,6 +46,8 @@ #include "servers/rendering/storage/utilities.h" #include "servers/xr/xr_interface.h" +class RenderingLightCuller; + class RendererSceneCull : public RenderingMethod { public: RendererSceneRender *scene_render = nullptr; @@ -679,7 +681,6 @@ public: uint64_t last_version; List<Instance *>::Element *D; // directional light in scenario - bool shadow_dirty; bool uses_projector = false; bool uses_softshadow = false; @@ -690,12 +691,59 @@ public: RS::LightBakeMode bake_mode; uint32_t max_sdfgi_cascade = 2; + private: + // Instead of a single dirty flag, we maintain a count + // so that we can detect lights that are being made dirty + // each frame, and switch on tighter caster culling. + int32_t shadow_dirty_count; + + uint32_t light_update_frame_id; + bool light_intersects_multiple_cameras; + uint32_t light_intersects_multiple_cameras_timeout_frame_id; + + public: + bool is_shadow_dirty() const { return shadow_dirty_count != 0; } + void make_shadow_dirty() { shadow_dirty_count = light_intersects_multiple_cameras ? 1 : 2; } + void detect_light_intersects_multiple_cameras(uint32_t p_frame_id) { + // We need to detect the case where shadow updates are occurring + // more than once per frame. In this case, we need to turn off + // tighter caster culling, so situation reverts to one full shadow update + // per frame (light_intersects_multiple_cameras is set). + if (p_frame_id == light_update_frame_id) { + light_intersects_multiple_cameras = true; + light_intersects_multiple_cameras_timeout_frame_id = p_frame_id + 60; + } else { + // When shadow_volume_intersects_multiple_cameras is set, we + // want to detect the situation this is no longer the case, via a timeout. + // The system can go back to tighter caster culling in this situation. + // Having a long-ish timeout prevents rapid cycling. + if (light_intersects_multiple_cameras && (p_frame_id >= light_intersects_multiple_cameras_timeout_frame_id)) { + light_intersects_multiple_cameras = false; + light_intersects_multiple_cameras_timeout_frame_id = UINT32_MAX; + } + } + light_update_frame_id = p_frame_id; + } + + void decrement_shadow_dirty() { + shadow_dirty_count--; + DEV_ASSERT(shadow_dirty_count >= 0); + } + + // Shadow updates can either full (everything in the shadow volume) + // or closely culled to the camera frustum. + bool is_shadow_update_full() const { return shadow_dirty_count == 0; } + InstanceLightData() { bake_mode = RS::LIGHT_BAKE_DISABLED; - shadow_dirty = true; D = nullptr; last_version = 0; baked_light = nullptr; + + shadow_dirty_count = 1; + light_update_frame_id = UINT32_MAX; + light_intersects_multiple_cameras_timeout_frame_id = UINT32_MAX; + light_intersects_multiple_cameras = false; } }; @@ -955,6 +1003,7 @@ public: uint32_t geometry_instance_pair_mask = 0; // used in traditional forward, unnecessary on clustered LocalVector<Vector2> camera_jitter_array; + RenderingLightCuller *light_culler = nullptr; virtual RID instance_allocate(); virtual void instance_initialize(RID p_rid); |