Implement a Render Graph #16
|
@ -22,6 +22,24 @@
|
|||
"args": [],
|
||||
"cwd": "${workspaceFolder}/examples/testbed"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug example simple_scene",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--manifest-path", "${workspaceFolder}/examples/simple_scene/Cargo.toml"
|
||||
//"--bin=testbed",
|
||||
],
|
||||
"filter": {
|
||||
"name": "simple_scene",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/examples/simple_scene"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
|
|
|
@ -11,9 +11,11 @@ pub struct GraphExecutionPath {
|
|||
}
|
||||
|
||||
impl GraphExecutionPath {
|
||||
pub fn new(built_in_slots: FxHashSet<u64>, pass_descriptions: Vec<&RenderGraphPassDesc>) -> Self {
|
||||
pub fn new(pass_descriptions: Vec<&RenderGraphPassDesc>) -> Self {
|
||||
// collect all the output slots
|
||||
let mut total_outputs = HashMap::new();
|
||||
total_outputs.reserve(pass_descriptions.len());
|
||||
|
||||
for desc in pass_descriptions.iter() {
|
||||
for slot in desc.output_slots() {
|
||||
total_outputs.insert(slot.name.clone(), SlotOwnerPair {
|
||||
|
@ -28,9 +30,6 @@ impl GraphExecutionPath {
|
|||
// find the node inputs
|
||||
let mut inputs = vec![];
|
||||
for slot in desc.input_slots() {
|
||||
// If the slot is built in to the graph, no need to care about the sorting.
|
||||
if built_in_slots.contains(&slot.id) { continue; }
|
||||
|
||||
let inp = total_outputs.get(&slot.name)
|
||||
.expect(&format!("failed to find slot: '{}', ensure that there is a pass outputting it", slot.name));
|
||||
inputs.push(*inp);
|
||||
|
|
|
@ -17,8 +17,8 @@ pub use slot_desc::*;
|
|||
|
||||
mod execution_path;
|
||||
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use tracing::{debug_span, instrument, trace};
|
||||
use rustc_hash::FxHashMap;
|
||||
use tracing::{debug_span, instrument, trace, warn};
|
||||
|
||||
use self::execution_path::GraphExecutionPath;
|
||||
|
||||
|
@ -38,6 +38,7 @@ pub struct BindGroupEntry {
|
|||
pub layout: Option<Rc<wgpu::BindGroupLayout>>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct ResourcedSlot {
|
||||
name: String,
|
||||
//slot: RenderPassSlot,
|
||||
|
@ -54,6 +55,13 @@ pub struct PipelineResource {
|
|||
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 {
|
||||
device: Rc<wgpu::Device>,
|
||||
queue: Rc<wgpu::Queue>,
|
||||
|
@ -69,42 +77,21 @@ pub struct RenderGraph {
|
|||
pipelines: FxHashMap<u64, PipelineResource>,
|
||||
current_id: u64,
|
||||
exec_path: Option<GraphExecutionPath>,
|
||||
|
||||
pub(crate) surface_config: wgpu::SurfaceConfiguration,
|
||||
}
|
||||
|
||||
impl RenderGraph {
|
||||
pub fn new(
|
||||
device: Rc<wgpu::Device>,
|
||||
queue: Rc<wgpu::Queue>,
|
||||
surface_config: wgpu::SurfaceConfiguration,
|
||||
) -> Self {
|
||||
let mut slots = FxHashMap::default();
|
||||
let mut slot_names = HashMap::default();
|
||||
|
||||
slots.insert(
|
||||
0,
|
||||
ResourcedSlot {
|
||||
name: "window_texture_view".to_string(),
|
||||
ty: SlotType::TextureView,
|
||||
// this will get set in prepare stage.
|
||||
value: SlotValue::None,
|
||||
},
|
||||
);
|
||||
slot_names.insert("window_texture_view".to_string(), 0u64);
|
||||
|
||||
pub fn new(device: Rc<wgpu::Device>, queue: Rc<wgpu::Queue>) -> Self {
|
||||
Self {
|
||||
device,
|
||||
queue,
|
||||
slots,
|
||||
slot_names,
|
||||
slots: Default::default(),
|
||||
slot_names: Default::default(),
|
||||
passes: Default::default(),
|
||||
bind_groups: Default::default(),
|
||||
bind_group_names: Default::default(),
|
||||
pipelines: Default::default(),
|
||||
current_id: 1,
|
||||
exec_path: None,
|
||||
surface_config,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,6 +125,11 @@ impl RenderGraph {
|
|||
slot.name, desc.name
|
||||
);
|
||||
|
||||
trace!(
|
||||
"Found existing slot for {}, changing id to {}",
|
||||
slot.name, id
|
||||
);
|
||||
|
||||
// if there is a slot of the same name
|
||||
slot.id = *id;
|
||||
} else {
|
||||
|
@ -229,61 +221,61 @@ 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); // include the base pass
|
||||
h
|
||||
};
|
||||
let descs = self.passes.values().map(|p| &*p.desc).collect();
|
||||
let path = GraphExecutionPath::new(builtin, descs);
|
||||
let path = GraphExecutionPath::new(descs);
|
||||
trace!(
|
||||
"Found {} steps in the rendergraph to execute",
|
||||
path.queue.len()
|
||||
);
|
||||
|
||||
self.exec_path = Some(path);
|
||||
}
|
||||
|
||||
#[instrument(skip(self, surface))]
|
||||
pub fn render(&mut self, surface: &wgpu::Surface) {
|
||||
#[instrument(skip(self))]
|
||||
pub fn render(&mut self) {
|
||||
let mut path = self.exec_path.take().unwrap();
|
||||
|
||||
let output = surface.get_current_texture().unwrap();
|
||||
let view = output
|
||||
.texture
|
||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
// update the window texture view slot.
|
||||
let window_tv_slot = self.slots.get_mut(&0).unwrap(); // 0 is window_texture_view
|
||||
debug_assert_eq!(
|
||||
window_tv_slot.name.as_str(),
|
||||
"window_texture_view",
|
||||
"unexpected slot where 'window_texture_view' should be"
|
||||
);
|
||||
window_tv_slot.value = SlotValue::TextureView(Rc::new(view));
|
||||
|
||||
let mut encoders = vec![];
|
||||
let mut encoders = Vec::with_capacity(self.passes.len() / 2);
|
||||
while let Some(pass_id) = path.queue.pop_front() {
|
||||
let pass = self.passes.get(&pass_id).unwrap();
|
||||
let pass_inn = pass.inner.clone();
|
||||
let pass_desc = pass.desc.clone();
|
||||
let label = format!("{} Encoder", pass_desc.name);
|
||||
|
||||
let encoder = self
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
label: Some(&label),
|
||||
});
|
||||
// encoders are not needed for presenter nodes.
|
||||
let encoder = if pass_desc.pass_type == RenderPassType::Presenter {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
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 context = RenderGraphContext::new(&queue, encoder);
|
||||
|
||||
// all encoders need to be submitted before a presenter node is executed.
|
||||
if pass_desc.pass_type == RenderPassType::Presenter {
|
||||
self.queue.submit(encoders.drain(..));
|
||||
}
|
||||
|
||||
let mut inner = pass_inn.borrow_mut();
|
||||
inner.execute(self, &*pass_desc, &mut context);
|
||||
|
||||
encoders.push(context.encoder.unwrap().finish());
|
||||
if let Some(encoder) = context.encoder {
|
||||
encoders.push(encoder.finish());
|
||||
}
|
||||
}
|
||||
|
||||
self.queue.submit(encoders.into_iter());
|
||||
output.present();
|
||||
if !encoders.is_empty() {
|
||||
warn!("{} encoders were not submitted in the same render cycle they were created. \
|
||||
Make sure there is a presenting pass at the end. You may still see something, \
|
||||
however it will be delayed a render cycle.", encoders.len());
|
||||
self.queue.submit(encoders.into_iter());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn slot_value(&self, id: u64) -> Option<&SlotValue> {
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
use std::{collections::HashMap, num::NonZeroU32, rc::Rc};
|
||||
use std::{cell::{Ref, RefCell, RefMut}, collections::HashMap, num::NonZeroU32, rc::Rc};
|
||||
|
||||
use lyra_ecs::World;
|
||||
|
||||
use crate::render::resource::RenderPipelineDescriptor;
|
||||
|
||||
use super::{RenderGraph, RenderGraphContext};
|
||||
use super::{RenderGraph, RenderGraphContext, RenderTarget};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||
pub enum RenderPassType {
|
||||
Compute,
|
||||
#[default]
|
||||
Render,
|
||||
Presenter,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -19,15 +20,19 @@ pub enum SlotType {
|
|||
Sampler,
|
||||
Texture,
|
||||
Buffer,
|
||||
RenderTarget,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SlotValue {
|
||||
None,
|
||||
/// The value will be set during a later phase of the render graph.
|
||||
Lazy,
|
||||
TextureView(Rc<wgpu::TextureView>),
|
||||
Sampler(Rc<wgpu::Sampler>),
|
||||
Texture(Rc<wgpu::Texture>),
|
||||
Buffer(Rc<wgpu::Buffer>),
|
||||
RenderTarget(Rc<RefCell<RenderTarget>>),
|
||||
}
|
||||
|
||||
impl SlotValue {
|
||||
|
@ -52,6 +57,20 @@ impl SlotValue {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_render_target(&self) -> Option<Ref<RenderTarget>> {
|
||||
match self {
|
||||
Self::RenderTarget(v) => Some(v.borrow()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_render_target_mut(&mut self) -> Option<RefMut<RenderTarget>> {
|
||||
match self {
|
||||
Self::RenderTarget(v) => Some(v.borrow_mut()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum SlotAttribute {
|
||||
|
@ -162,6 +181,11 @@ impl RenderGraphPassDesc {
|
|||
}
|
||||
|
||||
pub fn add_slot(&mut self, slot: RenderPassSlot) {
|
||||
debug_assert!(
|
||||
!(slot.attribute == SlotAttribute::Input && slot.value.is_some()),
|
||||
"input slots should not have values"
|
||||
);
|
||||
|
||||
self.slot_names.insert(slot.name.clone(), slot.id);
|
||||
self.slots.push(slot);
|
||||
}
|
||||
|
@ -175,7 +199,7 @@ impl RenderGraphPassDesc {
|
|||
value: Option<SlotValue>,
|
||||
) {
|
||||
debug_assert!(
|
||||
matches!(value, None | Some(SlotValue::Buffer(_))),
|
||||
matches!(value, None | Some(SlotValue::Lazy) | Some(SlotValue::Buffer(_))),
|
||||
"slot value is not a buffer"
|
||||
);
|
||||
|
||||
|
@ -198,7 +222,7 @@ impl RenderGraphPassDesc {
|
|||
value: Option<SlotValue>,
|
||||
) {
|
||||
debug_assert!(
|
||||
matches!(value, None | Some(SlotValue::Texture(_))),
|
||||
matches!(value, None | Some(SlotValue::Lazy) | Some(SlotValue::Texture(_))),
|
||||
"slot value is not a texture"
|
||||
);
|
||||
|
||||
|
@ -221,7 +245,7 @@ impl RenderGraphPassDesc {
|
|||
value: Option<SlotValue>,
|
||||
) {
|
||||
debug_assert!(
|
||||
matches!(value, None | Some(SlotValue::TextureView(_))),
|
||||
matches!(value, None | Some(SlotValue::Lazy) | Some(SlotValue::TextureView(_))),
|
||||
"slot value is not a texture view"
|
||||
);
|
||||
|
||||
|
@ -244,7 +268,7 @@ impl RenderGraphPassDesc {
|
|||
value: Option<SlotValue>,
|
||||
) {
|
||||
debug_assert!(
|
||||
matches!(value, None | Some(SlotValue::Sampler(_))),
|
||||
matches!(value, None | Some(SlotValue::Lazy) | Some(SlotValue::Sampler(_))),
|
||||
"slot value is not a sampler"
|
||||
);
|
||||
|
||||
|
|
|
@ -1,47 +1,100 @@
|
|||
use glam::UVec2;
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use crate::render::{camera::CameraUniform, graph::{BufferInitDescriptor, RenderGraphPass, RenderGraphPassDesc, RenderPassType, SlotAttribute, SlotDescriptor}};
|
||||
use crate::render::graph::{RenderGraphContext, RenderGraphPass, RenderGraphPassDesc, RenderPassSlot, RenderPassType, RenderTarget, SlotAttribute, SlotType, SlotValue};
|
||||
|
||||
/// Supplies some basic things other passes needs.
|
||||
///
|
||||
/// screen size buffer, camera buffer,
|
||||
#[derive(Default)]
|
||||
pub struct BasePass;
|
||||
pub struct BasePass {
|
||||
/// Temporary storage for the main render target
|
||||
///
|
||||
/// This should be Some when the pass is first created then after its added to
|
||||
/// the render graph it will be None and stay None.
|
||||
temp_render_target: Option<RenderTarget>,
|
||||
main_rt_id: u64,
|
||||
window_tv_id: u64,
|
||||
}
|
||||
|
||||
impl BasePass {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
pub fn new(surface: wgpu::Surface, surface_config: wgpu::SurfaceConfiguration) -> Self {
|
||||
Self {
|
||||
temp_render_target: Some(RenderTarget {
|
||||
surface,
|
||||
surface_config,
|
||||
current_texture: None,
|
||||
}),
|
||||
main_rt_id: 0,
|
||||
window_tv_id: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderGraphPass for BasePass {
|
||||
fn desc(&self, graph: &mut crate::render::graph::RenderGraph, id: &mut u64) -> crate::render::graph::RenderGraphPassDesc {
|
||||
let mut desc = RenderGraphPassDesc::new(*id, "BasePass", RenderPassType::Compute);
|
||||
*id += 1;
|
||||
fn desc(&mut self, graph: &mut crate::render::graph::RenderGraph) -> crate::render::graph::RenderGraphPassDesc {
|
||||
let mut desc = RenderGraphPassDesc::new(
|
||||
graph.next_id(),
|
||||
"base",
|
||||
RenderPassType::Render,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
|
||||
desc.add_buffer_slot(*id, "screen_size_buffer", SlotAttribute::Output, Some(SlotDescriptor::BufferInit(BufferInitDescriptor {
|
||||
/* desc.add_buffer_slot(*id, "screen_size_buffer", SlotAttribute::Output, Some(SlotDescriptor::BufferInit(BufferInitDescriptor {
|
||||
label: Some("B_ScreenSize".to_string()),
|
||||
contents: bytemuck::bytes_of(&UVec2::new(800, 600)).to_vec(),
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
})));
|
||||
*id += 1;
|
||||
desc.add_buffer_slot(*id, "camera_buffer", SlotAttribute::Output, Some(SlotDescriptor::BufferInit(BufferInitDescriptor {
|
||||
label: Some("B_Camera".to_string()),
|
||||
contents: bytemuck::bytes_of(&CameraUniform::default()).to_vec(),
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
})));
|
||||
*id += 1;
|
||||
*id += 1; */
|
||||
|
||||
self.main_rt_id = graph.next_id();
|
||||
let render_target = self.temp_render_target.take().unwrap();
|
||||
desc.add_slot(
|
||||
RenderPassSlot {
|
||||
ty: SlotType::RenderTarget,
|
||||
attribute: SlotAttribute::Output,
|
||||
id: self.main_rt_id,
|
||||
name: "main_render_target".into(),
|
||||
value: Some(SlotValue::RenderTarget(Rc::new(RefCell::new(render_target)))),
|
||||
}
|
||||
);
|
||||
self.window_tv_id = graph.next_id();
|
||||
desc.add_texture_view_slot(
|
||||
self.window_tv_id,
|
||||
"window_texture_view",
|
||||
SlotAttribute::Output,
|
||||
Some(SlotValue::Lazy),
|
||||
);
|
||||
|
||||
desc
|
||||
}
|
||||
|
||||
fn prepare(&mut self, world: &mut lyra_ecs::World) {
|
||||
let _ = world;
|
||||
todo!()
|
||||
fn prepare(&mut self, _world: &mut lyra_ecs::World, _context: &mut RenderGraphContext) {
|
||||
|
||||
}
|
||||
|
||||
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!()
|
||||
fn execute(&mut self, graph: &mut crate::render::graph::RenderGraph, _desc: &crate::render::graph::RenderGraphPassDesc, _context: &mut crate::render::graph::RenderGraphContext) {
|
||||
let tv_slot = graph.slot_value_mut(self.main_rt_id)
|
||||
.expect("somehow the main render target slot is missing");
|
||||
let mut rt = tv_slot.as_render_target_mut().unwrap();
|
||||
debug_assert!(!rt.current_texture.is_some(), "main render target surface was not presented!");
|
||||
|
||||
let surface_tex = rt.surface.get_current_texture().unwrap();
|
||||
let view = surface_tex.texture.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
|
||||
|
||||
// store the surface texture to the slot
|
||||
let tv_slot = graph.slot_value_mut(self.window_tv_id)
|
||||
.expect("somehow the window texture view slot is missing");
|
||||
*tv_slot = SlotValue::TextureView(Rc::new(view));
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
/* mod light_cull_compute;
|
||||
pub use light_cull_compute::*;
|
||||
|
||||
mod base;
|
||||
pub use base::*;
|
||||
|
||||
|
||||
mod depth_prepass;
|
||||
pub use depth_prepass::*; */
|
||||
|
@ -10,5 +9,11 @@ pub use depth_prepass::*; */
|
|||
/* mod simple_phong;
|
||||
pub use simple_phong::*; */
|
||||
|
||||
mod base;
|
||||
pub use base::*;
|
||||
|
||||
mod present_pass;
|
||||
pub use present_pass::*;
|
||||
|
||||
mod triangle;
|
||||
pub use triangle::*;
|
|
@ -0,0 +1,52 @@
|
|||
use crate::render::graph::{RenderGraphContext, RenderGraphPass, RenderGraphPassDesc, RenderPassSlot, RenderPassType, SlotAttribute, SlotType};
|
||||
|
||||
/// Supplies some basic things other passes needs.
|
||||
///
|
||||
/// screen size buffer, camera buffer,
|
||||
pub struct PresentPass {
|
||||
render_target_slot: String,
|
||||
}
|
||||
|
||||
impl PresentPass {
|
||||
pub fn new(render_target_slot: &str) -> Self {
|
||||
Self {
|
||||
render_target_slot: render_target_slot.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderGraphPass for PresentPass {
|
||||
fn desc(&mut self, graph: &mut crate::render::graph::RenderGraph) -> crate::render::graph::RenderGraphPassDesc {
|
||||
let mut desc = RenderGraphPassDesc::new(
|
||||
graph.next_id(),
|
||||
&format!("present_{}", self.render_target_slot),
|
||||
RenderPassType::Presenter,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
|
||||
desc.add_slot(
|
||||
RenderPassSlot {
|
||||
ty: SlotType::RenderTarget,
|
||||
attribute: SlotAttribute::Input,
|
||||
id: graph.next_id(),
|
||||
name: self.render_target_slot.clone(),
|
||||
value: None,
|
||||
}
|
||||
);
|
||||
|
||||
desc
|
||||
}
|
||||
|
||||
fn prepare(&mut self, _world: &mut lyra_ecs::World, _context: &mut 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)
|
||||
.expect(&format!("render target slot '{}' for PresentPass is missing", self.render_target_slot));
|
||||
let mut slot = graph.slot_value_mut(id).unwrap().as_render_target_mut().unwrap();
|
||||
let surf_tex = slot.current_texture.take().unwrap();
|
||||
surf_tex.present();
|
||||
}
|
||||
}
|
|
@ -44,6 +44,13 @@ impl RenderGraphPass for TrianglePass {
|
|||
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(),
|
||||
"TrianglePass",
|
||||
|
@ -61,7 +68,7 @@ impl RenderGraphPass for TrianglePass {
|
|||
module: shader,
|
||||
entry_point: "fs_main".into(),
|
||||
targets: vec![Some(wgpu::ColorTargetState {
|
||||
format: graph.surface_config.format,
|
||||
format: surface_config_format,
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
|
@ -12,7 +13,7 @@ use wgpu::Limits;
|
|||
use winit::window::Window;
|
||||
|
||||
use crate::math::Transform;
|
||||
use crate::render::graph::TrianglePass;
|
||||
use crate::render::graph::{BasePass, PresentPass, TrianglePass};
|
||||
use crate::render::material::MaterialUniform;
|
||||
use crate::render::render_buffer::BufferWrapperBuilder;
|
||||
|
||||
|
@ -82,10 +83,8 @@ pub struct InterpTransform {
|
|||
}
|
||||
|
||||
pub struct BasicRenderer {
|
||||
pub surface: wgpu::Surface,
|
||||
pub device: Rc<wgpu::Device>, // device does not need to be mutable, no need for refcell
|
||||
pub queue: Rc<wgpu::Queue>,
|
||||
pub config: wgpu::SurfaceConfiguration,
|
||||
pub size: winit::dpi::PhysicalSize<u32>,
|
||||
pub window: Arc<Window>,
|
||||
|
||||
|
@ -214,7 +213,7 @@ impl BasicRenderer {
|
|||
let queue = Rc::new(queue);
|
||||
//let light_cull_compute = LightCullCompute::new(device.clone(), queue.clone(), size, &light_uniform_buffers, &camera_buffer, &mut depth_texture);
|
||||
|
||||
let mut g = RenderGraph::new(device.clone(), queue.clone(), config.clone());
|
||||
let mut g = RenderGraph::new(device.clone(), queue.clone());
|
||||
/* debug!("Adding base pass");
|
||||
g.add_pass(TrianglePass::new());
|
||||
debug!("Adding depth pre-pass");
|
||||
|
@ -222,16 +221,18 @@ impl BasicRenderer {
|
|||
debug!("Adding light cull compute pass");
|
||||
g.add_pass(LightCullComputePass::new(size)); */
|
||||
|
||||
debug!("Adding base pass");
|
||||
g.add_pass(BasePass::new(surface, config));
|
||||
debug!("Adding triangle pass");
|
||||
g.add_pass(TrianglePass::new());
|
||||
debug!("Adding present pass");
|
||||
g.add_pass(PresentPass::new("main_render_target"));
|
||||
g.setup(&device);
|
||||
|
||||
let mut s = Self {
|
||||
Self {
|
||||
window,
|
||||
surface,
|
||||
device,
|
||||
queue,
|
||||
config,
|
||||
size,
|
||||
clear_color: wgpu::Color {
|
||||
r: 0.1,
|
||||
|
@ -244,21 +245,7 @@ impl BasicRenderer {
|
|||
|
||||
render_limits,
|
||||
graph: g,
|
||||
};
|
||||
|
||||
// create the default pipelines
|
||||
/* let mut pipelines = rustc_hash::FxHashMap::default();
|
||||
pipelines.insert(0, Arc::new(RenderPipeline::new(&s.device, &s.config, &shader,
|
||||
vec![super::vertex::Vertex::desc(),],
|
||||
vec![&s.bgl_texture, &s.transform_buffers.bindgroup_layout,
|
||||
s.camera_buffer.bindgroup_layout().unwrap(),
|
||||
&s.light_buffers.bind_group_pair.layout, &s.material_buffer.bindgroup_pair.as_ref().unwrap().layout,
|
||||
&s.bgl_texture,
|
||||
&s.light_cull_compute.light_indices_grid.bg_pair.layout,
|
||||
])));
|
||||
s.render_pipelines = pipelines; */
|
||||
|
||||
s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,7 +257,7 @@ impl Renderer for BasicRenderer {
|
|||
|
||||
#[instrument(skip(self))]
|
||||
fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
|
||||
self.graph.render(&self.surface);
|
||||
self.graph.render();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -279,15 +266,17 @@ impl Renderer for BasicRenderer {
|
|||
fn on_resize(&mut self, world: &mut World, new_size: winit::dpi::PhysicalSize<u32>) {
|
||||
if new_size.width > 0 && new_size.height > 0 {
|
||||
self.size = new_size;
|
||||
self.config.width = new_size.width;
|
||||
self.config.height = new_size.height;
|
||||
|
||||
// tell other things of updated resize
|
||||
self.surface.configure(&self.device, &self.config);
|
||||
|
||||
// update surface config and the surface
|
||||
let mut rt = self.graph.slot_value_mut(self.graph.slot_id("main_render_target").unwrap())
|
||||
.unwrap().as_render_target_mut().unwrap();
|
||||
rt.surface_config.width = new_size.width;
|
||||
rt.surface_config.height = new_size.height;
|
||||
rt.surface.configure(&self.device, &rt.surface_config);
|
||||
|
||||
// update screen size resource in ecs
|
||||
let mut world_ss = world.get_resource_mut::<ScreenSize>();
|
||||
world_ss.0 = glam::UVec2::new(new_size.width, new_size.height);
|
||||
self.graph.surface_config = self.config.clone();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue