From 527b6172efa1cbe95eead7396b3c18d732141948 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Mon, 11 Dec 2023 23:47:07 -0500 Subject: [PATCH 1/8] Iterate on the rendergraph api --- rend3-routine/src/base.rs | 285 +++++++++++++++++--------------------- 1 file changed, 130 insertions(+), 155 deletions(-) diff --git a/rend3-routine/src/base.rs b/rend3-routine/src/base.rs index 6252db3c..1732e514 100644 --- a/rend3-routine/src/base.rs +++ b/rend3-routine/src/base.rs @@ -21,7 +21,6 @@ use rend3::{ graph::{ DataHandle, InstructionEvaluationOutput, RenderGraph, RenderTargetDescriptor, RenderTargetHandle, ViewportRect, }, - managers::ShadowDesc, types::{SampleCount, TextureFormat, TextureUsages}, Renderer, ShaderPreProcessor, INTERNAL_SHADOW_DEPTH_FORMAT, }; @@ -31,7 +30,7 @@ use crate::{ common::{self, CameraIndex}, culling, forward::RoutineAddToGraphArgs, - pbr, skinning, skybox, tonemapping, + pbr, skinning, }; #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -75,6 +74,22 @@ impl DepthTargets { } } +pub struct BaseRenderGraphInputs<'a, 'node> { + pub eval_output: &'a InstructionEvaluationOutput, + pub pbr: &'node crate::pbr::PbrRoutine, + pub skybox: Option<&'node crate::skybox::SkyboxRoutine>, + pub tonemapping: &'node crate::tonemapping::TonemappingRoutine, + pub target_texture: RenderTargetHandle, + pub resolution: UVec2, + pub samples: SampleCount, +} + +#[derive(Debug, Default)] +pub struct BaseRenderGraphSettings { + pub ambient: Vec4, + pub clear_color: Vec4, +} + /// Starter RenderGraph. /// /// See module for documentation. @@ -112,69 +127,62 @@ impl BaseRenderGraph { pub fn add_to_graph<'node>( &'node self, graph: &mut RenderGraph<'node>, - eval_output: &InstructionEvaluationOutput, - pbr: &'node crate::pbr::PbrRoutine, - skybox: Option<&'node crate::skybox::SkyboxRoutine>, - tonemapping: &'node crate::tonemapping::TonemappingRoutine, - target_texture: RenderTargetHandle, - resolution: UVec2, - samples: SampleCount, - ambient: Vec4, - clear_color: Vec4, + inputs: BaseRenderGraphInputs<'_, 'node>, + settings: BaseRenderGraphSettings, ) { // Create the data and handles for the graph. - let state = BaseRenderGraphIntermediateState::new(graph, eval_output, resolution, samples); + let mut state = BaseRenderGraphIntermediateState::new(graph, inputs, settings); // Clear the shadow map. - state.clear_shadow(graph); + state.clear_shadow(); // Prepare all the uniforms that all shaders need access to. - state.create_frame_uniforms(graph, self, ambient, resolution); + state.create_frame_uniforms(self); // Perform compute based skinning. - state.skinning(graph, self); + state.skinning(self); // Upload the uniforms for the objects in the shadow pass. - state.shadow_object_uniform_upload(graph, self, eval_output); + state.shadow_object_uniform_upload(self); // Perform culling for the objects in the shadow pass. - state.pbr_shadow_culling(graph, self); + state.pbr_shadow_culling(self); // Render all the shadows to the shadow map. - state.pbr_shadow_rendering(graph, pbr, &eval_output.shadows); + state.pbr_shadow_rendering(); // Clear the primary render target and depth target. - state.clear(graph, clear_color); + state.clear(); // Upload the uniforms for the objects in the forward pass. - state.object_uniform_upload(graph, self, resolution, samples); + state.object_uniform_upload(self); // Do the first pass, rendering the predicted triangles from last frame. - state.pbr_render_opaque_predicted_triangles(graph, pbr, samples); + state.pbr_render_opaque_predicted_triangles(); // Create the hi-z buffer. - state.hi_z(graph, pbr, resolution); + state.hi_z(); // Perform culling for the objects in the forward pass. // // The result of culling will be used to predict the visible triangles for // the next frame. It will also render all the triangles that were visible // but were not predicted last frame. - state.pbr_culling(graph, self); + state.pbr_culling(self); // Do the second pass, rendering the residual triangles. - state.pbr_render_opaque_residual_triangles(graph, pbr, samples); + state.pbr_render_opaque_residual_triangles(); // Render the skybox. - state.skybox(graph, skybox, samples); + state.skybox(); // Render all transparent objects. // // This _must_ happen after culling, as all transparent objects are // considered "residual". - state.pbr_forward_rendering_transparent(graph, pbr, samples); + state.pbr_forward_rendering_transparent(); // Tonemap the HDR inner buffer to the output buffer. - state.tonemapping(graph, tonemapping, target_texture); + state.tonemapping(); } } @@ -182,7 +190,11 @@ impl BaseRenderGraph { /// /// This is intentionally public so all this can be changed by the user if they /// so desire. -pub struct BaseRenderGraphIntermediateState { +pub struct BaseRenderGraphIntermediateState<'a, 'node> { + pub graph: &'a mut RenderGraph<'node>, + pub inputs: BaseRenderGraphInputs<'a, 'node>, + pub settings: BaseRenderGraphSettings, + pub pre_cull: DataHandle, pub shadow_cull: Vec>>, pub cull: DataHandle>, @@ -195,16 +207,15 @@ pub struct BaseRenderGraphIntermediateState { pub depth: DepthTargets, pub pre_skinning_buffers: DataHandle, } -impl BaseRenderGraphIntermediateState { +impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { /// Create the default setting for all state. pub fn new( - graph: &mut RenderGraph<'_>, - eval_output: &InstructionEvaluationOutput, - resolution: UVec2, - samples: SampleCount, + graph: &'a mut RenderGraph<'node>, + inputs: BaseRenderGraphInputs<'a, 'node>, + settings: BaseRenderGraphSettings, ) -> Self { // We need to know how many shadows we need to render - let shadow_count = eval_output.shadows.len(); + let shadow_count = inputs.eval_output.shadows.len(); // Create global bind group information let shadow_uniform_bg = graph.add_data::(); @@ -213,7 +224,7 @@ impl BaseRenderGraphIntermediateState { // Shadow render target let shadow = graph.add_render_target(RenderTargetDescriptor { label: Some("shadow target".into()), - resolution: eval_output.shadow_target_size, + resolution: inputs.eval_output.shadow_target_size, depth: 1, mip_levels: Some(1), samples: SampleCount::One, @@ -224,17 +235,17 @@ impl BaseRenderGraphIntermediateState { // Make the actual render targets we want to render to. let color = graph.add_render_target(RenderTargetDescriptor { label: Some("hdr color".into()), - resolution, + resolution: inputs.resolution, depth: 1, - samples, + samples: inputs.samples, mip_levels: Some(1), format: TextureFormat::Rgba16Float, usage: TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING, }); - let resolve = samples.needs_resolve().then(|| { + let resolve = inputs.samples.needs_resolve().then(|| { graph.add_render_target(RenderTargetDescriptor { label: Some("hdr resolve".into()), - resolution, + resolution: inputs.resolution, depth: 1, mip_levels: Some(1), samples: SampleCount::One, @@ -242,18 +253,22 @@ impl BaseRenderGraphIntermediateState { usage: TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING, }) }); - let depth = DepthTargets::new(graph, resolution, samples); + let depth = DepthTargets::new(graph, inputs.resolution, inputs.samples); let pre_skinning_buffers = graph.add_data::(); + let pre_cull = graph.add_data(); + let mut shadow_cull = Vec::with_capacity(shadow_count); + shadow_cull.resize_with(shadow_count, || graph.add_data()); + let cull = graph.add_data(); Self { - pre_cull: graph.add_data(), - shadow_cull: { - let mut shadows = Vec::with_capacity(shadow_count); - shadows.resize_with(shadow_count, || graph.add_data()); - shadows - }, - cull: graph.add_data(), + graph, + inputs, + settings, + + pre_cull, + shadow_cull, + cull, shadow_uniform_bg, forward_uniform_bg, @@ -266,33 +281,23 @@ impl BaseRenderGraphIntermediateState { } /// Create all the uniforms all the shaders in this graph need. - pub fn create_frame_uniforms<'node>( - &self, - graph: &mut RenderGraph<'node>, - base: &'node BaseRenderGraph, - ambient: Vec4, - resolution: UVec2, - ) { + pub fn create_frame_uniforms(&mut self, base: &'node BaseRenderGraph) { crate::uniforms::add_to_graph( - graph, + self.graph, self.shadow_uniform_bg, self.forward_uniform_bg, self.shadow, &base.interfaces, &base.samplers, - ambient, - resolution, + self.settings.ambient, + self.inputs.resolution, ); } - pub fn shadow_object_uniform_upload<'node>( - &self, - graph: &mut RenderGraph<'node>, - base: &'node BaseRenderGraph, - eval_output: &InstructionEvaluationOutput, - ) { - for (shadow_index, shadow) in eval_output.shadows.iter().enumerate() { + + pub fn shadow_object_uniform_upload(&mut self, base: &'node BaseRenderGraph) { + for (shadow_index, shadow) in self.inputs.eval_output.shadows.iter().enumerate() { base.gpu_culler.add_object_uniform_upload_to_graph::( - graph, + self.graph, CameraIndex::Shadow(shadow_index as u32), UVec2::splat(shadow.map.size), SampleCount::One, @@ -302,10 +307,10 @@ impl BaseRenderGraphIntermediateState { } /// Does all shadow culling for the PBR materials. - pub fn pbr_shadow_culling<'node>(&self, graph: &mut RenderGraph<'node>, base: &'node BaseRenderGraph) { + pub fn pbr_shadow_culling(&mut self, base: &'node BaseRenderGraph) { for (shadow_index, &shadow_culled) in self.shadow_cull.iter().enumerate() { base.gpu_culler.add_culling_to_graph::( - graph, + self.graph, shadow_culled, self.shadow, CameraIndex::Shadow(shadow_index as u32), @@ -314,30 +319,24 @@ impl BaseRenderGraphIntermediateState { } } - pub fn skinning<'node>(&self, graph: &mut RenderGraph<'node>, base: &'node BaseRenderGraph) { - skinning::add_skinning_to_graph(graph, &base.gpu_skinner); + pub fn skinning(&mut self, base: &'node BaseRenderGraph) { + skinning::add_skinning_to_graph(self.graph, &base.gpu_skinner); } - pub fn object_uniform_upload<'node>( - &self, - graph: &mut RenderGraph<'node>, - base: &'node BaseRenderGraph, - resolution: UVec2, - samples: SampleCount, - ) { + pub fn object_uniform_upload(&mut self, base: &'node BaseRenderGraph) { base.gpu_culler.add_object_uniform_upload_to_graph::( - graph, + self.graph, CameraIndex::Viewport, - resolution, - samples, + self.inputs.resolution, + self.inputs.samples, "Uniform Bake", ); } /// Does all culling for the forward PBR materials. - pub fn pbr_culling<'node>(&self, graph: &mut RenderGraph<'node>, base: &'node BaseRenderGraph) { + pub fn pbr_culling(&mut self, base: &'node BaseRenderGraph) { base.gpu_culler.add_culling_to_graph::( - graph, + self.graph, self.cull, self.depth.single_sample_mipped, CameraIndex::Viewport, @@ -346,38 +345,33 @@ impl BaseRenderGraphIntermediateState { } /// Clear all the targets to their needed values - pub fn clear_shadow(&self, graph: &mut RenderGraph<'_>) { - crate::clear::add_clear_to_graph(graph, None, None, self.shadow, Vec4::ZERO, 0.0); + pub fn clear_shadow(&mut self) { + crate::clear::add_clear_to_graph(self.graph, None, None, self.shadow, Vec4::ZERO, 0.0); } /// Clear all the targets to their needed values - pub fn clear(&self, graph: &mut RenderGraph<'_>, clear_color: Vec4) { + pub fn clear(&mut self) { crate::clear::add_clear_to_graph( - graph, + self.graph, Some(self.color), self.resolve, self.depth.rendering_target(), - clear_color, + self.settings.clear_color, 0.0, ); } /// Render all shadows for the PBR materials. - pub fn pbr_shadow_rendering<'node>( - &self, - graph: &mut RenderGraph<'node>, - pbr: &'node pbr::PbrRoutine, - shadows: &[ShadowDesc], - ) { - let iter = zip(&self.shadow_cull, shadows); + pub fn pbr_shadow_rendering(&mut self) { + let iter = zip(&self.shadow_cull, &self.inputs.eval_output.shadows); for (shadow_index, (shadow_cull, desc)) in iter.enumerate() { - let routines = [&pbr.opaque_depth, &pbr.cutout_depth]; + let routines = [&self.inputs.pbr.opaque_depth, &self.inputs.pbr.cutout_depth]; for routine in routines { routine.add_forward_to_graph(RoutineAddToGraphArgs { - graph, + graph: self.graph, whole_frame_uniform_bg: self.shadow_uniform_bg, culling_output_handle: Some(*shadow_cull), - per_material: &pbr.per_material, + per_material: &self.inputs.pbr.per_material, extra_bgs: None, label: &format!("pbr shadow renderering S{shadow_index}"), samples: SampleCount::One, @@ -393,41 +387,31 @@ impl BaseRenderGraphIntermediateState { } /// Render the skybox. - pub fn skybox<'node>( - &self, - graph: &mut RenderGraph<'node>, - skybox: Option<&'node skybox::SkyboxRoutine>, - samples: SampleCount, - ) { - if let Some(skybox) = skybox { + pub fn skybox(&mut self) { + if let Some(skybox) = self.inputs.skybox { skybox.add_to_graph( - graph, + self.graph, self.color, self.resolve, self.depth.rendering_target(), self.forward_uniform_bg, - samples, + self.inputs.samples, ); } } /// Render the PBR materials. - pub fn pbr_render_opaque_predicted_triangles<'node>( - &self, - graph: &mut RenderGraph<'node>, - pbr: &'node pbr::PbrRoutine, - samples: SampleCount, - ) { - let routines = [&pbr.opaque_routine, &pbr.cutout_routine]; + pub fn pbr_render_opaque_predicted_triangles(&mut self) { + let routines = [&self.inputs.pbr.opaque_routine, &self.inputs.pbr.cutout_routine]; for routine in routines { routine.add_forward_to_graph(RoutineAddToGraphArgs { - graph, + graph: self.graph, whole_frame_uniform_bg: self.forward_uniform_bg, culling_output_handle: None, - per_material: &pbr.per_material, + per_material: &self.inputs.pbr.per_material, extra_bgs: None, label: "PBR Forward Pass 1", - samples, + samples: self.inputs.samples, camera: CameraIndex::Viewport, color: Some(self.color), resolve: self.resolve, @@ -437,22 +421,17 @@ impl BaseRenderGraphIntermediateState { } /// Render the PBR materials. - pub fn pbr_render_opaque_residual_triangles<'node>( - &self, - graph: &mut RenderGraph<'node>, - pbr: &'node pbr::PbrRoutine, - samples: SampleCount, - ) { - let routines = [&pbr.opaque_routine, &pbr.cutout_routine]; + pub fn pbr_render_opaque_residual_triangles(&mut self) { + let routines = [&self.inputs.pbr.opaque_routine, &self.inputs.pbr.cutout_routine]; for routine in routines { routine.add_forward_to_graph(RoutineAddToGraphArgs { - graph, + graph: self.graph, whole_frame_uniform_bg: self.forward_uniform_bg, culling_output_handle: Some(self.cull), - per_material: &pbr.per_material, + per_material: &self.inputs.pbr.per_material, extra_bgs: None, label: "PBR Forward Pass 2", - samples, + samples: self.inputs.samples, camera: CameraIndex::Viewport, color: Some(self.color), resolve: self.resolve, @@ -462,42 +441,38 @@ impl BaseRenderGraphIntermediateState { } /// Render the PBR materials. - pub fn pbr_forward_rendering_transparent<'node>( - &self, - graph: &mut RenderGraph<'node>, - pbr: &'node pbr::PbrRoutine, - samples: SampleCount, - ) { - pbr.blend_routine.add_forward_to_graph(RoutineAddToGraphArgs { - graph, - whole_frame_uniform_bg: self.forward_uniform_bg, - culling_output_handle: Some(self.cull), - per_material: &pbr.per_material, - extra_bgs: None, - label: "PBR Forward", - camera: CameraIndex::Viewport, - samples, - color: Some(self.color), - resolve: self.resolve, - depth: self.depth.rendering_target(), - }); + pub fn pbr_forward_rendering_transparent(&mut self) { + self.inputs + .pbr + .blend_routine + .add_forward_to_graph(RoutineAddToGraphArgs { + graph: self.graph, + whole_frame_uniform_bg: self.forward_uniform_bg, + culling_output_handle: Some(self.cull), + per_material: &self.inputs.pbr.per_material, + extra_bgs: None, + label: "PBR Forward", + camera: CameraIndex::Viewport, + samples: self.inputs.samples, + color: Some(self.color), + resolve: self.resolve, + depth: self.depth.rendering_target(), + }); } - pub fn hi_z<'node>(&self, graph: &mut RenderGraph<'node>, pbr: &'node pbr::PbrRoutine, resolution: UVec2) { - pbr.hi_z.add_hi_z_to_graph(graph, self.depth, resolution); + pub fn hi_z(&mut self) { + self.inputs + .pbr + .hi_z + .add_hi_z_to_graph(self.graph, self.depth, self.inputs.resolution); } /// Tonemap onto the given render target. - pub fn tonemapping<'node>( - &self, - graph: &mut RenderGraph<'node>, - tonemapping: &'node tonemapping::TonemappingRoutine, - target: RenderTargetHandle, - ) { - tonemapping.add_to_graph( - graph, + pub fn tonemapping(&mut self) { + self.inputs.tonemapping.add_to_graph( + self.graph, self.resolve.unwrap_or(self.color), - target, + self.inputs.target_texture, self.forward_uniform_bg, ); } From ab79659a9b2dc769de3cdcad35eb73409fbc941c Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Mon, 18 Dec 2023 02:03:21 -0500 Subject: [PATCH 2/8] Vastly clean up base rendergraph internals --- Cargo.toml | 6 +- examples/animation/src/lib.rs | 22 ++- examples/cube-no-framework/src/main.rs | 22 ++- examples/cube/src/lib.rs | 22 ++- examples/egui/src/main.rs | 22 ++- examples/scene-viewer/src/lib.rs | 22 ++- examples/skinning/src/lib.rs | 22 ++- examples/static-gltf/src/main.rs | 22 ++- examples/textured-quad/src/main.rs | 22 ++- rend3-egui/src/lib.rs | 11 +- rend3-routine/src/base.rs | 181 +++++++++--------- rend3-routine/src/clear.rs | 47 ----- rend3-routine/src/common/camera.rs | 10 +- rend3-routine/src/common/interfaces.rs | 5 + rend3-routine/src/culling/batching.rs | 20 +- rend3-routine/src/culling/culler.rs | 56 +++--- rend3-routine/src/forward.rs | 153 +++++++++------ rend3-routine/src/hi_z.rs | 18 +- rend3-routine/src/lib.rs | 1 - rend3-routine/src/pbr/routine.rs | 4 +- rend3-routine/src/skybox.rs | 28 +-- rend3-routine/src/tonemapping.rs | 8 +- rend3-routine/src/uniforms.rs | 77 ++++---- rend3-test/src/runner.rs | 22 ++- rend3/src/graph/graph.rs | 20 +- rend3/src/graph/mod.rs | 32 ++-- rend3/src/graph/node.rs | 7 + rend3/src/managers/camera.rs | 6 +- rend3/src/managers/directional.rs | 6 +- .../src/managers/directional/shadow_camera.rs | 6 +- rend3/src/renderer/eval.rs | 8 +- rend3/src/renderer/mod.rs | 6 +- rend3/src/renderer/setup.rs | 6 +- 33 files changed, 476 insertions(+), 444 deletions(-) delete mode 100644 rend3-routine/src/clear.rs diff --git a/Cargo.toml b/Cargo.toml index ba1f3401..d82f5965 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,10 +24,10 @@ inherits = "dev" debug = false incremental = false -[profile.dev-release] -inherits = "dev" +[profile.ci.package."*"] +opt-level = 0 -[profile.dev-release.package."*"] +[profile.dev.package."*"] opt-level = 3 [profile.release] diff --git a/examples/animation/src/lib.rs b/examples/animation/src/lib.rs index 8f159c85..460d806c 100644 --- a/examples/animation/src/lib.rs +++ b/examples/animation/src/lib.rs @@ -173,15 +173,19 @@ impl rend3_framework::App for AnimationExample { // Add the default rendergraph without a skybox base_rendergraph.add_to_graph( &mut graph, - &eval_output, - &pbr_routine, - None, - &tonemapping_routine, - frame_handle, - resolution, - SAMPLE_COUNT, - glam::Vec4::splat(0.15), - glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + rend3_routine::base::BaseRenderGraphInputs { + eval_output: &eval_output, + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + target_texture: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, + rend3_routine::base::BaseRenderGraphSettings { + ambient_color: glam::Vec4::ZERO, + clear_color: glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + }, ); // Dispatch a render using the built up rendergraph! diff --git a/examples/cube-no-framework/src/main.rs b/examples/cube-no-framework/src/main.rs index 8495a2bf..95d8f952 100644 --- a/examples/cube-no-framework/src/main.rs +++ b/examples/cube-no-framework/src/main.rs @@ -220,15 +220,19 @@ fn main() { // Add the default rendergraph without a skybox base_rendergraph.add_to_graph( &mut graph, - &eval_output, - &pbr_routine, - None, - &tonemapping_routine, - frame_handle, - resolution, - rend3::types::SampleCount::One, - glam::Vec4::ZERO, - glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + rend3_routine::base::BaseRenderGraphInputs { + eval_output: &eval_output, + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + target_texture: frame_handle, + resolution, + samples: rend3::types::SampleCount::One, + }, + rend3_routine::base::BaseRenderGraphSettings { + ambient_color: glam::Vec4::ZERO, + clear_color: glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + }, ); // Dispatch a render using the built up rendergraph! diff --git a/examples/cube/src/lib.rs b/examples/cube/src/lib.rs index bdb9d989..3dde28e9 100644 --- a/examples/cube/src/lib.rs +++ b/examples/cube/src/lib.rs @@ -193,15 +193,19 @@ impl rend3_framework::App for CubeExample { // Add the default rendergraph without a skybox base_rendergraph.add_to_graph( &mut graph, - &eval_output, - &pbr_routine, - None, - &tonemapping_routine, - frame_handle, - resolution, - SAMPLE_COUNT, - glam::Vec4::ZERO, - glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + rend3_routine::base::BaseRenderGraphInputs { + eval_output: &eval_output, + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + target_texture: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, + rend3_routine::base::BaseRenderGraphSettings { + ambient_color: glam::Vec4::ZERO, + clear_color: glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + }, ); // Dispatch a render using the built up rendergraph! diff --git a/examples/egui/src/main.rs b/examples/egui/src/main.rs index 662e398b..0e257e07 100644 --- a/examples/egui/src/main.rs +++ b/examples/egui/src/main.rs @@ -225,15 +225,19 @@ impl rend3_framework::App for EguiExample { // Add the default rendergraph without a skybox base_rendergraph.add_to_graph( &mut graph, - &eval_output, - &pbr_routine, - None, - &tonemapping_routine, - frame_handle, - resolution, - SAMPLE_COUNT, - glam::Vec4::ZERO, - glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + rend3_routine::base::BaseRenderGraphInputs { + eval_output: &eval_output, + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + target_texture: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, + rend3_routine::base::BaseRenderGraphSettings { + ambient_color: glam::Vec4::ZERO, + clear_color: glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + }, ); // Add egui on top of all the other passes diff --git a/examples/scene-viewer/src/lib.rs b/examples/scene-viewer/src/lib.rs index 82d709be..049b9742 100644 --- a/examples/scene-viewer/src/lib.rs +++ b/examples/scene-viewer/src/lib.rs @@ -634,15 +634,19 @@ impl rend3_framework::App for SceneViewer { // Add the default rendergraph base_rendergraph.add_to_graph( &mut graph, - &eval_output, - &pbr_routine, - Some(&skybox_routine), - &tonemapping_routine, - frame_handle, - resolution, - self.samples, - Vec3::splat(self.ambient_light_level).extend(1.0), - glam::Vec4::new(0.0, 0.0, 0.0, 1.0), + rend3_routine::base::BaseRenderGraphInputs { + eval_output: &eval_output, + pbr: &pbr_routine, + skybox: Some(&skybox_routine), + tonemapping: &tonemapping_routine, + target_texture: frame_handle, + resolution, + samples: self.samples, + }, + rend3_routine::base::BaseRenderGraphSettings { + ambient_color: Vec3::splat(self.ambient_light_level).extend(1.0), + clear_color: glam::Vec4::new(0.0, 0.0, 0.0, 1.0), + }, ); // Dispatch a render using the built up rendergraph! diff --git a/examples/skinning/src/lib.rs b/examples/skinning/src/lib.rs index ec7401b1..f8c262b3 100644 --- a/examples/skinning/src/lib.rs +++ b/examples/skinning/src/lib.rs @@ -167,15 +167,19 @@ impl rend3_framework::App for SkinningExample { // Add the default rendergraph without a skybox base_rendergraph.add_to_graph( &mut graph, - &eval_output, - &pbr_routine, - None, - &tonemapping_routine, - frame_handle, - resolution, - SAMPLE_COUNT, - glam::Vec4::splat(0.15), - glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + rend3_routine::base::BaseRenderGraphInputs { + eval_output: &eval_output, + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + target_texture: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, + rend3_routine::base::BaseRenderGraphSettings { + ambient_color: glam::Vec4::ZERO, + clear_color: glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + }, ); // Dispatch a render using the built up rendergraph! diff --git a/examples/static-gltf/src/main.rs b/examples/static-gltf/src/main.rs index 2ea21eff..d062c4cb 100644 --- a/examples/static-gltf/src/main.rs +++ b/examples/static-gltf/src/main.rs @@ -158,15 +158,19 @@ impl rend3_framework::App for GltfExample { // Add the default rendergraph without a skybox base_rendergraph.add_to_graph( &mut graph, - &eval_output, - &pbr_routine, - None, - &tonemapping_routine, - frame_handle, - resolution, - SAMPLE_COUNT, - glam::Vec4::ZERO, - glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + rend3_routine::base::BaseRenderGraphInputs { + eval_output: &eval_output, + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + target_texture: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, + rend3_routine::base::BaseRenderGraphSettings { + ambient_color: glam::Vec4::ZERO, + clear_color: glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + }, ); // Dispatch a render using the built up rendergraph! graph.execute(renderer, &mut eval_output); diff --git a/examples/textured-quad/src/main.rs b/examples/textured-quad/src/main.rs index 714cbb2f..f788fbc1 100644 --- a/examples/textured-quad/src/main.rs +++ b/examples/textured-quad/src/main.rs @@ -183,15 +183,19 @@ impl rend3_framework::App for TexturedQuadExample { // Add the default rendergraph base_rendergraph.add_to_graph( &mut graph, - &eval_output, - &pbr_routine, - None, - &tonemapping_routine, - frame_handle, - resolution, - SAMPLE_COUNT, - glam::Vec4::ZERO, - glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + rend3_routine::base::BaseRenderGraphInputs { + eval_output: &eval_output, + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + target_texture: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, + rend3_routine::base::BaseRenderGraphSettings { + ambient_color: glam::Vec4::ZERO, + clear_color: glam::Vec4::new(0.10, 0.05, 0.10, 1.0), // Nice scene-referred purple + }, ); // Dispatch a render using the built up rendergraph! diff --git a/rend3-egui/src/lib.rs b/rend3-egui/src/lib.rs index b6a036f1..3d530854 100644 --- a/rend3-egui/src/lib.rs +++ b/rend3-egui/src/lib.rs @@ -5,12 +5,13 @@ use std::{mem, sync::Arc}; use egui::TexturesDelta; +use glam::Vec4; use rend3::{ - graph::{NodeResourceUsage, RenderGraph, RenderPassTarget, RenderPassTargets, RenderTargetHandle}, + graph::{RenderGraph, RenderPassTarget, RenderPassTargets, RenderTargetHandle}, types::SampleCount, Renderer, }; -use wgpu::{Color, TextureFormat}; +use wgpu::TextureFormat; pub struct EguiRenderRoutine { pub internal: egui_wgpu::Renderer, @@ -58,12 +59,10 @@ impl EguiRenderRoutine { ) { let mut builder = graph.add_node("egui"); - let output_handle = builder.add_render_target(output, NodeResourceUsage::InputOutput); - let rpass_handle = builder.add_renderpass(RenderPassTargets { targets: vec![RenderPassTarget { - color: output_handle, - clear: Color::BLACK, + color: output, + clear: Vec4::ZERO, resolve: None, }], depth_stencil: None, diff --git a/rend3-routine/src/base.rs b/rend3-routine/src/base.rs index 1732e514..5fa052a2 100644 --- a/rend3-routine/src/base.rs +++ b/rend3-routine/src/base.rs @@ -19,7 +19,8 @@ use glam::{UVec2, Vec4}; use rend3::{ format_sso, graph::{ - DataHandle, InstructionEvaluationOutput, RenderGraph, RenderTargetDescriptor, RenderTargetHandle, ViewportRect, + self, DataHandle, InstructionEvaluationOutput, RenderGraph, RenderPassTargets, RenderTargetDescriptor, + RenderTargetHandle, ViewportRect, }, types::{SampleCount, TextureFormat, TextureUsages}, Renderer, ShaderPreProcessor, INTERNAL_SHADOW_DEPTH_FORMAT, @@ -27,10 +28,10 @@ use rend3::{ use wgpu::{BindGroup, Buffer}; use crate::{ - common::{self, CameraIndex}, + common::{self, CameraSpecifier}, culling, - forward::RoutineAddToGraphArgs, - pbr, skinning, + forward::{self, ForwardRoutineArgs}, + pbr, skinning, uniforms, }; #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -86,7 +87,7 @@ pub struct BaseRenderGraphInputs<'a, 'node> { #[derive(Debug, Default)] pub struct BaseRenderGraphSettings { - pub ambient: Vec4, + pub ambient_color: Vec4, pub clear_color: Vec4, } @@ -133,9 +134,6 @@ impl BaseRenderGraph { // Create the data and handles for the graph. let mut state = BaseRenderGraphIntermediateState::new(graph, inputs, settings); - // Clear the shadow map. - state.clear_shadow(); - // Prepare all the uniforms that all shaders need access to. state.create_frame_uniforms(self); @@ -150,9 +148,6 @@ impl BaseRenderGraph { // Render all the shadows to the shadow map. state.pbr_shadow_rendering(); - // Clear the primary render target and depth target. - state.clear(); - // Upload the uniforms for the objects in the forward pass. state.object_uniform_upload(self); @@ -201,10 +196,11 @@ pub struct BaseRenderGraphIntermediateState<'a, 'node> { pub shadow_uniform_bg: DataHandle, pub forward_uniform_bg: DataHandle, + pub shadow: RenderTargetHandle, - pub color: RenderTargetHandle, - pub resolve: Option, pub depth: DepthTargets, + pub primary_renderpass: RenderPassTargets, + pub pre_skinning_buffers: DataHandle, } impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { @@ -254,6 +250,18 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { }) }); let depth = DepthTargets::new(graph, inputs.resolution, inputs.samples); + let primary_renderpass = graph::RenderPassTargets { + targets: vec![graph::RenderPassTarget { + color, + resolve, + clear: settings.clear_color, + }], + depth_stencil: Some(graph::RenderPassDepthTarget { + target: depth.rendering_target(), + depth_clear: Some(0.0), + stencil_clear: None, + }), + }; let pre_skinning_buffers = graph.add_data::(); @@ -272,25 +280,30 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { shadow_uniform_bg, forward_uniform_bg, + shadow, - color, - resolve, depth, + primary_renderpass, + pre_skinning_buffers, } } /// Create all the uniforms all the shaders in this graph need. pub fn create_frame_uniforms(&mut self, base: &'node BaseRenderGraph) { - crate::uniforms::add_to_graph( + uniforms::add_to_graph( self.graph, - self.shadow_uniform_bg, - self.forward_uniform_bg, self.shadow, - &base.interfaces, - &base.samplers, - self.settings.ambient, - self.inputs.resolution, + uniforms::UniformBindingHandles { + interfaces: &base.interfaces, + shadow_uniform_bg: self.shadow_uniform_bg, + forward_uniform_bg: self.forward_uniform_bg, + }, + uniforms::UniformInformation { + samplers: &base.samplers, + ambient: self.settings.ambient_color, + resolution: self.inputs.resolution, + }, ); } @@ -298,7 +311,7 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { for (shadow_index, shadow) in self.inputs.eval_output.shadows.iter().enumerate() { base.gpu_culler.add_object_uniform_upload_to_graph::( self.graph, - CameraIndex::Shadow(shadow_index as u32), + CameraSpecifier::Shadow(shadow_index as u32), UVec2::splat(shadow.map.size), SampleCount::One, &format_sso!("Shadow Culling S{}", shadow_index), @@ -313,7 +326,7 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { self.graph, shadow_culled, self.shadow, - CameraIndex::Shadow(shadow_index as u32), + CameraSpecifier::Shadow(shadow_index as u32), &format_sso!("Shadow Culling S{}", shadow_index), ); } @@ -326,7 +339,7 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { pub fn object_uniform_upload(&mut self, base: &'node BaseRenderGraph) { base.gpu_culler.add_object_uniform_upload_to_graph::( self.graph, - CameraIndex::Viewport, + CameraSpecifier::Viewport, self.inputs.resolution, self.inputs.samples, "Uniform Bake", @@ -339,48 +352,41 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { self.graph, self.cull, self.depth.single_sample_mipped, - CameraIndex::Viewport, + CameraSpecifier::Viewport, "Primary Culling", ); } - /// Clear all the targets to their needed values - pub fn clear_shadow(&mut self) { - crate::clear::add_clear_to_graph(self.graph, None, None, self.shadow, Vec4::ZERO, 0.0); - } - - /// Clear all the targets to their needed values - pub fn clear(&mut self) { - crate::clear::add_clear_to_graph( - self.graph, - Some(self.color), - self.resolve, - self.depth.rendering_target(), - self.settings.clear_color, - 0.0, - ); - } - /// Render all shadows for the PBR materials. pub fn pbr_shadow_rendering(&mut self) { let iter = zip(&self.shadow_cull, &self.inputs.eval_output.shadows); for (shadow_index, (shadow_cull, desc)) in iter.enumerate() { + let target = self + .shadow + .set_viewport(ViewportRect::new(desc.map.offset, UVec2::splat(desc.map.size))); + let renderpass = graph::RenderPassTargets { + targets: vec![], + depth_stencil: Some(graph::RenderPassDepthTarget { + target, + depth_clear: Some(0.0), + stencil_clear: None, + }), + }; + let routines = [&self.inputs.pbr.opaque_depth, &self.inputs.pbr.cutout_depth]; for routine in routines { - routine.add_forward_to_graph(RoutineAddToGraphArgs { + routine.add_forward_to_graph(ForwardRoutineArgs { graph: self.graph, - whole_frame_uniform_bg: self.shadow_uniform_bg, - culling_output_handle: Some(*shadow_cull), - per_material: &self.inputs.pbr.per_material, - extra_bgs: None, label: &format!("pbr shadow renderering S{shadow_index}"), + camera: CameraSpecifier::Shadow(shadow_index as u32), + binding_data: forward::ForwardRoutineBindingData { + whole_frame_uniform_bg: self.shadow_uniform_bg, + per_material_bgl: &self.inputs.pbr.per_material, + extra_bgs: None, + }, + culling_source: forward::CullingSource::Residual(*shadow_cull), samples: SampleCount::One, - camera: CameraIndex::Shadow(shadow_index as u32), - color: None, - resolve: None, - depth: self - .shadow - .set_viewport(ViewportRect::new(desc.map.offset, UVec2::splat(desc.map.size))), + renderpass: renderpass.clone(), }); } } @@ -391,9 +397,7 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { if let Some(skybox) = self.inputs.skybox { skybox.add_to_graph( self.graph, - self.color, - self.resolve, - self.depth.rendering_target(), + self.primary_renderpass.clone(), self.forward_uniform_bg, self.inputs.samples, ); @@ -404,18 +408,18 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { pub fn pbr_render_opaque_predicted_triangles(&mut self) { let routines = [&self.inputs.pbr.opaque_routine, &self.inputs.pbr.cutout_routine]; for routine in routines { - routine.add_forward_to_graph(RoutineAddToGraphArgs { + routine.add_forward_to_graph(ForwardRoutineArgs { graph: self.graph, - whole_frame_uniform_bg: self.forward_uniform_bg, - culling_output_handle: None, - per_material: &self.inputs.pbr.per_material, - extra_bgs: None, label: "PBR Forward Pass 1", + camera: CameraSpecifier::Viewport, + binding_data: forward::ForwardRoutineBindingData { + whole_frame_uniform_bg: self.forward_uniform_bg, + per_material_bgl: &self.inputs.pbr.per_material, + extra_bgs: None, + }, + culling_source: forward::CullingSource::Predicted, samples: self.inputs.samples, - camera: CameraIndex::Viewport, - color: Some(self.color), - resolve: self.resolve, - depth: self.depth.rendering_target(), + renderpass: self.primary_renderpass.clone(), }); } } @@ -424,40 +428,37 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { pub fn pbr_render_opaque_residual_triangles(&mut self) { let routines = [&self.inputs.pbr.opaque_routine, &self.inputs.pbr.cutout_routine]; for routine in routines { - routine.add_forward_to_graph(RoutineAddToGraphArgs { + routine.add_forward_to_graph(ForwardRoutineArgs { graph: self.graph, - whole_frame_uniform_bg: self.forward_uniform_bg, - culling_output_handle: Some(self.cull), - per_material: &self.inputs.pbr.per_material, - extra_bgs: None, label: "PBR Forward Pass 2", + camera: CameraSpecifier::Viewport, + binding_data: forward::ForwardRoutineBindingData { + whole_frame_uniform_bg: self.forward_uniform_bg, + per_material_bgl: &self.inputs.pbr.per_material, + extra_bgs: None, + }, + culling_source: forward::CullingSource::Residual(self.cull), samples: self.inputs.samples, - camera: CameraIndex::Viewport, - color: Some(self.color), - resolve: self.resolve, - depth: self.depth.rendering_target(), + renderpass: self.primary_renderpass.clone(), }); } } /// Render the PBR materials. pub fn pbr_forward_rendering_transparent(&mut self) { - self.inputs - .pbr - .blend_routine - .add_forward_to_graph(RoutineAddToGraphArgs { - graph: self.graph, + self.inputs.pbr.blend_routine.add_forward_to_graph(ForwardRoutineArgs { + graph: self.graph, + label: "PBR Forward Transparent", + camera: CameraSpecifier::Viewport, + binding_data: forward::ForwardRoutineBindingData { whole_frame_uniform_bg: self.forward_uniform_bg, - culling_output_handle: Some(self.cull), - per_material: &self.inputs.pbr.per_material, + per_material_bgl: &self.inputs.pbr.per_material, extra_bgs: None, - label: "PBR Forward", - camera: CameraIndex::Viewport, - samples: self.inputs.samples, - color: Some(self.color), - resolve: self.resolve, - depth: self.depth.rendering_target(), - }); + }, + culling_source: forward::CullingSource::Residual(self.cull), + samples: self.inputs.samples, + renderpass: self.primary_renderpass.clone(), + }); } pub fn hi_z(&mut self) { @@ -471,7 +472,7 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { pub fn tonemapping(&mut self) { self.inputs.tonemapping.add_to_graph( self.graph, - self.resolve.unwrap_or(self.color), + self.primary_renderpass.resolved_color(0), self.inputs.target_texture, self.forward_uniform_bg, ); diff --git a/rend3-routine/src/clear.rs b/rend3-routine/src/clear.rs deleted file mode 100644 index 576be017..00000000 --- a/rend3-routine/src/clear.rs +++ /dev/null @@ -1,47 +0,0 @@ -use glam::Vec4; -use rend3::graph::{ - NodeResourceUsage, RenderGraph, RenderPassDepthTarget, RenderPassTarget, RenderPassTargets, RenderTargetHandle, -}; - -/// Uses the given targets to create a node which merely sets the clear color to what we want. -/// -/// While not strictly needed as the first pass using a target will get its clear color followed, -/// it makes it a lot easier to udnerstand where the clear is coming from. -pub fn add_clear_to_graph( - graph: &mut RenderGraph<'_>, - color: Option, - resolve: Option, - depth: RenderTargetHandle, - clear_color: Vec4, - depth_clear: f32, -) { - let mut builder = graph.add_node("Clear"); - - let hdr_color_handle = builder.add_optional_render_target(color, NodeResourceUsage::Output); - let hdr_resolve = builder.add_optional_render_target(resolve, NodeResourceUsage::Output); - let hdr_depth_handle = builder.add_render_target(depth, NodeResourceUsage::Output); - - let _rpass_handle = builder.add_renderpass(RenderPassTargets { - targets: if let Some(hdr_color_handle) = hdr_color_handle { - vec![RenderPassTarget { - color: hdr_color_handle, - clear: wgpu::Color { - r: clear_color.x as f64, - g: clear_color.y as f64, - b: clear_color.z as f64, - a: clear_color.w as f64, - }, - resolve: hdr_resolve, - }] - } else { - vec![] - }, - depth_stencil: Some(RenderPassDepthTarget { - target: hdr_depth_handle, - depth_clear: Some(depth_clear), - stencil_clear: None, - }), - }); - - builder.build(|_| ()) -} diff --git a/rend3-routine/src/common/camera.rs b/rend3-routine/src/common/camera.rs index 6f09f5cc..300a6876 100644 --- a/rend3-routine/src/common/camera.rs +++ b/rend3-routine/src/common/camera.rs @@ -1,12 +1,12 @@ -/// Index representing which camera we're referring to. +/// Specifier representing which camera we're referring to. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum CameraIndex { +pub enum CameraSpecifier { Viewport, Shadow(u32), } -impl CameraIndex { - /// Returns `true` if the camera index is [`Viewport`]. +impl CameraSpecifier { + /// Returns `true` if the camera specifier is [`Viewport`]. /// /// [`Viewport`]: CameraIndex::Viewport #[must_use] @@ -14,7 +14,7 @@ impl CameraIndex { matches!(self, Self::Viewport) } - /// Returns `true` if the camera index is [`Shadow`]. + /// Returns `true` if the camera specifier is [`Shadow`]. /// /// [`Shadow`]: CameraIndex::Shadow #[must_use] diff --git a/rend3-routine/src/common/interfaces.rs b/rend3-routine/src/common/interfaces.rs index e0f7b3b6..015f66d4 100644 --- a/rend3-routine/src/common/interfaces.rs +++ b/rend3-routine/src/common/interfaces.rs @@ -92,6 +92,7 @@ pub struct PerMaterialArchetypeInterface { impl PerMaterialArchetypeInterface { pub fn new(device: &Device) -> Self { let bgl = BindGroupLayoutBuilder::new() + // Object data buffer .append( ShaderStages::VERTEX_FRAGMENT, BindingType::Buffer { @@ -101,6 +102,7 @@ impl PerMaterialArchetypeInterface { }, None, ) + // Batch data buffer .append( ShaderStages::VERTEX_FRAGMENT, BindingType::Buffer { @@ -110,6 +112,7 @@ impl PerMaterialArchetypeInterface { }, None, ) + // Vertex buffer .append( ShaderStages::VERTEX_FRAGMENT, BindingType::Buffer { @@ -119,6 +122,7 @@ impl PerMaterialArchetypeInterface { }, None, ) + // Per-Camera uniforms .append( ShaderStages::VERTEX_FRAGMENT, BindingType::Buffer { @@ -128,6 +132,7 @@ impl PerMaterialArchetypeInterface { }, None, ) + // Mateiral data .append( ShaderStages::VERTEX_FRAGMENT, BindingType::Buffer { diff --git a/rend3-routine/src/culling/batching.rs b/rend3-routine/src/culling/batching.rs index cff60c9d..e5a02187 100644 --- a/rend3-routine/src/culling/batching.rs +++ b/rend3-routine/src/culling/batching.rs @@ -4,12 +4,12 @@ use encase::ShaderType; use ordered_float::OrderedFloat; use rend3::{ graph::NodeExecutionContext, - managers::{CameraManager, TextureBindGroupIndex}, + managers::{CameraState, TextureBindGroupIndex}, types::{GraphDataHandle, Material, RawObjectHandle, SortingOrder, SortingReason}, util::{math::round_up, typedefs::FastHashMap}, }; -use crate::common::CameraIndex; +use crate::common::CameraSpecifier; use super::{BATCH_SIZE, WORKGROUP_SIZE}; @@ -101,7 +101,7 @@ pub(super) struct ShaderObjectCullingInformation { /// Map containing the previous invocation of each object. pub struct PerCameraPreviousInvocationsMap { - inner: FastHashMap>, + inner: FastHashMap>, } impl PerCameraPreviousInvocationsMap { pub fn new() -> Self { @@ -110,11 +110,11 @@ impl PerCameraPreviousInvocationsMap { } } - pub fn get_and_reset_camera(&mut self, camera: CameraIndex) -> FastHashMap { + pub fn get_and_reset_camera(&mut self, camera: CameraSpecifier) -> FastHashMap { self.inner.remove(&camera).unwrap_or_default() } - pub fn set_camera(&mut self, camera: CameraIndex, previous_invocations: FastHashMap) { + pub fn set_camera(&mut self, camera: CameraSpecifier, previous_invocations: FastHashMap) { self.inner.insert(camera, previous_invocations); } } @@ -122,13 +122,13 @@ impl PerCameraPreviousInvocationsMap { pub(super) fn batch_objects( ctx: &mut NodeExecutionContext, previous_invocation_map_handle: &GraphDataHandle, - camera: &CameraManager, - camera_idx: CameraIndex, + camera: &CameraState, + camera_specifier: CameraSpecifier, ) -> ShaderBatchDatas { profiling::scope!("Batch Objects"); let mut per_camera_previous_invocation_map = ctx.data_core.graph_storage.get_mut(previous_invocation_map_handle); - let previous_invocation_map = per_camera_previous_invocation_map.get_and_reset_camera(camera_idx); + let previous_invocation_map = per_camera_previous_invocation_map.get_and_reset_camera(camera_specifier); let mut current_invocation_map = FastHashMap::default(); let mut jobs = ShaderBatchDatas { @@ -163,7 +163,7 @@ pub(super) fn batch_objects( let mut distance_sq = ctx .data_core - .camera_manager + .viewport_camera_state .location() .distance_squared(object.location.into()); if sorting.order == SortingOrder::BackToFront { @@ -273,7 +273,7 @@ pub(super) fn batch_objects( }); } - per_camera_previous_invocation_map.set_camera(camera_idx, current_invocation_map); + per_camera_previous_invocation_map.set_camera(camera_specifier, current_invocation_map); jobs } diff --git a/rend3-routine/src/culling/culler.rs b/rend3-routine/src/culling/culler.rs index bf4dcd7c..99a8928e 100644 --- a/rend3-routine/src/culling/culler.rs +++ b/rend3-routine/src/culling/culler.rs @@ -12,7 +12,7 @@ use glam::{Mat4, UVec2, Vec2}; use rend3::{ format_sso, graph::{DataHandle, DeclaredDependency, NodeExecutionContext, NodeResourceUsage, RenderGraph, RenderTargetHandle}, - managers::{CameraManager, ShaderObject, TextureBindGroupIndex}, + managers::{CameraState, ShaderObject, TextureBindGroupIndex}, types::{GraphDataHandle, Material, MaterialArray, SampleCount, VERTEX_ATTRIBUTE_POSITION}, util::{frustum::Frustum, math::IntegerExt, typedefs::FastHashMap}, Renderer, ShaderPreProcessor, ShaderVertexBufferConfig, @@ -26,7 +26,7 @@ use wgpu::{ }; use crate::{ - common::CameraIndex, + common::CameraSpecifier, culling::{ batching::{batch_objects, JobSubRegion, PerCameraPreviousInvocationsMap, ShaderBatchData, ShaderBatchDatas}, suballoc::InputOutputBuffer, @@ -51,10 +51,10 @@ pub struct DrawCall { #[derive(Default)] pub struct CullingBufferMap { - inner: FastHashMap, + inner: FastHashMap, } impl CullingBufferMap { - pub fn get_buffers(&self, camera: CameraIndex) -> Option<&CullingBuffers> { + pub fn get_buffers(&self, camera: CameraSpecifier) -> Option<&CullingBuffers> { self.inner.get(&camera) } @@ -63,7 +63,7 @@ impl CullingBufferMap { queue: &Queue, device: &Device, encoder: &mut CommandEncoder, - camera: CameraIndex, + camera: CameraSpecifier, sizes: CullingBufferSizes, ) -> &mut CullingBuffers { match self.inner.entry(camera) { @@ -190,7 +190,7 @@ pub struct GpuCuller { sampler: Sampler, winding: wgpu::FrontFace, type_id: TypeId, - per_material_buffer_handle: GraphDataHandle>>, + per_material_buffer_handle: GraphDataHandle>>, pub culling_buffer_map_handle: GraphDataHandle, previous_invocation_map_handle: GraphDataHandle, } @@ -427,8 +427,8 @@ impl GpuCuller { pub fn object_uniform_upload( &self, ctx: &mut NodeExecutionContext, - camera: &CameraManager, - camera_idx: CameraIndex, + camera: &CameraState, + camera_specifier: CameraSpecifier, resolution: UVec2, samples: SampleCount, ) where @@ -468,7 +468,7 @@ impl GpuCuller { mapped_at_creation: false, })) }; - let buffer = match per_mat_buffer_map.entry(camera_idx) { + let buffer = match per_mat_buffer_map.entry(camera_specifier) { Entry::Occupied(o) => { let r = o.into_mut(); if r.size() != per_map_buffer_size { @@ -479,9 +479,9 @@ impl GpuCuller { Entry::Vacant(o) => o.insert(new_per_mat_buffer()), }; - let culling = match camera_idx { - CameraIndex::Shadow(_) => wgpu::Face::Front, - CameraIndex::Viewport => wgpu::Face::Back, + let culling = match camera_specifier { + CameraSpecifier::Shadow(_) => wgpu::Face::Front, + CameraSpecifier::Viewport => wgpu::Face::Back, }; { @@ -490,7 +490,7 @@ impl GpuCuller { let per_camera_data = PerCameraUniform { view: camera.view(), view_proj: camera.view_proj(), - shadow_index: camera_idx.to_shader_index(), + shadow_index: camera_specifier.to_shader_index(), frustum: camera.world_frustum(), resolution: resolution.as_vec2(), flags: { @@ -548,7 +548,7 @@ impl GpuCuller { ctx: &mut NodeExecutionContext, jobs: ShaderBatchDatas, depth_handle: DeclaredDependency, - camera_idx: CameraIndex, + camera_specifier: CameraSpecifier, ) -> DrawCallSet where M: Material, @@ -575,7 +575,7 @@ impl GpuCuller { &ctx.renderer.queue, &ctx.renderer.device, encoder, - camera_idx, + camera_specifier, CullingBufferSizes { invocations: total_invocations as u64, draw_calls: jobs.regions.len() as u64, @@ -586,8 +586,8 @@ impl GpuCuller { ctx.data_core .graph_storage .get_mut(&self.per_material_buffer_handle) - .get(&camera_idx) - .unwrap_or_else(|| panic!("No per camera uniform for camera {:?}", camera_idx)), + .get(&camera_specifier) + .unwrap_or_else(|| panic!("No per camera uniform for camera {:?}", camera_specifier)), ); let culling_data_buffer = { @@ -712,7 +712,7 @@ impl GpuCuller { pub fn add_object_uniform_upload_to_graph<'node, M: Material>( &'node self, graph: &mut RenderGraph<'node>, - camera_idx: CameraIndex, + camera_specifier: CameraSpecifier, resolution: UVec2, samples: SampleCount, name: &str, @@ -721,12 +721,12 @@ impl GpuCuller { node.add_side_effect(); node.build(move |mut ctx| { - let camera = match camera_idx { - CameraIndex::Shadow(i) => &ctx.eval_output.shadows[i as usize].camera, - CameraIndex::Viewport => &ctx.data_core.camera_manager, + let camera = match camera_specifier { + CameraSpecifier::Shadow(i) => &ctx.eval_output.shadows[i as usize].camera, + CameraSpecifier::Viewport => &ctx.data_core.viewport_camera_state, }; - self.object_uniform_upload::(&mut ctx, camera, camera_idx, resolution, samples); + self.object_uniform_upload::(&mut ctx, camera, camera_specifier, resolution, samples); }); } @@ -735,7 +735,7 @@ impl GpuCuller { graph: &mut RenderGraph<'node>, draw_calls_hdl: DataHandle>, depth_handle: RenderTargetHandle, - camera_idx: CameraIndex, + camera_specifier: CameraSpecifier, name: &str, ) { let mut node = graph.add_node(name); @@ -743,18 +743,18 @@ impl GpuCuller { let depth_handle = node.add_render_target(depth_handle, NodeResourceUsage::Input); node.build(move |mut ctx| { - let camera = match camera_idx { - CameraIndex::Shadow(i) => &ctx.eval_output.shadows[i as usize].camera, - CameraIndex::Viewport => &ctx.data_core.camera_manager, + let camera = match camera_specifier { + CameraSpecifier::Shadow(i) => &ctx.eval_output.shadows[i as usize].camera, + CameraSpecifier::Viewport => &ctx.data_core.viewport_camera_state, }; - let jobs = batch_objects::(&mut ctx, &self.previous_invocation_map_handle, camera, camera_idx); + let jobs = batch_objects::(&mut ctx, &self.previous_invocation_map_handle, camera, camera_specifier); if jobs.jobs.is_empty() { return; } - let draw_calls = self.cull::(&mut ctx, jobs, depth_handle, camera_idx); + let draw_calls = self.cull::(&mut ctx, jobs, depth_handle, camera_specifier); ctx.graph_data.set_data(output, Some(Arc::new(draw_calls))); }); diff --git a/rend3-routine/src/forward.rs b/rend3-routine/src/forward.rs index c33fa69c..7d966be3 100644 --- a/rend3-routine/src/forward.rs +++ b/rend3-routine/src/forward.rs @@ -7,24 +7,21 @@ use std::{marker::PhantomData, sync::Arc}; use arrayvec::ArrayVec; use encase::ShaderSize; use rend3::{ - graph::{ - DataHandle, NodeResourceUsage, RenderGraph, RenderPassDepthTarget, RenderPassTarget, RenderPassTargets, - RenderTargetHandle, - }, + graph::{self, DataHandle, NodeResourceUsage, RenderGraph, RenderPassTargets}, types::{GraphDataHandle, Material, SampleCount}, util::{bind_merge::BindGroupBuilder, typedefs::FastHashMap}, ProfileData, Renderer, RendererDataCore, RendererProfile, ShaderPreProcessor, }; use serde::Serialize; use wgpu::{ - BindGroup, BindGroupLayout, Color, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, - DepthStencilState, FragmentState, IndexFormat, MultisampleState, PipelineLayoutDescriptor, PolygonMode, - PrimitiveState, PrimitiveTopology, RenderPipeline, RenderPipelineDescriptor, ShaderModule, StencilState, - TextureFormat, VertexState, + BindGroup, BindGroupLayout, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState, + FragmentState, IndexFormat, MultisampleState, PipelineLayoutDescriptor, PolygonMode, PrimitiveState, + PrimitiveTopology, RenderPipeline, RenderPipelineDescriptor, ShaderModule, StencilState, TextureFormat, + VertexState, }; use crate::{ - common::{CameraIndex, PerMaterialArchetypeInterface, WholeFrameInterfaces}, + common::{CameraSpecifier, PerMaterialArchetypeInterface, WholeFrameInterfaces}, culling::{self, CullingBufferMap, DrawCall, DrawCallSet, InputOutputPartition}, }; @@ -47,7 +44,45 @@ pub struct ShaderModulePair<'a> { pub fs_module: &'a ShaderModule, } -pub struct RoutineArgs<'a, M> { +enum DeclaredCullingOutput { + Predicted, + Residual(graph::DeclaredDependency>>), +} + +impl DeclaredCullingOutput { + /// Returns `true` if the declared culling output is [`Residual`]. + /// + /// [`Residual`]: DeclaredCullingOutput::Residual + #[must_use] + fn is_residual(&self) -> bool { + matches!(self, Self::Residual(..)) + } +} + +pub enum CullingSource { + /// We are rendering the first pass with the predicted triangles from last frame. + /// + /// This is used on the first pass. + Predicted, + /// We are rendering the second pass with the residual triangles from this frame. + /// + /// This is used when we are rendering the residual triangles from this frame, as part of the second pass. + Residual(DataHandle>), +} + +impl CullingSource { + fn add_inner_data(&self, builder: &mut graph::RenderGraphNodeBuilder<'_, '_>) -> DeclaredCullingOutput { + match self { + CullingSource::Predicted => DeclaredCullingOutput::Predicted, + CullingSource::Residual(handle) => { + let handle = builder.add_data(*handle, NodeResourceUsage::Input); + DeclaredCullingOutput::Residual(handle) + } + } + } +} + +pub struct ForwardRoutineCreateArgs<'a, M> { pub name: &'a str, pub renderer: &'a Arc, @@ -68,31 +103,42 @@ pub struct RoutineArgs<'a, M> { pub descriptor_callback: Option<&'a dyn Fn(&mut RenderPipelineDescriptor<'_>, &mut [Option])>, } -pub struct RoutineAddToGraphArgs<'a, 'node, M> { - pub graph: &'a mut RenderGraph<'node>, +pub struct ForwardRoutineBindingData<'node, M> { + /// Bind group holding references to all the uniforms needed by the entire frame. + /// This is will be either the shadow pass uniforms, or the forward pass uniforms. + /// + /// This includes bindings provided by all the managers. pub whole_frame_uniform_bg: DataHandle, - // If this is None, we are rendering the first pass with the predicted triangles from last frame. - // - // If this is Some, we are rendering the second pass with the residual triangles from this frame. - pub culling_output_handle: Option>>, - pub per_material: &'node PerMaterialArchetypeInterface, + /// Bind group layout for all the per-material uniforms for this material. + /// + /// The bind group is constructed in the rendergraph nodes. + pub per_material_bgl: &'node PerMaterialArchetypeInterface, + /// Extra bind groups to be added to the pipeline. pub extra_bgs: Option<&'node [BindGroup]>, +} + +pub struct ForwardRoutineArgs<'a, 'node, M> { + pub graph: &'a mut RenderGraph<'node>, + pub label: &'a str, + + pub camera: CameraSpecifier, + pub binding_data: ForwardRoutineBindingData<'node, M>, + + /// Source of culling information, determines which triangles are rendered this pass. + pub culling_source: CullingSource, pub samples: SampleCount, - pub color: Option, - pub resolve: Option, - pub depth: RenderTargetHandle, - pub camera: CameraIndex, + pub renderpass: RenderPassTargets, } /// A set of pipelines for rendering a specific combination of a material. pub struct ForwardRoutine { - pub pipeline_s1: RenderPipeline, - pub pipeline_s4: RenderPipeline, - pub material_key: u64, - pub culling_buffer_map_handle: GraphDataHandle, - pub draw_call_set_cache_handle: GraphDataHandle>>, - pub _phantom: PhantomData, + pipeline_s1: RenderPipeline, + pipeline_s4: RenderPipeline, + material_key: u64, + culling_buffer_map_handle: GraphDataHandle, + draw_call_set_cache_handle: GraphDataHandle>>, + _phantom: PhantomData, } impl ForwardRoutine { /// Create a new forward routine with optional customizations. @@ -110,7 +156,7 @@ impl ForwardRoutine { /// If use_prepass is true, depth tests/writes are set such that it is /// assumed a full depth-prepass has happened before. #[allow(clippy::too_many_arguments)] - pub fn new(args: RoutineArgs<'_, M>) -> Self { + pub fn new(args: ForwardRoutineCreateArgs<'_, M>) -> Self { profiling::scope!("PrimaryPasses::new"); let mut bgls: ArrayVec<&BindGroupLayout, 8> = ArrayVec::new(); @@ -143,33 +189,16 @@ impl ForwardRoutine { } /// Add the given routine to the graph with the given settings. - pub fn add_forward_to_graph<'node>(&'node self, args: RoutineAddToGraphArgs<'_, 'node, M>) { + pub fn add_forward_to_graph<'node>(&'node self, args: ForwardRoutineArgs<'_, 'node, M>) { let mut builder = args.graph.add_node(args.label); - let color_handle = builder.add_optional_render_target(args.color, NodeResourceUsage::InputOutput); - let resolve_handle = builder.add_optional_render_target(args.resolve, NodeResourceUsage::InputOutput); - let depth_handle = builder.add_render_target(args.depth, NodeResourceUsage::InputOutput); - builder.add_side_effect(); - let rpass_handle = builder.add_renderpass(RenderPassTargets { - targets: match color_handle { - Some(color) => vec![RenderPassTarget { - color, - clear: Color::BLACK, - resolve: resolve_handle, - }], - None => vec![], - }, - depth_stencil: Some(RenderPassDepthTarget { - target: depth_handle, - depth_clear: Some(0.0), - stencil_clear: None, - }), - }); + let rpass_handle = builder.add_renderpass(args.renderpass.clone()); - let whole_frame_uniform_handle = builder.add_data(args.whole_frame_uniform_bg, NodeResourceUsage::Input); - let culling_output_handle = builder.add_optional_data(args.culling_output_handle, NodeResourceUsage::Input); + let whole_frame_uniform_handle = + builder.add_data(args.binding_data.whole_frame_uniform_bg, NodeResourceUsage::Input); + let culling_output_handle = args.culling_source.add_inner_data(&mut builder); builder.build(move |mut ctx| { let rpass = ctx.encoder_or_pass.take_rpass(rpass_handle); @@ -179,9 +208,8 @@ impl ForwardRoutine { let mut draw_call_set_cache = ctx.data_core.graph_storage.get_mut(&self.draw_call_set_cache_handle); let draw_call_set = match culling_output_handle { - // If we are provided a culling output handle, we are rendering the second pass - // with the residual triangles from this frame. - Some(handle) => { + // We are rendering the second pass with the residual triangles from this frame. + DeclaredCullingOutput::Residual(handle) => { // If there is no draw call set for this camera in the cache, there isn't actually anything to render. let Some(draw_call_set) = ctx.graph_data.get_data(ctx.temps, handle) else { return; @@ -192,11 +220,10 @@ impl ForwardRoutine { draw_call_set } - // If we are not provided a culling output handle, this mean we are rendering the first pass - // with the predicted triangles from last frame. - None => { + // We are rendering the first pass with the predicted triangles from last frame. + DeclaredCullingOutput::Predicted => { // If there is no draw call set for this camera in the cache, that means we have yet to actually render anything, - // so either no objects yet exist, or we are in the first frame. + // so either no objects yet exist, or we are in the first frame, so we can bail out. let Some(draw_call_set) = draw_call_set_cache.get(&args.camera) else { return; }; @@ -204,7 +231,7 @@ impl ForwardRoutine { draw_call_set } }; - let residual = culling_output_handle.is_some() && args.camera.is_viewport(); + let residual = culling_output_handle.is_residual() && args.camera.is_viewport(); let culling_buffer_storage = ctx.data_core.graph_storage.get(&self.culling_buffer_map_handle); @@ -237,7 +264,11 @@ impl ForwardRoutine { .append_buffer(&ctx.eval_output.mesh_buffer) .append_buffer(&draw_call_set.per_camera_uniform) .append_buffer(ctx.data_core.material_manager.archetype_view::().buffer()) - .build(&ctx.renderer.device, Some("Per-Material BG"), &args.per_material.bgl), + .build( + &ctx.renderer.device, + Some("Per-Material BG"), + &args.binding_data.per_material_bgl.bgl, + ), ); let pipeline = match args.samples { @@ -250,7 +281,7 @@ impl ForwardRoutine { ); rpass.set_pipeline(pipeline); rpass.set_bind_group(0, whole_frame_uniform_bg, &[]); - if let Some(v) = args.extra_bgs { + if let Some(v) = args.binding_data.extra_bgs { for (idx, bg) in v.iter().enumerate() { rpass.set_bind_group((idx + 3) as _, bg, &[]) } @@ -294,7 +325,7 @@ impl ForwardRoutine { fn build_forward_pipeline_inner( pll: &wgpu::PipelineLayout, - args: &RoutineArgs<'_, M>, + args: &ForwardRoutineCreateArgs<'_, M>, samples: SampleCount, ) -> RenderPipeline { let mut render_targets: ArrayVec<_, 1> = ArrayVec::new(); diff --git a/rend3-routine/src/hi_z.rs b/rend3-routine/src/hi_z.rs index 39f6d0b2..f345d807 100644 --- a/rend3-routine/src/hi_z.rs +++ b/rend3-routine/src/hi_z.rs @@ -211,17 +211,12 @@ impl HiZRoutine { if let Some(multi_sample) = depth_targets.multi_sample { let mut node = graph.add_node("HiZ Resolve"); - let target = node.add_render_target( - depth_targets.single_sample_mipped.set_mips(0..1), - NodeResourceUsage::Output, - ); - let source = node.add_render_target(multi_sample, NodeResourceUsage::Output); let rpass_handle = node.add_renderpass(RenderPassTargets { targets: vec![], depth_stencil: Some(RenderPassDepthTarget { - target, + target: depth_targets.single_sample_mipped.set_mips(0..1), depth_clear: Some(0.0), stencil_clear: None, }), @@ -242,13 +237,10 @@ impl HiZRoutine { let dst_extent = extent.mip_level_size(dst_mip as u32, TextureDimension::D2); let src_extent = extent.mip_level_size(src_mip as u32, TextureDimension::D2); - let dst_target = node.add_render_target( - depth_targets - .single_sample_mipped - .set_mips(dst_mip..dst_mip + 1) - .set_viewport(ViewportRect::from_size(UVec2::new(dst_extent.width, dst_extent.height))), - NodeResourceUsage::Output, - ); + let dst_target = depth_targets + .single_sample_mipped + .set_mips(dst_mip..dst_mip + 1) + .set_viewport(ViewportRect::from_size(UVec2::new(dst_extent.width, dst_extent.height))); let src_target = node.add_render_target( depth_targets .single_sample_mipped diff --git a/rend3-routine/src/lib.rs b/rend3-routine/src/lib.rs index 9f13361b..99666a2f 100644 --- a/rend3-routine/src/lib.rs +++ b/rend3-routine/src/lib.rs @@ -19,7 +19,6 @@ //! too much user side boilerplate. pub mod base; -pub mod clear; pub mod common; pub mod culling; pub mod forward; diff --git a/rend3-routine/src/pbr/routine.rs b/rend3-routine/src/pbr/routine.rs index f54e7914..31ec5328 100644 --- a/rend3-routine/src/pbr/routine.rs +++ b/rend3-routine/src/pbr/routine.rs @@ -9,7 +9,7 @@ use wgpu::{BlendState, ShaderModuleDescriptor, ShaderSource}; use crate::{ common::{PerMaterialArchetypeInterface, WholeFrameInterfaces}, culling::CullingBufferMap, - forward::{ForwardRoutine, RoutineArgs, RoutineType, ShaderModulePair}, + forward::{ForwardRoutine, ForwardRoutineCreateArgs, RoutineType, ShaderModulePair}, hi_z::HiZRoutine, pbr::{PbrMaterial, TransparencyType}, }; @@ -109,7 +109,7 @@ impl PbrRoutine { }); let mut inner = |routine_type, module, transparency| { - ForwardRoutine::new(RoutineArgs { + ForwardRoutine::new(ForwardRoutineCreateArgs { name: &format!("pbr {routine_type:?} {transparency:?}"), renderer, data_core, diff --git a/rend3-routine/src/skybox.rs b/rend3-routine/src/skybox.rs index e32bfcdb..f5a792ea 100644 --- a/rend3-routine/src/skybox.rs +++ b/rend3-routine/src/skybox.rs @@ -3,16 +3,13 @@ use std::borrow::Cow; use rend3::{ - graph::{ - DataHandle, NodeResourceUsage, RenderGraph, RenderPassDepthTarget, RenderPassTarget, RenderPassTargets, - RenderTargetHandle, - }, + graph::{DataHandle, NodeResourceUsage, RenderGraph, RenderPassTargets}, types::{SampleCount, TextureCubeHandle}, util::bind_merge::{BindGroupBuilder, BindGroupLayoutBuilder}, Renderer, ShaderConfig, ShaderPreProcessor, }; use wgpu::{ - BindGroup, BindGroupLayout, BindingType, Color, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, + BindGroup, BindGroupLayout, BindingType, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState, Face, FragmentState, FrontFace, MultisampleState, PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, RenderPipeline, RenderPipelineDescriptor, ShaderModuleDescriptor, ShaderSource, ShaderStages, StencilState, TextureFormat, TextureSampleType, TextureViewDimension, VertexState, @@ -87,30 +84,13 @@ impl SkyboxRoutine { pub fn add_to_graph<'node>( &'node self, graph: &mut RenderGraph<'node>, - color: RenderTargetHandle, - resolve: Option, - depth: RenderTargetHandle, + renderpass: RenderPassTargets, forward_uniform_bg: DataHandle, samples: SampleCount, ) { let mut builder = graph.add_node("Skybox"); - let hdr_color_handle = builder.add_render_target(color, NodeResourceUsage::InputOutput); - let hdr_resolve = builder.add_optional_render_target(resolve, NodeResourceUsage::InputOutput); - let hdr_depth_handle = builder.add_render_target(depth, NodeResourceUsage::Input); - - let rpass_handle = builder.add_renderpass(RenderPassTargets { - targets: vec![RenderPassTarget { - color: hdr_color_handle, - clear: Color::BLACK, - resolve: hdr_resolve, - }], - depth_stencil: Some(RenderPassDepthTarget { - target: hdr_depth_handle, - depth_clear: Some(0.0), - stencil_clear: None, - }), - }); + let rpass_handle = builder.add_renderpass(renderpass); let forward_uniform_handle = builder.add_data(forward_uniform_bg, NodeResourceUsage::Input); diff --git a/rend3-routine/src/tonemapping.rs b/rend3-routine/src/tonemapping.rs index 4750ccbc..2198eb4f 100644 --- a/rend3-routine/src/tonemapping.rs +++ b/rend3-routine/src/tonemapping.rs @@ -11,13 +11,14 @@ use std::borrow::Cow; +use glam::Vec4; use rend3::{ graph::{DataHandle, NodeResourceUsage, RenderGraph, RenderPassTarget, RenderPassTargets, RenderTargetHandle}, util::bind_merge::{BindGroupBuilder, BindGroupLayoutBuilder}, Renderer, ShaderConfig, ShaderPreProcessor, }; use wgpu::{ - BindGroup, BindGroupLayout, BindingType, Color, ColorTargetState, ColorWrites, Device, FragmentState, FrontFace, + BindGroup, BindGroupLayout, BindingType, ColorTargetState, ColorWrites, Device, FragmentState, FrontFace, MultisampleState, PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, RenderPipeline, RenderPipelineDescriptor, ShaderModuleDescriptor, ShaderSource, ShaderStages, TextureFormat, TextureSampleType, TextureViewDimension, VertexState, @@ -127,12 +128,11 @@ impl TonemappingRoutine { let mut builder = graph.add_node("Tonemapping"); let input_handle = builder.add_render_target(src, NodeResourceUsage::Input); - let output_handle = builder.add_render_target(dst, NodeResourceUsage::Output); let rpass_handle = builder.add_renderpass(RenderPassTargets { targets: vec![RenderPassTarget { - color: output_handle, - clear: Color::BLACK, + color: dst, + clear: Vec4::ZERO, resolve: None, }], depth_stencil: None, diff --git a/rend3-routine/src/uniforms.rs b/rend3-routine/src/uniforms.rs index 735c7020..9249c247 100644 --- a/rend3-routine/src/uniforms.rs +++ b/rend3-routine/src/uniforms.rs @@ -1,24 +1,19 @@ //! Helpers for building the per-camera uniform data used for cameras and //! shadows. -use std::iter::once; - +use encase::{ShaderSize, ShaderType, UniformBuffer}; use glam::{Mat4, UVec2, Vec4}; use rend3::{ graph::{DataHandle, NodeResourceUsage, RenderGraph, RenderTargetHandle}, - managers::CameraManager, + managers::CameraState, util::{bind_merge::BindGroupBuilder, frustum::Frustum}, }; -use wgpu::{ - util::{BufferInitDescriptor, DeviceExt}, - BindGroup, BufferUsages, -}; +use wgpu::{BindGroup, BufferUsages}; use crate::common::{Samplers, WholeFrameInterfaces}; -/// The actual structure passed to the shader. -#[derive(Debug, Copy, Clone)] -#[repr(C, align(16))] +/// Set of uniforms that are useful for the whole frame. +#[derive(Debug, Copy, Clone, ShaderType)] pub struct FrameUniforms { pub view: Mat4, pub view_proj: Mat4, @@ -32,7 +27,7 @@ pub struct FrameUniforms { } impl FrameUniforms { /// Use the given camera to generate these uniforms. - pub fn new(camera: &CameraManager, ambient: Vec4, resolution: UVec2) -> Self { + pub fn new(camera: &CameraState, info: &UniformInformation<'_>) -> Self { profiling::scope!("create uniforms"); let view = camera.view(); @@ -47,48 +42,66 @@ impl FrameUniforms { inv_view_proj: view_proj.inverse(), inv_origin_view_proj: origin_view_proj.inverse(), frustum: Frustum::from_matrix(camera.proj()), - ambient, - resolution, + ambient: info.ambient, + resolution: info.resolution, } } } -unsafe impl bytemuck::Zeroable for FrameUniforms {} -unsafe impl bytemuck::Pod for FrameUniforms {} +/// Various information sources for the uniform data. +pub struct UniformInformation<'node> { + /// Struct containing the default set of samplers. + pub samplers: &'node Samplers, + /// Ambient light color. + pub ambient: Vec4, + /// Resolution of the viewport. + pub resolution: UVec2, +} + +pub struct UniformBindingHandles<'node> { + /// Interfaces containing the bind group layouts for the uniform bind groups. + pub interfaces: &'node WholeFrameInterfaces, + /// The output bind group handle for the shadow uniform data. This does not + /// include the shadow map texture, preventing a cycle. + pub shadow_uniform_bg: DataHandle, + /// The output bind group handle for the forward uniform data. This does + /// include the shadow map texture. + pub forward_uniform_bg: DataHandle, +} /// Add the creation of these uniforms to the graph. -#[allow(clippy::too_many_arguments)] pub fn add_to_graph<'node>( graph: &mut RenderGraph<'node>, - shadow_uniform_bg: DataHandle, - forward_uniform_bg: DataHandle, shadow_target: RenderTargetHandle, - interfaces: &'node WholeFrameInterfaces, - samplers: &'node Samplers, - ambient: Vec4, - resolution: UVec2, + binding_handles: UniformBindingHandles<'node>, + info: UniformInformation<'node>, ) { let mut builder = graph.add_node("build uniform data"); - let shadow_handle = builder.add_data(shadow_uniform_bg, NodeResourceUsage::Output); - let forward_handle = builder.add_data(forward_uniform_bg, NodeResourceUsage::Output); + let shadow_handle = builder.add_data(binding_handles.shadow_uniform_bg, NodeResourceUsage::Output); + let forward_handle = builder.add_data(binding_handles.forward_uniform_bg, NodeResourceUsage::Output); // Get the shadow target and declare it a dependency of the forward_uniform_bg let shadow_target_handle = builder.add_render_target(shadow_target, NodeResourceUsage::Reference); - builder.add_dependencies_to_render_targets(forward_uniform_bg, once(shadow_target)); + builder.add_dependencies_to_render_targets(binding_handles.forward_uniform_bg, [shadow_target]); builder.build(move |ctx| { let shadow_target = ctx.graph_data.get_render_target(shadow_target_handle); let mut bgb = BindGroupBuilder::new(); - samplers.add_to_bg(&mut bgb); + info.samplers.add_to_bg(&mut bgb); - let uniforms = FrameUniforms::new(&ctx.data_core.camera_manager, ambient, resolution); - let uniform_buffer = ctx.renderer.device.create_buffer_init(&BufferInitDescriptor { - label: Some("frame uniform"), - contents: bytemuck::bytes_of(&uniforms), + let uniforms = FrameUniforms::new(&ctx.data_core.viewport_camera_state, &info); + let uniform_buffer = ctx.renderer.device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Frame Uniforms"), + size: FrameUniforms::SHADER_SIZE.get(), usage: BufferUsages::UNIFORM, + mapped_at_creation: true, }); + let mut mapping = uniform_buffer.slice(..).get_mapped_range_mut(); + UniformBuffer::new(&mut *mapping).write(&uniforms).unwrap(); + drop(mapping); + uniform_buffer.unmap(); bgb.append_buffer(&uniform_buffer); @@ -98,7 +111,7 @@ pub fn add_to_graph<'node>( let shadow_uniform_bg = bgb.build( &ctx.renderer.device, Some("shadow uniform bg"), - &interfaces.depth_uniform_bgl, + &binding_handles.interfaces.depth_uniform_bgl, ); bgb.append_texture_view(shadow_target); @@ -106,7 +119,7 @@ pub fn add_to_graph<'node>( let forward_uniform_bg = bgb.build( &ctx.renderer.device, Some("forward uniform bg"), - &interfaces.forward_uniform_bgl, + &binding_handles.interfaces.forward_uniform_bgl, ); ctx.graph_data.set_data(shadow_handle, Some(shadow_uniform_bg)); diff --git a/rend3-test/src/runner.rs b/rend3-test/src/runner.rs index b5ddd5f3..11edc61d 100644 --- a/rend3-test/src/runner.rs +++ b/rend3-test/src/runner.rs @@ -163,15 +163,19 @@ impl TestRunner { self.base_rendergraph.add_to_graph( &mut graph, - &eval_output, - &self.pbr, - None, - &self.tonemapping, - frame_handle, - UVec2::splat(settings.size), - settings.samples, - glam::Vec4::ZERO, - glam::Vec4::ZERO, + rend3_routine::base::BaseRenderGraphInputs { + eval_output: &eval_output, + pbr: &self.pbr, + skybox: None, + tonemapping: &self.tonemapping, + target_texture: frame_handle, + resolution: UVec2::splat(settings.size), + samples: settings.samples, + }, + rend3_routine::base::BaseRenderGraphSettings { + ambient_color: glam::Vec4::ZERO, + clear_color: glam::Vec4::ZERO, + }, ); graph.execute(&self.renderer, &mut eval_output); diff --git a/rend3/src/graph/graph.rs b/rend3/src/graph/graph.rs index 6159b83d..3ef755b1 100644 --- a/rend3/src/graph/graph.rs +++ b/rend3/src/graph/graph.rs @@ -457,8 +457,8 @@ impl<'node> RenderGraph<'node> { .targets .first() .map_or_else( - || rpass_desc.depth_stencil.as_ref().unwrap().target.handle.to_region(), - |t| t.color.handle.to_region(), + || rpass_desc.depth_stencil.as_ref().unwrap().target.to_region(), + |t| t.color.to_region(), ) .viewport; @@ -562,12 +562,18 @@ impl<'node> RenderGraph<'node> { .targets .iter() .map(|target| { - let view_span = resource_spans[&target.color.handle.resource.to_resource()]; + let view_span = resource_spans[&target.color.resource.to_resource()]; let first_usage = view_span.first_usage.expect("internal rendergraph error: renderpass attachment counts as a usage, but no first usage registered on texture"); let load = if first_usage == node_idx { - LoadOp::Clear(target.clear) + let clear_f64 = target.clear.as_dvec4(); + LoadOp::Clear(wgpu::Color { + r: clear_f64.x, + g: clear_f64.y, + b: clear_f64.z, + a: clear_f64.w, + }) } else { LoadOp::Load }; @@ -575,14 +581,14 @@ impl<'node> RenderGraph<'node> { let store = if view_span.last_reference == Some(pass_end_idx) { StoreOp::Discard } else { StoreOp::Store }; RenderPassColorAttachment { - view: match target.color.handle.resource { + view: match target.color.resource { GraphSubResource::ImportedTexture(region) => &active_imported_views[®ion], GraphSubResource::Texture(region) => &active_views[®ion], _ => { panic!("internal rendergraph error: using a non-texture as a renderpass attachment") } }, - resolve_target: target.resolve.as_ref().map(|dep| match dep.handle.resource { + resolve_target: target.resolve.as_ref().map(|dep| match dep.resource { GraphSubResource::ImportedTexture(region) => &active_imported_views[®ion], GraphSubResource::Texture(region) => &active_views[®ion], _ => { @@ -595,7 +601,7 @@ impl<'node> RenderGraph<'node> { .map(Option::Some) .collect(); let depth_stencil_attachment = desc.depth_stencil.as_ref().map(|ds_target| { - let resource = ds_target.target.handle.resource; + let resource = ds_target.target.resource; let view_span = resource_spans[&resource.to_resource()]; diff --git a/rend3/src/graph/mod.rs b/rend3/src/graph/mod.rs index cd85fa92..5cef2f4b 100644 --- a/rend3/src/graph/mod.rs +++ b/rend3/src/graph/mod.rs @@ -45,9 +45,9 @@ use std::ops::Range; -use glam::UVec2; +use glam::{UVec2, Vec4}; use rend3_types::{SampleCount, TextureFormat, TextureUsages}; -use wgpu::{Color, Extent3d, TextureDimension, TextureView}; +use wgpu::{Extent3d, TextureDimension, TextureView}; use crate::util::typedefs::SsoString; @@ -241,7 +241,7 @@ impl RenderTargetHandle { } /// Targets that make up a renderpass. -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct RenderPassTargets { /// Color targets pub targets: Vec, @@ -250,6 +250,14 @@ pub struct RenderPassTargets { } impl RenderPassTargets { + pub fn resolved_color(&self, idx: usize) -> RenderTargetHandle { + let target = &self.targets[idx]; + match target.resolve { + Some(resolve) => resolve, + None => target.color, + } + } + /// Determines if two renderpasses have compatible targets. /// /// `this: Some, other: Some` will check the contents @@ -260,9 +268,9 @@ impl RenderPassTargets { (Some(this), Some(other)) => { let targets_compatible = this.targets.len() == other.targets.len() && this.targets.iter().zip(other.targets.iter()).all(|(me, you)| { - let color_compat = me.color.handle.compatible(&you.color.handle); + let color_compat = me.color.compatible(&you.color); let resolve_compat = match (me.resolve, you.resolve) { - (Some(me_dep), Some(you_dep)) => me_dep.handle.compatible(&you_dep.handle), + (Some(me_dep), Some(you_dep)) => me_dep.compatible(&you_dep), (None, None) => true, _ => false, }; @@ -271,7 +279,7 @@ impl RenderPassTargets { let depth_compatible = match (&this.depth_stencil, &other.depth_stencil) { (Some(this_depth), Some(other_depth)) => { - this_depth.target.handle.compatible(&other_depth.target.handle) + this_depth.target.compatible(&other_depth.target) && this_depth.depth_clear == other_depth.depth_clear && this_depth.stencil_clear == other_depth.stencil_clear } @@ -288,23 +296,23 @@ impl RenderPassTargets { } /// Color target in a renderpass. -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct RenderPassTarget { /// Color attachment. Must be declared as a dependency of the node before it /// can be used. - pub color: DeclaredDependency, + pub color: RenderTargetHandle, /// Color the attachment will be cleared with if this is the first use. - pub clear: Color, + pub clear: Vec4, /// Resolve attachment. Can only be present if color attachment has > 1 /// sample. - pub resolve: Option>, + pub resolve: Option, } /// Depth target in a renderpass. -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct RenderPassDepthTarget { /// The target to use as depth. - pub target: DeclaredDependency, + pub target: RenderTargetHandle, /// Depth value the attachment will be cleared with if this is the first /// use. pub depth_clear: Option, diff --git a/rend3/src/graph/node.rs b/rend3/src/graph/node.rs index c1f29ea0..b7eb3264 100644 --- a/rend3/src/graph/node.rs +++ b/rend3/src/graph/node.rs @@ -101,6 +101,13 @@ impl<'a, 'node> RenderGraphNodeBuilder<'a, 'node> { self.rpass.is_none(), "Cannot have more than one graph-associated renderpass per node." ); + for targets in &targets.targets { + self.add_render_target(targets.color, NodeResourceUsage::InputOutput); + self.add_optional_render_target(targets.resolve, NodeResourceUsage::InputOutput); + } + if let Some(depth_stencil) = &targets.depth_stencil { + self.add_render_target(depth_stencil.target, NodeResourceUsage::InputOutput); + } self.rpass = Some(targets); DeclaredDependency { handle: RenderPassHandle, diff --git a/rend3/src/managers/camera.rs b/rend3/src/managers/camera.rs index 7db4a0e0..2fa6b6bb 100644 --- a/rend3/src/managers/camera.rs +++ b/rend3/src/managers/camera.rs @@ -8,7 +8,7 @@ use crate::{ /// Manages the camera's location and projection settings. #[derive(Debug, Clone)] -pub struct CameraManager { +pub struct CameraState { handedness: Handedness, orig_view: Mat4, proj: Mat4, @@ -17,11 +17,11 @@ pub struct CameraManager { data: Camera, aspect_ratio: f32, } -impl CameraManager { +impl CameraState { /// Builds a new camera, using the given aspect ratio. If no aspect ratio is /// given it is assumed that no aspect ratio scaling should be done. pub fn new(data: Camera, handedness: Handedness, aspect_ratio: Option) -> Self { - profiling::scope!("CameraManager::new"); + profiling::scope!("CameraState::new"); let aspect_ratio = aspect_ratio.unwrap_or(1.0); let proj = compute_projection_matrix(data, handedness, aspect_ratio); diff --git a/rend3/src/managers/directional.rs b/rend3/src/managers/directional.rs index e3a36945..5734bbdb 100644 --- a/rend3/src/managers/directional.rs +++ b/rend3/src/managers/directional.rs @@ -7,7 +7,7 @@ use wgpu::{ }; use crate::{ - managers::CameraManager, + managers::CameraState, types::{DirectionalLight, DirectionalLightHandle}, util::{ bind_merge::{BindGroupBuilder, BindGroupLayoutBuilder}, @@ -55,7 +55,7 @@ struct ShaderDirectionalLight { #[derive(Debug, Clone)] pub struct ShadowDesc { pub map: ShadowMap, - pub camera: CameraManager, + pub camera: CameraState, } /// Manages directional lights and their associated shadow maps. @@ -100,7 +100,7 @@ impl DirectionalLightManager { self.data[handle.idx].take().unwrap(); } - pub fn evaluate(&mut self, renderer: &Renderer, user_camera: &CameraManager) -> (UVec2, Vec) { + pub fn evaluate(&mut self, renderer: &Renderer, user_camera: &CameraState) -> (UVec2, Vec) { profiling::scope!("DirectionalLightManager::evaluate"); let shadow_maps: Vec<_> = self diff --git a/rend3/src/managers/directional/shadow_camera.rs b/rend3/src/managers/directional/shadow_camera.rs index 678eb182..e3883b0a 100644 --- a/rend3/src/managers/directional/shadow_camera.rs +++ b/rend3/src/managers/directional/shadow_camera.rs @@ -1,9 +1,9 @@ use glam::{Mat4, Vec3, Vec3A}; use rend3_types::{Camera, CameraProjection, Handedness}; -use crate::managers::{CameraManager, InternalDirectionalLight}; +use crate::managers::{CameraState, InternalDirectionalLight}; -pub(super) fn shadow_camera(l: &InternalDirectionalLight, user_camera: &CameraManager) -> CameraManager { +pub(super) fn shadow_camera(l: &InternalDirectionalLight, user_camera: &CameraState) -> CameraState { let camera_location = user_camera.location(); let shadow_texel_size = l.inner.distance / l.inner.resolution as f32; @@ -22,7 +22,7 @@ pub(super) fn shadow_camera(l: &InternalDirectionalLight, user_camera: &CameraMa let inv_origin_view = origin_view.inverse(); let new_shadow_location = inv_origin_view.transform_point3(shadow_location); - CameraManager::new( + CameraState::new( Camera { projection: CameraProjection::Orthographic { size: Vec3A::splat(l.inner.distance), diff --git a/rend3/src/renderer/eval.rs b/rend3/src/renderer/eval.rs index 6bf7033a..bf673e5c 100644 --- a/rend3/src/renderer/eval.rs +++ b/rend3/src/renderer/eval.rs @@ -116,9 +116,11 @@ pub fn evaluate_instructions(renderer: &Renderer) -> InstructionEvaluationOutput InstructionKind::ChangePointLight { handle, change } => { data_core.point_light_manager.update(handle, change); } - InstructionKind::SetAspectRatio { ratio } => data_core.camera_manager.set_aspect_ratio(Some(ratio)), + InstructionKind::SetAspectRatio { ratio } => { + data_core.viewport_camera_state.set_aspect_ratio(Some(ratio)) + } InstructionKind::SetCameraData { data } => { - data_core.camera_manager.set_data(data); + data_core.viewport_camera_state.set_data(data); } InstructionKind::DuplicateObject { src_handle, @@ -202,7 +204,7 @@ pub fn evaluate_instructions(renderer: &Renderer) -> InstructionEvaluationOutput let d2c_texture = data_core.d2c_texture_manager.evaluate(&renderer.device); let (shadow_target_size, shadows) = data_core .directional_light_manager - .evaluate(renderer, &data_core.camera_manager); + .evaluate(renderer, &data_core.viewport_camera_state); data_core.point_light_manager.evaluate(renderer); let mesh_buffer = renderer.mesh_manager.evaluate(); diff --git a/rend3/src/renderer/mod.rs b/rend3/src/renderer/mod.rs index 0ce025a9..529167f7 100644 --- a/rend3/src/renderer/mod.rs +++ b/rend3/src/renderer/mod.rs @@ -14,7 +14,7 @@ use crate::{ graph::{GraphTextureStore, InstructionEvaluationOutput}, instruction::{InstructionKind, InstructionStreamPair}, managers::{ - CameraManager, DirectionalLightManager, GraphStorage, HandleAllocator, MaterialManager, MeshCreationError, + CameraState, DirectionalLightManager, GraphStorage, HandleAllocator, MaterialManager, MeshCreationError, MeshManager, ObjectManager, PointLightManager, SkeletonCreationError, SkeletonManager, TextureCreationError, TextureManager, }, @@ -97,8 +97,8 @@ impl Default for HandleAllocators { /// All the mutex protected data within the renderer pub struct RendererDataCore { - /// Position and settings of the camera. - pub camera_manager: CameraManager, + /// Position and settings of the viewport camera. + pub viewport_camera_state: CameraState, /// Manages all 2D textures, including bindless bind group. pub d2_texture_manager: TextureManager, /// Manages all Cube textures, including bindless bind groups. diff --git a/rend3/src/renderer/setup.rs b/rend3/src/renderer/setup.rs index 9c477e84..6c5968f3 100644 --- a/rend3/src/renderer/setup.rs +++ b/rend3/src/renderer/setup.rs @@ -9,7 +9,7 @@ use crate::{ graph::GraphTextureStore, instruction::InstructionStreamPair, managers::{ - CameraManager, DirectionalLightManager, GraphStorage, MaterialManager, MeshManager, ObjectManager, + CameraState, DirectionalLightManager, GraphStorage, MaterialManager, MeshManager, ObjectManager, PointLightManager, SkeletonManager, TextureManager, }, renderer::{HandleAllocators, RendererDataCore}, @@ -28,7 +28,7 @@ pub fn create_renderer( let limits = iad.device.limits(); let downlevel = iad.adapter.get_downlevel_capabilities(); - let camera_manager = CameraManager::new(Camera::default(), handedness, aspect_ratio); + let camera_state = CameraState::new(Camera::default(), handedness, aspect_ratio); let d2_texture_manager = TextureManager::new( &iad.device, @@ -88,7 +88,7 @@ pub fn create_renderer( resource_handle_allocators: HandleAllocators::default(), mesh_manager, data_core: Mutex::new(RendererDataCore { - camera_manager, + viewport_camera_state: camera_state, d2_texture_manager, d2c_texture_manager, material_manager, From 7daf025f255694677e50ab39f6f8a9e9223d8a5a Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Tue, 26 Dec 2023 20:17:23 -0500 Subject: [PATCH 3/8] Further split up the input struct --- examples/animation/src/lib.rs | 16 ++-- examples/cube-no-framework/src/main.rs | 16 ++-- examples/cube/src/lib.rs | 16 ++-- examples/egui/src/main.rs | 16 ++-- examples/scene-viewer/src/lib.rs | 16 ++-- examples/skinning/src/lib.rs | 16 ++-- examples/static-gltf/src/main.rs | 16 ++-- examples/textured-quad/src/main.rs | 16 ++-- rend3-routine/src/base.rs | 100 +++++++++++++++---------- rend3-test/src/runner.rs | 16 ++-- 10 files changed, 151 insertions(+), 93 deletions(-) diff --git a/examples/animation/src/lib.rs b/examples/animation/src/lib.rs index 460d806c..3829abe3 100644 --- a/examples/animation/src/lib.rs +++ b/examples/animation/src/lib.rs @@ -175,12 +175,16 @@ impl rend3_framework::App for AnimationExample { &mut graph, rend3_routine::base::BaseRenderGraphInputs { eval_output: &eval_output, - pbr: &pbr_routine, - skybox: None, - tonemapping: &tonemapping_routine, - target_texture: frame_handle, - resolution, - samples: SAMPLE_COUNT, + routines: rend3_routine::base::BaseRenderGraphRoutines { + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + }, + target: rend3_routine::base::OutputRenderTarget { + handle: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, }, rend3_routine::base::BaseRenderGraphSettings { ambient_color: glam::Vec4::ZERO, diff --git a/examples/cube-no-framework/src/main.rs b/examples/cube-no-framework/src/main.rs index 95d8f952..471076b5 100644 --- a/examples/cube-no-framework/src/main.rs +++ b/examples/cube-no-framework/src/main.rs @@ -222,12 +222,16 @@ fn main() { &mut graph, rend3_routine::base::BaseRenderGraphInputs { eval_output: &eval_output, - pbr: &pbr_routine, - skybox: None, - tonemapping: &tonemapping_routine, - target_texture: frame_handle, - resolution, - samples: rend3::types::SampleCount::One, + routines: rend3_routine::base::BaseRenderGraphRoutines { + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + }, + target: rend3_routine::base::OutputRenderTarget { + handle: frame_handle, + resolution, + samples: rend3::types::SampleCount::One, + }, }, rend3_routine::base::BaseRenderGraphSettings { ambient_color: glam::Vec4::ZERO, diff --git a/examples/cube/src/lib.rs b/examples/cube/src/lib.rs index 3dde28e9..1446dde7 100644 --- a/examples/cube/src/lib.rs +++ b/examples/cube/src/lib.rs @@ -195,12 +195,16 @@ impl rend3_framework::App for CubeExample { &mut graph, rend3_routine::base::BaseRenderGraphInputs { eval_output: &eval_output, - pbr: &pbr_routine, - skybox: None, - tonemapping: &tonemapping_routine, - target_texture: frame_handle, - resolution, - samples: SAMPLE_COUNT, + routines: rend3_routine::base::BaseRenderGraphRoutines { + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + }, + target: rend3_routine::base::OutputRenderTarget { + handle: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, }, rend3_routine::base::BaseRenderGraphSettings { ambient_color: glam::Vec4::ZERO, diff --git a/examples/egui/src/main.rs b/examples/egui/src/main.rs index 0e257e07..e4011b4d 100644 --- a/examples/egui/src/main.rs +++ b/examples/egui/src/main.rs @@ -227,12 +227,16 @@ impl rend3_framework::App for EguiExample { &mut graph, rend3_routine::base::BaseRenderGraphInputs { eval_output: &eval_output, - pbr: &pbr_routine, - skybox: None, - tonemapping: &tonemapping_routine, - target_texture: frame_handle, - resolution, - samples: SAMPLE_COUNT, + routines: rend3_routine::base::BaseRenderGraphRoutines { + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + }, + target: rend3_routine::base::OutputRenderTarget { + handle: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, }, rend3_routine::base::BaseRenderGraphSettings { ambient_color: glam::Vec4::ZERO, diff --git a/examples/scene-viewer/src/lib.rs b/examples/scene-viewer/src/lib.rs index 049b9742..870cb632 100644 --- a/examples/scene-viewer/src/lib.rs +++ b/examples/scene-viewer/src/lib.rs @@ -636,12 +636,16 @@ impl rend3_framework::App for SceneViewer { &mut graph, rend3_routine::base::BaseRenderGraphInputs { eval_output: &eval_output, - pbr: &pbr_routine, - skybox: Some(&skybox_routine), - tonemapping: &tonemapping_routine, - target_texture: frame_handle, - resolution, - samples: self.samples, + routines: rend3_routine::base::BaseRenderGraphRoutines { + pbr: &pbr_routine, + skybox: Some(&skybox_routine), + tonemapping: &tonemapping_routine, + }, + target: rend3_routine::base::OutputRenderTarget { + handle: frame_handle, + resolution, + samples: self.samples, + }, }, rend3_routine::base::BaseRenderGraphSettings { ambient_color: Vec3::splat(self.ambient_light_level).extend(1.0), diff --git a/examples/skinning/src/lib.rs b/examples/skinning/src/lib.rs index f8c262b3..fbd33350 100644 --- a/examples/skinning/src/lib.rs +++ b/examples/skinning/src/lib.rs @@ -169,12 +169,16 @@ impl rend3_framework::App for SkinningExample { &mut graph, rend3_routine::base::BaseRenderGraphInputs { eval_output: &eval_output, - pbr: &pbr_routine, - skybox: None, - tonemapping: &tonemapping_routine, - target_texture: frame_handle, - resolution, - samples: SAMPLE_COUNT, + routines: rend3_routine::base::BaseRenderGraphRoutines { + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + }, + target: rend3_routine::base::OutputRenderTarget { + handle: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, }, rend3_routine::base::BaseRenderGraphSettings { ambient_color: glam::Vec4::ZERO, diff --git a/examples/static-gltf/src/main.rs b/examples/static-gltf/src/main.rs index d062c4cb..bfd3b9f5 100644 --- a/examples/static-gltf/src/main.rs +++ b/examples/static-gltf/src/main.rs @@ -160,12 +160,16 @@ impl rend3_framework::App for GltfExample { &mut graph, rend3_routine::base::BaseRenderGraphInputs { eval_output: &eval_output, - pbr: &pbr_routine, - skybox: None, - tonemapping: &tonemapping_routine, - target_texture: frame_handle, - resolution, - samples: SAMPLE_COUNT, + routines: rend3_routine::base::BaseRenderGraphRoutines { + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + }, + target: rend3_routine::base::OutputRenderTarget { + handle: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, }, rend3_routine::base::BaseRenderGraphSettings { ambient_color: glam::Vec4::ZERO, diff --git a/examples/textured-quad/src/main.rs b/examples/textured-quad/src/main.rs index f788fbc1..26906b15 100644 --- a/examples/textured-quad/src/main.rs +++ b/examples/textured-quad/src/main.rs @@ -185,12 +185,16 @@ impl rend3_framework::App for TexturedQuadExample { &mut graph, rend3_routine::base::BaseRenderGraphInputs { eval_output: &eval_output, - pbr: &pbr_routine, - skybox: None, - tonemapping: &tonemapping_routine, - target_texture: frame_handle, - resolution, - samples: SAMPLE_COUNT, + routines: rend3_routine::base::BaseRenderGraphRoutines { + pbr: &pbr_routine, + skybox: None, + tonemapping: &tonemapping_routine, + }, + target: rend3_routine::base::OutputRenderTarget { + handle: frame_handle, + resolution, + samples: SAMPLE_COUNT, + }, }, rend3_routine::base::BaseRenderGraphSettings { ambient_color: glam::Vec4::ZERO, diff --git a/rend3-routine/src/base.rs b/rend3-routine/src/base.rs index 5fa052a2..d5d576d8 100644 --- a/rend3-routine/src/base.rs +++ b/rend3-routine/src/base.rs @@ -75,14 +75,22 @@ impl DepthTargets { } } -pub struct BaseRenderGraphInputs<'a, 'node> { - pub eval_output: &'a InstructionEvaluationOutput, +pub struct OutputRenderTarget { + pub handle: RenderTargetHandle, + pub resolution: UVec2, + pub samples: SampleCount, +} + +pub struct BaseRenderGraphRoutines<'node> { pub pbr: &'node crate::pbr::PbrRoutine, pub skybox: Option<&'node crate::skybox::SkyboxRoutine>, pub tonemapping: &'node crate::tonemapping::TonemappingRoutine, - pub target_texture: RenderTargetHandle, - pub resolution: UVec2, - pub samples: SampleCount, +} + +pub struct BaseRenderGraphInputs<'a, 'node> { + pub eval_output: &'a InstructionEvaluationOutput, + pub routines: BaseRenderGraphRoutines<'node>, + pub target: OutputRenderTarget, } #[derive(Debug, Default)] @@ -231,17 +239,17 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { // Make the actual render targets we want to render to. let color = graph.add_render_target(RenderTargetDescriptor { label: Some("hdr color".into()), - resolution: inputs.resolution, + resolution: inputs.target.resolution, depth: 1, - samples: inputs.samples, + samples: inputs.target.samples, mip_levels: Some(1), format: TextureFormat::Rgba16Float, usage: TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING, }); - let resolve = inputs.samples.needs_resolve().then(|| { + let resolve = inputs.target.samples.needs_resolve().then(|| { graph.add_render_target(RenderTargetDescriptor { label: Some("hdr resolve".into()), - resolution: inputs.resolution, + resolution: inputs.target.resolution, depth: 1, mip_levels: Some(1), samples: SampleCount::One, @@ -249,7 +257,7 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { usage: TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING, }) }); - let depth = DepthTargets::new(graph, inputs.resolution, inputs.samples); + let depth = DepthTargets::new(graph, inputs.target.resolution, inputs.target.samples); let primary_renderpass = graph::RenderPassTargets { targets: vec![graph::RenderPassTarget { color, @@ -302,7 +310,7 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { uniforms::UniformInformation { samplers: &base.samplers, ambient: self.settings.ambient_color, - resolution: self.inputs.resolution, + resolution: self.inputs.target.resolution, }, ); } @@ -340,8 +348,8 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { base.gpu_culler.add_object_uniform_upload_to_graph::( self.graph, CameraSpecifier::Viewport, - self.inputs.resolution, - self.inputs.samples, + self.inputs.target.resolution, + self.inputs.target.samples, "Uniform Bake", ); } @@ -373,7 +381,10 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { }), }; - let routines = [&self.inputs.pbr.opaque_depth, &self.inputs.pbr.cutout_depth]; + let routines = [ + &self.inputs.routines.pbr.opaque_depth, + &self.inputs.routines.pbr.cutout_depth, + ]; for routine in routines { routine.add_forward_to_graph(ForwardRoutineArgs { graph: self.graph, @@ -381,7 +392,7 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { camera: CameraSpecifier::Shadow(shadow_index as u32), binding_data: forward::ForwardRoutineBindingData { whole_frame_uniform_bg: self.shadow_uniform_bg, - per_material_bgl: &self.inputs.pbr.per_material, + per_material_bgl: &self.inputs.routines.pbr.per_material, extra_bgs: None, }, culling_source: forward::CullingSource::Residual(*shadow_cull), @@ -394,19 +405,22 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { /// Render the skybox. pub fn skybox(&mut self) { - if let Some(skybox) = self.inputs.skybox { + if let Some(skybox) = self.inputs.routines.skybox { skybox.add_to_graph( self.graph, self.primary_renderpass.clone(), self.forward_uniform_bg, - self.inputs.samples, + self.inputs.target.samples, ); } } /// Render the PBR materials. pub fn pbr_render_opaque_predicted_triangles(&mut self) { - let routines = [&self.inputs.pbr.opaque_routine, &self.inputs.pbr.cutout_routine]; + let routines = [ + &self.inputs.routines.pbr.opaque_routine, + &self.inputs.routines.pbr.cutout_routine, + ]; for routine in routines { routine.add_forward_to_graph(ForwardRoutineArgs { graph: self.graph, @@ -414,11 +428,11 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { camera: CameraSpecifier::Viewport, binding_data: forward::ForwardRoutineBindingData { whole_frame_uniform_bg: self.forward_uniform_bg, - per_material_bgl: &self.inputs.pbr.per_material, + per_material_bgl: &self.inputs.routines.pbr.per_material, extra_bgs: None, }, culling_source: forward::CullingSource::Predicted, - samples: self.inputs.samples, + samples: self.inputs.target.samples, renderpass: self.primary_renderpass.clone(), }); } @@ -426,7 +440,10 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { /// Render the PBR materials. pub fn pbr_render_opaque_residual_triangles(&mut self) { - let routines = [&self.inputs.pbr.opaque_routine, &self.inputs.pbr.cutout_routine]; + let routines = [ + &self.inputs.routines.pbr.opaque_routine, + &self.inputs.routines.pbr.cutout_routine, + ]; for routine in routines { routine.add_forward_to_graph(ForwardRoutineArgs { graph: self.graph, @@ -434,11 +451,11 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { camera: CameraSpecifier::Viewport, binding_data: forward::ForwardRoutineBindingData { whole_frame_uniform_bg: self.forward_uniform_bg, - per_material_bgl: &self.inputs.pbr.per_material, + per_material_bgl: &self.inputs.routines.pbr.per_material, extra_bgs: None, }, culling_source: forward::CullingSource::Residual(self.cull), - samples: self.inputs.samples, + samples: self.inputs.target.samples, renderpass: self.primary_renderpass.clone(), }); } @@ -446,34 +463,39 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { /// Render the PBR materials. pub fn pbr_forward_rendering_transparent(&mut self) { - self.inputs.pbr.blend_routine.add_forward_to_graph(ForwardRoutineArgs { - graph: self.graph, - label: "PBR Forward Transparent", - camera: CameraSpecifier::Viewport, - binding_data: forward::ForwardRoutineBindingData { - whole_frame_uniform_bg: self.forward_uniform_bg, - per_material_bgl: &self.inputs.pbr.per_material, - extra_bgs: None, - }, - culling_source: forward::CullingSource::Residual(self.cull), - samples: self.inputs.samples, - renderpass: self.primary_renderpass.clone(), - }); + self.inputs + .routines + .pbr + .blend_routine + .add_forward_to_graph(ForwardRoutineArgs { + graph: self.graph, + label: "PBR Forward Transparent", + camera: CameraSpecifier::Viewport, + binding_data: forward::ForwardRoutineBindingData { + whole_frame_uniform_bg: self.forward_uniform_bg, + per_material_bgl: &self.inputs.routines.pbr.per_material, + extra_bgs: None, + }, + culling_source: forward::CullingSource::Residual(self.cull), + samples: self.inputs.target.samples, + renderpass: self.primary_renderpass.clone(), + }); } pub fn hi_z(&mut self) { self.inputs + .routines .pbr .hi_z - .add_hi_z_to_graph(self.graph, self.depth, self.inputs.resolution); + .add_hi_z_to_graph(self.graph, self.depth, self.inputs.target.resolution); } /// Tonemap onto the given render target. pub fn tonemapping(&mut self) { - self.inputs.tonemapping.add_to_graph( + self.inputs.routines.tonemapping.add_to_graph( self.graph, self.primary_renderpass.resolved_color(0), - self.inputs.target_texture, + self.inputs.target.handle, self.forward_uniform_bg, ); } diff --git a/rend3-test/src/runner.rs b/rend3-test/src/runner.rs index 11edc61d..a06bf8d1 100644 --- a/rend3-test/src/runner.rs +++ b/rend3-test/src/runner.rs @@ -165,12 +165,16 @@ impl TestRunner { &mut graph, rend3_routine::base::BaseRenderGraphInputs { eval_output: &eval_output, - pbr: &self.pbr, - skybox: None, - tonemapping: &self.tonemapping, - target_texture: frame_handle, - resolution: UVec2::splat(settings.size), - samples: settings.samples, + routines: rend3_routine::base::BaseRenderGraphRoutines { + pbr: &self.pbr, + skybox: None, + tonemapping: &self.tonemapping, + }, + target: rend3_routine::base::OutputRenderTarget { + handle: frame_handle, + resolution: UVec2::splat(settings.size), + samples: settings.samples, + }, }, rend3_routine::base::BaseRenderGraphSettings { ambient_color: glam::Vec4::ZERO, From fcf9190f6e1f3c1c67a0edbda0ddaab7263952ff Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Tue, 26 Dec 2023 20:21:34 -0500 Subject: [PATCH 4/8] Fix doc link --- rend3-routine/src/common/camera.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rend3-routine/src/common/camera.rs b/rend3-routine/src/common/camera.rs index 300a6876..0be9baef 100644 --- a/rend3-routine/src/common/camera.rs +++ b/rend3-routine/src/common/camera.rs @@ -8,7 +8,7 @@ pub enum CameraSpecifier { impl CameraSpecifier { /// Returns `true` if the camera specifier is [`Viewport`]. /// - /// [`Viewport`]: CameraIndex::Viewport + /// [`Viewport`]: CameraSpecifier::Viewport #[must_use] pub fn is_viewport(&self) -> bool { matches!(self, Self::Viewport) @@ -16,7 +16,7 @@ impl CameraSpecifier { /// Returns `true` if the camera specifier is [`Shadow`]. /// - /// [`Shadow`]: CameraIndex::Shadow + /// [`Shadow`]: CameraSpecifier::Shadow #[must_use] pub fn is_shadow(&self) -> bool { matches!(self, Self::Shadow(..)) From 499395cd4705f88f9b658f1fc02d89774a7d2f03 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Tue, 26 Dec 2023 20:52:58 -0500 Subject: [PATCH 5/8] Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d2480c4..e10a7508 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ Per Keep a Changelog there are 6 main categories of changes: ### Major Changes - rend3: `add_mesh`, `add_skeleton` and `add_texture_*` now return Results with fully typed errors. This will catch all errors on all platforms except for web, where wgpu allocation errors will not be caught. @cwfitzgerald +- rend3-routine: Argument structs broken up into multiple sub-structs for better ergonomics. @cwfitzgerald ### Added - rend3-egui: Added the ability to create egui textures (egui::TextureId) with the wgpu backend @AlbinSjoegren From 284e0a03fa4bb42825525107d36f9cb640dd7d2f Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 27 Dec 2023 02:39:10 -0500 Subject: [PATCH 6/8] Fix shadow buffer clears --- rend3-egui/src/lib.rs | 21 +++++++++------- rend3-routine/src/base.rs | 9 +++++++ rend3-routine/src/clear.rs | 20 +++++++++++++++ rend3-routine/src/culling/culler.rs | 9 ++++++- rend3-routine/src/forward.rs | 2 +- rend3-routine/src/hi_z.rs | 38 +++++++++++++++++------------ rend3-routine/src/lib.rs | 1 + rend3-routine/src/skybox.rs | 2 +- rend3-routine/src/tonemapping.rs | 19 +++++++++------ rend3/src/graph/graph.rs | 6 +++-- rend3/src/graph/node.rs | 9 ++++--- 11 files changed, 94 insertions(+), 42 deletions(-) create mode 100644 rend3-routine/src/clear.rs diff --git a/rend3-egui/src/lib.rs b/rend3-egui/src/lib.rs index 3d530854..27a0c2f8 100644 --- a/rend3-egui/src/lib.rs +++ b/rend3-egui/src/lib.rs @@ -7,7 +7,7 @@ use std::{mem, sync::Arc}; use egui::TexturesDelta; use glam::Vec4; use rend3::{ - graph::{RenderGraph, RenderPassTarget, RenderPassTargets, RenderTargetHandle}, + graph::{NodeResourceUsage, RenderGraph, RenderPassTarget, RenderPassTargets, RenderTargetHandle}, types::SampleCount, Renderer, }; @@ -59,14 +59,17 @@ impl EguiRenderRoutine { ) { let mut builder = graph.add_node("egui"); - let rpass_handle = builder.add_renderpass(RenderPassTargets { - targets: vec![RenderPassTarget { - color: output, - clear: Vec4::ZERO, - resolve: None, - }], - depth_stencil: None, - }); + let rpass_handle = builder.add_renderpass( + RenderPassTargets { + targets: vec![RenderPassTarget { + color: output, + clear: Vec4::ZERO, + resolve: None, + }], + depth_stencil: None, + }, + NodeResourceUsage::Output, + ); // We can't free textures directly after the call to `execute_with_renderpass` as it freezes // the lifetime of `self` for the remainder of the closure. so we instead buffer the textures diff --git a/rend3-routine/src/base.rs b/rend3-routine/src/base.rs index d5d576d8..8b6dcc9b 100644 --- a/rend3-routine/src/base.rs +++ b/rend3-routine/src/base.rs @@ -28,6 +28,7 @@ use rend3::{ use wgpu::{BindGroup, Buffer}; use crate::{ + clear, common::{self, CameraSpecifier}, culling, forward::{self, ForwardRoutineArgs}, @@ -142,6 +143,9 @@ impl BaseRenderGraph { // Create the data and handles for the graph. let mut state = BaseRenderGraphIntermediateState::new(graph, inputs, settings); + // Clear the shadow buffers. This, as an explicit node, must be done as a limitation of the graph dependency system. + state.clear_shadow_buffers(); + // Prepare all the uniforms that all shaders need access to. state.create_frame_uniforms(self); @@ -297,6 +301,11 @@ impl<'a, 'node> BaseRenderGraphIntermediateState<'a, 'node> { } } + /// Clear the shadow buffers. This, as an explicit node, must be done as a limitation of the graph dependency system. + fn clear_shadow_buffers(&mut self) { + clear::add_depth_clear_to_graph(self.graph, self.shadow, 0.0); + } + /// Create all the uniforms all the shaders in this graph need. pub fn create_frame_uniforms(&mut self, base: &'node BaseRenderGraph) { uniforms::add_to_graph( diff --git a/rend3-routine/src/clear.rs b/rend3-routine/src/clear.rs new file mode 100644 index 00000000..9e87825b --- /dev/null +++ b/rend3-routine/src/clear.rs @@ -0,0 +1,20 @@ +use rend3::graph::{NodeResourceUsage, RenderGraph, RenderPassDepthTarget, RenderPassTargets, RenderTargetHandle}; + +/// Due to limitations of how we auto-clear buffers, we need to explicitly clear the shadow depth buffer. +pub fn add_depth_clear_to_graph(graph: &mut RenderGraph<'_>, depth: RenderTargetHandle, depth_clear: f32) { + let mut builder = graph.add_node("Clear Depth"); + + let _rpass_handle = builder.add_renderpass( + RenderPassTargets { + targets: vec![], + depth_stencil: Some(RenderPassDepthTarget { + target: depth, + depth_clear: Some(depth_clear), + stencil_clear: None, + }), + }, + NodeResourceUsage::Output, + ); + + builder.build(|_| ()) +} diff --git a/rend3-routine/src/culling/culler.rs b/rend3-routine/src/culling/culler.rs index 99a8928e..b9ed06f7 100644 --- a/rend3-routine/src/culling/culler.rs +++ b/rend3-routine/src/culling/culler.rs @@ -740,7 +740,14 @@ impl GpuCuller { ) { let mut node = graph.add_node(name); let output = node.add_data(draw_calls_hdl, NodeResourceUsage::Output); - let depth_handle = node.add_render_target(depth_handle, NodeResourceUsage::Input); + let depth_handle = node.add_render_target( + depth_handle, + if camera_specifier.is_shadow() { + NodeResourceUsage::Reference + } else { + NodeResourceUsage::Input + }, + ); node.build(move |mut ctx| { let camera = match camera_specifier { diff --git a/rend3-routine/src/forward.rs b/rend3-routine/src/forward.rs index 7d966be3..a54b2cd7 100644 --- a/rend3-routine/src/forward.rs +++ b/rend3-routine/src/forward.rs @@ -194,7 +194,7 @@ impl ForwardRoutine { builder.add_side_effect(); - let rpass_handle = builder.add_renderpass(args.renderpass.clone()); + let rpass_handle = builder.add_renderpass(args.renderpass.clone(), NodeResourceUsage::Output); let whole_frame_uniform_handle = builder.add_data(args.binding_data.whole_frame_uniform_bg, NodeResourceUsage::Input); diff --git a/rend3-routine/src/hi_z.rs b/rend3-routine/src/hi_z.rs index f345d807..2fd75bc8 100644 --- a/rend3-routine/src/hi_z.rs +++ b/rend3-routine/src/hi_z.rs @@ -213,14 +213,17 @@ impl HiZRoutine { let source = node.add_render_target(multi_sample, NodeResourceUsage::Output); - let rpass_handle = node.add_renderpass(RenderPassTargets { - targets: vec![], - depth_stencil: Some(RenderPassDepthTarget { - target: depth_targets.single_sample_mipped.set_mips(0..1), - depth_clear: Some(0.0), - stencil_clear: None, - }), - }); + let rpass_handle = node.add_renderpass( + RenderPassTargets { + targets: vec![], + depth_stencil: Some(RenderPassDepthTarget { + target: depth_targets.single_sample_mipped.set_mips(0..1), + depth_clear: Some(0.0), + stencil_clear: None, + }), + }, + NodeResourceUsage::InputOutput, + ); node.add_side_effect(); @@ -249,14 +252,17 @@ impl HiZRoutine { NodeResourceUsage::Input, ); - let rpass_handle = node.add_renderpass(RenderPassTargets { - targets: vec![], - depth_stencil: Some(RenderPassDepthTarget { - target: dst_target, - depth_clear: Some(0.0), - stencil_clear: None, - }), - }); + let rpass_handle = node.add_renderpass( + RenderPassTargets { + targets: vec![], + depth_stencil: Some(RenderPassDepthTarget { + target: dst_target, + depth_clear: Some(0.0), + stencil_clear: None, + }), + }, + NodeResourceUsage::InputOutput, + ); node.add_side_effect(); diff --git a/rend3-routine/src/lib.rs b/rend3-routine/src/lib.rs index 99666a2f..9f13361b 100644 --- a/rend3-routine/src/lib.rs +++ b/rend3-routine/src/lib.rs @@ -19,6 +19,7 @@ //! too much user side boilerplate. pub mod base; +pub mod clear; pub mod common; pub mod culling; pub mod forward; diff --git a/rend3-routine/src/skybox.rs b/rend3-routine/src/skybox.rs index f5a792ea..e8ae5d8a 100644 --- a/rend3-routine/src/skybox.rs +++ b/rend3-routine/src/skybox.rs @@ -90,7 +90,7 @@ impl SkyboxRoutine { ) { let mut builder = graph.add_node("Skybox"); - let rpass_handle = builder.add_renderpass(renderpass); + let rpass_handle = builder.add_renderpass(renderpass, NodeResourceUsage::InputOutput); let forward_uniform_handle = builder.add_data(forward_uniform_bg, NodeResourceUsage::Input); diff --git a/rend3-routine/src/tonemapping.rs b/rend3-routine/src/tonemapping.rs index 2198eb4f..ee4c1d41 100644 --- a/rend3-routine/src/tonemapping.rs +++ b/rend3-routine/src/tonemapping.rs @@ -129,14 +129,17 @@ impl TonemappingRoutine { let input_handle = builder.add_render_target(src, NodeResourceUsage::Input); - let rpass_handle = builder.add_renderpass(RenderPassTargets { - targets: vec![RenderPassTarget { - color: dst, - clear: Vec4::ZERO, - resolve: None, - }], - depth_stencil: None, - }); + let rpass_handle = builder.add_renderpass( + RenderPassTargets { + targets: vec![RenderPassTarget { + color: dst, + clear: Vec4::ZERO, + resolve: None, + }], + depth_stencil: None, + }, + NodeResourceUsage::InputOutput, + ); let forward_uniform_handle = builder.add_data(forward_uniform_bg, NodeResourceUsage::Input); diff --git a/rend3/src/graph/graph.rs b/rend3/src/graph/graph.rs index 3ef755b1..24942e40 100644 --- a/rend3/src/graph/graph.rs +++ b/rend3/src/graph/graph.rs @@ -224,7 +224,6 @@ impl<'node> RenderGraph<'node> { resource_spans .entry(reference.to_resource()) .and_modify(|span| { - span.first_usage.get_or_insert(idx); span.last_reference = Some(idx); }) .or_insert(ResourceSpan { @@ -257,7 +256,10 @@ impl<'node> RenderGraph<'node> { }; resource_spans .entry(output.to_resource()) - .and_modify(|span| span.last_reference = end) + .and_modify(|span| { + span.first_usage.get_or_insert(idx); + span.last_reference = end + }) .or_insert(ResourceSpan { first_reference: idx, first_usage: Some(idx), diff --git a/rend3/src/graph/node.rs b/rend3/src/graph/node.rs index b7eb3264..c4a6c4df 100644 --- a/rend3/src/graph/node.rs +++ b/rend3/src/graph/node.rs @@ -41,6 +41,7 @@ pub(super) struct RenderGraphNode<'node> { pub exec: Box FnOnce(NodeExecutionContext<'a, 'pass, 'node>) + 'node>, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum NodeResourceUsage { /// Doesn't access the resource at all, just need access to the resource. Reference, @@ -96,17 +97,17 @@ impl<'a, 'node> RenderGraphNodeBuilder<'a, 'node> { /// Declares a renderpass that will be written to. Declaring a renderpass /// will prevent access to an encoder in the node. - pub fn add_renderpass(&mut self, targets: RenderPassTargets) -> DeclaredDependency { + pub fn add_renderpass(&mut self, targets: RenderPassTargets, usage: NodeResourceUsage) -> DeclaredDependency { assert!( self.rpass.is_none(), "Cannot have more than one graph-associated renderpass per node." ); for targets in &targets.targets { - self.add_render_target(targets.color, NodeResourceUsage::InputOutput); - self.add_optional_render_target(targets.resolve, NodeResourceUsage::InputOutput); + self.add_render_target(targets.color, usage); + self.add_optional_render_target(targets.resolve, usage); } if let Some(depth_stencil) = &targets.depth_stencil { - self.add_render_target(depth_stencil.target, NodeResourceUsage::InputOutput); + self.add_render_target(depth_stencil.target, usage); } self.rpass = Some(targets); DeclaredDependency { From 0407f9aef623f47a63bd497fdd7ab06062227c82 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 27 Dec 2023 03:06:22 -0500 Subject: [PATCH 7/8] Switch back to 256 workgroup size --- rend3-routine/shaders/src/cull.wgsl | 20 ++++++++++++++++---- rend3-routine/shaders/src/uniform_prep.wgsl | 2 +- rend3-routine/src/culling/mod.rs | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/rend3-routine/shaders/src/cull.wgsl b/rend3-routine/shaders/src/cull.wgsl index 9dc7792a..295090e7 100644 --- a/rend3-routine/shaders/src/cull.wgsl +++ b/rend3-routine/shaders/src/cull.wgsl @@ -179,7 +179,7 @@ struct ObjectSearchResult { } fn find_object_info(wid: u32) -> ObjectSearchResult { - let target_invocation = wid * 64u; + let target_invocation = wid * 256u; // pulled directly from https://doc.rust-lang.org/src/core/slice/mod.rs.html#2412-2438 var size = culling_job.total_objects; @@ -206,13 +206,19 @@ fn find_object_info(wid: u32) -> ObjectSearchResult { return ObjectSearchResult(object_info, 0xFFFFFFFFu); } -// 64 workgroup size / 32 bits -var workgroup_culling_results: array, 2>; +// 256 workgroup size / 32 bits +var workgroup_culling_results: array, 8>; fn clear_culling_results(lid: u32) { if lid == 0u { atomicStore(&workgroup_culling_results[0], 0u); atomicStore(&workgroup_culling_results[1], 0u); + atomicStore(&workgroup_culling_results[2], 0u); + atomicStore(&workgroup_culling_results[3], 0u); + atomicStore(&workgroup_culling_results[4], 0u); + atomicStore(&workgroup_culling_results[5], 0u); + atomicStore(&workgroup_culling_results[6], 0u); + atomicStore(&workgroup_culling_results[7], 0u); } } @@ -225,6 +231,12 @@ fn save_culling_results(global_invocation: u32, lid: u32) { let culling_results_index = culling_results.output_offset + (global_invocation / 32u); culling_results.bits[culling_results_index + 0u] = atomicLoad(&workgroup_culling_results[0]); culling_results.bits[culling_results_index + 1u] = atomicLoad(&workgroup_culling_results[1]); + culling_results.bits[culling_results_index + 2u] = atomicLoad(&workgroup_culling_results[2]); + culling_results.bits[culling_results_index + 3u] = atomicLoad(&workgroup_culling_results[3]); + culling_results.bits[culling_results_index + 4u] = atomicLoad(&workgroup_culling_results[4]); + culling_results.bits[culling_results_index + 5u] = atomicLoad(&workgroup_culling_results[5]); + culling_results.bits[culling_results_index + 6u] = atomicLoad(&workgroup_culling_results[6]); + culling_results.bits[culling_results_index + 7u] = atomicLoad(&workgroup_culling_results[7]); } } @@ -311,7 +323,7 @@ fn execute_culling( return true; } -@compute @workgroup_size(64) +@compute @workgroup_size(256) fn cs_main( @builtin(workgroup_id) wid: vec3, @builtin(global_invocation_id) gid: vec3, diff --git a/rend3-routine/shaders/src/uniform_prep.wgsl b/rend3-routine/shaders/src/uniform_prep.wgsl index 7cc2ae8f..4812e94f 100644 --- a/rend3-routine/shaders/src/uniform_prep.wgsl +++ b/rend3-routine/shaders/src/uniform_prep.wgsl @@ -6,7 +6,7 @@ var object_buffer: array; @group(0) @binding(1) var per_camera_uniform: PerCameraUniform; -@compute @workgroup_size(64) +@compute @workgroup_size(256) fn cs_main( @builtin(global_invocation_id) gid: vec3, ) { diff --git a/rend3-routine/src/culling/mod.rs b/rend3-routine/src/culling/mod.rs index 805aa218..3ff0b355 100644 --- a/rend3-routine/src/culling/mod.rs +++ b/rend3-routine/src/culling/mod.rs @@ -1,5 +1,5 @@ const BATCH_SIZE: usize = 256; -const WORKGROUP_SIZE: u32 = 64; +const WORKGROUP_SIZE: u32 = 256; mod batching; mod culler; From 7f4d89b07e6fe7025a8afe86ea38c488980c6228 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 27 Dec 2023 03:07:19 -0500 Subject: [PATCH 8/8] Format --- rend3/src/graph/node.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rend3/src/graph/node.rs b/rend3/src/graph/node.rs index c4a6c4df..30ab9d3a 100644 --- a/rend3/src/graph/node.rs +++ b/rend3/src/graph/node.rs @@ -97,7 +97,11 @@ impl<'a, 'node> RenderGraphNodeBuilder<'a, 'node> { /// Declares a renderpass that will be written to. Declaring a renderpass /// will prevent access to an encoder in the node. - pub fn add_renderpass(&mut self, targets: RenderPassTargets, usage: NodeResourceUsage) -> DeclaredDependency { + pub fn add_renderpass( + &mut self, + targets: RenderPassTargets, + usage: NodeResourceUsage, + ) -> DeclaredDependency { assert!( self.rpass.is_none(), "Cannot have more than one graph-associated renderpass per node."