Skip to content

Commit

Permalink
[re_renderer] Introduce DrawPhasees for simpl(istic) multi pass ren…
Browse files Browse the repository at this point in the history
…dering

Or rather as a first and super easy step towards it. Also takes the first step towards supporting transparency, see #702
Replaces previous sorting key!

Very simple idea: Every `Renderer` is invoked with every `DrawPhase` it registered for.
`DrawPhase` have a strict order and implicitly describe the `wgpu::RenderPass` that is passed for drawing.

For now and forseeable future, these passes are managed by the ViewBuilder (unchanged!).
At some point we will probably make `DrawPhase` a more complex object, but this is not today!
  • Loading branch information
Wumpf committed Feb 27, 2023
1 parent c31906a commit a2fc17b
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 65 deletions.
7 changes: 6 additions & 1 deletion crates/re_renderer/src/renderer/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
},
};

use super::{DrawData, FileResolver, FileSystem, RenderContext, Renderer};
use super::{DrawData, DrawPhase, FileResolver, FileSystem, RenderContext, Renderer};

use smallvec::smallvec;

Expand Down Expand Up @@ -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<()> {
Expand All @@ -141,4 +142,8 @@ impl Renderer for Compositor {

Ok(())
}

fn participated_phases() -> &'static [DrawPhase] {
&[DrawPhase::Composition]
}
}
7 changes: 4 additions & 3 deletions crates/re_renderer/src/renderer/generic_skybox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Expand Down Expand Up @@ -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<()> {
Expand All @@ -118,7 +119,7 @@ impl Renderer for GenericSkybox {
Ok(())
}

fn draw_order() -> u32 {
DrawOrder::Background as u32
fn participated_phases() -> &'static [DrawPhase] {
&[DrawPhase::Background]
}
}
5 changes: 3 additions & 2 deletions crates/re_renderer/src/renderer/lines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<()> {
Expand Down
3 changes: 2 additions & 1 deletion crates/re_renderer/src/renderer/mesh_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{
};

use super::{
DrawData, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData,
DrawData, DrawPhase, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData,
WgpuResourcePools,
};

Expand Down Expand Up @@ -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<()> {
Expand Down
47 changes: 19 additions & 28 deletions crates/re_renderer/src/renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<RendererDrawData = Self>;
type Renderer: Renderer<RendererDrawData = Self> + Send + Sync;
}

/// A Renderer encapsulate the knowledge of how to render a certain kind of primitives.
Expand All @@ -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)]
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.
Composition,
}
3 changes: 2 additions & 1 deletion crates/re_renderer/src/renderer/point_cloud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use crate::{
};

use super::{
DrawData, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData,
DrawData, DrawPhase, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData,
WgpuResourcePools,
};

Expand Down Expand Up @@ -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<()> {
Expand Down
10 changes: 6 additions & 4 deletions crates/re_renderer/src/renderer/rectangles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::{
};

use super::{
DrawData, DrawOrder, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData,
DrawData, DrawPhase, FileResolver, FileSystem, RenderContext, Renderer, SharedRendererData,
WgpuResourcePools,
};

Expand Down Expand Up @@ -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,
})],
Expand 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,
},
Expand All @@ -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<()> {
Expand All @@ -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]
}
}
1 change: 1 addition & 0 deletions crates/re_renderer/src/renderer/test_triangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<()> {
Expand Down
51 changes: 26 additions & 25 deletions crates/re_renderer/src/view_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<()>
Expand All @@ -25,7 +23,7 @@ type DrawFn = dyn for<'a, 'b> Fn(
struct QueuedDraw {
draw_func: Box<DrawFn>,
draw_data: Box<dyn std::any::Any + std::marker::Send + std::marker::Sync>,
sorting_index: u32,
participated_phases: &'static [DrawPhase],
}

/// The highest level rendering block in `re_renderer`.
Expand All @@ -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<ViewTargetSetup>,
queued_draws: Vec<QueuedDraw>, // &mut wgpu::RenderPass
queued_draws: Vec<QueuedDraw>,
}

struct ViewTargetSetup {
name: DebugLabel,

compositor_draw_data: CompositorDrawData,

bind_group_0: GpuBindGroup,
main_target_msaa: GpuTexture,
main_target_resolved: GpuTexture,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -423,25 +418,39 @@ 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())
.context("drawing a view")?;
}
}
Ok(())
}

pub fn queue_draw<D: DrawData + Sync + Send + Clone + 'static>(
&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::<D::Renderer>()
.context("failed to retrieve renderer")?;
let draw_data = draw_data
.downcast_ref::<D>()
.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
Expand Down Expand Up @@ -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)?;
}
}

Expand Down Expand Up @@ -538,11 +544,6 @@ impl ViewBuilder {
);

pass.set_bind_group(0, &setup.bind_group_0, &[]);

let renderers = ctx.renderers.read();
let tonemapper = renderers.get::<Compositor>().context("get compositor")?;
tonemapper
.draw(&ctx.gpu_resources, pass, &setup.compositor_draw_data)
.context("composite into main view")
self.draw_phase(ctx, DrawPhase::Composition, pass)
}
}

0 comments on commit a2fc17b

Please sign in to comment.