Skip to content

Commit

Permalink
Show previews of colormaps when selecting them (#1846)
Browse files Browse the repository at this point in the history
* Make infallible version of get_or_create_texture

* Show colormap previews in UI

* Spelling
  • Loading branch information
emilk authored Apr 14, 2023
1 parent fe7ac0e commit beffbc3
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 23 deletions.
30 changes: 26 additions & 4 deletions crates/re_viewer/src/gpu_bridge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub fn viewport_resolution_in_pixels(clip_rect: egui::Rect, pixels_from_point: f
[resolution.x as u32, resolution.y as u32]
}

pub fn get_or_create_texture<'a, Err>(
pub fn try_get_or_create_texture<'a, Err>(
render_ctx: &mut RenderContext,
texture_key: u64,
try_create_texture_desc: impl FnOnce() -> Result<Texture2DCreationDesc<'a>, Err>,
Expand All @@ -64,6 +64,23 @@ pub fn get_or_create_texture<'a, Err>(
)
}

pub fn get_or_create_texture<'a>(
render_ctx: &mut RenderContext,
texture_key: u64,
create_texture_desc: impl FnOnce() -> Texture2DCreationDesc<'a>,
) -> GpuTexture2DHandle {
enum Never {}
let result: Result<GpuTexture2DHandle, Never> = render_ctx
.texture_manager_2d
.get_or_create_with(texture_key, &mut render_ctx.gpu_resources.textures, || {
Ok(create_texture_desc())
});
match result {
Ok(handle) => handle,
Err(never) => match never {},
}
}

