Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce wgpu based re_renderer (experimental!) #175

Merged
merged 19 commits into from
Oct 11, 2022
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions crates/re_renderer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "re_renderer"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false

[dependencies]


[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
wgpu = { version = "0.14", default-features = false }

[target.'cfg(target_arch = "wasm32")'.dependencies]
wgpu = { version = "0.14", default-features = false, features = ["webgl"] }
3 changes: 3 additions & 0 deletions crates/re_renderer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The Rerun renderer

A [wgpu](https://github.com/gfx-rs/wgpu/) based renderer for all your visualization needs.
32 changes: 32 additions & 0 deletions crates/re_renderer/shader/test_triangle.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

struct VertexOut {
@location(0) color: vec4<f32>,
@builtin(position) position: vec4<f32>,
Wumpf marked this conversation as resolved.
Show resolved Hide resolved
};

var<private> v_positions: array<vec2<f32>, 3> = array<vec2<f32>, 3>(
vec2<f32>(0.0, 1.0),
vec2<f32>(1.0, -1.0),
vec2<f32>(-1.0, -1.0),
);

var<private> v_colors: array<vec4<f32>, 3> = array<vec4<f32>, 3>(
vec4<f32>(1.0, 0.0, 0.0, 1.0),
vec4<f32>(0.0, 1.0, 0.0, 1.0),
vec4<f32>(0.0, 0.0, 1.0, 1.0),
);

@vertex
fn vs_main(@builtin(vertex_index) v_idx: u32) -> VertexOut {
var out: VertexOut;

out.position = vec4<f32>(v_positions[v_idx], 0.0, 1.0);
out.color = v_colors[v_idx];

return out;
}

@fragment
fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
return in.color;
}
101 changes: 101 additions & 0 deletions crates/re_renderer/src/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/// Any resource involving wgpu rendering which can be re-used accross different scenes.
/// I.e. render pipelines, resource pools, etc.
pub struct RenderContext {
/// The color format used by the eframe output buffer.
output_format_color: wgpu::TextureFormat,
/// The depth format used by the eframe output buffer.
Wumpf marked this conversation as resolved.
Show resolved Hide resolved
/// TODO(andreas): Should we maintain depth buffers per view and ask for no depth from eframe?
output_format_depth: Option<wgpu::TextureFormat>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
output_format_color: wgpu::TextureFormat,
/// The depth format used by the eframe output buffer.
/// TODO(andreas): Should we maintain depth buffers per view and ask for no depth from eframe?
output_format_depth: Option<wgpu::TextureFormat>,
color_output_format: wgpu::TextureFormat,
/// The depth format used by the eframe output buffer.
/// TODO(andreas): Should we maintain depth buffers per view and ask for no depth from eframe?
depth_output_format: Option<wgpu::TextureFormat>,

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

starting with output_format is more autocompletion friendly though ;)


// TODO(andreas): Introduce a pipeline manager
test_triangle: Option<wgpu::RenderPipeline>,
// TODO(andreas): Strongly consider https://docs.rs/slotmap/latest/slotmap/ for resource pools
}

/// Render pipeline handle that needs to be requested from the `RenderContext` and can be resolved to a `wgpu::RenderPipeline` before drawing.
#[derive(Clone, Copy)]
pub(crate) struct RenderPipelineHandle;

impl RenderContext {
pub fn new(
_device: &wgpu::Device,
_queue: &wgpu::Queue,
output_format_color: wgpu::TextureFormat,
output_format_depth: Option<wgpu::TextureFormat>,
) -> Self {
RenderContext {
output_format_color,
output_format_depth,
test_triangle: None,
}
}

/// Requests a render pipeline and returns a handle to it.
///
/// Internally, this ensures the requested pipeline is created and tracked.
/// Returns a handle even if creating the pipeline fails!
/// (this might be due to shader compilation error that might be fixed later)
pub(crate) fn request_render_pipeline(
&mut self,
device: &wgpu::Device,
) -> RenderPipelineHandle {
self.test_triangle.get_or_insert_with(|| {
// TODO(andreas): Standardize bind group and render pipeline layouts so we only ever have a handful.
// (is this feasable?)
// let bind_group_layout =
// device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
// label: Some("custom3d"),
// entries: &[],
// });
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("custom3d"),
bind_group_layouts: &[],
push_constant_ranges: &[],
});
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("custom3d"),
source: wgpu::ShaderSource::Wgsl(
include_str!("../shader/test_triangle.wgsl").into(),
),
});
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("test triangle"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[Some(self.output_format_color.into())],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: self
.output_format_depth
.map(|format| wgpu::DepthStencilState {
format,
depth_compare: wgpu::CompareFunction::Always,
depth_write_enabled: false,
stencil: Default::default(),
bias: Default::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview: None,
})
});

