@@ -4,13 +4,14 @@ use std::borrow::Cow;
4
4
5
5
use anyhow:: Context as _;
6
6
use egui:: { Rangef , util:: hash} ;
7
+ use half:: f16;
7
8
use wgpu:: TextureFormat ;
8
9
9
10
use re_renderer:: {
10
11
RenderContext ,
11
12
device_caps:: DeviceCaps ,
12
13
pad_rgb_to_rgba,
13
- renderer:: { ColorMapper , ColormappedTexture , ShaderDecoding } ,
14
+ renderer:: { ColorMapper , ColormappedTexture , ShaderDecoding , TextureAlpha } ,
14
15
resource_managers:: {
15
16
ImageDataDesc , SourceImageDataFormat , YuvMatrixCoefficients , YuvPixelLayout , YuvRange ,
16
17
} ,
@@ -141,21 +142,25 @@ fn color_image_to_gpu(
141
142
ColorMapper :: OffRGB
142
143
} ;
143
144
144
- // Assume that the texture has a separate (non-pre-multiplied) alpha.
145
- // TODO(wumpf): There should be a way to specify whether a texture uses pre-multiplied alpha or not.
146
- let multiply_rgb_with_alpha = image_format. has_alpha ( ) ;
145
+ let texture_alpha = if image_format. has_alpha ( ) {
146
+ // Assume that the texture has a separate (non-pre-multiplied) alpha.
147
+ // TODO(wumpf): There should be a way to specify whether a texture uses pre-multiplied alpha or not.
148
+ TextureAlpha :: SeparateAlpha
149
+ } else {
150
+ TextureAlpha :: Opaque
151
+ } ;
147
152
148
153
let gamma = 1.0 ;
149
154
150
155
re_log:: trace_once!(
151
- "color_tensor_to_gpu {debug_name:?}, range: {range:?}, decode_srgb: {decode_srgb:?}, multiply_rgb_with_alpha : {multiply_rgb_with_alpha :?}, gamma: {gamma:?}, color_mapper: {color_mapper:?}" ,
156
+ "color_tensor_to_gpu {debug_name:?}, range: {range:?}, decode_srgb: {decode_srgb:?}, texture_alpha : {texture_alpha :?}, gamma: {gamma:?}, color_mapper: {color_mapper:?}" ,
152
157
) ;
153
158
154
159
Ok ( ColormappedTexture {
155
160
texture : texture_handle,
156
161
range : [ range. min , range. max ] ,
157
162
decode_srgb,
158
- multiply_rgb_with_alpha ,
163
+ texture_alpha ,
159
164
gamma,
160
165
color_mapper,
161
166
shader_decoding,
@@ -327,7 +332,7 @@ pub fn texture_creation_desc_from_color_image<'a>(
327
332
// Why not use `Rgba8UnormSrgb`? Because premul must happen _before_ sRGB decode, so we can't
328
333
// use a "Srgb-aware" texture like `Rgba8UnormSrgb` for RGBA.
329
334
( ColorModel :: RGB , ChannelDatatype :: U8 ) => (
330
- pad_rgb_to_rgba ( & image. buffer , u8 :: MAX ) . into ( ) ,
335
+ pad_rgb_to_rgba ( & image. buffer , 0 ) . into ( ) ,
331
336
SourceImageDataFormat :: WgpuCompatible ( TextureFormat :: Rgba8Unorm ) ,
332
337
) ,
333
338
( ColorModel :: RGBA , ChannelDatatype :: U8 ) => (
@@ -349,7 +354,7 @@ pub fn texture_creation_desc_from_color_image<'a>(
349
354
//
350
355
// See also [`required_shader_decode`] which lists this case as a format that does not need to be decoded.
351
356
( ColorModel :: BGR , ChannelDatatype :: U8 ) => {
352
- let padded_data = pad_rgb_to_rgba ( & image. buffer , u8 :: MAX ) . into ( ) ;
357
+ let padded_data = pad_rgb_to_rgba ( & image. buffer , 0 ) . into ( ) ;
353
358
let texture_format = if required_shader_decode ( device_caps, & image. format ) . is_some ( )
354
359
{
355
360
TextureFormat :: Rgba8Unorm
@@ -433,7 +438,7 @@ fn depth_image_to_gpu(
433
438
texture,
434
439
range : value_range,
435
440
decode_srgb : false ,
436
- multiply_rgb_with_alpha : false ,
441
+ texture_alpha : TextureAlpha :: Opaque ,
437
442
gamma : 1.0 ,
438
443
color_mapper : ColorMapper :: Function ( colormap_to_re_renderer ( colormap) ) ,
439
444
shader_decoding : None ,
@@ -509,7 +514,7 @@ fn segmentation_image_to_gpu(
509
514
texture : main_texture_handle,
510
515
range : [ 0.0 , ( colormap_width * colormap_height) as f32 ] ,
511
516
decode_srgb : false , // Setting this to true would affect the class ids, not the color they resolve to.
512
- multiply_rgb_with_alpha : false , // already premultiplied!
517
+ texture_alpha : TextureAlpha :: AlreadyPremultiplied ,
513
518
gamma : 1.0 ,
514
519
color_mapper : ColorMapper :: Texture ( colormap_texture_handle) ,
515
520
shader_decoding : None ,
@@ -562,37 +567,30 @@ fn general_texture_creation_desc_from_image<'a>(
562
567
// BGR->RGB conversion is done in the shader.
563
568
ColorModel :: RGB | ColorModel :: BGR => {
564
569
// There are no 3-channel textures in wgpu, so we need to pad to 4 channels.
565
- // What should we pad with? It depends on whether or not the shader interprets these as alpha.
566
- // To be safe, we pad with the MAX value of integers, and with 1.0 for floats.
567
- // TODO(emilk): tell the shader to ignore the alpha channel instead!
570
+ // What should we pad with?
571
+ // It doesn't matter - we tell the shader to ignore the alpha channel.
568
572
569
573
match datatype {
570
- ChannelDatatype :: U8 => (
571
- pad_rgb_to_rgba ( buf, u8:: MAX ) . into ( ) ,
572
- TextureFormat :: Rgba8Uint ,
573
- ) ,
574
- ChannelDatatype :: U16 => ( pad_cast_img ( image, u16:: MAX ) , TextureFormat :: Rgba16Uint ) ,
575
- ChannelDatatype :: U32 => ( pad_cast_img ( image, u32:: MAX ) , TextureFormat :: Rgba32Uint ) ,
574
+ ChannelDatatype :: U8 => ( pad_rgb_to_rgba ( buf, 0 ) . into ( ) , TextureFormat :: Rgba8Uint ) ,
575
+ ChannelDatatype :: U16 => ( pad_cast_img :: < u16 > ( image) , TextureFormat :: Rgba16Uint ) ,
576
+ ChannelDatatype :: U32 => ( pad_cast_img :: < u32 > ( image) , TextureFormat :: Rgba32Uint ) ,
576
577
ChannelDatatype :: U64 => (
577
- pad_and_narrow_and_cast ( & image. to_slice ( ) , 1.0 , |x : u64 | x as f32 ) ,
578
+ pad_and_narrow_and_cast ( & image. to_slice ( ) , |x : u64 | x as f32 ) ,
578
579
TextureFormat :: Rgba32Float ,
579
580
) ,
580
581
581
- ChannelDatatype :: I8 => ( pad_cast_img ( image , i8 :: MAX ) , TextureFormat :: Rgba8Sint ) ,
582
- ChannelDatatype :: I16 => ( pad_cast_img ( image , i16 :: MAX ) , TextureFormat :: Rgba16Sint ) ,
583
- ChannelDatatype :: I32 => ( pad_cast_img ( image , i32 :: MAX ) , TextureFormat :: Rgba32Sint ) ,
582
+ ChannelDatatype :: I8 => ( pad_cast_img :: < i8 > ( image ) , TextureFormat :: Rgba8Sint ) ,
583
+ ChannelDatatype :: I16 => ( pad_cast_img :: < i16 > ( image ) , TextureFormat :: Rgba16Sint ) ,
584
+ ChannelDatatype :: I32 => ( pad_cast_img :: < i32 > ( image ) , TextureFormat :: Rgba32Sint ) ,
584
585
ChannelDatatype :: I64 => (
585
- pad_and_narrow_and_cast ( & image. to_slice ( ) , 1.0 , |x : i64 | x as f32 ) ,
586
+ pad_and_narrow_and_cast ( & image. to_slice ( ) , |x : i64 | x as f32 ) ,
586
587
TextureFormat :: Rgba32Float ,
587
588
) ,
588
589
589
- ChannelDatatype :: F16 => (
590
- pad_cast_img ( image, half:: f16:: from_f32 ( 1.0 ) ) ,
591
- TextureFormat :: Rgba16Float ,
592
- ) ,
593
- ChannelDatatype :: F32 => ( pad_cast_img ( image, 1.0_f32 ) , TextureFormat :: Rgba32Float ) ,
590
+ ChannelDatatype :: F16 => ( pad_cast_img :: < f16 > ( image) , TextureFormat :: Rgba16Float ) ,
591
+ ChannelDatatype :: F32 => ( pad_cast_img :: < f32 > ( image) , TextureFormat :: Rgba32Float ) ,
594
592
ChannelDatatype :: F64 => (
595
- pad_and_narrow_and_cast ( & image. to_slice ( ) , 1.0 , |x : f64 | x as f32 ) ,
593
+ pad_and_narrow_and_cast ( & image. to_slice ( ) , |x : f64 | x as f32 ) ,
596
594
TextureFormat :: Rgba32Float ,
597
595
) ,
598
596
}
@@ -675,29 +673,30 @@ fn narrow_f64_to_f32s(slice: &[f64]) -> Cow<'static, [u8]> {
675
673
}
676
674
677
675
/// Pad an RGB image to RGBA and cast the results to bytes.
678
- fn pad_and_cast < T : Copy + bytemuck:: Pod > ( data : & [ T ] , pad : T ) -> Cow < ' static , [ u8 ] > {
676
+ fn pad_and_cast < T : Copy + bytemuck:: Pod + Default > ( data : & [ T ] ) -> Cow < ' static , [ u8 ] > {
679
677
re_tracing:: profile_function!( ) ;
680
678
// TODO(emilk): optimize by combining the two steps into one; avoiding one allocation and memcpy
681
- let padded: Vec < T > = pad_rgb_to_rgba ( data, pad ) ;
679
+ let padded: Vec < T > = pad_rgb_to_rgba ( data, T :: default ( ) ) ;
682
680
let bytes: Vec < u8 > = bytemuck:: pod_collect_to_vec ( & padded) ;
683
681
bytes. into ( )
684
682
}
685
683
686
684
/// Pad an RGB image to RGBA and cast the results to bytes.
687
- fn pad_cast_img < T : Copy + bytemuck:: Pod > ( img : & ImageInfo , pad : T ) -> Cow < ' static , [ u8 ] > {
688
- pad_and_cast ( & img. to_slice ( ) , pad )
685
+ fn pad_cast_img < T : Copy + bytemuck:: Pod + Default > ( img : & ImageInfo ) -> Cow < ' static , [ u8 ] > {
686
+ pad_and_cast :: < T > ( & img. to_slice ( ) )
689
687
}
690
688
691
- fn pad_and_narrow_and_cast < T : Copy + bytemuck:: Pod > (
689
+ fn pad_and_narrow_and_cast < T : Copy + bytemuck:: Pod + Default > (
692
690
data : & [ T ] ,
693
- pad : f32 ,
694
691
narrow : impl Fn ( T ) -> f32 ,
695
692
) -> Cow < ' static , [ u8 ] > {
696
693
re_tracing:: profile_function!( ) ;
697
694
695
+ let alpha = 0.0 ; // The shader should just ignore it
696
+
698
697
let floats: Vec < f32 > = data
699
698
. chunks_exact ( 3 )
700
- . flat_map ( |chunk| [ narrow ( chunk[ 0 ] ) , narrow ( chunk[ 1 ] ) , narrow ( chunk[ 2 ] ) , pad ] )
699
+ . flat_map ( |chunk| [ narrow ( chunk[ 0 ] ) , narrow ( chunk[ 1 ] ) , narrow ( chunk[ 2 ] ) , alpha ] )
701
700
. collect ( ) ;
702
701
bytemuck:: pod_collect_to_vec ( & floats) . into ( )
703
702
}
0 commit comments