Compare commits

...

5 Commits

15 changed files with 415 additions and 195 deletions

View File

@ -29,8 +29,8 @@ tracy = ["lyra-game/tracy"]
lyra-game = { path = "lyra-game" } lyra-game = { path = "lyra-game" }
lyra-scripting = { path = "lyra-scripting", optional = true } lyra-scripting = { path = "lyra-scripting", optional = true }
[profile.dev] #[profile.dev]
opt-level = 1 #opt-level = 1
[profile.release] [profile.release]
debug = true debug = true

View File

@ -0,0 +1,100 @@
use std::{collections::VecDeque, sync::Arc};
use tracing::instrument;
use super::{Frame, RenderGraphLabel, RenderGraphLabelValue, RenderTarget};
/// 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
pub(crate) target_slot: RenderGraphLabelValue,
pub(crate) offset: u64,
pub(crate) bytes: Vec<u8>,
}
#[allow(dead_code)]
pub struct RenderGraphContext<'a> {
/// The [`wgpu::CommandEncoder`] used to encode GPU operations.
///
/// This is `None` during the `prepare` stage.
pub encoder: Option<wgpu::CommandEncoder>,
/// The gpu device that is being used.
pub device: Arc<wgpu::Device>,
pub queue: Arc<wgpu::Queue>,
pub(crate) buffer_writes: VecDeque<GraphBufferWrite>,
renderpass_desc: Vec<wgpu::RenderPassDescriptor<'a, 'a>>,
/// The label of this Node.
pub label: RenderGraphLabelValue,
}
impl<'a> RenderGraphContext<'a> {
pub(crate) fn new(device: Arc<wgpu::Device>, queue: Arc<wgpu::Queue>, encoder: Option<wgpu::CommandEncoder>, label: RenderGraphLabelValue) -> Self {
Self {
encoder,
device,
queue,
buffer_writes: Default::default(),
renderpass_desc: vec![],
label,
}
}
pub fn begin_render_pass(
&'a mut self,
desc: wgpu::RenderPassDescriptor<'a, 'a>,
) -> wgpu::RenderPass {
self.encoder
.as_mut()
.expect(
"RenderGraphContext is missing a command encoder. This is likely \
because you are trying to run render commands in the prepare stage.",
)
.begin_render_pass(&desc)
}
pub fn begin_compute_pass(&mut self, desc: &wgpu::ComputePassDescriptor) -> wgpu::ComputePass {
self.encoder
.as_mut()
.expect(
"RenderGraphContext is missing a command encoder. This is likely \
because you are trying to run render commands in the prepare stage.",
)
.begin_compute_pass(desc)
}
/// Queue a data write to a buffer at that is contained in `target_slot`.
///
/// 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: impl RenderGraphLabel, offset: u64, bytes: &[u8]) {
self.buffer_writes.push_back(GraphBufferWrite {
target_slot: target_slot.into(),
offset,
bytes: bytes.to_vec(),
})
}
/// 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: impl RenderGraphLabel,
offset: u64,
bytes: T,
) {
self.queue_buffer_write(target_slot, offset, bytemuck::bytes_of(&bytes));
}
pub fn get_frame(&self, render_target: &RenderTarget) -> super::Frame {
let texture = render_target.frame_texture()
.expect("failed to create frame texture"); // should this be returned to the user?
Frame {
device: self.device.clone(),
queue: self.queue.clone(),
texture,
}
}
}

View File

