Skip to content

Commit

Permalink
Bind point light counts
Browse files Browse the repository at this point in the history
Once space is allocated in a buffer, it's allocated. Despawning a light
doesn't clear the memory in the binding, unless we make a new binding.

Prior to this change, despawning a light could have it hang around, still
in memory.

This change adds a separate binding to track the number of active point
lights, and uses the number to iterate through the point light buffer,
ensuring we won't over step.
  • Loading branch information
jgayfer committed Aug 18, 2024
1 parent 8548a55 commit f93ca9b
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 18 deletions.
6 changes: 4 additions & 2 deletions src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use crate::{
ExtractedAmbientLight2d, ExtractedLightOccluder2d, ExtractedPointLight2d,
},
light_map::{
prepare_light_map_texture, LightMapNode, LightMapPass, LightMapPipeline,
LIGHT_MAP_SHADER,
prepare_light_map_texture, prepare_point_light_count, LightMapNode, LightMapPass,
LightMapPipeline, PointLightCount, LIGHT_MAP_SHADER,
},
lighting::{
prepare_lighting_pipelines, LightingNode, LightingPass, LightingPipeline,
Expand Down Expand Up @@ -83,6 +83,7 @@ impl Plugin for Light2dPlugin {

render_app
.init_resource::<SpecializedRenderPipelines<LightingPipeline>>()
.init_resource::<PointLightCount>()
.add_systems(
ExtractSchedule,
(
Expand All @@ -95,6 +96,7 @@ impl Plugin for Light2dPlugin {
Render,
(
prepare_lighting_pipelines.in_set(RenderSet::Prepare),
prepare_point_light_count.in_set(RenderSet::Prepare),
prepare_sdf_texture
.after(prepare_view_targets)
.in_set(RenderSet::ManageViews),
Expand Down
13 changes: 4 additions & 9 deletions src/render/light_map/light_map.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ var<uniform> ambient_light: AmbientLight2d;
#endif

@group(0) @binding(3)
var sdf: texture_2d<f32>;
var<uniform> point_light_count: u32;

@group(0) @binding(4)
var sdf: texture_2d<f32>;

@group(0) @binding(5)
var sdf_sampler: sampler;

@fragment
Expand All @@ -45,14 +48,6 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {

var lighting_color = vec3(1.0);

// WebGL2 does not support storage buffers (or runtime sized arrays), so we
// need to use a fixed number of point lights.
#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
let point_light_count = arrayLength(&point_lights);
#else
let point_light_count = MAX_POINT_LIGHTS;
#endif

for (var i = 0u; i < point_light_count; i++) {
let light = point_lights[i];
let dist = distance(light.center, pos);
Expand Down
15 changes: 12 additions & 3 deletions src/render/light_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ mod prepare;

use bevy::{
asset::Handle,
ecs::component::Component,
render::{render_graph::RenderLabel, render_resource::Shader, texture::CachedTexture},
ecs::{component::Component, system::Resource},
render::{
render_graph::RenderLabel,
render_resource::{Shader, UniformBuffer},
texture::CachedTexture,
},
};

pub use node::LightMapNode;
pub use pipeline::LightMapPipeline;
pub use prepare::prepare_light_map_texture;
pub use prepare::{prepare_light_map_texture, prepare_point_light_count};

pub const LIGHT_MAP_SHADER: Handle<Shader> =
Handle::weak_from_u128(320609826414128764415270070474935914193);
Expand All @@ -22,3 +26,8 @@ pub struct LightMapPass;
pub struct LightMapTexture {
pub light_map: CachedTexture,
}

#[derive(Resource, Default)]
pub struct PointLightCount {
pub buffer: UniformBuffer<u32>,
}
5 changes: 4 additions & 1 deletion src/render/light_map/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use smallvec::{smallvec, SmallVec};
use crate::render::extract::{ExtractedAmbientLight2d, ExtractedPointLight2d};
use crate::render::sdf::SdfTexture;

use super::{LightMapPipeline, LightMapTexture};
use super::{LightMapPipeline, LightMapTexture, PointLightCount};

const LIGHT_MAP_PASS: &str = "light_map_pass";
const LIGHT_MAP_BIND_GROUP: &str = "light_map_bind_group";
Expand Down Expand Up @@ -48,6 +48,7 @@ impl ViewNode for LightMapNode {
Some(view_uniform_binding),
Some(ambient_light_uniform),
Some(point_light_binding),
Some(point_light_count_binding),
) = (
pipeline_cache.get_render_pipeline(light_map_pipeline.pipeline_id),
world.resource::<ViewUniforms>().uniforms.binding(),
Expand All @@ -58,6 +59,7 @@ impl ViewNode for LightMapNode {
world
.resource::<GpuArrayBuffer<ExtractedPointLight2d>>()
.binding(),
world.resource::<PointLightCount>().buffer.binding(),
)
else {
return Ok(());
Expand All @@ -70,6 +72,7 @@ impl ViewNode for LightMapNode {
view_uniform_binding.clone(),
ambient_light_uniform.clone(),
point_light_binding.clone(),
point_light_count_binding.clone(),
&sdf_texture.sdf.default_view,
&light_map_pipeline.sdf_sampler,
)),
Expand Down
1 change: 1 addition & 0 deletions src/render/light_map/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ impl FromWorld for LightMapPipeline {
uniform_buffer::<ViewUniform>(true),
uniform_buffer::<ExtractedAmbientLight2d>(true),
GpuArrayBuffer::<ExtractedPointLight2d>::binding_layout(render_device),
uniform_buffer::<u32>(false),
texture_2d(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
),
Expand Down
27 changes: 24 additions & 3 deletions src/render/light_map/prepare.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
use std::borrow::BorrowMut;

Check failure on line 1 in src/render/light_map/prepare.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `std::borrow::BorrowMut`

Check warning on line 1 in src/render/light_map/prepare.rs

View workflow job for this annotation

GitHub Actions / check

unused import: `std::borrow::BorrowMut`

Check warning on line 1 in src/render/light_map/prepare.rs

View workflow job for this annotation

GitHub Actions / check

unused import: `std::borrow::BorrowMut`

Check failure on line 1 in src/render/light_map/prepare.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `std::borrow::BorrowMut`

use bevy::{
a11y::accesskit::Point,

Check failure on line 4 in src/render/light_map/prepare.rs

View workflow job for this annotation

GitHub Actions / clippy

unused imports: `UniformBuffer` and `a11y::accesskit::Point`

Check warning on line 4 in src/render/light_map/prepare.rs

View workflow job for this annotation

GitHub Actions / check

unused imports: `UniformBuffer` and `a11y::accesskit::Point`

Check warning on line 4 in src/render/light_map/prepare.rs

View workflow job for this annotation

GitHub Actions / check

unused imports: `UniformBuffer` and `a11y::accesskit::Point`

Check failure on line 4 in src/render/light_map/prepare.rs

View workflow job for this annotation

GitHub Actions / clippy

unused imports: `UniformBuffer` and `a11y::accesskit::Point`
ecs::{
entity::Entity,
system::{Commands, Query, Res, ResMut},
},
render::{
render_resource::{TextureDescriptor, TextureDimension, TextureFormat, TextureUsages},
renderer::RenderDevice,
render_resource::{
TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, UniformBuffer,
},
renderer::{RenderDevice, RenderQueue},
texture::TextureCache,
view::ViewTarget,
},
};

use super::LightMapTexture;
use crate::render::extract::ExtractedPointLight2d;

use super::{LightMapTexture, PointLightCount};

const LIGHT_MAP_TEXTURE: &str = "light_map_texture";

Expand Down Expand Up @@ -41,3 +48,17 @@ pub fn prepare_light_map_texture(
});
}
}

pub fn prepare_point_light_count(
render_device: Res<RenderDevice>,
render_queue: Res<RenderQueue>,
point_lights: Query<&ExtractedPointLight2d>,
mut point_light_count: ResMut<PointLightCount>,
) {
point_light_count
.buffer
.set(point_lights.iter().count() as u32);
point_light_count
.buffer
.write_buffer(&render_device, &render_queue);
}

0 comments on commit f93ca9b

Please sign in to comment.