Compare commits
3 Commits
c846d52b0d
...
ef68b2a4c5
Author | SHA1 | Date |
---|---|---|
SeanOMik | ef68b2a4c5 | |
SeanOMik | 41d77c5687 | |
SeanOMik | bb21805278 |
|
@ -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"
|
||||||
|
|
|
@ -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" ] }
|
||||||
|
|
|
@ -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"
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -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,48 +172,53 @@ 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
|
||||||
);
|
);
|
||||||
|
|
||||||
// if there is a slot of the same name
|
// if there is a slot of the same name
|
||||||
slot.id = *id;
|
slot.id = *id;
|
||||||
} else {
|
} else {
|
||||||
|
debug_assert!(!self.slots.contains_key(&slot.id),
|
||||||
|
"Reuse of id detected in render graph! Pass: {:?}, slot: {:?}",
|
||||||
|
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);
|
||||||
|
@ -219,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);
|
||||||
}
|
}
|
||||||
|
@ -243,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);
|
||||||
|
|
||||||
|
@ -252,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() {
|
||||||
|
@ -277,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);
|
||||||
|
|
||||||
|
@ -336,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, ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,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, &[]);
|
||||||
}
|
}
|
||||||
|
@ -400,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>,
|
||||||
}
|
}
|
||||||
|
@ -455,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(),
|
||||||
})
|
})
|
||||||
|
@ -467,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,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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())),
|
||||||
);
|
);
|
||||||
|
|
|
@ -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),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -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,20 +22,26 @@ 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)>,
|
||||||
|
|
||||||
//#[allow(dead_code)]
|
// maybe this should just be a Uuid and the material can be retrieved though
|
||||||
//render_texture: Option<RenderTexture>,
|
// MeshPass's `material_buffers` field?
|
||||||
material: Option<Rc<Material>>,
|
material: Option<Rc<Material>>,
|
||||||
|
|
||||||
// The index of the transform for this entity.
|
|
||||||
// The tuple is structured like this: (transform index, index of transform inside the buffer)
|
|
||||||
//transform_index: TransformBufferIndices,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Component)]
|
#[derive(Clone, Debug, Component)]
|
||||||
|
@ -180,16 +187,8 @@ impl MeshPass {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Processes the mesh for the renderer, storing and creating buffers as needed. Returns true if a new mesh was processed.
|
/// Processes the mesh for the renderer, storing and creating buffers as needed. Returns true if a new mesh was processed.
|
||||||
#[instrument(skip(self, device, queue, transform, mesh, entity))]
|
#[instrument(skip(self, device, queue, mesh, entity))]
|
||||||
fn process_mesh(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, entity: Entity, transform: Transform, mesh: &Mesh, mesh_uuid: Uuid) -> bool {
|
fn process_mesh(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, entity: Entity, mesh: &Mesh, mesh_uuid: Uuid) -> bool {
|
||||||
let _ = transform;
|
|
||||||
/* if self.transform_buffers.should_expand() {
|
|
||||||
self.transform_buffers.expand_buffers(&self.device);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.transform_buffers.update_or_insert(&self.queue, &self.render_limits,
|
|
||||||
entity, || ( transform.calculate_mat4(), glam::Mat3::from_quat(transform.rotation) )); */
|
|
||||||
|
|
||||||
#[allow(clippy::map_entry)]
|
#[allow(clippy::map_entry)]
|
||||||
if !self.mesh_buffers.contains_key(&mesh_uuid) {
|
if !self.mesh_buffers.contains_key(&mesh_uuid) {
|
||||||
// create the mesh's buffers
|
// create the mesh's buffers
|
||||||
|
@ -233,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");
|
||||||
|
@ -243,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 {
|
||||||
|
@ -256,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()),
|
||||||
|
@ -298,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)),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -343,6 +342,9 @@ impl RenderGraphPass for MeshPass {
|
||||||
{
|
{
|
||||||
alive_entities.insert(entity);
|
alive_entities.insert(entity);
|
||||||
|
|
||||||
|
// Interpolate the transform for this entity using a component.
|
||||||
|
// If the entity does not have the component then it will be queued to be added
|
||||||
|
// to it after all the entities are prepared for rendering.
|
||||||
let interp_transform = match interp_tran {
|
let interp_transform = match interp_tran {
|
||||||
Some(mut interp_transform) => {
|
Some(mut interp_transform) => {
|
||||||
// found in https://youtu.be/YJB1QnEmlTs?t=472
|
// found in https://youtu.be/YJB1QnEmlTs?t=472
|
||||||
|
@ -362,22 +364,28 @@ impl RenderGraphPass for MeshPass {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
// expand the transform buffers if they need to be.
|
||||||
|
// this is done in its own scope to avoid multiple mutable references to self at
|
||||||
|
// once; aka, make the borrow checker happy
|
||||||
|
let transforms = self.transforms.as_mut().unwrap();
|
||||||
|
if transforms.needs_expand() {
|
||||||
|
debug!("Expanding transform buffers");
|
||||||
|
transforms.expand_buffers(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some((mesh_han, mesh_epoch)) = mesh_pair {
|
if let Some((mesh_han, mesh_epoch)) = mesh_pair {
|
||||||
if let Some(mesh) = mesh_han.data_ref() {
|
if let Some(mesh) = mesh_han.data_ref() {
|
||||||
// if process mesh did not just create a new mesh, and the epoch
|
// if process mesh did not just create a new mesh, and the epoch
|
||||||
// shows that the scene has changed, verify that the mesh buffers
|
// shows that the scene has changed, verify that the mesh buffers
|
||||||
// dont need to be resent to the gpu.
|
// dont need to be resent to the gpu.
|
||||||
if !self.process_mesh(device, queue, entity, interp_transform, &*mesh, mesh_han.uuid())
|
if !self.process_mesh(device, queue, entity, &*mesh, mesh_han.uuid())
|
||||||
&& mesh_epoch == last_epoch {
|
&& mesh_epoch == last_epoch {
|
||||||
self.check_mesh_buffers(device, queue, &mesh_han);
|
self.check_mesh_buffers(device, queue, &mesh_han);
|
||||||
}
|
}
|
||||||
|
|
||||||
let transforms = self.transforms.as_mut().unwrap();
|
|
||||||
if transforms.needs_expand() {
|
|
||||||
debug!("Expanding transform buffers");
|
|
||||||
transforms.expand_buffers(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let transforms = self.transforms.as_mut().unwrap();
|
||||||
let group = TransformGroup::EntityRes(entity, mesh_han.uuid());
|
let group = TransformGroup::EntityRes(entity, mesh_han.uuid());
|
||||||
let transform_id = transforms.update_or_push(device, queue, &render_limits,
|
let transform_id = transforms.update_or_push(device, queue, &render_limits,
|
||||||
group, interp_transform.calculate_mat4(), glam::Mat3::from_quat(interp_transform.rotation));
|
group, interp_transform.calculate_mat4(), glam::Mat3::from_quat(interp_transform.rotation));
|
||||||
|
@ -404,17 +412,12 @@ impl RenderGraphPass for MeshPass {
|
||||||
// if process mesh did not just create a new mesh, and the epoch
|
// if process mesh did not just create a new mesh, and the epoch
|
||||||
// shows that the scene has changed, verify that the mesh buffers
|
// shows that the scene has changed, verify that the mesh buffers
|
||||||
// dont need to be resent to the gpu.
|
// dont need to be resent to the gpu.
|
||||||
if !self.process_mesh(device, queue, entity, mesh_interpo, &*mesh, mesh_han.uuid())
|
if !self.process_mesh(device, queue, entity, &*mesh, mesh_han.uuid())
|
||||||
&& scene_epoch == last_epoch {
|
&& scene_epoch == last_epoch {
|
||||||
self.check_mesh_buffers(device, queue, &mesh_han);
|
self.check_mesh_buffers(device, queue, &mesh_han);
|
||||||
}
|
}
|
||||||
|
|
||||||
let transforms = self.transforms.as_mut().unwrap();
|
let transforms = self.transforms.as_mut().unwrap();
|
||||||
if transforms.needs_expand() {
|
|
||||||
debug!("Expanding transform buffers");
|
|
||||||
transforms.expand_buffers(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
let scene_mesh_group = TransformGroup::Res(scene_han.uuid(), mesh_han.uuid());
|
let scene_mesh_group = TransformGroup::Res(scene_han.uuid(), mesh_han.uuid());
|
||||||
let group = TransformGroup::OwnedGroup(entity, scene_mesh_group.into());
|
let group = TransformGroup::OwnedGroup(entity, scene_mesh_group.into());
|
||||||
let transform_id = transforms.update_or_push(device, queue, &render_limits,
|
let transform_id = transforms.update_or_push(device, queue, &render_limits,
|
||||||
|
@ -448,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 {
|
||||||
|
|
|
@ -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::*;
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue