diff --git a/crates/spirv-std/src/image.rs b/crates/spirv-std/src/image.rs index e37fe641df..59814a03d1 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 @@ -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/crates/spirv-std/src/image/params.rs b/crates/spirv-std/src/image/params.rs index c67873da8e..b4da908e55 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. +/// +/// 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 0000000000..72210879ad --- /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 b35b9c1298..4c3dca3c39 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 20464eb29a..1b097f3f9c 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, diff --git a/tests/compiletests/ui/image/query/rect_image_query_size.rs b/tests/compiletests/ui/image/query/rect_image_query_size.rs new file mode 100644 index 0000000000..5d1a201f48 --- /dev/null +++ b/tests/compiletests/ui/image/query/rect_image_query_size.rs @@ -0,0 +1,24 @@ +// build-pass +// compile-flags: -C target-feature=+ImageQuery,+SampledRect +// ignore-vulkan1.0 +// ignore-vulkan1.1 +// ignore-vulkan1.1spv1.4 +// ignore-vulkan1.2 + +use spirv_std::spirv; +use spirv_std::{Image, arch}; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] rect_storage: &Image!(rect, type=f32, sampled=false), + #[spirv(descriptor_set = 1, binding = 1)] rect_storage_array: &Image!(rect, type=f32, sampled=false, arrayed), + output: &mut glam::UVec3, +) { + // Rect images only support query_size (not query_size_lod) + let rect_size: glam::UVec2 = rect_storage.query_size(); + + // Arrayed rect images return 3D size (width, height, array_layers) + let rect_array_size: glam::UVec3 = rect_storage_array.query_size(); + + *output = glam::UVec3::new(rect_size.x, rect_size.y, rect_array_size.z); +} 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 0000000000..82ce6c07a2 --- /dev/null +++ b/tests/compiletests/ui/image/query/sampled_image_multisampled_query_size.rs @@ -0,0 +1,16 @@ +// 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 0000000000..fbde16285c --- /dev/null +++ b/tests/compiletests/ui/image/query/sampled_image_query_size.rs @@ -0,0 +1,53 @@ +// build-pass +// compile-flags: -C target-feature=+ImageQuery,+Sampled1D + +use spirv_std::spirv; +use spirv_std::{Image, arch, image::SampledImage}; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] sampled_image1d: &SampledImage< + Image!(1D, type=f32, sampled), + >, + #[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 = 3, binding = 3)] sampled_image2d_array: &SampledImage< + Image!(2D, type=f32, arrayed, sampled), + >, + #[spirv(descriptor_set = 4, binding = 4)] sampled_image3d: &SampledImage< + Image!(3D, type=f32, sampled), + >, + #[spirv(descriptor_set = 5, binding = 5)] sampled_image3d_array: &SampledImage< + Image!(3D, type=f32, arrayed, sampled), + >, + output: &mut glam::UVec4, +) { + // 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); + + // 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 0000000000..a1e6483499 --- /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 0000000000..e4000bd415 --- /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 0000000000..42234aebeb --- /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); +}