Skip to content

Commit d017565

Browse files
authored
Optimize point clouds (#4932)
### What Some optimizations I found while playing around with large point clouds. ### 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): * Using newly built examples: [app.rerun.io](https://app.rerun.io/pr/4932/index.html) * Using examples from latest `main` build: [app.rerun.io](https://app.rerun.io/pr/4932/index.html?manifest_url=https://app.rerun.io/version/main/examples_manifest.json) * Using full set of examples from `nightly` build: [app.rerun.io](https://app.rerun.io/pr/4932/index.html?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json) * [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/4932) - [Docs preview](https://rerun.io/preview/772cd4195531d6731463ca5b74e3f61eddb38600/docs) <!--DOCS-PREVIEW--> - [Examples preview](https://rerun.io/preview/772cd4195531d6731463ca5b74e3f61eddb38600/examples) <!--EXAMPLES-PREVIEW--> - [Recent benchmark results](https://build.rerun.io/graphs/crates.html) - [Wasm size tracking](https://build.rerun.io/graphs/sizes.html)
1 parent ce1a096 commit d017565

File tree

4 files changed

+80
-83
lines changed

4 files changed

+80
-83
lines changed

crates/re_renderer/src/allocator/cpu_write_gpu_read_belt.rs

+20-11
Original file line numberDiff line numberDiff line change
@@ -119,21 +119,30 @@ where
119119
elements: impl Iterator<Item = T>,
120120
) -> Result<usize, CpuWriteGpuReadError> {
121121
re_tracing::profile_function!();
122-
let num_written_before = self.num_written();
123122

124-
for element in elements {
125-
if self.unwritten_element_range.start >= self.unwritten_element_range.end {
126-
return Err(CpuWriteGpuReadError::BufferFull {
127-
buffer_element_capacity: self.capacity(),
128-
});
123+
// TODO(emilk): optimize the extend function.
124+
// Right now it is 3-4x faster to collect to a vec first, which is crazy.
125+
if true {
126+
let vec = elements.collect::<Vec<_>>();
127+
self.extend_from_slice(&vec)?;
128+
Ok(vec.len())
129+
} else {
130+
let num_written_before = self.num_written();
131+
132+
for element in elements {
133+
if self.unwritten_element_range.start >= self.unwritten_element_range.end {
134+
return Err(CpuWriteGpuReadError::BufferFull {
135+
buffer_element_capacity: self.capacity(),
136+
});
137+
}
138+
139+
self.as_mut_byte_slice()[..std::mem::size_of::<T>()]
140+
.copy_from_slice(bytemuck::bytes_of(&element));
141+
self.unwritten_element_range.start += 1;
129142
}
130143

131-
self.as_mut_byte_slice()[..std::mem::size_of::<T>()]
132-
.copy_from_slice(bytemuck::bytes_of(&element));
133-
self.unwritten_element_range.start += 1;
144+
Ok(self.num_written() - num_written_before)
134145
}
135-
136-
Ok(self.num_written() - num_written_before)
137146
}
138147

139148
/// Fills the buffer with n instances of an element.

crates/re_space_view_spatial/src/visualizers/mod.rs

+52-18
Original file line numberDiff line numberDiff line change
@@ -127,21 +127,50 @@ pub fn process_colors<'a, A: Archetype>(
127127
/// Process [`Color`] components using annotations and default colors.
128128
pub fn process_color_slice<'a>(
129129
colors: Option<&'a [Option<Color>]>,
130-
default_len: usize,
131130
ent_path: &'a EntityPath,
132131
annotation_infos: &'a ResolvedAnnotationInfos,
133-
) -> impl Iterator<Item = egui::Color32> + 'a {
132+
) -> Vec<egui::Color32> {
133+
// This can be rather slow for colors with transparency, since we need to pre-multiply the alpha.
134134
re_tracing::profile_function!();
135+
use rayon::prelude::*;
136+
135137
let default_color = DefaultColor::EntityPath(ent_path);
136138

137-
let colors = colors.as_ref().map_or(
138-
itertools::Either::Left(std::iter::repeat(&None).take(default_len)),
139-
|data| itertools::Either::Right(data.iter()),
140-
);
139+
match (colors, annotation_infos) {
140+
(None, ResolvedAnnotationInfos::Same(count, annotation_info)) => {
141+
re_tracing::profile_scope!("no colors, same annotation");
142+
let color = annotation_info.color(None, default_color);
143+
vec![color; *count]
144+
}
141145

142-
itertools::izip!(annotation_infos.iter(), colors).map(move |(annotation_info, color)| {
143-
annotation_info.color(color.map(|c| c.to_array()), default_color)
144-
})
146+
(None, ResolvedAnnotationInfos::Many(annotation_infos)) => {
147+
re_tracing::profile_scope!("no-colors, many annotations");
148+
annotation_infos
149+
.par_iter()
150+
.map(|annotation_info| annotation_info.color(None, default_color))
151+
.collect()
152+
}
153+
154+
(Some(colors), ResolvedAnnotationInfos::Same(count, annotation_info)) => {
155+
re_tracing::profile_scope!("many-colors, same annotation");
156+
debug_assert_eq!(colors.len(), *count);
157+
colors
158+
.par_iter()
159+
.map(|color| annotation_info.color(color.map(|c| c.to_array()), default_color))
160+
.collect()
161+
}
162+
163+
(Some(colors), ResolvedAnnotationInfos::Many(annotation_infos)) => {
164+
re_tracing::profile_scope!("many-colors, many annotations");
165+
colors
166+
.par_iter()
167+
.zip(annotation_infos.par_iter())
168+
.map(move |(color, annotation_info)| {
169+
annotation_info.color(color.map(|c| c.to_array()), default_color)
170+
})
171+
.collect()
172+
}
173+
}
145174
}
146175

