diff --git a/crates/spirv-std/src/textures.rs b/crates/spirv-std/src/textures.rs index f7f8caf516..6a2a8003fe 100644 --- a/crates/spirv-std/src/textures.rs +++ b/crates/spirv-std/src/textures.rs @@ -46,6 +46,65 @@ impl Image2d { result } } + #[spirv_std_macros::gpu_only] + #[cfg(feature = "const-generics")] + /// Sample the image at a coordinate by a lod + pub fn sample_by_lod>( + &self, + sampler: Sampler, + coordinate: impl Vector, + lod: f32, + ) -> V { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%coordinate = OpLoad _ {coordinate}", + "%lod = OpLoad _ {lod}", + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleExplicitLod _ %sampledImage %coordinate Lod %lod", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + coordinate = in(reg) &coordinate, + lod = in(reg) &lod + ); + } + result + } + #[spirv_std_macros::gpu_only] + #[cfg(feature = "const-generics")] + /// Sample the image based on a gradient formed by (dx, dy). Specifically, ([du/dx, dv/dx], [du/dy, dv/dy]) + pub fn sample_by_gradient>( + &self, + sampler: Sampler, + coordinate: impl Vector, + gradient_dx: impl Vector, + gradient_dy: impl Vector, + ) -> V { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%coordinate = OpLoad _ {coordinate}", + "%gradient_dx = OpLoad _ {gradient_dx}", + "%gradient_dy = OpLoad _ {gradient_dy}", + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleExplicitLod _ %sampledImage %coordinate Grad %gradient_dx %gradient_dy", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + coordinate = in(reg) &coordinate, + gradient_dx = in(reg) &gradient_dx, + gradient_dy = in(reg) &gradient_dy, + ); + } + result + } /// Fetch a single texel with a sampler set at compile time #[spirv_std_macros::gpu_only] #[cfg(feature = "const-generics")] @@ -172,6 +231,65 @@ impl Image2dArray { result } } + #[spirv_std_macros::gpu_only] + #[cfg(feature = "const-generics")] + /// Sample the image at a coordinate by a lod + pub fn sample_by_lod>( + &self, + sampler: Sampler, + coordinate: impl Vector, + lod: f32, + ) -> V { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%coordinate = OpLoad _ {coordinate}", + "%lod = OpLoad _ {lod}", + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleExplicitLod _ %sampledImage %coordinate Lod %lod", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + coordinate = in(reg) &coordinate, + lod = in(reg) &lod + ); + } + result + } + #[spirv_std_macros::gpu_only] + #[cfg(feature = "const-generics")] + /// Sample the image based on a gradient formed by (dx, dy). Specifically, ([du/dx, dv/dx], [du/dy, dv/dy]) + pub fn sample_by_gradient>( + &self, + sampler: Sampler, + coordinate: impl Vector, + gradient_dx: impl Vector, + gradient_dy: impl Vector, + ) -> V { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%coordinate = OpLoad _ {coordinate}", + "%gradient_dx = OpLoad _ {gradient_dx}", + "%gradient_dy = OpLoad _ {gradient_dy}", + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleExplicitLod _ %sampledImage %coordinate Grad %gradient_dx %gradient_dy", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + coordinate = in(reg) &coordinate, + gradient_dx = in(reg) &gradient_dx, + gradient_dy = in(reg) &gradient_dy, + ); + } + result + } } #[spirv(sampled_image)] diff --git a/tests/ui/image/sample_gradient.rs b/tests/ui/image/sample_gradient.rs new file mode 100644 index 0000000000..e6c011ba6c --- /dev/null +++ b/tests/ui/image/sample_gradient.rs @@ -0,0 +1,18 @@ +// Test `OpImageSampleExplicitLod` +// build-pass + +use spirv_std::{arch, storage_class::{Output, UniformConstant}, Image2d, Image2dArray, Sampler}; + +#[spirv(fragment)] +pub fn main( + image: UniformConstant, + image_array: UniformConstant, + sampler: UniformConstant, + mut image_output: Output, + mut image_array_output: Output, +) { + let image_result = image.sample_by_gradient(*sampler, glam::Vec2::new(0.0, 1.0), glam::Vec2::new(0.0, 1.0), glam::Vec2::new(0.0, 1.0)); + *image_output = image_result; + let image_array_result = image_array.sample_by_gradient(*sampler, glam::Vec3A::new(0.0, 0.0, 1.0), glam::Vec2::new(0.0, 1.0), glam::Vec2::new(0.0, 1.0)); + *image_array_output = image_array_result; +} diff --git a/tests/ui/image/sample_lod.rs b/tests/ui/image/sample_lod.rs new file mode 100644 index 0000000000..2e5659dcef --- /dev/null +++ b/tests/ui/image/sample_lod.rs @@ -0,0 +1,18 @@ +// Test `OpImageSampleExplicitLod` +// build-pass + +use spirv_std::{arch, storage_class::{Output, UniformConstant}, Image2d, Image2dArray, Sampler}; + +#[spirv(fragment)] +pub fn main( + image: UniformConstant, + image_array: UniformConstant, + sampler: UniformConstant, + mut image_output: Output, + mut image_array_output: Output, +) { + let image_result = image.sample_by_lod(*sampler, glam::Vec2::new(0.0, 1.0), 0.0); + *image_output = image_result; + let image_array_result = image_array.sample_by_lod(*sampler, glam::Vec3A::new(0.0, 0.0, 1.0), 0.0); + *image_array_output = image_array_result; +}