render: get sub render graphs working and create a simple test of them
This commit is contained in:
parent
5f1a61ef52
commit
6c1bff5768
|
@ -20,7 +20,7 @@ pub use render_target::*;
|
|||
|
||||
use rustc_hash::FxHashMap;
|
||||
use tracing::{debug_span, instrument, trace, warn};
|
||||
use wgpu::ComputePass;
|
||||
use wgpu::{CommandEncoder, ComputePass};
|
||||
|
||||
use super::resource::{ComputePipeline, Pipeline, RenderPipeline};
|
||||
|
||||
|
@ -90,6 +90,7 @@ struct PassEntry {
|
|||
pipeline: Rc<RefCell<Option<PipelineResource>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BindGroupEntry {
|
||||
pub label: RenderGraphLabelValue,
|
||||
/// BindGroup
|
||||
|
@ -99,6 +100,7 @@ pub struct BindGroupEntry {
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone)]
|
||||
struct ResourcedSlot {
|
||||
label: RenderGraphLabelValue,
|
||||
ty: SlotType,
|
||||
|
@ -255,6 +257,10 @@ impl RenderGraph {
|
|||
*pipeline = Some(res);
|
||||
}
|
||||
}
|
||||
|
||||
for sub in self.sub_graphs.values_mut() {
|
||||
sub.setup(device);
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self, world))]
|
||||
|
@ -306,6 +312,12 @@ impl RenderGraph {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_encoder(&self) -> CommandEncoder {
|
||||
self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
label: Some("graph encoder"),
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub fn render(&mut self) {
|
||||
let mut sorted: VecDeque<RenderGraphLabelValue> = petgraph::algo::toposort(&self.node_graph, None)
|
||||
|
@ -313,9 +325,14 @@ impl RenderGraph {
|
|||
.iter()
|
||||
.map(|i| self.node_graph[i.clone()].clone())
|
||||
.collect();
|
||||
//debug!("Render graph execution order: {:?}", sorted);
|
||||
|
||||
let mut encoders = Vec::with_capacity(self.nodes.len() / 2);
|
||||
// A bit of 'encoder hot potato' is played using this.
|
||||
// Although the encoder is an option, its only an option so ownership of it can be given
|
||||
// to the context for the time of the node execution.
|
||||
// After the node is executed, the encoder is taken back. If the node is a presenter node,
|
||||
// the encoder will be submitted and a new one will be made.
|
||||
let mut encoder = Some(self.create_encoder());
|
||||
|
||||
while let Some(pass_label) = sorted.pop_front() {
|
||||
let pass = self.nodes.get(&pass_label).unwrap();
|
||||
let pass_inn = pass.inner.clone();
|
||||
|
@ -323,48 +340,37 @@ impl RenderGraph {
|
|||
let pass_desc = pass.desc.clone();
|
||||
let pass_desc = (*pass_desc).borrow();
|
||||
|
||||
let label = format!("{:?} Encoder", pass_label.0);
|
||||
|
||||
// encoders are not needed for presenter nodes.
|
||||
let encoder = if pass_desc.ty.should_have_pipeline() {
|
||||
Some(
|
||||
self.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
label: Some(&label),
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// clone of the Rc's is required to appease the borrow checker
|
||||
let device = self.device.clone();
|
||||
let queue = self.queue.clone();
|
||||
let mut context = RenderGraphContext::new(device, queue, encoder, pass_label.clone());
|
||||
|
||||
// create a new encoder since the last one was presented
|
||||
if encoder.is_none() {
|
||||
encoder = Some(self.create_encoder());
|
||||
}
|
||||
|
||||
// all encoders need to be submitted before a presenter node is executed.
|
||||
if pass_desc.ty == NodeType::Presenter {
|
||||
trace!("Submitting {} encoderd before presenting", encoders.len());
|
||||
self.queue.submit(encoders.drain(..));
|
||||
trace!("Submitting encoder before presenting");
|
||||
|
||||
let finished = encoder.take().unwrap().finish();
|
||||
self.queue.submit(std::iter::once(finished));
|
||||
|
||||
// Do not create a new encoder yet since this node may be the last node.
|
||||
// A new encoder can be made on the next iteration of this loop.
|
||||
}
|
||||
|
||||
let mut context = RenderGraphContext::new(device, queue, encoder.take(), pass_label.clone());
|
||||
|
||||
trace!("Executing {:?}", pass_label.0);
|
||||
let mut inner = pass_inn.borrow_mut();
|
||||
inner.execute(self, &pass_desc, &mut context);
|
||||
|
||||
if let Some(encoder) = context.encoder {
|
||||
encoders.push(encoder.finish());
|
||||
}
|
||||
encoder = context.encoder;
|
||||
}
|
||||
|
||||
if !encoders.is_empty() {
|
||||
warn!(
|
||||
"{} encoders were not submitted in the same render cycle they were created. \
|
||||
Make sure there is a presenting pass at the end. You may still see something, \
|
||||
however it will be delayed a render cycle.",
|
||||
encoders.len()
|
||||
);
|
||||
self.queue.submit(encoders.into_iter());
|
||||
if let Some(encoder) = encoder {
|
||||
self.queue.submit(std::iter::once(encoder.finish()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,8 +416,9 @@ impl RenderGraph {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn bind_group_layout<L: Into<RenderGraphLabelValue>>(&self, label: L) -> &Rc<wgpu::BindGroupLayout> {
|
||||
self.try_bind_group_layout(label)
|
||||
.expect("Unknown id for bind group layout")
|
||||
let l = label.into();
|
||||
self.try_bind_group_layout(l.clone())
|
||||
.unwrap_or_else(|| panic!("Unknown label '{:?}' for bind group layout", l.clone()))
|
||||
}
|
||||
|
||||
pub fn add_edge(&mut self, from: impl RenderGraphLabel, to: impl RenderGraphLabel)
|
||||
|
@ -478,9 +485,67 @@ impl RenderGraph {
|
|||
pub fn sub_graph_mut<L: Into<RenderGraphLabelValue>>(&mut self, label: L) -> Option<&mut RenderGraph> {
|
||||
self.sub_graphs.get_mut(&label.into())
|
||||
}
|
||||
|
||||
pub fn add_sub_graph<L: Into<RenderGraphLabelValue>>(&mut self, label: L, sub: RenderGraph) {
|
||||
self.sub_graphs.insert(label.into(), sub);
|
||||
}
|
||||
|
||||
/// Clone rendering resources (slots, bind groups, etc.) to a sub graph.
|
||||
fn clone_resources_to_sub(&mut self, sub_graph: RenderGraphLabelValue, slots: Vec<RenderGraphLabelValue>) {
|
||||
// instead of inserting the slots to the sub graph as they are extracted from the parent graph,
|
||||
// they are done separately to make the borrow checker happy. If this is not done,
|
||||
// the borrow checker complains about multiple mutable borrows (or an inmutable borrow
|
||||
// while mutable borrowing) to self; caused by borrowing the sub graph from self, and
|
||||
// self.slots.
|
||||
let mut collected_slots = VecDeque::new();
|
||||
let mut collected_bind_groups = VecDeque::new();
|
||||
|
||||
for slot in slots.iter() {
|
||||
let mut found_res = false;
|
||||
|
||||
// Since slots and bind groups may go by the same label,
|
||||
// there must be a way to collect both of them. A flag variable is used to detect
|
||||
// if neither was found.
|
||||
|
||||
if let Some(slot_res) = self.slots.get(slot) {
|
||||
collected_slots.push_back(slot_res.clone());
|
||||
found_res = true;
|
||||
}
|
||||
|
||||
if let Some(bg_res) = self.bind_groups.get(slot) {
|
||||
collected_bind_groups.push_back(bg_res.clone());
|
||||
found_res = true;
|
||||
}
|
||||
|
||||
if !found_res {
|
||||
panic!("sub graph is missing {:?} input slot or bind group", slot);
|
||||
}
|
||||
}
|
||||
|
||||
let sg = self.sub_graph_mut(sub_graph.clone()).unwrap();
|
||||
while let Some(res) = collected_slots.pop_front() {
|
||||
sg.slots.insert(res.label.clone(), res);
|
||||
}
|
||||
|
||||
while let Some(bg) = collected_bind_groups.pop_front() {
|
||||
sg.bind_groups.insert(bg.label.clone(), bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SubGraphNode(RenderGraphLabelValue);
|
||||
pub struct SubGraphNode {
|
||||
subg: RenderGraphLabelValue,
|
||||
slots: Vec<RenderGraphLabelValue>,
|
||||
}
|
||||
|
||||
impl SubGraphNode {
|
||||
pub fn new<L: Into<RenderGraphLabelValue>>(sub_label: L, slot_labels: Vec<RenderGraphLabelValue>) -> Self {
|
||||
Self {
|
||||
subg: sub_label.into(),
|
||||
slots: slot_labels,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for SubGraphNode {
|
||||
fn desc<'a, 'b>(&'a mut self, _: &'b mut RenderGraph) -> NodeDesc {
|
||||
|
@ -488,8 +553,10 @@ impl Node for SubGraphNode {
|
|||
}
|
||||
|
||||
fn prepare(&mut self, graph: &mut RenderGraph, world: &mut World, _: &mut RenderGraphContext) {
|
||||
let sg = graph.sub_graph_mut(self.0.clone())
|
||||
.unwrap_or_else(|| panic!("failed to find sub graph for SubGraphNode: {:?}", self.0));
|
||||
graph.clone_resources_to_sub(self.subg.clone(), self.slots.clone());
|
||||
|
||||
let sg = graph.sub_graph_mut(self.subg.clone())
|
||||
.unwrap_or_else(|| panic!("failed to find sub graph for SubGraphNode: {:?}", self.subg));
|
||||
sg.prepare(world);
|
||||
}
|
||||
|
||||
|
@ -499,8 +566,10 @@ impl Node for SubGraphNode {
|
|||
_: &NodeDesc,
|
||||
_: &mut RenderGraphContext,
|
||||
) {
|
||||
let sg = graph.sub_graph_mut(self.0.clone())
|
||||
.unwrap_or_else(|| panic!("failed to find sub graph for SubGraphNode: {:?}", self.0));
|
||||
graph.clone_resources_to_sub(self.subg.clone(), self.slots.clone());
|
||||
|
||||
let sg = graph.sub_graph_mut(self.subg.clone())
|
||||
.unwrap_or_else(|| panic!("failed to find sub graph for SubGraphNode: {:?}", self.subg));
|
||||
sg.render();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use wgpu::util::DeviceExt;
|
|||
use crate::render::{
|
||||
graph::{
|
||||
Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext, SlotAttribute, SlotValue
|
||||
}, renderer::ScreenSize, resource::{ComputePipelineDescriptor, PipelineDescriptor, Shader}
|
||||
}, renderer::ScreenSize, resource::{ComputePipeline, ComputePipelineDescriptor, Shader}
|
||||
};
|
||||
|
||||
use super::{BasePassSlots, LightBasePassSlots};
|
||||
|
@ -26,12 +26,14 @@ pub enum LightCullComputePassSlots {
|
|||
|
||||
pub struct LightCullComputePass {
|
||||
workgroup_size: glam::UVec2,
|
||||
pipeline: Option<ComputePipeline>,
|
||||
}
|
||||
|
||||
impl LightCullComputePass {
|
||||
pub fn new(screen_size: winit::dpi::PhysicalSize<u32>) -> Self {
|
||||
Self {
|
||||
workgroup_size: glam::UVec2::new(screen_size.width, screen_size.height),
|
||||
pipeline: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,18 +43,6 @@ impl Node for LightCullComputePass {
|
|||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
) -> crate::render::graph::NodeDesc {
|
||||
let shader = Rc::new(Shader {
|
||||
label: Some("light_cull_comp_shader".into()),
|
||||
source: include_str!("../../shaders/light_cull.comp.wgsl").to_string(),
|
||||
});
|
||||
|
||||
// get the size of the work group for the grid
|
||||
let main_rt = graph
|
||||
.slot_value(BasePassSlots::MainRenderTarget)
|
||||
.and_then(|s| s.as_render_target())
|
||||
.expect("missing main render target");
|
||||
self.workgroup_size = main_rt.size();
|
||||
|
||||
// initialize some buffers with empty data
|
||||
let mut contents = Vec::<u8>::new();
|
||||
let contents_len =
|
||||
|
@ -165,16 +155,16 @@ impl Node for LightCullComputePass {
|
|||
label: Some("light_indices_grid_bind_group"),
|
||||
}));
|
||||
|
||||
drop(main_rt);
|
||||
//drop(main_rt);
|
||||
|
||||
let depth_tex_bgl = graph.bind_group_layout(BasePassSlots::DepthTexture);
|
||||
/* let depth_tex_bgl = graph.bind_group_layout(BasePassSlots::DepthTexture);
|
||||
let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera);
|
||||
let lights_bgl = graph.bind_group_layout(LightBasePassSlots::Lights);
|
||||
let screen_size_bgl = graph.bind_group_layout(BasePassSlots::ScreenSize);
|
||||
let screen_size_bgl = graph.bind_group_layout(BasePassSlots::ScreenSize); */
|
||||
|
||||
let mut desc = NodeDesc::new(
|
||||
NodeType::Compute,
|
||||
Some(PipelineDescriptor::Compute(ComputePipelineDescriptor {
|
||||
/* Some(PipelineDescriptor::Compute(ComputePipelineDescriptor {
|
||||
label: Some("light_cull_pipeline".into()),
|
||||
push_constant_ranges: vec![],
|
||||
layouts: vec![
|
||||
|
@ -186,7 +176,8 @@ impl Node for LightCullComputePass {
|
|||
],
|
||||
shader,
|
||||
shader_entry_point: "cs_main".into(),
|
||||
})),
|
||||
})), */
|
||||
None,
|
||||
vec![(
|
||||
&LightCullComputePassSlots::LightIndicesGridGroup,
|
||||
light_indices_bg,
|
||||
|
@ -194,11 +185,6 @@ impl Node for LightCullComputePass {
|
|||
)],
|
||||
);
|
||||
|
||||
desc.add_texture_view_slot(
|
||||
BasePassSlots::WindowTextureView,
|
||||
SlotAttribute::Input,
|
||||
None,
|
||||
);
|
||||
desc.add_buffer_slot(
|
||||
BasePassSlots::ScreenSize,
|
||||
SlotAttribute::Input,
|
||||
|
@ -214,7 +200,7 @@ impl Node for LightCullComputePass {
|
|||
desc
|
||||
}
|
||||
|
||||
fn prepare(&mut self, _graph: &mut RenderGraph, world: &mut World, context: &mut RenderGraphContext) {
|
||||
fn prepare(&mut self, graph: &mut RenderGraph, world: &mut World, context: &mut RenderGraphContext) {
|
||||
context.queue_buffer_write_with(LightCullComputePassSlots::IndexCounterBuffer, 0, 0);
|
||||
|
||||
let screen_size = world.get_resource::<ScreenSize>();
|
||||
|
@ -222,6 +208,37 @@ impl Node for LightCullComputePass {
|
|||
self.workgroup_size = screen_size.xy();
|
||||
todo!("Resize buffers and other resources");
|
||||
}
|
||||
|
||||
if self.pipeline.is_none() {
|
||||
let device = graph.device();
|
||||
|
||||
let depth_tex_bgl = graph.bind_group_layout(BasePassSlots::DepthTexture);
|
||||
let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera);
|
||||
let lights_bgl = graph.bind_group_layout(LightBasePassSlots::Lights);
|
||||
let screen_size_bgl = graph.bind_group_layout(BasePassSlots::ScreenSize);
|
||||
let light_indices_bg_layout = graph.bind_group_layout(LightCullComputePassSlots::LightIndicesGridGroup);
|
||||
|
||||
let shader = Rc::new(Shader {
|
||||
label: Some("light_cull_comp_shader".into()),
|
||||
source: include_str!("../../shaders/light_cull.comp.wgsl").to_string(),
|
||||
});
|
||||
|
||||
let pipeline = ComputePipeline::create(device, &ComputePipelineDescriptor {
|
||||
label: Some("light_cull_pipeline".into()),
|
||||
push_constant_ranges: vec![],
|
||||
layouts: vec![
|
||||
depth_tex_bgl.clone(),
|
||||
camera_bgl.clone(),
|
||||
lights_bgl.clone(),
|
||||
light_indices_bg_layout.clone(),
|
||||
screen_size_bgl.clone(),
|
||||
],
|
||||
shader,
|
||||
shader_entry_point: "cs_main".into(),
|
||||
});
|
||||
|
||||
self.pipeline = Some(pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
fn execute(
|
||||
|
@ -230,11 +247,7 @@ impl Node for LightCullComputePass {
|
|||
_: &crate::render::graph::NodeDesc,
|
||||
context: &mut RenderGraphContext,
|
||||
) {
|
||||
let label = context.label.clone();
|
||||
|
||||
let pipeline = graph.pipeline(label)
|
||||
.expect("Failed to find Pipeline for LightCullComputePass");
|
||||
let pipeline = pipeline.as_compute();
|
||||
let pipeline = self.pipeline.as_mut().unwrap();
|
||||
|
||||
let mut pass = context.begin_compute_pass(&wgpu::ComputePassDescriptor {
|
||||
label: Some("light_cull_pass"),
|
||||
|
|
|
@ -16,7 +16,7 @@ use crate::{
|
|||
render::{
|
||||
desc_buf_lay::DescVertexBufferLayout, graph::{
|
||||
Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext
|
||||
}, material::{Material, MaterialUniform}, render_buffer::{BufferStorage, BufferWrapper}, render_job::RenderJob, resource::{FragmentState, PipelineDescriptor, RenderPipelineDescriptor, Shader, VertexState}, texture::RenderTexture, transform_buffer_storage::{TransformBuffers, TransformGroup}, vertex::Vertex
|
||||
}, material::{Material, MaterialUniform}, render_buffer::{BufferStorage, BufferWrapper}, render_job::RenderJob, resource::{FragmentState, RenderPipeline, RenderPipelineDescriptor, Shader, VertexState}, texture::RenderTexture, transform_buffer_storage::{TransformBuffers, TransformGroup}, vertex::Vertex
|
||||
},
|
||||
DeltaTime,
|
||||
};
|
||||
|
@ -61,6 +61,9 @@ pub struct MeshPass {
|
|||
entity_meshes: FxHashMap<Entity, uuid::Uuid>,
|
||||
|
||||
default_texture: Option<RenderTexture>,
|
||||
|
||||
pipeline: Option<RenderPipeline>,
|
||||
material_bgl: Option<Rc<wgpu::BindGroupLayout>>,
|
||||
}
|
||||
|
||||
impl MeshPass {
|
||||
|
@ -209,7 +212,7 @@ impl Node for MeshPass {
|
|||
let device = graph.device();
|
||||
|
||||
let transforms = TransformBuffers::new(device);
|
||||
let transform_bgl = transforms.bindgroup_layout.clone();
|
||||
//let transform_bgl = transforms.bindgroup_layout.clone();
|
||||
self.transforms = Some(transforms);
|
||||
|
||||
let texture_bind_group_layout = Rc::new(RenderTexture::create_layout(&device));
|
||||
|
@ -222,6 +225,7 @@ impl Node for MeshPass {
|
|||
.contents(&[MaterialUniform::default()])
|
||||
.finish_parts(device);
|
||||
let material_bgl = Rc::new(material_bgl);
|
||||
self.material_bgl = Some(material_bgl.clone());
|
||||
let material_bg = Rc::new(material_bg);
|
||||
|
||||
self.material_buffer = Some(material_buf);
|
||||
|
@ -231,13 +235,13 @@ impl Node for MeshPass {
|
|||
self.default_texture = Some(RenderTexture::from_bytes(&device, &graph.queue, texture_bind_group_layout.clone(), bytes, "default_texture").unwrap());
|
||||
|
||||
// get surface config format
|
||||
let main_rt = graph.slot_value(BasePassSlots::MainRenderTarget)
|
||||
/* let main_rt = graph.slot_value(BasePassSlots::MainRenderTarget)
|
||||
.and_then(|s| s.as_render_target())
|
||||
.expect("missing main render target");
|
||||
let surface_config_format = main_rt.format();
|
||||
drop(main_rt);
|
||||
drop(main_rt); */
|
||||
|
||||
let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera);
|
||||
/* let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera);
|
||||
let lights_bgl = graph.bind_group_layout(LightBasePassSlots::Lights);
|
||||
let light_grid_bgl = graph
|
||||
.bind_group_layout(LightCullComputePassSlots::LightIndicesGridGroup);
|
||||
|
@ -245,11 +249,12 @@ impl Node for MeshPass {
|
|||
let shader = Rc::new(Shader {
|
||||
label: Some("base_shader".into()),
|
||||
source: include_str!("../../shaders/base.wgsl").to_string(),
|
||||
});
|
||||
}); */
|
||||
|
||||
let desc = NodeDesc::new(
|
||||
NodeType::Render,
|
||||
Some(PipelineDescriptor::Render(RenderPipelineDescriptor {
|
||||
None,
|
||||
/* Some(PipelineDescriptor::Render(RenderPipelineDescriptor {
|
||||
label: Some("meshes".into()),
|
||||
layouts: vec![
|
||||
texture_bind_group_layout.clone(),
|
||||
|
@ -287,7 +292,7 @@ impl Node for MeshPass {
|
|||
primitive: wgpu::PrimitiveState::default(),
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
})),
|
||||
})), */
|
||||
vec![
|
||||
(&MeshesPassSlots::Material, material_bg, Some(material_bgl)),
|
||||
],
|
||||
|
@ -296,8 +301,8 @@ impl Node for MeshPass {
|
|||
desc
|
||||
}
|
||||
|
||||
#[instrument(skip(self, _graph, world, context))]
|
||||
fn prepare(&mut self, _graph: &mut RenderGraph, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) {
|
||||
#[instrument(skip(self, graph, world, context))]
|
||||
fn prepare(&mut self, graph: &mut RenderGraph, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) {
|
||||
let device = &context.device;
|
||||
let queue = &context.queue;
|
||||
let render_limits = device.limits();
|
||||
|
@ -432,6 +437,67 @@ impl Node for MeshPass {
|
|||
|
||||
let transforms = self.transforms.as_mut().unwrap();
|
||||
transforms.send_to_gpu(&queue);
|
||||
|
||||
if self.pipeline.is_none() {
|
||||
let device = graph.device();
|
||||
|
||||
let main_rt = graph.slot_value(BasePassSlots::MainRenderTarget)
|
||||
.and_then(|s| s.as_render_target())
|
||||
.expect("missing main render target");
|
||||
let surface_config_format = main_rt.format();
|
||||
drop(main_rt);
|
||||
|
||||
let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera);
|
||||
let lights_bgl = graph.bind_group_layout(LightBasePassSlots::Lights);
|
||||
let light_grid_bgl = graph
|
||||
.bind_group_layout(LightCullComputePassSlots::LightIndicesGridGroup);
|
||||
|
||||
let shader = Rc::new(Shader {
|
||||
label: Some("base_shader".into()),
|
||||
source: include_str!("../../shaders/base.wgsl").to_string(),
|
||||
});
|
||||
|
||||
self.pipeline = Some(RenderPipeline::create(device, &RenderPipelineDescriptor {
|
||||
label: Some("meshes".into()),
|
||||
layouts: vec![
|
||||
self.texture_bind_group_layout.as_ref().unwrap().clone(),
|
||||
//transform_bgl
|
||||
self.transforms.as_ref().unwrap().bindgroup_layout.clone(),
|
||||
camera_bgl.clone(),
|
||||
lights_bgl.clone(),
|
||||
self.material_bgl.as_ref().unwrap().clone(),
|
||||
self.texture_bind_group_layout.as_ref().unwrap().clone(),
|
||||
light_grid_bgl.clone(),
|
||||
],
|
||||
push_constant_ranges: vec![],
|
||||
vertex: VertexState {
|
||||
module: shader.clone(),
|
||||
entry_point: "vs_main".into(),
|
||||
buffers: vec![
|
||||
Vertex::desc().into(),
|
||||
],
|
||||
},
|
||||
fragment: Some(FragmentState {
|
||||
module: shader,
|
||||
entry_point: "fs_main".into(),
|
||||
targets: vec![Some(wgpu::ColorTargetState {
|
||||
format: surface_config_format,
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: RenderTexture::DEPTH_FORMAT,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::Less,
|
||||
stencil: wgpu::StencilState::default(), // TODO: stencil buffer
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
fn execute(
|
||||
|
@ -466,8 +532,9 @@ impl Node for MeshPass {
|
|||
let material_bg = graph
|
||||
.bind_group(MeshesPassSlots::Material);
|
||||
|
||||
let pipeline = graph.pipeline(context.label.clone())
|
||||
.expect("Failed to find pipeline for MeshPass");
|
||||
/* let pipeline = graph.pipeline(context.label.clone())
|
||||
.expect("Failed to find pipeline for MeshPass"); */
|
||||
let pipeline = self.pipeline.as_ref().unwrap();
|
||||
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("Render Pass"),
|
||||
|
@ -495,7 +562,7 @@ impl Node for MeshPass {
|
|||
}),
|
||||
});
|
||||
|
||||
pass.set_pipeline(&pipeline.as_render());
|
||||
pass.set_pipeline(&pipeline);
|
||||
|
||||
//let material_buffer_bg = self.material_buffer.as_ref().unwrap().bindgroup();
|
||||
let default_texture = self.default_texture.as_ref().unwrap();
|
||||
|
|
|
@ -14,4 +14,7 @@ mod present_pass;
|
|||
pub use present_pass::*;
|
||||
|
||||
mod init;
|
||||
pub use init::*;
|
||||
pub use init::*;
|
||||
|
||||
mod tint;
|
||||
pub use tint::*;
|
|
@ -27,6 +27,25 @@ impl RenderTarget {
|
|||
Self(RenderTargetInner::Surface { surface, config })
|
||||
}
|
||||
|
||||
pub fn new_texture(device: &wgpu::Device, format: wgpu::TextureFormat, size: math::UVec2) -> Self {
|
||||
let tex = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: size.x,
|
||||
height: size.y,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
Self(RenderTargetInner::Texture { texture: Arc::new(tex) })
|
||||
}
|
||||
|
||||
pub fn format(&self) -> wgpu::TextureFormat {
|
||||
match &self.0 {
|
||||
RenderTargetInner::Surface { config, .. } => config.format,
|
||||
|
@ -63,8 +82,10 @@ impl RenderTarget {
|
|||
surface.configure(device, config);
|
||||
},
|
||||
RenderTargetInner::Texture { texture } => {
|
||||
let _ = texture;
|
||||
todo!()
|
||||
let format = texture.format();
|
||||
let size = self.size();
|
||||
|
||||
*self = Self::new_texture(device, format, size);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@ use std::ops::{Deref, DerefMut};
|
|||
use std::sync::Arc;
|
||||
|
||||
use lyra_ecs::World;
|
||||
use lyra_game_derive::RenderGraphLabel;
|
||||
use tracing::{debug, instrument, warn};
|
||||
use winit::window::Window;
|
||||
|
||||
use crate::render::graph::{BasePass, BasePassLabel, BasePassSlots, LightBasePass, LightBasePassLabel, LightCullComputePass, LightCullComputePassLabel, MeshPass, MeshesPassLabel, PresentPass, PresentPassLabel, RenderTarget};
|
||||
use crate::render::graph::{BasePass, BasePassLabel, BasePassSlots, LightBasePass, LightBasePassLabel, LightCullComputePass, LightCullComputePassLabel, MeshPass, MeshesPassLabel, PresentPass, PresentPassLabel, RenderGraphLabelValue, RenderTarget, SubGraphNode, TintPass, TintPassLabel, TintPassSlots};
|
||||
|
||||
use super::graph::RenderGraph;
|
||||
use super::{resource::RenderPipeline, render_job::RenderJob};
|
||||
|
@ -30,6 +31,9 @@ impl DerefMut for ScreenSize {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, RenderGraphLabel)]
|
||||
struct TestSubGraphLabel;
|
||||
|
||||
pub trait Renderer {
|
||||
fn prepare(&mut self, main_world: &mut World);
|
||||
fn render(&mut self) -> Result<(), wgpu::SurfaceError>;
|
||||
|
@ -123,37 +127,99 @@ impl BasicRenderer {
|
|||
let device = Arc::new(device);
|
||||
let queue = Arc::new(queue);
|
||||
|
||||
let mut g = RenderGraph::new(device.clone(), queue.clone());
|
||||
|
||||
let surface_size = wgpu::Extent3d {
|
||||
width: config.width,
|
||||
height: config.height,
|
||||
depth_or_array_layers: 1
|
||||
};
|
||||
let surface_target = RenderTarget::from_surface(surface, config);
|
||||
|
||||
let headless_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("headless_texture"),
|
||||
size: surface_size,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: surface_format,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT // we'll be rendering to it
|
||||
| wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
let headless_target = RenderTarget::from(headless_texture);
|
||||
|
||||
|
||||
let mut main_graph = RenderGraph::new(device.clone(), queue.clone());
|
||||
|
||||
debug!("Adding base pass");
|
||||
main_graph.add_node(BasePassLabel, BasePass::new(surface_target));
|
||||
|
||||
{
|
||||
let mut forward_plus_graph = RenderGraph::new(device.clone(), queue.clone());
|
||||
|
||||
debug!("Adding light base pass");
|
||||
forward_plus_graph.add_node(LightBasePassLabel, LightBasePass::new());
|
||||
|
||||
debug!("Adding light cull compute pass");
|
||||
forward_plus_graph.add_node(LightCullComputePassLabel, LightCullComputePass::new(size));
|
||||
|
||||
debug!("Adding mesh pass");
|
||||
forward_plus_graph.add_node(MeshesPassLabel, MeshPass::new());
|
||||
|
||||
forward_plus_graph.add_edge(LightBasePassLabel, LightCullComputePassLabel);
|
||||
|
||||
main_graph.add_sub_graph(TestSubGraphLabel, forward_plus_graph);
|
||||
main_graph.add_node(TestSubGraphLabel, SubGraphNode::new(TestSubGraphLabel,
|
||||
vec![
|
||||
RenderGraphLabelValue::from(BasePassSlots::WindowTextureView),
|
||||
RenderGraphLabelValue::from(BasePassSlots::MainRenderTarget),
|
||||
RenderGraphLabelValue::from(BasePassSlots::DepthTexture),
|
||||
RenderGraphLabelValue::from(BasePassSlots::DepthTextureView),
|
||||
RenderGraphLabelValue::from(BasePassSlots::Camera),
|
||||
RenderGraphLabelValue::from(BasePassSlots::ScreenSize),
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
let present_pass_label = PresentPassLabel::new(BasePassSlots::Frame);//TintPassSlots::Frame);
|
||||
let p = PresentPass::from_node_label(present_pass_label.clone());
|
||||
main_graph.add_node(p.label.clone(), p);
|
||||
|
||||
main_graph.add_edge(BasePassLabel, TestSubGraphLabel);
|
||||
main_graph.add_edge(TestSubGraphLabel, present_pass_label);
|
||||
|
||||
/* debug!("Adding base pass");
|
||||
g.add_node(BasePassLabel, BasePass::new(surface_target));
|
||||
debug!("Adding light base pass");
|
||||
g.add_node(LightBasePassLabel, LightBasePass::new());
|
||||
debug!("Adding light cull compute pass");
|
||||
g.add_node(LightCullComputePassLabel, LightCullComputePass::new(size));
|
||||
|
||||
//debug!("Adding triangle pass");
|
||||
//g.add_node(TrianglePass::new());
|
||||
|
||||
debug!("Adding mesh pass");
|
||||
g.add_node(MeshesPassLabel, MeshPass::new());
|
||||
|
||||
|
||||
debug!("Adding present pass");
|
||||
let present_pass_label = PresentPassLabel::new(BasePassSlots::Frame);
|
||||
let present_pass_label = PresentPassLabel::new(BasePassSlots::Frame);//TintPassSlots::Frame);
|
||||
let p = PresentPass::from_node_label(present_pass_label.clone());
|
||||
g.add_node(p.label.clone(), p);
|
||||
g.add_node(p.label.clone(), p); */
|
||||
|
||||
g.add_edge(BasePassLabel, LightBasePassLabel);
|
||||
/* debug!("adding tint pass");
|
||||
g.add_node(TintPassLabel, TintPass::new(surface_target));
|
||||
|
||||
g.add_edge(BasePassLabel, TintPassLabel);
|
||||
g.add_edge(LightCullComputePassLabel, TintPassLabel);
|
||||
g.add_edge(MeshesPassLabel, TintPassLabel);
|
||||
|
||||
g.add_edge(TintPassLabel, present_pass_label.clone());
|
||||
*/
|
||||
|
||||
/* g.add_edge(BasePassLabel, LightBasePassLabel);
|
||||
g.add_edge(LightBasePassLabel, LightCullComputePassLabel);
|
||||
g.add_edge(BasePassLabel, MeshesPassLabel);
|
||||
|
||||
// make sure that present runs last
|
||||
g.add_edge(BasePassLabel, present_pass_label.clone());
|
||||
g.add_edge(LightCullComputePassLabel, present_pass_label.clone());
|
||||
g.add_edge(MeshesPassLabel, present_pass_label.clone());
|
||||
g.add_edge(MeshesPassLabel, present_pass_label.clone()); */
|
||||
|
||||
g.setup(&device);
|
||||
main_graph.setup(&device);
|
||||
|
||||
Self {
|
||||
window,
|
||||
|
@ -169,7 +235,7 @@ impl BasicRenderer {
|
|||
render_pipelines: Default::default(),
|
||||
render_jobs: Default::default(),
|
||||
|
||||
graph: g,
|
||||
graph: main_graph,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue