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

Staging Belt & use in PointCloudBuilder #594

Closed
wants to merge 10 commits into from
8 changes: 4 additions & 4 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion crates/re_renderer/examples/2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ impl framework::Example for Render2D {
// Moving the windows to a high dpi screen makes the second one bigger.
// Also, it looks different under perspective projection.
// The third point is automatic thickness which is determined by the point renderer implementation.
let mut point_cloud_builder = PointCloudBuilder::<()>::default();
let mut point_cloud_builder = PointCloudBuilder::<()>::new(re_ctx, 32, 1);
point_cloud_builder
.batch("points")
.add_points_2d(
Expand Down
4 changes: 3 additions & 1 deletion crates/re_renderer/examples/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ impl<E: Example + 'static> Application<E> {
self.window.request_redraw();
}
Event::RedrawRequested(_) => {
self.re_ctx.frame_maintenance();
self.re_ctx.begin_frame();

// native debug build
#[cfg(all(not(target_arch = "wasm32"), debug_assertions))]
Expand Down Expand Up @@ -273,6 +273,8 @@ impl<E: Example + 'static> Application<E> {
// drop the pass so we can finish() the main encoder!
};

self.re_ctx.before_submit();

self.re_ctx.queue.submit(
view_cmd_buffers
.into_iter()
Expand Down
24 changes: 11 additions & 13 deletions crates/re_renderer/examples/multiview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ use rand::Rng;
use re_renderer::{
renderer::{
GenericSkyboxDrawData, LineDrawData, LineStripFlags, MeshDrawData, MeshInstance,
PointCloudBatchInfo, PointCloudDrawData, PointCloudVertex, TestTriangleDrawData,
PointCloudVertex, TestTriangleDrawData,
},
resource_managers::ResourceLifeTime,
view_builder::{OrthographicCameraMode, Projection, TargetConfiguration, ViewBuilder},
Color32, LineStripSeriesBuilder, RenderContext, Rgba, Size,
Color32, LineStripSeriesBuilder, PointCloudBuilder, RenderContext, Rgba, Size,
};
use winit::event::{ElementState, VirtualKeyCode};

Expand Down Expand Up @@ -254,20 +254,18 @@ impl Example for Multiview {
let view_from_world =
IsoTransform::look_at_rh(self.camera_position, Vec3::ZERO, Vec3::Y).unwrap();

let mut point_cloud_builder =
PointCloudBuilder::<()>::new(re_ctx, self.random_points.len(), 1);
point_cloud_builder
.batch("Random points")
.world_from_obj(glam::Mat4::from_rotation_x(seconds_since_startup))
.add_vertices(self.random_points.iter().cloned())
.colors(self.random_points_colors.iter().cloned());

let triangle = TestTriangleDrawData::new(re_ctx);
let skybox = GenericSkyboxDrawData::new(re_ctx);
let lines = build_lines(re_ctx, seconds_since_startup);
let point_cloud = PointCloudDrawData::new(
re_ctx,
&self.random_points,
&self.random_points_colors,
&[PointCloudBatchInfo {
label: "Random points".into(),
world_from_obj: glam::Mat4::from_rotation_x(seconds_since_startup),
point_count: self.random_points.len() as _,
}],
)
.unwrap();
let point_cloud = point_cloud_builder.to_draw_data(re_ctx).unwrap();
let meshes = build_mesh_instances(
re_ctx,
&self.model_mesh_instances,
Expand Down
72 changes: 53 additions & 19 deletions crates/re_renderer/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use std::sync::Arc;

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

use crate::{
config::RenderContextConfig,
global_bindings::GlobalBindings,
renderer::Renderer,
resource_managers::{MeshManager, TextureManager2D},
staging_write_belt::StagingWriteBelt,
wgpu_resources::WgpuResourcePools,
FileResolver, FileServer, FileSystem, RecommendedFileResolver,
};
Expand All @@ -24,12 +26,18 @@ pub struct RenderContext {
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>,
pub(crate) staging_belt: Mutex<StagingWriteBelt>,

/// Command encoder for all commands that should go in before view builder are submitted.
///
/// This should be used for any gpu copy operation outside of a renderer or view builder.
/// (i.e. typically in [`crate::renderer::DrawData`] creation!)
pub(crate) frame_global_commands: wgpu::CommandEncoder,

pub gpu_resources: WgpuResourcePools,
pub mesh_manager: MeshManager,
pub texture_manager_2d: TextureManager2D,

// TODO(andreas): Add frame/lifetime statistics, shared resources (e.g. "global" uniform buffer), ??
frame_index: u64,
}

Expand Down Expand Up @@ -137,35 +145,44 @@ impl RenderContext {
let texture_manager_2d =
TextureManager2D::new(device.clone(), queue.clone(), &mut gpu_resources.textures);

let before_view_builder_commands = Self::create_frame_global_command_encoder(&device);

RenderContext {
device,
queue,

shared_renderer_data,

renderers,
gpu_resources,
resolver,
#[cfg(all(not(target_arch = "wasm32"), debug_assertions))] // native debug build
err_tracker,
staging_belt: Mutex::new(StagingWriteBelt::new(1024 * 1024 * 32)), // 32mb chunk size (as big as a 2048x1024 float4 texture)

frame_global_commands: before_view_builder_commands,

gpu_resources,
mesh_manager,
texture_manager_2d,

resolver,

#[cfg(all(not(target_arch = "wasm32"), debug_assertions))] // native debug build
err_tracker,

frame_index: 0,
}
}

fn create_frame_global_command_encoder(device: &wgpu::Device) -> wgpu::CommandEncoder {
device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: crate::DebugLabel::from("before view builder commands").get(),
})
}

/// Call this at the beginning of a new frame.
///
/// Updates internal book-keeping, frame allocators and executes delayed events like shader reloading.
pub fn frame_maintenance(&mut self) {
pub fn begin_frame(&mut self) {
self.frame_index += 1;

// Tick the error tracker so that it knows when to reset!
// Note that we're ticking on frame_maintenance rather than raw frames, which
// Note that we're ticking on begin_frame rather than raw frames, which
// makes a world of difference when we're in a poisoned state.
#[cfg(all(not(target_arch = "wasm32"), debug_assertions))] // native debug build
self.err_tracker.tick();
Expand All @@ -178,8 +195,8 @@ impl RenderContext {
re_log::debug!(?modified_paths, "got some filesystem events");
}

self.mesh_manager.frame_maintenance(self.frame_index);
self.texture_manager_2d.frame_maintenance(self.frame_index);
self.mesh_manager.begin_frame(self.frame_index);
self.texture_manager_2d.begin_frame(self.frame_index);

{
let WgpuResourcePools {
Expand All @@ -195,13 +212,13 @@ 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.frame_maintenance(
shader_modules.begin_frame(
&self.device,
&mut self.resolver,
self.frame_index,
&modified_paths,
);
render_pipelines.frame_maintenance(
render_pipelines.begin_frame(
&self.device,
self.frame_index,
shader_modules,
Expand All @@ -210,15 +227,32 @@ impl RenderContext {

// Bind group maintenance must come before texture/buffer maintenance since it
// registers texture/buffer use
bind_groups.frame_maintenance(self.frame_index, textures, buffers, samplers);
bind_groups.begin_frame(self.frame_index, textures, buffers, samplers);

textures.frame_maintenance(self.frame_index);
buffers.frame_maintenance(self.frame_index);
textures.begin_frame(self.frame_index);
buffers.begin_frame(self.frame_index);

pipeline_layouts.frame_maintenance(self.frame_index);
bind_group_layouts.frame_maintenance(self.frame_index);
samplers.frame_maintenance(self.frame_index);
pipeline_layouts.begin_frame(self.frame_index);
bind_group_layouts.begin_frame(self.frame_index);
samplers.begin_frame(self.frame_index);
}

// Retrieve unused staging buffer.
self.staging_belt.lock().after_queue_submit();
}

/// Call this at the end of a frame but before submitting command buffers from [`crate::view_builder::ViewBuilder`]
pub fn before_submit(&mut self) {
// Unmap all staging buffers.
self.staging_belt.lock().before_queue_submit();

let mut command_encoder = Self::create_frame_global_command_encoder(&self.device);
std::mem::swap(&mut self.frame_global_commands, &mut command_encoder);
let command_buffer = command_encoder.finish();

// TODO(andreas): For better performance, we should try to bundle this with the single submit call that is currently happening in eframe.
// How do we hook in there and make sure this buffer is submitted first?
self.queue.submit([command_buffer]);
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/re_renderer/src/error_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ impl ErrorTracker {
/// Logs a wgpu error, making sure to deduplicate them as needed.
pub fn handle_error(&self, error: wgpu::Error) {
// The pipeline is in a poisoned state, errors are still coming in: we won't be
// clearing the tracker until it had at least 2 complete frame_maintenance cycles
// clearing the tracker until it had at least 2 complete begin_frame cycles
// without any errors (meaning the swapchain surface is stabilized).
self.clear_countdown.store(2, Ordering::Relaxed);

Expand Down
1 change: 1 addition & 0 deletions crates/re_renderer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod global_bindings;
mod line_strip_builder;
mod point_cloud_builder;
mod size;
mod staging_write_belt;
mod wgpu_buffer_types;
mod wgpu_resources;

Expand Down
Loading