Skip to content

Commit

Permalink
Optimize point clouds (#4932)
Browse files Browse the repository at this point in the history
### 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)
  • Loading branch information
emilk authored Jan 29, 2024
1 parent ce1a096 commit d017565
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 83 deletions.
31 changes: 20 additions & 11 deletions crates/re_renderer/src/allocator/cpu_write_gpu_read_belt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,21 +119,30 @@ where
elements: impl Iterator<Item = T>,
) -> Result<usize, CpuWriteGpuReadError> {
re_tracing::profile_function!();
let num_written_before = self.num_written();

for element in elements {
if self.unwritten_element_range.start >= self.unwritten_element_range.end {
return Err(CpuWriteGpuReadError::BufferFull {
buffer_element_capacity: self.capacity(),
});
// TODO(emilk): optimize the extend function.
// Right now it is 3-4x faster to collect to a vec first, which is crazy.
if true {
let vec = elements.collect::<Vec<_>>();
self.extend_from_slice(&vec)?;
Ok(vec.len())
} else {
let num_written_before = self.num_written();

for element in elements {
if self.unwritten_element_range.start >= self.unwritten_element_range.end {
return Err(CpuWriteGpuReadError::BufferFull {
buffer_element_capacity: self.capacity(),
});
}

self.as_mut_byte_slice()[..std::mem::size_of::<T>()]
.copy_from_slice(bytemuck::bytes_of(&element));
self.unwritten_element_range.start += 1;
}

self.as_mut_byte_slice()[..std::mem::size_of::<T>()]
.copy_from_slice(bytemuck::bytes_of(&element));
self.unwritten_element_range.start += 1;
Ok(self.num_written() - num_written_before)
}

Ok(self.num_written() - num_written_before)
}

/// Fills the buffer with n instances of an element.
Expand Down
70 changes: 52 additions & 18 deletions crates/re_space_view_spatial/src/visualizers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,21 +127,50 @@ pub fn process_colors<'a, A: Archetype>(
/// Process [`Color`] components using annotations and default colors.
pub fn process_color_slice<'a>(
colors: Option<&'a [Option<Color>]>,
default_len: usize,
ent_path: &'a EntityPath,
annotation_infos: &'a ResolvedAnnotationInfos,
) -> impl Iterator<Item = egui::Color32> + 'a {
) -> Vec<egui::Color32> {
// This can be rather slow for colors with transparency, since we need to pre-multiply the alpha.
re_tracing::profile_function!();
use rayon::prelude::*;

let default_color = DefaultColor::EntityPath(ent_path);

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

itertools::izip!(annotation_infos.iter(), colors).map(move |(annotation_info, color)| {
annotation_info.color(color.map(|c| c.to_array()), default_color)
})
(None, ResolvedAnnotationInfos::Many(annotation_infos)) => {
re_tracing::profile_scope!("no-colors, many annotations");
annotation_infos
.par_iter()
.map(|annotation_info| annotation_info.color(None, default_color))
.collect()
}

(Some(colors), ResolvedAnnotationInfos::Same(count, annotation_info)) => {
re_tracing::profile_scope!("many-colors, same annotation");
debug_assert_eq!(colors.len(), *count);
colors
.par_iter()
.map(|color| annotation_info.color(color.map(|c| c.to_array()), default_color))
.collect()
}

(Some(colors), ResolvedAnnotationInfos::Many(annotation_infos)) => {
re_tracing::profile_scope!("many-colors, many annotations");
colors
.par_iter()
.zip(annotation_infos.par_iter())
.map(move |(color, annotation_info)| {
annotation_info.color(color.map(|c| c.to_array()), default_color)
})
.collect()
}
}
}

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

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

let radii = radii.as_ref().map_or(
itertools::Either::Left(std::iter::repeat(&None).take(default_len)),
|data| itertools::Either::Right(data.iter()),
);
let ent_path = ent_path.clone();

