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

GPU colormapping, first step #1835

Merged
merged 31 commits into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
97d0e5b
Add TextureManager2D::get_or_create_with
emilk Apr 11, 2023
50aef30
Small code cleanup
emilk Apr 11, 2023
ec98f29
Add code to upload a Tensor to a GPU texture
emilk Apr 11, 2023
88494cf
Add helper method Tensor::image_height_width_depth
emilk Apr 11, 2023
8c487e1
Minor code cleanup (multiplicative_tint)
emilk Apr 11, 2023
1c7f3e3
Hook up color textures via the new path
emilk Apr 12, 2023
ffbced6
Refactor: introduce ColormappedTexture
emilk Apr 12, 2023
2aa9466
Start working on an uint sampler
emilk Apr 12, 2023
82d6208
merge fix
emilk Apr 12, 2023
51c8dda
Dumb colormapping of depth textures!
emilk Apr 12, 2023
408abcf
Use turbo for depth maps (and single-channel images :grimace:)
emilk Apr 12, 2023
0151766
Use grayscale for luminance
emilk Apr 12, 2023
5d8392a
ColorMap -> Colormap
emilk Apr 12, 2023
f66e52c
Apply annotation context colormaps
emilk Apr 12, 2023
3ee7b95
Support sint textures too
emilk Apr 12, 2023
f396122
cleanup
emilk Apr 12, 2023
11556cf
merge fix
emilk Apr 12, 2023
c9fa776
Fix RGB images
emilk Apr 12, 2023
add9991
More cleanup
emilk Apr 12, 2023
486fe33
Better error-handlign and nicer error message
emilk Apr 13, 2023
207be57
Clean up the SAMPLE_TYPE with constants
emilk Apr 13, 2023
7050459
Nicer shader interface
emilk Apr 13, 2023
965f85a
Better error handling
emilk Apr 13, 2023
d3897ff
Remove dead code
emilk Apr 13, 2023
96adb39
Self-review cleanup
emilk Apr 13, 2023
91512f2
Fix bug in shader when sampling sint textures
emilk Apr 13, 2023
2a0dac7
Use textureSampleLevel
emilk Apr 13, 2023
5c9471f
Apply a gamma to the image (unused as of now)
emilk Apr 13, 2023
57dca58
image_height_width_channels
emilk Apr 13, 2023
64ba7f2
fix various review comments
emilk Apr 13, 2023
117610f
Optimize narrow_f64_to_f32s: avoid one allocation
emilk Apr 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions crates/re_data_store/src/entity_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ impl ExtraQueryHistory {

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum ColorMap {
pub enum Colormap {
/// Perceptually even
Grayscale,
#[default]
Turbo,
Expand All @@ -150,15 +151,15 @@ pub enum ColorMap {
Inferno,
}

impl std::fmt::Display for ColorMap {
impl std::fmt::Display for Colormap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
ColorMap::Grayscale => "Grayscale",
ColorMap::Turbo => "Turbo",
ColorMap::Viridis => "Viridis",
ColorMap::Plasma => "Plasma",
ColorMap::Magma => "Magma",
ColorMap::Inferno => "Inferno",
Colormap::Grayscale => "Grayscale",
Colormap::Turbo => "Turbo",
Colormap::Viridis => "Viridis",
Colormap::Plasma => "Plasma",
Colormap::Magma => "Magma",
Colormap::Inferno => "Inferno",
})
}
}
Expand All @@ -167,23 +168,23 @@ impl std::fmt::Display for ColorMap {
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum ColorMapper {
/// Use a well-known color map, pre-implemented as a wgsl module.
ColorMap(ColorMap),
Colormap(Colormap),
// TODO(cmc): support textures.
// TODO(cmc): support custom transfer functions.
}

impl std::fmt::Display for ColorMapper {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ColorMapper::ColorMap(colormap) => colormap.fmt(f),
ColorMapper::Colormap(colormap) => colormap.fmt(f),
}
}
}

impl Default for ColorMapper {
#[inline]
fn default() -> Self {
Self::ColorMap(ColorMap::default())
Self::Colormap(Colormap::default())
}
}

Expand Down
17 changes: 17 additions & 0 deletions crates/re_log_types/src/component_types/tensor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,23 @@ impl Tensor {
self.shape.len()
}

/// If this tensor is shaped as an image, return the height, width, and depth of it.
pub fn image_height_width_depth(&self) -> Option<[u64; 3]> {
emilk marked this conversation as resolved.
Show resolved Hide resolved
if self.shape.len() == 2 {
Some([self.shape[0].size, self.shape[1].size, 1])
} else if self.shape.len() == 3 {
let depth = self.shape[2].size;
// gray, rgb, rgba
if matches!(depth, 1 | 3 | 4) {
Some([self.shape[0].size, self.shape[1].size, depth])
} else {
None
}
} else {
None
}
}

