From 73d68d60bbdd45b2db738877e0941cfdf391d455 Mon Sep 17 00:00:00 2001 From: noxmore <76889683+Noxmore@users.noreply.github.com> Date: Tue, 17 Dec 2024 11:08:09 -0800 Subject: [PATCH] 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()`. --- crates/bevy_pbr/src/render/mesh.rs | 2 +- crates/bevy_render/src/gpu_readback.rs | 19 +++++++------- .../bevy_render/src/texture/fallback_image.rs | 2 +- crates/bevy_render/src/texture/gpu_image.rs | 25 +++++++++++++++---- .../bevy_render/src/view/window/screenshot.rs | 11 +++----- crates/bevy_sprite/src/mesh2d/mesh.rs | 2 +- crates/bevy_sprite/src/render/mod.rs | 4 +-- crates/bevy_ui/src/render/mod.rs | 4 +-- .../src/render/ui_texture_slice_pipeline.rs | 4 +-- examples/app/headless_renderer.rs | 10 ++------ 10 files changed, 43 insertions(+), 40 deletions(-) diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index c81259dd7c46a..30e2a13c56ef4 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -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, } }; diff --git a/crates/bevy_render/src/gpu_readback.rs b/crates/bevy_render/src/gpu_readback.rs index bb0092edf15bf..d67db45e0986b 100644 --- a/crates/bevy_render/src/gpu_readback.rs +++ b/crates/bevy_render/src/gpu_readback.rs @@ -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, diff --git a/crates/bevy_render/src/texture/fallback_image.rs b/crates/bevy_render/src/texture/fallback_image.rs index b46ee1d1de3ef..fa61b88abfc8d 100644 --- a/crates/bevy_render/src/texture/fallback_image.rs +++ b/crates/bevy_render/src/texture/fallback_image.rs @@ -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, } } diff --git a/crates/bevy_render/src/texture/gpu_image.rs b/crates/bevy_render/src/texture/gpu_image.rs index 7be547a4a119f..f1ee1ade7e8f5 100644 --- a/crates/bevy_render/src/texture/gpu_image.rs +++ b/crates/bevy_render/src/texture/gpu_image.rs @@ -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) + } +} diff --git a/crates/bevy_render/src/view/window/screenshot.rs b/crates/bevy_render/src/view/window/screenshot.rs index 7912931df3ba0..5bc194878c4be 100644 --- a/crates/bevy_render/src/view/window/screenshot.rs +++ b/crates/bevy_render/src/view/window/screenshot.rs @@ -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( diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index d3e340a02c8b6..bc6a5e9556e94 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -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, } }; diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 32ad0d1647ecd..51e5f41b97fd1 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -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 diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index d299267f15697..f4fd9af02374e 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -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()] { diff --git a/crates/bevy_ui/src/render/ui_texture_slice_pipeline.rs b/crates/bevy_ui/src/render/ui_texture_slice_pipeline.rs index 0d1e5e81c73a2..657e4a95aef9c 100644 --- a/crates/bevy_ui/src/render/ui_texture_slice_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_texture_slice_pipeline.rs @@ -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 diff --git a/examples/app/headless_renderer.rs b/examples/app/headless_renderer.rs index 8fe2ef5871acf..2518a55c55515 100644 --- a/examples/app/headless_renderer.rs +++ b/examples/app/headless_renderer.rs @@ -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::().unwrap();