diff --git a/crates/re_renderer/src/renderer/compositor.rs b/crates/re_renderer/src/renderer/compositor.rs index 187ba68b05ed..76adf6547c60 100644 --- a/crates/re_renderer/src/renderer/compositor.rs +++ b/crates/re_renderer/src/renderer/compositor.rs @@ -8,7 +8,7 @@ use crate::{ }, }; -use super::{DrawData, FileResolver, FileSystem, RenderContext, Renderer}; +use super::{DrawData, DrawPhase, FileResolver, FileSystem, RenderContext, Renderer}; use smallvec::smallvec; @@ -130,6 +130,7 @@ impl Renderer for Compositor { fn draw<'a>( &self, pools: &'a WgpuResourcePools, + _phase: DrawPhase, pass: &mut wgpu::RenderPass<'a>, draw_data: &'a CompositorDrawData, ) -> anyhow::Result<()> { @@ -141,4 +142,8 @@ impl Renderer for Compositor { Ok(()) } + + fn participated_phases() -> &'static [DrawPhase] { + &[DrawPhase::Compositing] + } } diff --git a/crates/re_renderer/src/renderer/generic_skybox.rs b/crates/re_renderer/src/renderer/generic_skybox.rs index 1e84152f8fbf..34f4ba8e9fc7 100644 --- a/crates/re_renderer/src/renderer/generic_skybox.rs +++ b/crates/re_renderer/src/renderer/generic_skybox.rs @@ -10,7 +10,7 @@ use crate::{ }, }; -use super::{DrawData, DrawOrder, FileResolver, FileSystem, RenderContext, Renderer}; +use super::{DrawData, DrawPhase, FileResolver, FileSystem, RenderContext, Renderer}; /// Renders a generated skybox from a color gradient /// @@ -105,6 +105,7 @@ impl Renderer for GenericSkybox { fn draw<'a>( &self, pools: &'a WgpuResourcePools, + _phase: DrawPhase, pass: &mut wgpu::RenderPass<'a>, _draw_data: &GenericSkyboxDrawData, ) -> anyhow::Result<()> { @@ -118,7 +119,7 @@ impl Renderer for GenericSkybox { Ok(()) } - fn draw_order() -> u32 { - DrawOrder::Background as u32 + fn participated_phases() -> &'static [DrawPhase] { + &[DrawPhase::Background] } } diff --git a/crates/re_renderer/src/renderer/lines.rs b/crates/re_renderer/src/renderer/lines.rs index 29dc902da0c9..aba67f19e5d1 100644 --- a/crates/re_renderer/src/renderer/lines.rs +++ b/crates/re_renderer/src/renderer/lines.rs @@ -127,8 +127,8 @@ use crate::{ }; use super::{ - DrawData, FileResolver, FileSystem, LineVertex, RenderContext, Renderer, SharedRendererData, - WgpuResourcePools, + DrawData, DrawPhase, FileResolver, FileSystem, LineVertex, RenderContext, Renderer, + SharedRendererData, WgpuResourcePools, }; pub mod gpu_data { @@ -673,6 +673,7 @@ impl Renderer for LineRenderer { fn draw<'a>( &self, pools: &'a WgpuResourcePools, + _phase: DrawPhase, pass: &mut wgpu::RenderPass<'a>, draw_data: &'a Self::RendererDrawData, ) -> anyhow::Result<()> { diff --git a/crates/re_renderer/src/renderer/mesh_renderer.rs b/crates/re_renderer/src/renderer/mesh_renderer.rs index eb84b97976e3..0908aabfd707 100644 --- a/crates/re_renderer/src/renderer/mesh_renderer.rs +++ b/crates/re_renderer/src/renderer/mesh_renderer.rs @@ -21,7 +21,7 @@ use crate::{ }; use super::{ - DrawData, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData, + DrawData, DrawPhase, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData, WgpuResourcePools, }; @@ -322,6 +322,7 @@ impl Renderer for MeshRenderer { fn draw<'a>( &self, pools: &'a WgpuResourcePools, + _phase: DrawPhase, pass: &mut wgpu::RenderPass<'a>, draw_data: &'a Self::RendererDrawData, ) -> anyhow::Result<()> { diff --git a/crates/re_renderer/src/renderer/mod.rs b/crates/re_renderer/src/renderer/mod.rs index 5ea2336c9b0e..0189b26d8e15 100644 --- a/crates/re_renderer/src/renderer/mod.rs +++ b/crates/re_renderer/src/renderer/mod.rs @@ -30,10 +30,10 @@ use crate::{ /// GPU sided data used by a [`Renderer`] to draw things to the screen. /// -/// Valid only for the frame in which it was created (typically uses temp allocations!) +/// Valid only for the frame in which it was created (typically uses temp allocations!). /// TODO(andreas): Add a mechanism to validate this. pub trait DrawData { - type Renderer: Renderer; + type Renderer: Renderer + Send + Sync; } /// A Renderer encapsulate the knowledge of how to render a certain kind of primitives. @@ -52,45 +52,36 @@ pub trait Renderer { ) -> Self; // TODO(andreas): Some Renderers need to create their own passes, need something like this for that. - // TODO(andreas): The harder part is that some of those might need to share them with others! - // E.g. Shadow Mapping! Conceivable that there are special traits for those (distinguish "ShadowMappingAwareRenderer") - // fn record_custom_passes<'a>( - // &self, - // pools: &'a WgpuResourcePools, - // pass: &mut wgpu::CommandEncoder, - // draw_data: &'a Self::DrawData, - // ) -> anyhow::Result<()> { - // } + /// Called once per phase given by [`Renderer::participated_phases`]. fn draw<'a>( &self, pools: &'a WgpuResourcePools, + phase: DrawPhase, pass: &mut wgpu::RenderPass<'a>, draw_data: &'a Self::RendererDrawData, ) -> anyhow::Result<()>; - /// Relative location in the rendering process when this renderer should be executed. - /// TODO(andreas): We might want to take [`DrawData`] into account for this. - /// But this touches on the [`Renderer::draw`] method might be split in the future, which haven't designed yet. - fn draw_order() -> u32 { - DrawOrder::Opaque as u32 + /// Combination of flags indicating in which phases [`Renderer::draw`] should be called. + fn participated_phases() -> &'static [DrawPhase] { + &[DrawPhase::Opaque] } } -/// Assigns rough meaning to draw sorting indices -#[allow(dead_code)] -#[repr(u32)] -enum DrawOrder { +/// Determines a (very rough) order of rendering and describes the active [`wgpu::RenderPass`]. +/// +/// Currently we do not support sorting *within* a rendering phase! +/// See [#702](https://github.com/rerun-io/rerun/issues/702) +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] +pub enum DrawPhase { /// Opaque objects, performing reads/writes to the depth buffer. + /// /// Typically they are order independent, so everything uses this same index. - Opaque = 30000, - - /// Transparent objects. Each draw typically gets its own sorting index. - Transparent = 50000, + Opaque, - /// Backgrounds should always be rendered last. - Background = 70000, + /// Background, rendering where depth wasn't written. + Background, - /// Postprocessing effects that are applied before the final tonemapping step. - Postprocess = 90000, + /// Drawn when compositing with the main target. + Compositing, } diff --git a/crates/re_renderer/src/renderer/point_cloud.rs b/crates/re_renderer/src/renderer/point_cloud.rs index 70bfbbb69045..618efdce3225 100644 --- a/crates/re_renderer/src/renderer/point_cloud.rs +++ b/crates/re_renderer/src/renderer/point_cloud.rs @@ -36,7 +36,7 @@ use crate::{ }; use super::{ - DrawData, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData, + DrawData, DrawPhase, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData, WgpuResourcePools, }; @@ -495,6 +495,7 @@ impl Renderer for PointCloudRenderer { fn draw<'a>( &self, pools: &'a WgpuResourcePools, + _phase: DrawPhase, pass: &mut wgpu::RenderPass<'a>, draw_data: &'a Self::RendererDrawData, ) -> anyhow::Result<()> { diff --git a/crates/re_renderer/src/renderer/rectangles.rs b/crates/re_renderer/src/renderer/rectangles.rs index 2a6d019bb263..ce2c3ffc6ac2 100644 --- a/crates/re_renderer/src/renderer/rectangles.rs +++ b/crates/re_renderer/src/renderer/rectangles.rs @@ -27,7 +27,7 @@ use crate::{ }; use super::{ - DrawData, DrawOrder, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData, + DrawData, DrawPhase, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData, WgpuResourcePools, }; @@ -280,6 +280,7 @@ impl Renderer for RectangleRenderer { vertex_buffers: smallvec![], render_targets: smallvec![Some(wgpu::ColorTargetState { format: ViewBuilder::MAIN_TARGET_COLOR_FORMAT, + // TODO(andreas): have two render pipelines, an opaque one and a transparent one. Transparent shouldn't write depth! blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, })], @@ -288,7 +289,6 @@ impl Renderer for RectangleRenderer { cull_mode: None, ..Default::default() }, - // We're rendering with transparency, so disable depth write. depth_stencil: ViewBuilder::MAIN_TARGET_DEFAULT_DEPTH_STATE, multisample: ViewBuilder::MAIN_TARGET_DEFAULT_MSAA_STATE, }, @@ -305,6 +305,7 @@ impl Renderer for RectangleRenderer { fn draw<'a>( &self, pools: &'a WgpuResourcePools, + _phase: DrawPhase, pass: &mut wgpu::RenderPass<'a>, draw_data: &'a Self::RendererDrawData, ) -> anyhow::Result<()> { @@ -324,7 +325,8 @@ impl Renderer for RectangleRenderer { Ok(()) } - fn draw_order() -> u32 { - DrawOrder::Transparent as u32 + fn participated_phases() -> &'static [DrawPhase] { + // TODO(andreas): This a hack. We have both opaque and transparent. + &[DrawPhase::Opaque] } } diff --git a/crates/re_renderer/src/renderer/test_triangle.rs b/crates/re_renderer/src/renderer/test_triangle.rs index 2b5a627080e3..e752995110ef 100644 --- a/crates/re_renderer/src/renderer/test_triangle.rs +++ b/crates/re_renderer/src/renderer/test_triangle.rs @@ -96,6 +96,7 @@ impl Renderer for TestTriangle { fn draw<'a>( &self, pools: &'a WgpuResourcePools, + _phase: DrawPhase, pass: &mut wgpu::RenderPass<'a>, _draw_data: &TestTriangleDrawData, ) -> anyhow::Result<()> { diff --git a/crates/re_renderer/src/view_builder.rs b/crates/re_renderer/src/view_builder.rs index defdeb80f770..42c10bf0b13b 100644 --- a/crates/re_renderer/src/view_builder.rs +++ b/crates/re_renderer/src/view_builder.rs @@ -6,16 +6,14 @@ use crate::{ allocator::create_and_fill_uniform_buffer, context::RenderContext, global_bindings::FrameUniformBuffer, - renderer::{ - compositor::{Compositor, CompositorDrawData}, - DrawData, Renderer, - }, + renderer::{compositor::CompositorDrawData, DrawData, DrawPhase, Renderer}, wgpu_resources::{GpuBindGroup, GpuTexture, TextureDesc}, DebugLabel, Rgba, Size, }; type DrawFn = dyn for<'a, 'b> Fn( &'b RenderContext, + DrawPhase, &'a mut wgpu::RenderPass<'b>, &'b dyn std::any::Any, ) -> anyhow::Result<()> @@ -25,7 +23,7 @@ type DrawFn = dyn for<'a, 'b> Fn( struct QueuedDraw { draw_func: Box, draw_data: Box, - sorting_index: u32, + participated_phases: &'static [DrawPhase], } /// The highest level rendering block in `re_renderer`. @@ -34,14 +32,12 @@ struct QueuedDraw { pub struct ViewBuilder { /// Result of [`ViewBuilder::setup_view`] - needs to be `Option` sine some of the fields don't have a default. setup: Option, - queued_draws: Vec, // &mut wgpu::RenderPass + queued_draws: Vec, } struct ViewTargetSetup { name: DebugLabel, - compositor_draw_data: CompositorDrawData, - bind_group_0: GpuBindGroup, main_target_msaa: GpuTexture, main_target_resolved: GpuTexture, @@ -267,7 +263,7 @@ impl ViewBuilder { }, ); - let tonemapping_draw_data = CompositorDrawData::new(ctx, &main_target_resolved); + self.queue_draw(&CompositorDrawData::new(ctx, &main_target_resolved)); let aspect_ratio = config.resolution_in_pixel[0] as f32 / config.resolution_in_pixel[1] as f32; @@ -412,7 +408,6 @@ impl ViewBuilder { self.setup = Some(ViewTargetSetup { name: config.name, - compositor_draw_data: tonemapping_draw_data, bind_group_0, main_target_msaa: hdr_render_target_msaa, main_target_resolved, @@ -423,14 +418,28 @@ impl ViewBuilder { Ok(self) } + fn draw_phase<'a>( + &'a self, + ctx: &'a RenderContext, + phase: DrawPhase, + pass: &mut wgpu::RenderPass<'a>, + ) -> Result<(), anyhow::Error> { + for queued_draw in &self.queued_draws { + if queued_draw.participated_phases.contains(&phase) { + (queued_draw.draw_func)(ctx, phase, pass, queued_draw.draw_data.as_ref()) + .with_context(|| format!("Draw call during phase {phase:?}"))?; + } + } + Ok(()) + } + pub fn queue_draw( &mut self, draw_data: &D, ) -> &mut Self { crate::profile_function!(); - self.queued_draws.push(QueuedDraw { - draw_func: Box::new(move |ctx, pass, draw_data| { + draw_func: Box::new(move |ctx, phase, pass, draw_data| { let renderers = ctx.renderers.read(); let renderer = renderers .get::() @@ -438,10 +447,10 @@ impl ViewBuilder { let draw_data = draw_data .downcast_ref::() .expect("passed wrong type of draw data"); - renderer.draw(&ctx.gpu_resources, pass, draw_data) + renderer.draw(&ctx.gpu_resources, phase, pass, draw_data) }), draw_data: Box::new(draw_data.clone()), - sorting_index: D::Renderer::draw_order(), + participated_phases: D::Renderer::participated_phases(), }); self @@ -500,11 +509,8 @@ impl ViewBuilder { pass.set_bind_group(0, &setup.bind_group_0, &[]); - self.queued_draws - .sort_by(|a, b| a.sorting_index.cmp(&b.sorting_index)); - for queued_draw in &self.queued_draws { - (queued_draw.draw_func)(ctx, &mut pass, queued_draw.draw_data.as_ref()) - .context("drawing a view")?; + for phase in [DrawPhase::Opaque, DrawPhase::Background] { + self.draw_phase(ctx, phase, &mut pass)?; } } @@ -538,11 +544,6 @@ impl ViewBuilder { ); pass.set_bind_group(0, &setup.bind_group_0, &[]); - - let renderers = ctx.renderers.read(); - let tonemapper = renderers.get::().context("get compositor")?; - tonemapper - .draw(&ctx.gpu_resources, pass, &setup.compositor_draw_data) - .context("composite into main view") + self.draw_phase(ctx, DrawPhase::Compositing, pass) } }