RenderGraph2: Lights node

This commit is contained in:
Carter Anderson 2020-04-24 15:13:00 -07:00
parent c124cbe22f
commit 06b6ade902
3 changed files with 168 additions and 7 deletions

View file

@ -39,8 +39,7 @@ use self::{
},
render_graph::RenderGraph,
render_resource::{
entity_render_resource_assignments_system,
resource_providers::{LightResourceProvider, UniformResourceProvider},
entity_render_resource_assignments_system, resource_providers::UniformResourceProvider,
AssetBatchers, EntityRenderResourceAssignments, RenderResourceAssignments,
},
shader::{uniforms::StandardMaterial, Shader},
@ -54,7 +53,10 @@ use bevy_window::{WindowCreated, WindowReference, WindowResized};
use pass::PassDescriptor;
use pipeline::pipelines::build_forward_pipeline;
use render_graph_2::{
nodes::{Camera2dNode, CameraNode, PassNode, WindowSwapChainNode, WindowTextureNode, UniformNode},
nodes::{
Camera2dNode, CameraNode, LightsNode, PassNode, UniformNode, WindowSwapChainNode,
WindowTextureNode,
},
RenderGraph2,
};
use render_resource::resource_providers::mesh_resource_provider_system;
@ -77,7 +79,6 @@ impl RenderPlugin {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph
.build(&mut pipelines, &mut shaders)
.add_resource_provider(LightResourceProvider::new(10))
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true));
}
}
@ -123,7 +124,12 @@ impl AppPlugin for RenderPlugin {
let resources = app.resources_mut();
render_graph.add_system_node_named("camera", CameraNode::default(), resources);
render_graph.add_system_node_named("camera2d", Camera2dNode::default(), resources);
render_graph.add_system_node_named("standard_material", UniformNode::<StandardMaterial>::new(true), resources);
render_graph.add_system_node_named(
"standard_material",
UniformNode::<StandardMaterial>::new(true),
resources,
);
render_graph.add_system_node_named("lights", LightsNode::new(10), resources);
render_graph.add_node_named(
"swapchain",
WindowSwapChainNode::new(
@ -185,7 +191,10 @@ impl AppPlugin for RenderPlugin {
// TODO: replace these with "autowire" groups
render_graph.add_node_edge("camera", "main_pass").unwrap();
render_graph.add_node_edge("camera2d", "main_pass").unwrap();
render_graph.add_node_edge("standard_material", "main_pass").unwrap();
render_graph
.add_node_edge("standard_material", "main_pass")
.unwrap();
render_graph.add_node_edge("lights", "main_pass").unwrap();
render_graph
.add_slot_edge(
"swapchain",

View file

@ -4,10 +4,12 @@ mod window_texture_node;
mod window_swapchain_node;
mod pass_node;
mod uniform_node;
mod lights_node;
pub use camera_node::*;
pub use camera2d_node::*;
pub use window_texture_node::*;
pub use window_swapchain_node::*;
pub use pass_node::*;
pub use uniform_node::*;
pub use uniform_node::*;
pub use lights_node::*;

View file

@ -0,0 +1,150 @@
use crate::{
render_graph_2::{CommandQueue, Node, ResourceSlots, SystemNode},
render_resource::{resource_name, BufferInfo, BufferUsage, RenderResourceAssignments},
renderer_2::{GlobalRenderResourceContext, RenderContext},
Light, LightRaw,
};
use bevy_transform::prelude::*;
use legion::prelude::*;
use zerocopy::AsBytes;
#[derive(Default)]
pub struct LightsNode {
command_queue: CommandQueue,
max_lights: usize,
}
impl LightsNode {
pub fn new(max_lights: usize) -> Self {
LightsNode {
max_lights,
command_queue: CommandQueue::default(),
}
}
}
impl Node for LightsNode {
fn update(
&mut self,
_world: &World,
_resources: &Resources,
render_context: &mut dyn RenderContext,
_input: &ResourceSlots,
_output: &mut ResourceSlots,
) {
self.command_queue.execute(render_context);
}
}
#[repr(C)]
#[derive(Clone, Copy, AsBytes)]
pub struct LightCount {
pub num_lights: [u32; 4],
}
impl SystemNode for LightsNode {
fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable> {
let mut light_buffer = None;
let mut lights_are_dirty = true;
// TODO: merge these
let mut tmp_count_buffer = None;
let mut tmp_light_buffer = None;
let mut command_queue = self.command_queue.clone();
let max_lights = self.max_lights;
SystemBuilder::new("light_node")
.read_resource::<GlobalRenderResourceContext>()
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
.write_resource::<RenderResourceAssignments>()
.with_query(<(Read<Light>, Read<LocalToWorld>, Read<Translation>)>::query())
.build(
move |_,
world,
(render_resource_context, ref mut render_resource_assignments),
query| {
if !lights_are_dirty {
return;
}
let render_resources = &render_resource_context.context;
if light_buffer.is_none() {
let light_uniform_size = std::mem::size_of::<LightCount>()
+ max_lights * std::mem::size_of::<LightRaw>();
let buffer = render_resources.create_buffer(BufferInfo {
size: light_uniform_size,
buffer_usage: BufferUsage::UNIFORM
| BufferUsage::COPY_SRC
| BufferUsage::COPY_DST,
..Default::default()
});
render_resource_assignments.set(resource_name::uniform::LIGHTS, buffer);
light_buffer = Some(buffer);
}
let light_count = query.iter(world).count();
if light_count == 0 {
return;
}
lights_are_dirty = false;
let size = std::mem::size_of::<LightRaw>();
let total_size = size * light_count;
let light_count_size = std::mem::size_of::<LightCount>();
if let Some(old_tmp_light_buffer) = tmp_light_buffer {
render_resources.remove_buffer(old_tmp_light_buffer);
}
if let Some(old_tmp_count_buffer) = tmp_count_buffer {
render_resources.remove_buffer(old_tmp_count_buffer);
}
tmp_light_buffer = Some(render_resources.create_buffer_mapped(
BufferInfo {
size: total_size,
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&mut |data, _renderer| {
for ((light, local_to_world, translation), slot) in
query.iter(world).zip(data.chunks_exact_mut(size))
{
slot.copy_from_slice(
LightRaw::from(&light, &local_to_world.0, &translation)
.as_bytes(),
);
}
},
));
tmp_count_buffer = Some(render_resources.create_buffer_mapped(
BufferInfo {
size: light_count_size,
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&mut |data, _renderer| {
data.copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
},
));
command_queue.copy_buffer_to_buffer(
tmp_count_buffer.unwrap(),
0,
light_buffer.unwrap(),
0,
light_count_size as u64,
);
command_queue.copy_buffer_to_buffer(
tmp_light_buffer.unwrap(),
0,
light_buffer.unwrap(),
light_count_size as u64,
total_size as u64,
);
},
)
}
}