From 64edcf34a748bcce9875fd4ae823d1f885cde57a Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Wed, 28 Apr 2021 09:47:40 +0200 Subject: [PATCH] Add Const Generic Image Type (#359) * Add parameterized Image type * nits * Update crates/spirv-std/src/lib.rs * Update crates/rustc_codegen_spirv/src/symbols.rs * Update crates/rustc_codegen_spirv/src/symbols.rs * Update symbols.rs --- Cargo.lock | 48 +- Cargo.toml | 4 +- crates/rustc_codegen_spirv/src/abi.rs | 95 ++- crates/rustc_codegen_spirv/src/attr.rs | 1 + crates/rustc_codegen_spirv/src/symbols.rs | 4 + crates/spirv-builder/src/lib.rs | 2 +- crates/spirv-std/Cargo.toml | 3 +- .../macros}/Cargo.toml | 2 + crates/spirv-std/macros/src/image.rs | 554 ++++++++++++++ .../macros}/src/lib.rs | 54 ++ crates/spirv-std/shared/Cargo.toml | 8 + crates/spirv-std/shared/src/image_params.rs | 228 ++++++ crates/spirv-std/shared/src/lib.rs | 5 + crates/spirv-std/src/arch/derivative.rs | 36 +- crates/spirv-std/src/image.rs | 715 ++++++++++++++++++ crates/spirv-std/src/image/params.rs | 74 ++ crates/spirv-std/src/lib.rs | 10 +- crates/spirv-std/src/sampler.rs | 7 + crates/spirv-std/src/textures.rs | 31 +- examples/shaders/compute-shader/Cargo.toml | 1 - examples/shaders/compute-shader/src/lib.rs | 3 +- examples/shaders/shared/Cargo.toml | 1 - examples/shaders/simplest-shader/Cargo.toml | 1 - examples/shaders/simplest-shader/src/lib.rs | 4 +- examples/shaders/sky-shader/Cargo.toml | 1 - examples/shaders/sky-shader/src/lib.rs | 3 +- tests/ui/image/fetch.rs | 7 +- tests/ui/image/format.rs | 12 + tests/ui/image/issue_527.rs | 2 +- tests/ui/image/read.rs | 4 +- tests/ui/image/sample.rs | 8 +- .../ui/image/sample_depth_reference/sample.rs | 8 +- .../sample_depth_reference/sample_gradient.rs | 8 +- .../sample_depth_reference/sample_lod.rs | 8 +- .../sample.rs | 4 +- .../sample_gradient.rs | 4 +- .../sample_lod.rs | 4 +- tests/ui/image/sample_gradient.rs | 8 +- tests/ui/image/sample_lod.rs | 8 +- .../sample_with_project_coordinate/sample.rs | 4 +- .../sample_gradient.rs | 4 +- .../sample_lod.rs | 4 +- tests/ui/image/write.rs | 7 +- .../ui/spirv-attr/bad-infer-storage-class.rs | 10 +- .../spirv-attr/bad-infer-storage-class.stderr | 34 +- 45 files changed, 1920 insertions(+), 123 deletions(-) rename crates/{spirv-std-macros => spirv-std/macros}/Cargo.toml (82%) create mode 100644 crates/spirv-std/macros/src/image.rs rename crates/{spirv-std-macros => spirv-std/macros}/src/lib.rs (80%) create mode 100644 crates/spirv-std/shared/Cargo.toml create mode 100644 crates/spirv-std/shared/src/image_params.rs create mode 100644 crates/spirv-std/shared/src/lib.rs create mode 100644 crates/spirv-std/src/image.rs create mode 100644 crates/spirv-std/src/image/params.rs create mode 100644 crates/spirv-std/src/sampler.rs create mode 100644 tests/ui/image/format.rs diff --git a/Cargo.lock b/Cargo.lock index 5b0d9871a1..897a822ca4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -403,7 +403,6 @@ name = "compute-shader" version = "0.4.0-alpha.5" dependencies = [ "spirv-std", - "spirv-std-macros", ] [[package]] @@ -792,7 +791,7 @@ checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.2.5", + "redox_syscall 0.2.6", "winapi 0.3.9", ] @@ -992,9 +991,9 @@ dependencies = [ [[package]] name = "gfx-backend-dx12" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36dc6ba2b7647e2c2b27b8f74ff5ccdd53c703776588eee5b1de515fdcbd6bc9" +checksum = "5032d716a2a5f4dafb4675a794c5dc32081af8fbc7303c93ad93ff5413c6559f" dependencies = [ "arrayvec", "bit-set", @@ -1008,6 +1007,7 @@ dependencies = [ "raw-window-handle", "smallvec", "spirv_cross", + "thunderdome", "winapi 0.3.9", ] @@ -1262,9 +1262,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +checksum = "972f5ae5d1cb9c6ae417789196c803205313edde988685da5e3aae0827b9e7fd" dependencies = [ "libc", ] @@ -1728,7 +1728,7 @@ checksum = "0c976c5018e7f1db4359616d8b31ef8ae7d9649b11803c0b38fff67fd2999fc8" dependencies = [ "libc", "raw-window-handle", - "redox_syscall 0.2.5", + "redox_syscall 0.2.6", "sdl2", "sdl2-sys", "wasm-bindgen", @@ -1779,7 +1779,7 @@ dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall 0.2.5", + "redox_syscall 0.2.6", "smallvec", "winapi 0.3.9", ] @@ -1855,9 +1855,9 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "pretty_assertions" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f297542c27a7df8d45de2b0e620308ab883ad232d06c14b76ac3e144bda50184" +checksum = "1cab0e7c02cf376875e9335e0ba1da535775beb5450d21e1dffca068818ed98b" dependencies = [ "ansi_term 0.12.1", "ctor", @@ -2022,9 +2022,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_syscall" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" dependencies = [ "bitflags", ] @@ -2036,7 +2036,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom", - "redox_syscall 0.2.5", + "redox_syscall 0.2.6", ] [[package]] @@ -2078,12 +2078,12 @@ dependencies = [ [[package]] name = "rspirv" version = "0.7.0" -source = "git+https://github.com/gfx-rs/rspirv.git?rev=719cf08#719cf08e4af0436242707479e3509add5ec3d514" +source = "git+https://github.com/gfx-rs/rspirv?rev=719cf08#719cf08e4af0436242707479e3509add5ec3d514" dependencies = [ "derive_more", "fxhash", "num-traits", - "spirv_headers 1.5.0 (git+https://github.com/gfx-rs/rspirv.git?rev=719cf08)", + "spirv_headers 1.5.0 (git+https://github.com/gfx-rs/rspirv?rev=719cf08)", ] [[package]] @@ -2267,7 +2267,6 @@ version = "0.4.0-alpha.5" dependencies = [ "glam", "spirv-std", - "spirv-std-macros", ] [[package]] @@ -2282,7 +2281,6 @@ version = "0.4.0-alpha.5" dependencies = [ "shared", "spirv-std", - "spirv-std-macros", ] [[package]] @@ -2291,14 +2289,13 @@ version = "0.4.0-alpha.5" dependencies = [ "shared", "spirv-std", - "spirv-std-macros", ] [[package]] name = "slab" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" [[package]] name = "slotmap" @@ -2351,14 +2348,17 @@ dependencies = [ "bitflags", "num-traits", "spirv-std-macros", + "spirv-types", ] [[package]] name = "spirv-std-macros" version = "0.4.0-alpha.5" dependencies = [ + "heck", "proc-macro2", "quote", + "spirv-types", "syn", ] @@ -2382,6 +2382,10 @@ dependencies = [ "cc", ] +[[package]] +name = "spirv-types" +version = "0.4.0-alpha.5" + [[package]] name = "spirv_cross" version = "0.23.1" @@ -2396,7 +2400,7 @@ dependencies = [ [[package]] name = "spirv_headers" version = "1.5.0" -source = "git+https://github.com/gfx-rs/rspirv.git?rev=719cf08#719cf08e4af0436242707479e3509add5ec3d514" +source = "git+https://github.com/gfx-rs/rspirv?rev=719cf08#719cf08e4af0436242707479e3509add5ec3d514" dependencies = [ "bitflags", "num-traits", @@ -2515,7 +2519,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "rand", - "redox_syscall 0.2.5", + "redox_syscall 0.2.6", "remove_dir_all", "winapi 0.3.9", ] diff --git a/Cargo.toml b/Cargo.toml index eea31b9ae0..5ad386ddeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,8 @@ members = [ "crates/rustc_codegen_spirv", "crates/spirv-builder", "crates/spirv-std", + "crates/spirv-std/shared", + "crates/spirv-std/macros", "tests", "tests/deps-helper", @@ -34,7 +36,7 @@ codegen-units = 256 [patch.crates-io] spirv-std = { path = "./crates/spirv-std" } -spirv-std-macros = { path = "./crates/spirv-std-macros" } +spirv-std-macros = { path = "./crates/spirv-std/macros" } # TODO: Remove once next version is released - needed to include these two PRs: # * Manishearth/compiletest-rs#240 (for handling SPIR-V extension across platforms) # * Manishearth/compiletest-rs#241 (for the `$TEST_BUILD_DIR` path normalization) diff --git a/crates/rustc_codegen_spirv/src/abi.rs b/crates/rustc_codegen_spirv/src/abi.rs index bd71990a2e..b5df8e1a18 100644 --- a/crates/rustc_codegen_spirv/src/abi.rs +++ b/crates/rustc_codegen_spirv/src/abi.rs @@ -10,7 +10,9 @@ use rustc_errors::ErrorReported; use rustc_middle::bug; use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{GeneratorSubsts, PolyFnSig, Ty, TyKind, TypeAndMut}; +use rustc_middle::ty::{ + Const, FloatTy, GeneratorSubsts, IntTy, ParamEnv, PolyFnSig, Ty, TyKind, TypeAndMut, UintTy, +}; use rustc_span::def_id::DefId; use rustc_span::Span; use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind}; @@ -21,6 +23,9 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::fmt; +use num_traits::cast::FromPrimitive; +use rspirv::spirv; + /// If a struct contains a pointer to itself, even indirectly, then doing a naiive recursive walk /// of the fields will result in an infinite loop. Because pointers are the only thing that are /// allowed to be recursive, keep track of what pointers we've translated, or are currently in the @@ -768,6 +773,94 @@ fn trans_intrinsic_type<'tcx>( } // Hardcode to float for now let sampled_type = SpirvType::Float(32).def(span, cx); + + let ty = SpirvType::Image { + sampled_type, + dim, + depth, + arrayed, + multisampled, + sampled, + image_format, + access_qualifier, + }; + + Ok(ty.def(span, cx)) + } + IntrinsicType::GenericImageType => { + // see SpirvType::sizeof + if ty.size != Size::from_bytes(4) { + cx.tcx + .sess + .err("#[spirv(generic_image)] type must have size 4"); + return Err(ErrorReported); + } + + fn type_from_variant_discriminant<'tcx, P: FromPrimitive>( + cx: &CodegenCx<'tcx>, + const_: &'tcx Const<'tcx>, + ) -> P { + let adt_def = const_.ty.ty_adt_def().unwrap(); + assert!(adt_def.is_enum()); + let destructured = cx.tcx.destructure_const(ParamEnv::reveal_all().and(const_)); + let idx = destructured.variant.unwrap(); + let value = const_.ty.discriminant_for_variant(cx.tcx, idx).unwrap().val as u64; + <_>::from_u64(value).unwrap() + } + + let sampled_type = match substs.type_at(0).kind() { + TyKind::Int(int) => match int { + IntTy::Isize => { + SpirvType::Integer(cx.tcx.data_layout.pointer_size.bits() as u32, true) + .def(span, cx) + } + IntTy::I8 => SpirvType::Integer(8, true).def(span, cx), + IntTy::I16 => SpirvType::Integer(16, true).def(span, cx), + IntTy::I32 => SpirvType::Integer(32, true).def(span, cx), + IntTy::I64 => SpirvType::Integer(64, true).def(span, cx), + IntTy::I128 => SpirvType::Integer(128, true).def(span, cx), + }, + TyKind::Uint(uint) => match uint { + UintTy::Usize => { + SpirvType::Integer(cx.tcx.data_layout.pointer_size.bits() as u32, false) + .def(span, cx) + } + UintTy::U8 => SpirvType::Integer(8, false).def(span, cx), + UintTy::U16 => SpirvType::Integer(16, false).def(span, cx), + UintTy::U32 => SpirvType::Integer(32, false).def(span, cx), + UintTy::U64 => SpirvType::Integer(64, false).def(span, cx), + UintTy::U128 => SpirvType::Integer(128, false).def(span, cx), + }, + TyKind::Float(FloatTy::F32) => SpirvType::Float(32).def(span, cx), + TyKind::Float(FloatTy::F64) => SpirvType::Float(64).def(span, cx), + _ => { + cx.tcx + .sess + .span_err(span, "Invalid sampled type to `Image`."); + return Err(ErrorReported); + } + }; + + let dim: spirv::Dim = type_from_variant_discriminant(cx, substs.const_at(1)); + let depth: u32 = type_from_variant_discriminant(cx, substs.const_at(2)); + let arrayed: u32 = type_from_variant_discriminant(cx, substs.const_at(3)); + let multisampled: u32 = type_from_variant_discriminant(cx, substs.const_at(4)); + let sampled: u32 = type_from_variant_discriminant(cx, substs.const_at(5)); + let image_format: spirv::ImageFormat = + type_from_variant_discriminant(cx, substs.const_at(6)); + + let access_qualifier = { + let option = cx + .tcx + .destructure_const(ParamEnv::reveal_all().and(substs.const_at(7))); + + match option.variant.map(|i| i.as_u32()).unwrap_or(0) { + 0 => None, + 1 => Some(type_from_variant_discriminant(cx, option.fields[0])), + _ => unreachable!(), + } + }; + let ty = SpirvType::Image { sampled_type, dim, diff --git a/crates/rustc_codegen_spirv/src/attr.rs b/crates/rustc_codegen_spirv/src/attr.rs index 267c2709d5..d53d838f24 100644 --- a/crates/rustc_codegen_spirv/src/attr.rs +++ b/crates/rustc_codegen_spirv/src/attr.rs @@ -61,6 +61,7 @@ impl From for Entry { /// `struct` types that are used to represent special SPIR-V types. #[derive(Debug, Clone)] pub enum IntrinsicType { + GenericImageType, ImageType { dim: Dim, depth: u32, diff --git a/crates/rustc_codegen_spirv/src/symbols.rs b/crates/rustc_codegen_spirv/src/symbols.rs index 401fe7aa07..3cf817bea3 100644 --- a/crates/rustc_codegen_spirv/src/symbols.rs +++ b/crates/rustc_codegen_spirv/src/symbols.rs @@ -317,6 +317,10 @@ impl Symbols { "sampler", SpirvAttribute::IntrinsicType(IntrinsicType::Sampler), ), + ( + "generic_image_type", + SpirvAttribute::IntrinsicType(IntrinsicType::GenericImageType), + ), ( "acceleration_structure", SpirvAttribute::IntrinsicType(IntrinsicType::AccelerationStructureKhr), diff --git a/crates/spirv-builder/src/lib.rs b/crates/spirv-builder/src/lib.rs index cccb0e8feb..17c2b0aff6 100644 --- a/crates/spirv-builder/src/lib.rs +++ b/crates/spirv-builder/src/lib.rs @@ -204,7 +204,7 @@ fn invoke_rustc(builder: &SpirvBuilder, multimodule: bool) -> Result, + arrayed: Arrayed, + crate_root: Option, + depth: ImageDepth, + dimensionality: Dimensionality, + format: ImageFormat, + multisampled: Multisampled, + sampled: Sampled, + sampled_type: SampledType, +} + +impl Parse for ImageType { + fn parse(input: ParseStream<'_>) -> syn::Result { + let mut access_qualifier = None; + let mut sampled_type = None; + let mut dimensionality = None; + let mut arrayed = None; + let mut depth: Option = None; + let mut format = None; + let mut multisampled = None; + let mut sampled: Option = None; + let mut crate_root = None; + + let starting_span = input.span(); + + macro_rules! set_unique { + ($id:ident = $ex:expr) => {{ + if $id.replace($ex).is_some() { + return Err(syn::Error::new( + input.span(), + concat!("Unexpected duplicate parameter for `", stringify!($id), "`"), + )); + } + }}; + } + + macro_rules! peek_and_eat_value { + ($typ:ty) => {{ + if input.peek(syn::Token![=]) { + input.parse::()?; + Some(input.parse::<$typ>()?) + } else { + None + } + }} + } + + while !input.is_empty() { + if input.peek(syn::LitInt) { + let int = input.parse::().unwrap(); + set_unique!( + dimensionality = match (int.base10_digits(), int.suffix()) { + ("1", "D") | ("1", "d") => Dimensionality::OneD, + ("2", "D") | ("2", "d") => Dimensionality::TwoD, + ("3", "D") | ("3", "d") => Dimensionality::ThreeD, + _ => return Err(syn::Error::new(int.span(), "Unexpected integer")), + } + ); + } else if input.peek(syn::Ident) { + let ident = input.parse::().unwrap(); + + if ident == "access" { + let value = peek_and_eat_value!(syn::Ident) + .as_ref() + .map(|i| params::access_qualifier_from_str(&i.to_string())); + + if value.is_none() { + return Err(syn::Error::new( + ident.span(), + "Expected argument for `access`.", + )); + } + + access_qualifier = value.unwrap().ok(); + } else if ident == "buffer" { + set_unique!(dimensionality = Dimensionality::Buffer); + } else if ident == "cube" { + set_unique!(dimensionality = Dimensionality::Cube); + } else if ident == "rect" { + set_unique!(dimensionality = Dimensionality::Rect); + } else if ident == "subpass" { + set_unique!(dimensionality = Dimensionality::SubpassData); + } else if ident == "arrayed" { + set_unique!( + arrayed = peek_and_eat_value!(syn::LitBool) + .as_ref() + .map(syn::LitBool::value) + .map_or(Arrayed::True, From::from) + ); + } else if ident == "multisampled" { + set_unique!( + multisampled = peek_and_eat_value!(syn::LitBool) + .as_ref() + .map(syn::LitBool::value) + .map_or(Multisampled::True, From::from) + ); + } else if ident == "sampled" { + set_unique!( + sampled = peek_and_eat_value!(syn::LitBool) + .as_ref() + .map(syn::LitBool::value) + .map_or(Sampled::Yes, From::from) + ); + } else if ident == "depth" { + set_unique!( + depth = peek_and_eat_value!(syn::LitBool) + .as_ref() + .map(syn::LitBool::value) + .map_or(ImageDepth::True, From::from) + ); + } else if ident == "format" { + let value = peek_and_eat_value!(syn::Ident); + + if value.is_none() { + return Err(syn::Error::new( + ident.span(), + "Expected argument for `format`.", + )); + } + + let value = params::image_format_from_str(&value.unwrap().to_string()); + + if let Err(err) = value { + return Err(syn::Error::new(ident.span(), err)); + } + + format = value.ok(); + } else if ident == "__crate_root" { + input.parse::()?; + crate_root = Some(input.parse::()?); + } + } else if input.peek(syn::token::Type) { + input.parse::()?; + input.parse::()?; + + sampled_type = Some(if input.peek(kw::u8) { + input.parse::()?; + + SampledType::U8 + } else if input.peek(kw::u16) { + input.parse::()?; + + SampledType::U16 + } else if input.peek(kw::u32) { + input.parse::()?; + + SampledType::U32 + } else if input.peek(kw::u64) { + input.parse::()?; + + SampledType::U64 + } else if input.peek(kw::i8) { + input.parse::()?; + + SampledType::I8 + } else if input.peek(kw::i16) { + input.parse::()?; + + SampledType::I16 + } else if input.peek(kw::i32) { + input.parse::()?; + + SampledType::I32 + } else if input.peek(kw::i64) { + input.parse::()?; + + SampledType::I64 + } else if input.peek(kw::f32) { + input.parse::()?; + + SampledType::F32 + } else if input.peek(kw::f64) { + input.parse::()?; + + SampledType::F64 + } else { + return Err(syn::Error::new( + input.span(), + "Unknown value provided to `unknown(_)`.", + )); + }); + } + + if input.peek(syn::Token![,]) { + input.parse::()?; + continue; + } else { + break; + } + } + + if !input.is_empty() { + return Err(syn::Error::new( + input.span(), + "Unexpected trailing arguments.", + )); + } + + let dimensionality = dimensionality.ok_or_else(|| { + syn::Error::new( + starting_span, + "Expected either `1D`, `2D`, `3D`, `cube`, `rect`, `buffer`, \ + or `subpass` to be present", + ) + })?; + + if format.is_some() && sampled_type.is_some() { + if format != Some(ImageFormat::Unknown) { + return Err(syn::Error::new( + starting_span, + "Can't specify `type` with a known image format. Either \ + specify just the `format` or use `format=unknown`.", + )); + } + } else if sampled_type.is_some() { + format = Some(ImageFormat::Unknown); + } else if let Some(format) = &format { + sampled_type = Some(match format { + ImageFormat::Rgba32f + | ImageFormat::Rgba16f + | ImageFormat::R32f + | ImageFormat::Rgba8 + | ImageFormat::Rgba8Snorm + | ImageFormat::Rg32f + | ImageFormat::Rg16f + | ImageFormat::R11fG11fB10f + | ImageFormat::R16f + | ImageFormat::Rgba16 + | ImageFormat::Rgb10A2 + | ImageFormat::Rg16 + | ImageFormat::Rg8 + | ImageFormat::R16 + | ImageFormat::R8 + | ImageFormat::Rgba16Snorm + | ImageFormat::Rg16Snorm + | ImageFormat::Rg8Snorm + | ImageFormat::R16Snorm + | ImageFormat::R8Snorm => SampledType::F32, + ImageFormat::Rgba32i + | ImageFormat::Rgba16i + | ImageFormat::Rgba8i + | ImageFormat::R32i + | ImageFormat::Rg32i + | ImageFormat::Rg16i + | ImageFormat::Rg8i + | ImageFormat::R16i + | ImageFormat::R8i => SampledType::I32, + + ImageFormat::Rgba32ui + | ImageFormat::Rgba16ui + | ImageFormat::Rgba8ui + | ImageFormat::R32ui + | ImageFormat::Rgb10A2ui + | ImageFormat::Rg32ui + | ImageFormat::Rg16ui + | ImageFormat::Rg8ui + | ImageFormat::R16ui + | ImageFormat::R8ui => SampledType::U32, + + ImageFormat::R64ui => SampledType::U64, + ImageFormat::R64i => SampledType::I64, + + ImageFormat::Unknown => unreachable!(), + }); + } + + let sampled_type = + sampled_type.ok_or_else(|| syn::Error::new(starting_span, MISSING_SAMPLE_ERROR))?; + let format = format.ok_or_else(|| syn::Error::new(starting_span, MISSING_SAMPLE_ERROR))?; + let depth = depth.unwrap_or(ImageDepth::Unknown); + let arrayed = arrayed.unwrap_or(Arrayed::False); + let multisampled = multisampled.unwrap_or(Multisampled::False); + let sampled = sampled.unwrap_or(Sampled::Unknown); + + Ok(Self { + access_qualifier, + arrayed, + crate_root, + depth, + dimensionality, + format, + multisampled, + sampled, + sampled_type, + }) + } +} + +impl quote::ToTokens for ImageType { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let crate_root = self.crate_root.clone().unwrap_or_else(|| syn::Path { + leading_colon: None, + segments: { + let mut punct = syn::punctuated::Punctuated::new(); + punct.push(Ident::new("spirv_std", proc_macro2::Span::mixed_site()).into()); + + punct + }, + }); + let access_qualifier = match self.access_qualifier { + Some(aq) => { + let aq = params::access_qualifier_to_tokens(&aq); + quote!(Some(#crate_root::image::#aq)) + } + None => quote!(None), + }; + let dimensionality = params::dimensionality_to_tokens(&self.dimensionality); + let arrayed = params::arrayed_to_tokens(&self.arrayed); + let depth = params::image_depth_to_tokens(&self.depth); + let format = params::image_format_to_tokens(&self.format); + let multisampled = params::multisampled_to_tokens(&self.multisampled); + let sampled = params::sampled_to_tokens(&self.sampled); + let sampled_type = &self.sampled_type; + + tokens.append_all(quote::quote! { + #crate_root::image::Image< + #crate_root::image::__private::#sampled_type, + { #crate_root::image::#dimensionality }, + { #crate_root::image::#depth }, + { #crate_root::image::#arrayed }, + { #crate_root::image::#multisampled }, + { #crate_root::image::#sampled }, + { #crate_root::image::#format }, + { #access_qualifier }, + > + }) + } +} + +mod params { + use super::*; + use proc_macro2::TokenStream; + + pub fn access_qualifier_from_str(s: &str) -> Result { + match s { + "read" => Ok(AccessQualifier::ReadOnly), + "write" => Ok(AccessQualifier::WriteOnly), + "read_write" => Ok(AccessQualifier::ReadWrite), + _ => Err("Invalid access qualifier."), + } + } + + pub fn image_format_from_str(s: &str) -> Result { + Ok(match s { + "rgba32f" => ImageFormat::Rgba32f, + "rgba16f" => ImageFormat::Rgba16f, + "r32f" => ImageFormat::R32f, + "rgba8" => ImageFormat::Rgba8, + "rgba8_snorm" => ImageFormat::Rgba8Snorm, + "rg32f" => ImageFormat::Rg32f, + "rg16f" => ImageFormat::Rg16f, + "r11f_g11f_b10f" => ImageFormat::R11fG11fB10f, + "r16f" => ImageFormat::R16f, + "rgba16" => ImageFormat::Rgba16, + "rgb10_a2" => ImageFormat::Rgb10A2, + "rg16" => ImageFormat::Rg16, + "rg8" => ImageFormat::Rg8, + "r16" => ImageFormat::R16, + "r8" => ImageFormat::R8, + "rgba16_snorm" => ImageFormat::Rgba16Snorm, + "rg16_snorm" => ImageFormat::Rg16Snorm, + "rg8_snorm" => ImageFormat::Rg8Snorm, + "r16_snorm" => ImageFormat::R16Snorm, + "r8_snorm" => ImageFormat::R8Snorm, + "rgba32i" => ImageFormat::Rgba32i, + "rgba16i" => ImageFormat::Rgba16i, + "rgba8i" => ImageFormat::Rgba8i, + "r32i" => ImageFormat::R32i, + "rg32i" => ImageFormat::Rg32i, + "rg16i" => ImageFormat::Rg16i, + "rg8i" => ImageFormat::Rg8i, + "r16i" => ImageFormat::R16i, + "r8i" => ImageFormat::R8i, + "rgba32ui" => ImageFormat::Rgba32ui, + "rgba16ui" => ImageFormat::Rgba16ui, + "rgba8ui" => ImageFormat::Rgba8ui, + "r32ui" => ImageFormat::R32ui, + "rgb10_a2ui" => ImageFormat::Rgb10A2ui, + "rg32ui" => ImageFormat::Rg32ui, + "rg16ui" => ImageFormat::Rg16ui, + "rg8ui" => ImageFormat::Rg8ui, + "r16ui" => ImageFormat::R16ui, + "r8ui" => ImageFormat::R8ui, + "r64ui" => ImageFormat::R64ui, + "r64i" => ImageFormat::R64i, + _ => return Err( + "Unknown specified image format. Use `type=` instead if this is intentional.", + ), + }) + } + + /// The sampled type of an unknown image format. + pub enum SampledType { + U8, + U16, + U32, + U64, + I8, + I16, + I32, + I64, + F32, + F64, + } + + impl quote::ToTokens for SampledType { + fn to_tokens(&self, stream: &mut TokenStream) { + stream.append_all(match self { + Self::U8 => quote!(u8), + Self::U16 => quote!(u16), + Self::U32 => quote!(u32), + Self::U64 => quote!(u64), + Self::I8 => quote!(i8), + Self::I16 => quote!(i16), + Self::I32 => quote!(i32), + Self::I64 => quote!(i64), + Self::F32 => quote!(f32), + Self::F64 => quote!(f64), + }); + } + } + + pub fn access_qualifier_to_tokens(aq: &AccessQualifier) -> TokenStream { + match aq { + AccessQualifier::ReadOnly => quote!(AccessQualifier::ReadOnly), + AccessQualifier::WriteOnly => quote!(AccessQualifier::WriteOnly), + AccessQualifier::ReadWrite => quote!(AccessQualifier::ReadWrite), + } + } + + pub fn image_depth_to_tokens(id: &ImageDepth) -> TokenStream { + match id { + ImageDepth::True => quote!(ImageDepth::True), + ImageDepth::False => quote!(ImageDepth::False), + ImageDepth::Unknown => quote!(ImageDepth::Unknown), + } + } + + pub fn arrayed_to_tokens(arrayed: &Arrayed) -> TokenStream { + match arrayed { + Arrayed::True => quote!(Arrayed::True), + Arrayed::False => quote!(Arrayed::False), + } + } + + pub fn dimensionality_to_tokens(dim: &Dimensionality) -> TokenStream { + match dim { + Dimensionality::OneD => quote!(Dimensionality::OneD), + Dimensionality::TwoD => quote!(Dimensionality::TwoD), + Dimensionality::ThreeD => quote!(Dimensionality::ThreeD), + Dimensionality::Rect => quote!(Dimensionality::Rect), + Dimensionality::Cube => quote!(Dimensionality::Cube), + Dimensionality::Buffer => quote!(Dimensionality::Buffer), + Dimensionality::SubpassData => quote!(Dimensionality::SubpassData), + } + } + + pub fn multisampled_to_tokens(multisampled: &Multisampled) -> TokenStream { + match multisampled { + Multisampled::True => quote!(Multisampled::True), + Multisampled::False => quote!(Multisampled::False), + } + } + + pub fn sampled_to_tokens(sampled: &Sampled) -> TokenStream { + match sampled { + Sampled::Yes => quote!(Sampled::Yes), + Sampled::No => quote!(Sampled::No), + Sampled::Unknown => quote!(Sampled::Unknown), + } + } + + pub fn image_format_to_tokens(format: &ImageFormat) -> proc_macro2::TokenStream { + let variant = { + let variant = match format { + ImageFormat::Unknown => "Unknown", + ImageFormat::Rgba32f => "Rgba32f", + ImageFormat::Rgba16f => "Rgba16f", + ImageFormat::R32f => "R32f", + ImageFormat::Rgba8 => "Rgba8", + ImageFormat::Rgba8Snorm => "Rgba8Snorm", + ImageFormat::Rg32f => "Rg32f", + ImageFormat::Rg16f => "Rg16f", + ImageFormat::R11fG11fB10f => "R11fG11fB10f", + ImageFormat::R16f => "R16f", + ImageFormat::Rgba16 => "Rgba16", + ImageFormat::Rgb10A2 => "Rgb10A2", + ImageFormat::Rg16 => "Rg16", + ImageFormat::Rg8 => "Rg8", + ImageFormat::R16 => "R16", + ImageFormat::R8 => "R8", + ImageFormat::Rgba16Snorm => "Rgba16Snorm", + ImageFormat::Rg16Snorm => "Rg16Snorm", + ImageFormat::Rg8Snorm => "Rg8Snorm", + ImageFormat::R16Snorm => "R16Snorm", + ImageFormat::R8Snorm => "R8Snorm", + ImageFormat::Rgba32i => "Rgba32i", + ImageFormat::Rgba16i => "Rgba16i", + ImageFormat::Rgba8i => "Rgba8i", + ImageFormat::R32i => "R32i", + ImageFormat::Rg32i => "Rg32i", + ImageFormat::Rg16i => "Rg16i", + ImageFormat::Rg8i => "Rg8i", + ImageFormat::R16i => "R16i", + ImageFormat::R8i => "R8i", + ImageFormat::Rgba32ui => "Rgba32ui", + ImageFormat::Rgba16ui => "Rgba16ui", + ImageFormat::Rgba8ui => "Rgba8ui", + ImageFormat::R32ui => "R32ui", + ImageFormat::Rgb10A2ui => "Rgb10A2ui", + ImageFormat::Rg32ui => "Rg32ui", + ImageFormat::Rg16ui => "Rg16ui", + ImageFormat::Rg8ui => "Rg8ui", + ImageFormat::R16ui => "R16ui", + ImageFormat::R8ui => "R8ui", + ImageFormat::R64ui => "R64ui", + ImageFormat::R64i => "R64i", + }; + + let variant = proc_macro2::Ident::new(variant, proc_macro2::Span::mixed_site()); + + quote!(#variant) + }; + + quote!(ImageFormat::#variant) + } +} diff --git a/crates/spirv-std-macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs similarity index 80% rename from crates/spirv-std-macros/src/lib.rs rename to crates/spirv-std/macros/src/lib.rs index a5415b0266..787f7f670d 100644 --- a/crates/spirv-std-macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -53,11 +53,65 @@ // crate-specific exceptions: #![allow()] +mod image; + use proc_macro::TokenStream; use proc_macro2::{Delimiter, Group, Ident, Span, TokenTree}; use syn::{punctuated::Punctuated, spanned::Spanned, ItemFn, Token}; +use quote::ToTokens; + +/// A macro for creating SPIR-V `OpTypeImage` types. +/// +/// The grammar for the macro is as follows: +/// +/// ```no_compile +/// Image!( +/// , +/// , +/// [sampled[=],] +/// [multisampled[=],] +/// [arrayed[=],] +/// [depth[=],] +/// ) +/// ``` +/// +/// A basic example looks like this: +/// ```no_compile +/// #[spirv(vertex)] +/// fn main(#[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, type=f32)) {} +/// ``` +/// +/// ## Arguments +/// +/// - `dimensionality` — Dimensionality of an image. Accepted values: `1D`, +/// `2D`, `3D`, `rect`, `cube`, `subpass`. +/// - `type` — The sampled type of an image, mutually exclusive with `format`, +/// when set the image format is unknown. Accepted values: `f32`, `f64`, +/// `u8`, `u16`, `u32`, `u64`, `i8`, `i16`, `i32`, `i64`. +/// - `format` — The image format of the image, mutually exclusive with `type`, +/// Accepted values: Camel case versions of [`ImageFormat`]. +/// - `sampled` — Whether it is known that the image will be used with a sampler +/// at compile time, Accepted values: `true` or `false`. Default: `unknown`. +/// - `multisampled` — Whether the image contains multisampled content. Accepted +/// values: `true` or `false`. Default: `false`. +/// - `arrayed` — Whether the image contains arrayed content. Accepted +/// values: `true` or `false`. Default: `false`. +/// - `depth` — Whether it is known that the image is a depth image, +/// Accepted values: `true` or `false`. Default: `unknown`. +/// +/// [`ImageFormat`]: spirv_types::image_params::ImageFormat +#[proc_macro] +// The `Image` is supposed to be used in the type position, which +// uses `PascalCase`. +#[allow(nonstandard_style)] +pub fn Image(item: TokenStream) -> TokenStream { + let output = syn::parse_macro_input!(item as image::ImageType).into_token_stream(); + + output.into() +} + #[proc_macro_attribute] pub fn spirv(_attr: TokenStream, item: TokenStream) -> TokenStream { let mut tokens = Vec::new(); diff --git a/crates/spirv-std/shared/Cargo.toml b/crates/spirv-std/shared/Cargo.toml new file mode 100644 index 0000000000..74cd0496c8 --- /dev/null +++ b/crates/spirv-std/shared/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "spirv-types" +description = "SPIR-V types shared between spirv-std and spirv-std-macros" +version = "0.4.0-alpha.5" +authors = ["Embark "] +edition = "2018" +license = "MIT OR Apache-2.0" +repository = "https://github.com/EmbarkStudios/rust-gpu" diff --git a/crates/spirv-std/shared/src/image_params.rs b/crates/spirv-std/shared/src/image_params.rs new file mode 100644 index 0000000000..a51bf4b5aa --- /dev/null +++ b/crates/spirv-std/shared/src/image_params.rs @@ -0,0 +1,228 @@ +/// The access permissions for the image. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum AccessQualifier { + /// A read only image. + ReadOnly = 0, + /// A write only image. + WriteOnly = 1, + /// A readable and writable image. + ReadWrite = 2, +} + +/// Whether the image uses arrayed content. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Arrayed { + /// The image uses not arrayed content. + False = 0, + /// The image uses arrayed content. + True = 1, +} + +impl From for Arrayed { + fn from(val: bool) -> Self { + if val { + Self::True + } else { + Self::False + } + } +} + +/// The dimension of the image. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Dimensionality { + /// 1D + OneD = 0, + /// 2D + TwoD = 1, + /// 3D + ThreeD = 2, + /// 2D Cubemap texture + Cube = 3, + /// 2D Rectangle texture + Rect = 4, + /// 1D Buffer texture + Buffer = 5, + /// Vulkan subpass buffer + SubpassData = 6, +} + +/// Whether a given image contains [depth] information. **Note** Whether or not +/// to perform depth comparisons is a property of the sampling code, not of this +/// type. +/// +/// [depth]: https://en.wikipedia.org/wiki/Depth_map +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum ImageDepth { + /// Indicates that the image does not contain depth information. + False = 0, + /// Indicates that the image contains depth information. + True = 1, + /// Indicates that is not known ahead of time whether the image has depth + /// information or not. + Unknown = 2, +} + +impl From> for ImageDepth { + fn from(val: Option) -> Self { + match val { + Some(true) => Self::True, + Some(false) => Self::False, + None => Self::Unknown, + } + } +} + +impl From for ImageDepth { + fn from(val: bool) -> Self { + match val { + true => Self::True, + false => Self::False, + } + } +} + +/// Whether the image uses arrayed content. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Multisampled { + /// The image contains single-sampled content. + False = 0, + /// The image contains multisampled content. + True = 1, +} + +impl From for Multisampled { + fn from(val: bool) -> Self { + if val { + Self::True + } else { + Self::False + } + } +} + +/// Whether or not the image will be accessed in combination with a sampler. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Sampled { + /// Indicates that it is not known ahead of time whether the image will use + /// a sampler or not. + Unknown = 0, + /// The image will be used with a sampler. + Yes = 1, + /// The image will not be used with a sampler. + No = 2, +} + +impl From> for Sampled { + fn from(val: Option) -> Self { + match val { + Some(true) => Self::Yes, + Some(false) => Self::No, + None => Self::Unknown, + } + } +} + +impl From for Sampled { + fn from(val: bool) -> Self { + match val { + true => Self::Yes, + false => Self::No, + } + } +} + +/// The underlying internal representation of the image. +#[derive(PartialEq, Eq)] +pub enum ImageFormat { + /// Representation not known at compile time. + Unknown, + /// RGBA channels, 32 bit floating point integer. + Rgba32f, + /// RGBA channels, 16 bit floating point integer. + Rgba16f, + /// RGBA channels, 16 bit floating point integer. + R32f, + /// RGBA channels, 8 bit floating point integer. + Rgba8, + /// RGBA channels, 8 bit signed normalized integer. + Rgba8Snorm, + /// Red+Green channels, 32 bit floating point integer. + Rg32f, + /// Red+Green channels, 16 bit floating point integer. + Rg16f, + /// 32 bit unsigned integer containing two 11 bit floating point integers + /// for the Red and Green channels, and a 10 bit floating point integer for + /// the Blue channel. + R11fG11fB10f, + /// Red channel, 16 bit floating point. + R16f, + /// RGBA channel, 16 bit floating point. + Rgba16, + /// 32 bit unsigned integer containing three 10 bit unsigned normalized + /// integers for the Red, Green, and Blue channels; with a 2 unsigned + /// normalized integer for the Alpha channel. + Rgb10A2, + /// Red+Green channels, 16 bit floating point integer. + Rg16, + /// Red+Green channels, 8 bit floating point integer. + Rg8, + /// Red+Green channels, 16 bit floating point integer. + R16, + /// Red channel, 8 bit floating point integer. + R8, + /// RGBA channels, 16 bit signed normalized integer. + Rgba16Snorm, + /// RGB channels, 16 bit signed normalized integer. + Rg16Snorm, + /// Red+Green channels, 8 bit signed normalized integer. + Rg8Snorm, + /// Red channel, 16 bit signed normalized integer. + R16Snorm, + /// Red channel, 16 bit signed normalized integer. + R8Snorm, + /// RGBA channels, 32 bit signed integer. + Rgba32i, + /// RGBA channels, 16 bit signed integer. + Rgba16i, + /// RGBA channels, 8 bit signed integer. + Rgba8i, + /// Red channel, 32 bit signed integer. + R32i, + /// Red+Green channels, 32 bit signed integer. + Rg32i, + /// Red+Green channels, 16 bit signed integer. + Rg16i, + /// Red+Green channels, 8 bit signed integer. + Rg8i, + /// Red channel, 16 bit signed integer. + R16i, + /// Red channel, 8 bit signed integer. + R8i, + /// RGBA channels, 32 bit unsigned integer. + Rgba32ui, + /// RGBA channels, 16 bit unsigned integer. + Rgba16ui, + /// RGBA channels, 8 bit unsigned integer. + Rgba8ui, + /// Red channel, 32 bit unsigned integer. + R32ui, + /// 32 bit unsigned integer containing three 10 bit unsigned integers for + /// the Red, Green, and Blue channels, and a 2 bit unsigned integer for the + /// Alpha channel. + Rgb10A2ui, + /// Red+Green channels, 32 bit unsigned integer. + Rg32ui, + /// Red+Green channels, 16 bit unsigned integer. + Rg16ui, + /// Red+Green channels, 8 bit unsigned integer. + Rg8ui, + /// Red channel, 16 bit unsigned integer. + R16ui, + /// Red channel, 8 bit unsigned integer. + R8ui, + /// Red channel, 64 bit unsigned integer. + R64ui, + /// Red channel, 64 bit signed integer. + R64i, +} diff --git a/crates/spirv-std/shared/src/lib.rs b/crates/spirv-std/shared/src/lib.rs new file mode 100644 index 0000000000..7547af23df --- /dev/null +++ b/crates/spirv-std/shared/src/lib.rs @@ -0,0 +1,5 @@ +//! Small shared crate, to share definitions between `spirv-std` +//! and `spirv-std-macros`. +#![no_std] + +pub mod image_params; diff --git a/crates/spirv-std/src/arch/derivative.rs b/crates/spirv-std/src/arch/derivative.rs index 6dede6bb5c..8217c843c8 100644 --- a/crates/spirv-std/src/arch/derivative.rs +++ b/crates/spirv-std/src/arch/derivative.rs @@ -29,8 +29,8 @@ macro_rules! deriv_fn { /// Returns the partial derivative of `component` with respect to the window's X /// coordinate. Returns the same result as either [`ddx_fine`] or /// [`ddx_coarse`], selection of which one is dependent on external factors. -#[spirv_std_macros::vectorized] -#[spirv_std_macros::gpu_only] +#[crate::macros::vectorized] +#[crate::macros::gpu_only] pub fn ddx(component: F) -> F { deriv_fn!(component, OpDPdx, false) } @@ -38,8 +38,8 @@ pub fn ddx(component: F) -> F { /// Returns the partial derivative of `component` with respect to the window's X /// coordinate. Uses local differencing based on the value of `component` for /// the current fragment and its immediate neighbor(s). -#[spirv_std_macros::vectorized] -#[spirv_std_macros::gpu_only] +#[crate::macros::vectorized] +#[crate::macros::gpu_only] pub fn ddx_fine(component: F) -> F { deriv_fn!(component, OpDPdxFine, true) } @@ -50,8 +50,8 @@ pub fn ddx_fine(component: F) -> F { /// includes the value of `component` for the current fragment. That is, over a /// given area, the implementation can compute X derivatives in fewer unique /// locations than would be allowed by [`ddx_fine`]. -#[spirv_std_macros::vectorized] -#[spirv_std_macros::gpu_only] +#[crate::macros::vectorized] +#[crate::macros::gpu_only] pub fn ddx_coarse(component: F) -> F { deriv_fn!(component, OpDPdxCoarse, true) } @@ -59,8 +59,8 @@ pub fn ddx_coarse(component: F) -> F { /// Returns the partial derivative of `component` with respect to the window's Y /// coordinate. Returns the same result as either [`ddy_fine`] or /// [`ddy_coarse`], selection of which one is dependent on external factors. -#[spirv_std_macros::vectorized] -#[spirv_std_macros::gpu_only] +#[crate::macros::vectorized] +#[crate::macros::gpu_only] pub fn ddy(component: F) -> F { deriv_fn!(component, OpDPdy, false) } @@ -68,8 +68,8 @@ pub fn ddy(component: F) -> F { /// Returns the partial derivative of `component` with respect to the window's Y /// coordinate. Uses local differencing based on the value of `component` for /// the current fragment and its immediate neighbor(s). -#[spirv_std_macros::vectorized] -#[spirv_std_macros::gpu_only] +#[crate::macros::vectorized] +#[crate::macros::gpu_only] pub fn ddy_fine(component: F) -> F { deriv_fn!(component, OpDPdyFine, true) } @@ -80,32 +80,32 @@ pub fn ddy_fine(component: F) -> F { /// includes the value of `component` for the current fragment. That is, over a /// given area, the implementation can compute Y derivatives in fewer unique /// locations than would be allowed by [`ddy_fine`]. -#[spirv_std_macros::vectorized] -#[spirv_std_macros::gpu_only] +#[crate::macros::vectorized] +#[crate::macros::gpu_only] pub fn ddy_coarse(component: F) -> F { deriv_fn!(component, OpDPdyCoarse, true) } /// Returns the sum of the absolute values of [`ddx`] and [`ddy`] as a single /// operation. -#[spirv_std_macros::vectorized] -#[spirv_std_macros::gpu_only] +#[crate::macros::vectorized] +#[crate::macros::gpu_only] pub fn fwidth(component: F) -> F { deriv_fn!(component, OpFwidth, false) } /// Returns the sum of the absolute values of [`ddx_fine`] and [`ddy_fine`] as a /// single operation. -#[spirv_std_macros::vectorized] -#[spirv_std_macros::gpu_only] +#[crate::macros::vectorized] +#[crate::macros::gpu_only] pub fn fwidth_fine(component: F) -> F { deriv_fn!(component, OpFwidthFine, true) } /// Returns the sum of the absolute values of [`ddx_coarse`] and [`ddy_coarse`] /// as a single operation. -#[spirv_std_macros::vectorized] -#[spirv_std_macros::gpu_only] +#[crate::macros::vectorized] +#[crate::macros::gpu_only] pub fn fwidth_coarse(component: F) -> F { deriv_fn!(component, OpFwidthCoarse, true) } diff --git a/crates/spirv-std/src/image.rs b/crates/spirv-std/src/image.rs new file mode 100644 index 0000000000..a181768fd9 --- /dev/null +++ b/crates/spirv-std/src/image.rs @@ -0,0 +1,715 @@ +//! Image types + +// Rustfmt formats long marker trait impls over multiple lines which makes them +// harder to read. +#[rustfmt::skip] +mod params; + +pub use self::params::{ImageCoordinate, SampleType}; +pub use crate::macros::Image; +pub use spirv_types::image_params::{ + AccessQualifier, Arrayed, Dimensionality, ImageDepth, ImageFormat, Multisampled, Sampled, +}; + +use crate::{float::Float, integer::Integer, vector::Vector, Sampler}; + +/// Re-export of primitive types to ensure the `Image` proc macro always points +/// to the right type. +#[doc(hidden)] +pub mod __private { + pub use {f32, f64, i16, i32, i64, i8, u16, u32, u64, u8}; +} + +pub type Image2d = crate::Image!(2D, type=f32, sampled, __crate_root=crate); +pub type Cubemap = crate::Image!(cube, type=f32, sampled, __crate_root=crate); +pub type Image2dArray = crate::Image!(cube, type=f32, sampled, arrayed, __crate_root=crate); +pub type StorageImage2d = crate::Image!(cube, type=f32, sampled=false, __crate_root=crate); + +/// An opaque image type. Corresponds to `OpTypeImage`. +#[spirv(generic_image_type)] +#[derive(Copy, Clone)] +pub struct Image< + SampledType: SampleType, + const DIM: Dimensionality, + const DEPTH: ImageDepth, + const ARRAYED: Arrayed, + const MULTISAMPLED: Multisampled, + const SAMPLED: Sampled, + const FORMAT: ImageFormat, + const ACCESS_QUALIFIER: Option, +> { + _x: u32, + _marker: core::marker::PhantomData, +} + +impl< + SampledType: SampleType, + const DIM: Dimensionality, + const DEPTH: ImageDepth, + const ARRAYED: Arrayed, + const MULTISAMPLED: Multisampled, + const FORMAT: ImageFormat, + const ACCESS_QUALIFIER: Option, + > + Image< + SampledType, + DIM, + DEPTH, + ARRAYED, + MULTISAMPLED, + { Sampled::Yes }, + FORMAT, + ACCESS_QUALIFIER, + > +{ + /// Fetch a single texel with a sampler set at compile time + #[crate::macros::gpu_only] + #[doc(alias = "OpImageFetch")] + pub fn fetch(&self, coordinate: impl ImageCoordinate) -> V + where + V: Vector, + I: Integer, + { + let mut result = V::default(); + unsafe { + asm! { + "%image = OpLoad _ {this}", + "%coordinate = OpLoad _ {coordinate}", + "%result = OpImageFetch typeof*{result} %image %coordinate", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + coordinate = in(reg) &coordinate, + } + } + result + } +} + +impl< + SampledType: SampleType, + const DIM: Dimensionality, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const ACCESS_QUALIFIER: Option, + > + Image< + SampledType, + DIM, + DEPTH, + ARRAYED, + { Multisampled::False }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ + /// Sample texels at `coord` from the image using `sampler`. + #[crate::macros::gpu_only] + pub fn sample(&self, sampler: Sampler, coord: impl ImageCoordinate) -> 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", + "OpStore {0} %result", + in(reg) &mut result, + in(reg) self, + in(reg) &sampler, + in(reg) &coord + ); + result + } + } + + /// Fetch a single texel with a sampler set at compile time + #[crate::macros::gpu_only] + #[doc(alias = "OpImageSampleExplicitLod")] + /// Sample the image at a coordinate by a lod + pub fn sample_by_lod( + &self, + sampler: Sampler, + coordinate: impl ImageCoordinate, + lod: f32, + ) -> V + where + F: Float, + V: Vector, + { + 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 + } + + #[crate::macros::gpu_only] + #[doc(alias = "OpImageSampleExplicitLod")] + /// 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 ImageCoordinate, + gradient_dx: impl ImageCoordinate, + gradient_dy: impl ImageCoordinate, + ) -> V + where + F: Float, + V: Vector, + { + 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 + } + + #[crate::macros::gpu_only] + #[doc(alias = "OpImageSampleDrefImplicitLod")] + /// Sample the image's depth reference + pub fn sample_depth_reference( + &self, + sampler: Sampler, + coordinate: impl ImageCoordinate, + depth_reference: f32, + ) -> SampledType + where + F: Float, + { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%coordinate = OpLoad _ {coordinate}", + "%depth_reference = OpLoad _ {depth_reference}", // not required to do this way, but done for consistency + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleDrefImplicitLod _ %sampledImage %coordinate %depth_reference", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + coordinate = in(reg) &coordinate, + depth_reference = in(reg) &depth_reference, + ); + } + result + } + + #[crate::macros::gpu_only] + #[doc(alias = "OpImageSampleDrefExplicitLod")] + /// Sample the image's depth reference based on an explicit lod + pub fn sample_depth_reference_by_lod( + &self, + sampler: Sampler, + coordinate: impl ImageCoordinate, + depth_reference: f32, + lod: f32, + ) -> SampledType + where + F: Float, + { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%coordinate = OpLoad _ {coordinate}", + "%depth_reference = OpLoad _ {depth_reference}", + "%lod = OpLoad _ {lod}", + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleDrefExplicitLod _ %sampledImage %coordinate %depth_reference Lod %lod", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + coordinate = in(reg) &coordinate, + depth_reference = in(reg) &depth_reference, + lod = in(reg) &lod, + ) + } + result + } + + #[crate::macros::gpu_only] + #[doc(alias = "OpImageSampleDrefExplicitLod")] + /// Sample the image's depth reference based on a gradient formed by (dx, dy). + /// Specifically, ([du/dx, dv/dx], [du/dy, dv/dy]) + pub fn sample_depth_reference_by_gradient( + &self, + sampler: Sampler, + coordinate: impl ImageCoordinate, + depth_reference: f32, + gradient_dx: impl ImageCoordinate, + gradient_dy: impl ImageCoordinate, + ) -> SampledType + where + F: Float, + { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%coordinate = OpLoad _ {coordinate}", + "%depth_reference = OpLoad _ {depth_reference}", + "%gradient_dx = OpLoad _ {gradient_dx}", + "%gradient_dy = OpLoad _ {gradient_dy}", + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleDrefExplicitLod _ %sampledImage %coordinate %depth_reference 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, + depth_reference = in(reg) &depth_reference, + gradient_dx = in(reg) &gradient_dx, + gradient_dy = in(reg) &gradient_dy, + ); + } + result + } +} + +impl< + SampledType: SampleType, + const DIM: Dimensionality, + const DEPTH: ImageDepth, + const SAMPLED: Sampled, + const FORMAT: ImageFormat, + const ACCESS_QUALIFIER: Option, + > + Image< + SampledType, + DIM, + DEPTH, + { Arrayed::False }, + { Multisampled::False }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + > +{ + /// Fetch a single texel with a sampler set at compile time + #[crate::macros::gpu_only] + #[doc(alias = "OpImageFetch")] + pub fn sample_with_project_coordinate( + &self, + sampler: Sampler, + project_coordinate: impl ImageCoordinate, + ) -> V + where + F: Float, + V: Vector, + { + unsafe { + let mut result = Default::default(); + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%project_coordinate = OpLoad _ {project_coordinate}", + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleProjImplicitLod _ %sampledImage %project_coordinate", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + project_coordinate = in(reg) &project_coordinate, + ); + result + } + } + + #[crate::macros::gpu_only] + #[doc(alias = "OpImageSampleProjExplicitLod")] + /// Sample the image with a project coordinate by a lod + pub fn sample_with_project_coordinate_by_lod( + &self, + sampler: Sampler, + project_coordinate: impl ImageCoordinate, + lod: f32, + ) -> V + where + F: Float, + V: Vector, + { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%project_coordinate = OpLoad _ {project_coordinate}", + "%lod = OpLoad _ {lod}", + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleProjExplicitLod _ %sampledImage %project_coordinate Lod %lod", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + project_coordinate = in(reg) &project_coordinate, + lod = in(reg) &lod + ); + } + result + } + + #[crate::macros::gpu_only] + #[doc(alias = "OpImageSampleProjExplicitLod")] + /// Sample the image with a project coordinate based on a gradient formed by (dx, dy). Specifically, ([du/dx, dv/dx], [du/dy, dv/dy]) + pub fn sample_with_project_coordinate_by_gradient( + &self, + sampler: Sampler, + project_coordinate: impl ImageCoordinate, + gradient_dx: impl ImageCoordinate, + gradient_dy: impl ImageCoordinate, + ) -> V + where + F: Float, + V: Vector, + { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%project_coordinate = OpLoad _ {project_coordinate}", + "%gradient_dx = OpLoad _ {gradient_dx}", + "%gradient_dy = OpLoad _ {gradient_dy}", + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleProjExplicitLod _ %sampledImage %project_coordinate Grad %gradient_dx %gradient_dy", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + project_coordinate = in(reg) &project_coordinate, + gradient_dx = in(reg) &gradient_dx, + gradient_dy = in(reg) &gradient_dy, + ); + } + result + } + + #[crate::macros::gpu_only] + #[doc(alias = "OpImageSampleProjDrefImplicitLod")] + /// Sample the image's depth reference with the project coordinate + pub fn sample_depth_reference_with_project_coordinate( + &self, + sampler: Sampler, + project_coordinate: impl ImageCoordinate, + depth_reference: f32, + ) -> SampledType + where + F: Float, + { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%project_coordinate = OpLoad _ {project_coordinate}", + "%depth_reference = OpLoad _ {depth_reference}", // not required to do this way, but done for consistency + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleProjDrefImplicitLod _ %sampledImage %project_coordinate %depth_reference", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + project_coordinate = in(reg) &project_coordinate, + depth_reference = in(reg) &depth_reference, + ); + } + result + } + + #[crate::macros::gpu_only] + #[doc(alias = "OpImageSampleProjDrefExplicitLod")] + /// Sample the image's depth reference with the project coordinate based on an explicit lod + pub fn sample_depth_reference_with_project_coordinate_by_lod( + &self, + sampler: Sampler, + coordinate: impl ImageCoordinate, + depth_reference: f32, + lod: f32, + ) -> SampledType + where + F: Float, + { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%coordinate = OpLoad _ {coordinate}", + "%depth_reference = OpLoad _ {depth_reference}", + "%lod = OpLoad _ {lod}", + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleProjDrefExplicitLod _ %sampledImage %coordinate %depth_reference Lod %lod", + "OpStore {result} %result", + result = in(reg) &mut result, + this = in(reg) self, + sampler = in(reg) &sampler, + coordinate = in(reg) &coordinate, + depth_reference = in(reg) &depth_reference, + lod = in(reg) &lod, + ) + } + result + } + + #[crate::macros::gpu_only] + #[doc(alias = "OpImageSampleProjDrefExplicitLod")] + /// Sample the image's depth reference with the project coordinate based on a gradient formed by (dx, dy). + /// Specifically, ([du/dx, dv/dx], [du/dy, dv/dy]) + pub fn sample_depth_reference_with_project_coordinate_by_gradient( + &self, + sampler: Sampler, + coordinate: impl ImageCoordinate, + depth_reference: f32, + gradient_dx: impl ImageCoordinate, + gradient_dy: impl ImageCoordinate, + ) -> SampledType + where + F: Float, + { + let mut result = Default::default(); + unsafe { + asm!( + "%image = OpLoad _ {this}", + "%sampler = OpLoad _ {sampler}", + "%coordinate = OpLoad _ {coordinate}", + "%depth_reference = OpLoad _ {depth_reference}", + "%gradient_dx = OpLoad _ {gradient_dx}", + "%gradient_dy = OpLoad _ {gradient_dy}", + "%sampledImage = OpSampledImage _ %image %sampler", + "%result = OpImageSampleProjDrefExplicitLod _ %sampledImage %coordinate %depth_reference 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, + depth_reference = in(reg) &depth_reference, + gradient_dx = in(reg) &gradient_dx, + gradient_dy = in(reg) &gradient_dy, + ); + } + result + } +} + +impl< + SampledType: SampleType, + const DIM: Dimensionality, + const DEPTH: ImageDepth, + const ARRAYED: Arrayed, + const MULTISAMPLED: Multisampled, + const FORMAT: ImageFormat, + const ACCESS_QUALIFIER: Option, + > + Image +{ + /// Read a texel from an image without a sampler. + #[crate::macros::gpu_only] + #[doc(alias = "OpImageRead")] + pub fn read(&self, coordinate: impl ImageCoordinate) -> V + where + I: Integer, + V: Vector, + { + let mut result = V::default(); + + unsafe { + asm! { + "%image = OpLoad _ {this}", + "%coordinate = OpLoad _ {coordinate}", + "%result = OpImageRead typeof*{result} %image %coordinate", + "OpStore {result} %result", + this = in(reg) self, + coordinate = in(reg) &coordinate, + result = in(reg) &mut result, + } + } + + result + } + + /// Write a texel to an image without a sampler. + #[crate::macros::gpu_only] + #[doc(alias = "OpImageWrite")] + pub unsafe fn write( + &self, + coordinate: impl ImageCoordinate, + texels: impl Vector, + ) where + I: Integer, + { + asm! { + "%image = OpLoad _ {this}", + "%coordinate = OpLoad _ {coordinate}", + "%texels = OpLoad _ {texels}", + "OpImageWrite %image %coordinate %texels", + this = in(reg) self, + coordinate = in(reg) &coordinate, + texels = in(reg) &texels, + } + } +} + +impl< + SampledType: SampleType, + const DIM: Dimensionality, + const DEPTH: ImageDepth, + const FORMAT: ImageFormat, + const ARRAYED: Arrayed, + const MULTISAMPLED: Multisampled, + const ACCESS_QUALIFIER: Option, + > + Image< + SampledType, + DIM, + DEPTH, + ARRAYED, + MULTISAMPLED, + { Sampled::Unknown }, + FORMAT, + ACCESS_QUALIFIER, + > +{ + /// Read a texel from an image without a sampler. + #[crate::macros::gpu_only] + #[doc(alias = "OpImageRead")] + pub fn read(&self, coordinate: impl ImageCoordinate) -> V + where + I: Integer, + V: Vector, + { + let mut result = V::default(); + + unsafe { + asm! { + "%image = OpLoad _ {this}", + "%coordinate = OpLoad _ {coordinate}", + "%result = OpImageRead typeof*{result} %image %coordinate", + "OpStore {result} %result", + this = in(reg) self, + coordinate = in(reg) &coordinate, + result = in(reg) &mut result, + } + } + + result + } + + /// Write a texel to an image without a sampler. + #[crate::macros::gpu_only] + #[doc(alias = "OpImageWrite")] + pub unsafe fn write( + &self, + coordinate: impl ImageCoordinate, + texels: impl Vector, + ) where + I: Integer, + { + asm! { + "%image = OpLoad _ {this}", + "%coordinate = OpLoad _ {coordinate}", + "%texels = OpLoad _ {texels}", + "OpImageWrite %image %coordinate %texels", + this = in(reg) self, + coordinate = in(reg) &coordinate, + texels = in(reg) &texels, + } + } +} + +/// An image combined with a sampler, enabling filtered accesses of the +/// image’s contents. +#[spirv(sampled_image)] +#[derive(Copy, Clone)] +pub struct SampledImage { + _image: I, +} + +impl< + SampledType: SampleType, + const DIM: Dimensionality, + const DEPTH: ImageDepth, + const ARRAYED: Arrayed, + const SAMPLED: Sampled, + const FORMAT: ImageFormat, + const ACCESS_QUALIFIER: Option, + > + SampledImage< + Image< + SampledType, + DIM, + DEPTH, + ARRAYED, + { Multisampled::False }, + SAMPLED, + FORMAT, + ACCESS_QUALIFIER, + >, + > +{ + /// Sample texels at `coord` from the sampled image. + /// + /// # Safety + /// Sampling with a type (`S`) that doesn't match the image's image format + /// will result in undefined behaviour. + #[crate::macros::gpu_only] + pub unsafe fn sample(&self, coord: impl ImageCoordinate) -> V + where + F: Float, + V: Vector, + { + let mut result = Default::default(); + asm!( + "%sampledImage = OpLoad typeof*{1} {1}", + "%coord = OpLoad typeof*{2} {2}", + "%result = OpImageSampleImplicitLod typeof*{0} %sampledImage %coord", + "OpStore {0} %result", + in(reg) &mut result, + in(reg) self, + in(reg) &coord + ); + result + } +} diff --git a/crates/spirv-std/src/image/params.rs b/crates/spirv-std/src/image/params.rs new file mode 100644 index 0000000000..b46d0eb0dd --- /dev/null +++ b/crates/spirv-std/src/image/params.rs @@ -0,0 +1,74 @@ +use super::{Arrayed, Dimensionality, ImageFormat}; +use crate::{scalar::Scalar, vector::Vector}; + +/// Marker trait for arguments that accept single scalar values or vectors +/// of scalars. +pub trait SampleType: Scalar {} + +impl SampleType<{ ImageFormat::Unknown }> for i8 {} +impl SampleType<{ ImageFormat::Unknown }> for i16 {} +impl SampleType<{ ImageFormat::Unknown }> for i32 {} +impl SampleType<{ ImageFormat::Unknown }> for i64 {} +impl SampleType<{ ImageFormat::Unknown }> for u8 {} +impl SampleType<{ ImageFormat::Unknown }> for u16 {} +impl SampleType<{ ImageFormat::Unknown }> for u32 {} +impl SampleType<{ ImageFormat::Unknown }> for u64 {} +impl SampleType<{ ImageFormat::Unknown }> for f32 {} +impl SampleType<{ ImageFormat::Unknown }> for f64 {} +impl SampleType<{ ImageFormat::Rgba32f }> for f32 {} +impl SampleType<{ ImageFormat::Rgba16f }> for f32 {} +impl SampleType<{ ImageFormat::R32f }> for f32 {} +impl SampleType<{ ImageFormat::Rgba8 }> for f32 {} +impl SampleType<{ ImageFormat::Rgba8Snorm }> for f32 {} +impl SampleType<{ ImageFormat::Rg32f }> for f32 {} +impl SampleType<{ ImageFormat::Rg16f }> for f32 {} +impl SampleType<{ ImageFormat::R11fG11fB10f }> for f32 {} +impl SampleType<{ ImageFormat::R16f }> for f32 {} +impl SampleType<{ ImageFormat::Rgba16 }> for f32 {} +impl SampleType<{ ImageFormat::Rgb10A2 }> for f32 {} +impl SampleType<{ ImageFormat::Rg16 }> for f32 {} +impl SampleType<{ ImageFormat::Rg8 }> for f32 {} +impl SampleType<{ ImageFormat::R16 }> for f32 {} +impl SampleType<{ ImageFormat::R8 }> for f32 {} +impl SampleType<{ ImageFormat::Rgba16Snorm }> for f32 {} +impl SampleType<{ ImageFormat::Rg16Snorm }> for f32 {} +impl SampleType<{ ImageFormat::Rg8Snorm }> for f32 {} +impl SampleType<{ ImageFormat::R16Snorm }> for f32 {} +impl SampleType<{ ImageFormat::R8Snorm }> for f32 {} +impl SampleType<{ ImageFormat::Rgba32i }> for i32 {} +impl SampleType<{ ImageFormat::Rgba16i }> for i32 {} +impl SampleType<{ ImageFormat::Rgba8i }> for i32 {} +impl SampleType<{ ImageFormat::R32i }> for i32 {} +impl SampleType<{ ImageFormat::Rg32i }> for i32 {} +impl SampleType<{ ImageFormat::Rg16i }> for i32 {} +impl SampleType<{ ImageFormat::Rg8i }> for i32 {} +impl SampleType<{ ImageFormat::R16i }> for i32 {} +impl SampleType<{ ImageFormat::R8i }> for i32 {} +impl SampleType<{ ImageFormat::Rgba32ui }> for u32 {} +impl SampleType<{ ImageFormat::Rgba16ui }> for u32 {} +impl SampleType<{ ImageFormat::Rgba8ui }> for u32 {} +impl SampleType<{ ImageFormat::R32ui }> for u32 {} +impl SampleType<{ ImageFormat::Rgb10A2ui }> for u32 {} +impl SampleType<{ ImageFormat::Rg32ui }> for u32 {} +impl SampleType<{ ImageFormat::Rg16ui }> for u32 {} +impl SampleType<{ ImageFormat::Rg8ui }> for u32 {} +impl SampleType<{ ImageFormat::R16ui }> for u32 {} +impl SampleType<{ ImageFormat::R8ui }> for u32 {} +impl SampleType<{ ImageFormat::R64ui }> for u64 {} +impl SampleType<{ ImageFormat::R64i }> for i64 {} + +/// Marker trait for arguments that accept a coordinate for an [`crate::Image`]. +pub trait ImageCoordinate {} + +impl ImageCoordinate for S {} +impl ImageCoordinate for S {} + +impl, S: Scalar> ImageCoordinate for V {} +impl, S: Scalar> ImageCoordinate for V {} +impl, S: Scalar> ImageCoordinate for V {} +impl, S: Scalar> ImageCoordinate for V {} + +impl, S: Scalar> ImageCoordinate for V {} +impl, S: Scalar> ImageCoordinate for V {} +impl, S: Scalar> ImageCoordinate for V {} +impl, S: Scalar> ImageCoordinate for V {} diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index c1f0b685cc..2ecde0ab1a 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -68,22 +68,28 @@ // We deblierately provide an unimplemented version of our API on CPU // platforms so that code completion still works. clippy::unimplemented, + // The part of `const-generics` we're using (C-like enums) is not incomplete. + incomplete_features, )] -#[macro_use] -#[cfg(not(target_arch = "spirv"))] +#[cfg_attr(not(target_arch = "spirv"), macro_use)] pub extern crate spirv_std_macros as macros; pub mod arch; pub mod float; +#[cfg(feature = "const-generics")] +pub mod image; pub mod integer; pub mod memory; pub mod ray_tracing; +mod sampler; pub mod scalar; pub(crate) mod sealed; mod textures; pub mod vector; +pub use self::sampler::Sampler; +pub use crate::macros::Image; pub use num_traits; pub use textures::*; diff --git a/crates/spirv-std/src/sampler.rs b/crates/spirv-std/src/sampler.rs new file mode 100644 index 0000000000..ef04a61642 --- /dev/null +++ b/crates/spirv-std/src/sampler.rs @@ -0,0 +1,7 @@ +/// An opaque reference to settings that describe how to access, filter, or +/// sample an image. +#[spirv(sampler)] +#[derive(Copy, Clone)] +pub struct Sampler { + _x: u32, +} diff --git a/crates/spirv-std/src/textures.rs b/crates/spirv-std/src/textures.rs index 86aa662956..4ff525c5bd 100644 --- a/crates/spirv-std/src/textures.rs +++ b/crates/spirv-std/src/textures.rs @@ -1,11 +1,11 @@ use crate::{integer::Integer, vector::Vector}; -#[spirv(sampler)] -#[derive(Copy, Clone)] -pub struct Sampler { - _x: u32, -} +pub use crate::sampler::Sampler; +#[cfg_attr( + feature = "const-generics", + deprecated = "Legacy image type. Use `spirv_std::image::Image2d` instead." +)] #[spirv(image_type( // sampled_type is hardcoded to f32 for now dim = "Dim2D", @@ -20,6 +20,7 @@ pub struct Image2d { _x: u32, } +#[allow(deprecated)] impl Image2d { #[spirv_std_macros::gpu_only] #[doc(alias = "OpImageSampleImplicitLod")] @@ -412,6 +413,10 @@ impl Image2d { } } +#[cfg_attr( + feature = "const-generics", + deprecated = "Legacy image type. Use `spirv_std::image::StorageImage2d` instead." +)] #[spirv(image_type( // sampled_type is hardcoded to f32 for now dim = "Dim2D", @@ -426,6 +431,7 @@ pub struct StorageImage2d { _x: u32, } +#[allow(deprecated)] impl StorageImage2d { /// Read a texel from an image without a sampler. #[spirv_std_macros::gpu_only] @@ -474,6 +480,10 @@ impl StorageImage2d { } } +#[cfg_attr( + feature = "const-generics", + deprecated = "Legacy image type. Use `spirv_std::image::Image2dArray` instead." +)] #[spirv(image_type( // sampled_type is hardcoded to f32 for now dim = "Dim2D", @@ -488,6 +498,7 @@ pub struct Image2dArray { _x: u32, } +#[allow(deprecated)] impl Image2dArray { #[spirv_std_macros::gpu_only] #[doc(alias = "OpImageSampleImplicitLod")] @@ -673,6 +684,10 @@ impl Image2dArray { } } +#[cfg_attr( + feature = "const-generics", + deprecated = "Legacy image type. Use `spirv_std::image::Cubemap` instead." +)] #[spirv(image_type( // sampled_type is hardcoded to f32 for now dim = "DimCube", @@ -687,6 +702,7 @@ pub struct Cubemap { _x: u32, } +#[allow(deprecated)] impl Cubemap { #[spirv_std_macros::gpu_only] #[doc(alias = "OpSampledImage")] @@ -872,12 +888,17 @@ impl Cubemap { } } +#[cfg_attr( + feature = "const-generics", + deprecated = "Legacy image type. Use `spirv_std::image::SampledImage` instead." +)] #[spirv(sampled_image)] #[derive(Copy, Clone)] pub struct SampledImage { _image: I, } +#[allow(deprecated)] impl SampledImage { #[spirv_std_macros::gpu_only] #[doc(alias = "OpImageSampleImplicitLod")] diff --git a/examples/shaders/compute-shader/Cargo.toml b/examples/shaders/compute-shader/Cargo.toml index 6a325d3f05..477b89963e 100644 --- a/examples/shaders/compute-shader/Cargo.toml +++ b/examples/shaders/compute-shader/Cargo.toml @@ -9,5 +9,4 @@ license = "MIT OR Apache-2.0" crate-type = ["dylib"] [dependencies] -spirv-std-macros = { path = "../../../crates/spirv-std-macros" } spirv-std = { path = "../../../crates/spirv-std" } diff --git a/examples/shaders/compute-shader/src/lib.rs b/examples/shaders/compute-shader/src/lib.rs index 19b3435087..84cfb2366e 100644 --- a/examples/shaders/compute-shader/src/lib.rs +++ b/examples/shaders/compute-shader/src/lib.rs @@ -10,8 +10,7 @@ extern crate spirv_std; #[cfg(not(target_arch = "spirv"))] -#[macro_use] -pub extern crate spirv_std_macros; +use spirv_std::macros::spirv; // LocalSize/numthreads of (x = 32, y = 1, z = 1) #[spirv(compute(threads(32)))] diff --git a/examples/shaders/shared/Cargo.toml b/examples/shaders/shared/Cargo.toml index bc1f4cda9b..75d5155fa5 100644 --- a/examples/shaders/shared/Cargo.toml +++ b/examples/shaders/shared/Cargo.toml @@ -7,6 +7,5 @@ license = "MIT OR Apache-2.0" publish = false [dependencies] -spirv-std-macros = { path = "../../../crates/spirv-std-macros" } spirv-std = { path = "../../../crates/spirv-std" } glam = { version = "0.14", default-features = false, features = ["libm", "scalar-math", "spirv-std"] } diff --git a/examples/shaders/simplest-shader/Cargo.toml b/examples/shaders/simplest-shader/Cargo.toml index 2deb5e76a4..07ec9080ba 100644 --- a/examples/shaders/simplest-shader/Cargo.toml +++ b/examples/shaders/simplest-shader/Cargo.toml @@ -10,6 +10,5 @@ publish = false crate-type = ["dylib"] [dependencies] -spirv-std-macros = { path = "../../../crates/spirv-std-macros" } spirv-std = { path = "../../../crates/spirv-std" } shared = { path = "../shared" } diff --git a/examples/shaders/simplest-shader/src/lib.rs b/examples/shaders/simplest-shader/src/lib.rs index b602a12d4b..5221084905 100644 --- a/examples/shaders/simplest-shader/src/lib.rs +++ b/examples/shaders/simplest-shader/src/lib.rs @@ -8,8 +8,8 @@ #![deny(warnings)] #[cfg(not(target_arch = "spirv"))] -#[macro_use] -pub extern crate spirv_std_macros; +use spirv_std::macros::spirv; + use shared::glam::{vec4, Vec4}; #[spirv(fragment)] diff --git a/examples/shaders/sky-shader/Cargo.toml b/examples/shaders/sky-shader/Cargo.toml index 3960b8b3e2..32f0623cf9 100644 --- a/examples/shaders/sky-shader/Cargo.toml +++ b/examples/shaders/sky-shader/Cargo.toml @@ -11,5 +11,4 @@ crate-type = ["dylib"] [dependencies] shared = { path = "../../shaders/shared" } -spirv-std-macros = { path = "../../../crates/spirv-std-macros" } spirv-std = { path = "../../../crates/spirv-std" } diff --git a/examples/shaders/sky-shader/src/lib.rs b/examples/shaders/sky-shader/src/lib.rs index 9f2f6e9de9..ba95a6dc3b 100644 --- a/examples/shaders/sky-shader/src/lib.rs +++ b/examples/shaders/sky-shader/src/lib.rs @@ -10,8 +10,7 @@ #![deny(warnings)] #[cfg(not(target_arch = "spirv"))] -#[macro_use] -pub extern crate spirv_std_macros; +use spirv_std::macros::spirv; use core::f32::consts::PI; use glam::{const_vec3, vec2, vec3, Vec2, Vec3, Vec4}; diff --git a/tests/ui/image/fetch.rs b/tests/ui/image/fetch.rs index b8740ece6d..ac18c9cd96 100644 --- a/tests/ui/image/fetch.rs +++ b/tests/ui/image/fetch.rs @@ -1,9 +1,12 @@ // build-pass -use spirv_std::{arch, Image2d}; +use spirv_std::{arch, Image}; #[spirv(fragment)] -pub fn main(#[spirv(descriptor_set = 0, binding = 0)] image: &Image2d, output: &mut glam::Vec4) { +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, type=f32, sampled), + output: &mut glam::Vec4, +) { let texel = image.fetch(glam::IVec2::new(0, 1)); *output = texel; } diff --git a/tests/ui/image/format.rs b/tests/ui/image/format.rs new file mode 100644 index 0000000000..f1aff17fb7 --- /dev/null +++ b/tests/ui/image/format.rs @@ -0,0 +1,12 @@ +// build-pass + +use spirv_std::{arch, Image}; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, format=rgba32f, sampled), + output: &mut glam::Vec4, +) { + let texel = image.fetch(glam::IVec2::new(0, 1)); + *output = texel; +} diff --git a/tests/ui/image/issue_527.rs b/tests/ui/image/issue_527.rs index 50c7f62bb9..7d9a43d8e9 100644 --- a/tests/ui/image/issue_527.rs +++ b/tests/ui/image/issue_527.rs @@ -4,7 +4,7 @@ use glam::*; pub fn main_cs( #[spirv(global_invocation_id)] id: UVec3, #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] points_buffer: &mut [UVec2; 100], - #[spirv(descriptor_set = 1, binding = 1)] image: &spirv_std::StorageImage2d, + #[spirv(descriptor_set = 1, binding = 1)] image: &spirv_std::Image!(2D, type=f32, sampled=false), ) { unsafe { asm!("OpCapability StorageImageWriteWithoutFormat") }; let position = id.xy(); diff --git a/tests/ui/image/read.rs b/tests/ui/image/read.rs index 9aa81ee3a3..7f13a9e96e 100644 --- a/tests/ui/image/read.rs +++ b/tests/ui/image/read.rs @@ -1,11 +1,11 @@ // Test `OpImageRead` // build-pass -use spirv_std::{arch, StorageImage2d}; +use spirv_std::{arch, Image}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image: &StorageImage2d, + #[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, type=f32, sampled=false), output: &mut glam::Vec4, ) { unsafe { asm!("OpCapability StorageImageReadWithoutFormat") }; diff --git a/tests/ui/image/sample.rs b/tests/ui/image/sample.rs index 66bec07efa..6d4af97f0b 100644 --- a/tests/ui/image/sample.rs +++ b/tests/ui/image/sample.rs @@ -1,13 +1,13 @@ // Test `OpImageSampleImplicitLod` // build-pass -use spirv_std::{arch, Cubemap, Image2d, Image2dArray, Sampler}; +use spirv_std::{arch, Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image2d, - #[spirv(descriptor_set = 1, binding = 1)] image2d_array: &Image2dArray, - #[spirv(descriptor_set = 2, binding = 2)] cubemap: &Cubemap, + #[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, ) { diff --git a/tests/ui/image/sample_depth_reference/sample.rs b/tests/ui/image/sample_depth_reference/sample.rs index c82ef200b4..004edb4523 100644 --- a/tests/ui/image/sample_depth_reference/sample.rs +++ b/tests/ui/image/sample_depth_reference/sample.rs @@ -1,13 +1,13 @@ // Test `OpImageSampleDrefImplicitLod` // build-pass -use spirv_std::{arch, Cubemap, Image2d, Image2dArray, Sampler}; +use spirv_std::{arch, Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image: &Image2d, - #[spirv(descriptor_set = 1, binding = 1)] image_array: &Image2dArray, - #[spirv(descriptor_set = 2, binding = 2)] cubemap: &Cubemap, + #[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, type=f32, sampled), + #[spirv(descriptor_set = 1, binding = 1)] image_array: &Image!(2D, type=f32, arrayed, sampled), + #[spirv(descriptor_set = 2, binding = 2)] cubemap: &Image!(cube, type=f32, sampled), #[spirv(descriptor_set = 3, binding = 3)] sampler: &Sampler, output: &mut f32, ) { diff --git a/tests/ui/image/sample_depth_reference/sample_gradient.rs b/tests/ui/image/sample_depth_reference/sample_gradient.rs index dcbb4f0403..319b964eaf 100644 --- a/tests/ui/image/sample_depth_reference/sample_gradient.rs +++ b/tests/ui/image/sample_depth_reference/sample_gradient.rs @@ -1,14 +1,14 @@ // Test `OpImageSampleDrefExplicitLod` // build-pass -use spirv_std::{arch, Cubemap, Image2d, Image2dArray, Sampler}; +use spirv_std::{Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image: &Image2d, - #[spirv(descriptor_set = 1, binding = 1)] image_array: &Image2dArray, + #[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, type=f32, sampled), + #[spirv(descriptor_set = 1, binding = 1)] image_array: &Image!(2D, type=f32, arrayed, sampled), #[spirv(descriptor_set = 2, binding = 2)] sampler: &Sampler, - #[spirv(descriptor_set = 3, binding = 3)] cubemap: &Cubemap, + #[spirv(descriptor_set = 3, binding = 3)] cubemap: &Image!(3D, type=f32, sampled), output: &mut f32, ) { let v2 = glam::Vec2::new(0.0, 1.0); diff --git a/tests/ui/image/sample_depth_reference/sample_lod.rs b/tests/ui/image/sample_depth_reference/sample_lod.rs index 6c4b926c29..9c9f49fdb6 100644 --- a/tests/ui/image/sample_depth_reference/sample_lod.rs +++ b/tests/ui/image/sample_depth_reference/sample_lod.rs @@ -1,14 +1,14 @@ // Test `OpImageSampleDrefExplicitLod` // build-pass -use spirv_std::{arch, Cubemap, Image2d, Image2dArray, Sampler}; +use spirv_std::{Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image: &Image2d, - #[spirv(descriptor_set = 1, binding = 1)] image_array: &Image2dArray, + #[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, type=f32, sampled), + #[spirv(descriptor_set = 1, binding = 1)] image_array: &Image!(2D, type=f32, arrayed, sampled), #[spirv(descriptor_set = 2, binding = 2)] sampler: &Sampler, - #[spirv(descriptor_set = 3, binding = 3)] cubemap: &Cubemap, + #[spirv(descriptor_set = 3, binding = 3)] cubemap: &Image!(3D, type=f32), output: &mut f32, ) { let v2 = glam::Vec2::new(0.0, 1.0); diff --git a/tests/ui/image/sample_depth_reference_with_project_coordinate/sample.rs b/tests/ui/image/sample_depth_reference_with_project_coordinate/sample.rs index 4b357cafa6..45ab323403 100644 --- a/tests/ui/image/sample_depth_reference_with_project_coordinate/sample.rs +++ b/tests/ui/image/sample_depth_reference_with_project_coordinate/sample.rs @@ -1,11 +1,11 @@ // Test `OpImageSampleProjDrefImplicitLod` // build-pass -use spirv_std::{arch, Image2d, Sampler}; +use spirv_std::{arch, Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image: &Image2d, + #[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, type=f32, sampled), #[spirv(descriptor_set = 1, binding = 1)] sampler: &Sampler, output: &mut f32, ) { diff --git a/tests/ui/image/sample_depth_reference_with_project_coordinate/sample_gradient.rs b/tests/ui/image/sample_depth_reference_with_project_coordinate/sample_gradient.rs index 482aa23264..7ebba0ad81 100644 --- a/tests/ui/image/sample_depth_reference_with_project_coordinate/sample_gradient.rs +++ b/tests/ui/image/sample_depth_reference_with_project_coordinate/sample_gradient.rs @@ -1,11 +1,11 @@ // Test `OpImageSampleProjDrefExplicitLod` // build-pass -use spirv_std::{arch, Image2d, Sampler}; +use spirv_std::{Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image: &Image2d, + #[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, type=f32, sampled), #[spirv(descriptor_set = 1, binding = 1)] sampler: &Sampler, output: &mut f32, ) { diff --git a/tests/ui/image/sample_depth_reference_with_project_coordinate/sample_lod.rs b/tests/ui/image/sample_depth_reference_with_project_coordinate/sample_lod.rs index f94e0d301c..8212d88d41 100644 --- a/tests/ui/image/sample_depth_reference_with_project_coordinate/sample_lod.rs +++ b/tests/ui/image/sample_depth_reference_with_project_coordinate/sample_lod.rs @@ -1,11 +1,11 @@ // Test `OpImageSampleProjDrefExplicitLod` // build-pass -use spirv_std::{arch, Image2d, Sampler}; +use spirv_std::{Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image: &Image2d, + #[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, type=f32, sampled), #[spirv(descriptor_set = 1, binding = 1)] sampler: &Sampler, output: &mut f32, ) { diff --git a/tests/ui/image/sample_gradient.rs b/tests/ui/image/sample_gradient.rs index e18d36e091..09a82bb000 100644 --- a/tests/ui/image/sample_gradient.rs +++ b/tests/ui/image/sample_gradient.rs @@ -1,13 +1,13 @@ // Test `OpImageSampleExplicitLod` Grad // build-pass -use spirv_std::{arch, Cubemap, Image2d, Image2dArray, Sampler}; +use spirv_std::{arch, Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image2d, - #[spirv(descriptor_set = 1, binding = 1)] image2d_array: &Image2dArray, - #[spirv(descriptor_set = 2, binding = 2)] cubemap: &Cubemap, + #[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, ) { diff --git a/tests/ui/image/sample_lod.rs b/tests/ui/image/sample_lod.rs index a011bb0647..503ba5191c 100644 --- a/tests/ui/image/sample_lod.rs +++ b/tests/ui/image/sample_lod.rs @@ -1,13 +1,13 @@ // Test `OpImageSampleExplicitLod` Lod // build-pass -use spirv_std::{arch, Cubemap, Image2d, Image2dArray, Sampler}; +use spirv_std::{arch, Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image2d, - #[spirv(descriptor_set = 1, binding = 1)] image2d_array: &Image2dArray, - #[spirv(descriptor_set = 2, binding = 2)] cubemap: &Cubemap, + #[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, ) { diff --git a/tests/ui/image/sample_with_project_coordinate/sample.rs b/tests/ui/image/sample_with_project_coordinate/sample.rs index 2371d69b88..218502300c 100644 --- a/tests/ui/image/sample_with_project_coordinate/sample.rs +++ b/tests/ui/image/sample_with_project_coordinate/sample.rs @@ -1,11 +1,11 @@ // Test `OpImageSampleProjImplicitLod` // build-pass -use spirv_std::{arch, Image2d, Sampler}; +use spirv_std::{Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image2d, + #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image!(2D, type=f32, sampled), #[spirv(descriptor_set = 1, binding = 1)] sampler: &Sampler, output: &mut glam::Vec4, ) { diff --git a/tests/ui/image/sample_with_project_coordinate/sample_gradient.rs b/tests/ui/image/sample_with_project_coordinate/sample_gradient.rs index 4c3fcbb003..6dc4d0e664 100644 --- a/tests/ui/image/sample_with_project_coordinate/sample_gradient.rs +++ b/tests/ui/image/sample_with_project_coordinate/sample_gradient.rs @@ -1,11 +1,11 @@ // Test `OpImageSampleProjExplicitLod` // build-pass -use spirv_std::{arch, Image2d, Sampler}; +use spirv_std::{arch, Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image2d, + #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image!(2D, type=f32, sampled), #[spirv(descriptor_set = 1, binding = 1)] sampler: &Sampler, output: &mut glam::Vec4, ) { diff --git a/tests/ui/image/sample_with_project_coordinate/sample_lod.rs b/tests/ui/image/sample_with_project_coordinate/sample_lod.rs index caaa16fbf8..ce11225365 100644 --- a/tests/ui/image/sample_with_project_coordinate/sample_lod.rs +++ b/tests/ui/image/sample_with_project_coordinate/sample_lod.rs @@ -1,11 +1,11 @@ // Test `OpImageSampleProjExplicitLod` // build-pass -use spirv_std::{arch, Image2d, Sampler}; +use spirv_std::{arch, Image, Sampler}; #[spirv(fragment)] pub fn main( - #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image2d, + #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image!(2D, type=f32, sampled), #[spirv(descriptor_set = 1, binding = 1)] sampler: &Sampler, output: &mut glam::Vec4, ) { diff --git a/tests/ui/image/write.rs b/tests/ui/image/write.rs index e8e917099c..4950f4e4ab 100644 --- a/tests/ui/image/write.rs +++ b/tests/ui/image/write.rs @@ -1,10 +1,13 @@ // Test `OpImageWrite` // build-pass -use spirv_std::{arch, StorageImage2d}; +use spirv_std::{arch, Image}; #[spirv(fragment)] -pub fn main(texels: glam::Vec2, #[spirv(descriptor_set = 0, binding = 0)] image: &StorageImage2d) { +pub fn main( + texels: glam::Vec2, + #[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, type=f32, sampled=false), +) { unsafe { asm!("OpCapability StorageImageWriteWithoutFormat"); image.write(glam::UVec2::new(0, 1), texels); diff --git a/tests/ui/spirv-attr/bad-infer-storage-class.rs b/tests/ui/spirv-attr/bad-infer-storage-class.rs index fa9cdfb991..22cba464b9 100644 --- a/tests/ui/spirv-attr/bad-infer-storage-class.rs +++ b/tests/ui/spirv-attr/bad-infer-storage-class.rs @@ -1,11 +1,15 @@ // Tests that storage class inference fails correctly // build-fail -use spirv_std::Image2d; +use spirv_std::Image; #[spirv(vertex)] -pub fn main(#[spirv(uniform)] error: &Image2d, #[spirv(uniform_constant)] warning: &Image2d) {} +pub fn main( + #[spirv(uniform)] error: &Image!(2D, type=f32), + #[spirv(uniform_constant)] warning: &Image!(2D, type=f32), +) { +} // https://github.com/EmbarkStudios/rust-gpu/issues/585 #[spirv(vertex)] -pub fn issue_585(invalid: Image2d) {} +pub fn issue_585(invalid: Image!(2D, type=f32)) {} diff --git a/tests/ui/spirv-attr/bad-infer-storage-class.stderr b/tests/ui/spirv-attr/bad-infer-storage-class.stderr index 547a498c69..c337afa341 100644 --- a/tests/ui/spirv-attr/bad-infer-storage-class.stderr +++ b/tests/ui/spirv-attr/bad-infer-storage-class.stderr @@ -1,29 +1,31 @@ error: storage class mismatch - --> $DIR/bad-infer-storage-class.rs:7:13 + --> $DIR/bad-infer-storage-class.rs:8:5 | -7 | pub fn main(#[spirv(uniform)] error: &Image2d, #[spirv(uniform_constant)] warning: &Image2d) {} - | ^^^^^^^^-------^^^^^^^^^^-------- - | | | - | | UniformConstant inferred from type - | Uniform specified in attribute +8 | #[spirv(uniform)] error: &Image!(2D, type=f32), + | ^^^^^^^^-------^^^^^^^^^^--------------------- + | | | + | | UniformConstant inferred from type + | Uniform specified in attribute | help: remove storage class attribute to use UniformConstant as storage class - --> $DIR/bad-infer-storage-class.rs:7:21 + --> $DIR/bad-infer-storage-class.rs:8:13 | -7 | pub fn main(#[spirv(uniform)] error: &Image2d, #[spirv(uniform_constant)] warning: &Image2d) {} - | ^^^^^^^ +8 | #[spirv(uniform)] error: &Image!(2D, type=f32), + | ^^^^^^^ warning: redundant storage class specifier, storage class is inferred from type - --> $DIR/bad-infer-storage-class.rs:7:56 + --> $DIR/bad-infer-storage-class.rs:9:13 | -7 | pub fn main(#[spirv(uniform)] error: &Image2d, #[spirv(uniform_constant)] warning: &Image2d) {} - | ^^^^^^^^^^^^^^^^ +9 | #[spirv(uniform_constant)] warning: &Image!(2D, type=f32), + | ^^^^^^^^^^^^^^^^ -error: entry parameter type must be by-reference: `&spirv_std::Image2d` - --> $DIR/bad-infer-storage-class.rs:11:27 +error: entry parameter type must be by-reference: `&spirv_std::image::Image::None>` + --> $DIR/bad-infer-storage-class.rs:15:27 | -11 | pub fn issue_585(invalid: Image2d) {} - | ^^^^^^^ +15 | pub fn issue_585(invalid: Image!(2D, type=f32)) {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors; 1 warning emitted