RenderPipelineHandle
}

/// Retrieves a `wgpu::RenderPipeline` given a handle.
Wumpf marked this conversation as resolved.
Show resolved Hide resolved
/// Returns None if the pipeline does not exist or failed to create.
pub(crate) fn render_pipeline(
&self,
_handle: RenderPipelineHandle,
) -> Option<&wgpu::RenderPipeline> {
// TODO(andreas)render_context
self.test_triangle.as_ref()
}
}
53 changes: 53 additions & 0 deletions crates/re_renderer/src/frame_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::sync::{Arc, RwLock};
Wumpf marked this conversation as resolved.
Show resolved Hide resolved

use crate::context::{RenderContext, RenderPipelineHandle};

/// Mirrors the GPU contents of a frame-global uniform buffer.
/// Contains information that is constant for a single frame like camera.
/// (does not contain information that is special to a particular renderer or global to the Context)
//struct FrameUniformBuffer {
// TODO(andreas): camera matrix and the like.
// What does not go here are even more global things like
Wumpf marked this conversation as resolved.
Show resolved Hide resolved
//}

/// The highest level rendering block in `re_renderer`.
///
/// They are used to build up/collect various resources and then send them off for rendering.
/// Collecting objects in this fashion allows for re-use of common resources (e.g. camera)
#[derive(Default)]
pub struct FrameBuilder {
render_pipeline: Option<RenderPipelineHandle>,
}

pub type SharedFrameBuilder = Arc<RwLock<FrameBuilder>>;

impl FrameBuilder {
pub fn new() -> Self {
FrameBuilder {
render_pipeline: None,
}
}

pub fn new_shared() -> SharedFrameBuilder {
Arc::new(RwLock::new(FrameBuilder::new()))
}

pub fn test_triangle(&mut self, ctx: &mut RenderContext, device: &wgpu::Device) -> &mut Self {
self.render_pipeline = Some(ctx.request_render_pipeline(device));
self
}

/// Draws the final result of a `FrameBuilder` to a given output `RenderPass`
///
/// The bound surface(s) on the `RenderPass` are expected to be the same format as specified on `Context` creation.
pub fn draw<'a>(&self, ctx: &'a RenderContext, pass: &mut wgpu::RenderPass<'a>) {
if let Some(handle) = self.render_pipeline {
let render_pipeline = ctx.render_pipeline(handle);

if let Some(render_pipeline) = render_pipeline {
pass.set_pipeline(render_pipeline);
pass.draw(0..3, 0..1);
}
}
}
}
7 changes: 7 additions & 0 deletions crates/re_renderer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! Rerun's renderer.
//!
//! A wgpu based renderer [wgpu](https://github.com/gfx-rs/wgpu/) for all your visualization needs.
//! Used in `re_runner` to display the contents of any view contents other than pure UI.

pub mod context;
pub mod frame_builder;
6 changes: 3 additions & 3 deletions crates/re_viewer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ glow = [
]

## Enable the [`wgpu`](https://crates.io/crates/wgpu) renderer.
wgpu = ["eframe/wgpu", "dep:egui-wgpu", "dep:wgpu"]
wgpu = ["eframe/wgpu", "dep:egui-wgpu", "dep:re_renderer", "dep:wgpu"]


[dependencies]
Expand All @@ -45,6 +45,7 @@ re_log_types = { path = "../re_log_types", features = ["save", "load"] }
re_string_interner = { path = "../re_string_interner" }
re_tensor_ops = { path = "../re_tensor_ops" }
re_ws_comms = { path = "../re_ws_comms", features = ["client"] }
re_renderer = { path = "../re_renderer", optional = true }

