From a93d6e0f2a59165e10aee428df6b317e23aeb133 Mon Sep 17 00:00:00 2001 From: Ashley Hauck Date: Fri, 6 Aug 2021 15:26:30 +0200 Subject: [PATCH] Add sample_bias and gather functions (#704) * Add sample_bias function * Update line numbers * Add gather function * Update spirv-tools CI was failing on "Capability SampledRect is not allowed by Vulkan 1.1 specification (or requires extension)", except locally it was fine, and I have more up to date spirv-tools than CI, so try bumping the CI version to see if it's just an out-of-date spirv-val * Fix gather() in vulkan * Convert compiler valication into marker traits --- .github/workflows/ci.yaml | 6 +- .../src/builder/spirv_asm.rs | 128 +--- crates/spirv-std/src/image.rs | 638 +++++++++++++++++- tests/ui/image/gather.rs | 35 + tests/ui/image/gather_err.rs | 18 + tests/ui/image/gather_err.stderr | 25 + tests/ui/image/query/query_levels_err.stderr | 24 +- tests/ui/image/query/query_lod_err.stderr | 25 +- tests/ui/image/query/query_size_err.stderr | 27 +- .../ui/image/query/query_size_lod_err.stderr | 26 +- tests/ui/image/sample_bias.rs | 20 + 11 files changed, 762 insertions(+), 210 deletions(-) create mode 100644 tests/ui/image/gather.rs create mode 100644 tests/ui/image/gather_err.rs create mode 100644 tests/ui/image/gather_err.stderr create mode 100644 tests/ui/image/sample_bias.rs diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3634992b0e..ca5d33e771 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,7 +22,7 @@ jobs: target: aarch64-linux-android runs-on: ${{ matrix.os }} env: - spirv_tools_version: "20200928" + spirv_tools_version: "20210805" RUSTUP_UNPACK_RAM: "26214400" RUSTUP_IO_THREADS: "1" steps: @@ -34,7 +34,7 @@ jobs: run: | sudo apt install libwayland-cursor0 libxkbcommon-dev libwayland-dev mkdir "${HOME}/spirv-tools" - curl -fL https://storage.googleapis.com/spirv-tools/artifacts/prod/graphics_shader_compiler/spirv-tools/linux-clang-release/continuous/1409/20210313-175801/install.tgz | tar -xz -C "${HOME}/spirv-tools" + curl -fL https://storage.googleapis.com/spirv-tools/artifacts/prod/graphics_shader_compiler/spirv-tools/linux-clang-release/continuous/1530/20210805-040049/install.tgz | tar -xz -C "${HOME}/spirv-tools" echo "${HOME}/spirv-tools/install/bin" >> $GITHUB_PATH - if: ${{ runner.os == 'macOS' }} name: Mac - Install spirv-tools @@ -47,7 +47,7 @@ jobs: run: | tmparch=$(mktemp) mkdir "${HOME}/spirv-tools" - curl -fL -o "$tmparch" https://storage.googleapis.com/spirv-tools/artifacts/prod/graphics_shader_compiler/spirv-tools/windows-msvc-2017-release/continuous/1391/20210313-183536/install.zip + curl -fL -o "$tmparch" https://storage.googleapis.com/spirv-tools/artifacts/prod/graphics_shader_compiler/spirv-tools/windows-msvc-2017-release/continuous/1517/20210805-040116/install.zip unzip "$tmparch" -d "${HOME}/spirv-tools" - if: ${{ runner.os == 'Windows' }} # Runs separately to add spir-v tools to Powershell's Path. diff --git a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs index 26bb368126..5a84dd7919 100644 --- a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs +++ b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs @@ -5,7 +5,7 @@ use crate::spirv_type::SpirvType; use rspirv::dr; use rspirv::grammar::{LogicalOperand, OperandKind, OperandQuantifier}; use rspirv::spirv::{ - Dim, FPFastMathMode, FragmentShadingRate, FunctionControl, ImageOperands, KernelProfilingInfo, + FPFastMathMode, FragmentShadingRate, FunctionControl, ImageOperands, KernelProfilingInfo, LoopControl, MemoryAccess, MemorySemantics, Op, RayFlags, SelectionControl, StorageClass, Word, }; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; @@ -333,7 +333,6 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { return; } _ => { - self.validate_instruction(&inst); self.emit() .insert_into_block(dr::InsertPoint::End, inst) .unwrap(); @@ -1314,131 +1313,6 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { } true } - - pub fn validate_instruction(&mut self, inst: &dr::Instruction) { - fn find_image_ty<'cx, 'tcx>( - builder: &mut Builder<'cx, 'tcx>, - inst: &dr::Instruction, - ) -> Option { - // Assumes the image parameter is the first operand - let image_obj = inst.operands[0].unwrap_id_ref(); - let emit = builder.emit(); - // Assumes the image's value definition is in the current block - let block = &emit.module_ref().functions[emit.selected_function().unwrap()].blocks - [emit.selected_block().unwrap()]; - // Loop through the block to find the defining instruction - let defining_inst = match block - .instructions - .iter() - .find(|inst| inst.result_id == Some(image_obj)) - { - Some(defining_inst) => defining_inst, - None => { - // Something has gone wrong. All the asm! blocks using these instructions - // should produce the image value in their own basic blocks (usually with - // an OpLoad), so there's probably some typo somewhere with an error - // already emitted, so just skip validation. If there truly is something - // bad going on, spirv-val will catch it. - return None; - } - }; - match builder.lookup_type(defining_inst.result_type.unwrap()) { - SpirvType::SampledImage { image_type } => Some(builder.lookup_type(image_type)), - ty => Some(ty), - } - } - - fn is_valid_query_size(ty: &SpirvType) -> bool { - match *ty { - SpirvType::Image { - dim, - multisampled, - sampled, - .. - } => match dim { - Dim::Dim1D | Dim::Dim2D | Dim::Dim3D | Dim::DimCube => { - multisampled == 1 || sampled == 0 || sampled == 2 - } - Dim::DimBuffer | Dim::DimRect => true, - Dim::DimSubpassData => false, - }, - _ => true, - } - } - - fn is_valid_query_size_lod(ty: &SpirvType) -> bool { - match *ty { - SpirvType::Image { - dim, multisampled, .. - } => match dim { - Dim::Dim1D | Dim::Dim2D | Dim::Dim3D | Dim::DimCube => multisampled == 0, - _ => false, - }, - _ => true, - } - } - - match inst.class.opcode { - Op::ImageQueryLevels | Op::ImageQueryLod => { - let image_ty = match find_image_ty(self, inst) { - Some(ty) => ty, - None => return, - }; - if let SpirvType::Image { dim, .. } = image_ty { - match dim { - Dim::Dim1D | Dim::Dim2D | Dim::Dim3D | Dim::DimCube => {} - bad => self - .struct_err(&format!( - "Op{}'s image has a dimension of {:?}", - inst.class.opname, bad - )) - .note("Allowed dimensions are 1D, 2D, 3D, and Cube") - .emit(), - } - } - // If the type isn't an image, something has gone wrong. The functions in image.rs - // shouldn't allow it, so the user is doing something weird. Let spirv-val handle - // the error later on. - } - Op::ImageQuerySize => { - let image_ty = match find_image_ty(self, inst) { - Some(ty) => ty, - None => return, - }; - if !is_valid_query_size(&image_ty) { - let mut err = - self.struct_err("OpImageQuerySize is invalid for this image type"); - err.note( - "allowed dimensions are 1D, 2D, 3D, Buffer, Rect, or Cube. \ - if dimension is 1D, 2D, 3D, or Cube, it must have either \ - multisampled be true, *or* sampled of Unknown or No", - ); - if is_valid_query_size_lod(&image_ty) { - err.note("query_size_lod is valid for this image, did you mean to use it instead?"); - } - err.emit(); - } - } - Op::ImageQuerySizeLod => { - let image_ty = match find_image_ty(self, inst) { - Some(ty) => ty, - None => return, - }; - if !is_valid_query_size_lod(&image_ty) { - let mut err = - self.struct_err("OpImageQuerySizeLod is invalid for this image type"); - err.note("The image's dimension must be 1D, 2D, 3D, or Cube. Multisampled must be false."); - if is_valid_query_size(&image_ty) { - err.note( - "query_size is valid for this image, did you mean to use it instead?", - ); - } - err.emit(); - } - } - _ => {} - } - } } pub const IMAGE_OPERANDS: &[(&str, ImageOperands)] = &[ diff --git a/crates/spirv-std/src/image.rs b/crates/spirv-std/src/image.rs index 2070a81266..9e38533a30 100644 --- a/crates/spirv-std/src/image.rs +++ b/crates/spirv-std/src/image.rs @@ -136,6 +136,42 @@ impl< ACCESS_QUALIFIER, > { + // Note: #[inline] is needed because in vulkan, the component must be a constant expression. + /// Gathers the requested component from four texels. + #[crate::macros::gpu_only] + #[doc(alias = "OpImageGather")] + #[inline] + pub fn gather( + &self, + sampler: Sampler, + coordinate: impl ImageCoordinate, + component: u32, + ) -> V + where + Self: HasGather, + F: Float, + V: Vector, + { + let mut result = V::default(); + unsafe { + asm! { + "%typeSampledImage = OpTypeSampledImage typeof*{this}", + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%coordinate = OpLoad _ {coordinate}", + "%sampledImage = OpSampledImage %typeSampledImage %image %sampler", + "%result = OpImageGather typeof*{result} %sampledImage %coordinate {component}", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + coordinate = in(reg) &coordinate, + component = in(reg) component, + } + } + result + } + /// Sample texels at `coord` from the image using `sampler`. #[crate::macros::gpu_only] pub fn sample(&self, sampler: Sampler, coord: impl ImageCoordinate) -> V @@ -162,6 +198,39 @@ impl< } } + /// Sample texels at `coord` from the image using `sampler`, after adding the input bias to the + /// implicit level of detail. + #[crate::macros::gpu_only] + pub fn sample_bias( + &self, + sampler: Sampler, + coord: impl ImageCoordinate, + bias: f32, + ) -> V + where + F: Float, + V: Vector, + { + unsafe { + let mut result = Default::default(); + asm!( + "%typeSampledImage = OpTypeSampledImage typeof*{1}", + "%image = OpLoad typeof*{1} {1}", + "%sampler = OpLoad typeof*{2} {2}", + "%coord = OpLoad typeof*{3} {3}", + "%sampledImage = OpSampledImage %typeSampledImage %image %sampler", + "%result = OpImageSampleImplicitLod typeof*{0} %sampledImage %coord Bias {4}", + "OpStore {0} %result", + in(reg) &mut result, + in(reg) self, + in(reg) &sampler, + in(reg) &coord, + in(reg) bias, + ); + result + } + } + /// Fetch a single texel with a sampler set at compile time #[crate::macros::gpu_only] #[doc(alias = "OpImageSampleExplicitLod")] @@ -358,9 +427,9 @@ impl< ACCESS_QUALIFIER, > { - /// Fetch a single texel with a sampler set at compile time + /// Sample the image with a project coordinate #[crate::macros::gpu_only] - #[doc(alias = "OpImageFetch")] + #[doc(alias = "OpImageSampleProjImplicitLod")] pub fn sample_with_project_coordinate( &self, sampler: Sampler, @@ -750,14 +819,12 @@ impl< > Image { /// Query the number of mipmap levels. - /// - /// Note: Const generics aren't able to reason about the constraints on this function (yet), - /// and so are enforced by the compiler. The constraints are: - /// - /// The image's dimension must be 1D, 2D, 3D, or Cube. #[crate::macros::gpu_only] #[doc(alias = "OpImageQueryLevels")] - pub fn query_levels(&self) -> u32 { + pub fn query_levels(&self) -> u32 + where + Self: HasQueryLevels, + { let result: u32; unsafe { asm! { @@ -774,18 +841,16 @@ impl< /// Coordinate using an implicit level of detail. The first component of the result contains /// the mipmap array layer. The second component of the result contains the implicit level of /// detail relative to the base level. - /// - /// Note: Const generics aren't able to reason about the constraints on this function (yet), - /// and so are enforced by the compiler. The constraints are: - /// - /// The image's dimension must be 1D, 2D, 3D, or Cube. #[crate::macros::gpu_only] #[doc(alias = "OpImageQueryLod")] pub fn query_lod>( &self, sampler: Sampler, coord: impl ImageCoordinate, - ) -> V { + ) -> V + where + Self: HasQueryLevels, + { // Note: Arrayed::False isn't a typo in the ImageCoordinate, the spec states: // Coordinate must be a scalar or vector of floating-point type or integer type. It // contains (u[, v] ... ) as needed by the definition of Sampled Image, **not including any @@ -811,15 +876,12 @@ impl< } /// Query the dimensions of Image, with no level of detail. - /// - /// Note: Const generics aren't able to reason about the constraints on this function (yet), - /// and so are enforced by the compiler. The constraints are: - /// - /// The image's dimension must be 1D, 2D, 3D, Buffer, Rect, or Cube. If dimension is 1D, 2D, - /// 3D, or Cube, it must have *either* multisampled be true, *or* sampled of Unknown or No. #[crate::macros::gpu_only] #[doc(alias = "OpImageQuerySize")] - pub fn query_size + Default>(&self) -> Size { + pub fn query_size + Default>(&self) -> Size + where + Self: HasQuerySize, + { let mut result: Size = Default::default(); unsafe { asm! { @@ -855,17 +917,15 @@ impl< > { /// Query the dimensions of Image, with no level of detail. - /// - /// Note: Const generics aren't able to reason about the constraints on this function (yet), - /// and so are enforced by the compiler. The constraints are: - /// - /// The image's dimension must be 1D, 2D, 3D, or Cube. Multisampled must be false. #[crate::macros::gpu_only] #[doc(alias = "OpImageQuerySizeLod")] pub fn query_size_lod + Default>( &self, lod: u32, - ) -> Size { + ) -> Size + where + Self: HasQuerySizeLod, + { let mut result: Size = Default::default(); unsafe { asm! { @@ -974,3 +1034,527 @@ impl< result } } + +/// This is a marker trait to represent the constraints on `OpImageGather` too complex to be +/// represented by const generics. Specifically: +/// +/// "Its `OpTypeImage` must have a Dim of 2D, Cube, or Rect. The MS operand of the underlying +/// `OpTypeImage` must be 0." +pub trait HasGather {} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasGather + for Image< + SampledType, + { Dimensionality::TwoD }, + DEPTH, + ARRAYED, + { Multisampled::False }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasGather + for Image< + SampledType, + { Dimensionality::Rect }, + DEPTH, + ARRAYED, + { Multisampled::False }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasGather + for Image< + SampledType, + { Dimensionality::Cube }, + DEPTH, + ARRAYED, + { Multisampled::False }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} + +/// This is a marker trait to represent the constraints on `OpImageQueryLevels` and +/// `OpImageQueryLod` too complex to be represented by const generics. Specifically: +/// +/// "Its Dim operand must be one of 1D, 2D, 3D, or Cube." +pub trait HasQueryLevels {} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const MULTISAMPLED: Multisampled, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQueryLevels + for Image< + SampledType, + { Dimensionality::OneD }, + DEPTH, + ARRAYED, + MULTISAMPLED, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const MULTISAMPLED: Multisampled, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQueryLevels + for Image< + SampledType, + { Dimensionality::TwoD }, + DEPTH, + ARRAYED, + MULTISAMPLED, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const MULTISAMPLED: Multisampled, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQueryLevels + for Image< + SampledType, + { Dimensionality::ThreeD }, + DEPTH, + ARRAYED, + MULTISAMPLED, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const MULTISAMPLED: Multisampled, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQueryLevels + for Image< + SampledType, + { Dimensionality::Cube }, + DEPTH, + ARRAYED, + MULTISAMPLED, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} + +/// This is a marker trait to represent the constraints on `OpImageQuerySize` too complex to be +/// represented by const generics. Specifically: +/// +/// "Its Dim operand must be 1D, 2D, 3D, Cube, Rect, or Buffer. Additionally, if its Dim is 1D, 2D, +/// 3D, or Cube, it must also have either an MS of 1 or a Sampled of 0 or 2." +pub trait HasQuerySize {} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::OneD }, + DEPTH, + ARRAYED, + { Multisampled::True }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::OneD }, + DEPTH, + ARRAYED, + { Multisampled::False }, + { Sampled::Unknown }, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::OneD }, + DEPTH, + ARRAYED, + { Multisampled::False }, + { Sampled::No }, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::TwoD }, + DEPTH, + ARRAYED, + { Multisampled::True }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::TwoD }, + DEPTH, + ARRAYED, + { Multisampled::False }, + { Sampled::Unknown }, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::TwoD }, + DEPTH, + ARRAYED, + { Multisampled::False }, + { Sampled::No }, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::ThreeD }, + DEPTH, + ARRAYED, + { Multisampled::True }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::ThreeD }, + DEPTH, + ARRAYED, + { Multisampled::False }, + { Sampled::Unknown }, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::ThreeD }, + DEPTH, + ARRAYED, + { Multisampled::False }, + { Sampled::No }, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::Cube }, + DEPTH, + ARRAYED, + { Multisampled::True }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::Cube }, + DEPTH, + ARRAYED, + { Multisampled::False }, + { Sampled::Unknown }, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::Cube }, + DEPTH, + ARRAYED, + { Multisampled::False }, + { Sampled::No }, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const MULTISAMPLED: Multisampled, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::Rect }, + DEPTH, + ARRAYED, + MULTISAMPLED, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const MULTISAMPLED: Multisampled, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQuerySize + for Image< + SampledType, + { Dimensionality::Buffer }, + DEPTH, + ARRAYED, + MULTISAMPLED, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} + +/// This is a marker trait to represent the constraints on `OpImageQuerySizeLod` too complex to be +/// represented by const generics. Specifically: +/// +/// "Its Dim operand must be one of 1D, 2D, 3D, or Cube, and its MS must be 0." +pub trait HasQuerySizeLod {} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQuerySizeLod + for Image< + SampledType, + { Dimensionality::OneD }, + DEPTH, + ARRAYED, + { Multisampled::False }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQuerySizeLod + for Image< + SampledType, + { Dimensionality::TwoD }, + DEPTH, + ARRAYED, + { Multisampled::False }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQuerySizeLod + for Image< + SampledType, + { Dimensionality::ThreeD }, + DEPTH, + ARRAYED, + { Multisampled::False }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} +impl< + SampledType: SampleType, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > HasQuerySizeLod + for Image< + SampledType, + { Dimensionality::Cube }, + DEPTH, + ARRAYED, + { Multisampled::False }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ +} diff --git a/tests/ui/image/gather.rs b/tests/ui/image/gather.rs new file mode 100644 index 0000000000..02a82446b8 --- /dev/null +++ b/tests/ui/image/gather.rs @@ -0,0 +1,35 @@ +// Test `OpImageGather` +// build-pass + +use spirv_std::{arch, Image, Sampler}; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image!(2D, type=f32, sampled), + #[spirv(descriptor_set = 2, binding = 2)] cubemap: &Image!(cube, type=f32, sampled), + #[spirv(descriptor_set = 3, binding = 3)] sampler: &Sampler, + output: &mut glam::Vec4, +) { + let v2 = glam::Vec2::new(0.0, 1.0); + let v3 = glam::Vec3::new(0.0, 1.0, 0.5); + let r1: glam::Vec4 = image2d.gather(*sampler, v2, 0); + let r2: glam::Vec4 = cubemap.gather(*sampler, v3, 0); + *output = r1 + r2; +} + +#[cfg(not(any( + target_env = "vulkan1.0", + target_env = "vulkan1.1", + target_env = "vulkan1.2" +)))] +#[spirv(fragment)] +pub fn main_rect( + #[spirv(descriptor_set = 1, binding = 1)] rect: &Image!(rect, type=f32, sampled), + #[spirv(descriptor_set = 3, binding = 3)] sampler: &Sampler, + output: &mut glam::Vec4, +) { + // Must be asm! and not -Ctarget-feature=+SampledRect due to being in cfg + unsafe { asm!("OpCapability SampledRect") }; + let v2 = glam::Vec2::new(0.0, 1.0); + *output = rect.gather(*sampler, v2, 0); +} diff --git a/tests/ui/image/gather_err.rs b/tests/ui/image/gather_err.rs new file mode 100644 index 0000000000..5ec3b80656 --- /dev/null +++ b/tests/ui/image/gather_err.rs @@ -0,0 +1,18 @@ +// build-fail +// normalize-stderr-test "\S*/crates/spirv-std/src/" -> "$$SPIRV_STD_SRC/" +// compile-flags: -Ctarget-feature=+Sampled1D + +use spirv_std::{arch, Image, Sampler}; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] image1d: &Image!(1D, type=f32, sampled), + #[spirv(descriptor_set = 2, binding = 1)] image3d: &Image!(3D, type=f32, sampled), + #[spirv(descriptor_set = 3, binding = 3)] sampler: &Sampler, + output: &mut glam::Vec4, +) { + let v3 = glam::Vec3::new(0.0, 1.0, 0.5); + let r1: glam::Vec4 = image1d.gather(*sampler, 0.0, 0); + let r2: glam::Vec4 = image3d.gather(*sampler, v3, 0); + *output = r1 + r2; +} diff --git a/tests/ui/image/gather_err.stderr b/tests/ui/image/gather_err.stderr new file mode 100644 index 0000000000..14d1ca1f53 --- /dev/null +++ b/tests/ui/image/gather_err.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `Image::None>: HasGather` is not satisfied + --> $DIR/gather_err.rs:15:34 + | +15 | let r1: glam::Vec4 = image1d.gather(*sampler, 0.0, 0); + | ^^^^^^ the trait `HasGather` is not implemented for `Image::None>` + | + = help: the following implementations were found: + as HasGather> + as HasGather> + as HasGather> + +error[E0277]: the trait bound `Image::None>: HasGather` is not satisfied + --> $DIR/gather_err.rs:16:34 + | +16 | let r2: glam::Vec4 = image3d.gather(*sampler, v3, 0); + | ^^^^^^ the trait `HasGather` is not implemented for `Image::None>` + | + = help: the following implementations were found: + as HasGather> + as HasGather> + as HasGather> + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/image/query/query_levels_err.stderr b/tests/ui/image/query/query_levels_err.stderr index 95e9eae88c..56df54881c 100644 --- a/tests/ui/image/query/query_levels_err.stderr +++ b/tests/ui/image/query/query_levels_err.stderr @@ -1,15 +1,15 @@ -error: OpImageQueryLevels's image has a dimension of DimRect - --> $SPIRV_STD_SRC/image.rs:763:13 - | -763 | / asm! { -764 | | "%image = OpLoad _ {this}", -765 | | "{result} = OpImageQueryLevels typeof{result} %image", -766 | | this = in(reg) self, -767 | | result = out(reg) result, -768 | | } - | |_____________^ - | - = note: Allowed dimensions are 1D, 2D, 3D, and Cube +error[E0277]: the trait bound `Image::None>: HasQueryLevels` is not satisfied + --> $DIR/query_levels_err.rs:12:21 + | +12 | *output = image.query_levels(); + | ^^^^^^^^^^^^ the trait `HasQueryLevels` is not implemented for `Image::None>` + | + = help: the following implementations were found: + as HasQueryLevels> + as HasQueryLevels> + as HasQueryLevels> + as HasQueryLevels> error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/image/query/query_lod_err.stderr b/tests/ui/image/query/query_lod_err.stderr index 03f6c7f014..f8f0bd3520 100644 --- a/tests/ui/image/query/query_lod_err.stderr +++ b/tests/ui/image/query/query_lod_err.stderr @@ -1,16 +1,15 @@ -error: OpImageQueryLod's image has a dimension of DimRect - --> $SPIRV_STD_SRC/image.rs:796:13 - | -796 | / asm! { -797 | | "%typeSampledImage = OpTypeSampledImage typeof*{this}", -798 | | "%image = OpLoad _ {this}", -799 | | "%sampler = OpLoad _ {sampler}", -... | -807 | | coord = in(reg) &coord -808 | | } - | |_____________^ - | - = note: Allowed dimensions are 1D, 2D, 3D, and Cube +error[E0277]: the trait bound `Image::None>: HasQueryLevels` is not satisfied + --> $DIR/query_lod_err.rs:13:21 + | +13 | *output = image.query_lod(*sampler, glam::Vec2::new(0.0, 1.0)); + | ^^^^^^^^^ the trait `HasQueryLevels` is not implemented for `Image::None>` + | + = help: the following implementations were found: + as HasQueryLevels> + as HasQueryLevels> + as HasQueryLevels> + as HasQueryLevels> error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/image/query/query_size_err.stderr b/tests/ui/image/query/query_size_err.stderr index 63dd9de844..36ca234d0d 100644 --- a/tests/ui/image/query/query_size_err.stderr +++ b/tests/ui/image/query/query_size_err.stderr @@ -1,17 +1,16 @@ -error: OpImageQuerySize is invalid for this image type - --> $SPIRV_STD_SRC/image.rs:825:13 - | -825 | / asm! { -826 | | "%image = OpLoad _ {this}", -827 | | "%result = OpImageQuerySize typeof*{result} %image", -828 | | "OpStore {result} %result", -829 | | this = in(reg) self, -830 | | result = in(reg) &mut result, -831 | | } - | |_____________^ - | - = note: allowed dimensions are 1D, 2D, 3D, Buffer, Rect, or Cube. if dimension is 1D, 2D, 3D, or Cube, it must have either multisampled be true, *or* sampled of Unknown or No - = note: query_size_lod is valid for this image, did you mean to use it instead? +error[E0277]: the trait bound `Image::None>: HasQuerySize` is not satisfied + --> $DIR/query_size_err.rs:12:21 + | +12 | *output = image.query_size(); + | ^^^^^^^^^^ the trait `HasQuerySize` is not implemented for `Image::None>` + | + = help: the following implementations were found: + as HasQuerySize> + as HasQuerySize> + as HasQuerySize> + as HasQuerySize> + and 10 others error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/image/query/query_size_lod_err.stderr b/tests/ui/image/query/query_size_lod_err.stderr index a45d563603..64a8883e71 100644 --- a/tests/ui/image/query/query_size_lod_err.stderr +++ b/tests/ui/image/query/query_size_lod_err.stderr @@ -1,17 +1,15 @@ -error: OpImageQuerySizeLod is invalid for this image type - --> $SPIRV_STD_SRC/image.rs:871:13 - | -871 | / asm! { -872 | | "%image = OpLoad _ {this}", -873 | | "%result = OpImageQuerySizeLod typeof*{result} %image {lod}", -874 | | "OpStore {result} %result", -... | -877 | | result = in(reg) &mut result, -878 | | } - | |_____________^ - | - = note: The image's dimension must be 1D, 2D, 3D, or Cube. Multisampled must be false. - = note: query_size is valid for this image, did you mean to use it instead? +error[E0277]: the trait bound `Image::None>: HasQuerySizeLod` is not satisfied + --> $DIR/query_size_lod_err.rs:12:21 + | +12 | *output = image.query_size_lod(0); + | ^^^^^^^^^^^^^^ the trait `HasQuerySizeLod` is not implemented for `Image::None>` + | + = help: the following implementations were found: + as HasQuerySizeLod> + as HasQuerySizeLod> + as HasQuerySizeLod> + as HasQuerySizeLod> error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/image/sample_bias.rs b/tests/ui/image/sample_bias.rs new file mode 100644 index 0000000000..85e652c75f --- /dev/null +++ b/tests/ui/image/sample_bias.rs @@ -0,0 +1,20 @@ +// Test `OpImageSampleImplicitLod` Bias +// build-pass + +use spirv_std::{arch, Image, Sampler}; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image!(2D, type=f32, sampled), + #[spirv(descriptor_set = 1, binding = 1)] image2d_array: &Image!(2D, type=f32, arrayed, sampled), + #[spirv(descriptor_set = 2, binding = 2)] cubemap: &Image!(3D, type=f32, sampled), + #[spirv(descriptor_set = 3, binding = 3)] sampler: &Sampler, + output: &mut glam::Vec4, +) { + let v2 = glam::Vec2::new(0.0, 1.0); + let v3 = glam::Vec3::new(0.0, 1.0, 0.5); + let r1: glam::Vec4 = image2d.sample_bias(*sampler, v2, 0.0); + let r2: glam::Vec4 = image2d_array.sample_bias(*sampler, v3, 0.0); + let r3: glam::Vec4 = cubemap.sample_bias(*sampler, v3, 0.0); + *output = r1 + r2 + r3; +}