@ -12,6 +12,12 @@ pub use passes::*;
mod slot_desc; mod slot_desc;
pub use slot_desc::*; pub use slot_desc::*;
mod context;
pub use context::*;
mod render_target;
pub use render_target::*;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use tracing::{debug_span, instrument, trace, warn}; use tracing::{debug_span, instrument, trace, warn};
use wgpu::ComputePass; use wgpu::ComputePass;
@ -108,32 +114,27 @@ pub struct PipelineResource {
pub bg_layout_name_lookup: HashMap<String, u32>, pub bg_layout_name_lookup: HashMap<String, u32>,
} }
#[derive(Debug)]
pub struct RenderTarget {
pub surface: wgpu::Surface,
pub surface_config: wgpu::SurfaceConfiguration,
pub current_texture: Option<wgpu::SurfaceTexture>,
}
pub struct RenderGraph { pub struct RenderGraph {
device: Rc<wgpu::Device>, device: Arc<wgpu::Device>,
queue: Rc<wgpu::Queue>, queue: Arc<wgpu::Queue>,
slots: FxHashMap<RenderGraphLabelValue, ResourcedSlot>, slots: FxHashMap<RenderGraphLabelValue, ResourcedSlot>,
nodes: FxHashMap<RenderGraphLabelValue, PassEntry>, nodes: FxHashMap<RenderGraphLabelValue, PassEntry>,
sub_graphs: FxHashMap<RenderGraphLabelValue, RenderGraph>,
bind_groups: FxHashMap<RenderGraphLabelValue, BindGroupEntry>, bind_groups: FxHashMap<RenderGraphLabelValue, BindGroupEntry>,
/// A directed graph describing the execution path of the RenderGraph /// A directed graph used to determine dependencies of nodes.
execution_graph: petgraph::matrix_graph::DiMatrix<RenderGraphLabelValue, (), Option<()>, usize>, node_graph: petgraph::matrix_graph::DiMatrix<RenderGraphLabelValue, (), Option<()>, usize>,
} }
impl RenderGraph { impl RenderGraph {
pub fn new(device: Rc<wgpu::Device>, queue: Rc<wgpu::Queue>) -> Self { pub fn new(device: Arc<wgpu::Device>, queue: Arc<wgpu::Queue>) -> Self {
Self { Self {
device, device,
queue, queue,
slots: Default::default(), slots: Default::default(),
nodes: Default::default(), nodes: Default::default(),
sub_graphs: Default::default(),
bind_groups: Default::default(), bind_groups: Default::default(),
execution_graph: Default::default(), node_graph: Default::default(),
} }
} }
@ -152,7 +153,7 @@ impl RenderGraph {
/// not change. The IDs of output slots do stay the same. /// 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. /// 3. Ensuring that no two slots share the same ID when the names do not match.
#[instrument(skip(self, pass), level = "debug")] #[instrument(skip(self, pass), level = "debug")]
pub fn add_pass<P: Node>(&mut self, label: impl RenderGraphLabel, mut pass: P) { pub fn add_node<P: Node>(&mut self, label: impl RenderGraphLabel, mut pass: P) {
let mut desc = pass.desc(self); let mut desc = pass.desc(self);
// collect all the slots of the pass // collect all the slots of the pass
@ -203,7 +204,7 @@ impl RenderGraph {
} }
let label: RenderGraphLabelValue = label.into(); let label: RenderGraphLabelValue = label.into();
let index = self.execution_graph.add_node(label.clone()); let index = self.node_graph.add_node(label.clone());
self.nodes.insert( self.nodes.insert(
label, label,
@ -239,9 +240,9 @@ impl RenderGraph {
.as_compute_pipeline_descriptor() .as_compute_pipeline_descriptor()
.expect("got render pipeline descriptor in a compute pass"), .expect("got render pipeline descriptor in a compute pass"),
)), )),
NodeType::Presenter | NodeType::Node => { NodeType::Presenter | NodeType::Node | NodeType::Graph => {
panic!("Present or Node RenderGraph passes should not have a pipeline descriptor!"); panic!("Present or Node RenderGraph passes should not have a pipeline descriptor!");
} },
}; };
drop(desc); drop(desc);
@ -258,16 +259,27 @@ impl RenderGraph {
#[instrument(skip(self, world))] #[instrument(skip(self, world))]
pub fn prepare(&mut self, world: &mut World) { pub fn prepare(&mut self, world: &mut World) {
// prepare all passes
let mut buffer_writes = VecDeque::<GraphBufferWrite>::new(); let mut buffer_writes = VecDeque::<GraphBufferWrite>::new();
// reserve some buffer writes. not all nodes write so half the amount of them is probably // reserve some buffer writes. not all nodes write so half the amount of them is probably
// fine. // fine.
buffer_writes.reserve(self.nodes.len() / 2); buffer_writes.reserve(self.nodes.len() / 2);
for (label, pass) in &mut self.nodes { let mut sorted: VecDeque<RenderGraphLabelValue> = petgraph::algo::toposort(&self.node_graph, None)
let mut context = RenderGraphContext::new(&self.device, &self.queue, None, label.clone()); .expect("RenderGraph had cycled!")
let mut inner = pass.inner.borrow_mut(); .iter()
inner.prepare(world, &mut context); .map(|i| self.node_graph[i.clone()].clone())
.collect();
while let Some(pass_label) = sorted.pop_front() {
let pass = self.nodes.get(&pass_label).unwrap();
let device = self.device.clone();
let queue = self.queue.clone();
let inner = pass.inner.clone();
let mut inner = inner.borrow_mut();
let mut context = RenderGraphContext::new(device, queue, None, pass_label.clone());
inner.prepare(self, world, &mut context);
buffer_writes.append(&mut context.buffer_writes); buffer_writes.append(&mut context.buffer_writes);
} }
@ -296,10 +308,10 @@ impl RenderGraph {
#[instrument(skip(self))] #[instrument(skip(self))]
pub fn render(&mut self) { pub fn render(&mut self) {
let mut sorted: VecDeque<RenderGraphLabelValue> = petgraph::algo::toposort(&self.execution_graph, None) let mut sorted: VecDeque<RenderGraphLabelValue> = petgraph::algo::toposort(&self.node_graph, None)
.expect("RenderGraph had cycled!") .expect("RenderGraph had cycled!")
.iter() .iter()
.map(|i| self.execution_graph[i.clone()].clone()) .map(|i| self.node_graph[i.clone()].clone())
.collect(); .collect();
//debug!("Render graph execution order: {:?}", sorted); //debug!("Render graph execution order: {:?}", sorted);
@ -328,7 +340,7 @@ impl RenderGraph {
// clone of the Rc's is required to appease the borrow checker // clone of the Rc's is required to appease the borrow checker
let device = self.device.clone(); let device = self.device.clone();
let queue = self.queue.clone(); let queue = self.queue.clone();
let mut context = RenderGraphContext::new(&device, &queue, encoder, pass_label.clone()); let mut context = RenderGraphContext::new(device, queue, encoder, pass_label.clone());
// all encoders need to be submitted before a presenter node is executed. // all encoders need to be submitted before a presenter node is executed.
if pass_desc.ty == NodeType::Presenter { if pass_desc.ty == NodeType::Presenter {
@ -412,23 +424,23 @@ impl RenderGraph {
.iter() .iter()
.find(|p| *p.0 == from) .find(|p| *p.0 == from)
.map(|p| p.1.graph_index) .map(|p| p.1.graph_index)
.expect("Failed to find from pass"); .expect("Failed to find from node");
let to_idx = self let to_idx = self
.nodes .nodes
.iter() .iter()
.find(|p| *p.0 == to) .find(|p| *p.0 == to)
.map(|p| p.1.graph_index) .map(|p| p.1.graph_index)
.expect("Failed to find to pass"); .expect("Failed to find to node");
debug_assert_ne!(from_idx, to_idx, "cannot add edges between the same node"); debug_assert_ne!(from_idx, to_idx, "cannot add edges between the same node");
self.execution_graph.add_edge(from_idx, to_idx, ()); self.node_graph.add_edge(from_idx, to_idx, ());
} }
/// Utility method for setting the bind groups for a pass. /// Utility method for setting the bind groups for a node.
/// ///
/// The parameter `bind_groups` can be used to specify the labels of a bind group, and the /// The parameter `bind_groups` can be used to specify the labels of a bind group, and the
/// index of the bind group in the pipeline for the pass. If a bind group of the provided /// index of the bind group in the pipeline for the node. If a bind group of the provided
/// name is not found in the graph, a panic will occur. /// name is not found in the graph, a panic will occur.
/// ///
/// # Example: /// # Example:
@ -462,88 +474,33 @@ impl RenderGraph {
pass.set_bind_group(*index, bg, &[]); pass.set_bind_group(*index, bg, &[]);
} }
} }
}
/// A queued write to a GPU buffer targeting a graph slot. pub fn sub_graph_mut<L: Into<RenderGraphLabelValue>>(&mut self, label: L) -> Option<&mut RenderGraph> {
pub(crate) struct GraphBufferWrite { self.sub_graphs.get_mut(&label.into())
/// The name of the slot that has the resource that will be written
target_slot: RenderGraphLabelValue,
offset: u64,
bytes: Vec<u8>,
}
#[allow(dead_code)]
pub struct RenderGraphContext<'a> {
/// The [`wgpu::CommandEncoder`] used to encode GPU operations.
///
/// This is `None` during the `prepare` stage.
pub encoder: Option<wgpu::CommandEncoder>,
/// The gpu device that is being used.
pub device: &'a wgpu::Device,
pub queue: &'a wgpu::Queue,
pub(crate) buffer_writes: VecDeque<GraphBufferWrite>,
renderpass_desc: Vec<wgpu::RenderPassDescriptor<'a, 'a>>,
/// The label of this Node.
pub label: RenderGraphLabelValue,
}
impl<'a> RenderGraphContext<'a> {
pub(crate) fn new(device: &'a wgpu::Device, queue: &'a wgpu::Queue, encoder: Option<wgpu::CommandEncoder>, label: RenderGraphLabelValue) -> Self {
Self {
encoder,
device,
queue,
buffer_writes: Default::default(),
renderpass_desc: vec![],
label,
} }
} }
pub fn begin_render_pass( pub struct SubGraphNode(RenderGraphLabelValue);
&'a mut self,
desc: wgpu::RenderPassDescriptor<'a, 'a>, impl Node for SubGraphNode {
) -> wgpu::RenderPass { fn desc<'a, 'b>(&'a mut self, _: &'b mut RenderGraph) -> NodeDesc {
self.encoder NodeDesc::new(NodeType::Graph, None, vec![])
.as_mut()
.expect(
"RenderGraphContext is missing a command encoder. This is likely \
because you are trying to run render commands in the prepare stage.",
)
.begin_render_pass(&desc)
} }
pub fn begin_compute_pass(&mut self, desc: &wgpu::ComputePassDescriptor) -> wgpu::ComputePass { fn prepare(&mut self, graph: &mut RenderGraph, world: &mut World, _: &mut RenderGraphContext) {
self.encoder let sg = graph.sub_graph_mut(self.0.clone())
.as_mut() .unwrap_or_else(|| panic!("failed to find sub graph for SubGraphNode: {:?}", self.0));
.expect( sg.prepare(world);
"RenderGraphContext is missing a command encoder. This is likely \
because you are trying to run render commands in the prepare stage.",
)
.begin_compute_pass(desc)
} }
/// Queue a data write to a buffer at that is contained in `target_slot`. fn execute(
///
/// 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: impl RenderGraphLabel, offset: u64, bytes: &[u8]) {
self.buffer_writes.push_back(GraphBufferWrite {
target_slot: target_slot.into(),
offset,
bytes: bytes.to_vec(),
})
}
/// 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, &mut self,
target_slot: impl RenderGraphLabel, graph: &mut RenderGraph,
offset: u64, _: &NodeDesc,
bytes: T, _: &mut RenderGraphContext,
) { ) {
self.queue_buffer_write(target_slot, offset, bytemuck::bytes_of(&bytes)); let sg = graph.sub_graph_mut(self.0.clone())
.unwrap_or_else(|| panic!("failed to find sub graph for SubGraphNode: {:?}", self.0));
sg.render();
} }
} }

