Implement a Render Graph #16
|
@ -384,6 +384,12 @@ version = "1.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bind_match"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "171f0236f66c7be99f32060539c2bade94033ded356ecf4c9dc9b1e6198326cd"
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.3"
|
||||
|
@ -1859,6 +1865,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"async-std",
|
||||
"async-trait",
|
||||
"bind_match",
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"gilrs-core",
|
||||
|
|
|
@ -37,6 +37,7 @@ thiserror = "1.0.56"
|
|||
unique = "0.9.1"
|
||||
rustc-hash = "1.1.0"
|
||||
petgraph = { version = "0.6.5", features = ["matrix_graph"] }
|
||||
bind_match = "0.1.2"
|
||||
|
||||
[features]
|
||||
tracy = ["dep:tracing-tracy"]
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
mod pass;
|
||||
mod node;
|
||||
use std::{
|
||||
cell::RefCell, collections::{HashMap, VecDeque}, fmt::Debug, hash::Hash, rc::Rc, sync::Arc
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
use lyra_ecs::World;
|
||||
pub use pass::*;
|
||||
pub use node::*;
|
||||
|
||||
mod passes;
|
||||
pub use passes::*;
|
||||
|
@ -76,8 +76,8 @@ impl PartialEq for RenderGraphLabelValue {
|
|||
impl Eq for RenderGraphLabelValue {}
|
||||
|
||||
struct PassEntry {
|
||||
inner: Arc<RefCell<dyn RenderGraphPass>>,
|
||||
desc: Arc<RenderGraphPassDesc>,
|
||||
inner: Arc<RefCell<dyn Node>>,
|
||||
desc: Arc<NodeDesc>,
|
||||
/// The index of the pass in the execution graph
|
||||
graph_index: petgraph::matrix_graph::NodeIndex<usize>,
|
||||
}
|
||||
|
@ -165,8 +165,18 @@ impl RenderGraph {
|
|||
self.slot_label_lookup.get(&label.rc_clone().into()).cloned()
|
||||
}
|
||||
|
||||
/// Add a [`Node`] to the RenderGraph.
|
||||
///
|
||||
/// When the node is added, its [`Node::desc`] method will be executed.
|
||||
///
|
||||
/// Additionally, all [`Slot`](node::NodeSlot)s of the node will be iterated,
|
||||
/// 1. Ensuring that there are no two slots of the same name, with different value types
|
||||
/// 2. Changing the id of insert slots to match the id of the output slot of the same name.
|
||||
/// * This means that the id of insert slots **ARE NOT STABLE**. **DO NOT** rely on them to
|
||||
/// not change. The IDs of output slots do stay the same.
|
||||
/// 3. Ensuring that no two slots share the same ID when the names do not match.
|
||||
#[instrument(skip(self, pass), level = "debug")]
|
||||
pub fn add_pass<P: RenderGraphPass>(&mut self, mut pass: P) {
|
||||
pub fn add_pass<P: Node>(&mut self, mut pass: P) {
|
||||
let mut desc = pass.desc(self);
|
||||
|
||||
// collect all the slots of the pass
|
||||
|
@ -234,25 +244,28 @@ impl RenderGraph {
|
|||
}
|
||||
|
||||
/// Creates all buffers required for the passes, also creates an internal execution path.
|
||||
///
|
||||
/// This only needs to be ran when the [`Node`]s in the graph change, or they are removed or
|
||||
/// added.
|
||||
#[instrument(skip(self, device))]
|
||||
pub fn setup(&mut self, device: &wgpu::Device) {
|
||||
// For all passes, create their pipelines
|
||||
for pass in self.passes.values() {
|
||||
if let Some(pipeline_desc) = &pass.desc.pipeline_desc {
|
||||
let pipeline = match pass.desc.pass_type {
|
||||
RenderPassType::Render => Pipeline::Render(RenderPipeline::create(
|
||||
let pipeline = match pass.desc.ty {
|
||||
NodeType::Render => Pipeline::Render(RenderPipeline::create(
|
||||
device,
|
||||
pipeline_desc
|
||||
.as_render_pipeline_descriptor()
|
||||
.expect("got compute pipeline descriptor in a render pass"),
|
||||
)),
|
||||
RenderPassType::Compute => Pipeline::Compute(ComputePipeline::create(
|
||||
NodeType::Compute => Pipeline::Compute(ComputePipeline::create(
|
||||
device,
|
||||
pipeline_desc
|
||||
.as_compute_pipeline_descriptor()
|
||||
.expect("got render pipeline descriptor in a compute pass"),
|
||||
)),
|
||||
RenderPassType::Presenter | RenderPassType::Node => {
|
||||
NodeType::Presenter | NodeType::Node => {
|
||||
panic!("Present or Node RenderGraph passes should not have a pipeline descriptor!");
|
||||
}
|
||||
};
|
||||
|
@ -319,7 +332,7 @@ impl RenderGraph {
|
|||
let label = format!("{:?} Encoder", pass_desc.label);
|
||||
|
||||
// encoders are not needed for presenter nodes.
|
||||
let encoder = if pass_desc.pass_type.should_have_pipeline() {
|
||||
let encoder = if pass_desc.ty.should_have_pipeline() {
|
||||
Some(
|
||||
self.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
|
@ -336,7 +349,7 @@ impl RenderGraph {
|
|||
let mut context = RenderGraphContext::new(&device, &queue, encoder);
|
||||
|
||||
// all encoders need to be submitted before a presenter node is executed.
|
||||
if pass_desc.pass_type == RenderPassType::Presenter {
|
||||
if pass_desc.ty == NodeType::Presenter {
|
||||
trace!("Submitting {} encoderd before presenting", encoders.len());
|
||||
self.queue.submit(encoders.drain(..));
|
||||
}
|
||||
|
@ -369,7 +382,7 @@ impl RenderGraph {
|
|||
self.slots.get_mut(&id).map(|s| &mut s.value)
|
||||
}
|
||||
|
||||
pub fn pass(&self, id: u64) -> Option<&RenderGraphPassDesc> {
|
||||
pub fn pass(&self, id: u64) -> Option<&NodeDesc> {
|
||||
self.passes.get(&id).map(|s| &*s.desc)
|
||||
}
|
||||
|
||||
|
@ -438,13 +451,13 @@ impl RenderGraph {
|
|||
/// graph.set_bind_groups(
|
||||
/// &mut pass,
|
||||
/// &[
|
||||
/// // retrieves the "depth_texture" bind group and sets the index 0 in the
|
||||
/// // retrieves the `BasePassSlots::DepthTexture` bind group and sets the index 0 in the
|
||||
/// // pass to it.
|
||||
/// ("depth_texture", 0),
|
||||
/// ("camera", 1),
|
||||
/// ("light_buffers", 2),
|
||||
/// ("light_indices_grid", 3),
|
||||
/// ("screen_size", 4),
|
||||
/// (&BasePassSlots::DepthTexture, 0),
|
||||
/// (&BasePassSlots::Camera, 1),
|
||||
/// (&LightBasePassSlots::Lights, 2),
|
||||
/// (&LightCullComputePassSlots::LightIndicesGridGroup, 3),
|
||||
/// (&BasePassSlots::ScreenSize, 4),
|
||||
/// ],
|
||||
/// );
|
||||
/// ```
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::{cell::{Ref, RefCell, RefMut}, collections::HashMap, num::NonZeroU32, rc::Rc};
|
||||
|
||||
use bind_match::bind_match;
|
||||
use lyra_ecs::World;
|
||||
|
||||
use crate::render::resource::PipelineDescriptor;
|
||||
|
@ -7,26 +8,31 @@ use crate::render::resource::PipelineDescriptor;
|
|||
use super::{RenderGraph, RenderGraphContext, RenderGraphLabel, RenderGraphLabelValue, RenderTarget};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||
pub enum RenderPassType {
|
||||
pub enum NodeType {
|
||||
/// A node doesn't render, compute, or present anything. This likely means it injects data into the graph.
|
||||
Node,
|
||||
Compute,
|
||||
#[default]
|
||||
Node,
|
||||
/// A Compute pass node type.
|
||||
Compute,
|
||||
/// A render pass node type.
|
||||
Render,
|
||||
/// A node that presents render results to a render target.
|
||||
Presenter,
|
||||
}
|
||||
|
||||
impl RenderPassType {
|
||||
impl NodeType {
|
||||
/// Returns a boolean indicating if the node should have a [`Pipeline`](crate::render::resource::Pipeline).
|
||||
pub fn should_have_pipeline(&self) -> bool {
|
||||
match self {
|
||||
RenderPassType::Node => false,
|
||||
RenderPassType::Compute => true,
|
||||
RenderPassType::Render => true,
|
||||
RenderPassType::Presenter => false,
|
||||
NodeType::Node => false,
|
||||
NodeType::Compute => true,
|
||||
NodeType::Render => true,
|
||||
NodeType::Presenter => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of data that is stored in a [`Node`] slot.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum SlotType {
|
||||
TextureView,
|
||||
|
@ -36,10 +42,13 @@ pub enum SlotType {
|
|||
RenderTarget,
|
||||
}
|
||||
|
||||
/// The value of a slot in a [`Node`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SlotValue {
|
||||
/// This slot doesn't have any value
|
||||
None,
|
||||
/// The value will be set during a later phase of the render graph.
|
||||
/// The value will be set during a later phase of the render graph. To see the type of value
|
||||
/// this will be set to, see the slots type.
|
||||
Lazy,
|
||||
TextureView(Rc<wgpu::TextureView>),
|
||||
Sampler(Rc<wgpu::Sampler>),
|
||||
|
@ -49,56 +58,51 @@ pub enum SlotValue {
|
|||
}
|
||||
|
||||
impl SlotValue {
|
||||
/// Gets `self` as a texture, panics if self is not a instance of [`SlotValue::Texture`].
|
||||
pub fn as_texture(&self) -> &wgpu::Texture {
|
||||
match self {
|
||||
Self::Texture(v) => v,
|
||||
_ => panic!("self is not an instance of SlotValue::Texture"),
|
||||
}
|
||||
pub fn as_texture_view(&self) -> Option<&Rc<wgpu::TextureView>> {
|
||||
bind_match!(self, Self::TextureView(v) => v)
|
||||
}
|
||||
|
||||
pub fn as_texture_view(&self) -> &wgpu::TextureView {
|
||||
match self {
|
||||
Self::TextureView(v) => v,
|
||||
_ => panic!("self is not an instance of SlotValue::TextureView"),
|
||||
}
|
||||
pub fn as_sampler(&self) -> Option<&Rc<wgpu::Sampler>> {
|
||||
bind_match!(self, Self::Sampler(v) => v)
|
||||
}
|
||||
|
||||
pub fn as_buffer(&self) -> Option<&wgpu::Buffer> {
|
||||
match self {
|
||||
Self::Buffer(v) => Some(v),
|
||||
_ => None,
|
||||
pub fn as_texture(&self) -> Option<&Rc<wgpu::Texture>> {
|
||||
bind_match!(self, Self::Texture(v) => v)
|
||||
}
|
||||
|
||||
pub fn as_buffer(&self) -> Option<&Rc<wgpu::Buffer>> {
|
||||
bind_match!(self, Self::Buffer(v) => v)
|
||||
}
|
||||
|
||||
pub fn as_render_target(&self) -> Option<Ref<RenderTarget>> {
|
||||
match self {
|
||||
Self::RenderTarget(v) => Some(v.borrow()),
|
||||
_ => None,
|
||||
}
|
||||
bind_match!(self, Self::RenderTarget(v) => v.borrow())
|
||||
}
|
||||
|
||||
pub fn as_render_target_mut(&mut self) -> Option<RefMut<RenderTarget>> {
|
||||
match self {
|
||||
Self::RenderTarget(v) => Some(v.borrow_mut()),
|
||||
_ => None,
|
||||
}
|
||||
bind_match!(self, Self::RenderTarget(v) => v.borrow_mut())
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum SlotAttribute {
|
||||
/// This slot inputs a value into the node, expecting another node to `Output` it.
|
||||
Input,
|
||||
/// This slot outputs a value from the node, providing the value to other nodes that
|
||||
/// `Input`it.
|
||||
Output,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RenderPassSlot {
|
||||
pub struct NodeSlot {
|
||||
/// The type of the value that this slot inputs/outputs.
|
||||
pub ty: SlotType,
|
||||
/// The way this slot uses the value. Defines if this slot is an output or input.
|
||||
pub attribute: SlotAttribute,
|
||||
// What if these are just completely removed and labels are used everywhere instead?
|
||||
pub id: u64,
|
||||
/// The identifying label of this slot.
|
||||
pub label: RenderGraphLabelValue,
|
||||
/// The descriptor of the slot value.
|
||||
/// This will be `None` if this slot is an input.
|
||||
/// The value of the slot.
|
||||
/// This is `None` if the slot is a `SlotAttribute::Input` type.
|
||||
pub value: Option<SlotValue>,
|
||||
}
|
||||
|
||||
|
@ -157,13 +161,23 @@ impl RenderGraphPipelineInfo {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct RenderGraphPassDesc {
|
||||
/// Descriptor of a Node in a [`RenderGraph`].
|
||||
pub struct NodeDesc {
|
||||
pub id: u64,
|
||||
/// The label of the Node, used to identify the Node.
|
||||
pub label: RenderGraphLabelValue,
|
||||
pub pass_type: RenderPassType,
|
||||
pub slots: Vec<RenderPassSlot>,
|
||||
/// The [`NodeType`] of the node.
|
||||
pub ty: NodeType,
|
||||
/// The slots that the Node uses.
|
||||
/// This defines the resources that the node uses and creates in the graph.
|
||||
pub slots: Vec<NodeSlot>,
|
||||
slot_label_lookup: HashMap<RenderGraphLabelValue, u64>,
|
||||
/// An optional pipeline descriptor for the Node.
|
||||
/// This is `None` if the Node type is not a node that requires a pipeline
|
||||
/// (see [`NodeType::should_have_pipeline`]).
|
||||
pub pipeline_desc: Option<PipelineDescriptor>,
|
||||
/// The bind groups that this Node creates.
|
||||
/// This makes the bind groups accessible to other Nodes.
|
||||
pub bind_groups: Vec<(
|
||||
RenderGraphLabelValue,
|
||||
Rc<wgpu::BindGroup>,
|
||||
|
@ -171,18 +185,19 @@ pub struct RenderGraphPassDesc {
|
|||
)>,
|
||||
}
|
||||
|
||||
impl RenderGraphPassDesc {
|
||||
impl NodeDesc {
|
||||
/// Create a new node descriptor.
|
||||
pub fn new<L: RenderGraphLabel>(
|
||||
id: u64,
|
||||
label: L,
|
||||
pass_type: RenderPassType,
|
||||
pass_type: NodeType,
|
||||
pipeline_desc: Option<PipelineDescriptor>,
|
||||
bind_groups: Vec<(&dyn RenderGraphLabel, Rc<wgpu::BindGroup>, Option<Rc<wgpu::BindGroupLayout>>)>,
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
label: label.into(),
|
||||
pass_type,
|
||||
ty: pass_type,
|
||||
slots: vec![],
|
||||
slot_label_lookup: HashMap::default(),
|
||||
pipeline_desc,
|
||||
|
@ -193,7 +208,11 @@ impl RenderGraphPassDesc {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_slot(&mut self, slot: RenderPassSlot) {
|
||||
/// Add a slot to the descriptor.
|
||||
///
|
||||
/// In debug builds, there is an assert that triggers if the slot is an input slot and has
|
||||
/// a value set.
|
||||
pub fn add_slot(&mut self, slot: NodeSlot) {
|
||||
debug_assert!(
|
||||
!(slot.attribute == SlotAttribute::Input && slot.value.is_some()),
|
||||
"input slots should not have values"
|
||||
|
@ -203,6 +222,11 @@ impl RenderGraphPassDesc {
|
|||
self.slots.push(slot);
|
||||
}
|
||||
|
||||
/// Add a buffer slot to the descriptor.
|
||||
///
|
||||
/// In debug builds, there is an assert that triggers if the slot is an input slot and has
|
||||
/// a value set. There is also an assert that is triggered if this slot value is not `None`,
|
||||
/// `SlotValue::Lazy` or a `Buffer`.
|
||||
#[inline(always)]
|
||||
pub fn add_buffer_slot<L: RenderGraphLabel>(
|
||||
&mut self,
|
||||
|
@ -216,7 +240,7 @@ impl RenderGraphPassDesc {
|
|||
"slot value is not a buffer"
|
||||
);
|
||||
|
||||
let slot = RenderPassSlot {
|
||||
let slot = NodeSlot {
|
||||
id,
|
||||
label: label.into(),
|
||||
ty: SlotType::Buffer,
|
||||
|
@ -226,6 +250,11 @@ impl RenderGraphPassDesc {
|
|||
self.add_slot(slot);
|
||||
}
|
||||
|
||||
/// Add a slot that stores a [`wgpu::Texture`] to the descriptor.
|
||||
///
|
||||
/// In debug builds, there is an assert that triggers if the slot is an input slot and has
|
||||
/// a value set. There is also an assert that is triggered if this slot value is not `None`,
|
||||
/// `SlotValue::Lazy` or a `SlotValue::Texture`.
|
||||
#[inline(always)]
|
||||
pub fn add_texture_slot<L: RenderGraphLabel>(
|
||||
&mut self,
|
||||
|
@ -239,7 +268,7 @@ impl RenderGraphPassDesc {
|
|||
"slot value is not a texture"
|
||||
);
|
||||
|
||||
let slot = RenderPassSlot {
|
||||
let slot = NodeSlot {
|
||||
id,
|
||||
label: label.into(),
|
||||
ty: SlotType::Texture,
|
||||
|
@ -249,6 +278,11 @@ impl RenderGraphPassDesc {
|
|||
self.add_slot(slot);
|
||||
}
|
||||
|
||||
/// Add a slot that stores a [`wgpu::TextureView`] to the descriptor.
|
||||
///
|
||||
/// In debug builds, there is an assert that triggers if the slot is an input slot and has
|
||||
/// a value set. There is also an assert that is triggered if this slot value is not `None`,
|
||||
/// `SlotValue::Lazy` or a `SlotValue::TextureView`.
|
||||
#[inline(always)]
|
||||
pub fn add_texture_view_slot<L: RenderGraphLabel>(
|
||||
&mut self,
|
||||
|
@ -262,7 +296,7 @@ impl RenderGraphPassDesc {
|
|||
"slot value is not a texture view"
|
||||
);
|
||||
|
||||
let slot = RenderPassSlot {
|
||||
let slot = NodeSlot {
|
||||
id,
|
||||
label: label.into(),
|
||||
ty: SlotType::TextureView,
|
||||
|
@ -272,6 +306,11 @@ impl RenderGraphPassDesc {
|
|||
self.add_slot(slot);
|
||||
}
|
||||
|
||||
/// Add a slot that stores a [`wgpu::Sampler`] to the descriptor.
|
||||
///
|
||||
/// In debug builds, there is an assert that triggers if the slot is an input slot and has
|
||||
/// a value set. There is also an assert that is triggered if this slot value is not `None`,
|
||||
/// `SlotValue::Lazy` or a `SlotValue::Sampler`.
|
||||
#[inline(always)]
|
||||
pub fn add_sampler_slot<L: RenderGraphLabel>(
|
||||
&mut self,
|
||||
|
@ -285,7 +324,7 @@ impl RenderGraphPassDesc {
|
|||
"slot value is not a sampler"
|
||||
);
|
||||
|
||||
let slot = RenderPassSlot {
|
||||
let slot = NodeSlot {
|
||||
id,
|
||||
label: label.into(),
|
||||
ty: SlotType::Sampler,
|
||||
|
@ -295,14 +334,16 @@ impl RenderGraphPassDesc {
|
|||
self.add_slot(slot);
|
||||
}
|
||||
|
||||
pub fn input_slots(&self) -> Vec<&RenderPassSlot> {
|
||||
/// Returns all input slots that the descriptor defines.
|
||||
pub fn input_slots(&self) -> Vec<&NodeSlot> {
|
||||
self.slots
|
||||
.iter()
|
||||
.filter(|s| s.attribute == SlotAttribute::Input)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn output_slots(&self) -> Vec<&RenderPassSlot> {
|
||||
/// Returns all output slots that the descriptor defines.
|
||||
pub fn output_slots(&self) -> Vec<&NodeSlot> {
|
||||
self.slots
|
||||
.iter()
|
||||
.filter(|s| s.attribute == SlotAttribute::Output)
|
||||
|
@ -310,17 +351,34 @@ impl RenderGraphPassDesc {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait RenderGraphPass: 'static {
|
||||
/// Create a render pass describer.
|
||||
/// A node that can be executed and scheduled in a [`RenderGraph`].
|
||||
///
|
||||
/// The `id` argument is passed as mutable so you can increment it as you use it for new slots.
|
||||
fn desc<'a, 'b>(&'a mut self, graph: &'b mut RenderGraph) -> RenderGraphPassDesc;
|
||||
/// A node can be used for rendering, computing data on the GPU, collecting data from the main
|
||||
/// world and writing it to GPU buffers, or presenting renders to a surface.
|
||||
///
|
||||
/// The [`RenderGraph`] is ran in phases. The first phase is `prepare`, then `execute`. When a node
|
||||
/// is first added to a RenderGraph, its [`Node::desc`] function will be ran. The descriptor
|
||||
/// describes all resources the node requires for execution during the `execute` phase.
|
||||
pub trait Node: 'static {
|
||||
/// Retrieve a descriptor of the Node.
|
||||
fn desc<'a, 'b>(&'a mut self, graph: &'b mut RenderGraph) -> NodeDesc;
|
||||
|
||||
/// Prepare the node for rendering.
|
||||
///
|
||||
/// This phase runs before `execute` and is meant to be used to collect data from the World
|
||||
/// and write to GPU buffers.
|
||||
fn prepare(&mut self, world: &mut World, context: &mut RenderGraphContext);
|
||||
|
||||
/// Execute the node.
|
||||
///
|
||||
/// Parameters:
|
||||
/// * `graph` - The RenderGraph that this node is a part of. Can be used to get bind groups and bind to them.
|
||||
/// * `desc` - The descriptor of this node.
|
||||
/// * `context` - The rendering graph context.
|
||||
fn execute(
|
||||
&mut self,
|
||||
graph: &mut RenderGraph,
|
||||
desc: &RenderGraphPassDesc,
|
||||
desc: &NodeDesc,
|
||||
context: &mut RenderGraphContext,
|
||||
);
|
||||
}
|
|
@ -9,8 +9,8 @@ use crate::{
|
|||
render::{
|
||||
camera::{CameraUniform, RenderCamera},
|
||||
graph::{
|
||||
RenderGraphContext, RenderGraphPass, RenderGraphPassDesc, RenderPassSlot,
|
||||
RenderPassType, RenderTarget, SlotAttribute, SlotType, SlotValue,
|
||||
RenderGraphContext, Node, NodeDesc, NodeSlot,
|
||||
NodeType, RenderTarget, SlotAttribute, SlotType, SlotValue,
|
||||
},
|
||||
render_buffer::BufferWrapper, texture::RenderTexture,
|
||||
},
|
||||
|
@ -61,11 +61,11 @@ impl BasePass {
|
|||
}
|
||||
}
|
||||
|
||||
impl RenderGraphPass for BasePass {
|
||||
impl Node for BasePass {
|
||||
fn desc(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
) -> crate::render::graph::RenderGraphPassDesc {
|
||||
) -> crate::render::graph::NodeDesc {
|
||||
let render_target = self.temp_render_target.take().unwrap();
|
||||
self.screen_size = UVec2::new(
|
||||
render_target.surface_config.width,
|
||||
|
@ -101,10 +101,10 @@ impl RenderGraphPass for BasePass {
|
|||
let depth_texture_bgl = dt_bg_pair.layout;
|
||||
let depth_texture_view = Rc::new(depth_texture.view);
|
||||
|
||||
let mut desc = RenderGraphPassDesc::new(
|
||||
let mut desc = NodeDesc::new(
|
||||
graph.next_id(),
|
||||
BasePassLabel,
|
||||
RenderPassType::Node,
|
||||
NodeType::Node,
|
||||
None,
|
||||
vec![
|
||||
// TODO: Make this a trait maybe?
|
||||
|
@ -120,7 +120,7 @@ impl RenderGraphPass for BasePass {
|
|||
);
|
||||
|
||||
self.main_rt_id = graph.next_id();
|
||||
desc.add_slot(RenderPassSlot {
|
||||
desc.add_slot(NodeSlot {
|
||||
ty: SlotType::RenderTarget,
|
||||
attribute: SlotAttribute::Output,
|
||||
id: self.main_rt_id,
|
||||
|
@ -173,7 +173,7 @@ impl RenderGraphPass for BasePass {
|
|||
fn execute(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
_desc: &crate::render::graph::RenderGraphPassDesc,
|
||||
_desc: &crate::render::graph::NodeDesc,
|
||||
context: &mut crate::render::graph::RenderGraphContext,
|
||||
) {
|
||||
let tv_slot = graph
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
use glam::UVec2;
|
||||
|
||||
use crate::render::{
|
||||
camera::CameraUniform,
|
||||
graph::{
|
||||
BufferInitDescriptor, RenderGraphPass, RenderGraphPassDesc, RenderPassType, SamplerDescriptor, SlotAttribute, SlotDescriptor, TextureDescriptor, TextureViewDescriptor
|
||||
},
|
||||
};
|
||||
|
||||
/// Supplies some basic things other passes needs.
|
||||
///
|
||||
/// screen size buffer, camera buffer,
|
||||
#[derive(Default)]
|
||||
pub struct DepthPrePass;
|
||||
|
||||
impl DepthPrePass {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderGraphPass for DepthPrePass {
|
||||
fn desc(
|
||||
&self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
id: &mut u64,
|
||||
) -> crate::render::graph::RenderGraphPassDesc {
|
||||
let mut desc = RenderGraphPassDesc::new(*id, "DepthPrePass", RenderPassType::Compute);
|
||||
*id += 1;
|
||||
|
||||
let size = wgpu::Extent3d {
|
||||
width: graph.surface_config.width,
|
||||
height: graph.surface_config.height,
|
||||
depth_or_array_layers: 1,
|
||||
};
|
||||
|
||||
desc.add_texture_slot(
|
||||
*id,
|
||||
"depth_texture",
|
||||
SlotAttribute::Output,
|
||||
Some(SlotDescriptor::Texture(TextureDescriptor {
|
||||
size,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Depth32Float,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT
|
||||
| wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
view_formats: vec![],
|
||||
})),
|
||||
);
|
||||
*id += 1;
|
||||
|
||||
desc.add_texture_view_slot(
|
||||
*id,
|
||||
"depth_texture_view",
|
||||
SlotAttribute::Output,
|
||||
Some(SlotDescriptor::TextureView(TextureViewDescriptor::default_view("depth_texture"))),
|
||||
);
|
||||
*id += 1;
|
||||
|
||||
desc.add_texture_view_slot(
|
||||
*id,
|
||||
"depth_texture_sampler",
|
||||
SlotAttribute::Output,
|
||||
Some(SlotDescriptor::Sampler(SamplerDescriptor {
|
||||
mag_filter: wgpu::FilterMode::Linear,
|
||||
min_filter: wgpu::FilterMode::Linear,
|
||||
compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
lod_min_clamp: 0.0,
|
||||
lod_max_clamp: 100.0,
|
||||
..SamplerDescriptor::default_sampler("depth_texture")
|
||||
})),
|
||||
);
|
||||
*id += 1;
|
||||
|
||||
desc
|
||||
}
|
||||
|
||||
fn prepare(&mut self, world: &mut lyra_ecs::World) {
|
||||
let _ = world;
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn execute(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
desc: &crate::render::graph::RenderGraphPassDesc,
|
||||
context: &mut crate::render::graph::RenderGraphContext,
|
||||
) {
|
||||
let _ = (graph, desc, context);
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ use lyra_game_derive::RenderGraphLabel;
|
|||
|
||||
use crate::render::{
|
||||
graph::{
|
||||
RenderGraphContext, RenderGraphPass, RenderGraphPassDesc, RenderPassType, SlotAttribute,
|
||||
RenderGraphContext, Node, NodeDesc, NodeType, SlotAttribute,
|
||||
SlotValue,
|
||||
},
|
||||
light::LightUniformBuffers,
|
||||
|
@ -30,19 +30,19 @@ impl LightBasePass {
|
|||
}
|
||||
}
|
||||
|
||||
impl RenderGraphPass for LightBasePass {
|
||||
impl Node for LightBasePass {
|
||||
fn desc(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
) -> crate::render::graph::RenderGraphPassDesc {
|
||||
) -> crate::render::graph::NodeDesc {
|
||||
let device = &graph.device;
|
||||
self.light_buffers = Some(LightUniformBuffers::new(device));
|
||||
let light_buffers = self.light_buffers.as_ref().unwrap();
|
||||
|
||||
let mut desc = RenderGraphPassDesc::new(
|
||||
let mut desc = NodeDesc::new(
|
||||
graph.next_id(),
|
||||
LightBasePassLabel,
|
||||
RenderPassType::Node,
|
||||
NodeType::Node,
|
||||
None,
|
||||
vec![(
|
||||
&LightBasePassSlots::Lights,
|
||||
|
@ -70,7 +70,7 @@ impl RenderGraphPass for LightBasePass {
|
|||
fn execute(
|
||||
&mut self,
|
||||
_graph: &mut crate::render::graph::RenderGraph,
|
||||
_desc: &crate::render::graph::RenderGraphPassDesc,
|
||||
_desc: &crate::render::graph::NodeDesc,
|
||||
_context: &mut crate::render::graph::RenderGraphContext,
|
||||
) {
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use wgpu::util::DeviceExt;
|
|||
|
||||
use crate::render::{
|
||||
graph::{
|
||||
RenderGraphContext, RenderGraphPass, RenderGraphPassDesc, RenderPassType, SlotAttribute,
|
||||
RenderGraphContext, Node, NodeDesc, NodeType, SlotAttribute,
|
||||
SlotValue,
|
||||
},
|
||||
resource::{ComputePipelineDescriptor, PipelineDescriptor, Shader},
|
||||
|
@ -37,11 +37,11 @@ impl LightCullComputePass {
|
|||
}
|
||||
}
|
||||
|
||||
impl RenderGraphPass for LightCullComputePass {
|
||||
impl Node for LightCullComputePass {
|
||||
fn desc(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
) -> crate::render::graph::RenderGraphPassDesc {
|
||||
) -> crate::render::graph::NodeDesc {
|
||||
let shader = Rc::new(Shader {
|
||||
label: Some("light_cull_comp_shader".into()),
|
||||
source: include_str!("../../shaders/light_cull.comp.wgsl").to_string(),
|
||||
|
@ -176,10 +176,10 @@ impl RenderGraphPass for LightCullComputePass {
|
|||
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(&BasePassSlots::ScreenSize).unwrap());
|
||||
|
||||
let mut desc = RenderGraphPassDesc::new(
|
||||
let mut desc = NodeDesc::new(
|
||||
pass_id,
|
||||
LightCullComputePassLabel,
|
||||
RenderPassType::Compute,
|
||||
NodeType::Compute,
|
||||
Some(PipelineDescriptor::Compute(ComputePipelineDescriptor {
|
||||
label: Some("light_cull_pipeline".into()),
|
||||
push_constant_ranges: vec![],
|
||||
|
@ -228,7 +228,7 @@ impl RenderGraphPass for LightCullComputePass {
|
|||
fn execute(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
desc: &crate::render::graph::RenderGraphPassDesc,
|
||||
desc: &crate::render::graph::NodeDesc,
|
||||
context: &mut RenderGraphContext,
|
||||
) {
|
||||
let mut pass = context.begin_compute_pass(&wgpu::ComputePassDescriptor {
|
||||
|
|
|
@ -15,8 +15,8 @@ use wgpu::util::DeviceExt;
|
|||
use crate::{
|
||||
render::{
|
||||
desc_buf_lay::DescVertexBufferLayout, graph::{
|
||||
RenderGraphContext, RenderGraphPass, RenderGraphPassDesc,
|
||||
RenderPassType,
|
||||
RenderGraphContext, Node, NodeDesc,
|
||||
NodeType,
|
||||
}, material::{Material, MaterialUniform}, render_buffer::{BufferStorage, BufferWrapper}, render_job::RenderJob, resource::{FragmentState, PipelineDescriptor, RenderPipelineDescriptor, Shader, VertexState}, texture::RenderTexture, transform_buffer_storage::{TransformBuffers, TransformGroup}, vertex::Vertex
|
||||
},
|
||||
DeltaTime,
|
||||
|
@ -201,11 +201,11 @@ impl MeshPass {
|
|||
}
|
||||
}
|
||||
|
||||
impl RenderGraphPass for MeshPass {
|
||||
impl Node for MeshPass {
|
||||
fn desc(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
) -> crate::render::graph::RenderGraphPassDesc {
|
||||
) -> crate::render::graph::NodeDesc {
|
||||
|
||||
let device = graph.device();
|
||||
|
||||
|
@ -253,10 +253,10 @@ impl RenderGraphPass for MeshPass {
|
|||
source: include_str!("../../shaders/base.wgsl").to_string(),
|
||||
});
|
||||
|
||||
let desc = RenderGraphPassDesc::new(
|
||||
let desc = NodeDesc::new(
|
||||
pass_id,
|
||||
MeshesPassLabel,
|
||||
RenderPassType::Render,
|
||||
NodeType::Render,
|
||||
Some(PipelineDescriptor::Render(RenderPipelineDescriptor {
|
||||
label: Some("meshes".into()),
|
||||
layouts: vec![
|
||||
|
@ -445,7 +445,7 @@ impl RenderGraphPass for MeshPass {
|
|||
fn execute(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
desc: &crate::render::graph::RenderGraphPassDesc,
|
||||
desc: &crate::render::graph::NodeDesc,
|
||||
context: &mut crate::render::graph::RenderGraphContext,
|
||||
) {
|
||||
let encoder = context.encoder.as_mut().unwrap();
|
||||
|
@ -453,12 +453,14 @@ impl RenderGraphPass for MeshPass {
|
|||
let view = graph
|
||||
.slot_value(graph.slot_id(&BasePassSlots::WindowTextureView).unwrap())
|
||||
.unwrap()
|
||||
.as_texture_view();
|
||||
.as_texture_view()
|
||||
.expect("BasePassSlots::WindowTextureView was not a TextureView slot");
|
||||
|
||||
let depth_view = graph
|
||||
.slot_value(graph.slot_id(&BasePassSlots::DepthTextureView).unwrap())
|
||||
.unwrap()
|
||||
.as_texture_view();
|
||||
.as_texture_view()
|
||||
.expect("BasePassSlots::DepthTextureView was not a TextureView slot");
|
||||
|
||||
let camera_bg = graph
|
||||
.bind_group(graph.bind_group_id(&BasePassSlots::Camera)
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::hash::Hash;
|
|||
|
||||
use lyra_game_derive::RenderGraphLabel;
|
||||
|
||||
use crate::render::graph::{RenderGraphContext, RenderGraphLabel, RenderGraphLabelValue, RenderGraphPass, RenderGraphPassDesc, RenderPassSlot, RenderPassType, SlotAttribute, SlotType};
|
||||
use crate::render::graph::{RenderGraphContext, RenderGraphLabel, RenderGraphLabelValue, Node, NodeDesc, NodeSlot, NodeType, SlotAttribute, SlotType};
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)]
|
||||
pub struct PresentPassLabel(RenderGraphLabelValue);
|
||||
|
@ -31,18 +31,18 @@ impl PresentPass {
|
|||
}
|
||||
}
|
||||
|
||||
impl RenderGraphPass for PresentPass {
|
||||
fn desc(&mut self, graph: &mut crate::render::graph::RenderGraph) -> crate::render::graph::RenderGraphPassDesc {
|
||||
let mut desc = RenderGraphPassDesc::new(
|
||||
impl Node for PresentPass {
|
||||
fn desc(&mut self, graph: &mut crate::render::graph::RenderGraph) -> crate::render::graph::NodeDesc {
|
||||
let mut desc = NodeDesc::new(
|
||||
graph.next_id(),
|
||||
self.label.clone(),
|
||||
RenderPassType::Presenter,
|
||||
NodeType::Presenter,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
|
||||
desc.add_slot(
|
||||
RenderPassSlot {
|
||||
NodeSlot {
|
||||
ty: SlotType::RenderTarget,
|
||||
attribute: SlotAttribute::Input,
|
||||
id: graph.next_id(),
|
||||
|
@ -58,7 +58,7 @@ 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::NodeDesc, _context: &mut crate::render::graph::RenderGraphContext) {
|
||||
let id = graph.slot_id_rc(&self.label.0)
|
||||
.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();
|
||||
|
|
Loading…
Reference in New Issue