/// Render a `re_render` view using the given clip rectangle.
pub fn renderer_paint_callback(
render_ctx: &mut re_renderer::RenderContext,
Expand Down Expand Up @@ -132,6 +149,11 @@ pub fn render_image(

use re_renderer::renderer::{TextureFilterMag, TextureFilterMin};

let clip_rect = painter.clip_rect().intersect(image_rect_on_screen);
if !clip_rect.is_positive() {
return Ok(());
}

// Where in "world space" to paint the image.
let space_rect = egui::Rect::from_min_size(egui::Pos2::ZERO, image_rect_on_screen.size());

Expand Down Expand Up @@ -163,10 +185,10 @@ pub fn render_image(
let space_from_pixel = space_from_points * points_from_pixels;

let resolution_in_pixel =
crate::gpu_bridge::viewport_resolution_in_pixels(painter.clip_rect(), pixels_from_points);
crate::gpu_bridge::viewport_resolution_in_pixels(clip_rect, pixels_from_points);
anyhow::ensure!(resolution_in_pixel[0] > 0 && resolution_in_pixel[1] > 0);

let camera_position_space = space_from_ui.transform_pos(painter.clip_rect().min);
let camera_position_space = space_from_ui.transform_pos(clip_rect.min);

let top_left_position = glam::vec2(camera_position_space.x, camera_position_space.y);
let target_config = re_renderer::view_builder::TargetConfiguration {
Expand Down Expand Up @@ -196,7 +218,7 @@ pub fn render_image(
render_ctx,
command_buffer,
view_builder,
painter.clip_rect(),
clip_rect,
painter.ctx().pixels_per_point(),
));

Expand Down
23 changes: 10 additions & 13 deletions crates/re_viewer/src/gpu_bridge/tensor_to_gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use re_renderer::{
RenderContext,
};

use crate::misc::caches::TensorStats;
use crate::{gpu_bridge::get_or_create_texture, misc::caches::TensorStats};

use super::get_or_create_texture;
use super::try_get_or_create_texture;

// ----------------------------------------------------------------------------

Expand Down Expand Up @@ -63,7 +63,7 @@ fn color_tensor_to_gpu(
tensor: &Tensor,
tensor_stats: &TensorStats,
) -> anyhow::Result<ColormappedTexture> {
let texture_handle = get_or_create_texture(render_ctx, hash(tensor.id()), || {
let texture_handle = try_get_or_create_texture(render_ctx, hash(tensor.id()), || {
let [height, width, depth] = height_width_depth(tensor)?;
let (data, format) = match (depth, &tensor.data) {
// Use R8Unorm and R8Snorm to get filtering on the GPU:
Expand Down Expand Up @@ -161,10 +161,8 @@ fn class_id_tensor_to_gpu(
let colormap_width = 256;
let colormap_height = (max as usize + colormap_width - 1) / colormap_width;

let colormap_texture_handle = get_or_create_texture(
render_ctx,
hash(annotations.row_id),
|| -> anyhow::Result<_> {
let colormap_texture_handle =
get_or_create_texture(render_ctx, hash(annotations.row_id), || {
let data: Vec<u8> = (0..(colormap_width * colormap_height))
.flat_map(|id| {
let color = annotations
Expand All @@ -175,17 +173,16 @@ fn class_id_tensor_to_gpu(
})
.collect();

Ok(Texture2DCreationDesc {
Texture2DCreationDesc {
label: "class_id_colormap".into(),
data: data.into(),
format: TextureFormat::Rgba8UnormSrgb,
width: colormap_width as u32,
height: colormap_height as u32,
})
},
)?;
}
});

let main_texture_handle = get_or_create_texture(render_ctx, hash(tensor.id()), || {
let main_texture_handle = try_get_or_create_texture(render_ctx, hash(tensor.id()), || {
general_texture_creation_desc_from_tensor(debug_name, tensor)
})?;

Expand Down Expand Up @@ -214,7 +211,7 @@ fn depth_tensor_to_gpu(
);
let (min, max) = depth_tensor_range(tensor, tensor_stats)?;

let texture = get_or_create_texture(render_ctx, hash(tensor.id()), || {
let texture = try_get_or_create_texture(render_ctx, hash(tensor.id()), || {
general_texture_creation_desc_from_tensor(debug_name, tensor)
})?;

Expand Down
2 changes: 1 addition & 1 deletion crates/re_viewer/src/ui/view_tensor/tensor_slice_to_gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fn upload_texture_slice_to_gpu(
) -> Result<re_renderer::resource_managers::GpuTexture2DHandle, TensorUploadError> {
let id = egui::util::hash((tensor.id(), slice_selection));

crate::gpu_bridge::get_or_create_texture(render_ctx, id, || {
crate::gpu_bridge::try_get_or_create_texture(render_ctx, id, || {
texture_desc_from_tensor(tensor, slice_selection)
})
}
Expand Down
87 changes: 82 additions & 5 deletions crates/re_viewer/src/ui/view_tensor/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl ViewTensorState {
Some(ctx.cache.tensor_stats(tensor)),
);
self.texture_settings.ui(ctx.re_ui, ui);
self.color_mapping.ui(ctx.re_ui, ui);
self.color_mapping.ui(ctx.render_ctx, ctx.re_ui, ui);
});

ui.separator();
Expand Down Expand Up @@ -245,17 +245,29 @@ impl Default for ColorMapping {
}

impl ColorMapping {
fn ui(&mut self, re_ui: &re_ui::ReUi, ui: &mut egui::Ui) {
fn ui(
&mut self,
render_ctx: &mut re_renderer::RenderContext,
re_ui: &re_ui::ReUi,
ui: &mut egui::Ui,
) {
let ColorMapping { map, gamma } = self;

re_ui.grid_left_hand_label(ui, "Color map");
egui::ComboBox::from_id_source("color map select")
.selected_text(map.to_string())
.show_ui(ui, |ui| {
ui.style_mut().wrap = Some(false);
for option in Colormap::ALL {
ui.selectable_value(map, option, option.to_string());
}

egui::Grid::new("colormap_selector")
.num_columns(2)
.show(ui, |ui| {
for option in Colormap::ALL {
ui.selectable_value(map, option, option.to_string());
colormap_preview_ui(render_ctx, ui, option);
ui.end_row();
}
});
});
ui.end_row();

Expand All @@ -267,6 +279,71 @@ impl ColorMapping {
}
}

/// Show the given colormap as a horizontal bar.
fn colormap_preview_ui(
render_ctx: &mut re_renderer::RenderContext,
ui: &mut egui::Ui,
colormap: Colormap,
) -> egui::Response {
crate::profile_function!();

let desired_size = egui::vec2(128.0, 16.0);
let (rect, response) = ui.allocate_exact_size(desired_size, egui::Sense::hover());

if ui.is_rect_visible(rect) {
if let Err(err) = paint_colormap_gradient(render_ctx, colormap, ui, rect) {
re_log::error_once!("Failed to paint colormap preview: {err}");
}
}

response
}

fn paint_colormap_gradient(
render_ctx: &mut re_renderer::RenderContext,
colormap: Colormap,
ui: &mut egui::Ui,
rect: egui::Rect,
) -> anyhow::Result<()> {
let horizontal_gradient_id = egui::util::hash("horizontal_gradient");
let horizontal_gradient =
crate::gpu_bridge::get_or_create_texture(render_ctx, horizontal_gradient_id, || {
let width = 256;
let height = 1;
let data: Vec<u8> = (0..width)
.flat_map(|x| {
let t = x as f32 / (width as f32 - 1.0);
half::f16::from_f32(t).to_le_bytes()
})
.collect();

re_renderer::resource_managers::Texture2DCreationDesc {
label: "horizontal_gradient".into(),
data: data.into(),
format: wgpu::TextureFormat::R16Float,
width,
height,
}
});

let colormapped_texture = re_renderer::renderer::ColormappedTexture {
texture: horizontal_gradient,
range: [0.0, 1.0],
gamma: 1.0,
color_mapper: Some(re_renderer::renderer::ColorMapper::Function(colormap)),
};

let debug_name = format!("colormap_{colormap}");
crate::gpu_bridge::render_image(
render_ctx,
ui.painter(),
rect,
colormapped_texture,
egui::TextureOptions::LINEAR,
&debug_name,
)
}

// ----------------------------------------------------------------------------

/// Should we scale the rendered texture, and if so, how?
Expand Down

1 comment on commit beffbc3

@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: beffbc3 Previous: fe7ac0e Ratio
datastore/num_rows=1000/num_instances=1000/packed=false/insert/default 2877636 ns/iter (± 62881) 2819827 ns/iter (± 142144) 1.02
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at/default 372 ns/iter (± 5) 371 ns/iter (± 1) 1.00
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/primary/default 262 ns/iter (± 0) 307 ns/iter (± 0) 0.85
datastore/num_rows=1000/num_instances=1000/packed=false/latest_at_missing/secondaries/default 422 ns/iter (± 0) 431 ns/iter (± 2) 0.98
datastore/num_rows=1000/num_instances=1000/packed=false/range/default 3055292 ns/iter (± 80869) 2917031 ns/iter (± 39259) 1.05
datastore/num_rows=1000/num_instances=1000/gc/default 2426490 ns/iter (± 5620) 2424218 ns/iter (± 8074) 1.00
mono_points_arrow/generate_message_bundles 28560983 ns/iter (± 397414) 27021462 ns/iter (± 779940) 1.06
mono_points_arrow/generate_messages 114092789 ns/iter (± 866742) 113254286 ns/iter (± 873559) 1.01
mono_points_arrow/encode_log_msg 146171056 ns/iter (± 1264660) 143335168 ns/iter (± 735831) 1.02
mono_points_arrow/encode_total 287725342 ns/iter (± 1634449) 286108476 ns/iter (± 1191559) 1.01
mono_points_arrow/decode_log_msg 178510582 ns/iter (± 706333) 177959619 ns/iter (± 698319) 1.00
mono_points_arrow/decode_message_bundles 60513277 ns/iter (± 545427) 59357561 ns/iter (± 946158) 1.02
mono_points_arrow/decode_total 237899745 ns/iter (± 1140028) 235592840 ns/iter (± 1059523) 1.01
mono_points_arrow_batched/generate_message_bundles 23595041 ns/iter (± 1285668) 21794503 ns/iter (± 938392) 1.08
mono_points_arrow_batched/generate_messages 4529912 ns/iter (± 293322) 4290676 ns/iter (± 213744) 1.06
mono_points_arrow_batched/encode_log_msg 1380953 ns/iter (± 3357) 1376610 ns/iter (± 2566) 1.00
mono_points_arrow_batched/encode_total 30155636 ns/iter (± 1228395) 27696912 ns/iter (± 1063716) 1.09
mono_points_arrow_batched/decode_log_msg 782504 ns/iter (± 3329) 779502 ns/iter (± 1468) 1.00
mono_points_arrow_batched/decode_message_bundles 7674332 ns/iter (± 314277) 7594364 ns/iter (± 72975) 1.01
mono_points_arrow_batched/decode_total 8905489 ns/iter (± 340569) 8466092 ns/iter (± 84815) 1.05
batch_points_arrow/generate_message_bundles 193693 ns/iter (± 413) 193610 ns/iter (± 519) 1.00
batch_points_arrow/generate_messages 5098 ns/iter (± 9) 5089 ns/iter (± 34) 1.00
batch_points_arrow/encode_log_msg 259276 ns/iter (± 1454) 259391 ns/iter (± 2214) 1.00
batch_points_arrow/encode_total 487673 ns/iter (± 1840) 489148 ns/iter (± 1640) 1.00
batch_points_arrow/decode_log_msg 211534 ns/iter (± 994) 213390 ns/iter (± 560) 0.99
batch_points_arrow/decode_message_bundles 1900 ns/iter (± 3) 1890 ns/iter (± 10) 1.01
batch_points_arrow/decode_total 219596 ns/iter (± 907) 220726 ns/iter (± 615) 0.99
arrow_mono_points/insert 2306524156 ns/iter (± 6595048) 2301868154 ns/iter (± 5781112) 1.00
arrow_mono_points/query 1193517 ns/iter (± 10357) 1201539 ns/iter (± 6948) 0.99
arrow_batch_points/insert 1147408 ns/iter (± 6110) 1152832 ns/iter (± 6155) 1.00
arrow_batch_points/query 14360 ns/iter (± 113) 14392 ns/iter (± 103) 1.00
arrow_batch_vecs/insert 26264 ns/iter (± 341) 26380 ns/iter (± 81) 1.00
arrow_batch_vecs/query 326125 ns/iter (± 785) 325263 ns/iter (± 737) 1.00
tuid/Tuid::random 34 ns/iter (± 0) 34 ns/iter (± 0) 1

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

Please sign in to comment.