use wgpu TextureDataOrder (#19829)

# Objective

- Fixes #19140

## Solution

- Use TextureDataOrder

## Testing

- ran some examples that use ktx2 textures, they look fine
This commit is contained in:
atlv 2025-06-27 02:57:29 -04:00 committed by GitHub
parent 479c93d72b
commit 5fabb5343d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 15 additions and 38 deletions

View File

@ -447,6 +447,7 @@ pub fn lut_placeholder() -> Image {
let data = vec![255, 0, 255, 255];
Image {
data: Some(data),
data_order: TextureDataOrder::default(),
texture_descriptor: TextureDescriptor {
size: Extent3d::default(),
format,

View File

@ -18,8 +18,8 @@ use serde::{Deserialize, Serialize};
use thiserror::Error;
use wgpu_types::{
AddressMode, CompareFunction, Extent3d, Features, FilterMode, SamplerBorderColor,
SamplerDescriptor, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
TextureViewDescriptor,
SamplerDescriptor, TextureDataOrder, TextureDescriptor, TextureDimension, TextureFormat,
TextureUsages, TextureViewDescriptor,
};
/// Trait used to provide default values for Bevy-external types that
@ -372,6 +372,10 @@ pub struct Image {
/// CPU, then this should be `None`.
/// Otherwise, it should always be `Some`.
pub data: Option<Vec<u8>>,
/// For texture data with layers and mips, this field controls how wgpu interprets the buffer layout.
///
/// Use [`TextureDataOrder::default()`] for all other cases.
pub data_order: TextureDataOrder,
// TODO: this nesting makes accessing Image metadata verbose. Either flatten out descriptor or add accessors.
pub texture_descriptor: TextureDescriptor<Option<&'static str>, &'static [TextureFormat]>,
/// The [`ImageSampler`] to use during rendering.
@ -764,6 +768,7 @@ impl Image {
) -> Self {
Image {
data: None,
data_order: TextureDataOrder::default(),
texture_descriptor: TextureDescriptor {
size,
format,

View File

@ -238,43 +238,12 @@ pub fn ktx2_buffer_to_image(
)));
}
// Reorder data from KTX2 MipXLayerYFaceZ to wgpu LayerYFaceZMipX
let texture_format_info = texture_format;
let (block_width_pixels, block_height_pixels) = (
texture_format_info.block_dimensions().0 as usize,
texture_format_info.block_dimensions().1 as usize,
);
// Texture is not a depth or stencil format, it is possible to pass `None` and unwrap
let block_bytes = texture_format_info.block_copy_size(None).unwrap() as usize;
let mut wgpu_data = vec![Vec::default(); (layer_count * face_count) as usize];
for (level, level_data) in levels.iter().enumerate() {
let (level_width, level_height, level_depth) = (
(width as usize >> level).max(1),
(height as usize >> level).max(1),
(depth as usize >> level).max(1),
);
let (num_blocks_x, num_blocks_y) = (
level_width.div_ceil(block_width_pixels).max(1),
level_height.div_ceil(block_height_pixels).max(1),
);
let level_bytes = num_blocks_x * num_blocks_y * level_depth * block_bytes;
let mut index = 0;
for _layer in 0..layer_count {
for _face in 0..face_count {
let offset = index * level_bytes;
wgpu_data[index].extend_from_slice(&level_data[offset..(offset + level_bytes)]);
index += 1;
}
}
}
// Assign the data and fill in the rest of the metadata now the possible
// error cases have been handled
let mut image = Image::default();
image.texture_descriptor.format = texture_format;
image.data = Some(wgpu_data.into_iter().flatten().collect::<Vec<_>>());
image.data = Some(levels.into_iter().flatten().collect::<Vec<_>>());
image.data_order = wgpu_types::TextureDataOrder::MipMajor;
// Note: we must give wgpu the logical texture dimensions, so it can correctly compute mip sizes.
// However this currently causes wgpu to panic if the dimensions arent a multiple of blocksize.
// See https://github.com/gfx-rs/wgpu/issues/7677 for more context.

View File

@ -51,8 +51,7 @@ impl RenderAsset for GpuImage {
render_device.create_texture_with_data(
render_queue,
&image.texture_descriptor,
// TODO: Is this correct? Do we need to use `MipMajor` if it's a ktx2 file?
wgpu::util::TextureDataOrder::default(),
image.data_order,
data,
)
} else {

View File

@ -16,7 +16,9 @@ use bevy_math::{FloatOrd, UVec2, Vec2, Vec3};
use bevy_platform::collections::HashMap;
use bevy_render::{
mesh::{Indices, Mesh, Mesh2d, PrimitiveTopology},
render_resource::{TextureDescriptor, TextureDimension, TextureFormat, TextureUsages},
render_resource::{
TextureDataOrder, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
},
};
use tracing::warn;
@ -198,6 +200,7 @@ fn make_chunk_image(size: &UVec2, indices: &[Option<u16>]) -> Image {
.flat_map(|i| u16::to_ne_bytes(i.unwrap_or(u16::MAX)))
.collect(),
),
data_order: TextureDataOrder::default(),
texture_descriptor: TextureDescriptor {
size: size.to_extents(),
dimension: TextureDimension::D2,