Change GpuImage::size from UVec2 to Extent3d (#16815)

# Objective

When preparing `GpuImage`s, we currently discard the
`depth_or_array_layers` of the `Image`'s size by converting it into a
`UVec2`.

Fixes #16715.

## Solution

Change `GpuImage::size` to `Extent3d`, and just pass that through when
creating `GpuImage`s.
Also copy the `aspect_ratio`, and `size` (now `size_2d` for
disambiguation from the field) functions from `Image` to `GpuImage` for
ease of use with 2D textures.
I originally copied all size-related functions (like `width`, and
`height`), but i think they are unnecessary considering how visible the
`size` field on `GpuImage` is compared to `Image`.

## Testing

Tested via `cargo r -p ci` for everything except docs, when generating
docs it keeps spitting out a ton of
```
error[E0554]: `#![feature]` may not be used on the stable release channel
 --> crates/bevy_dylib/src/lib.rs:1:21
  |
1 | #![cfg_attr(docsrs, feature(doc_auto_cfg))]
  | 
```
Not sure why this is happening, but it also happens without my changes,
so it's almost certainly some strange issue specific to my machine.

## Migration Guide

- `GpuImage::size` is now an `Extent3d`. To easily get 2D size, use
`size_2d()`.
This commit is contained in:
noxmore 2024-12-17 11:08:09 -08:00 committed by GitHub
parent bfa6553f9c
commit 73d68d60bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 43 additions and 40 deletions

View File

@ -1523,7 +1523,7 @@ impl FromWorld for MeshPipeline {
texture_view,
texture_format: image.texture_descriptor.format,
sampler,
size: image.size(),
size: image.texture_descriptor.size,
mip_level_count: image.texture_descriptor.mip_level_count,
}
};

View File

@ -23,7 +23,7 @@ use bevy_ecs::{
use bevy_image::{Image, TextureFormatPixelInfo};
use bevy_reflect::Reflect;
use bevy_render_macros::ExtractComponent;
use bevy_utils::{default, tracing::warn, HashMap};
use bevy_utils::{tracing::warn, HashMap};
use encase::internal::ReadFrom;
use encase::private::Reader;
use encase::ShaderType;
@ -239,17 +239,16 @@ fn prepare_buffers(
match readback {
Readback::Texture(image) => {
if let Some(gpu_image) = gpu_images.get(image) {
let size = Extent3d {
width: gpu_image.size.x,
height: gpu_image.size.y,
..default()
};
let layout = layout_data(size.width, size.height, gpu_image.texture_format);
let layout = layout_data(
gpu_image.size.width,
gpu_image.size.height,
gpu_image.texture_format,
);
let buffer = buffer_pool.get(
&render_device,
get_aligned_size(
size.width,
size.height,
gpu_image.size.width,
gpu_image.size.height,
gpu_image.texture_format.pixel_size() as u32,
) as u64,
);
@ -259,7 +258,7 @@ fn prepare_buffers(
src: ReadbackSource::Texture {
texture: gpu_image.texture.clone(),
layout,
size,
size: gpu_image.size,
},
buffer,
rx,

View File

@ -135,7 +135,7 @@ fn fallback_image_new(
texture_view,
texture_format: image.texture_descriptor.format,
sampler,
size: image.size(),
size: image.texture_descriptor.size,
mip_level_count: image.texture_descriptor.mip_level_count,
}
}

View File

@ -6,8 +6,8 @@ use crate::{
use bevy_asset::AssetId;
use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};
use bevy_image::{Image, ImageSampler};
use bevy_math::UVec2;
use wgpu::{TextureFormat, TextureViewDescriptor};
use bevy_math::{AspectRatio, UVec2};
use wgpu::{Extent3d, TextureFormat, TextureViewDescriptor};
/// The GPU-representation of an [`Image`].
/// Consists of the [`Texture`], its [`TextureView`] and the corresponding [`Sampler`], and the texture's size.
@ -17,7 +17,7 @@ pub struct GpuImage {
pub texture_view: TextureView,
pub texture_format: TextureFormat,
pub sampler: Sampler,
pub size: UVec2,
pub size: Extent3d,
pub mip_level_count: u32,
}
@ -53,7 +53,6 @@ impl RenderAsset for GpuImage {
&image.data,
);
let size = image.size();
let texture_view = texture.create_view(
image
.texture_view_descriptor
@ -73,8 +72,24 @@ impl RenderAsset for GpuImage {
texture_view,
texture_format: image.texture_descriptor.format,
sampler,
size,
size: image.texture_descriptor.size,
mip_level_count: image.texture_descriptor.mip_level_count,
})
}
}
impl GpuImage {
/// Returns the aspect ratio (width / height) of a 2D image.
#[inline]
pub fn aspect_ratio(&self) -> AspectRatio {
AspectRatio::try_from_pixels(self.size.width, self.size.height).expect(
"Failed to calculate aspect ratio: Image dimensions must be positive, non-zero values",
)
}
/// Returns the size of a 2D image.
#[inline]
pub fn size_2d(&self) -> UVec2 {
UVec2::new(self.size.width, self.size.height)
}
}

View File

@ -302,13 +302,8 @@ fn prepare_screenshots(
continue;
};
let format = gpu_image.texture_format;
let size = Extent3d {
width: gpu_image.size.x,
height: gpu_image.size.y,
..default()
};
let (texture_view, state) = prepare_screenshot_state(
size,
gpu_image.size,
format,
&render_device,
&screenshot_pipeline,
@ -542,8 +537,8 @@ pub(crate) fn submit_screenshot_commands(world: &World, encoder: &mut CommandEnc
warn!("Unknown image for screenshot, skipping: {:?}", image);
continue;
};
let width = gpu_image.size.x;
let height = gpu_image.size.y;
let width = gpu_image.size.width;
let height = gpu_image.size.height;
let texture_format = gpu_image.texture_format;
let texture_view = gpu_image.texture_view.deref();
render_screenshot(

View File

@ -313,7 +313,7 @@ impl FromWorld for Mesh2dPipeline {
texture_view,
texture_format: image.texture_descriptor.format,
sampler,
size: image.size(),
size: image.texture_descriptor.size,
mip_level_count: image.texture_descriptor.mip_level_count,
}
};

View File

@ -117,7 +117,7 @@ impl FromWorld for SpritePipeline {
texture_view,
texture_format: image.texture_descriptor.format,
sampler,
size: image.size(),
size: image.texture_descriptor.size,
mip_level_count: image.texture_descriptor.mip_level_count,
}
};
@ -676,7 +676,7 @@ pub fn prepare_sprite_image_bind_groups(
continue;
};
batch_image_size = gpu_image.size.as_vec2();
batch_image_size = gpu_image.size_2d().as_vec2();
batch_image_handle = extracted_sprite.image_handle_id;
image_bind_groups
.values

View File

@ -1052,7 +1052,7 @@ pub fn prepare_uinodes(
);
// Rescale atlases. This is done here because we need texture data that might not be available in Extract.
let atlas_extent = atlas_scaling
.map(|scaling| image.size.as_vec2() * scaling)
.map(|scaling| image.size_2d().as_vec2() * scaling)
.unwrap_or(uinode_rect.max);
if *flip_x {
core::mem::swap(&mut uinode_rect.max.x, &mut uinode_rect.min.x);
@ -1127,7 +1127,7 @@ pub fn prepare_uinodes(
.get(extracted_uinode.image)
.expect("Image was checked during batching and should still exist");
let atlas_extent = image.size.as_vec2() * *atlas_scaling;
let atlas_extent = image.size_2d().as_vec2() * *atlas_scaling;
let color = extracted_uinode.color.to_f32_array();
for glyph in &extracted_uinodes.glyphs[range.clone()] {

View File

@ -442,7 +442,7 @@ pub fn prepare_ui_slices(
if let Some(gpu_image) = gpu_images.get(texture_slices.image) {
batch_item_index = item_index;
batch_image_handle = texture_slices.image;
batch_image_size = gpu_image.size.as_vec2();
batch_image_size = gpu_image.size_2d().as_vec2();
let new_batch = UiTextureSlicerBatch {
range: vertices_index..vertices_index,
@ -475,7 +475,7 @@ pub fn prepare_ui_slices(
{
if let Some(gpu_image) = gpu_images.get(texture_slices.image) {
batch_image_handle = texture_slices.image;
batch_image_size = gpu_image.size.as_vec2();
batch_image_size = gpu_image.size_2d().as_vec2();
existing_batch.as_mut().unwrap().1.image = texture_slices.image;
image_bind_groups

View File

@ -367,15 +367,9 @@ impl render_graph::Node for ImageCopyDriver {
// That's why image in buffer can be little bit wider
// This should be taken into account at copy from buffer stage
let padded_bytes_per_row = RenderDevice::align_copy_bytes_per_row(
(src_image.size.x as usize / block_dimensions.0 as usize) * block_size as usize,
(src_image.size.width as usize / block_dimensions.0 as usize) * block_size as usize,
);
let texture_extent = Extent3d {
width: src_image.size.x,
height: src_image.size.y,
depth_or_array_layers: 1,
};
encoder.copy_texture_to_buffer(
src_image.texture.as_image_copy(),
ImageCopyBuffer {
@ -390,7 +384,7 @@ impl render_graph::Node for ImageCopyDriver {
rows_per_image: None,
},
},
texture_extent,
src_image.size,
);
let render_queue = world.get_resource::<RenderQueue>().unwrap();