Readback
: Add support for texture depth/array layers (#17479)
# Objective
Fixes #16963
## Solution
I am - no pun intended - somewhat out of my depth here but this worked
in my testing. The validation error is gone and the data read from the
GPU looks sensible. I'd greatly appreciate if somebody more familiar
with the matter could double-check this.
## References
Relevant documentation in
[WebGPU](https://gpuweb.github.io/gpuweb/#gputexelcopybufferlayout) and
[wgpu](https://github.com/gfx-rs/wgpu/blob/v23/wgpu-types/src/lib.rs#L6350).
## Testing
<details><summary>Example code for testing</summary>
<p>
```rust
use bevy::{
image::{self as bevy_image, TextureFormatPixelInfo},
prelude::*,
render::{
render_asset::RenderAssetUsages,
render_resource::{
Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
},
},
};
fn main() {
let mut app = App::new();
app.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, readback_system);
app.run();
}
#[derive(Resource)]
struct ImageResource(Handle<Image>);
const TEXTURE_HEIGHT: u32 = 64;
const TEXTURE_WIDTH: u32 = 32;
const TEXTURE_LAYERS: u32 = 4;
const FORMAT: TextureFormat = TextureFormat::Rgba8Uint;
fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
let layer_pixel_count = (TEXTURE_WIDTH * TEXTURE_HEIGHT) as usize;
let layer_size = layer_pixel_count * FORMAT.pixel_size();
let data: Vec<u8> = (0..TEXTURE_LAYERS as u8)
.flat_map(|layer| (0..layer_size).map(move |_| layer))
.collect();
let image_size = data.len();
println!("{image_size}");
let image = Image {
data,
texture_descriptor: TextureDescriptor {
label: Some("image"),
size: Extent3d {
width: TEXTURE_WIDTH,
height: TEXTURE_HEIGHT,
depth_or_array_layers: TEXTURE_LAYERS,
},
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
format: FORMAT,
usage: TextureUsages::COPY_DST | TextureUsages::COPY_SRC,
view_formats: &[],
},
sampler: bevy_image::ImageSampler::Default,
texture_view_descriptor: None,
asset_usage: RenderAssetUsages::RENDER_WORLD,
};
commands.insert_resource(ImageResource(images.add(image)));
}
fn readback_system(
mut commands: Commands,
keys: Res<ButtonInput<KeyCode>>,
image: Res<ImageResource>,
) {
if !keys.just_pressed(KeyCode::KeyR) {
return;
}
commands
.spawn(bevy::render::gpu_readback::Readback::Texture(
image.0.clone(),
))
.observe(
|trigger: Trigger<bevy::render::gpu_readback::ReadbackComplete>,
mut commands: Commands| {
info!("readback complete");
println!("{:#?}", &trigger.0);
commands.entity(trigger.observer()).despawn();
},
);
}
```
</p>
</details>