eframe = { version = "0.19", default-features = false, features = [
"default_fonts",
Expand All @@ -53,7 +54,6 @@ eframe = { version = "0.19", default-features = false, features = [
egui = { version = "0.19", features = ["extra_debug_asserts", "tracing"] }
egui_extras = { version = "0.19", features = ["tracing"] }


ahash = "0.8"
anyhow = "1.0"
bytemuck = { version = "1.11", features = ["extern_crate_alloc"] }
Expand Down Expand Up @@ -96,7 +96,7 @@ three-d-asset = { version = "0.3.0", optional = true, default-features = false,
] }

egui-wgpu = { version = "0.19", optional = true }
wgpu = { version = "0.14", optional = true, features = ["webgl"] }
wgpu = { version = "0.14", optional = true }


# native dependencies:
Expand Down
3 changes: 1 addition & 2 deletions crates/re_viewer/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use std::sync::mpsc::Receiver;

use crate::misc::{Caches, Options, RecordingConfig, ViewerContext};
use egui_extras::RetainedImage;
use itertools::Itertools as _;
use nohash_hasher::IntMap;
use re_data_store::log_db::LogDb;
use re_log_types::*;

use crate::misc::{Caches, Options, RecordingConfig, ViewerContext};

const WATERMARK: bool = false; // Nice for recording media material

// ----------------------------------------------------------------------------
Expand Down
29 changes: 27 additions & 2 deletions crates/re_viewer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ pub(crate) use misc::*;
pub(crate) use ui::*;

pub use app::App;
#[cfg(feature = "wgpu")]
use re_renderer::context::RenderContext;
pub use remote_viewer_app::RemoteViewerApp;
Wumpf marked this conversation as resolved.
Show resolved Hide resolved

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -63,6 +65,29 @@ macro_rules! profile_scope {

// ---------------------------------------------------------------------------

pub(crate) fn customize_egui(ctx: &egui::Context) {
design_tokens::apply_design_tokens(ctx);
pub(crate) fn customize_eframe(cc: &eframe::CreationContext<'_>) {
#[cfg(feature = "wgpu")]
{
let render_state = cc.wgpu_render_state.as_ref().unwrap();
let paint_callback_resources = &mut render_state.renderer.write().paint_callback_resources;

// TODO(andreas): Query used surface format from eframe/renderer.
#[cfg(target_arch = "wasm32")]
let (output_format_color, output_format_depth) =
(wgpu::TextureFormat::Rgba8UnormSrgb, None); // TODO(andreas) fix for not using srgb is in flight!
Wumpf marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(not(target_arch = "wasm32"))]
let (output_format_color, output_format_depth) = (
wgpu::TextureFormat::Bgra8Unorm,
Some(wgpu::TextureFormat::Depth32Float),
);

paint_callback_resources.insert(RenderContext::new(
&render_state.device,
&render_state.queue,
output_format_color,
output_format_depth,
));
}

design_tokens::apply_design_tokens(&cc.egui_ctx);
}
2 changes: 0 additions & 2 deletions crates/re_viewer/src/misc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ pub fn calc_bbox_2d(objects: &re_data_store::Objects<'_>) -> emath::Rect {
bbox
}

#[cfg(feature = "glow")]
pub fn calc_bbox_3d(objects: &re_data_store::Objects<'_>) -> macaw::BoundingBox {
crate::profile_function!();

Expand Down Expand Up @@ -163,7 +162,6 @@ pub fn calc_bbox_3d(objects: &re_data_store::Objects<'_>) -> macaw::BoundingBox

// ----------------------------------------------------------------------------

#[cfg(feature = "glow")]
pub mod cam {
use glam::*;
use macaw::Ray3;
Expand Down
2 changes: 1 addition & 1 deletion crates/re_viewer/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn run_native_app(app_creator: eframe::AppCreator) {
"Rerun Viewer",
native_options,
Box::new(move |cc| {
crate::customize_egui(&cc.egui_ctx);
crate::customize_eframe(cc);
app_creator(cc)
}),
);
Expand Down
1 change: 0 additions & 1 deletion crates/re_viewer/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ pub(crate) mod selection_panel;
pub(crate) mod text_entry_view;
pub(crate) mod time_panel;
pub(crate) mod view2d;
#[cfg(feature = "glow")]
pub(crate) mod view3d;
pub(crate) mod view_tensor;
pub(crate) mod viewport_panel;
Expand Down
Loading