View File

@ -5,7 +5,7 @@ use lyra_ecs::World;
use crate::render::resource::PipelineDescriptor; use crate::render::resource::PipelineDescriptor;
use super::{RenderGraph, RenderGraphContext, RenderGraphLabel, RenderGraphLabelValue, RenderTarget}; use super::{Frame, 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 NodeType { pub enum NodeType {
@ -18,6 +18,8 @@ pub enum NodeType {
Render, Render,
/// A node that presents render results to a render target. /// A node that presents render results to a render target.
Presenter, Presenter,
/// A node that represents a sub-graph.
Graph,
} }
impl NodeType { impl NodeType {
@ -28,6 +30,7 @@ impl NodeType {
NodeType::Compute => true, NodeType::Compute => true,
NodeType::Render => true, NodeType::Render => true,
NodeType::Presenter => false, NodeType::Presenter => false,
NodeType::Graph => false,
} }
} }
} }
@ -40,10 +43,11 @@ pub enum SlotType {
Texture, Texture,
Buffer, Buffer,
RenderTarget, RenderTarget,
Frame,
} }
/// The value of a slot in a [`Node`]. /// The value of a slot in a [`Node`].
#[derive(Debug, Clone)] #[derive(Clone)]
pub enum SlotValue { pub enum SlotValue {
/// This slot doesn't have any value /// This slot doesn't have any value
None, None,
@ -55,6 +59,7 @@ pub enum SlotValue {
Texture(Rc<wgpu::Texture>), Texture(Rc<wgpu::Texture>),
Buffer(Rc<wgpu::Buffer>), Buffer(Rc<wgpu::Buffer>),
RenderTarget(Rc<RefCell<RenderTarget>>), RenderTarget(Rc<RefCell<RenderTarget>>),
Frame(Rc<RefCell<Option<Frame>>>),
} }
impl SlotValue { impl SlotValue {
@ -81,6 +86,14 @@ impl SlotValue {
pub fn as_render_target_mut(&mut self) -> Option<RefMut<RenderTarget>> { pub fn as_render_target_mut(&mut self) -> Option<RefMut<RenderTarget>> {
bind_match!(self, Self::RenderTarget(v) => v.borrow_mut()) bind_match!(self, Self::RenderTarget(v) => v.borrow_mut())
} }
pub fn as_frame(&self) -> Option<Ref<Option<Frame>>> {
bind_match!(self, Self::Frame(v) => v.borrow())
}
pub fn as_frame_mut(&mut self) -> Option<RefMut<Option<Frame>>> {
bind_match!(self, Self::Frame(v) => v.borrow_mut())
}
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum SlotAttribute { pub enum SlotAttribute {
@ -348,7 +361,7 @@ pub trait Node: 'static {
/// ///
/// This phase runs before `execute` and is meant to be used to collect data from the World /// This phase runs before `execute` and is meant to be used to collect data from the World
/// and write to GPU buffers. /// and write to GPU buffers.
fn prepare(&mut self, world: &mut World, context: &mut RenderGraphContext); fn prepare(&mut self, graph: &mut RenderGraph, world: &mut World, context: &mut RenderGraphContext);
/// Execute the node. /// Execute the node.
/// ///

View File

@ -1,6 +1,5 @@
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use glam::UVec2;
use lyra_game_derive::RenderGraphLabel; use lyra_game_derive::RenderGraphLabel;
use tracing::warn; use tracing::warn;
use winit::dpi::PhysicalSize; use winit::dpi::PhysicalSize;
@ -9,8 +8,7 @@ use crate::{
render::{ render::{
camera::{CameraUniform, RenderCamera}, camera::{CameraUniform, RenderCamera},
graph::{ graph::{
RenderGraphContext, Node, NodeDesc, NodeSlot, Node, NodeDesc, NodeSlot, NodeType, RenderGraph, RenderGraphContext, RenderTarget, SlotAttribute, SlotType, SlotValue
NodeType, RenderTarget, SlotAttribute, SlotType, SlotValue,
}, },
render_buffer::BufferWrapper, texture::RenderTexture, render_buffer::BufferWrapper, texture::RenderTexture,
}, },
@ -28,6 +26,7 @@ pub enum BasePassSlots {
MainRenderTarget, MainRenderTarget,
WindowTextureView, WindowTextureView,
DepthTextureView, DepthTextureView,
Frame,
} }
/// Supplies some basic things other passes needs. /// Supplies some basic things other passes needs.
@ -44,15 +43,11 @@ pub struct BasePass {
} }
impl BasePass { impl BasePass {
pub fn new(surface: wgpu::Surface, surface_config: wgpu::SurfaceConfiguration) -> Self { pub fn new(render_target: RenderTarget) -> Self {
let size = glam::UVec2::new(surface_config.width, surface_config.height); let size = render_target.size();
Self { Self {
temp_render_target: Some(RenderTarget { temp_render_target: Some(render_target),
surface,
surface_config,
current_texture: None,
}),
screen_size: size, screen_size: size,
..Default::default() ..Default::default()
} }
@ -65,10 +60,7 @@ impl Node for BasePass {
graph: &mut crate::render::graph::RenderGraph, graph: &mut crate::render::graph::RenderGraph,
) -> crate::render::graph::NodeDesc { ) -> crate::render::graph::NodeDesc {
let render_target = self.temp_render_target.take().unwrap(); let render_target = self.temp_render_target.take().unwrap();
self.screen_size = UVec2::new( self.screen_size = render_target.size();
render_target.surface_config.width,
render_target.surface_config.height,
);
let (screen_size_bgl, screen_size_bg, screen_size_buf, _) = BufferWrapper::builder() let (screen_size_bgl, screen_size_bg, screen_size_buf, _) = BufferWrapper::builder()
.buffer_usage(wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST) .buffer_usage(wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
@ -91,7 +83,7 @@ impl Node for BasePass {
let camera_bg = Rc::new(camera_bg); let camera_bg = Rc::new(camera_bg);
// create the depth texture using the utility struct, then take all the required fields // create the depth texture using the utility struct, then take all the required fields
let mut depth_texture = RenderTexture::create_depth_texture(&graph.device(), &render_target.surface_config, "depth_texture"); let mut depth_texture = RenderTexture::create_depth_texture(&graph.device(), self.screen_size, "depth_texture");
depth_texture.create_bind_group(&graph.device); depth_texture.create_bind_group(&graph.device);
let dt_bg_pair = depth_texture.bindgroup_pair.unwrap(); let dt_bg_pair = depth_texture.bindgroup_pair.unwrap();
@ -123,6 +115,12 @@ impl Node for BasePass {
render_target, render_target,
)))), )))),
}); });
desc.add_slot(NodeSlot {
ty: SlotType::Frame,
attribute: SlotAttribute::Output,
label: BasePassSlots::Frame.into(),
value: Some(SlotValue::Lazy),
});
desc.add_texture_view_slot( desc.add_texture_view_slot(
BasePassSlots::WindowTextureView, BasePassSlots::WindowTextureView,
SlotAttribute::Output, SlotAttribute::Output,
@ -147,7 +145,7 @@ impl Node for BasePass {
desc desc
} }
fn prepare(&mut self, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) { fn prepare(&mut self, _graph: &mut RenderGraph, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) {
if let Some(camera) = world.view_iter::<&mut CameraComponent>().next() { if let Some(camera) = world.view_iter::<&mut CameraComponent>().next() {
let mut render_cam = let mut render_cam =
RenderCamera::new(PhysicalSize::new(self.screen_size.x, self.screen_size.y)); RenderCamera::new(PhysicalSize::new(self.screen_size.x, self.screen_size.y));
@ -168,28 +166,31 @@ impl Node for BasePass {
let tv_slot = graph let tv_slot = graph
.slot_value_mut(BasePassSlots::MainRenderTarget) .slot_value_mut(BasePassSlots::MainRenderTarget)
.expect("somehow the main render target slot is missing"); .expect("somehow the main render target slot is missing");
let mut rt = tv_slot.as_render_target_mut().unwrap(); let rt = tv_slot.as_render_target().unwrap();
debug_assert!( let rt_size = rt.size();
let frame = context.get_frame(&rt);
/* debug_assert!(
!rt.current_texture.is_some(), !rt.current_texture.is_some(),
"main render target surface was not presented!" "main render target surface was not presented!"
); ); */
// update the screen size buffer if the size changed. // update the screen size buffer if the size changed.
if rt.surface_config.width != self.screen_size.x if rt_size != self.screen_size {
|| rt.surface_config.height != self.screen_size.y self.screen_size = rt_size;
{
self.screen_size = UVec2::new(rt.surface_config.width, rt.surface_config.height);
context.queue_buffer_write_with(BasePassSlots::ScreenSize, 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 = frame.texture();
let view = surface_tex let view = surface_tex
.texture
.create_view(&wgpu::TextureViewDescriptor::default()); .create_view(&wgpu::TextureViewDescriptor::default());
rt.current_texture = Some(surface_tex);
drop(rt); // must be manually dropped for borrow checker when getting texture view slot drop(rt); // must be manually dropped for borrow checker when getting texture view slot
let frame_slot = graph
.slot_value_mut(BasePassSlots::Frame)
.expect("somehow the frame slot is missing");
*frame_slot = SlotValue::Frame(Rc::new(RefCell::new(Some(frame))));
// store the surface texture to the slot // store the surface texture to the slot
let tv_slot = graph let tv_slot = graph
.slot_value_mut(BasePassSlots::WindowTextureView) .slot_value_mut(BasePassSlots::WindowTextureView)

View File

@ -0,0 +1,33 @@
use lyra_game_derive::RenderGraphLabel;
use crate::render::graph::{Node, NodeDesc, NodeSlot, NodeType};
#[derive(Debug, Default, Clone, Copy, Hash, RenderGraphLabel)]
pub struct InitNodeLabel;
pub struct InitNode {
slots: Vec<NodeSlot>,
}
impl Node for InitNode {
fn desc<'a, 'b>(&'a mut self, _: &'b mut crate::render::graph::RenderGraph) -> crate::render::graph::NodeDesc {
let mut desc = NodeDesc::new(NodeType::Node, None, vec![]);
// the slots can just be cloned since the slot attribute doesn't really matter much.
desc.slots = self.slots.clone();
desc
}
fn prepare(&mut self, _: &mut crate::render::graph::RenderGraph, _: &mut lyra_ecs::World, _: &mut crate::render::graph::RenderGraphContext) {
}
fn execute(
&mut self,
_: &mut crate::render::graph::RenderGraph,
_: &crate::render::graph::NodeDesc,
_: &mut crate::render::graph::RenderGraphContext,
) {
}
}

View File

@ -2,8 +2,7 @@ use lyra_game_derive::RenderGraphLabel;
use crate::render::{ use crate::render::{
graph::{ graph::{
RenderGraphContext, Node, NodeDesc, NodeType, SlotAttribute, Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext, SlotAttribute, SlotValue
SlotValue,
}, },
light::LightUniformBuffers, light::LightUniformBuffers,
}; };
@ -58,10 +57,10 @@ impl Node for LightBasePass {
desc desc
} }
fn prepare(&mut self, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) { fn prepare(&mut self, _graph: &mut RenderGraph, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) {
let tick = world.current_tick(); let tick = world.current_tick();
let lights = self.light_buffers.as_mut().unwrap(); let lights = self.light_buffers.as_mut().unwrap();
lights.update_lights(context.queue, tick, world); lights.update_lights(&context.queue, tick, world);
} }
fn execute( fn execute(

View File

@ -7,7 +7,7 @@ use wgpu::util::DeviceExt;
use crate::render::{ use crate::render::{
graph::{ graph::{
Node, NodeDesc, NodeType, RenderGraphContext, SlotAttribute, SlotValue Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext, SlotAttribute, SlotValue
}, renderer::ScreenSize, resource::{ComputePipelineDescriptor, PipelineDescriptor, Shader} }, renderer::ScreenSize, resource::{ComputePipelineDescriptor, PipelineDescriptor, Shader}
}; };
@ -51,8 +51,7 @@ impl Node for LightCullComputePass {
.slot_value(BasePassSlots::MainRenderTarget) .slot_value(BasePassSlots::MainRenderTarget)
.and_then(|s| s.as_render_target()) .and_then(|s| s.as_render_target())
.expect("missing main render target"); .expect("missing main render target");
self.workgroup_size = self.workgroup_size = main_rt.size();
glam::UVec2::new(main_rt.surface_config.width, main_rt.surface_config.height);
// initialize some buffers with empty data // initialize some buffers with empty data
let mut contents = Vec::<u8>::new(); let mut contents = Vec::<u8>::new();
@ -215,7 +214,7 @@ impl Node for LightCullComputePass {
desc desc
} }
fn prepare(&mut self, world: &mut World, context: &mut RenderGraphContext) { fn prepare(&mut self, _graph: &mut RenderGraph, world: &mut World, context: &mut RenderGraphContext) {
context.queue_buffer_write_with(LightCullComputePassSlots::IndexCounterBuffer, 0, 0); context.queue_buffer_write_with(LightCullComputePassSlots::IndexCounterBuffer, 0, 0);
let screen_size = world.get_resource::<ScreenSize>(); let screen_size = world.get_resource::<ScreenSize>();

View File

@ -15,8 +15,7 @@ use wgpu::util::DeviceExt;
use crate::{ use crate::{
render::{ render::{
desc_buf_lay::DescVertexBufferLayout, graph::{ desc_buf_lay::DescVertexBufferLayout, graph::{
RenderGraphContext, Node, NodeDesc, Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext
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 }, 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, DeltaTime,
@ -235,7 +234,7 @@ impl Node for MeshPass {
let main_rt = graph.slot_value(BasePassSlots::MainRenderTarget) let main_rt = graph.slot_value(BasePassSlots::MainRenderTarget)
.and_then(|s| s.as_render_target()) .and_then(|s| s.as_render_target())
.expect("missing main render target"); .expect("missing main render target");
let surface_config_format = main_rt.surface_config.format; let surface_config_format = main_rt.format();
drop(main_rt); drop(main_rt);
let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera); let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera);
@ -297,10 +296,10 @@ impl Node for MeshPass {
desc desc
} }
#[instrument(skip(self, world, context))] #[instrument(skip(self, _graph, world, context))]
fn prepare(&mut self, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) { fn prepare(&mut self, _graph: &mut RenderGraph, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) {
let device = context.device; let device = &context.device;
let queue = context.queue; let queue = &context.queue;
let render_limits = device.limits(); let render_limits = device.limits();
let last_epoch = world.current_tick(); let last_epoch = world.current_tick();
@ -364,7 +363,7 @@ impl Node for MeshPass {
let transforms = self.transforms.as_mut().unwrap(); let transforms = self.transforms.as_mut().unwrap();
if transforms.needs_expand() { if transforms.needs_expand() {
debug!("Expanding transform buffers"); debug!("Expanding transform buffers");
transforms.expand_buffers(device); transforms.expand_buffers(&device);
} }
} }
@ -373,14 +372,14 @@ impl Node 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, 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(); 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));
let material = mesh.material.as_ref().unwrap() let material = mesh.material.as_ref().unwrap()
@ -405,15 +404,15 @@ impl Node 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, 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();
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,
group, mesh_interpo.calculate_mat4(), glam::Mat3::from_quat(mesh_interpo.rotation) ); group, mesh_interpo.calculate_mat4(), glam::Mat3::from_quat(mesh_interpo.rotation) );
let material = mesh.material.as_ref().unwrap() let material = mesh.material.as_ref().unwrap()
@ -432,7 +431,7 @@ impl Node for MeshPass {
} }
let transforms = self.transforms.as_mut().unwrap(); let transforms = self.transforms.as_mut().unwrap();
transforms.send_to_gpu(queue); transforms.send_to_gpu(&queue);
} }
fn execute( fn execute(

View File

@ -12,3 +12,6 @@ pub use light_base::*;
mod present_pass; mod present_pass;
pub use present_pass::*; pub use present_pass::*;
mod init;
pub use init::*;

View File

@ -2,14 +2,14 @@ use std::hash::Hash;
use lyra_game_derive::RenderGraphLabel; use lyra_game_derive::RenderGraphLabel;
use crate::render::graph::{RenderGraphContext, RenderGraphLabel, RenderGraphLabelValue, Node, NodeDesc, NodeSlot, NodeType, SlotAttribute, SlotType}; use crate::render::graph::{Node, NodeDesc, NodeSlot, NodeType, RenderGraph, RenderGraphContext, RenderGraphLabel, RenderGraphLabelValue, SlotAttribute, SlotType};
#[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)] #[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)]
pub struct PresentPassLabel(RenderGraphLabelValue); pub struct PresentPassLabel(RenderGraphLabelValue);
impl PresentPassLabel { impl PresentPassLabel {
pub fn new(label: impl RenderGraphLabel) -> Self { pub fn new(frame_label: impl RenderGraphLabel) -> Self {
Self(label.into()) Self(frame_label.into())
} }
} }
@ -22,10 +22,17 @@ pub struct PresentPass {
} }
impl PresentPass { impl PresentPass {
pub fn new(render_target_slot: impl RenderGraphLabel) -> Self { /// Create a new PresentNode, presenting the frame at `frame_label`
pub fn new(frame_label: impl RenderGraphLabel) -> Self {
Self { Self {
//render_target_slot: render_target_slot.rc_clone(), //render_target_slot: render_target_slot.rc_clone(),
label: PresentPassLabel::new(render_target_slot), label: PresentPassLabel::new(frame_label),
}
}
pub fn from_node_label(present_pass_label: PresentPassLabel) -> Self {
Self {
label: present_pass_label,
} }
} }
} }
@ -40,7 +47,7 @@ impl Node for PresentPass {
desc.add_slot( desc.add_slot(
NodeSlot { NodeSlot {
ty: SlotType::RenderTarget, ty: SlotType::Frame,
attribute: SlotAttribute::Input, attribute: SlotAttribute::Input,
label: self.label.0.clone(), label: self.label.0.clone(),
value: None, value: None,
@ -50,15 +57,17 @@ impl Node for PresentPass {
desc desc
} }
fn prepare(&mut self, _world: &mut lyra_ecs::World, _context: &mut RenderGraphContext) { fn prepare(&mut self, _graph: &mut RenderGraph, _world: &mut lyra_ecs::World, _context: &mut RenderGraphContext) {
} }
fn execute(&mut self, graph: &mut crate::render::graph::RenderGraph, _desc: &crate::render::graph::NodeDesc, _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 mut slot = graph.slot_value_mut(self.label.0.clone()) let slot = graph.slot_value_mut(self.label.0.clone())
.expect(&format!("render target slot '{:?}' for PresentPass is missing", self.label.0)) .unwrap_or_else(|| panic!("frame slot '{:?}' for PresentPass is missing", self.label.0))
.as_render_target_mut().unwrap(); .as_frame_mut()
let surf_tex = slot.current_texture.take().unwrap(); .unwrap()
surf_tex.present(); .take()
.unwrap_or_else(|| panic!("frame '{:?}' was already presented", self.label.0));
slot.present();
} }
} }

View File

@ -0,0 +1,102 @@
use std::sync::Arc;
use crate::math;
enum RenderTargetInner {
Surface {
surface: wgpu::Surface,
config: wgpu::SurfaceConfiguration,
},
Texture {
texture: Arc<wgpu::Texture>,
}
}
/// A render target that is a surface or a texture.
#[repr(transparent)]
pub struct RenderTarget(RenderTargetInner);
impl From<wgpu::Texture> for RenderTarget {
fn from(value: wgpu::Texture) -> Self {
Self(RenderTargetInner::Texture { texture: Arc::new(value) })
}
}
impl RenderTarget {
pub fn from_surface(surface: wgpu::Surface, config: wgpu::SurfaceConfiguration) -> Self {
Self(RenderTargetInner::Surface { surface, config })
}
pub fn format(&self) -> wgpu::TextureFormat {
match &self.0 {
RenderTargetInner::Surface { config, .. } => config.format,
RenderTargetInner::Texture { texture } => texture.format(),
}
}
pub fn size(&self) -> math::UVec2 {
match &self.0 {
RenderTargetInner::Surface { config, .. } => math::UVec2::new(config.width, config.height),
RenderTargetInner::Texture { texture } => {
let s = texture.size();
math::UVec2::new(s.width, s.height)
},
}
}
/// Get the frame texture of the [`RenderTarget`]
///
/// If this is target is a surface and the frame texture was already retrieved from the swap
/// chain, a [`wgpu::SurfaceError`] error will be returned.
pub fn frame_texture(&self) -> Result<FrameTexture, wgpu::SurfaceError> {
match &self.0 {
RenderTargetInner::Surface { surface, .. } => Ok(FrameTexture::Surface(surface.get_current_texture()?)),
RenderTargetInner::Texture { texture } => Ok(FrameTexture::Texture(texture.clone())),
}
}
pub fn resize(&mut self, device: &wgpu::Device, new_size: math::UVec2) {
match &mut self.0 {
RenderTargetInner::Surface { surface, config } => {
config.width = new_size.x;
config.height = new_size.y;
surface.configure(device, config);
},
RenderTargetInner::Texture { texture } => {
let _ = texture;
todo!()
},
}
}
}
pub enum FrameTexture {
Surface(wgpu::SurfaceTexture),
Texture(Arc<wgpu::Texture>),
}
#[allow(dead_code)]
pub struct Frame {
pub(crate) device: Arc<wgpu::Device>,
pub(crate) queue: Arc<wgpu::Queue>,
pub(crate) texture: FrameTexture,
}
impl Frame {
pub fn texture(&self) -> &wgpu::Texture {
match &self.texture {
FrameTexture::Surface(s) => &s.texture,
FrameTexture::Texture(t) => t,
}
}
/// Present the frame
///
/// If this frame is from a surface, it will be present, else nothing will happen.
pub fn present(self) {
match self.texture {
FrameTexture::Surface(s) => s.present(),
FrameTexture::Texture(_) => {},
}
}
}

View File

@ -17,8 +17,8 @@ pub(crate) struct LightIndicesGridBuffer {
} }
pub(crate) struct LightCullCompute { pub(crate) struct LightCullCompute {
device: Rc<wgpu::Device>, device: Arc<wgpu::Device>,
queue: Rc<wgpu::Queue>, queue: Arc<wgpu::Queue>,
pipeline: ComputePipeline, pipeline: ComputePipeline,
pub light_indices_grid: LightIndicesGridBuffer, pub light_indices_grid: LightIndicesGridBuffer,
screen_size_buffer: BufferWrapper, screen_size_buffer: BufferWrapper,
@ -153,7 +153,7 @@ impl LightCullCompute {
} }
} }
pub fn new(device: Rc<wgpu::Device>, queue: Rc<wgpu::Queue>, screen_size: PhysicalSize<u32>, lights_buffers: &LightUniformBuffers, camera_buffers: &BufferWrapper, depth_texture: &mut RenderTexture) -> Self { pub fn new(device: Arc<wgpu::Device>, queue: Arc<wgpu::Queue>, screen_size: PhysicalSize<u32>, lights_buffers: &LightUniformBuffers, camera_buffers: &BufferWrapper, depth_texture: &mut RenderTexture) -> Self {
let screen_size_buffer = BufferWrapper::builder() let screen_size_buffer = BufferWrapper::builder()
.buffer_usage(wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST) .buffer_usage(wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
.label_prefix("ScreenSize") .label_prefix("ScreenSize")

View File

@ -1,17 +1,18 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use lyra_ecs::World; 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, BasePassLabel, BasePassSlots, LightBasePass, LightBasePassLabel, LightCullComputePass, LightCullComputePassLabel, MeshPass, MeshesPassLabel, PresentPass, PresentPassLabel}; use crate::render::graph::{BasePass, BasePassLabel, BasePassSlots, LightBasePass, LightBasePassLabel, LightCullComputePass, LightCullComputePassLabel, MeshPass, MeshesPassLabel, PresentPass, PresentPassLabel, RenderTarget};
use super::graph::RenderGraph; use super::graph::RenderGraph;
use super::{resource::RenderPipeline, render_job::RenderJob}; use super::{resource::RenderPipeline, render_job::RenderJob};
use crate::math;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct ScreenSize(glam::UVec2); pub struct ScreenSize(glam::UVec2);
@ -45,8 +46,8 @@ pub trait RenderPass {
} }
pub struct BasicRenderer { pub struct BasicRenderer {
pub device: Rc<wgpu::Device>, // device does not need to be mutable, no need for refcell pub device: Arc<wgpu::Device>, // device does not need to be mutable, no need for refcell
pub queue: Rc<wgpu::Queue>, pub queue: Arc<wgpu::Queue>,
pub size: winit::dpi::PhysicalSize<u32>, pub size: winit::dpi::PhysicalSize<u32>,
pub window: Arc<Window>, pub window: Arc<Window>,
@ -119,35 +120,38 @@ impl BasicRenderer {
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
let device = Rc::new(device); let device = Arc::new(device);
let queue = Rc::new(queue); let queue = Arc::new(queue);
let mut g = RenderGraph::new(device.clone(), queue.clone()); let mut g = RenderGraph::new(device.clone(), queue.clone());
let surface_target = RenderTarget::from_surface(surface, config);
debug!("Adding base pass"); debug!("Adding base pass");
g.add_pass(BasePassLabel, BasePass::new(surface, config)); g.add_node(BasePassLabel, BasePass::new(surface_target));
debug!("Adding light base pass"); debug!("Adding light base pass");
g.add_pass(LightBasePassLabel, LightBasePass::new()); g.add_node(LightBasePassLabel, LightBasePass::new());
debug!("Adding light cull compute pass"); debug!("Adding light cull compute pass");
g.add_pass(LightCullComputePassLabel, LightCullComputePass::new(size)); g.add_node(LightCullComputePassLabel, LightCullComputePass::new(size));
//debug!("Adding triangle pass"); //debug!("Adding triangle pass");
//g.add_pass(TrianglePass::new()); //g.add_node(TrianglePass::new());
debug!("Adding mesh pass"); debug!("Adding mesh pass");
g.add_pass(MeshesPassLabel, MeshPass::new()); g.add_node(MeshesPassLabel, MeshPass::new());
debug!("Adding present pass"); debug!("Adding present pass");
let p = PresentPass::new(BasePassSlots::MainRenderTarget); let present_pass_label = PresentPassLabel::new(BasePassSlots::Frame);
g.add_pass(p.label.clone(), p); let p = PresentPass::from_node_label(present_pass_label.clone());
g.add_node(p.label.clone(), p);
g.add_edge(BasePassLabel, LightBasePassLabel); g.add_edge(BasePassLabel, LightBasePassLabel);
g.add_edge(LightBasePassLabel, LightCullComputePassLabel); g.add_edge(LightBasePassLabel, LightCullComputePassLabel);
g.add_edge(BasePassLabel, MeshesPassLabel); g.add_edge(BasePassLabel, MeshesPassLabel);
// make sure that present runs last // make sure that present runs last
g.add_edge(BasePassLabel, PresentPassLabel::new(BasePassSlots::MainRenderTarget)); g.add_edge(BasePassLabel, present_pass_label.clone());
g.add_edge(LightCullComputePassLabel, PresentPassLabel::new(BasePassSlots::MainRenderTarget)); g.add_edge(LightCullComputePassLabel, present_pass_label.clone());
g.add_edge(MeshesPassLabel, PresentPassLabel::new(BasePassSlots::MainRenderTarget)); g.add_edge(MeshesPassLabel, present_pass_label.clone());
g.setup(&device); g.setup(&device);
@ -191,9 +195,10 @@ impl Renderer for BasicRenderer {
// update surface config and the surface // update surface config and the surface
let mut rt = self.graph.slot_value_mut(BasePassSlots::MainRenderTarget) let mut rt = self.graph.slot_value_mut(BasePassSlots::MainRenderTarget)
.unwrap().as_render_target_mut().unwrap(); .unwrap().as_render_target_mut().unwrap();
rt.surface_config.width = new_size.width; rt.resize(&self.device, math::UVec2::new(new_size.width, new_size.height));
/* rt.surface_config.width = new_size.width;
rt.surface_config.height = new_size.height; rt.surface_config.height = new_size.height;
rt.surface.configure(&self.device, &rt.surface_config); rt.surface.configure(&self.device, &rt.surface_config); */
// update screen size resource in ecs // update screen size resource in ecs
let mut world_ss = world.get_resource_mut::<ScreenSize>(); let mut world_ss = world.get_resource_mut::<ScreenSize>();

View File

@ -254,10 +254,10 @@ impl RenderTexture {
); );
} }
pub fn create_depth_texture(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration, label: &str) -> Self { pub fn create_depth_texture(device: &wgpu::Device, size: crate::math::UVec2, label: &str) -> Self {
let size = wgpu::Extent3d { let size = wgpu::Extent3d {
width: config.width, width: size.x,
height: config.height, height: size.y,
depth_or_array_layers: 1, depth_or_array_layers: 1,
}; };
let desc = wgpu::TextureDescriptor { let desc = wgpu::TextureDescriptor {