Implement a Render Graph #16

Merged
SeanOMik merged 20 commits from feature/render-graph into main 2024-06-15 22:54:47 +00:00
5 changed files with 42 additions and 37 deletions
Showing only changes of commit 8c3446389c - Show all commits

View File

@ -38,7 +38,7 @@ impl GraphExecutionPath {
let node = Node {
id: desc.id,
desc: (*desc).clone(),
desc: (*desc),
slot_inputs: inputs
};
nodes.insert(node.id, node);
@ -75,12 +75,14 @@ impl GraphExecutionPath {
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
struct SlotOwnerPair {
pass: u64,
slot: u64,
}
#[allow(dead_code)]
struct Node<'a> {
id: u64,
desc: &'a RenderGraphPassDesc,

View File

@ -121,17 +121,11 @@ impl RenderGraph {
self.slot_names.get(name).cloned()
}
pub fn slot_value(&self, id: u64) -> Option<&SlotValue> {
self.slots.get(&id).map(|s| &s.value)
}
pub fn pass(&self, id: u64) -> Option<&RenderGraphPassDesc> {
self.passes.get(&id).map(|s| &*s.desc)
}
#[instrument(skip(self, pass), level = "debug")]
pub fn add_pass<P: RenderGraphPass>(&mut self, mut pass: P) {
let mut desc = pass.desc(self);
// collect all the slots of the pass
for slot in &mut desc.slots {
if let Some((id, other)) = self
.slot_names
@ -158,6 +152,7 @@ impl RenderGraph {
}
}
// get clones of the bind groups and layouts
for (name, bg, bgl) in &desc.bind_groups {
let bg_id = self.next_id();
self.bind_groups.insert(
@ -211,8 +206,8 @@ impl RenderGraph {
inner.prepare(world, &mut context);
}
// Queue all buffer writes to the gpu
{
// Queue all buffer writes to the gpu
let s = debug_span!("queue_buffer_writes");
let _e = s.enter();
@ -236,7 +231,7 @@ impl RenderGraph {
// create the execution path for the graph. This will be executed in `RenderGraph::render`
let builtin = {
let mut h = FxHashSet::default();
h.insert(0u64);
h.insert(0u64); // include the base pass
h
};
let descs = self.passes.values().map(|p| &*p.desc).collect();
@ -248,7 +243,8 @@ impl RenderGraph {
self.exec_path = Some(path);
}
pub fn render(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, surface: &wgpu::Surface) {
#[instrument(skip(self, surface))]
pub fn render(&mut self, surface: &wgpu::Surface) {
let mut path = self.exec_path.take().unwrap();
let output = surface.get_current_texture().unwrap();
@ -272,10 +268,13 @@ impl RenderGraph {
let pass_desc = pass.desc.clone();
let label = format!("{} Encoder", pass_desc.name);
let encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some(&label),
});
let mut context = RenderGraphContext::new(queue, Some(encoder));
let encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some(&label),
});
let queue = self.queue.clone(); // clone is required to appease the borrow checker
let mut context = RenderGraphContext::new(&queue, Some(encoder));
let mut inner = pass_inn.borrow_mut();
inner.execute(self, &*pass_desc, &mut context);
@ -283,10 +282,22 @@ impl RenderGraph {
encoders.push(context.encoder.unwrap().finish());
}
queue.submit(encoders.into_iter());
self.queue.submit(encoders.into_iter());
output.present();
}
pub fn slot_value(&self, id: u64) -> Option<&SlotValue> {
self.slots.get(&id).map(|s| &s.value)
}
pub fn slot_value_mut(&mut self, id: u64) -> Option<&mut SlotValue> {
self.slots.get_mut(&id).map(|s| &mut s.value)
}
pub fn pass(&self, id: u64) -> Option<&RenderGraphPassDesc> {
self.passes.get(&id).map(|s| &*s.desc)
}
#[inline(always)]
pub fn pipeline(&self, id: u64) -> &Pipeline {
&self.pipelines.get(&id).unwrap().pipeline
@ -319,7 +330,8 @@ impl RenderGraph {
}
}
pub(crate) struct BufferWrite {
/// A queued write to a GPU buffer targeting a graph slot.
pub(crate) struct GraphBufferWrite {
/// The name of the slot that has the resource that will be written
target_slot: String,
offset: u64,
@ -331,7 +343,7 @@ pub struct RenderGraphContext<'a> {
/// Becomes None when the encoder is submitted
pub(crate) encoder: Option<wgpu::CommandEncoder>,
pub(crate) queue: &'a wgpu::Queue,
pub(crate) buffer_writes: VecDeque<BufferWrite>,
pub(crate) buffer_writes: VecDeque<GraphBufferWrite>,
renderpass_desc: Vec<wgpu::RenderPassDescriptor<'a, 'a>>,
}
@ -373,15 +385,17 @@ impl<'a> RenderGraphContext<'a> {
/// This does not submit the data to the GPU immediately, or add it to the `wgpu::Queue`. The
/// data will be submitted to the GPU queue right after the prepare stage for all passes
/// is ran.
#[instrument(skip(self, bytes), level="trace", fields(size = bytes.len()))]
pub fn queue_buffer_write(&mut self, target_slot: &str, offset: u64, bytes: &[u8]) {
self.buffer_writes.push_back(BufferWrite {
self.buffer_writes.push_back(GraphBufferWrite {
target_slot: target_slot.to_string(),
offset,
bytes: bytes.to_vec(),
})
}
/// Write
/// Queue a data write of a type that to a buffer at that is contained in `target_slot`.
#[instrument(skip(self, bytes), level="trace", fields(size = std::mem::size_of::<T>()))]
pub fn queue_buffer_write_with<T: bytemuck::NoUninit>(
&mut self,
target_slot: &str,

View File

@ -12,13 +12,9 @@ use crate::{
DeltaTime,
};
/// Supplies some basic things other passes needs.
///
/// screen size buffer, camera buffer,
/// A demo pass that renders a triangle that changes colors every frame.
#[derive(Default)]
pub struct TrianglePass {
//color_bg: Option<Rc<wgpu::BindGroup>>,
//color_buf: Option<Rc<wgpu::Buffer>>,
acc: f32,
}
@ -48,8 +44,6 @@ impl RenderGraphPass for TrianglePass {
let color_bgl = Rc::new(color_bgl);
let color_bg = Rc::new(color_bg);
//let color_buf = Rc::new(color_buf);
let mut desc = RenderGraphPassDesc::new(
graph.next_id(),
"TrianglePass",
@ -120,14 +114,9 @@ impl RenderGraphPass for TrianglePass {
.slot_value(graph.slot_id("window_texture_view").unwrap())
.unwrap()
.as_texture_view();
let encoder = context.encoder.as_mut().unwrap();
//context.queue.write_buffer(buffer, offset, data)
//let color_bg = graph.bind_group(graph.slot_id("color_buffer").unwrap());
//let color_bg = self.color_bg.as_ref().unwrap();
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("TrianglePass"),
color_attachments: &[

View File

@ -270,7 +270,7 @@ impl Renderer for BasicRenderer {
#[instrument(skip(self))]
fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
self.graph.render(&self.device, &self.queue, &self.surface);
self.graph.render(&self.surface);
Ok(())
}

View File

@ -1,4 +1,4 @@
use std::{collections::HashMap, ops::Deref};
use std::ops::Deref;
use wgpu::PipelineLayout;