From 82ddb0d3094c7e812548d0cde9a7ce876c8b3c7b Mon Sep 17 00:00:00 2001
From: Christian Legnitto <christian@legnitto.com>
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 e37fe641df..6bc1cc4fa1 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<Size: ImageCoordinate<u32, DIM, ARRAYED> + 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<FORMAT, COMPONENTS>,
+    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<Size: ImageCoordinate<u32, DIM, ARRAYED> + 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 0000000000..08bebd4121
--- /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 0000000000..b9242ab41c
--- /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 <christian@legnitto.com>
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 6bc1cc4fa1..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<Size: ImageCoordinate<u32, DIM, ARRAYED> + Default>(&self) -> Size
+    pub fn query_size<Size: ImageSizeQuery<u32, DIM, ARRAYED> + 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<Size: ImageCoordinate<u32, DIM, ARRAYED> + Default>(
+    pub fn query_size_lod<Size: ImageSizeQuery<u32, DIM, ARRAYED> + 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<Size: ImageCoordinate<u32, DIM, ARRAYED> + Default>(
+    pub fn query_size_lod<Size: ImageSizeQuery<u32, DIM, ARRAYED> + 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<Size: ImageCoordinate<u32, DIM, ARRAYED> + Default>(&self) -> Size
+    pub fn query_size<Size: ImageSizeQuery<u32, DIM, ARRAYED> + 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 c67873da8e..ae6ec2c8e7 100644
--- a/crates/spirv-std/src/image/params.rs
+++ b/crates/spirv-std/src/image/params.rs
@@ -194,3 +194,68 @@ impl<V: Vector<S, 4>, S: Scalar>
 pub trait ImageCoordinateSubpassData<T, const ARRAYED: u32> {}
 impl<V: Vector<I, 2>, I: Integer> ImageCoordinateSubpassData<I, { Arrayed::False as u32 }> for V {}
 impl<V: Vector<I, 3>, I: Integer> ImageCoordinateSubpassData<I, { Arrayed::True as u32 }> 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<T, const DIM: u32, const ARRAYED: u32> {}
+
+// 1D images
+impl<T: Scalar> ImageSizeQuery<T, { Dimensionality::OneD as u32 }, { Arrayed::False as u32 }>
+    for T
+{
+}
+impl<V: Vector<T, 2>, T: Scalar>
+    ImageSizeQuery<T, { Dimensionality::OneD as u32 }, { Arrayed::True as u32 }> for V
+{
+}
+
+// 2D images
+impl<V: Vector<T, 2>, T: Scalar>
+    ImageSizeQuery<T, { Dimensionality::TwoD as u32 }, { Arrayed::False as u32 }> for V
+{
+}
+impl<V: Vector<T, 3>, T: Scalar>
+    ImageSizeQuery<T, { Dimensionality::TwoD as u32 }, { Arrayed::True as u32 }> for V
+{
+}
+
+// 3D images
+impl<V: Vector<T, 3>, T: Scalar>
+    ImageSizeQuery<T, { Dimensionality::ThreeD as u32 }, { Arrayed::False as u32 }> for V
+{
+}
+impl<V: Vector<T, 4>, T: Scalar>
+    ImageSizeQuery<T, { Dimensionality::ThreeD as u32 }, { Arrayed::True as u32 }> for V
+{
+}
+
+// Cube images - returns 2D size (width/height of face)
+impl<V: Vector<T, 2>, T: Scalar>
+    ImageSizeQuery<T, { Dimensionality::Cube as u32 }, { Arrayed::False as u32 }> for V
+{
+}
+impl<V: Vector<T, 3>, T: Scalar>
+    ImageSizeQuery<T, { Dimensionality::Cube as u32 }, { Arrayed::True as u32 }> for V
+{
+}
+
+// Rect images
+impl<V: Vector<T, 2>, T: Scalar>
+    ImageSizeQuery<T, { Dimensionality::Rect as u32 }, { Arrayed::False as u32 }> for V
+{
+}
+impl<V: Vector<T, 3>, T: Scalar>
+    ImageSizeQuery<T, { Dimensionality::Rect as u32 }, { Arrayed::True as u32 }> for V
+{
+}
+
+// Buffer images
+impl<T: Scalar> ImageSizeQuery<T, { Dimensionality::Buffer as u32 }, { Arrayed::False as u32 }>
+    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<f32, 1, 2, 0, 0, 1, 0, 4>: HasQuerySize` is
 note: required by a bound in `Image::<SampledType, DIM, DEPTH, ARRAYED, MULTISAMPLED, SAMPLED, FORMAT, COMPONENTS>::query_size`
    --> $SPIRV_STD_SRC/image.rs:938:15
     |
-936 |     pub fn query_size<Size: ImageCoordinate<u32, DIM, ARRAYED> + Default>(&self) -> Size
+936 |     pub fn query_size<Size: ImageSizeQuery<u32, DIM, ARRAYED> + 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<f32, 4, 2, 0, 0, 1, 0, 4>: HasQuerySizeLod`
 note: required by a bound in `Image::<SampledType, DIM, DEPTH, ARRAYED, spirv_std::::image::{impl#7}::{constant#0}, SAMPLED, FORMAT, COMPONENTS>::query_size_lod`
    --> $SPIRV_STD_SRC/image.rs:982:15
     |
-977 |     pub fn query_size_lod<Size: ImageCoordinate<u32, DIM, ARRAYED> + Default>(
+977 |     pub fn query_size_lod<Size: ImageSizeQuery<u32, DIM, ARRAYED> + Default>(
     |            -------------- required by a bound in this associated function
 ...
 982 |         Self: HasQuerySizeLod,

From 84d80fa31ec1a89be45bc74a5538b21b052a7e71 Mon Sep 17 00:00:00 2001
From: Christian Legnitto <christian@legnitto.com>
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 ae6ec2c8e7..b4da908e55 100644
--- a/crates/spirv-std/src/image/params.rs
+++ b/crates/spirv-std/src/image/params.rs
@@ -197,7 +197,7 @@ impl<V: Vector<I, 3>, I: Integer> ImageCoordinateSubpassData<I, { Arrayed::True
 
 /// Marker trait for query size results based on image dimension and arraying.
 ///
-/// Unlike `ImageCoordinate`, this trait represents the SPIR-V size query results:
+/// 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
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
index 08bebd4121..82ce6c07a2 100644
--- a/tests/compiletests/ui/image/query/sampled_image_multisampled_query_size.rs
+++ b/tests/compiletests/ui/image/query/sampled_image_multisampled_query_size.rs
@@ -1,4 +1,3 @@
-// Test `OpImageQuerySize` on multisampled `SampledImage`
 // build-pass
 // compile-flags: -C target-feature=+ImageQuery
 
diff --git a/tests/compiletests/ui/image/query/sampled_image_query_size.rs b/tests/compiletests/ui/image/query/sampled_image_query_size.rs
index b9242ab41c..fbde16285c 100644
--- a/tests/compiletests/ui/image/query/sampled_image_query_size.rs
+++ b/tests/compiletests/ui/image/query/sampled_image_query_size.rs
@@ -1,27 +1,53 @@
-// Test `OpImageQuerySizeLod` on `SampledImage`
 // build-pass
-// compile-flags: -C target-feature=+ImageQuery
+// 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_image2d: &SampledImage<
+    #[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 = 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 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<f32, 4, 2, 0, 0, 1, 0, 4>: 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<f32, 4, 2, 0, 0, 1, 0, 4>`
+     |
+     = help: the following other types implement trait `HasQuerySizeLod`:
+               Image<SampledType, 0, DEPTH, ARRAYED, 0, SAMPLED, FORMAT, COMPONENTS>
+               Image<SampledType, 1, DEPTH, ARRAYED, 0, SAMPLED, FORMAT, COMPONENTS>
+               Image<SampledType, 2, DEPTH, ARRAYED, 0, SAMPLED, FORMAT, COMPONENTS>
+               Image<SampledType, 3, DEPTH, ARRAYED, 0, SAMPLED, FORMAT, COMPONENTS>
+note: required by a bound in `SampledImage::<Image<SampledType, DIM, DEPTH, ARRAYED, spirv_std::::image::{impl#9}::{constant#0}, SAMPLED, FORMAT, COMPONENTS>>::query_size_lod`
+    --> /image.rs:1138:12
+     |
+1124 |     pub fn query_size_lod<Size: ImageSizeQuery<u32, DIM, ARRAYED> + Default>(
+     |            -------------- required by a bound in this associated function
+...
+1138 |         >: HasQuerySizeLod,
+     |            ^^^^^^^^^^^^^^^ required by this bound in `SampledImage::<Image<SampledType, DIM, DEPTH, ARRAYED, spirv_std::::image::{impl#9}::{constant#0}, SAMPLED, FORMAT, COMPONENTS>>::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);
+}