Repository: godotengine/godot
File: servers/rendering/renderer_scene_cull.cpp (C++)

Code before:
							RSG::particles_storage->particles_request_process(idata.base_rid);
							cull_data.cull->lock.unlock();

							RS::get_singleton()->call_on_render_thread(callable_mp_static(&RendererSceneCull::_scene_particles_set_view_axis).bind(idata.base_rid, -cull_data.cam_transform.basis.get_column(2).normalized(), cull_data.cam_transform.basis.get_column(1).normalized()));
							//particles visible? request redraw
							RenderingServerDefault::redraw_request();
						}
					}

					if (idata.parent_array_index != -1) {
						float fade = 1.0f;
						const uint32_t &parent_flags = cull_data.scenario->instance_data[idata.parent_array_index].flags;
						if (parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN) {
							const int32_t &parent_idx = cull_data.scenario->instance_data[idata.parent_array_index].visibility_index;
							fade = cull_data.scenario->instance_visibility[parent_idx].children_fade_alpha;
						}
						idata.instance_geometry->set_parent_fade_alpha(fade);
					}

					if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) {
						InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(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<uint32_t, uint32_t> 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<Pair<float, uint32_t>> omni_score_idx, spot_score_idx; //	score, index into the light array
							SortArray<Pair<float, uint32_t>> 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))) {
									//	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<InstanceLightData *>(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);

Review comment (suggestion):
```suggestion
							// Run through all M lights, but use a heap to keep track of the best N
```

Code after:

					if (base_type == RS::INSTANCE_MESH) {
						mesh_visible = true;
					} else if (base_type == RS::INSTANCE_PARTICLES) {
						//particles visible? process them
						if (RSG::particles_storage->particles_is_inactive(idata.base_rid)) {
							//but if nothing is going on, don't do it.
							keep = false;
						} else {
							cull_data.cull->lock.lock();
							RSG::particles_storage->particles_request_process(idata.base_rid);
							cull_data.cull->lock.unlock();

							RS::get_singleton()->call_on_render_thread(callable_mp_static(&RendererSceneCull::_scene_particles_set_view_axis).bind(idata.base_rid, -cull_data.cam_transform.basis.get_column(2).normalized(), cull_data.cam_transform.basis.get_column(1).normalized()));
							//particles visible? request redraw
							RenderingServerDefault::redraw_request();
						}
					}

					if (idata.parent_array_index != -1) {
						float fade = 1.0f;
						const uint32_t &parent_flags = cull_data.scenario->instance_data[idata.parent_array_index].flags;
						if (parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN) {
							const int32_t &parent_idx = cull_data.scenario->instance_data[idata.parent_array_index].visibility_index;
							fade = cull_data.scenario->instance_visibility[parent_idx].children_fade_alpha;
						}
						idata.instance_geometry->set_parent_fade_alpha(fade);
					}

					if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) {
						InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
						ERR_FAIL_NULL(geom->geometry_instance);
						// Clear any existing light instances for this mesh and find the max count per-mesh, and total (per-scene).
						geom->geometry_instance->clear_light_instances();
						if ((max_lights_per_mesh > 0) && (max_lights_total > 0)) {
							// For the top N lights, track the score and the index into the internal light storage array.
							uint32_t total_omni_count = 0, total_spot_count = 0;
							bool omni_needs_heap = true, spot_needs_heap = true;
							uint32_t omni_count = 0, spot_count = 0;
							omni_score_idx.clear();
							spot_score_idx.clear();
							SortArray<Pair<float, uint32_t>> heapify; // SortArray has heap functions, but no local storage.
							// Iterate over the lights (possibly > max_renderable_lights), keeping the closest to the mesh center.
							Vector3 mesh_center = idata.instance->transformed_aabb.get_center();
							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_lights_total)) ||
										((RS::LIGHT_SPOT == light_type) && (total_spot_count++ < max_lights_total))) {
									// Perform culling.
									if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) {
										continue;