Skip to content

Commit

Permalink
Improved readback data handling (#1734)
Browse files Browse the repository at this point in the history
* user or re_renderer is no longer forced to consume all data in one go, instead we'll search if the data you request is available and return it then
    * this leaves the possibility for stale data, which might cause heavy memory leaks, so we clean stale stuff up automatically! (this can happen easily in a healthy application! Think closing a view for which you request picking data)
* identifiers are user-chosen and not required to be unique (space view id is a good & valid identifier!)
* readback data can cary arbitrary user data
* the readback belt itself is a strictly internal datastructure now. Higher level systems like `ScreenshotProcessor` (new! shifting further towards a class-per-draw-pass; this is still an ongoing evolution!) or `PickingLayerProcessor` wrap your userdata and provide everything you need to know about for their readback data
   * this keeps the readback belt agnostic while presenting high level constructs where needed! 
* Do smaller readback chunks
  • Loading branch information
Wumpf authored Mar 31, 2023
1 parent 118630c commit 6dbc5b9
Show file tree
Hide file tree
Showing 20 changed files with 719 additions and 575 deletions.
103 changes: 46 additions & 57 deletions crates/re_renderer/examples/multiview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ use re_renderer::{
GenericSkyboxDrawData, LineDrawData, LineStripFlags, MeshDrawData, MeshInstance,
TestTriangleDrawData,
},
view_builder::{
OrthographicCameraMode, Projection, ScheduledScreenshot, TargetConfiguration, ViewBuilder,
},
Color32, LineStripSeriesBuilder, PointCloudBuilder, RenderContext, Rgba, Size,
view_builder::{OrthographicCameraMode, Projection, TargetConfiguration, ViewBuilder},
Color32, GpuReadbackIdentifier, LineStripSeriesBuilder, PointCloudBuilder, RenderContext, Rgba,
ScreenshotProcessor, Size,
};
use winit::event::{ElementState, VirtualKeyCode};

Expand Down Expand Up @@ -151,7 +150,6 @@ struct Multiview {
random_points_colors: Vec<Color32>,

take_screenshot_next_frame_for_view: Option<u32>,
scheduled_screenshots: Vec<ScheduledScreenshot>,
}