pub fn is_shaped_like_an_image(&self) -> bool {
self.num_dim() == 2
|| self.num_dim() == 3 && {
Expand Down
13 changes: 9 additions & 4 deletions crates/re_renderer/examples/2d.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use ecolor::Hsva;
use re_renderer::{
renderer::{
LineStripFlags, RectangleDrawData, TextureFilterMag, TextureFilterMin, TexturedRect,
ColormappedTexture, LineStripFlags, RectangleDrawData, TextureFilterMag, TextureFilterMin,
TexturedRect,
},
resource_managers::{GpuTexture2DHandle, Texture2DCreationDesc},
view_builder::{self, Projection, TargetConfiguration, ViewBuilder},
Expand Down Expand Up @@ -39,7 +40,7 @@ impl framework::Example for Render2D {
&mut re_ctx.gpu_resources.textures,
&Texture2DCreationDesc {
label: "rerun logo".into(),
data: &image_data,
data: image_data.into(),
format: wgpu::TextureFormat::Rgba8UnormSrgb,
width: rerun_logo.width(),
height: rerun_logo.height(),
Expand Down Expand Up @@ -196,7 +197,9 @@ impl framework::Example for Render2D {
top_left_corner_position: glam::vec3(500.0, 120.0, -0.05),
extent_u: self.rerun_logo_texture_width as f32 * image_scale * glam::Vec3::X,
extent_v: self.rerun_logo_texture_height as f32 * image_scale * glam::Vec3::Y,
texture: self.rerun_logo_texture.clone(),
colormapped_texture: ColormappedTexture::from_srgba_unorm(
self.rerun_logo_texture.clone(),
),
texture_filter_magnification: TextureFilterMag::Nearest,
texture_filter_minification: TextureFilterMin::Linear,
..Default::default()
Expand All @@ -210,7 +213,9 @@ impl framework::Example for Render2D {
),
extent_u: self.rerun_logo_texture_width as f32 * image_scale * glam::Vec3::X,
extent_v: self.rerun_logo_texture_height as f32 * image_scale * glam::Vec3::Y,
texture: self.rerun_logo_texture.clone(),
colormapped_texture: ColormappedTexture::from_srgba_unorm(
self.rerun_logo_texture.clone(),
),
texture_filter_magnification: TextureFilterMag::Linear,
texture_filter_minification: TextureFilterMin::Linear,
depth_offset: 1,
Expand Down
10 changes: 5 additions & 5 deletions crates/re_renderer/examples/depth_cloud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use itertools::Itertools;
use macaw::IsoTransform;
use re_renderer::{
renderer::{
DepthCloud, DepthCloudDepthData, DepthCloudDrawData, DepthClouds, DrawData,
GenericSkyboxDrawData, RectangleDrawData, TexturedRect,
ColormappedTexture, DepthCloud, DepthCloudDepthData, DepthCloudDrawData, DepthClouds,
DrawData, GenericSkyboxDrawData, RectangleDrawData, TexturedRect,
},
resource_managers::{GpuTexture2DHandle, Texture2DCreationDesc},
view_builder::{self, Projection, ViewBuilder},
Expand Down Expand Up @@ -181,7 +181,7 @@ impl RenderDepthClouds {
max_depth_in_world: 5.0,
depth_dimensions: depth.dimensions,
depth_data: depth.data.clone(),
colormap: re_renderer::ColorMap::ColorMapTurbo,
colormap: re_renderer::Colormap::Turbo,
outline_mask_id: Default::default(),
}],
radius_boost_in_ui_points_for_outlines: 2.5,
Expand Down Expand Up @@ -243,7 +243,7 @@ impl framework::Example for RenderDepthClouds {
&mut re_ctx.gpu_resources.textures,
&Texture2DCreationDesc {
label: "albedo".into(),
data: bytemuck::cast_slice(&albedo.rgba8),
data: bytemuck::cast_slice(&albedo.rgba8).into(),
format: wgpu::TextureFormat::Rgba8UnormSrgb,
width: albedo.dimensions.x,
height: albedo.dimensions.y,
Expand Down Expand Up @@ -329,7 +329,7 @@ impl framework::Example for RenderDepthClouds {
.transform_point3(glam::Vec3::new(1.0, 1.0, 0.0)),
extent_u: world_from_model.transform_vector3(-glam::Vec3::X),
extent_v: world_from_model.transform_vector3(-glam::Vec3::Y),
texture: albedo_handle.clone(),
colormapped_texture: ColormappedTexture::from_srgba_unorm(albedo_handle.clone()),
texture_filter_magnification: re_renderer::renderer::TextureFilterMag::Nearest,
texture_filter_minification: re_renderer::renderer::TextureFilterMin::Linear,
multiplicative_tint: Rgba::from_white_alpha(0.5),
Expand Down
20 changes: 11 additions & 9 deletions crates/re_renderer/shader/colormap.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@
#import <./utils/srgb.wgsl>

// NOTE: Keep in sync with `colormap.rs`!
const GRAYSCALE: u32 = 0u;
const COLORMAP_TURBO: u32 = 1u;
const COLORMAP_VIRIDIS: u32 = 2u;
const COLORMAP_PLASMA: u32 = 3u;
const COLORMAP_MAGMA: u32 = 4u;
const COLORMAP_INFERNO: u32 = 5u;
const COLORMAP_GRAYSCALE: u32 = 1u;
const COLORMAP_TURBO: u32 = 2u;
const COLORMAP_VIRIDIS: u32 = 3u;
const COLORMAP_PLASMA: u32 = 4u;
const COLORMAP_MAGMA: u32 = 5u;
const COLORMAP_INFERNO: u32 = 6u;

/// Returns a gamma-space sRGB in 0-1 range.
///
/// The input will be saturated to [0, 1] range.
fn colormap_srgb(which: u32, t: f32) -> Vec3 {
if which == COLORMAP_TURBO {
if which == COLORMAP_GRAYSCALE {
return linear_from_srgb(Vec3(t));
} else if which == COLORMAP_TURBO {
return colormap_turbo_srgb(t);
} else if which == COLORMAP_VIRIDIS {
return colormap_viridis_srgb(t);
Expand All @@ -23,8 +25,8 @@ fn colormap_srgb(which: u32, t: f32) -> Vec3 {
return colormap_magma_srgb(t);
} else if which == COLORMAP_INFERNO {
return colormap_inferno_srgb(t);
} else { // assume grayscale
return linear_from_srgb(Vec3(t));
} else {
return ERROR_RGBA.rgb;
}
}

Expand Down
76 changes: 73 additions & 3 deletions crates/re_renderer/shader/rectangle.wgsl
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
#import <./types.wgsl>
#import <./colormap.wgsl>
#import <./global_bindings.wgsl>
#import <./utils/depth_offset.wgsl>

const SAMPLE_TYPE_FLOAT = 1u;
const SAMPLE_TYPE_SINT = 2u;
const SAMPLE_TYPE_UINT = 3u;

const COLOR_MAPPER_OFF = 1u;
const COLOR_MAPPER_FUNCTION = 2u;
const COLOR_MAPPER_TEXTURE = 3u;

struct UniformBuffer {
/// Top left corner position in world space.
top_left_corner_position: Vec3,

/// Which colormap to use, if any
colormap_function: u32,

/// Vector that spans up the rectangle from its top left corner along the u axis of the texture.
extent_u: Vec3,

/// Which texture sample to use
sample_type: u32,

/// Vector that spans up the rectangle from its top left corner along the v axis of the texture.
extent_v: Vec3,

Expand All @@ -18,16 +33,31 @@ struct UniformBuffer {
multiplicative_tint: Vec4,

outline_mask: UVec2,

/// Range of the texture values.
/// Will be mapped to the [0, 1] range before we colormap.
range_min_max: Vec2,

color_mapper: u32,
};

@group(1) @binding(0)
var<uniform> rect_info: UniformBuffer;

@group(1) @binding(1)
var texture: texture_2d<f32>;
var texture_sampler: sampler;

@group(1) @binding(2)
var texture_sampler: sampler;
var texture_float: texture_2d<f32>;

@group(1) @binding(3)
var texture_sint: texture_2d<i32>;

@group(1) @binding(4)
var texture_uint: texture_2d<u32>;

@group(1) @binding(5)
var colormap_texture: texture_2d<f32>;


struct VertexOut {
Expand All @@ -50,7 +80,47 @@ fn vs_main(@builtin(vertex_index) v_idx: u32) -> VertexOut {

@fragment
fn fs_main(in: VertexOut) -> @location(0) Vec4 {
let texture_color = textureSample(texture, texture_sampler, in.texcoord);
let icoords = IVec2(in.texcoord * Vec2(textureDimensions(texture_uint).xy));
emilk marked this conversation as resolved.
Show resolved Hide resolved

// Sample the main texture:

var sampled_value: Vec4;
if rect_info.sample_type == SAMPLE_TYPE_FLOAT {
sampled_value = textureSample(texture_float, texture_sampler, in.texcoord);
emilk marked this conversation as resolved.
Show resolved Hide resolved
} else if rect_info.sample_type == SAMPLE_TYPE_SINT {
sampled_value = Vec4(textureLoad(texture_sint, icoords, 0));
} else if rect_info.sample_type == SAMPLE_TYPE_UINT {
sampled_value = Vec4(textureLoad(texture_uint, icoords, 0));
} else {
return ERROR_RGBA; // unknown sample type
}

// Normalize the sample:
let range = rect_info.range_min_max;
let normalized_value: Vec4 = (sampled_value - range.x) / (range.y - range.x);

// TODO(emilk): apply a user-specified gamma-curve here

// Apply colormap, if any:
var texture_color: Vec4;

if rect_info.color_mapper == COLOR_MAPPER_OFF {
texture_color = normalized_value;
} else if rect_info.color_mapper == COLOR_MAPPER_FUNCTION {
let rgb = colormap_linear(rect_info.colormap_function, normalized_value.r);
texture_color = Vec4(rgb, 1.0);
} else if rect_info.color_mapper == COLOR_MAPPER_TEXTURE {
let colormap_size = textureDimensions(colormap_texture).xy;
let color_index = normalized_value.r * f32(colormap_size.x * colormap_size.y);
// TODO(emilk): interpolate between neighboring colors for non-integral color indices
let color_index_i32 = i32(color_index);
let x = color_index_i32 % colormap_size.x;
let y = color_index_i32 / colormap_size.x;
texture_color = textureLoad(colormap_texture, IVec2(x, y), 0);
} else {
return ERROR_RGBA; // unknown color mapper
}

return texture_color * rect_info.multiplicative_tint;
}

Expand Down
4 changes: 4 additions & 0 deletions crates/re_renderer/shader/types.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,7 @@ const ONE = Vec4(1.0, 1.0, 1.0, 1.0);
// fn inf() -> f32 {
// return 1.0 / 0.0;
// }


/// The color to use when we encounter an error.
const ERROR_RGBA = Vec4(1.0, 0.0, 1.0, 1.0);
Copy link
Member

Choose a reason for hiding this comment

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

nice!

33 changes: 18 additions & 15 deletions crates/re_renderer/src/colormap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,28 @@ use glam::{Vec2, Vec3A, Vec4, Vec4Swizzles};
// ---

// NOTE: Keep in sync with `colormap.wgsl`!
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u32)]
pub enum ColorMap {
Grayscale = 0,
ColorMapTurbo = 1,
ColorMapViridis = 2,
ColorMapPlasma = 3,
ColorMapMagma = 4,
ColorMapInferno = 5,
pub enum Colormap {
// Reserve 0 for "disabled"
/// Perceptually even
#[default]
Grayscale = 1,
Turbo = 2,
Viridis = 3,
Plasma = 4,
Magma = 5,
Inferno = 6,
}

pub fn colormap_srgb(which: ColorMap, t: f32) -> [u8; 4] {
pub fn colormap_srgb(which: Colormap, t: f32) -> [u8; 4] {
match which {
ColorMap::Grayscale => grayscale_srgb(t),
ColorMap::ColorMapTurbo => colormap_turbo_srgb(t),
ColorMap::ColorMapViridis => colormap_viridis_srgb(t),
ColorMap::ColorMapPlasma => colormap_plasma_srgb(t),
ColorMap::ColorMapMagma => colormap_magma_srgb(t),
ColorMap::ColorMapInferno => colormap_inferno_srgb(t),
Colormap::Grayscale => grayscale_srgb(t),
Colormap::Turbo => colormap_turbo_srgb(t),
Colormap::Viridis => colormap_viridis_srgb(t),
Colormap::Plasma => colormap_plasma_srgb(t),
Colormap::Magma => colormap_magma_srgb(t),
Colormap::Inferno => colormap_inferno_srgb(t),
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/re_renderer/src/importer/gltf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub fn load_gltf_from_buffer(
format!("gltf image used by {texture_names} in {mesh_name}")
}
.into(),
data: &data,
data: data.into(),
format,
width: image.width,
height: image.height,
Expand Down
2 changes: 1 addition & 1 deletion crates/re_renderer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub use allocator::GpuReadbackIdentifier;
pub use color::Rgba32Unmul;
pub use colormap::{
colormap_inferno_srgb, colormap_magma_srgb, colormap_plasma_srgb, colormap_srgb,
colormap_turbo_srgb, colormap_viridis_srgb, grayscale_srgb, ColorMap,
colormap_turbo_srgb, colormap_viridis_srgb, grayscale_srgb, Colormap,
};
pub use context::RenderContext;
pub use debug_label::DebugLabel;
Expand Down
Loading