Skip to content

Commit

Permalink
Make draw data creation no longer require a mutable re_renderer conte…
Browse files Browse the repository at this point in the history
…xt (#4422)

### What

* Prerequisite for #1325
* Follow-up of #4421
* Followed by #4430

Make draw data (this is in essence resource submission to GPU! e.g. make
pointcloud ready to render) an operation that doesn't require a mutable
renderer context.

Two pieces to this:
* `FileResolver` resolve needs to be non-mut, this turned out to be
trivial
* `Renderer::get_or_create` had to be streamlined. Renderer creation is
now done directly on the context and holding a renderer implies holding
a read lock. Since Renderers are added **very** rarely, this isn't much
of a limitation!

This causes a large trickle of removing `&mut` and gets us _almost_ to
having a non-mutable render context reference on the Viewer context!

### Checklist
* [x] I have read and agree to [Contributor
Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and
the [Code of
Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md)
* [x] I've included a screenshot or gif (if applicable)
* [x] I have tested the web demo (if applicable):
  * Full build: [app.rerun.io](https://app.rerun.io/pr/4422/index.html)
* Partial build:
[app.rerun.io](https://app.rerun.io/pr/4422/index.html?manifest_url=https://app.rerun.io/version
* [x] The PR title and labels are set such as to maximize their
usefulness for the next release's CHANGELOG

- [PR Build Summary](https://build.rerun.io/pr/4422)
- [Docs
preview](https://rerun.io/preview/5a1ad48f35f4cd28bb4dc4cd56f56ac289a50ab3/docs)
<!--DOCS-PREVIEW-->
- [Examples
preview](https://rerun.io/preview/5a1ad48f35f4cd28bb4dc4cd56f56ac289a50ab3/examples)
<!--EXAMPLES-PREVIEW-->
- [Recent benchmark results](https://build.rerun.io/graphs/crates.html)
- [Wasm size tracking](https://build.rerun.io/graphs/sizes.html)

---
Part of series towards more multithreading in the viewer!
* #4387
* #4404
* #4389
* #4421
* You are here ➡️ #4422
* #4430
  • Loading branch information
Wumpf authored Dec 5, 2023
1 parent c59377d commit eab8244
Show file tree
Hide file tree
Showing 28 changed files with 130 additions and 167 deletions.
4 changes: 2 additions & 2 deletions crates/re_renderer/examples/2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl framework::Example for Render2D {
"2D Rendering"
}

fn new(re_ctx: &mut re_renderer::RenderContext) -> Self {
fn new(re_ctx: &re_renderer::RenderContext) -> Self {
let rerun_logo =
image::load_from_memory(include_bytes!("../../re_ui/data/logo_dark_mode.png")).unwrap();

Expand Down Expand Up @@ -53,7 +53,7 @@ impl framework::Example for Render2D {

fn draw(
&mut self,
re_ctx: &mut re_renderer::RenderContext,
re_ctx: &re_renderer::RenderContext,
resolution: [u32; 2],
time: &framework::Time,
pixels_from_point: f32,
Expand Down
8 changes: 4 additions & 4 deletions crates/re_renderer/examples/depth_cloud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl RenderDepthClouds {
/// Manually backproject the depth texture into a point cloud and render it.
fn draw_backprojected_point_cloud<FD, ID>(
&mut self,
re_ctx: &mut re_renderer::RenderContext,
re_ctx: &re_renderer::RenderContext,
pixels_from_point: f32,
resolution_in_pixel: [u32; 2],
target_location: glam::Vec2,
Expand Down Expand Up @@ -143,7 +143,7 @@ impl RenderDepthClouds {
/// Pass the depth texture to our native depth cloud renderer.
fn draw_depth_cloud<FD, ID>(
&mut self,
re_ctx: &mut re_renderer::RenderContext,
re_ctx: &re_renderer::RenderContext,
pixels_from_point: f32,
resolution_in_pixel: [u32; 2],
target_location: glam::Vec2,
Expand Down Expand Up @@ -226,7 +226,7 @@ impl framework::Example for RenderDepthClouds {
"Depth clouds"
}

fn new(re_ctx: &mut re_renderer::RenderContext) -> Self {
fn new(re_ctx: &re_renderer::RenderContext) -> Self {
re_log::info!("Stop camera movement by pressing 'Space'");

let depth = DepthTexture::spiral(re_ctx, glam::uvec2(640, 480));
Expand Down Expand Up @@ -260,7 +260,7 @@ impl framework::Example for RenderDepthClouds {

fn draw(
&mut self,
re_ctx: &mut re_renderer::RenderContext,
re_ctx: &re_renderer::RenderContext,
resolution: [u32; 2],
time: &framework::Time,
pixels_from_point: f32,
Expand Down
4 changes: 2 additions & 2 deletions crates/re_renderer/examples/depth_offset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl framework::Example for Render2D {
"Depth Offset"
}

fn new(_re_ctx: &mut re_renderer::RenderContext) -> Self {
fn new(_re_ctx: &re_renderer::RenderContext) -> Self {
Render2D {
distance_scale: 100.0,
near_plane: 0.1,
Expand All @@ -34,7 +34,7 @@ impl framework::Example for Render2D {

fn draw(
&mut self,
re_ctx: &mut re_renderer::RenderContext,
re_ctx: &re_renderer::RenderContext,
resolution: [u32; 2],
_time: &framework::Time,
pixels_from_point: f32,
Expand Down
10 changes: 5 additions & 5 deletions crates/re_renderer/examples/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ pub struct ViewDrawResult {
pub trait Example {
fn title() -> &'static str;

fn new(re_ctx: &mut RenderContext) -> Self;
fn new(re_ctx: &RenderContext) -> Self;

fn draw(
&mut self,
re_ctx: &mut RenderContext,
re_ctx: &RenderContext,
resolution: [u32; 2],
time: &Time,
pixels_from_point: f32,
Expand Down Expand Up @@ -160,7 +160,7 @@ impl<E: Example + 'static> Application<E> {
};
surface.configure(&device, &surface_config);

let mut re_ctx = RenderContext::new(
let re_ctx = RenderContext::new(
&adapter,
device,
queue,
Expand All @@ -170,7 +170,7 @@ impl<E: Example + 'static> Application<E> {
},
);

let example = E::new(&mut re_ctx);
let example = E::new(&re_ctx);

Ok(Self {
event_loop,
Expand Down Expand Up @@ -263,7 +263,7 @@ impl<E: Example + 'static> Application<E> {
.create_view(&wgpu::TextureViewDescriptor::default());

let draw_results = self.example.draw(
&mut self.re_ctx,
&self.re_ctx,
[self.surface_config.width, self.surface_config.height],
&self.time,
self.window.scale_factor() as f32,
Expand Down
10 changes: 5 additions & 5 deletions crates/re_renderer/examples/multiview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use winit::event::{ElementState, VirtualKeyCode};
mod framework;

fn build_mesh_instances(
re_ctx: &mut RenderContext,
re_ctx: &RenderContext,
model_mesh_instances: &[MeshInstance],
mesh_instance_positions_and_colors: &[(glam::Vec3, Color32)],
seconds_since_startup: f32,
Expand Down Expand Up @@ -80,7 +80,7 @@ fn lorenz_points(seconds_since_startup: f32) -> Vec<glam::Vec3> {
.collect()
}

fn build_lines(re_ctx: &mut RenderContext, seconds_since_startup: f32) -> LineDrawData {
fn build_lines(re_ctx: &RenderContext, seconds_since_startup: f32) -> LineDrawData {
// Calculate some points that look nice for an animated line.
let lorenz_points = lorenz_points(seconds_since_startup);

Expand Down Expand Up @@ -211,7 +211,7 @@ fn handle_incoming_screenshots(re_ctx: &RenderContext) {
impl Multiview {
fn draw_view<D: 'static + re_renderer::renderer::DrawData + Sync + Send + Clone>(
&mut self,
re_ctx: &mut RenderContext,
re_ctx: &RenderContext,
target_cfg: TargetConfiguration,
skybox: GenericSkyboxDrawData,
draw_data: D,
Expand Down Expand Up @@ -244,7 +244,7 @@ impl Example for Multiview {
"Multiple Views"
}

fn new(re_ctx: &mut RenderContext) -> Self {
fn new(re_ctx: &RenderContext) -> Self {
re_log::info!("Switch between orthographic & perspective by pressing 'O'");
re_log::info!("Stop camera movement by pressing 'Space'");

Expand Down Expand Up @@ -298,7 +298,7 @@ impl Example for Multiview {

fn draw(
&mut self,
re_ctx: &mut RenderContext,
re_ctx: &RenderContext,
resolution: [u32; 2],
time: &framework::Time,
pixels_from_point: f32,
Expand Down
4 changes: 2 additions & 2 deletions crates/re_renderer/examples/outlines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl framework::Example for Outlines {
"Outlines"
}

fn new(re_ctx: &mut re_renderer::RenderContext) -> Self {
fn new(re_ctx: &re_renderer::RenderContext) -> Self {
Outlines {
is_paused: false,
seconds_since_startup: 0.0,
Expand All @@ -35,7 +35,7 @@ impl framework::Example for Outlines {

fn draw(
&mut self,
re_ctx: &mut re_renderer::RenderContext,
re_ctx: &re_renderer::RenderContext,
resolution: [u32; 2],
time: &framework::Time,
pixels_from_point: f32,
Expand Down
4 changes: 2 additions & 2 deletions crates/re_renderer/examples/picking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl framework::Example for Picking {
self.picking_position = position_in_pixel;
}

fn new(re_ctx: &mut re_renderer::RenderContext) -> Self {
fn new(re_ctx: &re_renderer::RenderContext) -> Self {
let mut rnd = <rand::rngs::StdRng as rand::SeedableRng>::seed_from_u64(42);
let random_point_range = -5.0_f32..5.0_f32;
let point_count = 1000;
Expand Down Expand Up @@ -93,7 +93,7 @@ impl framework::Example for Picking {

fn draw(
&mut self,
re_ctx: &mut re_renderer::RenderContext,
re_ctx: &re_renderer::RenderContext,
resolution: [u32; 2],
_time: &framework::Time,
pixels_from_point: f32,
Expand Down
52 changes: 38 additions & 14 deletions crates/re_renderer/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::sync::Arc;

use parking_lot::{Mutex, RwLock};
use parking_lot::{MappedRwLockReadGuard, Mutex, RwLock, RwLockReadGuard};
use type_map::concurrent::{self, TypeMap};

use crate::{
Expand All @@ -20,7 +20,7 @@ pub struct RenderContext {
pub queue: Arc<wgpu::Queue>,

pub(crate) shared_renderer_data: SharedRendererData,
pub(crate) renderers: RwLock<Renderers>,
renderers: RwLock<Renderers>,
pub(crate) resolver: RecommendedFileResolver,
#[cfg(all(not(target_arch = "wasm32"), debug_assertions))] // native debug build
pub(crate) err_tracker: std::sync::Arc<crate::error_tracker::ErrorTracker>,
Expand Down Expand Up @@ -60,9 +60,9 @@ impl Renderers {
pub fn get_or_create<Fs: FileSystem, R: 'static + Renderer + Send + Sync>(
&mut self,
shared_data: &SharedRendererData,
resource_pools: &mut WgpuResourcePools,
resource_pools: &WgpuResourcePools,
device: &wgpu::Device,
resolver: &mut FileResolver<Fs>,
resolver: &FileResolver<Fs>,
) -> &R {
self.renderers.entry().or_insert_with(|| {
re_tracing::profile_scope!("create_renderer", std::any::type_name::<R>());
Expand Down Expand Up @@ -170,16 +170,16 @@ impl RenderContext {
global_bindings,
};

let mut resolver = crate::new_recommended_file_resolver();
let resolver = crate::new_recommended_file_resolver();
let mut renderers = RwLock::new(Renderers {
renderers: TypeMap::new(),
});

let mesh_manager = RwLock::new(MeshManager::new(renderers.get_mut().get_or_create(
&shared_renderer_data,
&mut gpu_resources,
&gpu_resources,
&device,
&mut resolver,
&resolver,
)));
let texture_manager_2d =
TextureManager2D::new(device.clone(), queue.clone(), &gpu_resources.textures);
Expand Down Expand Up @@ -325,7 +325,7 @@ impl RenderContext {
// The set of files on disk that were modified in any way since last frame,
// ignoring deletions.
// Always an empty set in release builds.
let modified_paths = FileServer::get_mut(|fs| fs.collect(&mut self.resolver));
let modified_paths = FileServer::get_mut(|fs| fs.collect(&self.resolver));
if !modified_paths.is_empty() {
re_log::debug!(?modified_paths, "got some filesystem events");
}
Expand All @@ -348,12 +348,7 @@ impl RenderContext {

// Shader module maintenance must come before render pipelines because render pipeline
// recompilation picks up all shaders that have been recompiled this frame.
shader_modules.begin_frame(
&self.device,
&mut self.resolver,
frame_index,
&modified_paths,
);
shader_modules.begin_frame(&self.device, &self.resolver, frame_index, &modified_paths);
render_pipelines.begin_frame(
&self.device,
frame_index,
Expand Down Expand Up @@ -399,6 +394,35 @@ impl RenderContext {
.push(self.queue.submit([command_buffer]));
}
}

/// Gets a renderer with the specified type, initializing it if necessary.
pub fn renderer<R: 'static + Renderer + Send + Sync>(&self) -> MappedRwLockReadGuard<'_, R> {
// Most likely we already have the renderer. Take a read lock and return it.
if let Ok(renderer) =
parking_lot::RwLockReadGuard::try_map(self.renderers.read(), |r| r.get::<R>())
{
return renderer;
}

// If it wasn't there we have to add it.
// This path is rare since it happens only once per renderer type in the lifetime of the ctx.
// (we don't discard renderers ever)
self.renderers.write().get_or_create::<_, R>(
&self.shared_renderer_data,
&self.gpu_resources,
&self.device,
&self.resolver,
);

// Release write lock again and only take a read lock.
// safe to unwrap since we just created it and nobody removes elements from the renderer.
parking_lot::RwLockReadGuard::map(self.renderers.read(), |r| r.get::<R>().unwrap())
}

/// Read access to renderers.
pub(crate) fn read_lock_renderers(&self) -> RwLockReadGuard<'_, Renderers> {
self.renderers.read()
}
}

pub struct FrameGlobalCommandEncoder(Option<wgpu::CommandEncoder>);
Expand Down
8 changes: 4 additions & 4 deletions crates/re_renderer/src/draw_phases/outlines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ impl OutlineMaskProcessor {
}

pub fn new(
ctx: &mut RenderContext,
ctx: &RenderContext,
config: &OutlineConfig,
view_name: &DebugLabel,
resolution_in_pixel: [u32; 2],
Expand Down Expand Up @@ -265,7 +265,7 @@ impl OutlineMaskProcessor {
// ------------- Render Pipelines -------------

let screen_triangle_vertex_shader =
screen_triangle_vertex_shader(&mut ctx.gpu_resources, &ctx.device, &mut ctx.resolver);
screen_triangle_vertex_shader(&ctx.gpu_resources, &ctx.device, &ctx.resolver);
let jumpflooding_init_shader_module = if mask_sample_count == 1 {
include_shader_module!("../../shader/outlines/jumpflooding_init.wgsl")
} else {
Expand All @@ -286,7 +286,7 @@ impl OutlineMaskProcessor {
fragment_entrypoint: "main".into(),
fragment_handle: ctx.gpu_resources.shader_modules.get_or_create(
&ctx.device,
&mut ctx.resolver,
&ctx.resolver,
&jumpflooding_init_shader_module,
),
vertex_buffers: smallvec![],
Expand Down Expand Up @@ -315,7 +315,7 @@ impl OutlineMaskProcessor {
),
fragment_handle: ctx.gpu_resources.shader_modules.get_or_create(
&ctx.device,
&mut ctx.resolver,
&ctx.resolver,
&include_shader_module!("../../shader/outlines/jumpflooding_step.wgsl"),
),
..jumpflooding_init_desc
Expand Down
8 changes: 4 additions & 4 deletions crates/re_renderer/src/draw_phases/picking_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ impl PickingLayerProcessor {
/// It allows to sample the picking layer texture in a shader.
#[allow(clippy::too_many_arguments)]
pub fn new<T: 'static + Send + Sync>(
ctx: &mut RenderContext,
ctx: &RenderContext,
view_name: &DebugLabel,
screen_resolution: glam::UVec2,
picking_rect: RectInt,
Expand Down Expand Up @@ -485,7 +485,7 @@ impl DepthReadbackWorkaround {
const READBACK_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba32Float;

fn new(
ctx: &mut RenderContext,
ctx: &RenderContext,
extent: glam::UVec2,
depth_target_handle: GpuTextureHandle,
) -> DepthReadbackWorkaround {
Expand Down Expand Up @@ -551,13 +551,13 @@ impl DepthReadbackWorkaround {
vertex_entrypoint: "main".into(),
vertex_handle: ctx.gpu_resources.shader_modules.get_or_create(
&ctx.device,
&mut ctx.resolver,
&ctx.resolver,
&include_shader_module!("../../shader/screen_triangle.wgsl"),
),
fragment_entrypoint: "main".into(),
fragment_handle: ctx.gpu_resources.shader_modules.get_or_create(
&ctx.device,
&mut ctx.resolver,
&ctx.resolver,
&include_shader_module!("../../shader/copy_texture.wgsl"),
),
vertex_buffers: smallvec![],
Expand Down
Loading

0 comments on commit eab8244

Please sign in to comment.