147176
/// Process [`Text`] components using annotations.
@@ -174,20 +203,25 @@ pub fn process_radii<'a, A: Archetype>(
174203

175204
/// Process [`re_types::components::Radius`] components to [`re_renderer::Size`] using auto size
176205
/// where no radius is specified.
177-
pub fn process_radius_slice<'a>(
178-
radii: Option<&'a [Option<re_types::components::Radius>]>,
206+
pub fn process_radius_slice(
207+
radii: Option<&[Option<re_types::components::Radius>]>,
179208
default_len: usize,
180209
ent_path: &EntityPath,
181-
) -> impl Iterator<Item = re_renderer::Size> + 'a {
210+
) -> Vec<re_renderer::Size> {
182211
re_tracing::profile_function!();
183-
let ent_path = ent_path.clone();
212+
use rayon::prelude::*;
184213

185-
let radii = radii.as_ref().map_or(
186-
itertools::Either::Left(std::iter::repeat(&None).take(default_len)),
187-
|data| itertools::Either::Right(data.iter()),
188-
);
214+
let ent_path = ent_path.clone();
189215

190-
radii.map(move |radius| process_radius(&ent_path, radius))
216+
match radii {
217+
None => {
218+
vec![re_renderer::Size::AUTO; default_len]
219+
}
220+
Some(radii) => radii
221+
.par_iter()
222+
.map(|radius| process_radius(&ent_path, radius))
223+
.collect(),
224+
}
191225
}
192226

193227
fn process_radius(

crates/re_space_view_spatial/src/visualizers/points2d.rs

+4-27
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,7 @@ impl Points2DVisualizer {
143143
re_tracing::profile_scope!("labels");
144144

145145
// Max labels is small enough that we can afford iterating on the colors again.
146-
let colors = process_color_slice(
147-
data.colors,
148-
data.positions.len(),
149-
ent_path,
150-
&annotation_infos,
151-
)
152-
.collect::<Vec<_>>();
146+
let colors = process_color_slice(data.colors, ent_path, &annotation_infos);
153147

154148
let instance_path_hashes_for_picking = {
155149
re_tracing::profile_scope!("instance_hashes");
@@ -190,33 +184,16 @@ impl Points2DVisualizer {
190184
}: &Points2DComponentData<'_>,
191185
ent_path: &EntityPath,
192186
) -> Vec<re_renderer::Size> {
193-
re_tracing::profile_function!();
194-
let radii = crate::visualizers::process_radius_slice(radii, positions.len(), ent_path);
195-
{
196-
re_tracing::profile_scope!("collect");
197-
radii.collect()
198-
}
187+
crate::visualizers::process_radius_slice(radii, positions.len(), ent_path)
199188
}
200189

201190
#[inline]
202191
pub fn load_colors(
203-
&Points2DComponentData {
204-
positions, colors, ..
205-
}: &Points2DComponentData<'_>,
192+
&Points2DComponentData { colors, .. }: &Points2DComponentData<'_>,
206193
ent_path: &EntityPath,
207194
annotation_infos: &ResolvedAnnotationInfos,
208195
) -> Vec<re_renderer::Color32> {
209-
re_tracing::profile_function!();
210-
let colors = crate::visualizers::process_color_slice(
211-
colors,
212-
positions.len(),
213-
ent_path,
214-
annotation_infos,
215-
);
216-
{
217-
re_tracing::profile_scope!("collect");
218-
colors.collect()
219-
}
196+
crate::visualizers::process_color_slice(colors, ent_path, annotation_infos)
220197
}
221198

222199
#[inline]

crates/re_space_view_spatial/src/visualizers/points3d.rs

+4-27
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,7 @@ impl Points3DVisualizer {
134134
re_tracing::profile_scope!("labels");
135135

136136
// Max labels is small enough that we can afford iterating on the colors again.
137-
let colors = process_color_slice(
138-
data.colors,
139-
data.positions.len(),
140-
ent_path,
141-
&annotation_infos,
142-
)
143-
.collect::<Vec<_>>();
137+
let colors = process_color_slice(data.colors, ent_path, &annotation_infos);
144138

145139
let instance_path_hashes_for_picking = {
146140
re_tracing::profile_scope!("instance_hashes");
@@ -325,33 +319,16 @@ impl LoadedPoints {
325319
}: &Points3DComponentData<'_>,
326320
ent_path: &EntityPath,
327321
) -> Vec<re_renderer::Size> {
328-
re_tracing::profile_function!();
329-
let radii = crate::visualizers::process_radius_slice(radii, positions.len(), ent_path);
330-
{
331-
re_tracing::profile_scope!("collect");
332-
radii.collect()
333-
}
322+
crate::visualizers::process_radius_slice(radii, positions.len(), ent_path)
334323
}
335324

336325
#[inline]
337326
pub fn load_colors(
338-
&Points3DComponentData {
339-
positions, colors, ..
340-
}: &Points3DComponentData<'_>,
327+
&Points3DComponentData { colors, .. }: &Points3DComponentData<'_>,
341328
ent_path: &EntityPath,
342329
annotation_infos: &ResolvedAnnotationInfos,
343330
) -> Vec<re_renderer::Color32> {
344-
re_tracing::profile_function!();
345-
let colors = crate::visualizers::process_color_slice(
346-
colors,
347-
positions.len(),
348-
ent_path,
349-
annotation_infos,
350-
);
351-
{
352-
re_tracing::profile_scope!("collect");
353-
colors.collect()
354-
}
331+
crate::visualizers::process_color_slice(colors, ent_path, annotation_infos)
355332
}
356333

357334
#[inline]

0 commit comments

Comments
 (0)