From 82ddb0d3094c7e812548d0cde9a7ce876c8b3c7b Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Wed, 11 Jun 2025 18:25:27 -0700 Subject: [PATCH 1/3] Add query_size_lod and query_size methods to SampledImage - Add query_size_lod for non-multisampled sampled images (Sampled=1) - Add query_size for multisampled sampled images - Add missing HasQuerySize trait implementations for Sampled::Yes - Add tests for both methods --- crates/spirv-std/src/image.rs | 88 +++++++++++++++++++ .../sampled_image_multisampled_query_size.rs | 17 ++++ .../image/query/sampled_image_query_size.rs | 27 ++++++ 3 files changed, 132 insertions(+) create mode 100644 tests/compiletests/ui/image/query/sampled_image_multisampled_query_size.rs create mode 100644 tests/compiletests/ui/image/query/sampled_image_query_size.rs diff --git a/crates/spirv-std/src/image.rs b/crates/spirv-std/src/image.rs index e37fe641df4..6bc1cc4fa1c 100644 --- a/crates/spirv-std/src/image.rs +++ b/crates/spirv-std/src/image.rs @@ -1117,6 +1117,94 @@ impl< } result.truncate_into() } + + /// Query the dimensions of the image at the specified level of detail. + #[crate::macros::gpu_only] + #[doc(alias = "OpImageQuerySizeLod")] + pub fn query_size_lod + Default>( + &self, + lod: u32, + ) -> Size + where + Image< + SampledType, + DIM, + DEPTH, + ARRAYED, + { Multisampled::False as u32 }, + SAMPLED, + FORMAT, + COMPONENTS, + >: HasQuerySizeLod, + { + let mut result: Size = Default::default(); + unsafe { + asm! { + "%sampledImage = OpLoad _ {this}", + "%image = OpImage _ %sampledImage", + "%result = OpImageQuerySizeLod typeof*{result} %image {lod}", + "OpStore {result} %result", + this = in(reg) self, + lod = in(reg) lod, + result = in(reg) &mut result, + } + } + result + } +} + +impl< + SampledType: SampleType, + const DIM: u32, + const DEPTH: u32, + const ARRAYED: u32, + const SAMPLED: u32, + const FORMAT: u32, + const COMPONENTS: u32, +> + SampledImage< + Image< + SampledType, + DIM, + DEPTH, + ARRAYED, + { Multisampled::True as u32 }, + SAMPLED, + FORMAT, + COMPONENTS, + >, + > +{ + /// Query the dimensions of the image, with no level of detail. + /// Available only for multisampled images. + #[crate::macros::gpu_only] + #[doc(alias = "OpImageQuerySize")] + pub fn query_size + Default>(&self) -> Size + where + Image< + SampledType, + DIM, + DEPTH, + ARRAYED, + { Multisampled::True as u32 }, + SAMPLED, + FORMAT, + COMPONENTS, + >: HasQuerySize, + { + let mut result: Size = Default::default(); + unsafe { + asm! { + "%sampledImage = OpLoad _ {this}", + "%image = OpImage _ %sampledImage", + "%result = OpImageQuerySize typeof*{result} %image", + "OpStore {result} %result", + this = in(reg) self, + result = in(reg) &mut result, + } + } + result + } } /// Helper trait that defines all `*_with` methods on an `Image` that use the extra image operands, diff --git a/tests/compiletests/ui/image/query/sampled_image_multisampled_query_size.rs b/tests/compiletests/ui/image/query/sampled_image_multisampled_query_size.rs new file mode 100644 index 00000000000..08bebd41215 --- /dev/null +++ b/tests/compiletests/ui/image/query/sampled_image_multisampled_query_size.rs @@ -0,0 +1,17 @@ +// Test `OpImageQuerySize` on multisampled `SampledImage` +// build-pass +// compile-flags: -C target-feature=+ImageQuery + +use spirv_std::spirv; +use spirv_std::{Image, arch, image::SampledImage}; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] sampled_image2d_ms: &SampledImage< + Image!(2D, type=f32, multisampled, sampled), + >, + output: &mut glam::UVec2, +) { + // Multisampled sampled images can use query_size directly + *output = sampled_image2d_ms.query_size(); +} diff --git a/tests/compiletests/ui/image/query/sampled_image_query_size.rs b/tests/compiletests/ui/image/query/sampled_image_query_size.rs new file mode 100644 index 00000000000..b9242ab41c2 --- /dev/null +++ b/tests/compiletests/ui/image/query/sampled_image_query_size.rs @@ -0,0 +1,27 @@ +// Test `OpImageQuerySizeLod` on `SampledImage` +// build-pass +// compile-flags: -C target-feature=+ImageQuery + +use spirv_std::spirv; +use spirv_std::{Image, arch, image::SampledImage}; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] sampled_image2d: &SampledImage< + Image!(2D, type=f32, sampled), + >, + #[spirv(descriptor_set = 1, binding = 1)] sampled_image2d_array: &SampledImage< + Image!(2D, type=f32, arrayed, sampled), + >, + #[spirv(descriptor_set = 2, binding = 2)] sampled_image3d: &SampledImage< + Image!(3D, type=f32, sampled), + >, + output: &mut glam::UVec3, +) { + // For sampled images, we need to use query_size_lod + let size_2d: glam::UVec2 = sampled_image2d.query_size_lod(0); + let size_2d_array: glam::UVec3 = sampled_image2d_array.query_size_lod(0); + let size_3d: glam::UVec3 = sampled_image3d.query_size_lod(0); + + *output = glam::UVec3::new(size_2d.x, size_2d_array.y, size_3d.z); +} From 9075508b08efa63ef748ce5dfe92ecc8e1a3c0a6 Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Thu, 12 Jun 2025 00:34:38 -0700 Subject: [PATCH 2/3] Add `ImageSizeQuery` Without this cubemaps were broken...we were returning UVec3 but spirv validation required UVec2. --- crates/spirv-std/src/image.rs | 12 ++-- crates/spirv-std/src/image/params.rs | 65 +++++++++++++++++++ .../ui/image/query/cubemap_query_size.rs | 24 +++++++ .../ui/image/query/query_size_err.stderr | 2 +- .../ui/image/query/query_size_lod_err.stderr | 2 +- 5 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 tests/compiletests/ui/image/query/cubemap_query_size.rs diff --git a/crates/spirv-std/src/image.rs b/crates/spirv-std/src/image.rs index 6bc1cc4fa1c..59814a03d1a 100644 --- a/crates/spirv-std/src/image.rs +++ b/crates/spirv-std/src/image.rs @@ -10,7 +10,7 @@ mod params; /// Contains extra image operands pub mod sample_with; -pub use self::params::{ImageCoordinate, ImageCoordinateSubpassData, SampleType}; +pub use self::params::{ImageCoordinate, ImageCoordinateSubpassData, ImageSizeQuery, SampleType}; pub use crate::macros::Image; pub use spirv_std_types::image_params::{ AccessQualifier, Arrayed, Dimensionality, ImageDepth, ImageFormat, Multisampled, Sampled, @@ -933,7 +933,7 @@ impl< /// Query the dimensions of Image, with no level of detail. #[crate::macros::gpu_only] #[doc(alias = "OpImageQuerySize")] - pub fn query_size + Default>(&self) -> Size + pub fn query_size + Default>(&self) -> Size where Self: HasQuerySize, { @@ -971,10 +971,10 @@ impl< COMPONENTS, > { - /// Query the dimensions of Image, with no level of detail. + /// Query the dimensions of Image at a specific level of detail. #[crate::macros::gpu_only] #[doc(alias = "OpImageQuerySizeLod")] - pub fn query_size_lod + Default>( + pub fn query_size_lod + Default>( &self, lod: u32, ) -> Size @@ -1121,7 +1121,7 @@ impl< /// Query the dimensions of the image at the specified level of detail. #[crate::macros::gpu_only] #[doc(alias = "OpImageQuerySizeLod")] - pub fn query_size_lod + Default>( + pub fn query_size_lod + Default>( &self, lod: u32, ) -> Size @@ -1179,7 +1179,7 @@ impl< /// Available only for multisampled images. #[crate::macros::gpu_only] #[doc(alias = "OpImageQuerySize")] - pub fn query_size + Default>(&self) -> Size + pub fn query_size + Default>(&self) -> Size where Image< SampledType, diff --git a/crates/spirv-std/src/image/params.rs b/crates/spirv-std/src/image/params.rs index c67873da8e3..ae6ec2c8e7e 100644 --- a/crates/spirv-std/src/image/params.rs +++ b/crates/spirv-std/src/image/params.rs @@ -194,3 +194,68 @@ impl, S: Scalar> pub trait ImageCoordinateSubpassData {} impl, I: Integer> ImageCoordinateSubpassData for V {} impl, I: Integer> ImageCoordinateSubpassData for V {} + +/// Marker trait for query size results based on image dimension and arraying. +/// +/// Unlike `ImageCoordinate`, this trait represents the SPIR-V size query results: +/// - 1D images return a scalar +/// - 2D/Cube/Rect images return 2 components (Cube returns face width/height) +/// - 3D images return 3 components +/// - Arrayed images add one component for the array size +pub trait ImageSizeQuery {} + +// 1D images +impl ImageSizeQuery + for T +{ +} +impl, T: Scalar> + ImageSizeQuery for V +{ +} + +// 2D images +impl, T: Scalar> + ImageSizeQuery for V +{ +} +impl, T: Scalar> + ImageSizeQuery for V +{ +} + +// 3D images +impl, T: Scalar> + ImageSizeQuery for V +{ +} +impl, T: Scalar> + ImageSizeQuery for V +{ +} + +// Cube images - returns 2D size (width/height of face) +impl, T: Scalar> + ImageSizeQuery for V +{ +} +impl, T: Scalar> + ImageSizeQuery for V +{ +} + +// Rect images +impl, T: Scalar> + ImageSizeQuery for V +{ +} +impl, T: Scalar> + ImageSizeQuery for V +{ +} + +// Buffer images +impl ImageSizeQuery + for T +{ +} diff --git a/tests/compiletests/ui/image/query/cubemap_query_size.rs b/tests/compiletests/ui/image/query/cubemap_query_size.rs new file mode 100644 index 00000000000..72210879ad2 --- /dev/null +++ b/tests/compiletests/ui/image/query/cubemap_query_size.rs @@ -0,0 +1,24 @@ +// build-pass +// compile-flags: -C target-feature=+ImageQuery + +use spirv_std::spirv; +use spirv_std::{Image, arch, image::Cubemap}; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] cubemap: &Cubemap, + #[spirv(descriptor_set = 1, binding = 1)] cubemap_array: &Image!(cube, type=f32, sampled, arrayed), + #[spirv(descriptor_set = 2, binding = 2)] storage_cubemap: &Image!(cube, type=f32, sampled=false), + output: &mut glam::UVec3, +) { + // Cubemaps return 2D size (width, height of one face) + let size: glam::UVec2 = cubemap.query_size_lod(0); + + // Arrayed cubemaps return 3D size (width, height, array_layers) + let size_array: glam::UVec3 = cubemap_array.query_size_lod(0); + + // Storage cubemaps can use query_size directly + let storage_size: glam::UVec2 = storage_cubemap.query_size(); + + *output = glam::UVec3::new(size.x, size_array.z, storage_size.x); +} diff --git a/tests/compiletests/ui/image/query/query_size_err.stderr b/tests/compiletests/ui/image/query/query_size_err.stderr index b35b9c1298c..4c3dca3c392 100644 --- a/tests/compiletests/ui/image/query/query_size_err.stderr +++ b/tests/compiletests/ui/image/query/query_size_err.stderr @@ -17,7 +17,7 @@ error[E0277]: the trait bound `Image: HasQuerySize` is note: required by a bound in `Image::::query_size` --> $SPIRV_STD_SRC/image.rs:938:15 | -936 | pub fn query_size + Default>(&self) -> Size +936 | pub fn query_size + Default>(&self) -> Size | ---------- required by a bound in this associated function 937 | where 938 | Self: HasQuerySize, diff --git a/tests/compiletests/ui/image/query/query_size_lod_err.stderr b/tests/compiletests/ui/image/query/query_size_lod_err.stderr index 20464eb29a3..1b097f3f9c0 100644 --- a/tests/compiletests/ui/image/query/query_size_lod_err.stderr +++ b/tests/compiletests/ui/image/query/query_size_lod_err.stderr @@ -12,7 +12,7 @@ error[E0277]: the trait bound `Image: HasQuerySizeLod` note: required by a bound in `Image::::query_size_lod` --> $SPIRV_STD_SRC/image.rs:982:15 | -977 | pub fn query_size_lod + Default>( +977 | pub fn query_size_lod + Default>( | -------------- required by a bound in this associated function ... 982 | Self: HasQuerySizeLod, From 84d80fa31ec1a89be45bc74a5538b21b052a7e71 Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Thu, 12 Jun 2025 05:29:17 -0700 Subject: [PATCH 3/3] Add other query cases to tests --- crates/spirv-std/src/image/params.rs | 2 +- .../ui/image/query/rect_image_query_size.rs | 24 +++++++++++ .../sampled_image_multisampled_query_size.rs | 1 - .../image/query/sampled_image_query_size.rs | 42 +++++++++++++++---- .../sampled_image_rect_query_size_lod_err.rs | 20 +++++++++ ...mpled_image_rect_query_size_lod_err.stderr | 23 ++++++++++ .../image/query/storage_image_query_size.rs | 28 +++++++++++++ 7 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 tests/compiletests/ui/image/query/rect_image_query_size.rs create mode 100644 tests/compiletests/ui/image/query/sampled_image_rect_query_size_lod_err.rs create mode 100644 tests/compiletests/ui/image/query/sampled_image_rect_query_size_lod_err.stderr create mode 100644 tests/compiletests/ui/image/query/storage_image_query_size.rs diff --git a/crates/spirv-std/src/image/params.rs b/crates/spirv-std/src/image/params.rs index ae6ec2c8e7e..b4da908e552 100644 --- a/crates/spirv-std/src/image/params.rs +++ b/crates/spirv-std/src/image/params.rs @@ -197,7 +197,7 @@ impl, I: Integer> ImageCoordinateSubpassData, + #[spirv(descriptor_set = 1, binding = 1)] sampled_image1d_array: &SampledImage< + Image!(1D, type=f32, arrayed, sampled), + >, + #[spirv(descriptor_set = 2, binding = 2)] sampled_image2d: &SampledImage< Image!(2D, type=f32, sampled), >, - #[spirv(descriptor_set = 1, binding = 1)] sampled_image2d_array: &SampledImage< + #[spirv(descriptor_set = 3, binding = 3)] sampled_image2d_array: &SampledImage< Image!(2D, type=f32, arrayed, sampled), >, - #[spirv(descriptor_set = 2, binding = 2)] sampled_image3d: &SampledImage< + #[spirv(descriptor_set = 4, binding = 4)] sampled_image3d: &SampledImage< Image!(3D, type=f32, sampled), >, - output: &mut glam::UVec3, + #[spirv(descriptor_set = 5, binding = 5)] sampled_image3d_array: &SampledImage< + Image!(3D, type=f32, arrayed, sampled), + >, + output: &mut glam::UVec4, ) { - // For sampled images, we need to use query_size_lod + // 1D images return scalar + let size_1d: u32 = sampled_image1d.query_size_lod(0); + + // 1D arrayed images return 2 components (width, array_layers) + let size_1d_array: glam::UVec2 = sampled_image1d_array.query_size_lod(0); + + // 2D images return 2 components let size_2d: glam::UVec2 = sampled_image2d.query_size_lod(0); + + // 2D arrayed images return 3 components let size_2d_array: glam::UVec3 = sampled_image2d_array.query_size_lod(0); + + // 3D images return 3 components let size_3d: glam::UVec3 = sampled_image3d.query_size_lod(0); - *output = glam::UVec3::new(size_2d.x, size_2d_array.y, size_3d.z); + // 3D arrayed images return 4 components (width, height, depth, array_layers) + let size_3d_array: glam::UVec4 = sampled_image3d_array.query_size_lod(0); + + *output = glam::UVec4::new( + size_1d, + size_1d_array.y, + size_2d.x + size_3d.z, + size_3d_array.w, + ); } diff --git a/tests/compiletests/ui/image/query/sampled_image_rect_query_size_lod_err.rs b/tests/compiletests/ui/image/query/sampled_image_rect_query_size_lod_err.rs new file mode 100644 index 00000000000..a1e64834993 --- /dev/null +++ b/tests/compiletests/ui/image/query/sampled_image_rect_query_size_lod_err.rs @@ -0,0 +1,20 @@ +// build-fail +// normalize-stderr-test "\S*/crates/spirv-std/src/" -> "$SPIRV_STD_SRC/" +// compile-flags: -C target-feature=+ImageQuery,+SampledRect +// ignore-vulkan1.0 +// ignore-vulkan1.1 +// ignore-vulkan1.1spv1.4 +// ignore-vulkan1.2 + +use spirv_std::{Image, arch, image::SampledImage, spirv}; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] rect_sampled: &SampledImage< + Image!(rect, type=f32, sampled), + >, + output: &mut glam::UVec2, +) { + // This should fail because rect images don't support query_size_lod + *output = rect_sampled.query_size_lod(0); +} diff --git a/tests/compiletests/ui/image/query/sampled_image_rect_query_size_lod_err.stderr b/tests/compiletests/ui/image/query/sampled_image_rect_query_size_lod_err.stderr new file mode 100644 index 00000000000..e4000bd415e --- /dev/null +++ b/tests/compiletests/ui/image/query/sampled_image_rect_query_size_lod_err.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `Image: HasQuerySizeLod` is not satisfied + --> $DIR/sampled_image_rect_query_size_lod_err.rs:19:28 + | +19 | *output = rect_sampled.query_size_lod(0); + | ^^^^^^^^^^^^^^ the trait `HasQuerySizeLod` is not implemented for `Image` + | + = help: the following other types implement trait `HasQuerySizeLod`: + Image + Image + Image + Image +note: required by a bound in `SampledImage::>::query_size_lod` + --> /image.rs:1138:12 + | +1124 | pub fn query_size_lod + Default>( + | -------------- required by a bound in this associated function +... +1138 | >: HasQuerySizeLod, + | ^^^^^^^^^^^^^^^ required by this bound in `SampledImage::>::query_size_lod` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/compiletests/ui/image/query/storage_image_query_size.rs b/tests/compiletests/ui/image/query/storage_image_query_size.rs new file mode 100644 index 00000000000..42234aebebd --- /dev/null +++ b/tests/compiletests/ui/image/query/storage_image_query_size.rs @@ -0,0 +1,28 @@ +// build-pass +// compile-flags: -C target-feature=+ImageQuery,+Sampled1D,+SampledBuffer + +use spirv_std::spirv; +use spirv_std::{Image, arch}; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] buffer_image: &Image!(buffer, type=f32, sampled=false), + #[spirv(descriptor_set = 1, binding = 1)] storage_1d: &Image!(1D, type=f32, sampled=false), + #[spirv(descriptor_set = 2, binding = 2)] storage_1d_array: &Image!(1D, type=f32, sampled=false, arrayed), + #[spirv(descriptor_set = 3, binding = 3)] storage_3d_array: &Image!(3D, type=f32, sampled=false, arrayed), + output: &mut glam::UVec4, +) { + // Buffer images return scalar (number of texels) + let buffer_size: u32 = buffer_image.query_size(); + + // 1D storage images return scalar + let size_1d: u32 = storage_1d.query_size(); + + // 1D arrayed storage images return 2 components + let size_1d_array: glam::UVec2 = storage_1d_array.query_size(); + + // 3D arrayed storage images return 4 components + let size_3d_array: glam::UVec4 = storage_3d_array.query_size(); + + *output = glam::UVec4::new(buffer_size, size_1d, size_1d_array.y, size_3d_array.w); +}