Implement a Render Graph #16

Merged
SeanOMik merged 20 commits from feature/render-graph into main 2024-06-15 22:54:47 +00:00
14 changed files with 317 additions and 289 deletions
Showing only changes of commit ef68b2a4c5 - Show all commits

10
Cargo.lock generated
View File

@ -1867,6 +1867,7 @@ dependencies = [
"instant", "instant",
"itertools 0.11.0", "itertools 0.11.0",
"lyra-ecs", "lyra-ecs",
"lyra-game-derive",
"lyra-math", "lyra-math",
"lyra-reflect", "lyra-reflect",
"lyra-resource", "lyra-resource",
@ -1887,6 +1888,15 @@ dependencies = [
"winit", "winit",
] ]
[[package]]
name = "lyra-game-derive"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.51",
]
[[package]] [[package]]
name = "lyra-math" name = "lyra-math"
version = "0.1.0" version = "0.1.0"

View File

@ -4,6 +4,7 @@ version = "0.0.1"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
lyra-game-derive = { path = "./lyra-game-derive" }
lyra-resource = { path = "../lyra-resource" } lyra-resource = { path = "../lyra-resource" }
lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] } lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] }
lyra-reflect = { path = "../lyra-reflect", features = [ "math" ] } lyra-reflect = { path = "../lyra-reflect", features = [ "math" ] }

View File

@ -0,0 +1,14 @@
[package]
name = "lyra-game-derive"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "1.0.70"
quote = "1.0.33"
syn = "2.0.41"

View File

@ -0,0 +1,35 @@
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(RenderGraphLabel)]
pub fn derive_render_graph_label(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let type_ident = &input.ident;
proc_macro::TokenStream::from(quote! {
impl #impl_generics crate::render::graph::RenderGraphLabel for #type_ident #ty_generics #where_clause {
fn rc_clone(&self) -> std::rc::Rc<dyn crate::render::graph::RenderGraphLabel> {
std::rc::Rc::new(self.clone())
}
/* fn as_dyn(&self) -> &dyn crate::render::graph::RenderGraphLabel {
&self
}
fn as_partial_eq(&self) -> &dyn PartialEq<dyn crate::render::graph::RenderGraphLabel> {
self
} */
fn as_label_hash(&self) -> u64 {
let tyid = ::std::any::TypeId::of::<Self>();
let mut s = ::std::hash::DefaultHasher::new();
::std::hash::Hash::hash(&tyid, &mut s);
::std::hash::Hash::hash(self, &mut s);
::std::hash::Hasher::finish(&s)
}
}
})
}

View File

