use std::borrow::Cow;
#[derive(Clone, Debug)]
pub struct Texture2DBufferInfo {
pub bytes_per_row_unpadded: u32,
pub bytes_per_row_padded: u32,
pub buffer_size_unpadded: wgpu::BufferAddress,
pub buffer_size_padded: wgpu::BufferAddress,
}
impl Texture2DBufferInfo {
#[inline]
pub fn new(format: wgpu::TextureFormat, extent: wgpu::Extent3d) -> Self {
let block_dimensions = format.block_dimensions();
let width_blocks = extent.width / block_dimensions.0;
let height_blocks = extent.height / block_dimensions.1;
let block_size = format
.block_copy_size(Some(wgpu::TextureAspect::All))
.unwrap_or(0); let bytes_per_row_unpadded = width_blocks * block_size;
let bytes_per_row_padded =
wgpu::util::align_to(bytes_per_row_unpadded, wgpu::COPY_BYTES_PER_ROW_ALIGNMENT);
Self {
bytes_per_row_unpadded,
bytes_per_row_padded,
buffer_size_unpadded: (bytes_per_row_unpadded * height_blocks) as wgpu::BufferAddress,
buffer_size_padded: (bytes_per_row_padded * height_blocks) as wgpu::BufferAddress,
}
}
pub fn from_texture(texture: &wgpu::Texture) -> Self {
Self::new(texture.format(), texture.size())
}
#[inline]
pub fn num_rows(&self) -> u32 {
self.buffer_size_padded as u32 / self.bytes_per_row_padded
}
pub fn remove_padding<'a>(&self, buffer: &'a [u8]) -> Cow<'a, [u8]> {
re_tracing::profile_function!();
assert_eq!(buffer.len() as wgpu::BufferAddress, self.buffer_size_padded);
if self.bytes_per_row_padded == self.bytes_per_row_unpadded {
return Cow::Borrowed(buffer);
}
let mut unpadded_buffer = Vec::with_capacity(self.buffer_size_unpadded as _);
for row in 0..self.num_rows() {
let offset = (self.bytes_per_row_padded * row) as usize;
unpadded_buffer.extend_from_slice(
&buffer[offset..(offset + self.bytes_per_row_unpadded as usize)],
);
}
unpadded_buffer.into()
}
pub fn remove_padding_and_convert<T: bytemuck::Pod>(&self, buffer: &[u8]) -> Vec<T> {
re_tracing::profile_function!();
assert_eq!(buffer.len() as wgpu::BufferAddress, self.buffer_size_padded);
assert!(
self.bytes_per_row_unpadded
.is_multiple_of(std::mem::size_of::<T>() as u32)
);
let mut unpadded_buffer: Vec<T> = vec![
T::zeroed();
(self.num_rows() * self.bytes_per_row_unpadded / std::mem::size_of::<T>() as u32)
as usize
];
let unpadded_buffer_u8_view = bytemuck::cast_slice_mut(&mut unpadded_buffer);
for row in 0..self.num_rows() {
let offset_padded = (self.bytes_per_row_padded * row) as usize;
let offset_unpadded = (self.bytes_per_row_unpadded * row) as usize;
unpadded_buffer_u8_view
[offset_unpadded..(offset_unpadded + self.bytes_per_row_unpadded as usize)]
.copy_from_slice(
&buffer[offset_padded..(offset_padded + self.bytes_per_row_unpadded as usize)],
);
}
unpadded_buffer
}
}
pub fn is_float_filterable(format: wgpu::TextureFormat, device_features: wgpu::Features) -> bool {
format
.guaranteed_format_features(device_features)
.flags
.contains(wgpu::TextureFormatFeatureFlags::FILTERABLE)
}
pub fn sample_value_range(format: wgpu::TextureFormat) -> [f32; 2] {
use wgpu::TextureFormat as F;
#[expect(clippy::match_same_arms)]
match format {
F::R8Unorm
| F::Rg8Unorm
| F::Rgba8Unorm
| F::Rgba8UnormSrgb
| F::Bgra8Unorm
| F::Bgra8UnormSrgb => [0.0, 1.0],
F::R8Snorm | F::Rg8Snorm | F::Rgba8Snorm => [-1.0, 1.0],
F::R8Uint | F::Rg8Uint | F::Rgba8Uint => [0.0, u8::MAX as f32],
F::R8Sint | F::Rg8Sint | F::Rgba8Sint => [i8::MIN as f32, i8::MAX as f32],
F::R16Unorm | F::Rg16Unorm | F::Rgba16Unorm => [0.0, 1.0],
F::R16Snorm | F::Rg16Snorm | F::Rgba16Snorm => [-1.0, 1.0],
F::R16Uint | F::Rg16Uint | F::Rgba16Uint => [0.0, u16::MAX as f32],
F::R16Sint | F::Rg16Sint | F::Rgba16Sint => [i16::MIN as f32, i16::MAX as f32],
F::R16Float | F::Rg16Float | F::Rgba16Float => [0.0, 1.0],
F::R32Uint | F::Rg32Uint | F::Rgba32Uint | F::R64Uint => [0.0, u32::MAX as f32],
F::R32Sint | F::Rg32Sint | F::Rgba32Sint => [i32::MIN as f32, i32::MAX as f32],
F::R32Float | F::Rg32Float | F::Rgba32Float => [0.0, 1.0],
F::Rgb10a2Uint => [0.0, 1023.0],
F::Rgb10a2Unorm | F::Rg11b10Ufloat | F::Rgb9e5Ufloat => [0.0, 1.0],
F::Stencil8 => [0.0, u8::MAX as f32],
F::Depth16Unorm
| F::Depth24Plus
| F::Depth24PlusStencil8
| F::Depth32Float
| F::Depth32FloatStencil8 => [0.0, 1.0],
F::NV12 | F::P010 => [0.0, 1.0],
F::Bc1RgbaUnorm
| F::Bc1RgbaUnormSrgb
| F::Bc2RgbaUnorm
| F::Bc2RgbaUnormSrgb
| F::Bc3RgbaUnorm
| F::Bc3RgbaUnormSrgb
| F::Bc4RUnorm
| F::Bc5RgUnorm
| F::Bc6hRgbUfloat
| F::Bc6hRgbFloat
| F::Bc7RgbaUnorm
| F::Bc7RgbaUnormSrgb
| F::Etc2Rgb8Unorm
| F::Etc2Rgb8UnormSrgb
| F::Etc2Rgb8A1Unorm
| F::Etc2Rgb8A1UnormSrgb
| F::Etc2Rgba8Unorm
| F::Etc2Rgba8UnormSrgb
| F::EacR11Unorm
| F::EacRg11Unorm
| F::Astc { .. } => [0.0, 1.0],
F::Bc4RSnorm | F::Bc5RgSnorm | F::EacR11Snorm | F::EacRg11Snorm => [-1.0, 1.0],
}
}