From 9860d1c6f906377710ac503f1cb3fd57fcd5e2bd Mon Sep 17 00:00:00 2001 From: jon1solution <143551917+jon1solution@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:46:04 -0700 Subject: [PATCH 1/7] Keeping the top N lights per mesh in the culling phase. Removed pair_light_instances which took an intermediate collection of culled lights. Added in clear_light_instances to remove all paired lights from the mesh, and it returns how many lights max per mesh can be paired. Added pair_light_instance which pairs a specific light with a specific index into the pairing array. Inside RendererSceneCull::_scene_cull I keep the top N lights per mesh. The current implementation is not the fastest, I still need to move to a heap to efficiently keep the best lights, and SortArray seems to have the functionality I need. --- drivers/gles3/rasterizer_scene_gles3.cpp | 35 +++--- drivers/gles3/rasterizer_scene_gles3.h | 3 +- .../rendering/dummy/rasterizer_scene_dummy.h | 3 +- .../rendering/renderer_geometry_instance.h | 3 +- .../render_forward_clustered.h | 3 +- .../forward_mobile/render_forward_mobile.cpp | 31 ++--- .../forward_mobile/render_forward_mobile.h | 3 +- servers/rendering/renderer_scene_cull.cpp | 113 ++++++++++++++++-- 8 files changed, 150 insertions(+), 44 deletions(-) diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 6d0d59ce4266..ea032f688bd8 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -71,31 +71,36 @@ uint32_t RasterizerSceneGLES3::geometry_instance_get_pair_mask() { return ((1 << RS::INSTANCE_LIGHT) | (1 << RS::INSTANCE_REFLECTION_PROBE)); } -void RasterizerSceneGLES3::GeometryInstanceGLES3::pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) { - GLES3::Config *config = GLES3::Config::get_singleton(); - +uint32_t RasterizerSceneGLES3::GeometryInstanceGLES3::clear_light_instances() +{ paired_omni_light_count = 0; paired_spot_light_count = 0; paired_omni_lights.clear(); paired_spot_lights.clear(); - - for (uint32_t i = 0; i < p_light_instance_count; i++) { - RS::LightType type = GLES3::LightStorage::get_singleton()->light_instance_get_type(p_light_instances[i]); - switch (type) { + return GLES3::Config::get_singleton()->max_lights_per_object; +} +void RasterizerSceneGLES3::GeometryInstanceGLES3::pair_light_instance( + const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx ) +{ + if( placement_idx < GLES3::Config::get_singleton()->max_lights_per_object ){ + switch (light_type) { case RS::LIGHT_OMNI: { - if (paired_omni_light_count < (uint32_t)config->max_lights_per_object) { - paired_omni_lights.push_back(p_light_instances[i]); - paired_omni_light_count++; + if( placement_idx >= paired_omni_light_count ) { + paired_omni_lights.push_back( p_light_instance ); + ++paired_omni_light_count; + } else { + paired_omni_lights[ placement_idx ] = p_light_instance; } } break; case RS::LIGHT_SPOT: { - if (paired_spot_light_count < (uint32_t)config->max_lights_per_object) { - paired_spot_lights.push_back(p_light_instances[i]); - paired_spot_light_count++; + if( placement_idx >= paired_spot_light_count ) { + paired_spot_lights.push_back( p_light_instance ); + ++paired_spot_light_count; + } else { + paired_spot_lights[ placement_idx ] = p_light_instance; } } break; - default: - break; + default: break; } } } diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index aa0923fe7069..d3d184fb8f8b 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -341,7 +341,8 @@ class RasterizerSceneGLES3 : public RendererSceneRender { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override; + virtual uint32_t clear_light_instances() override; + virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} virtual void pair_voxel_gi_instances(const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override {} diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h index 4e86732d5e68..17cb51db7d17 100644 --- a/servers/rendering/dummy/rasterizer_scene_dummy.h +++ b/servers/rendering/dummy/rasterizer_scene_dummy.h @@ -66,7 +66,8 @@ class RasterizerSceneDummy : public RendererSceneRender { virtual Transform3D get_transform() override { return Transform3D(); } virtual AABB get_aabb() override { return AABB(); } - virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override {} + virtual uint32_t clear_light_instances() override {return 0;} + virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override {} virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {} virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} virtual void pair_voxel_gi_instances(const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override {} diff --git a/servers/rendering/renderer_geometry_instance.h b/servers/rendering/renderer_geometry_instance.h index eb6130722194..9504461c6f10 100644 --- a/servers/rendering/renderer_geometry_instance.h +++ b/servers/rendering/renderer_geometry_instance.h @@ -66,7 +66,8 @@ class RenderGeometryInstance { virtual Transform3D get_transform() = 0; virtual AABB get_aabb() = 0; - virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) = 0; + virtual uint32_t clear_light_instances() = 0; + virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) = 0; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) = 0; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) = 0; virtual void pair_voxel_gi_instances(const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) = 0; 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 0626cef6d311..508f0b6379cd 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -572,7 +572,8 @@ class RenderForwardClustered : public RendererSceneRenderRD { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override {} + virtual uint32_t clear_light_instances() override {return 0;} + virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override {} virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {} virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} virtual void pair_voxel_gi_instances(const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override; 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 c9d0d7b63c9b..4cf18f4c8148 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2553,27 +2553,28 @@ uint32_t RenderForwardMobile::geometry_instance_get_pair_mask() { return ((1 << RS::INSTANCE_LIGHT) + (1 << RS::INSTANCE_REFLECTION_PROBE) + (1 << RS::INSTANCE_DECAL)); } -void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) { +uint32_t RenderForwardMobile::GeometryInstanceForwardMobile::clear_light_instances() +{ omni_light_count = 0; spot_light_count = 0; - - for (uint32_t i = 0; i < p_light_instance_count; i++) { - RS::LightType type = RendererRD::LightStorage::get_singleton()->light_instance_get_type(p_light_instances[i]); - switch (type) { + return MAX_RDL_CULL; +} +void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instance( + const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx ) +{ + if( placement_idx < (uint32_t)MAX_RDL_CULL ){ + RendererRD::ForwardID light_id = RendererRD::LightStorage::get_singleton()-> + light_instance_get_forward_id(p_light_instance); + switch (light_type) { case RS::LIGHT_OMNI: { - if (omni_light_count < (uint32_t)MAX_RDL_CULL) { - omni_lights[omni_light_count] = RendererRD::LightStorage::get_singleton()->light_instance_get_forward_id(p_light_instances[i]); - omni_light_count++; - } + omni_lights[ placement_idx ] = light_id; + if( placement_idx >= omni_light_count ) { omni_light_count = placement_idx + 1; } } break; case RS::LIGHT_SPOT: { - if (spot_light_count < (uint32_t)MAX_RDL_CULL) { - spot_lights[spot_light_count] = RendererRD::LightStorage::get_singleton()->light_instance_get_forward_id(p_light_instances[i]); - spot_light_count++; - } + spot_lights[ placement_idx ] = light_id; + if( placement_idx >= spot_light_count ) { spot_light_count = placement_idx + 1; } } break; - default: - break; + default: break; } } } 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 5aa536c7df64..adff1eb1d008 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -537,7 +537,8 @@ class RenderForwardMobile : public RendererSceneRenderRD { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override; + virtual uint32_t clear_light_instances() override; + virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override; virtual void pair_voxel_gi_instances(const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override {} diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 0c84348b6991..911bca7ab50d 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1956,7 +1956,7 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) { InstanceGeometryData *geom = static_cast(p_instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); - geom->geometry_instance->pair_light_instances(nullptr, 0); + geom->geometry_instance->clear_light_instances(); geom->geometry_instance->pair_reflection_probe_instances(nullptr, 0); geom->geometry_instance->pair_decal_instances(nullptr, 0); geom->geometry_instance->pair_voxel_gi_instances(nullptr, 0); @@ -2813,6 +2813,8 @@ void RendererSceneCull::_scene_cull_threaded(uint32_t p_thread, CullData *cull_d _scene_cull(*cull_data, scene_cull_result_threads[p_thread], cull_from, cull_to); } +#include "core/os/os.h" +#include "core/os/time.h" void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to) { uint64_t frame_number = RSG::rasterizer->get_frame_number(); float lightmap_probe_update_speed = RSG::light_storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time(); @@ -2932,8 +2934,21 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { InstanceGeometryData *geom = static_cast(idata.instance->base_data); - uint32_t idx = 0; - + ERR_FAIL_NULL(geom->geometry_instance); + uint32_t link_max_count = geom->geometry_instance->clear_light_instances(); + if( link_max_count > 0 ) { + // Profile the new way vs old pair_light_instances + uint64_t tin = Time::get_singleton()->get_ticks_usec(); + + // clear any existing light instances and return the max count. + uint32_t omni_count = 0, omni_worst = 0, spot_count = 0, spot_worst = 0; + LocalVector omni_scores, spot_scores; // I want to switch to SortArray of a pair(score,index) + omni_scores.resize( link_max_count ); + spot_scores.resize( link_max_count ); + + // Score each light relative to this mesh. + Vector3 mesh_center = idata.instance->transformed_aabb.get_center(); + //print_line(vformat("mesh(%f,%f,%f)", mesh_center.x, mesh_center.y, mesh_center.z)); for (const Instance *E : geom->lights) { InstanceLightData *light = static_cast(E->base_data); if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) { @@ -2944,14 +2959,94 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul continue; } - instance_pair_buffer[idx++] = light->instance; - if (idx == MAX_INSTANCE_PAIRS) { - break; + #if 0 + // Only keep the 1st N + RS::LightType light_type = RSG::light_storage->light_get_type(E->base); + switch (light_type) { + case RS::LIGHT_OMNI: { + if( omni_count < link_max_count ) { + geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_count++); + } + } break; + case RS::LIGHT_SPOT: { + if( spot_count < link_max_count ) { + geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_count++); + } + } break; + default: break; + } + #else + // Large scores are worse, so linear with distance, inverse with energy and range + //Vector3 light_center = E->transformed_aabb.get_center(); // maybe a bit faster? + Vector3 light_center = E->transform.xform( RSG::light_storage->light_get_aabb(E->base).get_center() ); // should be more accurate + //print_line(vformat("light(%f,%f,%f)", light_center.x, light_center.y, light_center.z)); + float light_range = RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_RANGE); + float light_energy = RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_ENERGY); + float light_inst_score = mesh_center.distance_to( light_center ) / (0.1f + light_range * light_energy); + // Keep the best per-light-type + RS::LightType light_type = RSG::light_storage->light_get_type(E->base); + switch (light_type) { + case RS::LIGHT_OMNI: { + if( omni_count < link_max_count ) { + omni_scores[ omni_count ] = light_inst_score; + if( light_inst_score > omni_scores[ omni_worst ] ) { + omni_worst = omni_count; + } + geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_count++); + } else { + if( light_inst_score < omni_scores[ omni_worst ] ) { + geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_worst); + omni_scores[ omni_worst ] = light_inst_score; + for( uint32_t i = 0; i < link_max_count; ++i ) { + if( omni_scores[ i ] > omni_scores[ omni_worst ] ) { + omni_worst = i; + } + } + } + } + } break; + case RS::LIGHT_SPOT: { + if( spot_count < link_max_count ) { + spot_scores[ spot_count ] = light_inst_score; + if( light_inst_score > spot_scores[ spot_worst ] ) { + spot_worst = spot_count; + } + geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_count++); + }else { + if( light_inst_score < spot_scores[ spot_worst ] ) { + geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_worst); + spot_scores[ spot_worst ] = light_inst_score; + for( uint32_t i = 0; i < link_max_count; ++i ) { + if( spot_scores[ i ] > spot_scores[ spot_worst ] ) { + spot_worst = i; + } + } + } + } + } break; + default: break; + } + #endif + } + { + // This block is just for profiling. + uint64_t tout = Time::get_singleton()->get_ticks_usec(); + static uint64_t prof_lights = 0; + static uint64_t prof_count = 0; + static uint64_t prof_us = 0; + prof_lights += geom->lights.size(); + prof_us += tout - tin; + if( ++prof_count >= 100 ) + { + double lights_per_call = prof_lights; lights_per_call /= prof_count; + double us_per_call = prof_us; us_per_call /= prof_count; + print_line(vformat("modified pair_light_instances avg %1.2f [us] for %1.2f lights", us_per_call, lights_per_call)); + prof_lights = 0; + prof_count = 0; + prof_us = 0; + } } } - - ERR_FAIL_NULL(geom->geometry_instance); - geom->geometry_instance->pair_light_instances(instance_pair_buffer, idx); idata.flags &= ~InstanceData::FLAG_GEOM_LIGHTING_DIRTY; } From 24aa509c3841fc3316a332f0cc5b7d6a761f7ab3 Mon Sep 17 00:00:00 2001 From: jon1solution <143551917+jon1solution@users.noreply.github.com> Date: Thu, 5 Jun 2025 00:01:20 -0700 Subject: [PATCH 2/7] Uses SortArray to optimize nearest N lights. SortArray uses a heap internally, which is the best option. On my system, worst test case is 256 omnilights with 256 meshes with 64 lights/mesh, and that takes 8.9us per mesh just to compute the distance score for the lights, with an additional 5.1us per mesh to keep the top 64. --- .gitignore | 2 + servers/rendering/renderer_scene_cull.cpp | 80 ++++++++++++----------- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index 97cf4e625550..b23195683d07 100644 --- a/.gitignore +++ b/.gitignore @@ -387,3 +387,5 @@ $RECYCLE.BIN/ *.msp *.lnk *.generated.props +compile debug godot.bat +compile size godot.bat diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 911bca7ab50d..ce88776a180f 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -2941,23 +2941,25 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul uint64_t tin = Time::get_singleton()->get_ticks_usec(); // clear any existing light instances and return the max count. - uint32_t omni_count = 0, omni_worst = 0, spot_count = 0, spot_worst = 0; - LocalVector omni_scores, spot_scores; // I want to switch to SortArray of a pair(score,index) - omni_scores.resize( link_max_count ); - spot_scores.resize( link_max_count ); - + uint32_t omni_count = 0, spot_count = 0; + LocalVector > omni_score_idx, spot_score_idx; // score, index into the light array + omni_score_idx.resize( link_max_count ); + spot_score_idx.resize( link_max_count ); + SortArray > heapify; // I want to switch to SortArray of a pair(score,index) + bool omni_needs_heap = true, spot_needs_heap = true; + // Score each light relative to this mesh. Vector3 mesh_center = idata.instance->transformed_aabb.get_center(); //print_line(vformat("mesh(%f,%f,%f)", mesh_center.x, mesh_center.y, mesh_center.z)); - for (const Instance *E : geom->lights) { - InstanceLightData *light = static_cast(E->base_data); - if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) { - continue; - } + for (const Instance *E : geom->lights) { + InstanceLightData *light = static_cast(E->base_data); + if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) { + continue; + } - if ((RSG::light_storage->light_get_bake_mode(E->base) == RS::LIGHT_BAKE_STATIC) && idata.instance->lightmap) { - continue; - } + if ((RSG::light_storage->light_get_bake_mode(E->base) == RS::LIGHT_BAKE_STATIC) && idata.instance->lightmap) { + continue; + } #if 0 // Only keep the 1st N @@ -2988,39 +2990,39 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul switch (light_type) { case RS::LIGHT_OMNI: { if( omni_count < link_max_count ) { - omni_scores[ omni_count ] = light_inst_score; - if( light_inst_score > omni_scores[ omni_worst ] ) { - omni_worst = omni_count; - } + // We have room to just add it, and track the score and where it goes + omni_score_idx[ omni_count ] = Pair(light_inst_score, omni_count); geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_count++); } else { - if( light_inst_score < omni_scores[ omni_worst ] ) { - geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_worst); - omni_scores[ omni_worst ] = light_inst_score; - for( uint32_t i = 0; i < link_max_count; ++i ) { - if( omni_scores[ i ] > omni_scores[ omni_worst ] ) { - omni_worst = i; - } - } + if( omni_needs_heap ) { + // We need to make this a heap one time + heapify.make_heap( 0, link_max_count, &omni_score_idx[0] ); + omni_needs_heap = false; + } + if( light_inst_score < omni_score_idx[ 0 ].first ) { + uint32_t replace_index = omni_score_idx[ 0 ].second; + geom->geometry_instance->pair_light_instance(light->instance, light_type, replace_index); + heapify.adjust_heap( 0, 0, link_max_count, Pair( light_inst_score, replace_index ), + &omni_score_idx[0] ); } } } break; case RS::LIGHT_SPOT: { if( spot_count < link_max_count ) { - spot_scores[ spot_count ] = light_inst_score; - if( light_inst_score > spot_scores[ spot_worst ] ) { - spot_worst = spot_count; - } + // We have room to just add it, and track the score and where it goes + spot_score_idx[ spot_count ] = Pair(light_inst_score, spot_count); geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_count++); - }else { - if( light_inst_score < spot_scores[ spot_worst ] ) { - geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_worst); - spot_scores[ spot_worst ] = light_inst_score; - for( uint32_t i = 0; i < link_max_count; ++i ) { - if( spot_scores[ i ] > spot_scores[ spot_worst ] ) { - spot_worst = i; - } - } + } else { + if( spot_needs_heap ) { + // We need to make this a heap one time + heapify.make_heap( 0, link_max_count, &spot_score_idx[0] ); + spot_needs_heap = false; + } + if( light_inst_score < spot_score_idx[ 0 ].first ) { + uint32_t replace_index = spot_score_idx[ 0 ].second; + geom->geometry_instance->pair_light_instance(light->instance, light_type, replace_index); + heapify.adjust_heap( 0, 0, link_max_count, Pair( light_inst_score, replace_index ), + &spot_score_idx[0] ); } } } break; @@ -3028,6 +3030,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul } #endif } + #if 0 { // This block is just for profiling. uint64_t tout = Time::get_singleton()->get_ticks_usec(); @@ -3046,6 +3049,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul prof_us = 0; } } + #endif } idata.flags &= ~InstanceData::FLAG_GEOM_LIGHTING_DIRTY; } From 2fc9875b603c2b11a975b9cacbe66721589ab6e8 Mon Sep 17 00:00:00 2001 From: jon1solution <143551917+jon1solution@users.noreply.github.com> Date: Thu, 5 Jun 2025 11:27:31 -0700 Subject: [PATCH 3/7] Updating comments. Updating comments. --- servers/rendering/renderer_scene_cull.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index ce88776a180f..fdf14c6fbba4 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -2935,22 +2935,19 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { InstanceGeometryData *geom = static_cast(idata.instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); + // clear any existing light instances for this mesh and return the max count. uint32_t link_max_count = geom->geometry_instance->clear_light_instances(); if( link_max_count > 0 ) { - // Profile the new way vs old pair_light_instances uint64_t tin = Time::get_singleton()->get_ticks_usec(); - // clear any existing light instances and return the max count. + // Run through all M lights, but only use a heap to keep track of the best N uint32_t omni_count = 0, spot_count = 0; LocalVector > omni_score_idx, spot_score_idx; // score, index into the light array omni_score_idx.resize( link_max_count ); spot_score_idx.resize( link_max_count ); - SortArray > heapify; // I want to switch to SortArray of a pair(score,index) + SortArray > heapify; bool omni_needs_heap = true, spot_needs_heap = true; - - // Score each light relative to this mesh. Vector3 mesh_center = idata.instance->transformed_aabb.get_center(); - //print_line(vformat("mesh(%f,%f,%f)", mesh_center.x, mesh_center.y, mesh_center.z)); for (const Instance *E : geom->lights) { InstanceLightData *light = static_cast(E->base_data); if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) { @@ -2962,7 +2959,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul } #if 0 - // Only keep the 1st N + // Only pair the 1st N; this is the old way, for benchmarking RS::LightType light_type = RSG::light_storage->light_get_type(E->base); switch (light_type) { case RS::LIGHT_OMNI: { @@ -2979,12 +2976,16 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul } #else // Large scores are worse, so linear with distance, inverse with energy and range - //Vector3 light_center = E->transformed_aabb.get_center(); // maybe a bit faster? - Vector3 light_center = E->transform.xform( RSG::light_storage->light_get_aabb(E->base).get_center() ); // should be more accurate - //print_line(vformat("light(%f,%f,%f)", light_center.x, light_center.y, light_center.z)); + Vector3 light_center = E->transformed_aabb.get_center(); // maybe a bit faster? + //Vector3 light_center = E->transform.xform( RSG::light_storage->light_get_aabb(E->base).get_center() ); // should be more accurate + #if 1 float light_range = RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_RANGE); float light_energy = RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_ENERGY); float light_inst_score = mesh_center.distance_to( light_center ) / (0.1f + light_range * light_energy); + #else + // (on my machine this saves about 0.5 us per mesh, probably not worth it...) + float light_inst_score = mesh_center.distance_squared_to( light_center ); + #endif // Keep the best per-light-type RS::LightType light_type = RSG::light_storage->light_get_type(E->base); switch (light_type) { @@ -3030,7 +3031,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul } #endif } - #if 0 + #if 1 { // This block is just for profiling. uint64_t tout = Time::get_singleton()->get_ticks_usec(); From e38c6378d16cd36eb8eb2536a47889951986a33d Mon Sep 17 00:00:00 2001 From: jon1solution <143551917+jon1solution@users.noreply.github.com> Date: Thu, 5 Jun 2025 16:50:36 -0700 Subject: [PATCH 4/7] Takes Max Renderable Lights into account Takes Max Renderable Lights into account. The function clear_light_instances now also reports total_max_lights. Tried processing from cull_result.lights instead of geom->lights, but they are being built up over the life of the function, so the list is incomplete when I need it. (Also the function can be called from multiple threads) --- drivers/gles3/rasterizer_scene_gles3.cpp | 3 +- drivers/gles3/rasterizer_scene_gles3.h | 2 +- .../rendering/dummy/rasterizer_scene_dummy.h | 2 +- .../rendering/renderer_geometry_instance.h | 2 +- .../render_forward_clustered.h | 2 +- .../forward_mobile/render_forward_mobile.cpp | 3 +- .../forward_mobile/render_forward_mobile.h | 2 +- servers/rendering/renderer_scene_cull.cpp | 96 +++++++++++-------- 8 files changed, 66 insertions(+), 46 deletions(-) diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index ea032f688bd8..6dcaa3dbcffb 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -71,12 +71,13 @@ uint32_t RasterizerSceneGLES3::geometry_instance_get_pair_mask() { return ((1 << RS::INSTANCE_LIGHT) | (1 << RS::INSTANCE_REFLECTION_PROBE)); } -uint32_t RasterizerSceneGLES3::GeometryInstanceGLES3::clear_light_instances() +uint32_t RasterizerSceneGLES3::GeometryInstanceGLES3::clear_light_instances( uint32_t &total_max_lights ) { paired_omni_light_count = 0; paired_spot_light_count = 0; paired_omni_lights.clear(); paired_spot_lights.clear(); + total_max_lights = GLES3::Config::get_singleton()->max_renderable_lights; return GLES3::Config::get_singleton()->max_lights_per_object; } void RasterizerSceneGLES3::GeometryInstanceGLES3::pair_light_instance( diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index d3d184fb8f8b..8b0b439930a6 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -341,7 +341,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual uint32_t clear_light_instances() override; + virtual uint32_t clear_light_instances(uint32_t &total_max_lights) override; virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h index 17cb51db7d17..33dd21f5db62 100644 --- a/servers/rendering/dummy/rasterizer_scene_dummy.h +++ b/servers/rendering/dummy/rasterizer_scene_dummy.h @@ -66,7 +66,7 @@ class RasterizerSceneDummy : public RendererSceneRender { virtual Transform3D get_transform() override { return Transform3D(); } virtual AABB get_aabb() override { return AABB(); } - virtual uint32_t clear_light_instances() override {return 0;} + virtual uint32_t clear_light_instances(uint32_t &total_max_lights) override {return 0;} virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override {} virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {} virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} diff --git a/servers/rendering/renderer_geometry_instance.h b/servers/rendering/renderer_geometry_instance.h index 9504461c6f10..ce79372e9e31 100644 --- a/servers/rendering/renderer_geometry_instance.h +++ b/servers/rendering/renderer_geometry_instance.h @@ -66,7 +66,7 @@ class RenderGeometryInstance { virtual Transform3D get_transform() = 0; virtual AABB get_aabb() = 0; - virtual uint32_t clear_light_instances() = 0; + virtual uint32_t clear_light_instances(uint32_t &total_max_lights) = 0; virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) = 0; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) = 0; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) = 0; 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 508f0b6379cd..6dbf720c82b2 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -572,7 +572,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual uint32_t clear_light_instances() override {return 0;} + virtual uint32_t clear_light_instances(uint32_t &total_max_lights) override {return 0;} virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override {} virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {} virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} 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 4cf18f4c8148..775e1ae2bef8 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2553,10 +2553,11 @@ uint32_t RenderForwardMobile::geometry_instance_get_pair_mask() { return ((1 << RS::INSTANCE_LIGHT) + (1 << RS::INSTANCE_REFLECTION_PROBE) + (1 << RS::INSTANCE_DECAL)); } -uint32_t RenderForwardMobile::GeometryInstanceForwardMobile::clear_light_instances() +uint32_t RenderForwardMobile::GeometryInstanceForwardMobile::clear_light_instances(uint32_t &total_max_lights) { omni_light_count = 0; spot_light_count = 0; + total_max_lights = get_singleton()->get_max_elements(); return MAX_RDL_CULL; } void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instance( 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 adff1eb1d008..b487b59aed84 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -537,7 +537,7 @@ class RenderForwardMobile : public RendererSceneRenderRD { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual uint32_t clear_light_instances() override; + virtual uint32_t clear_light_instances(uint32_t &total_max_lights) override; virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index fdf14c6fbba4..085e3193d472 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1955,8 +1955,9 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) { // Clear these now because the InstanceData containing the dirty flags is gone InstanceGeometryData *geom = static_cast(p_instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); - - geom->geometry_instance->clear_light_instances(); + + uint32_t dummy_max_light_count = 256; + geom->geometry_instance->clear_light_instances(dummy_max_light_count); geom->geometry_instance->pair_reflection_probe_instances(nullptr, 0); geom->geometry_instance->pair_decal_instances(nullptr, 0); geom->geometry_instance->pair_voxel_gi_instances(nullptr, 0); @@ -2813,6 +2814,7 @@ void RendererSceneCull::_scene_cull_threaded(uint32_t p_thread, CullData *cull_d _scene_cull(*cull_data, scene_cull_result_threads[p_thread], cull_from, cull_to); } +// os.h and time.h are needed for simple profiling info #include "core/os/os.h" #include "core/os/time.h" void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to) { @@ -2936,19 +2938,28 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul InstanceGeometryData *geom = static_cast(idata.instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); // clear any existing light instances for this mesh and return the max count. - uint32_t link_max_count = geom->geometry_instance->clear_light_instances(); + uint32_t total_max_count = 256; + uint32_t link_max_count = geom->geometry_instance->clear_light_instances(total_max_count); if( link_max_count > 0 ) { uint64_t tin = Time::get_singleton()->get_ticks_usec(); // Run through all M lights, but only use a heap to keep track of the best N - uint32_t omni_count = 0, spot_count = 0; + uint32_t omni_count = 0, spot_count = 0, processed_count = 0; LocalVector > omni_score_idx, spot_score_idx; // score, index into the light array omni_score_idx.resize( link_max_count ); spot_score_idx.resize( link_max_count ); SortArray > heapify; bool omni_needs_heap = true, spot_needs_heap = true; Vector3 mesh_center = idata.instance->transformed_aabb.get_center(); + #if 1 + // Run through all lights in the scene (can be more than max_renderable_lights) for (const Instance *E : geom->lights) { + #else + // These are in the correct order, but the list is still being built up [8^/ + uint32_t num_culled_lights = cull_result.lights.size(); + for( uint32_t liidx = 0; liidx < num_culled_lights; ++liidx ) { + const Instance *E = cull_result.lights[ liidx ]; + #endif InstanceLightData *light = static_cast(E->base_data); if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) { continue; @@ -2963,12 +2974,12 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul RS::LightType light_type = RSG::light_storage->light_get_type(E->base); switch (light_type) { case RS::LIGHT_OMNI: { - if( omni_count < link_max_count ) { + if( (omni_count < link_max_count) && (omni_count < total_max_count) ) { geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_count++); } } break; case RS::LIGHT_SPOT: { - if( spot_count < link_max_count ) { + if( (spot_count < link_max_count) && (spot_count < total_max_count) ) { geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_count++); } } break; @@ -2977,7 +2988,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul #else // Large scores are worse, so linear with distance, inverse with energy and range Vector3 light_center = E->transformed_aabb.get_center(); // maybe a bit faster? - //Vector3 light_center = E->transform.xform( RSG::light_storage->light_get_aabb(E->base).get_center() ); // should be more accurate + //Vector3 light_center = E->transform.xform( RSG::light_storage->light_get_aabb(E->base).get_center() ); // maybe a bit more accurate #if 1 float light_range = RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_RANGE); float light_energy = RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_ENERGY); @@ -2990,46 +3001,53 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul RS::LightType light_type = RSG::light_storage->light_get_type(E->base); switch (light_type) { case RS::LIGHT_OMNI: { - if( omni_count < link_max_count ) { - // We have room to just add it, and track the score and where it goes - omni_score_idx[ omni_count ] = Pair(light_inst_score, omni_count); - geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_count++); - } else { - if( omni_needs_heap ) { - // We need to make this a heap one time - heapify.make_heap( 0, link_max_count, &omni_score_idx[0] ); - omni_needs_heap = false; - } - if( light_inst_score < omni_score_idx[ 0 ].first ) { - uint32_t replace_index = omni_score_idx[ 0 ].second; - geom->geometry_instance->pair_light_instance(light->instance, light_type, replace_index); - heapify.adjust_heap( 0, 0, link_max_count, Pair( light_inst_score, replace_index ), - &omni_score_idx[0] ); + if( omni_count < total_max_count ) { + if( omni_count < link_max_count ) { + // We have room to just add it, and track the score and where it goes + omni_score_idx[ omni_count ] = Pair(light_inst_score, omni_count); + geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_count); + } else { + if( omni_needs_heap ) { + // We need to make this a heap one time + heapify.make_heap( 0, link_max_count, &omni_score_idx[0] ); + omni_needs_heap = false; + } + if( light_inst_score < omni_score_idx[ 0 ].first ) { + uint32_t replace_index = omni_score_idx[ 0 ].second; + geom->geometry_instance->pair_light_instance(light->instance, light_type, replace_index); + heapify.adjust_heap( 0, 0, link_max_count, Pair( light_inst_score, replace_index ), + &omni_score_idx[0] ); + } } + ++omni_count; } } break; case RS::LIGHT_SPOT: { - if( spot_count < link_max_count ) { - // We have room to just add it, and track the score and where it goes - spot_score_idx[ spot_count ] = Pair(light_inst_score, spot_count); - geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_count++); - } else { - if( spot_needs_heap ) { - // We need to make this a heap one time - heapify.make_heap( 0, link_max_count, &spot_score_idx[0] ); - spot_needs_heap = false; - } - if( light_inst_score < spot_score_idx[ 0 ].first ) { - uint32_t replace_index = spot_score_idx[ 0 ].second; - geom->geometry_instance->pair_light_instance(light->instance, light_type, replace_index); - heapify.adjust_heap( 0, 0, link_max_count, Pair( light_inst_score, replace_index ), - &spot_score_idx[0] ); + if( spot_count < total_max_count ) { + if( spot_count < link_max_count ) { + // We have room to just add it, and track the score and where it goes + spot_score_idx[ spot_count ] = Pair(light_inst_score, spot_count); + geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_count); + } else { + if( spot_needs_heap ) { + // We need to make this a heap one time + heapify.make_heap( 0, link_max_count, &spot_score_idx[0] ); + spot_needs_heap = false; + } + if( light_inst_score < spot_score_idx[ 0 ].first ) { + uint32_t replace_index = spot_score_idx[ 0 ].second; + geom->geometry_instance->pair_light_instance(light->instance, light_type, replace_index); + heapify.adjust_heap( 0, 0, link_max_count, Pair( light_inst_score, replace_index ), + &spot_score_idx[0] ); + } } + ++spot_count; } } break; default: break; } - #endif + #endif + ++processed_count; } #if 1 { @@ -3038,7 +3056,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul static uint64_t prof_lights = 0; static uint64_t prof_count = 0; static uint64_t prof_us = 0; - prof_lights += geom->lights.size(); + prof_lights += processed_count; prof_us += tout - tin; if( ++prof_count >= 100 ) { From 688f07559de53b7f95b3c8d8ee6a2034199fdbc3 Mon Sep 17 00:00:00 2001 From: jon1solution <143551917+jon1solution@users.noreply.github.com> Date: Fri, 6 Jun 2025 10:38:01 -0700 Subject: [PATCH 5/7] Cleaned out test code. Removed the code I was using for testing and profiling. Changed how clear_light_instances returns the per-mesh and total light count. --- drivers/gles3/rasterizer_scene_gles3.cpp | 6 +- drivers/gles3/rasterizer_scene_gles3.h | 2 +- .../rendering/dummy/rasterizer_scene_dummy.h | 2 +- .../rendering/renderer_geometry_instance.h | 2 +- .../render_forward_clustered.h | 2 +- .../forward_mobile/render_forward_mobile.cpp | 6 +- .../forward_mobile/render_forward_mobile.h | 2 +- servers/rendering/renderer_scene_cull.cpp | 152 +++++------------- 8 files changed, 55 insertions(+), 119 deletions(-) diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 6dcaa3dbcffb..ff0c72d46601 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -71,14 +71,14 @@ uint32_t RasterizerSceneGLES3::geometry_instance_get_pair_mask() { return ((1 << RS::INSTANCE_LIGHT) | (1 << RS::INSTANCE_REFLECTION_PROBE)); } -uint32_t RasterizerSceneGLES3::GeometryInstanceGLES3::clear_light_instances( uint32_t &total_max_lights ) +Pair RasterizerSceneGLES3::GeometryInstanceGLES3::clear_light_instances() { paired_omni_light_count = 0; paired_spot_light_count = 0; paired_omni_lights.clear(); paired_spot_lights.clear(); - total_max_lights = GLES3::Config::get_singleton()->max_renderable_lights; - return GLES3::Config::get_singleton()->max_lights_per_object; + return Pair( (uint32_t)GLES3::Config::get_singleton()->max_lights_per_object, + (uint32_t)GLES3::Config::get_singleton()->max_renderable_lights ); } void RasterizerSceneGLES3::GeometryInstanceGLES3::pair_light_instance( const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx ) diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 8b0b439930a6..94175027a689 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -341,7 +341,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual uint32_t clear_light_instances(uint32_t &total_max_lights) override; + virtual Pair clear_light_instances() override; virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h index 33dd21f5db62..39a6a4204113 100644 --- a/servers/rendering/dummy/rasterizer_scene_dummy.h +++ b/servers/rendering/dummy/rasterizer_scene_dummy.h @@ -66,7 +66,7 @@ class RasterizerSceneDummy : public RendererSceneRender { virtual Transform3D get_transform() override { return Transform3D(); } virtual AABB get_aabb() override { return AABB(); } - virtual uint32_t clear_light_instances(uint32_t &total_max_lights) override {return 0;} + virtual Pair clear_light_instances() override {return Pair((uint32_t)0,(uint32_t)0);} virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override {} virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {} virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} diff --git a/servers/rendering/renderer_geometry_instance.h b/servers/rendering/renderer_geometry_instance.h index ce79372e9e31..272f7f44dfce 100644 --- a/servers/rendering/renderer_geometry_instance.h +++ b/servers/rendering/renderer_geometry_instance.h @@ -66,7 +66,7 @@ class RenderGeometryInstance { virtual Transform3D get_transform() = 0; virtual AABB get_aabb() = 0; - virtual uint32_t clear_light_instances(uint32_t &total_max_lights) = 0; + virtual Pair clear_light_instances() = 0; virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) = 0; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) = 0; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) = 0; 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 6dbf720c82b2..ea87161f8033 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -572,7 +572,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual uint32_t clear_light_instances(uint32_t &total_max_lights) override {return 0;} + virtual Pair clear_light_instances() override {return Pair((uint32_t)0,(uint32_t)0);} virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override {} virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {} virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} 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 775e1ae2bef8..6ac764b411f6 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2553,12 +2553,12 @@ uint32_t RenderForwardMobile::geometry_instance_get_pair_mask() { return ((1 << RS::INSTANCE_LIGHT) + (1 << RS::INSTANCE_REFLECTION_PROBE) + (1 << RS::INSTANCE_DECAL)); } -uint32_t RenderForwardMobile::GeometryInstanceForwardMobile::clear_light_instances(uint32_t &total_max_lights) +Pair RenderForwardMobile::GeometryInstanceForwardMobile::clear_light_instances() { omni_light_count = 0; spot_light_count = 0; - total_max_lights = get_singleton()->get_max_elements(); - return MAX_RDL_CULL; + return Pair( (uint32_t)MAX_RDL_CULL, + (uint32_t)get_singleton()->get_max_elements() ); } void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instance( const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx ) 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 b487b59aed84..fd86233c3dee 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -537,7 +537,7 @@ class RenderForwardMobile : public RendererSceneRenderRD { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual uint32_t clear_light_instances(uint32_t &total_max_lights) override; + virtual Pair clear_light_instances() override; virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 085e3193d472..df5b2ffd4878 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1956,8 +1956,7 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) { InstanceGeometryData *geom = static_cast(p_instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); - uint32_t dummy_max_light_count = 256; - geom->geometry_instance->clear_light_instances(dummy_max_light_count); + geom->geometry_instance->clear_light_instances(); geom->geometry_instance->pair_reflection_probe_instances(nullptr, 0); geom->geometry_instance->pair_decal_instances(nullptr, 0); geom->geometry_instance->pair_voxel_gi_instances(nullptr, 0); @@ -2814,9 +2813,6 @@ void RendererSceneCull::_scene_cull_threaded(uint32_t p_thread, CullData *cull_d _scene_cull(*cull_data, scene_cull_result_threads[p_thread], cull_from, cull_to); } -// os.h and time.h are needed for simple profiling info -#include "core/os/os.h" -#include "core/os/time.h" void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to) { uint64_t frame_number = RSG::rasterizer->get_frame_number(); float lightmap_probe_update_speed = RSG::light_storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time(); @@ -2937,138 +2933,78 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { InstanceGeometryData *geom = static_cast(idata.instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); - // clear any existing light instances for this mesh and return the max count. - uint32_t total_max_count = 256; - uint32_t link_max_count = geom->geometry_instance->clear_light_instances(total_max_count); - if( link_max_count > 0 ) { - uint64_t tin = Time::get_singleton()->get_ticks_usec(); - - // Run through all M lights, but only use a heap to keep track of the best N - uint32_t omni_count = 0, spot_count = 0, processed_count = 0; + // clear any existing light instances for this mesh and return the max count per-mesh, and total (per-scene). + Pair max_per_mesh_total = geom->geometry_instance->clear_light_instances(); + if( (max_per_mesh_total.first > 0) && (max_per_mesh_total.second > 0) ) { + // Run through all M lights, but use a heap to keep track of the best N + uint32_t omni_count = 0, spot_count = 0; LocalVector > omni_score_idx, spot_score_idx; // score, index into the light array - omni_score_idx.resize( link_max_count ); - spot_score_idx.resize( link_max_count ); - SortArray > heapify; + SortArray > heapify; // SortArray has heap functionality in it bool omni_needs_heap = true, spot_needs_heap = true; Vector3 mesh_center = idata.instance->transformed_aabb.get_center(); - #if 1 - // Run through all lights in the scene (can be more than max_renderable_lights) + // Run through all lights in the scene (there might be more than max_renderable_lights) + uint32_t total_omni_count = 0, total_spot_count = 0; for (const Instance *E : geom->lights) { - #else - // These are in the correct order, but the list is still being built up [8^/ - uint32_t num_culled_lights = cull_result.lights.size(); - for( uint32_t liidx = 0; liidx < num_culled_lights; ++liidx ) { - const Instance *E = cull_result.lights[ liidx ]; - #endif - InstanceLightData *light = static_cast(E->base_data); - if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) { - continue; - } - - if ((RSG::light_storage->light_get_bake_mode(E->base) == RS::LIGHT_BAKE_STATIC) && idata.instance->lightmap) { - continue; - } - - #if 0 - // Only pair the 1st N; this is the old way, for benchmarking RS::LightType light_type = RSG::light_storage->light_get_type(E->base); - switch (light_type) { - case RS::LIGHT_OMNI: { - if( (omni_count < link_max_count) && (omni_count < total_max_count) ) { - geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_count++); - } - } break; - case RS::LIGHT_SPOT: { - if( (spot_count < link_max_count) && (spot_count < total_max_count) ) { - geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_count++); - } - } break; - default: break; - } - #else - // Large scores are worse, so linear with distance, inverse with energy and range - Vector3 light_center = E->transformed_aabb.get_center(); // maybe a bit faster? - //Vector3 light_center = E->transform.xform( RSG::light_storage->light_get_aabb(E->base).get_center() ); // maybe a bit more accurate - #if 1 - float light_range = RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_RANGE); - float light_energy = RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_ENERGY); - float light_inst_score = mesh_center.distance_to( light_center ) / (0.1f + light_range * light_energy); - #else - // (on my machine this saves about 0.5 us per mesh, probably not worth it...) - float light_inst_score = mesh_center.distance_squared_to( light_center ); - #endif - // Keep the best per-light-type - RS::LightType light_type = RSG::light_storage->light_get_type(E->base); - switch (light_type) { - case RS::LIGHT_OMNI: { - if( omni_count < total_max_count ) { - if( omni_count < link_max_count ) { + if( ((RS::LIGHT_OMNI == light_type) && (total_omni_count++ < max_per_mesh_total.second)) || + ((RS::LIGHT_SPOT == light_type) && (total_spot_count++ < max_per_mesh_total.second)) ) { + // Cull + if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) { + continue; + } + if ((RSG::light_storage->light_get_bake_mode(E->base) == RS::LIGHT_BAKE_STATIC) && idata.instance->lightmap) { + continue; + } + + InstanceLightData *light = static_cast(E->base_data); + // Large scores are worse, so linear with distance, inverse with energy and range + Vector3 light_center = E->transformed_aabb.get_center(); + float light_range_energy = + RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_RANGE) * + RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_ENERGY); + float light_inst_score = mesh_center.distance_to( light_center ) / MAX(0.01f, light_range_energy); + // Keep the best per-light-type + switch (light_type) { + case RS::LIGHT_OMNI: { + if( omni_count < max_per_mesh_total.first ) { // We have room to just add it, and track the score and where it goes - omni_score_idx[ omni_count ] = Pair(light_inst_score, omni_count); - geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_count); + omni_score_idx.push_back( Pair(light_inst_score, omni_count) ); + geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_count++); } else { if( omni_needs_heap ) { // We need to make this a heap one time - heapify.make_heap( 0, link_max_count, &omni_score_idx[0] ); + heapify.make_heap( 0, omni_count, &omni_score_idx[0] ); omni_needs_heap = false; } if( light_inst_score < omni_score_idx[ 0 ].first ) { uint32_t replace_index = omni_score_idx[ 0 ].second; geom->geometry_instance->pair_light_instance(light->instance, light_type, replace_index); - heapify.adjust_heap( 0, 0, link_max_count, Pair( light_inst_score, replace_index ), - &omni_score_idx[0] ); + heapify.adjust_heap( 0, 0, omni_count, Pair( light_inst_score, replace_index ), &omni_score_idx[0] ); } } - ++omni_count; - } - } break; - case RS::LIGHT_SPOT: { - if( spot_count < total_max_count ) { - if( spot_count < link_max_count ) { + } break; + case RS::LIGHT_SPOT: { + if( spot_count < max_per_mesh_total.first ) { // We have room to just add it, and track the score and where it goes - spot_score_idx[ spot_count ] = Pair(light_inst_score, spot_count); - geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_count); + spot_score_idx.push_back( Pair(light_inst_score, spot_count) ); + geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_count++); } else { if( spot_needs_heap ) { // We need to make this a heap one time - heapify.make_heap( 0, link_max_count, &spot_score_idx[0] ); + heapify.make_heap( 0, spot_count, &spot_score_idx[0] ); spot_needs_heap = false; } if( light_inst_score < spot_score_idx[ 0 ].first ) { uint32_t replace_index = spot_score_idx[ 0 ].second; geom->geometry_instance->pair_light_instance(light->instance, light_type, replace_index); - heapify.adjust_heap( 0, 0, link_max_count, Pair( light_inst_score, replace_index ), - &spot_score_idx[0] ); + heapify.adjust_heap( 0, 0, spot_count, Pair( light_inst_score, replace_index ), &spot_score_idx[0] ); } } - ++spot_count; - } - } break; - default: break; + } break; + default: break; + } } - #endif - ++processed_count; - } - #if 1 - { - // This block is just for profiling. - uint64_t tout = Time::get_singleton()->get_ticks_usec(); - static uint64_t prof_lights = 0; - static uint64_t prof_count = 0; - static uint64_t prof_us = 0; - prof_lights += processed_count; - prof_us += tout - tin; - if( ++prof_count >= 100 ) - { - double lights_per_call = prof_lights; lights_per_call /= prof_count; - double us_per_call = prof_us; us_per_call /= prof_count; - print_line(vformat("modified pair_light_instances avg %1.2f [us] for %1.2f lights", us_per_call, lights_per_call)); - prof_lights = 0; - prof_count = 0; - prof_us = 0; - } } - #endif } idata.flags &= ~InstanceData::FLAG_GEOM_LIGHTING_DIRTY; } From 361c4989010a28c8571a8854a41d6b5260fe8109 Mon Sep 17 00:00:00 2001 From: jon1solution <143551917+jon1solution@users.noreply.github.com> Date: Fri, 6 Jun 2025 12:31:41 -0700 Subject: [PATCH 6/7] Ran clang-format. Ran clang-format on my files. Reverted useless change to .gitignore. --- .gitignore | 2 - drivers/gles3/rasterizer_scene_gles3.cpp | 27 +++++----- drivers/gles3/rasterizer_scene_gles3.h | 2 +- .../rendering/dummy/rasterizer_scene_dummy.h | 2 +- .../rendering/renderer_geometry_instance.h | 2 +- .../render_forward_clustered.h | 2 +- .../forward_mobile/render_forward_mobile.cpp | 30 ++++++----- .../forward_mobile/render_forward_mobile.h | 2 +- servers/rendering/renderer_scene_cull.cpp | 51 ++++++++++--------- 9 files changed, 60 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index b23195683d07..97cf4e625550 100644 --- a/.gitignore +++ b/.gitignore @@ -387,5 +387,3 @@ $RECYCLE.BIN/ *.msp *.lnk *.generated.props -compile debug godot.bat -compile size godot.bat diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index ff0c72d46601..cb9b5f0ddb4d 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -71,37 +71,36 @@ uint32_t RasterizerSceneGLES3::geometry_instance_get_pair_mask() { return ((1 << RS::INSTANCE_LIGHT) | (1 << RS::INSTANCE_REFLECTION_PROBE)); } -Pair RasterizerSceneGLES3::GeometryInstanceGLES3::clear_light_instances() -{ +Pair RasterizerSceneGLES3::GeometryInstanceGLES3::clear_light_instances() { paired_omni_light_count = 0; paired_spot_light_count = 0; paired_omni_lights.clear(); paired_spot_lights.clear(); - return Pair( (uint32_t)GLES3::Config::get_singleton()->max_lights_per_object, - (uint32_t)GLES3::Config::get_singleton()->max_renderable_lights ); + return Pair((uint32_t)GLES3::Config::get_singleton()->max_lights_per_object, + (uint32_t)GLES3::Config::get_singleton()->max_renderable_lights); } void RasterizerSceneGLES3::GeometryInstanceGLES3::pair_light_instance( - const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx ) -{ - if( placement_idx < GLES3::Config::get_singleton()->max_lights_per_object ){ + const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) { + if (placement_idx < GLES3::Config::get_singleton()->max_lights_per_object) { switch (light_type) { case RS::LIGHT_OMNI: { - if( placement_idx >= paired_omni_light_count ) { - paired_omni_lights.push_back( p_light_instance ); + if (placement_idx >= paired_omni_light_count) { + paired_omni_lights.push_back(p_light_instance); ++paired_omni_light_count; } else { - paired_omni_lights[ placement_idx ] = p_light_instance; + paired_omni_lights[placement_idx] = p_light_instance; } } break; case RS::LIGHT_SPOT: { - if( placement_idx >= paired_spot_light_count ) { - paired_spot_lights.push_back( p_light_instance ); + if (placement_idx >= paired_spot_light_count) { + paired_spot_lights.push_back(p_light_instance); ++paired_spot_light_count; } else { - paired_spot_lights[ placement_idx ] = p_light_instance; + paired_spot_lights[placement_idx] = p_light_instance; } } break; - default: break; + default: + break; } } } diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 94175027a689..85ec828675c6 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -341,7 +341,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual Pair clear_light_instances() override; + virtual Pair clear_light_instances() override; virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h index 39a6a4204113..71f122d67f02 100644 --- a/servers/rendering/dummy/rasterizer_scene_dummy.h +++ b/servers/rendering/dummy/rasterizer_scene_dummy.h @@ -66,7 +66,7 @@ class RasterizerSceneDummy : public RendererSceneRender { virtual Transform3D get_transform() override { return Transform3D(); } virtual AABB get_aabb() override { return AABB(); } - virtual Pair clear_light_instances() override {return Pair((uint32_t)0,(uint32_t)0);} + virtual Pair clear_light_instances() override { return Pair((uint32_t)0, (uint32_t)0); } virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override {} virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {} virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} diff --git a/servers/rendering/renderer_geometry_instance.h b/servers/rendering/renderer_geometry_instance.h index 272f7f44dfce..5ec5dea66208 100644 --- a/servers/rendering/renderer_geometry_instance.h +++ b/servers/rendering/renderer_geometry_instance.h @@ -66,7 +66,7 @@ class RenderGeometryInstance { virtual Transform3D get_transform() = 0; virtual AABB get_aabb() = 0; - virtual Pair clear_light_instances() = 0; + virtual Pair clear_light_instances() = 0; virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) = 0; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) = 0; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) = 0; 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 ea87161f8033..fee85fa2e72f 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -572,7 +572,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual Pair clear_light_instances() override {return Pair((uint32_t)0,(uint32_t)0);} + virtual Pair clear_light_instances() override { return Pair((uint32_t)0, (uint32_t)0); } virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override {} virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {} virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} 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 6ac764b411f6..bd1e1cfd52dc 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2553,29 +2553,31 @@ uint32_t RenderForwardMobile::geometry_instance_get_pair_mask() { return ((1 << RS::INSTANCE_LIGHT) + (1 << RS::INSTANCE_REFLECTION_PROBE) + (1 << RS::INSTANCE_DECAL)); } -Pair RenderForwardMobile::GeometryInstanceForwardMobile::clear_light_instances() -{ +Pair RenderForwardMobile::GeometryInstanceForwardMobile::clear_light_instances() { omni_light_count = 0; spot_light_count = 0; - return Pair( (uint32_t)MAX_RDL_CULL, - (uint32_t)get_singleton()->get_max_elements() ); + return Pair((uint32_t)MAX_RDL_CULL, + (uint32_t)get_singleton()->get_max_elements()); } void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instance( - const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx ) -{ - if( placement_idx < (uint32_t)MAX_RDL_CULL ){ - RendererRD::ForwardID light_id = RendererRD::LightStorage::get_singleton()-> - light_instance_get_forward_id(p_light_instance); + const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) { + if (placement_idx < (uint32_t)MAX_RDL_CULL) { + RendererRD::ForwardID light_id = RendererRD::LightStorage::get_singleton()->light_instance_get_forward_id(p_light_instance); switch (light_type) { case RS::LIGHT_OMNI: { - omni_lights[ placement_idx ] = light_id; - if( placement_idx >= omni_light_count ) { omni_light_count = placement_idx + 1; } + omni_lights[placement_idx] = light_id; + if (placement_idx >= omni_light_count) { + omni_light_count = placement_idx + 1; + } } break; case RS::LIGHT_SPOT: { - spot_lights[ placement_idx ] = light_id; - if( placement_idx >= spot_light_count ) { spot_light_count = placement_idx + 1; } + spot_lights[placement_idx] = light_id; + if (placement_idx >= spot_light_count) { + spot_light_count = placement_idx + 1; + } } break; - default: break; + default: + break; } } } 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 fd86233c3dee..8e1f321dcc61 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -537,7 +537,7 @@ class RenderForwardMobile : public RendererSceneRenderRD { virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; - virtual Pair clear_light_instances() override; + virtual Pair clear_light_instances() override; virtual void pair_light_instance(const RID p_light_instance, RS::LightType light_type, uint32_t placement_idx) override; virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index df5b2ffd4878..bfb5c3016feb 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1955,7 +1955,7 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) { // Clear these now because the InstanceData containing the dirty flags is gone InstanceGeometryData *geom = static_cast(p_instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); - + geom->geometry_instance->clear_light_instances(); geom->geometry_instance->pair_reflection_probe_instances(nullptr, 0); geom->geometry_instance->pair_decal_instances(nullptr, 0); @@ -2934,20 +2934,20 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul InstanceGeometryData *geom = static_cast(idata.instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); // clear any existing light instances for this mesh and return the max count per-mesh, and total (per-scene). - Pair max_per_mesh_total = geom->geometry_instance->clear_light_instances(); - if( (max_per_mesh_total.first > 0) && (max_per_mesh_total.second > 0) ) { + Pair max_per_mesh_total = geom->geometry_instance->clear_light_instances(); + if ((max_per_mesh_total.first > 0) && (max_per_mesh_total.second > 0)) { // Run through all M lights, but use a heap to keep track of the best N uint32_t omni_count = 0, spot_count = 0; - LocalVector > omni_score_idx, spot_score_idx; // score, index into the light array - SortArray > heapify; // SortArray has heap functionality in it + LocalVector> omni_score_idx, spot_score_idx; // score, index into the light array + SortArray> heapify; // SortArray has heap functionality in it bool omni_needs_heap = true, spot_needs_heap = true; Vector3 mesh_center = idata.instance->transformed_aabb.get_center(); // Run through all lights in the scene (there might be more than max_renderable_lights) uint32_t total_omni_count = 0, total_spot_count = 0; for (const Instance *E : geom->lights) { RS::LightType light_type = RSG::light_storage->light_get_type(E->base); - if( ((RS::LIGHT_OMNI == light_type) && (total_omni_count++ < max_per_mesh_total.second)) || - ((RS::LIGHT_SPOT == light_type) && (total_spot_count++ < max_per_mesh_total.second)) ) { + if (((RS::LIGHT_OMNI == light_type) && (total_omni_count++ < max_per_mesh_total.second)) || + ((RS::LIGHT_SPOT == light_type) && (total_spot_count++ < max_per_mesh_total.second))) { // Cull if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) { continue; @@ -2955,53 +2955,54 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul if ((RSG::light_storage->light_get_bake_mode(E->base) == RS::LIGHT_BAKE_STATIC) && idata.instance->lightmap) { continue; } - + InstanceLightData *light = static_cast(E->base_data); // Large scores are worse, so linear with distance, inverse with energy and range Vector3 light_center = E->transformed_aabb.get_center(); - float light_range_energy = + float light_range_energy = RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_RANGE) * RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_ENERGY); - float light_inst_score = mesh_center.distance_to( light_center ) / MAX(0.01f, light_range_energy); + float light_inst_score = mesh_center.distance_to(light_center) / MAX(0.01f, light_range_energy); // Keep the best per-light-type switch (light_type) { case RS::LIGHT_OMNI: { - if( omni_count < max_per_mesh_total.first ) { + if (omni_count < max_per_mesh_total.first) { // We have room to just add it, and track the score and where it goes - omni_score_idx.push_back( Pair(light_inst_score, omni_count) ); + omni_score_idx.push_back(Pair(light_inst_score, omni_count)); geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_count++); } else { - if( omni_needs_heap ) { + if (omni_needs_heap) { // We need to make this a heap one time - heapify.make_heap( 0, omni_count, &omni_score_idx[0] ); + heapify.make_heap(0, omni_count, &omni_score_idx[0]); omni_needs_heap = false; } - if( light_inst_score < omni_score_idx[ 0 ].first ) { - uint32_t replace_index = omni_score_idx[ 0 ].second; + if (light_inst_score < omni_score_idx[0].first) { + uint32_t replace_index = omni_score_idx[0].second; geom->geometry_instance->pair_light_instance(light->instance, light_type, replace_index); - heapify.adjust_heap( 0, 0, omni_count, Pair( light_inst_score, replace_index ), &omni_score_idx[0] ); + heapify.adjust_heap(0, 0, omni_count, Pair(light_inst_score, replace_index), &omni_score_idx[0]); } } } break; case RS::LIGHT_SPOT: { - if( spot_count < max_per_mesh_total.first ) { + if (spot_count < max_per_mesh_total.first) { // We have room to just add it, and track the score and where it goes - spot_score_idx.push_back( Pair(light_inst_score, spot_count) ); + spot_score_idx.push_back(Pair(light_inst_score, spot_count)); geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_count++); } else { - if( spot_needs_heap ) { + if (spot_needs_heap) { // We need to make this a heap one time - heapify.make_heap( 0, spot_count, &spot_score_idx[0] ); + heapify.make_heap(0, spot_count, &spot_score_idx[0]); spot_needs_heap = false; } - if( light_inst_score < spot_score_idx[ 0 ].first ) { - uint32_t replace_index = spot_score_idx[ 0 ].second; + if (light_inst_score < spot_score_idx[0].first) { + uint32_t replace_index = spot_score_idx[0].second; geom->geometry_instance->pair_light_instance(light->instance, light_type, replace_index); - heapify.adjust_heap( 0, 0, spot_count, Pair( light_inst_score, replace_index ), &spot_score_idx[0] ); + heapify.adjust_heap(0, 0, spot_count, Pair(light_inst_score, replace_index), &spot_score_idx[0]); } } } break; - default: break; + default: + break; } } } From b1cdbe023e3449bb01822e585154c6853fee6cc1 Mon Sep 17 00:00:00 2001 From: jon1solution <143551917+jon1solution@users.noreply.github.com> Date: Wed, 11 Jun 2025 08:11:35 -0700 Subject: [PATCH 7/7] Apply suggestions from Calinou's code review Co-authored-by: Hugo Locurcio --- servers/rendering/renderer_scene_cull.cpp | 26 ++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index bfb5c3016feb..3cf127c0aee5 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -2933,22 +2933,24 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { InstanceGeometryData *geom = static_cast(idata.instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); - // clear any existing light instances for this mesh and return the max count per-mesh, and total (per-scene). + // Clear any existing light instances for this mesh and return the max count per-mesh, and total (per-scene). Pair max_per_mesh_total = geom->geometry_instance->clear_light_instances(); if ((max_per_mesh_total.first > 0) && (max_per_mesh_total.second > 0)) { - // Run through all M lights, but use a heap to keep track of the best N + // Run through all M lights, but use a heap to keep track of the best N uint32_t omni_count = 0, spot_count = 0; - LocalVector> omni_score_idx, spot_score_idx; // score, index into the light array - SortArray> heapify; // SortArray has heap functionality in it + // Score, index into the light array. + LocalVector> omni_score_idx, spot_score_idx; + // SortArray has heap functionality in it. + SortArray> heapify; bool omni_needs_heap = true, spot_needs_heap = true; Vector3 mesh_center = idata.instance->transformed_aabb.get_center(); - // Run through all lights in the scene (there might be more than max_renderable_lights) + // Run through all lights in the scene (there might be more than max_renderable_lights). uint32_t total_omni_count = 0, total_spot_count = 0; for (const Instance *E : geom->lights) { RS::LightType light_type = RSG::light_storage->light_get_type(E->base); if (((RS::LIGHT_OMNI == light_type) && (total_omni_count++ < max_per_mesh_total.second)) || ((RS::LIGHT_SPOT == light_type) && (total_spot_count++ < max_per_mesh_total.second))) { - // Cull + // Perform culling. if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) { continue; } @@ -2957,22 +2959,22 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul } InstanceLightData *light = static_cast(E->base_data); - // Large scores are worse, so linear with distance, inverse with energy and range + // Large scores are worse, so linear with distance, inverse with energy and range. Vector3 light_center = E->transformed_aabb.get_center(); float light_range_energy = RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_RANGE) * RSG::light_storage->light_get_param(E->base, RS::LightParam::LIGHT_PARAM_ENERGY); float light_inst_score = mesh_center.distance_to(light_center) / MAX(0.01f, light_range_energy); - // Keep the best per-light-type + // Keep the "best" lights on a per-light-type basis. switch (light_type) { case RS::LIGHT_OMNI: { if (omni_count < max_per_mesh_total.first) { - // We have room to just add it, and track the score and where it goes + // We have room to just add it, and track the score and where it goes. omni_score_idx.push_back(Pair(light_inst_score, omni_count)); geom->geometry_instance->pair_light_instance(light->instance, light_type, omni_count++); } else { if (omni_needs_heap) { - // We need to make this a heap one time + // We need to make this a heap one time. heapify.make_heap(0, omni_count, &omni_score_idx[0]); omni_needs_heap = false; } @@ -2985,12 +2987,12 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul } break; case RS::LIGHT_SPOT: { if (spot_count < max_per_mesh_total.first) { - // We have room to just add it, and track the score and where it goes + // We have room to just add it, and track the score and where it goes. spot_score_idx.push_back(Pair(light_inst_score, spot_count)); geom->geometry_instance->pair_light_instance(light->instance, light_type, spot_count++); } else { if (spot_needs_heap) { - // We need to make this a heap one time + // We need to make this a heap one time. heapify.make_heap(0, spot_count, &spot_score_idx[0]); spot_needs_heap = false; }