@ -1,9 +1,6 @@
mod pass; mod pass;
use std::{ use std::{
cell::RefCell, cell::RefCell, collections::{HashMap, VecDeque}, fmt::Debug, hash::Hash, rc::Rc, sync::Arc
collections::{HashMap, VecDeque},
rc::Rc,
sync::Arc,
}; };
use itertools::Itertools; use itertools::Itertools;
@ -22,6 +19,62 @@ use wgpu::ComputePass;
use super::resource::{ComputePipeline, Pipeline, RenderPipeline}; use super::resource::{ComputePipeline, Pipeline, RenderPipeline};
pub trait RenderGraphLabel: Debug + 'static {
fn rc_clone(&self) -> Rc<dyn RenderGraphLabel>;
//fn as_dyn(&self) -> &dyn RenderGraphLabel;
//fn as_partial_eq(&self) -> &dyn PartialEq<dyn RenderGraphLabel>;
fn as_label_hash(&self) -> u64;
fn label_eq_rc(&self, other: &Rc<dyn RenderGraphLabel>) -> bool {
self.as_label_hash() == other.as_label_hash()
}
fn label_eq(&self, other: &dyn RenderGraphLabel) -> bool {
self.as_label_hash() == other.as_label_hash()
}
}
#[derive(Clone)]
pub struct RenderGraphLabelValue(Rc<dyn RenderGraphLabel>);
impl Debug for RenderGraphLabelValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl<L: RenderGraphLabel> From<L> for RenderGraphLabelValue {
fn from(value: L) -> Self {
Self(Rc::new(value))
}
}
impl From<Rc<dyn RenderGraphLabel>> for RenderGraphLabelValue {
fn from(value: Rc<dyn RenderGraphLabel>) -> Self {
Self(value)
}
}
impl From<&Rc<dyn RenderGraphLabel>> for RenderGraphLabelValue {
fn from(value: &Rc<dyn RenderGraphLabel>) -> Self {
Self(value.clone())
}
}
impl Hash for RenderGraphLabelValue {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
state.write_u64(self.0.as_label_hash());
}
}
impl PartialEq for RenderGraphLabelValue {
fn eq(&self, other: &Self) -> bool {
self.0.label_eq_rc(&other.0)
}
}
impl Eq for RenderGraphLabelValue {}
struct PassEntry { struct PassEntry {
inner: Arc<RefCell<dyn RenderGraphPass>>, inner: Arc<RefCell<dyn RenderGraphPass>>,
desc: Arc<RenderGraphPassDesc>, desc: Arc<RenderGraphPassDesc>,
@ -30,7 +83,7 @@ struct PassEntry {
} }
pub struct BindGroupEntry { pub struct BindGroupEntry {
pub name: String, pub label: RenderGraphLabelValue,
/// BindGroup /// BindGroup
pub bg: Rc<wgpu::BindGroup>, pub bg: Rc<wgpu::BindGroup>,
/// BindGroupLayout /// BindGroupLayout
@ -39,7 +92,7 @@ pub struct BindGroupEntry {
#[allow(dead_code)] #[allow(dead_code)]
struct ResourcedSlot { struct ResourcedSlot {
name: String, label: RenderGraphLabelValue,
ty: SlotType, ty: SlotType,
value: SlotValue, value: SlotValue,
} }
@ -64,11 +117,13 @@ pub struct RenderGraph {
device: Rc<wgpu::Device>, device: Rc<wgpu::Device>,
queue: Rc<wgpu::Queue>, queue: Rc<wgpu::Queue>,
slots: FxHashMap<u64, ResourcedSlot>, slots: FxHashMap<u64, ResourcedSlot>,
slot_names: HashMap<String, u64>, /// HashMap used to lookup the slot id using the label's hash
slot_label_lookup: FxHashMap<RenderGraphLabelValue, u64>,
passes: FxHashMap<u64, PassEntry>, passes: FxHashMap<u64, PassEntry>,
// TODO: Use a SlotMap // TODO: Use a SlotMap
bind_groups: FxHashMap<u64, BindGroupEntry>, bind_groups: FxHashMap<u64, BindGroupEntry>,
bind_group_names: HashMap<String, u64>, /// HashMap used to lookup the bind group id using the label's hash
bind_group_names: FxHashMap<RenderGraphLabelValue, u64>,
// TODO: make pipelines a `type` parameter in RenderPasses, // TODO: make pipelines a `type` parameter in RenderPasses,
// then the pipelines can be retrieved via TypeId to the pass. // then the pipelines can be retrieved via TypeId to the pass.
pipelines: FxHashMap<u64, PipelineResource>, pipelines: FxHashMap<u64, PipelineResource>,
@ -83,7 +138,7 @@ impl RenderGraph {
device, device,
queue, queue,
slots: Default::default(), slots: Default::default(),
slot_names: Default::default(), slot_label_lookup: Default::default(),
passes: Default::default(), passes: Default::default(),
bind_groups: Default::default(), bind_groups: Default::default(),
bind_group_names: Default::default(), bind_group_names: Default::default(),
@ -102,8 +157,12 @@ impl RenderGraph {
self.current_id self.current_id
} }
pub fn slot_id(&self, name: &str) -> Option<u64> { pub(crate) fn slot_id_rc(&self, label: &RenderGraphLabelValue) -> Option<u64> {
self.slot_names.get(name).cloned() self.slot_label_lookup.get(&label.clone().into()).cloned()
}
pub fn slot_id(&self, label: &dyn RenderGraphLabel) -> Option<u64> {
self.slot_label_lookup.get(&label.rc_clone().into()).cloned()
} }
#[instrument(skip(self, pass), level = "debug")] #[instrument(skip(self, pass), level = "debug")]
@ -113,19 +172,19 @@ impl RenderGraph {
// collect all the slots of the pass // collect all the slots of the pass
for slot in &mut desc.slots { for slot in &mut desc.slots {
if let Some((id, other)) = self if let Some((id, other)) = self
.slot_names .slot_label_lookup
.get(&slot.name) .get(&slot.label)
.and_then(|id| self.slots.get_mut(id).map(|s| (id, s))) .and_then(|id| self.slots.get_mut(id).map(|s| (id, s)))
{ {
debug_assert_eq!( debug_assert_eq!(
slot.ty, other.ty, slot.ty, other.ty,
"slot {} in pass {} does not match existing slot of same name", "slot {:?} in pass {:?} does not match existing slot of same name",
slot.name, desc.name slot.label, desc.label
); );
trace!( trace!(
"Found existing slot for {}, changing id to {}", "Found existing slot for {:?}, changing id to {}",
slot.name, slot.label,
id id
); );
@ -133,33 +192,33 @@ impl RenderGraph {
slot.id = *id; slot.id = *id;
} else { } else {
debug_assert!(!self.slots.contains_key(&slot.id), debug_assert!(!self.slots.contains_key(&slot.id),
"Reuse of id detected in render graph! Pass: {}, slot: {}", "Reuse of id detected in render graph! Pass: {:?}, slot: {:?}",
desc.name, slot.name, desc.label, slot.label,
); );
let res_slot = ResourcedSlot { let res_slot = ResourcedSlot {
name: slot.name.clone(), label: slot.label.clone(),
ty: slot.ty, ty: slot.ty,
value: slot.value.clone().unwrap_or(SlotValue::None), value: slot.value.clone().unwrap_or(SlotValue::None),
}; };
self.slots.insert(slot.id, res_slot); self.slots.insert(slot.id, res_slot);
self.slot_names.insert(slot.name.clone(), slot.id); self.slot_label_lookup.insert(slot.label.clone(), slot.id);
} }
} }
// get clones of the bind groups and layouts // get clones of the bind groups and layouts
for (name, bg, bgl) in &desc.bind_groups { for (label, bg, bgl) in &desc.bind_groups {
let bg_id = self.next_id(); let bg_id = self.next_id();
self.bind_groups.insert( self.bind_groups.insert(
bg_id, bg_id,
BindGroupEntry { BindGroupEntry {
name: name.clone(), label: label.clone(),
bg: bg.clone(), bg: bg.clone(),
layout: bgl.clone(), layout: bgl.clone(),
}, },
); );
self.bind_group_names.insert(name.clone(), bg_id); self.bind_group_names.insert(label.clone().into(), bg_id);
} }
let index = self.execution_graph.add_node(desc.id); let index = self.execution_graph.add_node(desc.id);
@ -224,15 +283,15 @@ impl RenderGraph {
while let Some(bufwr) = context.buffer_writes.pop_front() { while let Some(bufwr) = context.buffer_writes.pop_front() {
let slot = self let slot = self
.slots .slots
.get(&self.slot_id(&bufwr.target_slot).unwrap()) .get(&self.slot_id_rc(&bufwr.target_slot).unwrap())
.expect(&format!( .expect(&format!(
"Failed to find slot '{}' for buffer write", "Failed to find slot '{:?}' for buffer write",
bufwr.target_slot bufwr.target_slot
)); ));
let buf = slot let buf = slot
.value .value
.as_buffer() .as_buffer()
.expect(&format!("Slot '{}' is not a buffer", bufwr.target_slot)); .expect(&format!("Slot '{:?}' is not a buffer", bufwr.target_slot));
self.queue.write_buffer(buf, bufwr.offset, &bufwr.bytes); self.queue.write_buffer(buf, bufwr.offset, &bufwr.bytes);
} }
@ -248,7 +307,7 @@ impl RenderGraph {
.collect(); .collect();
let path_names = sorted let path_names = sorted
.iter() .iter()
.map(|i| self.pass(*i).unwrap().name.clone()) .map(|i| self.pass(*i).unwrap().label.clone())
.collect_vec(); .collect_vec();
trace!("Render graph execution order: {:?}", path_names); trace!("Render graph execution order: {:?}", path_names);
@ -257,7 +316,7 @@ impl RenderGraph {
let pass = self.passes.get(&pass_id).unwrap(); let pass = self.passes.get(&pass_id).unwrap();
let pass_inn = pass.inner.clone(); let pass_inn = pass.inner.clone();
let pass_desc = pass.desc.clone(); let pass_desc = pass.desc.clone();
let label = format!("{} Encoder", pass_desc.name); let label = format!("{:?} Encoder", pass_desc.label);
// encoders are not needed for presenter nodes. // encoders are not needed for presenter nodes.
let encoder = if pass_desc.pass_type.should_have_pipeline() { let encoder = if pass_desc.pass_type.should_have_pipeline() {
@ -282,7 +341,7 @@ impl RenderGraph {
self.queue.submit(encoders.drain(..)); self.queue.submit(encoders.drain(..));
} }
trace!("Executing {}", pass_desc.name); trace!("Executing {:?}", pass_desc.label);
let mut inner = pass_inn.borrow_mut(); let mut inner = pass_inn.borrow_mut();
inner.execute(self, &*pass_desc, &mut context); inner.execute(self, &*pass_desc, &mut context);
@ -341,24 +400,30 @@ impl RenderGraph {
} }
#[inline(always)] #[inline(always)]
pub fn bind_group_id(&self, name: &str) -> Option<u64> { pub fn bind_group_id(&self, label: &dyn RenderGraphLabel) -> Option<u64> {
self.bind_group_names.get(name).copied() self.bind_group_names.get(&label.rc_clone().into()).copied()
} }
pub fn add_edge(&mut self, from: &str, to: &str) { pub fn add_edge(&mut self, from: impl RenderGraphLabel, to: impl RenderGraphLabel)
{
let from = RenderGraphLabelValue::from(from);
let to = RenderGraphLabelValue::from(to);
let from_idx = self let from_idx = self
.passes .passes
.iter() .iter()
.find(|p| p.1.desc.name == from) .find(|p| p.1.desc.label == from)
.map(|p| p.1.graph_index) .map(|p| p.1.graph_index)
.expect("Failed to find from pass"); .expect("Failed to find from pass");
let to_idx = self let to_idx = self
.passes .passes
.iter() .iter()
.find(|p| p.1.desc.name == to) .find(|p| p.1.desc.label == to)
.map(|p| p.1.graph_index) .map(|p| p.1.graph_index)
.expect("Failed to find to pass"); .expect("Failed to find to pass");
debug_assert_ne!(from_idx, to_idx, "cannot add edges between the same node");
self.execution_graph.add_edge(from_idx, to_idx, ()); self.execution_graph.add_edge(from_idx, to_idx, ());
} }
@ -389,13 +454,13 @@ impl RenderGraph {
pub fn set_bind_groups<'a>( pub fn set_bind_groups<'a>(
&'a self, &'a self,
pass: &mut ComputePass<'a>, pass: &mut ComputePass<'a>,
bind_groups: &[(&str, u32)], bind_groups: &[(&dyn RenderGraphLabel, u32)],
) { ) {
for (name, index) in bind_groups { for (label, index) in bind_groups {
let bg = self let bg = self
.bind_group_id(name) .bind_group_id(*label)
.map(|bgi| self.bind_group(bgi)) .map(|bgi| self.bind_group(bgi))
.expect(&format!("Could not find bind group '{}'", name)); .expect(&format!("Could not find bind group '{:?}'", label));
pass.set_bind_group(*index, bg, &[]); pass.set_bind_group(*index, bg, &[]);
} }
@ -405,7 +470,7 @@ impl RenderGraph {
/// A queued write to a GPU buffer targeting a graph slot. /// A queued write to a GPU buffer targeting a graph slot.
pub(crate) struct GraphBufferWrite { pub(crate) struct GraphBufferWrite {
/// The name of the slot that has the resource that will be written /// The name of the slot that has the resource that will be written
target_slot: String, target_slot: RenderGraphLabelValue,
offset: u64, offset: u64,
bytes: Vec<u8>, bytes: Vec<u8>,
} }
@ -460,9 +525,9 @@ impl<'a> RenderGraphContext<'a> {
/// data will be submitted to the GPU queue right after the prepare stage for all passes /// data will be submitted to the GPU queue right after the prepare stage for all passes
/// is ran. /// is ran.
#[instrument(skip(self, bytes), level="trace", fields(size = bytes.len()))] #[instrument(skip(self, bytes), level="trace", fields(size = bytes.len()))]
pub fn queue_buffer_write(&mut self, target_slot: &str, offset: u64, bytes: &[u8]) { pub fn queue_buffer_write(&mut self, target_slot: impl RenderGraphLabel, offset: u64, bytes: &[u8]) {
self.buffer_writes.push_back(GraphBufferWrite { self.buffer_writes.push_back(GraphBufferWrite {
target_slot: target_slot.to_string(), target_slot: target_slot.into(),
offset, offset,
bytes: bytes.to_vec(), bytes: bytes.to_vec(),
}) })
@ -472,7 +537,7 @@ impl<'a> RenderGraphContext<'a> {
#[instrument(skip(self, bytes), level="trace", fields(size = std::mem::size_of::<T>()))] #[instrument(skip(self, bytes), level="trace", fields(size = std::mem::size_of::<T>()))]
pub fn queue_buffer_write_with<T: bytemuck::NoUninit>( pub fn queue_buffer_write_with<T: bytemuck::NoUninit>(
&mut self, &mut self,
target_slot: &str, target_slot: impl RenderGraphLabel,
offset: u64, offset: u64,
bytes: T, bytes: T,
) { ) {

View File

@ -4,7 +4,7 @@ use lyra_ecs::World;
use crate::render::resource::PipelineDescriptor; use crate::render::resource::PipelineDescriptor;
use super::{RenderGraph, RenderGraphContext, RenderTarget}; use super::{RenderGraph, RenderGraphContext, RenderGraphLabel, RenderGraphLabelValue, RenderTarget};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
pub enum RenderPassType { pub enum RenderPassType {
@ -96,7 +96,7 @@ pub struct RenderPassSlot {
pub ty: SlotType, pub ty: SlotType,
pub attribute: SlotAttribute, pub attribute: SlotAttribute,
pub id: u64, pub id: u64,
pub name: String, pub label: RenderGraphLabelValue,
/// The descriptor of the slot value. /// The descriptor of the slot value.
/// This will be `None` if this slot is an input. /// This will be `None` if this slot is an input.
pub value: Option<SlotValue>, pub value: Option<SlotValue>,
@ -159,36 +159,36 @@ impl RenderGraphPipelineInfo {
pub struct RenderGraphPassDesc { pub struct RenderGraphPassDesc {
pub id: u64, pub id: u64,
pub name: String, pub label: RenderGraphLabelValue,
pub pass_type: RenderPassType, pub pass_type: RenderPassType,
pub slots: Vec<RenderPassSlot>, pub slots: Vec<RenderPassSlot>,
slot_names: HashMap<String, u64>, slot_label_lookup: HashMap<RenderGraphLabelValue, u64>,
pub pipeline_desc: Option<PipelineDescriptor>, pub pipeline_desc: Option<PipelineDescriptor>,
pub bind_groups: Vec<( pub bind_groups: Vec<(
String, RenderGraphLabelValue,
Rc<wgpu::BindGroup>, Rc<wgpu::BindGroup>,
Option<Rc<wgpu::BindGroupLayout>>, Option<Rc<wgpu::BindGroupLayout>>,
)>, )>,
} }
impl RenderGraphPassDesc { impl RenderGraphPassDesc {
pub fn new( pub fn new<L: RenderGraphLabel>(
id: u64, id: u64,
name: &str, label: L,
pass_type: RenderPassType, pass_type: RenderPassType,
pipeline_desc: Option<PipelineDescriptor>, pipeline_desc: Option<PipelineDescriptor>,
bind_groups: Vec<(&str, Rc<wgpu::BindGroup>, Option<Rc<wgpu::BindGroupLayout>>)>, bind_groups: Vec<(&dyn RenderGraphLabel, Rc<wgpu::BindGroup>, Option<Rc<wgpu::BindGroupLayout>>)>,
) -> Self { ) -> Self {
Self { Self {
id, id,
name: name.to_string(), label: label.into(),
pass_type, pass_type,
slots: vec![], slots: vec![],
slot_names: HashMap::default(), slot_label_lookup: HashMap::default(),
pipeline_desc, pipeline_desc,
bind_groups: bind_groups bind_groups: bind_groups
.into_iter() .into_iter()
.map(|bg| (bg.0.to_string(), bg.1, bg.2)) .map(|bg| (bg.0.rc_clone().into(), bg.1, bg.2))
.collect(), .collect(),
} }
} }
@ -199,15 +199,15 @@ impl RenderGraphPassDesc {
"input slots should not have values" "input slots should not have values"
); );
self.slot_names.insert(slot.name.clone(), slot.id); self.slot_label_lookup.insert(slot.label.clone().into(), slot.id);
self.slots.push(slot); self.slots.push(slot);
} }
#[inline(always)] #[inline(always)]
pub fn add_buffer_slot( pub fn add_buffer_slot<L: RenderGraphLabel>(
&mut self, &mut self,
id: u64, id: u64,
name: &str, label: L,
attribute: SlotAttribute, attribute: SlotAttribute,
value: Option<SlotValue>, value: Option<SlotValue>,
) { ) {
@ -218,7 +218,7 @@ impl RenderGraphPassDesc {
let slot = RenderPassSlot { let slot = RenderPassSlot {
id, id,
name: name.to_string(), label: label.into(),
ty: SlotType::Buffer, ty: SlotType::Buffer,
attribute, attribute,
value, value,
@ -227,10 +227,10 @@ impl RenderGraphPassDesc {
} }
#[inline(always)] #[inline(always)]
pub fn add_texture_slot( pub fn add_texture_slot<L: RenderGraphLabel>(
&mut self, &mut self,
id: u64, id: u64,
name: &str, label: L,
attribute: SlotAttribute, attribute: SlotAttribute,
value: Option<SlotValue>, value: Option<SlotValue>,
) { ) {
@ -241,7 +241,7 @@ impl RenderGraphPassDesc {
let slot = RenderPassSlot { let slot = RenderPassSlot {
id, id,
name: name.to_string(), label: label.into(),
ty: SlotType::Texture, ty: SlotType::Texture,
attribute, attribute,
value, value,
@ -250,10 +250,10 @@ impl RenderGraphPassDesc {
} }
#[inline(always)] #[inline(always)]
pub fn add_texture_view_slot( pub fn add_texture_view_slot<L: RenderGraphLabel>(
&mut self, &mut self,
id: u64, id: u64,
name: &str, label: L,
attribute: SlotAttribute, attribute: SlotAttribute,
value: Option<SlotValue>, value: Option<SlotValue>,
) { ) {
@ -264,7 +264,7 @@ impl RenderGraphPassDesc {
let slot = RenderPassSlot { let slot = RenderPassSlot {
id, id,
name: name.to_string(), label: label.into(),
ty: SlotType::TextureView, ty: SlotType::TextureView,
attribute, attribute,
value, value,
@ -273,10 +273,10 @@ impl RenderGraphPassDesc {
} }
#[inline(always)] #[inline(always)]
pub fn add_sampler_slot( pub fn add_sampler_slot<L: RenderGraphLabel>(
&mut self, &mut self,
id: u64, id: u64,
name: &str, label: L,
attribute: SlotAttribute, attribute: SlotAttribute,
value: Option<SlotValue>, value: Option<SlotValue>,
) { ) {
@ -287,7 +287,7 @@ impl RenderGraphPassDesc {
let slot = RenderPassSlot { let slot = RenderPassSlot {
id, id,
name: name.to_string(), label: label.into(),
ty: SlotType::Sampler, ty: SlotType::Sampler,
attribute, attribute,
value, value,

View File

@ -1,6 +1,7 @@
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use glam::UVec2; use glam::UVec2;
use lyra_game_derive::RenderGraphLabel;
use tracing::warn; use tracing::warn;
use winit::dpi::PhysicalSize; use winit::dpi::PhysicalSize;
@ -16,6 +17,19 @@ use crate::{
scene::CameraComponent, scene::CameraComponent,
}; };
#[derive(Debug, Hash, Clone, Default, PartialEq, RenderGraphLabel)]
pub struct BasePassLabel;
#[derive(Debug, Hash, Clone, PartialEq, RenderGraphLabel)]
pub enum BasePassSlots {
DepthTexture,
ScreenSize,
Camera,
MainRenderTarget,
WindowTextureView,
DepthTextureView,
}
/// Supplies some basic things other passes needs. /// Supplies some basic things other passes needs.
/// ///
/// screen size buffer, camera buffer, /// screen size buffer, camera buffer,
@ -89,13 +103,13 @@ impl RenderGraphPass for BasePass {
let mut desc = RenderGraphPassDesc::new( let mut desc = RenderGraphPassDesc::new(
graph.next_id(), graph.next_id(),
"base", BasePassLabel,
RenderPassType::Node, RenderPassType::Node,
None, None,
vec![ vec![
("depth_texture", depth_texture_bg, Some(depth_texture_bgl)), (&BasePassSlots::DepthTexture, depth_texture_bg, Some(depth_texture_bgl)),
("screen_size", screen_size_bg, Some(screen_size_bgl)), (&BasePassSlots::ScreenSize, screen_size_bg, Some(screen_size_bgl)),
("camera", camera_bg, Some(camera_bgl)), (&BasePassSlots::Camera, camera_bg, Some(camera_bgl)),
], ],
); );
@ -104,7 +118,7 @@ impl RenderGraphPass for BasePass {
ty: SlotType::RenderTarget, ty: SlotType::RenderTarget,
attribute: SlotAttribute::Output, attribute: SlotAttribute::Output,
id: self.main_rt_id, id: self.main_rt_id,
name: "main_render_target".into(), label: BasePassSlots::MainRenderTarget.into(),
value: Some(SlotValue::RenderTarget(Rc::new(RefCell::new( value: Some(SlotValue::RenderTarget(Rc::new(RefCell::new(
render_target, render_target,
)))), )))),
@ -112,25 +126,25 @@ impl RenderGraphPass for BasePass {
self.window_tv_id = graph.next_id(); self.window_tv_id = graph.next_id();
desc.add_texture_view_slot( desc.add_texture_view_slot(
self.window_tv_id, self.window_tv_id,
"window_texture_view", BasePassSlots::WindowTextureView,
SlotAttribute::Output, SlotAttribute::Output,
Some(SlotValue::Lazy), Some(SlotValue::Lazy),
); );
desc.add_texture_view_slot( desc.add_texture_view_slot(
graph.next_id(), graph.next_id(),
"depth_texture_view", BasePassSlots::DepthTextureView,
SlotAttribute::Output, SlotAttribute::Output,
Some(SlotValue::TextureView(depth_texture_view)), Some(SlotValue::TextureView(depth_texture_view)),
); );
desc.add_buffer_slot( desc.add_buffer_slot(
graph.next_id(), graph.next_id(),
"screen_size_buffer", BasePassSlots::ScreenSize,
SlotAttribute::Output, SlotAttribute::Output,
Some(SlotValue::Buffer(Rc::new(screen_size_buf))), Some(SlotValue::Buffer(Rc::new(screen_size_buf))),
); );
desc.add_buffer_slot( desc.add_buffer_slot(
graph.next_id(), graph.next_id(),
"camera_buffer", BasePassSlots::Camera,
SlotAttribute::Output, SlotAttribute::Output,
Some(SlotValue::Buffer(Rc::new(camera_buf))), Some(SlotValue::Buffer(Rc::new(camera_buf))),
); );
@ -144,7 +158,7 @@ impl RenderGraphPass for BasePass {
RenderCamera::new(PhysicalSize::new(self.screen_size.x, self.screen_size.y)); RenderCamera::new(PhysicalSize::new(self.screen_size.x, self.screen_size.y));
let uniform = render_cam.calc_view_projection(&camera); let uniform = render_cam.calc_view_projection(&camera);
context.queue_buffer_write_with("camera_buffer", 0, uniform) context.queue_buffer_write_with(BasePassSlots::Camera, 0, uniform)
} else { } else {
warn!("Missing camera!"); warn!("Missing camera!");
} }
@ -170,7 +184,7 @@ impl RenderGraphPass for BasePass {
|| rt.surface_config.height != self.screen_size.y || rt.surface_config.height != self.screen_size.y
{ {
self.screen_size = UVec2::new(rt.surface_config.width, rt.surface_config.height); self.screen_size = UVec2::new(rt.surface_config.width, rt.surface_config.height);
context.queue_buffer_write_with("screen_size_buffer", 0, self.screen_size) context.queue_buffer_write_with(BasePassSlots::ScreenSize, 0, self.screen_size)
} }
let surface_tex = rt.surface.get_current_texture().unwrap(); let surface_tex = rt.surface.get_current_texture().unwrap();

View File

@ -1,3 +1,5 @@
use lyra_game_derive::RenderGraphLabel;
use crate::render::{ use crate::render::{
graph::{ graph::{
RenderGraphContext, RenderGraphPass, RenderGraphPassDesc, RenderPassType, SlotAttribute, RenderGraphContext, RenderGraphPass, RenderGraphPassDesc, RenderPassType, SlotAttribute,
@ -6,6 +8,14 @@ use crate::render::{
light::LightUniformBuffers, light::LightUniformBuffers,
}; };
#[derive(Debug, Hash, Clone, Default, PartialEq, RenderGraphLabel)]
pub struct LightBasePassLabel;
#[derive(Debug, Hash, Clone, PartialEq, RenderGraphLabel)]
pub enum LightBasePassSlots {
Lights
}
/// Supplies some basic things other passes needs. /// Supplies some basic things other passes needs.
/// ///
/// screen size buffer, camera buffer, /// screen size buffer, camera buffer,
@ -31,11 +41,11 @@ impl RenderGraphPass for LightBasePass {
let mut desc = RenderGraphPassDesc::new( let mut desc = RenderGraphPassDesc::new(
graph.next_id(), graph.next_id(),
"light_base", LightBasePassLabel,
RenderPassType::Node, RenderPassType::Node,
None, None,
vec![( vec![(
"light_buffers", &LightBasePassSlots::Lights,
light_buffers.bind_group.clone(), light_buffers.bind_group.clone(),
Some(light_buffers.bind_group_layout.clone()), Some(light_buffers.bind_group_layout.clone()),
)], )],
@ -43,7 +53,7 @@ impl RenderGraphPass for LightBasePass {
desc.add_buffer_slot( desc.add_buffer_slot(
graph.next_id(), graph.next_id(),
"light_buffers", LightBasePassSlots::Lights,
SlotAttribute::Output, SlotAttribute::Output,
Some(SlotValue::Buffer(light_buffers.buffer.clone())), Some(SlotValue::Buffer(light_buffers.buffer.clone())),
); );

View File

@ -1,6 +1,7 @@
use std::{mem, rc::Rc}; use std::{mem, rc::Rc};
use lyra_ecs::World; use lyra_ecs::World;
use lyra_game_derive::RenderGraphLabel;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use crate::render::{ use crate::render::{
@ -11,6 +12,19 @@ use crate::render::{
resource::{ComputePipelineDescriptor, PipelineDescriptor, Shader}, resource::{ComputePipelineDescriptor, PipelineDescriptor, Shader},
}; };
use super::{BasePassSlots, LightBasePassSlots};
#[derive(Debug, Hash, Clone, Default, PartialEq, RenderGraphLabel)]
pub struct LightCullComputePassLabel;
#[derive(Debug, Hash, Clone, PartialEq, RenderGraphLabel)]
pub enum LightCullComputePassSlots {
LightGridTexture,
LightGridTextureView,
IndexCounterBuffer,
LightIndicesGridGroup,
}
pub struct LightCullComputePass { pub struct LightCullComputePass {
workgroup_size: glam::UVec2, workgroup_size: glam::UVec2,
} }
@ -35,7 +49,7 @@ impl RenderGraphPass for LightCullComputePass {
// get the size of the work group for the grid // get the size of the work group for the grid
let main_rt = graph let main_rt = graph
.slot_id("main_render_target") .slot_id(&BasePassSlots::MainRenderTarget)
.and_then(|s| graph.slot_value(s)) .and_then(|s| graph.slot_value(s))
.and_then(|s| s.as_render_target()) .and_then(|s| s.as_render_target())
.expect("missing main render target"); .expect("missing main render target");
@ -157,14 +171,14 @@ impl RenderGraphPass for LightCullComputePass {
drop(main_rt); drop(main_rt);
let pass_id = graph.next_id(); let pass_id = graph.next_id();
let depth_tex_bgl = graph.bind_group_layout(graph.bind_group_id("depth_texture").unwrap()); let depth_tex_bgl = graph.bind_group_layout(graph.bind_group_id(&BasePassSlots::DepthTexture).unwrap());
let camera_bgl = graph.bind_group_layout(graph.bind_group_id("camera").unwrap()); let camera_bgl = graph.bind_group_layout(graph.bind_group_id(&BasePassSlots::Camera).unwrap());
let lights_bgl = graph.bind_group_layout(graph.bind_group_id("light_buffers").unwrap()); let lights_bgl = graph.bind_group_layout(graph.bind_group_id(&LightBasePassSlots::Lights).unwrap());
let screen_size_bgl = graph.bind_group_layout(graph.bind_group_id("screen_size").unwrap()); let screen_size_bgl = graph.bind_group_layout(graph.bind_group_id(&BasePassSlots::ScreenSize).unwrap());
let mut desc = RenderGraphPassDesc::new( let mut desc = RenderGraphPassDesc::new(
pass_id, pass_id,
"light_cull_compute", LightCullComputePassLabel,
RenderPassType::Compute, RenderPassType::Compute,
Some(PipelineDescriptor::Compute(ComputePipelineDescriptor { Some(PipelineDescriptor::Compute(ComputePipelineDescriptor {
label: Some("light_cull_pipeline".into()), label: Some("light_cull_pipeline".into()),
@ -180,7 +194,7 @@ impl RenderGraphPass for LightCullComputePass {
shader_entry_point: "cs_main".into(), shader_entry_point: "cs_main".into(),
})), })),
vec![( vec![(
"light_indices_grid", &LightCullComputePassSlots::LightIndicesGridGroup,
light_indices_bg, light_indices_bg,
Some(light_indices_bg_layout), Some(light_indices_bg_layout),
)], )],
@ -188,20 +202,20 @@ impl RenderGraphPass for LightCullComputePass {
desc.add_texture_view_slot( desc.add_texture_view_slot(
graph.next_id(), graph.next_id(),
"window_texture_view", BasePassSlots::WindowTextureView,
SlotAttribute::Input, SlotAttribute::Input,
None, None,
); );
desc.add_buffer_slot( desc.add_buffer_slot(
graph.next_id(), graph.next_id(),
"screen_size_buffer", BasePassSlots::ScreenSize,
SlotAttribute::Input, SlotAttribute::Input,
None, None,
); );
desc.add_buffer_slot(graph.next_id(), "camera_buffer", SlotAttribute::Input, None); desc.add_buffer_slot(graph.next_id(), BasePassSlots::Camera, SlotAttribute::Input, None);
desc.add_buffer_slot( desc.add_buffer_slot(
graph.next_id(), graph.next_id(),
"index_counter_buffer", LightCullComputePassSlots::IndexCounterBuffer,
SlotAttribute::Output, SlotAttribute::Output,
Some(SlotValue::Buffer(Rc::new(light_index_counter_buffer))), Some(SlotValue::Buffer(Rc::new(light_index_counter_buffer))),
); );
@ -239,11 +253,11 @@ impl RenderGraphPass for LightCullComputePass {
graph.set_bind_groups( graph.set_bind_groups(
&mut pass, &mut pass,
&[ &[
("depth_texture", 0), (&BasePassSlots::DepthTexture, 0),
("camera", 1), (&BasePassSlots::Camera, 1),
("light_buffers", 2), (&LightBasePassSlots::Lights, 2),
("light_indices_grid", 3), (&LightCullComputePassSlots::LightIndicesGridGroup, 3),
("screen_size", 4), (&BasePassSlots::ScreenSize, 4),
], ],
); );

View File

@ -3,6 +3,7 @@ use std::{collections::{HashSet, VecDeque}, rc::Rc};
use glam::Vec3; use glam::Vec3;
use itertools::izip; use itertools::izip;
use lyra_ecs::{query::{filter::{Has, Not, Or}, Entities, Res, TickOf}, relation::{ChildOf, RelationOriginComponent}, Component, Entity}; use lyra_ecs::{query::{filter::{Has, Not, Or}, Entities, Res, TickOf}, relation::{ChildOf, RelationOriginComponent}, Component, Entity};
use lyra_game_derive::RenderGraphLabel;
use lyra_math::Transform; use lyra_math::Transform;
use lyra_resource::{gltf::Mesh, ResHandle}; use lyra_resource::{gltf::Mesh, ResHandle};
use lyra_scene::{SceneGraph, WorldTransform}; use lyra_scene::{SceneGraph, WorldTransform};
@ -21,9 +22,19 @@ use crate::{
DeltaTime, DeltaTime,
}; };
use super::{BasePassSlots, LightBasePassSlots, LightCullComputePassSlots};
type MeshHandle = ResHandle<Mesh>; type MeshHandle = ResHandle<Mesh>;
type SceneHandle = ResHandle<SceneGraph>; type SceneHandle = ResHandle<SceneGraph>;
#[derive(Debug, Hash, Clone, Default, PartialEq, RenderGraphLabel)]
pub struct MeshesPassLabel;
#[derive(Debug, Hash, Clone, PartialEq, RenderGraphLabel)]
pub enum MeshesPassSlots {
Material
}
struct MeshBufferStorage { struct MeshBufferStorage {
buffer_vertex: BufferStorage, buffer_vertex: BufferStorage,
buffer_indices: Option<(wgpu::IndexFormat, BufferStorage)>, buffer_indices: Option<(wgpu::IndexFormat, BufferStorage)>,
@ -221,7 +232,7 @@ impl RenderGraphPass for MeshPass {
self.default_texture = Some(RenderTexture::from_bytes(&device, &graph.queue, texture_bind_group_layout.clone(), bytes, "default_texture").unwrap()); self.default_texture = Some(RenderTexture::from_bytes(&device, &graph.queue, texture_bind_group_layout.clone(), bytes, "default_texture").unwrap());
// get surface config format // get surface config format
let main_rt = graph.slot_id("main_render_target") let main_rt = graph.slot_id(&BasePassSlots::MainRenderTarget)
.and_then(|s| graph.slot_value(s)) .and_then(|s| graph.slot_value(s))
.and_then(|s| s.as_render_target()) .and_then(|s| s.as_render_target())
.expect("missing main render target"); .expect("missing main render target");
@ -231,10 +242,10 @@ impl RenderGraphPass for MeshPass {
// get the id here to make borrow checker happy // get the id here to make borrow checker happy
let pass_id = graph.next_id(); let pass_id = graph.next_id();
let camera_bgl = graph.bind_group_layout(graph.bind_group_id("camera").unwrap()); let camera_bgl = graph.bind_group_layout(graph.bind_group_id(&BasePassSlots::Camera).unwrap());
let lights_bgl = graph.bind_group_layout(graph.bind_group_id("light_buffers").unwrap()); let lights_bgl = graph.bind_group_layout(graph.bind_group_id(&LightBasePassSlots::Lights).unwrap());
let light_grid_bgl = graph let light_grid_bgl = graph
.bind_group_layout(graph.bind_group_id("light_indices_grid") .bind_group_layout(graph.bind_group_id(&LightCullComputePassSlots::LightIndicesGridGroup)
.expect("Missing light grid bind group")); .expect("Missing light grid bind group"));
let shader = Rc::new(Shader { let shader = Rc::new(Shader {
@ -244,7 +255,7 @@ impl RenderGraphPass for MeshPass {
let desc = RenderGraphPassDesc::new( let desc = RenderGraphPassDesc::new(
pass_id, pass_id,
"meshes", MeshesPassLabel,
RenderPassType::Render, RenderPassType::Render,
Some(PipelineDescriptor::Render(RenderPipelineDescriptor { Some(PipelineDescriptor::Render(RenderPipelineDescriptor {
label: Some("meshes".into()), label: Some("meshes".into()),
@ -286,7 +297,7 @@ impl RenderGraphPass for MeshPass {
multiview: None, multiview: None,
})), })),
vec![ vec![
("material", material_bg, Some(material_bgl)), (&MeshesPassSlots::Material, material_bg, Some(material_bgl)),
], ],
); );
@ -440,29 +451,29 @@ impl RenderGraphPass for MeshPass {
let encoder = context.encoder.as_mut().unwrap(); let encoder = context.encoder.as_mut().unwrap();
let view = graph let view = graph
.slot_value(graph.slot_id("window_texture_view").unwrap()) .slot_value(graph.slot_id(&BasePassSlots::WindowTextureView).unwrap())
.unwrap() .unwrap()
.as_texture_view(); .as_texture_view();
let depth_view = graph let depth_view = graph
.slot_value(graph.slot_id("depth_texture_view").unwrap()) .slot_value(graph.slot_id(&BasePassSlots::DepthTextureView).unwrap())
.unwrap() .unwrap()
.as_texture_view(); .as_texture_view();
let camera_bg = graph let camera_bg = graph
.bind_group(graph.bind_group_id("camera") .bind_group(graph.bind_group_id(&BasePassSlots::Camera)
.expect("Missing camera bind group")); .expect("Missing camera bind group"));
let lights_bg = graph let lights_bg = graph
.bind_group(graph.bind_group_id("light_buffers") .bind_group(graph.bind_group_id(&LightBasePassSlots::Lights)
.expect("Missing lights bind group")); .expect("Missing lights bind group"));
let light_grid_bg = graph let light_grid_bg = graph
.bind_group(graph.bind_group_id("light_indices_grid") .bind_group(graph.bind_group_id(&LightCullComputePassSlots::LightIndicesGridGroup)
.expect("Missing light grid bind group")); .expect("Missing light grid bind group"));
let material_bg = graph let material_bg = graph
.bind_group(graph.bind_group_id("material") .bind_group(graph.bind_group_id(&MeshesPassSlots::Material)
.expect("Missing material bind group")); .expect("Missing material bind group"));
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {

View File

@ -1,12 +1,6 @@
mod light_cull_compute; mod light_cull_compute;
pub use light_cull_compute::*; pub use light_cull_compute::*;
/*mod depth_prepass;
pub use depth_prepass::*; */
/* mod simple_phong;
pub use simple_phong::*; */
mod base; mod base;
pub use base::*; pub use base::*;
@ -17,7 +11,4 @@ mod light_base;
pub use light_base::*; pub use light_base::*;
mod present_pass; mod present_pass;
pub use present_pass::*; pub use present_pass::*;
mod triangle;
pub use triangle::*;

View File

@ -1,16 +1,32 @@
use crate::render::graph::{RenderGraphContext, RenderGraphPass, RenderGraphPassDesc, RenderPassSlot, RenderPassType, SlotAttribute, SlotType}; use std::hash::Hash;
use lyra_game_derive::RenderGraphLabel;
use crate::render::graph::{RenderGraphContext, RenderGraphLabel, RenderGraphLabelValue, RenderGraphPass, RenderGraphPassDesc, RenderPassSlot, RenderPassType, SlotAttribute, SlotType};
#[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)]
pub struct PresentPassLabel(RenderGraphLabelValue);
impl PresentPassLabel {
pub fn new(label: impl RenderGraphLabel) -> Self {
Self(label.into())
}
}
/// Supplies some basic things other passes needs. /// Supplies some basic things other passes needs.
/// ///
/// screen size buffer, camera buffer, /// screen size buffer, camera buffer,
pub struct PresentPass { pub struct PresentPass {
render_target_slot: String, /// Label of this pass
label: PresentPassLabel,
//render_target_slot: Rc<dyn RenderGraphLabel>,
} }
impl PresentPass { impl PresentPass {
pub fn new(render_target_slot: &str) -> Self { pub fn new(render_target_slot: impl RenderGraphLabel) -> Self {
Self { Self {
render_target_slot: render_target_slot.into(), //render_target_slot: render_target_slot.rc_clone(),
label: PresentPassLabel::new(render_target_slot),
} }
} }
} }
@ -19,7 +35,7 @@ impl RenderGraphPass for PresentPass {
fn desc(&mut self, graph: &mut crate::render::graph::RenderGraph) -> crate::render::graph::RenderGraphPassDesc { fn desc(&mut self, graph: &mut crate::render::graph::RenderGraph) -> crate::render::graph::RenderGraphPassDesc {
let mut desc = RenderGraphPassDesc::new( let mut desc = RenderGraphPassDesc::new(
graph.next_id(), graph.next_id(),
&format!("present_{}", self.render_target_slot), self.label.clone(),
RenderPassType::Presenter, RenderPassType::Presenter,
None, None,
vec![], vec![],
@ -30,7 +46,7 @@ impl RenderGraphPass for PresentPass {
ty: SlotType::RenderTarget, ty: SlotType::RenderTarget,
attribute: SlotAttribute::Input, attribute: SlotAttribute::Input,
id: graph.next_id(), id: graph.next_id(),
name: self.render_target_slot.clone(), label: self.label.0.clone(),
value: None, value: None,
} }
); );
@ -43,8 +59,8 @@ impl RenderGraphPass for PresentPass {
} }
fn execute(&mut self, graph: &mut crate::render::graph::RenderGraph, _desc: &crate::render::graph::RenderGraphPassDesc, _context: &mut crate::render::graph::RenderGraphContext) { fn execute(&mut self, graph: &mut crate::render::graph::RenderGraph, _desc: &crate::render::graph::RenderGraphPassDesc, _context: &mut crate::render::graph::RenderGraphContext) {
let id = graph.slot_id(&self.render_target_slot) let id = graph.slot_id_rc(&self.label.0)
.expect(&format!("render target slot '{}' for PresentPass is missing", self.render_target_slot)); .expect(&format!("render target slot '{:?}' for PresentPass is missing", self.label.0));
let mut slot = graph.slot_value_mut(id).unwrap().as_render_target_mut().unwrap(); let mut slot = graph.slot_value_mut(id).unwrap().as_render_target_mut().unwrap();
let surf_tex = slot.current_texture.take().unwrap(); let surf_tex = slot.current_texture.take().unwrap();
surf_tex.present(); surf_tex.present();

View File

@ -1,153 +0,0 @@
use std::rc::Rc;
use crate::{
render::{
graph::{
RenderGraphContext, RenderGraphPass, RenderGraphPassDesc, RenderPassType,
SlotAttribute, SlotValue,
},
render_buffer::BufferWrapper,
resource::{FragmentState, PipelineDescriptor, RenderPipelineDescriptor, Shader, VertexState},
},
DeltaTime,
};
/// A demo pass that renders a triangle that changes colors every frame.
#[derive(Default)]
pub struct TrianglePass {
acc: f32,
}
impl TrianglePass {
pub fn new() -> Self {
Self::default()
}
}
impl RenderGraphPass for TrianglePass {
fn desc(
&mut self,
graph: &mut crate::render::graph::RenderGraph,
) -> crate::render::graph::RenderGraphPassDesc {
let shader = Rc::new(Shader {
label: Some("triangle_shader".into()),
source: include_str!("../../shaders/triangle.wgsl").to_string(),
});
let device = graph.device();
let (color_bgl, color_bg, color_buf, _) = BufferWrapper::builder()
.label_prefix("color")
.visibility(wgpu::ShaderStages::FRAGMENT)
.buffer_usage(wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
.contents(&[glam::Vec4::new(0.902, 0.639, 0.451, 1.0)])
.finish_parts(device);
let color_bgl = Rc::new(color_bgl);
let color_bg = Rc::new(color_bg);
let main_rt = graph.slot_id("main_render_target")
.and_then(|s| graph.slot_value(s))
.and_then(|s| s.as_render_target())
.expect("missing main render target");
let surface_config_format = main_rt.surface_config.format;
drop(main_rt);
let mut desc = RenderGraphPassDesc::new(
graph.next_id(),
"triangle",
RenderPassType::Render,
Some(PipelineDescriptor::Render(RenderPipelineDescriptor {
label: Some("triangle_pipeline".into()),
layouts: vec![color_bgl.clone()],
push_constant_ranges: vec![],
vertex: VertexState {
module: shader.clone(),
entry_point: "vs_main".into(),
buffers: vec![],
},
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: None,
primitive: wgpu::PrimitiveState::default(),
multisample: wgpu::MultisampleState::default(),
multiview: None,
})),
vec![("color_bg", color_bg, Some(color_bgl))],
);
desc.add_texture_view_slot(
graph.next_id(),
"window_texture_view",
SlotAttribute::Input,
None,
);
desc.add_buffer_slot(
graph.next_id(),
"color_buffer",
SlotAttribute::Output,
Some(SlotValue::Buffer(Rc::new(color_buf))),
);
desc
}
fn prepare(&mut self, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) {
const SPEED: f32 = 1.5;
let dt = **world.get_resource::<DeltaTime>();
self.acc += dt;
let x = (self.acc * SPEED).sin();
let y = ((self.acc + 2.15) * SPEED).sin();
let z = ((self.acc + 5.35) * SPEED).sin();
let color = glam::Vec4::new(x, y, z, 1.0);
context.queue_buffer_write_with("color_buffer", 0, color);
}
fn execute(
&mut self,
graph: &mut crate::render::graph::RenderGraph,
desc: &crate::render::graph::RenderGraphPassDesc,
context: &mut crate::render::graph::RenderGraphContext,
) {
let view = graph
.slot_value(graph.slot_id("window_texture_view").unwrap())
.unwrap()
.as_texture_view();
let color_bg = graph.bind_group(graph.bind_group_id("color_bg").unwrap());
let encoder = context.encoder.as_mut().unwrap();
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("triangle_pass"),
color_attachments: &[
// This is what @location(0) in the fragment shader targets
Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.1,
g: 0.2,
b: 0.3,
a: 1.0,
}),
store: true,
},
}),
],
depth_stencil_attachment: None,
});
let pipeline = graph.pipeline(desc.id);
pass.set_pipeline(&pipeline.as_render());
pass.set_bind_group(0, color_bg, &[]);
pass.draw(0..3, 0..1);
}
}

View File

@ -7,7 +7,7 @@ use lyra_ecs::World;
use tracing::{debug, instrument, warn}; use tracing::{debug, instrument, warn};
use winit::window::Window; use winit::window::Window;
use crate::render::graph::{BasePass, LightBasePass, LightCullComputePass, MeshPass, PresentPass}; use crate::render::graph::{BasePass, BasePassLabel, BasePassSlots, LightBasePass, LightBasePassLabel, LightCullComputePass, LightCullComputePassLabel, MeshPass, MeshesPassLabel, PresentPass, PresentPassLabel};
use super::graph::RenderGraph; use super::graph::RenderGraph;
use super::{resource::RenderPipeline, render_job::RenderJob}; use super::{resource::RenderPipeline, render_job::RenderJob};
@ -137,16 +137,16 @@ impl BasicRenderer {
g.add_pass(MeshPass::new()); g.add_pass(MeshPass::new());
debug!("Adding present pass"); debug!("Adding present pass");
g.add_pass(PresentPass::new("main_render_target")); g.add_pass(PresentPass::new(BasePassSlots::MainRenderTarget));
g.add_edge("base", "light_base"); g.add_edge(BasePassLabel, LightBasePassLabel);
g.add_edge("light_base", "light_cull_compute"); g.add_edge(LightBasePassLabel, LightCullComputePassLabel);
g.add_edge("base", "meshes"); g.add_edge(BasePassLabel, MeshesPassLabel);
// make sure that present runs last // make sure that present runs last
g.add_edge("base", "present_main_render_target"); g.add_edge(BasePassLabel, PresentPassLabel::new(BasePassSlots::MainRenderTarget));
g.add_edge("light_cull_compute", "present_main_render_target"); g.add_edge(LightCullComputePassLabel, PresentPassLabel::new(BasePassSlots::MainRenderTarget));
g.add_edge("meshes", "present_main_render_target"); g.add_edge(MeshesPassLabel, PresentPassLabel::new(BasePassSlots::MainRenderTarget));
g.setup(&device); g.setup(&device);
@ -188,7 +188,7 @@ impl Renderer for BasicRenderer {
self.size = new_size; self.size = new_size;
// update surface config and the surface // update surface config and the surface
let mut rt = self.graph.slot_value_mut(self.graph.slot_id("main_render_target").unwrap()) let mut rt = self.graph.slot_value_mut(self.graph.slot_id(&BasePassSlots::MainRenderTarget).unwrap())
.unwrap().as_render_target_mut().unwrap(); .unwrap().as_render_target_mut().unwrap();
rt.surface_config.width = new_size.width; rt.surface_config.width = new_size.width;
rt.surface_config.height = new_size.height; rt.surface_config.height = new_size.height;