radii.map(move |radius| process_radius(&ent_path, radius))
match radii {
None => {
vec![re_renderer::Size::AUTO; default_len]
}
Some(radii) => radii
.par_iter()
.map(|radius| process_radius(&ent_path, radius))
.collect(),
}
}

fn process_radius(
Expand Down
31 changes: 4 additions & 27 deletions crates/re_space_view_spatial/src/visualizers/points2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,7 @@ impl Points2DVisualizer {
re_tracing::profile_scope!("labels");

// Max labels is small enough that we can afford iterating on the colors again.
let colors = process_color_slice(
data.colors,
data.positions.len(),
ent_path,
&annotation_infos,
)
.collect::<Vec<_>>();
let colors = process_color_slice(data.colors, ent_path, &annotation_infos);

let instance_path_hashes_for_picking = {
re_tracing::profile_scope!("instance_hashes");
Expand Down Expand Up @@ -190,33 +184,16 @@ impl Points2DVisualizer {
}: &Points2DComponentData<'_>,
ent_path: &EntityPath,
) -> Vec<re_renderer::Size> {
re_tracing::profile_function!();
let radii = crate::visualizers::process_radius_slice(radii, positions.len(), ent_path);
{
re_tracing::profile_scope!("collect");
radii.collect()
}
crate::visualizers::process_radius_slice(radii, positions.len(), ent_path)
}

#[inline]
pub fn load_colors(
&Points2DComponentData {
positions, colors, ..
}: &Points2DComponentData<'_>,
&Points2DComponentData { colors, .. }: &Points2DComponentData<'_>,
ent_path: &EntityPath,
annotation_infos: &ResolvedAnnotationInfos,
) -> Vec<re_renderer::Color32> {
re_tracing::profile_function!();
let colors = crate::visualizers::process_color_slice(
colors,
positions.len(),
ent_path,
annotation_infos,
);
{
re_tracing::profile_scope!("collect");
colors.collect()
}
crate::visualizers::process_color_slice(colors, ent_path, annotation_infos)
}

#[inline]
Expand Down
31 changes: 4 additions & 27 deletions crates/re_space_view_spatial/src/visualizers/points3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,7 @@ impl Points3DVisualizer {
re_tracing::profile_scope!("labels");

// Max labels is small enough that we can afford iterating on the colors again.
let colors = process_color_slice(
data.colors,
data.positions.len(),
ent_path,
&annotation_infos,
)
.collect::<Vec<_>>();
let colors = process_color_slice(data.colors, ent_path, &annotation_infos);

let instance_path_hashes_for_picking = {
re_tracing::profile_scope!("instance_hashes");
Expand Down Expand Up @@ -325,33 +319,16 @@ impl LoadedPoints {
}: &Points3DComponentData<'_>,
ent_path: &EntityPath,
) -> Vec<re_renderer::Size> {
re_tracing::profile_function!();
let radii = crate::visualizers::process_radius_slice(radii, positions.len(), ent_path);
{
re_tracing::profile_scope!("collect");
radii.collect()
}
crate::visualizers::process_radius_slice(radii, positions.len(), ent_path)
}

#[inline]
pub fn load_colors(
&Points3DComponentData {
positions, colors, ..
}: &Points3DComponentData<'_>,
&Points3DComponentData { colors, .. }: &Points3DComponentData<'_>,
ent_path: &EntityPath,
annotation_infos: &ResolvedAnnotationInfos,
) -> Vec<re_renderer::Color32> {
re_tracing::profile_function!();
let colors = crate::visualizers::process_color_slice(
colors,
positions.len(),
ent_path,
annotation_infos,
);
{
re_tracing::profile_scope!("collect");
colors.collect()
}
crate::visualizers::process_color_slice(colors, ent_path, annotation_infos)
}

#[inline]
Expand Down

0 comments on commit d017565

Please sign in to comment.