summaryrefslogtreecommitdiffstats
path: root/servers/rendering/renderer_scene_cull.h
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/renderer_scene_cull.h')
-rw-r--r--servers/rendering/renderer_scene_cull.h53
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);