fn random_color(rnd: &mut impl rand::Rng) -> Color32 {
Expand All @@ -164,6 +162,45 @@ fn random_color(rnd: &mut impl rand::Rng) -> Color32 {
.into()
}

/// Readback identifier for screenshots.
/// Identifiers don't need to be unique and we don't have anything interesting to distinguish here!
const READBACK_IDENTIFIER: GpuReadbackIdentifier = 0;

fn handle_incoming_screenshots(re_ctx: &RenderContext) {
ScreenshotProcessor::next_readback_result(
re_ctx,
READBACK_IDENTIFIER,
|data, _extent, view_idx: u32| {
re_log::info!(
"Received screenshot for view {view_idx}. Total bytes {:?}",
data.len()
);

#[cfg(not(target_arch = "wasm32"))]
{
// Get next available file name.
let mut i = 1;
let filename = loop {
let filename = format!("screenshot_{i}.png");
if !std::path::Path::new(&filename).exists() {
break filename;
}
i += 1;
};

image::save_buffer(
filename,
data,
_extent.x,
_extent.y,
image::ColorType::Rgba8,
)
.expect("Failed to save screenshot");
}
},
);
}

impl Multiview {
fn draw_view<D: 'static + re_renderer::renderer::DrawData + Sync + Send + Clone>(
&mut self,
Expand All @@ -180,8 +217,9 @@ impl Multiview {
.take_screenshot_next_frame_for_view
.map_or(false, |i| i == index)
{
self.scheduled_screenshots
.push(view_builder.schedule_screenshot(re_ctx).unwrap());
view_builder
.schedule_screenshot(re_ctx, READBACK_IDENTIFIER, index)
.unwrap();
re_log::info!("Scheduled screenshot for view {}", index);
}

Expand All @@ -193,54 +231,6 @@ impl Multiview {

(view_builder, command_buffer)
}

fn handle_incoming_screenshots(&mut self, re_ctx: &mut RenderContext) {
re_ctx
.gpu_readback_belt
.lock()
.receive_data(|data, identifier| {
if let Some(index) = self
.scheduled_screenshots
.iter()
.position(|s| s.identifier == identifier)
{
re_log::info!(
"Received screenshot. Total bytes {:?}. Identifier {identifier}",
data.len()
);

#[cfg(target_arch = "wasm32")]
self.scheduled_screenshots.remove(index);

#[cfg(not(target_arch = "wasm32"))]
{
let screenshot = self.scheduled_screenshots.swap_remove(index);

re_log::info!("Received screenshot. Total bytes {}", data.len());

// Get next available file name.
let mut i = 1;
let filename = loop {
let filename = format!("screenshot_{i}.png");
if !std::path::Path::new(&filename).exists() {
break filename;
}
i += 1;
};

#[cfg(not(target_arch = "wasm32"))]
image::save_buffer(
filename,
&screenshot.row_info.remove_padding(data),
screenshot.extent.x,
screenshot.extent.y,
image::ColorType::Rgba8,
)
.expect("Failed to save screenshot");
}
}
});
}
}

impl Example for Multiview {
Expand Down Expand Up @@ -297,7 +287,6 @@ impl Example for Multiview {
random_points_colors,

take_screenshot_next_frame_for_view: None,
scheduled_screenshots: Vec::new(),
}
}

Expand All @@ -317,7 +306,7 @@ impl Example for Multiview {
) * 10.0;
}

self.handle_incoming_screenshots(re_ctx);
handle_incoming_screenshots(re_ctx);

let seconds_since_startup = time.seconds_since_startup();
let view_from_world =
Expand Down
75 changes: 26 additions & 49 deletions crates/re_renderer/examples/picking.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use ahash::HashMap;
use itertools::Itertools as _;
use rand::Rng;
use re_renderer::{
view_builder::{Projection, TargetConfiguration, ViewBuilder},
Color32, GpuReadbackBufferIdentifier, IntRect, PickingLayerId, PickingLayerInstanceId,
PointCloudBuilder, RenderContext, ScheduledPickingRect, Size,
Color32, GpuReadbackIdentifier, IntRect, PickingLayerInstanceId, PickingLayerProcessor,
PointCloudBuilder, Size,
};

mod framework;
Expand All @@ -18,7 +17,6 @@ struct PointSet {

struct Picking {
point_sets: Vec<PointSet>,
scheduled_picking_rects: HashMap<GpuReadbackBufferIdentifier, ScheduledPickingRect>,
picking_position: glam::UVec2,
}

Expand All @@ -32,36 +30,9 @@ fn random_color(rnd: &mut impl rand::Rng) -> Color32 {
.into()
}

impl Picking {
#[allow(clippy::unused_self)]
fn handle_incoming_picking_data(&mut self, re_ctx: &mut RenderContext, _time: f32) {
re_ctx
.gpu_readback_belt
.lock()
.receive_data(|data, identifier| {
if let Some(picking_rect_info) = self.scheduled_picking_rects.remove(&identifier) {
// TODO(andreas): Move this into a utility function?
let picking_data_without_padding =
picking_rect_info.row_info.remove_padding(data);
let picking_data: &[PickingLayerId] =
bytemuck::cast_slice(&picking_data_without_padding);

// Grab the middle pixel. usually we'd want to do something clever that snaps the the closest object of interest.
let picked_pixel = picking_data[(picking_rect_info.rect.extent.x / 2
+ (picking_rect_info.rect.extent.y / 2) * picking_rect_info.rect.extent.x)
as usize];

if picked_pixel.object.0 != 0 {
let point_set = &mut self.point_sets[picked_pixel.object.0 as usize - 1];
point_set.radii[picked_pixel.instance.0 as usize] = Size::new_scene(0.1);
point_set.colors[picked_pixel.instance.0 as usize] = Color32::DEBUG_COLOR;
}
} else {
re_log::error!("Received picking data for unknown identifier");
}
});
}
}
/// Readback identifier for picking rects.
/// Identifiers don't need to be unique and we don't have anything interesting to distinguish here!
const READBACK_IDENTIFIER: GpuReadbackIdentifier = 0;

impl framework::Example for Picking {
fn title() -> &'static str {
Expand Down Expand Up @@ -103,7 +74,6 @@ impl framework::Example for Picking {

Picking {
point_sets,
scheduled_picking_rects: HashMap::default(),
picking_position: glam::UVec2::ZERO,
}
}
Expand All @@ -112,10 +82,23 @@ impl framework::Example for Picking {
&mut self,
re_ctx: &mut re_renderer::RenderContext,
resolution: [u32; 2],
time: &framework::Time,
_time: &framework::Time,
pixels_from_point: f32,
) -> Vec<framework::ViewDrawResult> {
self.handle_incoming_picking_data(re_ctx, time.seconds_since_startup());
while let Some(picking_result) =
PickingLayerProcessor::next_readback_result::<()>(re_ctx, READBACK_IDENTIFIER)
{
// Grab the middle pixel. usually we'd want to do something clever that snaps the the closest object of interest.
let picked_pixel = picking_result.picking_data[(picking_result.rect.extent.x / 2
+ (picking_result.rect.extent.y / 2) * picking_result.rect.extent.x)
as usize];

if picked_pixel.object.0 != 0 {
let point_set = &mut self.point_sets[picked_pixel.object.0 as usize - 1];
point_set.radii[picked_pixel.instance.0 as usize] = Size::new_scene(0.1);
point_set.colors[picked_pixel.instance.0 as usize] = Color32::DEBUG_COLOR;
}
}

let mut view_builder = ViewBuilder::default();

Expand Down Expand Up @@ -148,19 +131,13 @@ impl framework::Example for Picking {
// Use an uneven number of pixels for the picking rect so that there is a clearly defined middle-pixel.
// (for this sample a size of 1 would be sufficient, but for a real application you'd want to use a larger size to allow snapping)
let picking_rect_size = 31;

let picking_rect = view_builder
.schedule_picking_readback(
re_ctx,
IntRect::from_middle_and_extent(
self.picking_position.as_ivec2(),
glam::uvec2(picking_rect_size, picking_rect_size),
),
false,
)
let picking_rect = IntRect::from_middle_and_extent(
self.picking_position.as_ivec2(),
glam::uvec2(picking_rect_size, picking_rect_size),
);
view_builder
.schedule_picking_rect(re_ctx, picking_rect, READBACK_IDENTIFIER, (), false)
.unwrap();
self.scheduled_picking_rects
.insert(picking_rect.identifier, picking_rect);

let mut builder = PointCloudBuilder::<()>::new(re_ctx);

Expand Down
Loading

1 comment on commit 6dbc5b9

@github-actions
Copy link

Choose a reason for hiding this comment

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

Rust Benchmark

Benchmark suite Current: 6dbc5b9 Previous: 118630c Ratio
datastore/num_rows=1000/num_instances=1000/packed=false/insert/default 11028769 ns/iter (± 551494) 12379764 ns/iter (± 657716) 0.89
datastore/num_rows=1000/num_instances=1000/packed=false/insert/bucketsz=0 12796273 ns/iter (± 340092) 14032856 ns/iter (± 630549) 0.91
datastore/num_rows=1000/num_instances=1000/packed=false/insert/bucketsz=2 12343529 ns/iter (± 455692) 13325329 ns/iter (± 790890) 0.93
datastore/num_rows=1000/num_instances=1000/packed=false/insert/bucketsz=32 11657105 ns/iter (± 516711) 11151192 ns/iter (± 533348) 1.05
datastore/num_rows=1000/num_instances=1000/packed=false/insert/bucketsz=2048 11429470 ns/iter (± 600029) 10993438 ns/iter (± 433677) 1.04
datastore/num_rows=1000/num_instances=1000/packed=true/insert/default 10703912 ns/iter (± 554155) 10704961 ns/iter (± 520279) 1.00
datastore/num_rows=1000/num_instances=1000/packed=true/insert/bucketsz=0 13009003 ns/iter (± 646748) 13012367 ns/iter (± 724960) 1.00
datastore/num_rows=1000/num_instances=1000/packed=true/insert/bucketsz=2 12585551 ns/iter (± 579351) 12828264 ns/iter (± 783052) 0.98
datastore/num_rows=1000/num_instances=1000/packed=true/insert/bucketsz=32 11701801 ns/iter (± 457307) 11675537 ns/iter (± 843174) 1.00
datastore/num_rows=1000/num_instances=1000/packed=true/insert/bucketsz=2048 10998929 ns/iter (± 623164) 10819004 ns/iter (± 619410) 1.02
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at/default 1839 ns/iter (± 20) 1841 ns/iter (± 17) 1.00
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at/bucketsz=0 1861 ns/iter (± 7) 1863 ns/iter (± 3) 1.00
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at/bucketsz=2 1851 ns/iter (± 12) 1861 ns/iter (± 2) 0.99
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at/bucketsz=32 1838 ns/iter (± 9) 1851 ns/iter (± 1) 0.99
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at/bucketsz=2048 1837 ns/iter (± 6) 1855 ns/iter (± 4) 0.99
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at/default 1859 ns/iter (± 15) 1842 ns/iter (± 20) 1.01
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at/bucketsz=0 1869 ns/iter (± 4) 1871 ns/iter (± 7) 1.00
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at/bucketsz=2 1886 ns/iter (± 15) 1867 ns/iter (± 4) 1.01
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at/bucketsz=32 1886 ns/iter (± 4) 1841 ns/iter (± 1) 1.02
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at/bucketsz=2048 1858 ns/iter (± 8) 1849 ns/iter (± 0) 1.00
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/primary/default 283 ns/iter (± 1) 279 ns/iter (± 0) 1.01
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/secondaries/default 444 ns/iter (± 0) 434 ns/iter (± 0) 1.02
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/primary/bucketsz=0 280 ns/iter (± 0) 280 ns/iter (± 0) 1
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/secondaries/bucketsz=0 450 ns/iter (± 2) 442 ns/iter (± 0) 1.02
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/primary/bucketsz=2 279 ns/iter (± 1) 280 ns/iter (± 0) 1.00
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/secondaries/bucketsz=2 450 ns/iter (± 1) 442 ns/iter (± 0) 1.02
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/primary/bucketsz=32 282 ns/iter (± 1) 280 ns/iter (± 0) 1.01
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/secondaries/bucketsz=32 449 ns/iter (± 2) 445 ns/iter (± 0) 1.01
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/primary/bucketsz=2048 282 ns/iter (± 1) 280 ns/iter (± 0) 1.01
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/secondaries/bucketsz=2048 445 ns/iter (± 3) 436 ns/iter (± 0) 1.02
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at_missing/primary/default 281 ns/iter (± 1) 282 ns/iter (± 0) 1.00
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at_missing/secondaries/default 445 ns/iter (± 2) 433 ns/iter (± 0) 1.03
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at_missing/primary/bucketsz=0 279 ns/iter (± 2) 283 ns/iter (± 0) 0.99
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at_missing/secondaries/bucketsz=0 451 ns/iter (± 2) 442 ns/iter (± 0) 1.02
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at_missing/primary/bucketsz=2 279 ns/iter (± 1) 283 ns/iter (± 0) 0.99
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at_missing/secondaries/bucketsz=2 451 ns/iter (± 0) 442 ns/iter (± 0) 1.02
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at_missing/primary/bucketsz=32 281 ns/iter (± 2) 283 ns/iter (± 0) 0.99
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at_missing/secondaries/bucketsz=32 449 ns/iter (± 0) 440 ns/iter (± 0) 1.02
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at_missing/primary/bucketsz=2048 281 ns/iter (± 1) 283 ns/iter (± 0) 0.99
datastore/num_rows=1000/num_instances=1000/packed=true/latest_at_missing/secondaries/bucketsz=2048 445 ns/iter (± 2) 435 ns/iter (± 0) 1.02
datastore/num_rows=1000/num_instances=1000/packed=false/range/default 11616219 ns/iter (± 525499) 13580447 ns/iter (± 1338003) 0.86
datastore/num_rows=1000/num_instances=1000/packed=false/range/bucketsz=0 2182250 ns/iter (± 15632) 2229375 ns/iter (± 18821) 0.98
datastore/num_rows=1000/num_instances=1000/packed=false/range/bucketsz=2 2123443 ns/iter (± 10887) 2135611 ns/iter (± 7671) 0.99
datastore/num_rows=1000/num_instances=1000/packed=false/range/bucketsz=32 1926170 ns/iter (± 16799) 1887581 ns/iter (± 7398) 1.02
datastore/num_rows=1000/num_instances=1000/packed=false/range/bucketsz=2048 1913440 ns/iter (± 16633) 1895081 ns/iter (± 16027) 1.01
datastore/num_rows=1000/num_instances=1000/packed=true/range/default 11679932 ns/iter (± 552706) 12127148 ns/iter (± 1145753) 0.96
datastore/num_rows=1000/num_instances=1000/packed=true/range/bucketsz=0 2244443 ns/iter (± 21159) 2172117 ns/iter (± 16952) 1.03
datastore/num_rows=1000/num_instances=1000/packed=true/range/bucketsz=2 2116964 ns/iter (± 13231) 2224646 ns/iter (± 24429) 0.95
datastore/num_rows=1000/num_instances=1000/packed=true/range/bucketsz=32 1914764 ns/iter (± 7483) 1882330 ns/iter (± 18286) 1.02
datastore/num_rows=1000/num_instances=1000/packed=true/range/bucketsz=2048 1839548 ns/iter (± 9454) 1862335 ns/iter (± 100433) 0.99
mono_points_arrow/generate_message_bundles 42136952 ns/iter (± 775063) 47556952 ns/iter (± 1744151) 0.89
mono_points_arrow/generate_messages 165243914 ns/iter (± 1366901) 184952998 ns/iter (± 2178062) 0.89
mono_points_arrow/encode_log_msg 207198428 ns/iter (± 1049427) 228848482 ns/iter (± 2771203) 0.91
mono_points_arrow/encode_total 415245120 ns/iter (± 2245045) 452197250 ns/iter (± 2349357) 0.92
mono_points_arrow/decode_log_msg 251133394 ns/iter (± 1214242) 268471765 ns/iter (± 1109366) 0.94
mono_points_arrow/decode_message_bundles 86943563 ns/iter (± 970973) 101372522 ns/iter (± 955933) 0.86
mono_points_arrow/decode_total 337217408 ns/iter (± 1798207) 364789697 ns/iter (± 2207278) 0.92
mono_points_arrow_batched/generate_message_bundles 34364939 ns/iter (± 1991528) 34499540 ns/iter (± 1754024) 1.00
mono_points_arrow_batched/generate_messages 8678464 ns/iter (± 675461) 10191808 ns/iter (± 809149) 0.85
mono_points_arrow_batched/encode_log_msg 1801512 ns/iter (± 11278) 1780969 ns/iter (± 10346) 1.01
mono_points_arrow_batched/encode_total 44958727 ns/iter (± 2053000) 48392635 ns/iter (± 2993308) 0.93
mono_points_arrow_batched/decode_log_msg 975034 ns/iter (± 3095) 982645 ns/iter (± 5663) 0.99
mono_points_arrow_batched/decode_message_bundles 18453968 ns/iter (± 1186524) 17529663 ns/iter (± 1978381) 1.05
mono_points_arrow_batched/decode_total 18791933 ns/iter (± 794176) 20790421 ns/iter (± 951830) 0.90
batch_points_arrow/generate_message_bundles 288571 ns/iter (± 1489) 288739 ns/iter (± 1095) 1.00
batch_points_arrow/generate_messages 7629 ns/iter (± 71) 7653 ns/iter (± 19) 1.00
batch_points_arrow/encode_log_msg 385642 ns/iter (± 1623) 390895 ns/iter (± 1963) 0.99
batch_points_arrow/encode_total 698230 ns/iter (± 3894) 694653 ns/iter (± 2013) 1.01
batch_points_arrow/decode_log_msg 339464 ns/iter (± 2042) 337199 ns/iter (± 1221) 1.01
batch_points_arrow/decode_message_bundles 2891 ns/iter (± 25) 2883 ns/iter (± 7) 1.00
batch_points_arrow/decode_total 349051 ns/iter (± 1112) 350415 ns/iter (± 1001) 1.00
arrow_mono_points/insert 6134033149 ns/iter (± 19368173) 7060741725 ns/iter (± 12411274) 0.87
arrow_mono_points/query 1778265 ns/iter (± 17037) 1798259 ns/iter (± 15633) 0.99
arrow_batch_points/insert 3028900 ns/iter (± 16317) 2994901 ns/iter (± 7327) 1.01
arrow_batch_points/query 16843 ns/iter (± 136) 16931 ns/iter (± 21) 0.99
arrow_batch_vecs/insert 43557 ns/iter (± 316) 43045 ns/iter (± 179) 1.01
arrow_batch_vecs/query 533713 ns/iter (± 7351) 535786 ns/iter (± 1691) 1.00
tuid/Tuid::random 34 ns/iter (± 0) 42 ns/iter (± 0) 0.81

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.