diff --git a/CHANGELOG.md b/CHANGELOG.md index 898b83e6b28..804ce9e57f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,13 +40,16 @@ Bottom level categories: ## Unreleased -For naga changelogs at or before v0.14.0. See [naga's changelog](naga/CHANGELOG.md). - ### Changes #### General - Log vulkan validation layer messages during instance creation and destruction: By @exrook in [#4586](https://github.com/gfx-rs/wgpu/pull/4586) +- `TextureFormat::block_size` is deprecated, use `TextureFormat::block_copy_size` instead: By @wumpf in [#4647](https://github.com/gfx-rs/wgpu/pull/4647) + +#### Naga + +- Introduce a new `Scalar` struct type for use in Naga's IR, and update all frontend, middle, and backend code appropriately. By @jimblandy in [#4673](https://github.com/gfx-rs/wgpu/pull/4673). ### Bug Fixes @@ -54,12 +57,34 @@ For naga changelogs at or before v0.14.0. See [naga's changelog](naga/CHANGELOG. - Create a hidden window per `wgpu::Instance` instead of sharing a global one. -#### Naga MSL-OUT +#### Naga + +- Improve algorithm used by module compaction. By @jimblandy in [#4662](https://github.com/gfx-rs/wgpu/pull/4662). -- Fix issue where local variables were sometimes using variable names from previous functions. +- When reading GLSL, fix the argument types of the double-precision floating-point overloads of the `dot`, `reflect`, `distance`, and `ldexp` builtin functions. Correct the WGSL generated for constructing 64-bit floating-point matrices. Add tests for all the above. By @jimblandy in [#4684](https://github.com/gfx-rs/wgpu/pull/4684). + +## v0.18.1 (2023-11-15) + +(naga version 0.14.1) + +### Bug Fixes + +#### General +- Fix panic in `Surface::configure` in debug builds. By @cwfitzgerald in [#4635](https://github.com/gfx-rs/wgpu/pull/4635) +- Fix crash when all the following are true: By @teoxoy in #[#4642](https://github.com/gfx-rs/wgpu/pull/4642) + - Passing a naga module directly to `Device::create_shader_module`. + - `InstanceFlags::DEBUG` is enabled. + +#### DX12 +- Always use HLSL 2018 when using DXC to compile HLSL shaders. By @daxpedda in [#4629](https://github.com/gfx-rs/wgpu/pull/4629) + +#### Metal +- In Metal Shading Language output, fix issue where local variables were sometimes using variable names from previous functions. By @DJMcNab in [#4594](https://github.com/gfx-rs/wgpu/pull/4594) ## v0.18.0 (2023-10-25) +For naga changelogs at or before v0.14.0. See [naga's changelog](naga/CHANGELOG.md). + ### Desktop OpenGL 3.3+ Support on Windows We now support OpenGL on Windows! This brings support for a vast majority of the hardware that used to be covered by our DX11 backend. As of this writing we support OpenGL 3.3+, though there are efforts to reduce that further. @@ -73,7 +98,7 @@ By @Zoxc in [#4248](https://github.com/gfx-rs/wgpu/pull/4248) Timestamp queries are now supported on both Metal and Desktop OpenGL. On Apple chips on Metal, they only support timestamp queries in command buffers or in the renderpass descriptor, they do not support them inside a pass. -Metal: By @Wumpf in [#4008](https://github.com/gfx-rs/wgpu/pull/4008) +Metal: By @Wumpf in [#4008](https://github.com/gfx-rs/wgpu/pull/4008) OpenGL: By @Zoxc in [#4267](https://github.com/gfx-rs/wgpu/pull/4267) ### Render/Compute Pass Query Writes @@ -196,7 +221,7 @@ let instance = wgpu::Instance::new(InstanceDescriptor { }); ``` -`gles_minor_version`: By @PJB3005 in [#3998](https://github.com/gfx-rs/wgpu/pull/3998) +`gles_minor_version`: By @PJB3005 in [#3998](https://github.com/gfx-rs/wgpu/pull/3998) `flags`: By @nical in [#4230](https://github.com/gfx-rs/wgpu/pull/4230) ### Many New Examples! @@ -242,11 +267,13 @@ By @teoxoy in [#4185](https://github.com/gfx-rs/wgpu/pull/4185) - Add trace-level logging for most entry points in wgpu-core By @nical in [4183](https://github.com/gfx-rs/wgpu/pull/4183) - Add `Rgb10a2Uint` format. By @teoxoy in [4199](https://github.com/gfx-rs/wgpu/pull/4199) - Validate that resources are used on the right device. By @nical in [4207](https://github.com/gfx-rs/wgpu/pull/4207) -- Expose instance flags. +- Expose instance flags. - Add support for the bgra8unorm-storage feature. By @jinleili and @nical in [#4228](https://github.com/gfx-rs/wgpu/pull/4228) - Calls to lost devices now return `DeviceError::Lost` instead of `DeviceError::Invalid`. By @bradwerth in [#4238]([https://github.com/gfx-rs/wgpu/pull/4238]) - Let the `"strict_asserts"` feature enable check that wgpu-core's lock-ordering tokens are unique per thread. By @jimblandy in [#4258]([https://github.com/gfx-rs/wgpu/pull/4258]) - Allow filtering labels out before they are passed to GPU drivers by @nical in [https://github.com/gfx-rs/wgpu/pull/4246](4246) +- `DeviceLostClosure` callback mechanism provided so user agents can resolve `GPUDevice.lost` Promises at the appropriate time by @bradwerth in [#4645](https://github.com/gfx-rs/wgpu/pull/4645) + #### Vulkan @@ -271,6 +298,8 @@ By @teoxoy in [#4185](https://github.com/gfx-rs/wgpu/pull/4185) - Fix `clear` texture views being leaked when `wgpu::SurfaceTexture` is dropped before it is presented. By @rajveermalviya in [#4057](https://github.com/gfx-rs/wgpu/pull/4057). - Add `Feature::SHADER_UNUSED_VERTEX_OUTPUT` to allow unused vertex shader outputs. By @Aaron1011 in [#4116](https://github.com/gfx-rs/wgpu/pull/4116). - Fix a panic in `surface_configure`. By @nical in [#4220](https://github.com/gfx-rs/wgpu/pull/4220) and [#4227](https://github.com/gfx-rs/wgpu/pull/4227) +- Pipelines register their implicit layouts in error cases. By @bradwerth in [#4624](https://github.com/gfx-rs/wgpu/pull/4624) +- Better handle explicit destruction of textures and buffers. By @nical in [#4657](https://github.com/gfx-rs/wgpu/pull/4657) #### Vulkan diff --git a/Cargo.lock b/Cargo.lock index 3e7cc227ad4..f215b26d796 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1221,9 +1221,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", @@ -1530,9 +1530,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "js-sys", @@ -1567,8 +1567,7 @@ checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" [[package]] name = "glow" version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886c2a30b160c4c6fec8f987430c26b526b7988ca71f664e6a699ddf6f9601e4" +source = "git+https://github.com/grovesNL/glow.git?rev=29ff917a2b2ff7ce0a81b2cc5681de6d4735b36e#29ff917a2b2ff7ce0a81b2cc5681de6d4735b36e" dependencies = [ "js-sys", "slotmap", @@ -3084,9 +3083,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.190" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] @@ -3102,9 +3101,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.190" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", @@ -3205,9 +3204,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "smithay-client-toolkit" @@ -3380,9 +3379,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] @@ -3493,9 +3492,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -3512,9 +3511,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 07a2793307c..ddd0c319060 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -171,8 +171,8 @@ deno_url = "0.119.0" deno_web = "0.150.0" deno_webidl = "0.119.0" deno_webgpu = { version = "0.85.0", path = "./deno_webgpu" } -tokio = "1.33.0" -termcolor = "1.3.0" +tokio = "1.34.0" +termcolor = "1.4.0" [patch."https://github.com/gfx-rs/naga"] diff --git a/README.md b/README.md index 4a560af49dc..e8df5f5ec2f 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ We have a [wiki](https://github.com/gfx-rs/wgpu/wiki) that serves as a knowledge :white_check_mark: = First Class Support :ok: = Downlevel/Best Effort Support -:triangular_ruler: = Requires the [ANGLE](#angle) translation layer (GL ES 3.0 only) +:triangular_ruler: = Requires the [ANGLE](#angle) translation layer (GL ES 3.0 only) :volcano: = Requires the [MoltenVK](https://vulkan.lunarg.com/sdk/home#mac) translation layer :hammer_and_wrench: = Unsupported, though open to contributions diff --git a/examples/repeated-compute/Cargo.toml b/examples/repeated-compute/Cargo.toml index 5e26d020eef..2a50037157c 100644 --- a/examples/repeated-compute/Cargo.toml +++ b/examples/repeated-compute/Cargo.toml @@ -14,7 +14,7 @@ path = "src/main.rs" bytemuck.workspace = true env_logger.workspace = true futures-intrusive.workspace = true -getrandom = { version = "0.2.10", features = ["js"] } +getrandom = { version = "0.2.11", features = ["js"] } log.workspace = true pollster.workspace = true wgpu.workspace = true diff --git a/naga/Cargo.toml b/naga/Cargo.toml index eb5fb45f41c..9729adf709d 100644 --- a/naga/Cargo.toml +++ b/naga/Cargo.toml @@ -41,7 +41,7 @@ harness = false arbitrary = { version = "1.3", features = ["derive"], optional = true } bitflags = "2.2" bit-set = "0.5" -termcolor = { version = "1.0.4", optional = true } +termcolor = { version = "1.4.0", optional = true } # remove termcolor dep when updating to the next version of codespan-reporting # termcolor minimum version was wrong and was fixed in # https://github.com/brendanzab/codespan/commit/e99c867339a877731437e7ee6a903a3d03b5439e @@ -52,7 +52,7 @@ log = "0.4" num-traits = "0.2" spirv = { version = "0.2", optional = true } thiserror = "1.0.21" -serde = { version = "1.0.103", features = ["derive"], optional = true } +serde = { version = "1.0.192", features = ["derive"], optional = true } petgraph = { version = "0.6", optional = true } pp-rs = { version = "0.2.1", optional = true } hexf-parse = { version = "0.2.1", optional = true } diff --git a/naga/src/back/glsl/features.rs b/naga/src/back/glsl/features.rs index f534125496b..ec047d3d5b2 100644 --- a/naga/src/back/glsl/features.rs +++ b/naga/src/back/glsl/features.rs @@ -1,7 +1,7 @@ use super::{BackendResult, Error, Version, Writer}; use crate::{ - AddressSpace, Binding, Bytes, Expression, Handle, ImageClass, ImageDimension, Interpolation, - Sampling, ScalarKind, ShaderStage, StorageFormat, Type, TypeInner, + AddressSpace, Binding, Expression, Handle, ImageClass, ImageDimension, Interpolation, Sampling, + Scalar, ScalarKind, ShaderStage, StorageFormat, Type, TypeInner, }; use std::fmt::Write; @@ -281,10 +281,10 @@ impl<'a, W> Writer<'a, W> { for (ty_handle, ty) in self.module.types.iter() { match ty.inner { - TypeInner::Scalar { kind, width } => self.scalar_required_features(kind, width), - TypeInner::Vector { kind, width, .. } => self.scalar_required_features(kind, width), + TypeInner::Scalar(scalar) => self.scalar_required_features(scalar), + TypeInner::Vector { scalar, .. } => self.scalar_required_features(scalar), TypeInner::Matrix { width, .. } => { - self.scalar_required_features(ScalarKind::Float, width) + self.scalar_required_features(Scalar::float(width)) } TypeInner::Array { base, size, .. } => { if let TypeInner::Array { .. } = self.module.types[base].inner { @@ -485,8 +485,8 @@ impl<'a, W> Writer<'a, W> { } /// Helper method that checks the [`Features`] needed by a scalar - fn scalar_required_features(&mut self, kind: ScalarKind, width: Bytes) { - if kind == ScalarKind::Float && width == 8 { + fn scalar_required_features(&mut self, scalar: Scalar) { + if scalar.kind == ScalarKind::Float && scalar.width == 8 { self.features.request(Features::DOUBLE_TYPE); } } diff --git a/naga/src/back/glsl/mod.rs b/naga/src/back/glsl/mod.rs index e96b86541da..c1dfcb780d3 100644 --- a/naga/src/back/glsl/mod.rs +++ b/naga/src/back/glsl/mod.rs @@ -311,6 +311,8 @@ pub struct ReflectionInfo { pub uniforms: crate::FastHashMap, String>, /// Mapping between names and attribute locations. pub varying: crate::FastHashMap, + /// List of push constant items in the shader. + pub push_constant_items: Vec, } /// Mapping between a texture and its sampler, if it exists. @@ -330,6 +332,50 @@ pub struct TextureMapping { pub sampler: Option>, } +/// All information to bind a single uniform value to the shader. +/// +/// Push constants are emulated using traditional uniforms in OpenGL. +/// +/// These are composed of a set of primatives (scalar, vector, matrix) that +/// are given names. Because they are not backed by the concept of a buffer, +/// we must do the work of calculating the offset of each primative in the +/// push constant block. +#[derive(Debug, Clone)] +pub struct PushConstantItem { + /// GL uniform name for the item. This name is the same as if you were + /// to access it directly from a GLSL shader. + /// + /// The with the following example, the following names will be generated, + /// one name per GLSL uniform. + /// + /// ```glsl + /// struct InnerStruct { + /// value: f32, + /// } + /// + /// struct PushConstant { + /// InnerStruct inner; + /// vec4 array[2]; + /// } + /// + /// uniform PushConstants _push_constant_binding_cs; + /// ``` + /// + /// ```text + /// - _push_constant_binding_cs.inner.value + /// - _push_constant_binding_cs.array[0] + /// - _push_constant_binding_cs.array[1] + /// ``` + /// + pub access_path: String, + /// Type of the uniform. This will only ever be a scalar, vector, or matrix. + pub ty: Handle, + /// The offset in the push constant memory block this uniform maps to. + /// + /// The size of the uniform can be derived from the type. + pub offset: u32, +} + /// Helper structure that generates a number #[derive(Default)] struct IdGenerator(u32); @@ -427,8 +473,8 @@ pub enum Error { #[error("A call was made to an unsupported external: {0}")] UnsupportedExternal(String), /// A scalar with an unsupported width was requested. - #[error("A scalar with an unsupported width was requested: {0:?} {1:?}")] - UnsupportedScalar(crate::ScalarKind, crate::Bytes), + #[error("A scalar with an unsupported width was requested: {0:?}")] + UnsupportedScalar(crate::Scalar), /// A image was used with multiple samplers, which isn't supported. #[error("A image was used with multiple samplers")] ImageMultipleSamplers, @@ -919,27 +965,20 @@ impl<'a, W: Write> Writer<'a, W> { fn write_value_type(&mut self, inner: &TypeInner) -> BackendResult { match *inner { // Scalars are simple we just get the full name from `glsl_scalar` - TypeInner::Scalar { kind, width } - | TypeInner::Atomic { kind, width } + TypeInner::Scalar(scalar) + | TypeInner::Atomic(scalar) | TypeInner::ValuePointer { size: None, - kind, - width, + scalar, space: _, - } => write!(self.out, "{}", glsl_scalar(kind, width)?.full)?, + } => write!(self.out, "{}", glsl_scalar(scalar)?.full)?, // Vectors are just `gvecN` where `g` is the scalar prefix and `N` is the vector size - TypeInner::Vector { size, kind, width } + TypeInner::Vector { size, scalar } | TypeInner::ValuePointer { size: Some(size), - kind, - width, + scalar, space: _, - } => write!( - self.out, - "{}vec{}", - glsl_scalar(kind, width)?.prefix, - size as u8 - )?, + } => write!(self.out, "{}vec{}", glsl_scalar(scalar)?.prefix, size as u8)?, // Matrices are written with `gmatMxN` where `g` is the scalar prefix (only floats and // doubles are allowed), `M` is the columns count and `N` is the rows count // @@ -952,7 +991,7 @@ impl<'a, W: Write> Writer<'a, W> { } => write!( self.out, "{}mat{}x{}", - glsl_scalar(crate::ScalarKind::Float, width)?.prefix, + glsl_scalar(crate::Scalar::float(width))?.prefix, columns as u8, rows as u8 )?, @@ -1039,7 +1078,7 @@ impl<'a, W: Write> Writer<'a, W> { self.out, "{}{}{}{}{}{}{}", precision, - glsl_scalar(kind, 4)?.prefix, + glsl_scalar(crate::Scalar { kind, width: 4 })?.prefix, base, glsl_dimension(dim), ms, @@ -1234,7 +1273,7 @@ impl<'a, W: Write> Writer<'a, W> { crate::MathFunction::Dot => { // if the expression is a Dot product with integer arguments, // then the args needs baking as well - if let TypeInner::Scalar { kind, .. } = *inner { + if let TypeInner::Scalar(crate::Scalar { kind, .. }) = *inner { match kind { crate::ScalarKind::Sint | crate::ScalarKind::Uint => { self.need_bake_expressions.insert(arg); @@ -1266,8 +1305,8 @@ impl<'a, W: Write> Writer<'a, W> { handle: Handle, global: &crate::GlobalVariable, ) -> String { - match global.binding { - Some(ref br) => { + match (&global.binding, global.space) { + (&Some(ref br), _) => { format!( "_group_{}_binding_{}_{}", br.group, @@ -1275,7 +1314,10 @@ impl<'a, W: Write> Writer<'a, W> { self.entry_point.stage.to_str() ) } - None => self.names[&NameKey::GlobalVariable(handle)].clone(), + (&None, crate::AddressSpace::PushConstant) => { + format!("_push_constant_binding_{}", self.entry_point.stage.to_str()) + } + (&None, _) => self.names[&NameKey::GlobalVariable(handle)].clone(), } } @@ -1285,15 +1327,20 @@ impl<'a, W: Write> Writer<'a, W> { handle: Handle, global: &crate::GlobalVariable, ) -> BackendResult { - match global.binding { - Some(ref br) => write!( + match (&global.binding, global.space) { + (&Some(ref br), _) => write!( self.out, "_group_{}_binding_{}_{}", br.group, br.binding, self.entry_point.stage.to_str() )?, - None => write!( + (&None, crate::AddressSpace::PushConstant) => write!( + self.out, + "_push_constant_binding_{}", + self.entry_point.stage.to_str() + )?, + (&None, _) => write!( self.out, "{}", &self.names[&NameKey::GlobalVariable(handle)] @@ -2765,10 +2812,10 @@ impl<'a, W: Write> Writer<'a, W> { if let Some(expr) = level { let cast_to_int = matches!( *ctx.resolve_type(expr, &self.module.types), - crate::TypeInner::Scalar { + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Uint, .. - } + }) ); write!(self.out, ", ")?; @@ -2869,19 +2916,19 @@ impl<'a, W: Write> Writer<'a, W> { let right_inner = ctx.resolve_type(right, &self.module.types); let function = match (left_inner, right_inner) { - (&Ti::Vector { kind, .. }, &Ti::Vector { .. }) => match op { + (&Ti::Vector { scalar, .. }, &Ti::Vector { .. }) => match op { Bo::Less | Bo::LessEqual | Bo::Greater | Bo::GreaterEqual | Bo::Equal | Bo::NotEqual => BinaryOperation::VectorCompare, - Bo::Modulo if kind == Sk::Float => BinaryOperation::Modulo, - Bo::And if kind == Sk::Bool => { + Bo::Modulo if scalar.kind == Sk::Float => BinaryOperation::Modulo, + Bo::And if scalar.kind == Sk::Bool => { op = crate::BinaryOperator::LogicalAnd; BinaryOperation::VectorComponentWise } - Bo::InclusiveOr if kind == Sk::Bool => { + Bo::InclusiveOr if scalar.kind == Sk::Bool => { op = crate::BinaryOperator::LogicalOr; BinaryOperation::VectorComponentWise } @@ -3134,7 +3181,11 @@ impl<'a, W: Write> Writer<'a, W> { // geometry Mf::Dot => match *ctx.resolve_type(arg, &self.module.types) { crate::TypeInner::Vector { - kind: crate::ScalarKind::Float, + scalar: + crate::Scalar { + kind: crate::ScalarKind::Float, + .. + }, .. } => "dot", crate::TypeInner::Vector { size, .. } => { @@ -3189,9 +3240,9 @@ impl<'a, W: Write> Writer<'a, W> { // bits Mf::CountTrailingZeros => { match *ctx.resolve_type(arg, &self.module.types) { - crate::TypeInner::Vector { size, kind, .. } => { + crate::TypeInner::Vector { size, scalar, .. } => { let s = back::vector_size_str(size); - if let crate::ScalarKind::Uint = kind { + if let crate::ScalarKind::Uint = scalar.kind { write!(self.out, "min(uvec{s}(findLSB(")?; self.write_expr(arg, ctx)?; write!(self.out, ")), uvec{s}(32u))")?; @@ -3201,8 +3252,8 @@ impl<'a, W: Write> Writer<'a, W> { write!(self.out, ")), uvec{s}(32u)))")?; } } - crate::TypeInner::Scalar { kind, .. } => { - if let crate::ScalarKind::Uint = kind { + crate::TypeInner::Scalar(scalar) => { + if let crate::ScalarKind::Uint = scalar.kind { write!(self.out, "min(uint(findLSB(")?; self.write_expr(arg, ctx)?; write!(self.out, ")), 32u)")?; @@ -3219,10 +3270,10 @@ impl<'a, W: Write> Writer<'a, W> { Mf::CountLeadingZeros => { if self.options.version.supports_integer_functions() { match *ctx.resolve_type(arg, &self.module.types) { - crate::TypeInner::Vector { size, kind, .. } => { + crate::TypeInner::Vector { size, scalar } => { let s = back::vector_size_str(size); - if let crate::ScalarKind::Uint = kind { + if let crate::ScalarKind::Uint = scalar.kind { write!(self.out, "uvec{s}(ivec{s}(31) - findMSB(")?; self.write_expr(arg, ctx)?; write!(self.out, "))")?; @@ -3234,8 +3285,8 @@ impl<'a, W: Write> Writer<'a, W> { write!(self.out, ", ivec{s}(0)))")?; } } - crate::TypeInner::Scalar { kind, .. } => { - if let crate::ScalarKind::Uint = kind { + crate::TypeInner::Scalar(scalar) => { + if let crate::ScalarKind::Uint = scalar.kind { write!(self.out, "uint(31 - findMSB(")?; } else { write!(self.out, "(")?; @@ -3250,10 +3301,10 @@ impl<'a, W: Write> Writer<'a, W> { }; } else { match *ctx.resolve_type(arg, &self.module.types) { - crate::TypeInner::Vector { size, kind, .. } => { + crate::TypeInner::Vector { size, scalar } => { let s = back::vector_size_str(size); - if let crate::ScalarKind::Uint = kind { + if let crate::ScalarKind::Uint = scalar.kind { write!(self.out, "uvec{s}(")?; write!(self.out, "vec{s}(31.0) - floor(log2(vec{s}(")?; self.write_expr(arg, ctx)?; @@ -3268,8 +3319,8 @@ impl<'a, W: Write> Writer<'a, W> { write!(self.out, ", ivec{s}(0u))))")?; } } - crate::TypeInner::Scalar { kind, .. } => { - if let crate::ScalarKind::Uint = kind { + crate::TypeInner::Scalar(scalar) => { + if let crate::ScalarKind::Uint = scalar.kind { write!(self.out, "uint(31.0 - floor(log2(float(")?; self.write_expr(arg, ctx)?; write!(self.out, ") + 0.5)))")?; @@ -3323,14 +3374,17 @@ impl<'a, W: Write> Writer<'a, W> { // Check if the argument is an unsigned integer and return the vector size // in case it's a vector let maybe_uint_size = match *ctx.resolve_type(arg, &self.module.types) { - crate::TypeInner::Scalar { + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Uint, .. - } => Some(None), + }) => Some(None), crate::TypeInner::Vector { - kind: crate::ScalarKind::Uint, + scalar: + crate::Scalar { + kind: crate::ScalarKind::Uint, + .. + }, size, - .. } => Some(Some(size)), _ => None, }; @@ -3413,7 +3467,10 @@ impl<'a, W: Write> Writer<'a, W> { match convert { Some(width) => { // this is similar to `write_type`, but with the target kind - let scalar = glsl_scalar(target_kind, width)?; + let scalar = glsl_scalar(crate::Scalar { + kind: target_kind, + width, + })?; match *inner { TypeInner::Matrix { columns, rows, .. } => write!( self.out, @@ -3434,10 +3491,12 @@ impl<'a, W: Write> Writer<'a, W> { use crate::ScalarKind as Sk; let target_vector_type = match *inner { - TypeInner::Vector { size, width, .. } => Some(TypeInner::Vector { + TypeInner::Vector { size, scalar } => Some(TypeInner::Vector { size, - width, - kind: target_kind, + scalar: crate::Scalar { + kind: target_kind, + width: scalar.width, + }, }), _ => None, }; @@ -3576,14 +3635,17 @@ impl<'a, W: Write> Writer<'a, W> { // Otherwise write just the expression (and the 1D hack if needed) None => { let uvec_size = match *ctx.resolve_type(coordinate, &self.module.types) { - TypeInner::Scalar { + TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Uint, .. - } => Some(None), + }) => Some(None), TypeInner::Vector { size, - kind: crate::ScalarKind::Uint, - .. + scalar: + crate::Scalar { + kind: crate::ScalarKind::Uint, + .. + }, } => Some(Some(size as u32)), _ => None, }; @@ -3916,7 +3978,11 @@ impl<'a, W: Write> Writer<'a, W> { // End the first branch write!(self.out, " : ")?; // Write the 0 value - write!(self.out, "{}vec4(", glsl_scalar(kind, 4)?.prefix,)?; + write!( + self.out, + "{}vec4(", + glsl_scalar(crate::Scalar { kind, width: 4 })?.prefix, + )?; self.write_zero_init_scalar(kind)?; // Close the zero value constructor write!(self.out, ")")?; @@ -3969,13 +4035,13 @@ impl<'a, W: Write> Writer<'a, W> { fn write_zero_init_value(&mut self, ty: Handle) -> BackendResult { let inner = &self.module.types[ty].inner; match *inner { - TypeInner::Scalar { kind, .. } | TypeInner::Atomic { kind, .. } => { - self.write_zero_init_scalar(kind)?; + TypeInner::Scalar(scalar) | TypeInner::Atomic(scalar) => { + self.write_zero_init_scalar(scalar.kind)?; } - TypeInner::Vector { kind, .. } => { + TypeInner::Vector { scalar, .. } => { self.write_value_type(inner)?; write!(self.out, "(")?; - self.write_zero_init_scalar(kind)?; + self.write_zero_init_scalar(scalar.kind)?; write!(self.out, ")")?; } TypeInner::Matrix { .. } => { @@ -4086,6 +4152,7 @@ impl<'a, W: Write> Writer<'a, W> { } } + let mut push_constant_info = None; for (handle, var) in self.module.global_variables.iter() { if info[handle].is_empty() { continue; @@ -4110,17 +4177,105 @@ impl<'a, W: Write> Writer<'a, W> { let name = self.reflection_names_globals[&handle].clone(); uniforms.insert(handle, name); } + crate::AddressSpace::PushConstant => { + let name = self.reflection_names_globals[&handle].clone(); + push_constant_info = Some((name, var.ty)); + } _ => (), }, } } + let mut push_constant_segments = Vec::new(); + let mut push_constant_items = vec![]; + + if let Some((name, ty)) = push_constant_info { + // We don't have a layouter available to us, so we need to create one. + // + // This is potentially a bit wasteful, but the set of types in the program + // shouldn't be too large. + let mut layouter = crate::proc::Layouter::default(); + layouter.update(self.module.to_ctx()).unwrap(); + + // We start with the name of the binding itself. + push_constant_segments.push(name); + + // We then recursively collect all the uniform fields of the push constant. + self.collect_push_constant_items( + ty, + &mut push_constant_segments, + &layouter, + &mut 0, + &mut push_constant_items, + ); + } + Ok(ReflectionInfo { texture_mapping, uniforms, varying: mem::take(&mut self.varying), + push_constant_items, }) } + + fn collect_push_constant_items( + &mut self, + ty: Handle, + segments: &mut Vec, + layouter: &crate::proc::Layouter, + offset: &mut u32, + items: &mut Vec, + ) { + // At this point in the recursion, `segments` contains the path + // needed to access `ty` from the root. + + let layout = &layouter[ty]; + *offset = layout.alignment.round_up(*offset); + match self.module.types[ty].inner { + // All these types map directly to GL uniforms. + TypeInner::Scalar { .. } | TypeInner::Vector { .. } | TypeInner::Matrix { .. } => { + // Build the full name, by combining all current segments. + let name: String = segments.iter().map(String::as_str).collect(); + items.push(PushConstantItem { + access_path: name, + offset: *offset, + ty, + }); + *offset += layout.size; + } + // Arrays are recursed into. + TypeInner::Array { base, size, .. } => { + let crate::ArraySize::Constant(count) = size else { + unreachable!("Cannot have dynamic arrays in push constants"); + }; + + for i in 0..count.get() { + // Add the array accessor and recurse. + segments.push(format!("[{}]", i)); + self.collect_push_constant_items(base, segments, layouter, offset, items); + segments.pop(); + } + + // Ensure the stride is kept by rounding up to the alignment. + *offset = layout.alignment.round_up(*offset) + } + TypeInner::Struct { ref members, .. } => { + for (index, member) in members.iter().enumerate() { + // Add struct accessor and recurse. + segments.push(format!( + ".{}", + self.names[&NameKey::StructMember(ty, index as u32)] + )); + self.collect_push_constant_items(member.ty, segments, layouter, offset, items); + segments.pop(); + } + + // Ensure ending padding is kept by rounding up to the alignment. + *offset = layout.alignment.round_up(*offset) + } + _ => unreachable!(), + } + } } /// Structure returned by [`glsl_scalar`] @@ -4139,13 +4294,10 @@ struct ScalarString<'a> { /// /// # Errors /// If a [`Float`](crate::ScalarKind::Float) with an width that isn't 4 or 8 -const fn glsl_scalar( - kind: crate::ScalarKind, - width: crate::Bytes, -) -> Result, Error> { +const fn glsl_scalar(scalar: crate::Scalar) -> Result, Error> { use crate::ScalarKind as Sk; - Ok(match kind { + Ok(match scalar.kind { Sk::Sint => ScalarString { prefix: "i", full: "int", @@ -4154,7 +4306,7 @@ const fn glsl_scalar( prefix: "u", full: "uint", }, - Sk::Float => match width { + Sk::Float => match scalar.width { 4 => ScalarString { prefix: "", full: "float", @@ -4163,7 +4315,7 @@ const fn glsl_scalar( prefix: "d", full: "double", }, - _ => return Err(Error::UnsupportedScalar(kind, width)), + _ => return Err(Error::UnsupportedScalar(scalar)), }, Sk::Bool => ScalarString { prefix: "b", diff --git a/naga/src/back/hlsl/conv.rs b/naga/src/back/hlsl/conv.rs index 19bde6926a8..ca84ab5a057 100644 --- a/naga/src/back/hlsl/conv.rs +++ b/naga/src/back/hlsl/conv.rs @@ -13,21 +13,23 @@ impl crate::ScalarKind { Self::Bool => unreachable!(), } } +} +impl crate::Scalar { /// Helper function that returns scalar related strings /// /// - pub(super) const fn to_hlsl_str(self, width: crate::Bytes) -> Result<&'static str, Error> { - match self { - Self::Sint => Ok("int"), - Self::Uint => Ok("uint"), - Self::Float => match width { + pub(super) const fn to_hlsl_str(self) -> Result<&'static str, Error> { + match self.kind { + crate::ScalarKind::Sint => Ok("int"), + crate::ScalarKind::Uint => Ok("uint"), + crate::ScalarKind::Float => match self.width { 2 => Ok("half"), 4 => Ok("float"), 8 => Ok("double"), - _ => Err(Error::UnsupportedScalar(self, width)), + _ => Err(Error::UnsupportedScalar(self)), }, - Self::Bool => Ok("bool"), + crate::ScalarKind::Bool => Ok("bool"), } } } @@ -71,10 +73,10 @@ impl crate::TypeInner { names: &'a crate::FastHashMap, ) -> Result, Error> { Ok(match gctx.types[base].inner { - crate::TypeInner::Scalar { kind, width } => Cow::Borrowed(kind.to_hlsl_str(width)?), - crate::TypeInner::Vector { size, kind, width } => Cow::Owned(format!( + crate::TypeInner::Scalar(scalar) => Cow::Borrowed(scalar.to_hlsl_str()?), + crate::TypeInner::Vector { size, scalar } => Cow::Owned(format!( "{}{}", - kind.to_hlsl_str(width)?, + scalar.to_hlsl_str()?, crate::back::vector_size_str(size) )), crate::TypeInner::Matrix { @@ -83,7 +85,7 @@ impl crate::TypeInner { width, } => Cow::Owned(format!( "{}{}x{}", - crate::ScalarKind::Float.to_hlsl_str(width)?, + crate::Scalar::float(width).to_hlsl_str()?, crate::back::vector_size_str(columns), crate::back::vector_size_str(rows), )), diff --git a/naga/src/back/hlsl/help.rs b/naga/src/back/hlsl/help.rs index fcb9949fe15..ac0ce6740d6 100644 --- a/naga/src/back/hlsl/help.rs +++ b/naga/src/back/hlsl/help.rs @@ -133,7 +133,7 @@ impl<'a, W: Write> super::Writer<'a, W> { } crate::ImageClass::Sampled { kind, multi } => { let multi_str = if multi { "MS" } else { "" }; - let scalar_kind_str = kind.to_hlsl_str(4)?; + let scalar_kind_str = crate::Scalar { kind, width: 4 }.to_hlsl_str()?; write!(self.out, "{multi_str}<{scalar_kind_str}4>")? } crate::ImageClass::Storage { format, .. } => { @@ -658,8 +658,7 @@ impl<'a, W: Write> super::Writer<'a, W> { let vec_ty = match module.types[member.ty].inner { crate::TypeInner::Matrix { rows, width, .. } => crate::TypeInner::Vector { size: rows, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }, _ => unreachable!(), }; @@ -737,10 +736,9 @@ impl<'a, W: Write> super::Writer<'a, W> { _ => unreachable!(), }; let scalar_ty = match module.types[member.ty].inner { - crate::TypeInner::Matrix { width, .. } => crate::TypeInner::Scalar { - kind: crate::ScalarKind::Float, - width, - }, + crate::TypeInner::Matrix { width, .. } => { + crate::TypeInner::Scalar(crate::Scalar::float(width)) + } _ => unreachable!(), }; self.write_value_type(module, &scalar_ty)?; diff --git a/naga/src/back/hlsl/mod.rs b/naga/src/back/hlsl/mod.rs index b3b0ee6222d..6e9883e4e43 100644 --- a/naga/src/back/hlsl/mod.rs +++ b/naga/src/back/hlsl/mod.rs @@ -254,8 +254,8 @@ pub struct ReflectionInfo { pub enum Error { #[error(transparent)] IoError(#[from] FmtError), - #[error("A scalar with an unsupported width was requested: {0:?} {1:?}")] - UnsupportedScalar(crate::ScalarKind, crate::Bytes), + #[error("A scalar with an unsupported width was requested: {0:?}")] + UnsupportedScalar(crate::Scalar), #[error("{0}")] Unimplemented(String), // TODO: Error used only during development #[error("{0}")] diff --git a/naga/src/back/hlsl/storage.rs b/naga/src/back/hlsl/storage.rs index 1e02e9e5026..24389074e0b 100644 --- a/naga/src/back/hlsl/storage.rs +++ b/naga/src/back/hlsl/storage.rs @@ -157,25 +157,21 @@ impl super::Writer<'_, W> { func_ctx: &FunctionCtx, ) -> BackendResult { match *result_ty.inner_with(&module.types) { - crate::TypeInner::Scalar { kind, width: _ } => { + crate::TypeInner::Scalar(scalar) => { // working around the borrow checker in `self.write_expr` let chain = mem::take(&mut self.temp_access_chain); let var_name = &self.names[&NameKey::GlobalVariable(var_handle)]; - let cast = kind.to_hlsl_cast(); + let cast = scalar.kind.to_hlsl_cast(); write!(self.out, "{cast}({var_name}.Load(")?; self.write_storage_address(module, &chain, func_ctx)?; write!(self.out, "))")?; self.temp_access_chain = chain; } - crate::TypeInner::Vector { - size, - kind, - width: _, - } => { + crate::TypeInner::Vector { size, scalar } => { // working around the borrow checker in `self.write_expr` let chain = mem::take(&mut self.temp_access_chain); let var_name = &self.names[&NameKey::GlobalVariable(var_handle)]; - let cast = kind.to_hlsl_cast(); + let cast = scalar.kind.to_hlsl_cast(); write!(self.out, "{}({}.Load{}(", cast, var_name, size as u8)?; self.write_storage_address(module, &chain, func_ctx)?; write!(self.out, "))")?; @@ -189,7 +185,7 @@ impl super::Writer<'_, W> { write!( self.out, "{}{}x{}(", - crate::ScalarKind::Float.to_hlsl_str(width)?, + crate::Scalar::float(width).to_hlsl_str()?, columns as u8, rows as u8, )?; @@ -199,8 +195,7 @@ impl super::Writer<'_, W> { let iter = (0..columns as u32).map(|i| { let ty_inner = crate::TypeInner::Vector { size: rows, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }; (TypeResolution::Value(ty_inner), i * row_stride) }); @@ -296,7 +291,7 @@ impl super::Writer<'_, W> { } }; match *ty_resolution.inner_with(&module.types) { - crate::TypeInner::Scalar { .. } => { + crate::TypeInner::Scalar(_) => { // working around the borrow checker in `self.write_expr` let chain = mem::take(&mut self.temp_access_chain); let var_name = &self.names[&NameKey::GlobalVariable(var_handle)]; @@ -330,7 +325,7 @@ impl super::Writer<'_, W> { self.out, "{}{}{}x{} {}{} = ", level.next(), - crate::ScalarKind::Float.to_hlsl_str(width)?, + crate::Scalar::float(width).to_hlsl_str()?, columns as u8, rows as u8, STORE_TEMP_NAME, @@ -348,8 +343,7 @@ impl super::Writer<'_, W> { .push(SubAccess::Offset(i * row_stride)); let ty_inner = crate::TypeInner::Vector { size: rows, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }; let sv = StoreValue::TempIndex { depth, @@ -470,8 +464,8 @@ impl super::Writer<'_, W> { crate::TypeInner::Pointer { base, .. } => match module.types[base].inner { crate::TypeInner::Struct { ref members, .. } => Parent::Struct(members), crate::TypeInner::Array { stride, .. } => Parent::Array { stride }, - crate::TypeInner::Vector { width, .. } => Parent::Array { - stride: width as u32, + crate::TypeInner::Vector { scalar, .. } => Parent::Array { + stride: scalar.width as u32, }, crate::TypeInner::Matrix { rows, width, .. } => Parent::Array { // The stride between matrices is the count of rows as this is how @@ -480,8 +474,8 @@ impl super::Writer<'_, W> { }, _ => unreachable!(), }, - crate::TypeInner::ValuePointer { width, .. } => Parent::Array { - stride: width as u32, + crate::TypeInner::ValuePointer { scalar, .. } => Parent::Array { + stride: scalar.width as u32, }, _ => unreachable!(), }; diff --git a/naga/src/back/hlsl/writer.rs b/naga/src/back/hlsl/writer.rs index 08bfb872e61..e969d23d8db 100644 --- a/naga/src/back/hlsl/writer.rs +++ b/naga/src/back/hlsl/writer.rs @@ -912,8 +912,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } if member.binding.is_none() && rows == crate::VectorSize::Bi => { let vec_ty = crate::TypeInner::Vector { size: rows, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }; let field_name_key = NameKey::StructMember(handle, index as u32); @@ -1024,14 +1023,14 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { /// Adds no trailing or leading whitespace pub(super) fn write_value_type(&mut self, module: &Module, inner: &TypeInner) -> BackendResult { match *inner { - TypeInner::Scalar { kind, width } | TypeInner::Atomic { kind, width } => { - write!(self.out, "{}", kind.to_hlsl_str(width)?)?; + TypeInner::Scalar(scalar) | TypeInner::Atomic(scalar) => { + write!(self.out, "{}", scalar.to_hlsl_str()?)?; } - TypeInner::Vector { size, kind, width } => { + TypeInner::Vector { size, scalar } => { write!( self.out, "{}{}", - kind.to_hlsl_str(width)?, + scalar.to_hlsl_str()?, back::vector_size_str(size) )?; } @@ -1047,7 +1046,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { write!( self.out, "{}{}x{}", - crate::ScalarKind::Float.to_hlsl_str(width)?, + crate::Scalar::float(width).to_hlsl_str()?, back::vector_size_str(columns), back::vector_size_str(rows), )?; @@ -2500,7 +2499,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { write!(self.out, ")")?; // return x component if return type is scalar - if let TypeInner::Scalar { .. } = *func_ctx.resolve_type(expr, &module.types) { + if let TypeInner::Scalar(_) = *func_ctx.resolve_type(expr, &module.types) { write!(self.out, ".x")?; } } @@ -2583,23 +2582,27 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { let inner = func_ctx.resolve_type(expr, &module.types); match convert { Some(dst_width) => { + let scalar = crate::Scalar { + kind, + width: dst_width, + }; match *inner { TypeInner::Vector { size, .. } => { write!( self.out, "{}{}(", - kind.to_hlsl_str(dst_width)?, + scalar.to_hlsl_str()?, back::vector_size_str(size) )?; } - TypeInner::Scalar { .. } => { - write!(self.out, "{}(", kind.to_hlsl_str(dst_width)?,)?; + TypeInner::Scalar(_) => { + write!(self.out, "{}(", scalar.to_hlsl_str()?,)?; } TypeInner::Matrix { columns, rows, .. } => { write!( self.out, "{}{}x{}(", - kind.to_hlsl_str(dst_width)?, + scalar.to_hlsl_str()?, back::vector_size_str(columns), back::vector_size_str(rows) )?; @@ -2980,14 +2983,14 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } Function::CountTrailingZeros => { match *func_ctx.resolve_type(arg, &module.types) { - TypeInner::Vector { size, kind, .. } => { + TypeInner::Vector { size, scalar } => { let s = match size { crate::VectorSize::Bi => ".xx", crate::VectorSize::Tri => ".xxx", crate::VectorSize::Quad => ".xxxx", }; - if let ScalarKind::Uint = kind { + if let ScalarKind::Uint = scalar.kind { write!(self.out, "min((32u){s}, firstbitlow(")?; self.write_expr(module, arg, func_ctx)?; write!(self.out, "))")?; @@ -2997,8 +3000,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { write!(self.out, ")))")?; } } - TypeInner::Scalar { kind, .. } => { - if let ScalarKind::Uint = kind { + TypeInner::Scalar(scalar) => { + if let ScalarKind::Uint = scalar.kind { write!(self.out, "min(32u, firstbitlow(")?; self.write_expr(module, arg, func_ctx)?; write!(self.out, "))")?; @@ -3015,14 +3018,14 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } Function::CountLeadingZeros => { match *func_ctx.resolve_type(arg, &module.types) { - TypeInner::Vector { size, kind, .. } => { + TypeInner::Vector { size, scalar } => { let s = match size { crate::VectorSize::Bi => ".xx", crate::VectorSize::Tri => ".xxx", crate::VectorSize::Quad => ".xxxx", }; - if let ScalarKind::Uint = kind { + if let ScalarKind::Uint = scalar.kind { write!(self.out, "((31u){s} - firstbithigh(")?; self.write_expr(module, arg, func_ctx)?; write!(self.out, "))")?; @@ -3037,8 +3040,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { write!(self.out, ")))")?; } } - TypeInner::Scalar { kind, .. } => { - if let ScalarKind::Uint = kind { + TypeInner::Scalar(scalar) => { + if let ScalarKind::Uint = scalar.kind { write!(self.out, "(31u - firstbithigh(")?; self.write_expr(module, arg, func_ctx)?; write!(self.out, "))")?; diff --git a/naga/src/back/msl/writer.rs b/naga/src/back/msl/writer.rs index dcf346db38c..5d8811c734d 100644 --- a/naga/src/back/msl/writer.rs +++ b/naga/src/back/msl/writer.rs @@ -45,28 +45,28 @@ pub(crate) const FREXP_FUNCTION: &str = "naga_frexp"; /// - A two element slice `[ROWS COLUMNS]` produces a matrix of the given size. fn put_numeric_type( out: &mut impl Write, - kind: crate::ScalarKind, + scalar: crate::Scalar, sizes: &[crate::VectorSize], ) -> Result<(), FmtError> { - match (kind, sizes) { - (kind, &[]) => { - write!(out, "{}", kind.to_msl_name()) + match (scalar, sizes) { + (scalar, &[]) => { + write!(out, "{}", scalar.to_msl_name()) } - (kind, &[rows]) => { + (scalar, &[rows]) => { write!( out, "{}::{}{}", NAMESPACE, - kind.to_msl_name(), + scalar.to_msl_name(), back::vector_size_str(rows) ) } - (kind, &[rows, columns]) => { + (scalar, &[rows, columns]) => { write!( out, "{}::{}{}x{}", NAMESPACE, - kind.to_msl_name(), + scalar.to_msl_name(), back::vector_size_str(columns), back::vector_size_str(rows) ) @@ -96,13 +96,13 @@ impl<'a> Display for TypeContext<'a> { } match ty.inner { - crate::TypeInner::Scalar { kind, .. } => put_numeric_type(out, kind, &[]), - crate::TypeInner::Atomic { kind, .. } => { - write!(out, "{}::atomic_{}", NAMESPACE, kind.to_msl_name()) + crate::TypeInner::Scalar(scalar) => put_numeric_type(out, scalar, &[]), + crate::TypeInner::Atomic(scalar) => { + write!(out, "{}::atomic_{}", NAMESPACE, scalar.to_msl_name()) } - crate::TypeInner::Vector { size, kind, .. } => put_numeric_type(out, kind, &[size]), + crate::TypeInner::Vector { size, scalar } => put_numeric_type(out, scalar, &[size]), crate::TypeInner::Matrix { columns, rows, .. } => { - put_numeric_type(out, crate::ScalarKind::Float, &[rows, columns]) + put_numeric_type(out, crate::Scalar::F32, &[rows, columns]) } crate::TypeInner::Pointer { base, space } => { let sub = Self { @@ -118,8 +118,7 @@ impl<'a> Display for TypeContext<'a> { } crate::TypeInner::ValuePointer { size, - kind, - width: _, + scalar, space, } => { match space.to_msl_name() { @@ -127,8 +126,8 @@ impl<'a> Display for TypeContext<'a> { None => return Ok(()), }; match size { - Some(rows) => put_numeric_type(out, kind, &[rows])?, - None => put_numeric_type(out, kind, &[])?, + Some(rows) => put_numeric_type(out, scalar, &[rows])?, + None => put_numeric_type(out, scalar, &[])?, }; write!(out, "&") @@ -194,7 +193,7 @@ impl<'a> Display for TypeContext<'a> { ("texture", "", format.into(), access) } }; - let base_name = kind.to_msl_name(); + let base_name = crate::Scalar { kind, width: 4 }.to_msl_name(); let array_str = if arrayed { "_array" } else { "" }; write!( out, @@ -319,13 +318,26 @@ pub struct Writer { struct_member_pads: FastHashSet<(Handle, u32)>, } -impl crate::ScalarKind { +impl crate::Scalar { const fn to_msl_name(self) -> &'static str { + use crate::ScalarKind as Sk; match self { - Self::Float => "float", - Self::Sint => "int", - Self::Uint => "uint", - Self::Bool => "bool", + Self { + kind: Sk::Float, + width: _, + } => "float", + Self { + kind: Sk::Sint, + width: _, + } => "int", + Self { + kind: Sk::Uint, + width: _, + } => "uint", + Self { + kind: Sk::Bool, + width: _, + } => "bool", } } } @@ -343,7 +355,7 @@ fn should_pack_struct_member( span: u32, index: usize, module: &crate::Module, -) -> Option { +) -> Option { let member = &members[index]; //Note: this is imperfect - the same structure can be used for host-shared // things, where packed float would matter. @@ -362,9 +374,8 @@ fn should_pack_struct_member( match *ty_inner { crate::TypeInner::Vector { size: crate::VectorSize::Tri, - width: 4, - kind, - } if member.offset & 0xF != 0 || is_tight => Some(kind), + scalar: scalar @ crate::Scalar { width: 4, .. }, + } if member.offset & 0xF != 0 || is_tight => Some(scalar), _ => None, } } @@ -442,10 +453,10 @@ impl crate::Type { match self.inner { // value types are concise enough, we only alias them if they are named - Ti::Scalar { .. } + Ti::Scalar(_) | Ti::Vector { .. } | Ti::Matrix { .. } - | Ti::Atomic { .. } + | Ti::Atomic(_) | Ti::Pointer { .. } | Ti::ValuePointer { .. } => self.name.is_some(), // composite types are better to be aliased, regardless of the name @@ -549,10 +560,7 @@ impl<'a> ExpressionContext<'a> { index::access_needs_check(base, index, self.module, self.function, self.info) } - fn get_packed_vec_kind( - &self, - expr_handle: Handle, - ) -> Option { + fn get_packed_vec_kind(&self, expr_handle: Handle) -> Option { match self.function.expressions[expr_handle] { crate::Expression::AccessIndex { base, index } => { let ty = match *self.resolve_type(base) { @@ -673,7 +681,8 @@ impl Writer { crate::TypeInner::Image { dim, .. } => dim, ref other => unreachable!("Unexpected type {:?}", other), }; - let coordinate_type = kind.to_msl_name(); + let scalar = crate::Scalar { kind, width: 4 }; + let coordinate_type = scalar.to_msl_name(); match dim { crate::ImageDimension::D1 => { // Since 1D textures never have mipmaps, MSL requires that the @@ -721,11 +730,11 @@ impl Writer { ) -> BackendResult { // coordinates in IR are int, but Metal expects uint match *context.resolve_type(expr) { - crate::TypeInner::Scalar { .. } => { - put_numeric_type(&mut self.out, crate::ScalarKind::Uint, &[])? + crate::TypeInner::Scalar(_) => { + put_numeric_type(&mut self.out, crate::Scalar::U32, &[])? } crate::TypeInner::Vector { size, .. } => { - put_numeric_type(&mut self.out, crate::ScalarKind::Uint, &[size])? + put_numeric_type(&mut self.out, crate::Scalar::U32, &[size])? } _ => return Err(Error::Validation), }; @@ -1299,7 +1308,7 @@ impl Writer { }; write!(self.out, "{ty_name}")?; match module.types[ty].inner { - crate::TypeInner::Scalar { .. } + crate::TypeInner::Scalar(_) | crate::TypeInner::Vector { .. } | crate::TypeInner::Matrix { .. } => { self.put_call_parameters_impl( @@ -1326,11 +1335,11 @@ impl Writer { } } crate::Expression::Splat { size, value } => { - let scalar_kind = match *get_expr_ty(ctx, value).inner_with(&module.types) { - crate::TypeInner::Scalar { kind, .. } => kind, + let scalar = match *get_expr_ty(ctx, value).inner_with(&module.types) { + crate::TypeInner::Scalar(scalar) => scalar, _ => return Err(Error::Validation), }; - put_numeric_type(&mut self.out, scalar_kind, &[size])?; + put_numeric_type(&mut self.out, scalar, &[size])?; write!(self.out, "(")?; put_expression(self, ctx, value)?; write!(self.out, ")")?; @@ -1626,10 +1635,10 @@ impl Writer { accept, reject, } => match *context.resolve_type(condition) { - crate::TypeInner::Scalar { + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Bool, .. - } => { + }) => { if !is_scoped { write!(self.out, "(")?; } @@ -1643,7 +1652,11 @@ impl Writer { } } crate::TypeInner::Vector { - kind: crate::ScalarKind::Bool, + scalar: + crate::Scalar { + kind: crate::ScalarKind::Bool, + .. + }, .. } => { write!(self.out, "{NAMESPACE}::select(")?; @@ -1687,7 +1700,7 @@ impl Writer { let arg_type = context.resolve_type(arg); let scalar_argument = match arg_type { - &crate::TypeInner::Scalar { .. } => true, + &crate::TypeInner::Scalar(_) => true, _ => false, }; @@ -1732,7 +1745,11 @@ impl Writer { // geometry Mf::Dot => match *context.resolve_type(arg) { crate::TypeInner::Vector { - kind: crate::ScalarKind::Float, + scalar: + crate::Scalar { + kind: crate::ScalarKind::Float, + .. + }, .. } => "dot", crate::TypeInner::Vector { size, .. } => { @@ -1838,16 +1855,16 @@ impl Writer { // or metal will complain that select is ambiguous match *inner { - crate::TypeInner::Vector { size, kind, .. } => { + crate::TypeInner::Vector { size, scalar } => { let size = back::vector_size_str(size); - if let crate::ScalarKind::Sint = kind { + if let crate::ScalarKind::Sint = scalar.kind { write!(self.out, "int{size}")?; } else { write!(self.out, "uint{size}")?; } } - crate::TypeInner::Scalar { kind, .. } => { - if let crate::ScalarKind::Sint = kind { + crate::TypeInner::Scalar(scalar) => { + if let crate::ScalarKind::Sint = scalar.kind { write!(self.out, "int")?; } else { write!(self.out, "uint")?; @@ -1893,19 +1910,15 @@ impl Writer { kind, convert, } => match *context.resolve_type(expr) { - crate::TypeInner::Scalar { - kind: src_kind, - width: src_width, - } - | crate::TypeInner::Vector { - kind: src_kind, - width: src_width, - .. - } => { + crate::TypeInner::Scalar(src) | crate::TypeInner::Vector { scalar: src, .. } => { + let target_scalar = crate::Scalar { + kind, + width: convert.unwrap_or(src.width), + }; let is_bool_cast = - kind == crate::ScalarKind::Bool || src_kind == crate::ScalarKind::Bool; + kind == crate::ScalarKind::Bool || src.kind == crate::ScalarKind::Bool; let op = match convert { - Some(w) if w == src_width || is_bool_cast => "static_cast", + Some(w) if w == src.width || is_bool_cast => "static_cast", Some(8) if kind == crate::ScalarKind::Float => { return Err(Error::CapabilityNotSupported(valid::Capabilities::FLOAT64)) } @@ -1915,16 +1928,24 @@ impl Writer { write!(self.out, "{op}<")?; match *context.resolve_type(expr) { crate::TypeInner::Vector { size, .. } => { - put_numeric_type(&mut self.out, kind, &[size])? + put_numeric_type(&mut self.out, target_scalar, &[size])? } - _ => put_numeric_type(&mut self.out, kind, &[])?, + _ => put_numeric_type(&mut self.out, target_scalar, &[])?, }; write!(self.out, ">(")?; self.put_expression(expr, context, true)?; write!(self.out, ")")?; } - crate::TypeInner::Matrix { columns, rows, .. } => { - put_numeric_type(&mut self.out, kind, &[rows, columns])?; + crate::TypeInner::Matrix { + columns, + rows, + width, + } => { + let target_scalar = crate::Scalar { + kind, + width: convert.unwrap_or(width), + }; + put_numeric_type(&mut self.out, target_scalar, &[rows, columns])?; write!(self.out, "(")?; self.put_expression(expr, context, true)?; write!(self.out, ")")?; @@ -2008,8 +2029,8 @@ impl Writer { context: &ExpressionContext, is_scoped: bool, ) -> BackendResult { - if let Some(scalar_kind) = context.get_packed_vec_kind(expr_handle) { - write!(self.out, "{}::{}3(", NAMESPACE, scalar_kind.to_msl_name())?; + if let Some(scalar) = context.get_packed_vec_kind(expr_handle) { + write!(self.out, "{}::{}3(", NAMESPACE, scalar.to_msl_name())?; self.put_expression(expr_handle, context, is_scoped)?; write!(self.out, ")")?; } else { @@ -2475,8 +2496,8 @@ impl Writer { // check what kind of product this is depending // on the resolve type of the Dot function itself let inner = context.resolve_type(expr_handle); - if let crate::TypeInner::Scalar { kind, .. } = *inner { - match kind { + if let crate::TypeInner::Scalar(scalar) = *inner { + match scalar.kind { crate::ScalarKind::Sint | crate::ScalarKind::Uint => { self.need_bake_expressions.insert(arg); self.need_bake_expressions.insert(arg1.unwrap()); @@ -2522,14 +2543,19 @@ impl Writer { }; write!(self.out, "{ty_name}")?; } - TypeResolution::Value(crate::TypeInner::Scalar { kind, .. }) => { - put_numeric_type(&mut self.out, kind, &[])?; + TypeResolution::Value(crate::TypeInner::Scalar(scalar)) => { + put_numeric_type(&mut self.out, scalar, &[])?; } - TypeResolution::Value(crate::TypeInner::Vector { size, kind, .. }) => { - put_numeric_type(&mut self.out, kind, &[size])?; + TypeResolution::Value(crate::TypeInner::Vector { size, scalar }) => { + put_numeric_type(&mut self.out, scalar, &[size])?; } - TypeResolution::Value(crate::TypeInner::Matrix { columns, rows, .. }) => { - put_numeric_type(&mut self.out, crate::ScalarKind::Float, &[rows, columns])?; + TypeResolution::Value(crate::TypeInner::Matrix { + columns, + rows, + width, + }) => { + let element = crate::Scalar::float(width); + put_numeric_type(&mut self.out, element, &[rows, columns])?; } TypeResolution::Value(ref other) => { log::warn!("Type {:?} isn't a known local", other); //TEMP! @@ -3295,13 +3321,13 @@ impl Writer { // If the member should be packed (as is the case for a misaligned vec3) issue a packed vector match should_pack_struct_member(members, span, index, module) { - Some(kind) => { + Some(scalar) => { writeln!( self.out, "{}{}::packed_{}3 {};", back::INDENT, NAMESPACE, - kind.to_msl_name(), + scalar.to_msl_name(), member_name )?; } @@ -3325,11 +3351,10 @@ impl Writer { // for 3-component vectors, add one component if let crate::TypeInner::Vector { size: crate::VectorSize::Tri, - kind: _, - width, + scalar, } = *ty_inner { - last_offset += width as u32; + last_offset += scalar.width as u32; } } } diff --git a/naga/src/back/spv/block.rs b/naga/src/back/spv/block.rs index 519e38ef428..de7eae7e1a6 100644 --- a/naga/src/back/spv/block.rs +++ b/naga/src/back/spv/block.rs @@ -12,7 +12,7 @@ use spirv::Word; fn get_dimension(type_inner: &crate::TypeInner) -> Dimension { match *type_inner { - crate::TypeInner::Scalar { .. } => Dimension::Scalar, + crate::TypeInner::Scalar(_) => Dimension::Scalar, crate::TypeInner::Vector { .. } => Dimension::Vector, crate::TypeInner::Matrix { .. } => Dimension::Matrix, _ => unreachable!(), @@ -78,8 +78,7 @@ impl Writer { ) -> Result<(), Error> { let float_ptr_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Float, - width: 4, + scalar: crate::Scalar::F32, pointer_space: Some(spirv::StorageClass::Output), })); let index_y_id = self.get_index_constant(1); @@ -93,8 +92,7 @@ impl Writer { let float_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Float, - width: 4, + scalar: crate::Scalar::F32, pointer_space: None, })); let load_id = self.id_gen.next(); @@ -120,8 +118,7 @@ impl Writer { ) -> Result<(), Error> { let float_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Float, - width: 4, + scalar: crate::Scalar::F32, pointer_space: None, })); let zero_scalar_id = self.get_constant_scalar(crate::Literal::F32(0.0)); @@ -490,8 +487,8 @@ impl<'w> BlockContext<'w> { let spirv_op = match op { crate::BinaryOperator::Add => match *left_ty_inner { - crate::TypeInner::Scalar { kind, .. } - | crate::TypeInner::Vector { kind, .. } => match kind { + crate::TypeInner::Scalar(scalar) + | crate::TypeInner::Vector { scalar, .. } => match scalar.kind { crate::ScalarKind::Float => spirv::Op::FAdd, _ => spirv::Op::IAdd, }, @@ -518,8 +515,8 @@ impl<'w> BlockContext<'w> { _ => unimplemented!(), }, crate::BinaryOperator::Subtract => match *left_ty_inner { - crate::TypeInner::Scalar { kind, .. } - | crate::TypeInner::Vector { kind, .. } => match kind { + crate::TypeInner::Scalar(scalar) + | crate::TypeInner::Vector { scalar, .. } => match scalar.kind { crate::ScalarKind::Float => spirv::Op::FSub, _ => spirv::Op::ISub, }, @@ -742,20 +739,19 @@ impl<'w> BlockContext<'w> { other => unimplemented!("Unexpected max({:?})", other), }), Mf::Saturate => { - let (maybe_size, width) = match *arg_ty { - crate::TypeInner::Vector { size, width, .. } => (Some(size), width), - crate::TypeInner::Scalar { width, .. } => (None, width), + let (maybe_size, scalar) = match *arg_ty { + crate::TypeInner::Vector { size, scalar } => (Some(size), scalar), + crate::TypeInner::Scalar(scalar) => (None, scalar), ref other => unimplemented!("Unexpected saturate({:?})", other), }; - let kind = crate::ScalarKind::Float; - let mut arg1_id = self.writer.get_constant_scalar_with(0, kind, width)?; - let mut arg2_id = self.writer.get_constant_scalar_with(1, kind, width)?; + let scalar = crate::Scalar::float(scalar.width); + let mut arg1_id = self.writer.get_constant_scalar_with(0, scalar)?; + let mut arg2_id = self.writer.get_constant_scalar_with(1, scalar)?; if let Some(size) = maybe_size { let ty = LocalType::Value { vector_size: Some(size), - kind, - width, + scalar, pointer_space: None, } .into(); @@ -806,7 +802,11 @@ impl<'w> BlockContext<'w> { // geometry Mf::Dot => match *self.fun_info[arg].ty.inner_with(&self.ir_module.types) { crate::TypeInner::Vector { - kind: crate::ScalarKind::Float, + scalar: + crate::Scalar { + kind: crate::ScalarKind::Float, + .. + }, .. } => MathOp::Custom(Instruction::binary( spirv::Op::Dot, @@ -867,13 +867,12 @@ impl<'w> BlockContext<'w> { // if the selector is a scalar, we need to splat it ( &crate::TypeInner::Vector { size, .. }, - &crate::TypeInner::Scalar { kind, width }, + &crate::TypeInner::Scalar(scalar), ) => { let selector_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: Some(size), - kind, - width, + scalar, pointer_space: None, })); self.temp_list.clear(); @@ -916,14 +915,12 @@ impl<'w> BlockContext<'w> { arg0_id, )), Mf::CountTrailingZeros => { - let kind = crate::ScalarKind::Uint; - let uint_id = match *arg_ty { - crate::TypeInner::Vector { size, width, .. } => { + crate::TypeInner::Vector { size, mut scalar } => { + scalar.kind = crate::ScalarKind::Uint; let ty = LocalType::Value { vector_size: Some(size), - kind, - width, + scalar, pointer_space: None, } .into(); @@ -931,13 +928,14 @@ impl<'w> BlockContext<'w> { self.temp_list.clear(); self.temp_list.resize( size as _, - self.writer.get_constant_scalar_with(32, kind, width)?, + self.writer.get_constant_scalar_with(32, scalar)?, ); self.writer.get_constant_composite(ty, &self.temp_list) } - crate::TypeInner::Scalar { width, .. } => { - self.writer.get_constant_scalar_with(32, kind, width)? + crate::TypeInner::Scalar(mut scalar) => { + scalar.kind = crate::ScalarKind::Uint; + self.writer.get_constant_scalar_with(32, scalar)? } _ => unreachable!(), }; @@ -960,14 +958,12 @@ impl<'w> BlockContext<'w> { )) } Mf::CountLeadingZeros => { - let kind = crate::ScalarKind::Sint; - let (int_type_id, int_id) = match *arg_ty { - crate::TypeInner::Vector { size, width, .. } => { + crate::TypeInner::Vector { size, mut scalar } => { + scalar.kind = crate::ScalarKind::Sint; let ty = LocalType::Value { vector_size: Some(size), - kind, - width, + scalar, pointer_space: None, } .into(); @@ -975,7 +971,7 @@ impl<'w> BlockContext<'w> { self.temp_list.clear(); self.temp_list.resize( size as _, - self.writer.get_constant_scalar_with(31, kind, width)?, + self.writer.get_constant_scalar_with(31, scalar)?, ); ( @@ -983,15 +979,17 @@ impl<'w> BlockContext<'w> { self.writer.get_constant_composite(ty, &self.temp_list), ) } - crate::TypeInner::Scalar { width, .. } => ( - self.get_type_id(LookupType::Local(LocalType::Value { - vector_size: None, - kind, - width, - pointer_space: None, - })), - self.writer.get_constant_scalar_with(31, kind, width)?, - ), + crate::TypeInner::Scalar(mut scalar) => { + scalar.kind = crate::ScalarKind::Sint; + ( + self.get_type_id(LookupType::Local(LocalType::Value { + vector_size: None, + scalar, + pointer_space: None, + })), + self.writer.get_constant_scalar_with(31, scalar)?, + ) + } _ => unreachable!(), }; @@ -1140,13 +1138,13 @@ impl<'w> BlockContext<'w> { use crate::ScalarKind as Sk; let expr_id = self.cached[expr]; - let (src_kind, src_size, src_width, is_matrix) = + let (src_scalar, src_size, is_matrix) = match *self.fun_info[expr].ty.inner_with(&self.ir_module.types) { - crate::TypeInner::Scalar { kind, width } => (kind, None, width, false), - crate::TypeInner::Vector { kind, width, size } => { - (kind, Some(size), width, false) + crate::TypeInner::Scalar(scalar) => (scalar, None, false), + crate::TypeInner::Vector { scalar, size } => (scalar, Some(size), false), + crate::TypeInner::Matrix { width, .. } => { + (crate::Scalar::float(width), None, true) } - crate::TypeInner::Matrix { width, .. } => (kind, None, width, true), ref other => { log::error!("As source {:?}", other); return Err(Error::Validation("Unexpected Expression::As source")); @@ -1164,11 +1162,12 @@ impl<'w> BlockContext<'w> { // we only support identity casts for matrices Cast::Unary(spirv::Op::CopyObject) } else { - match (src_kind, kind, convert) { + match (src_scalar.kind, kind, convert) { // Filter out identity casts. Some Adreno drivers are // confused by no-op OpBitCast instructions. (src_kind, kind, convert) - if src_kind == kind && convert.unwrap_or(src_width) == src_width => + if src_kind == kind + && convert.filter(|&width| width != src_scalar.width).is_none() => { Cast::Identity } @@ -1176,20 +1175,18 @@ impl<'w> BlockContext<'w> { (_, _, None) => Cast::Unary(spirv::Op::Bitcast), // casting to a bool - generate `OpXxxNotEqual` (_, Sk::Bool, Some(_)) => { - let op = match src_kind { + let op = match src_scalar.kind { Sk::Sint | Sk::Uint => spirv::Op::INotEqual, Sk::Float => spirv::Op::FUnordNotEqual, Sk::Bool => unreachable!(), }; - let zero_scalar_id = self - .writer - .get_constant_scalar_with(0, src_kind, src_width)?; + let zero_scalar_id = + self.writer.get_constant_scalar_with(0, src_scalar)?; let zero_id = match src_size { Some(size) => { let ty = LocalType::Value { vector_size: Some(size), - kind: src_kind, - width: src_width, + scalar: src_scalar, pointer_space: None, } .into(); @@ -1206,16 +1203,19 @@ impl<'w> BlockContext<'w> { } // casting from a bool - generate `OpSelect` (Sk::Bool, _, Some(dst_width)) => { + let dst_scalar = crate::Scalar { + kind, + width: dst_width, + }; let zero_scalar_id = - self.writer.get_constant_scalar_with(0, kind, dst_width)?; + self.writer.get_constant_scalar_with(0, dst_scalar)?; let one_scalar_id = - self.writer.get_constant_scalar_with(1, kind, dst_width)?; + self.writer.get_constant_scalar_with(1, dst_scalar)?; let (accept_id, reject_id) = match src_size { Some(size) => { let ty = LocalType::Value { vector_size: Some(size), - kind, - width: dst_width, + scalar: dst_scalar, pointer_space: None, } .into(); @@ -1240,15 +1240,17 @@ impl<'w> BlockContext<'w> { } (Sk::Float, Sk::Uint, Some(_)) => Cast::Unary(spirv::Op::ConvertFToU), (Sk::Float, Sk::Sint, Some(_)) => Cast::Unary(spirv::Op::ConvertFToS), - (Sk::Float, Sk::Float, Some(dst_width)) if src_width != dst_width => { + (Sk::Float, Sk::Float, Some(dst_width)) + if src_scalar.width != dst_width => + { Cast::Unary(spirv::Op::FConvert) } (Sk::Sint, Sk::Float, Some(_)) => Cast::Unary(spirv::Op::ConvertSToF), - (Sk::Sint, Sk::Sint, Some(dst_width)) if src_width != dst_width => { + (Sk::Sint, Sk::Sint, Some(dst_width)) if src_scalar.width != dst_width => { Cast::Unary(spirv::Op::SConvert) } (Sk::Uint, Sk::Float, Some(_)) => Cast::Unary(spirv::Op::ConvertUToF), - (Sk::Uint, Sk::Uint, Some(dst_width)) if src_width != dst_width => { + (Sk::Uint, Sk::Uint, Some(dst_width)) if src_scalar.width != dst_width => { Cast::Unary(spirv::Op::UConvert) } // We assume it's either an identity cast, or int-uint. @@ -1335,10 +1337,12 @@ impl<'w> BlockContext<'w> { let object_ty = self.fun_info[accept].ty.inner_with(&self.ir_module.types); if let ( - &crate::TypeInner::Scalar { - kind: crate::ScalarKind::Bool, - width, - }, + &crate::TypeInner::Scalar( + condition_scalar @ crate::Scalar { + kind: crate::ScalarKind::Bool, + .. + }, + ), &crate::TypeInner::Vector { size, .. }, ) = (condition_ty, object_ty) { @@ -1348,8 +1352,7 @@ impl<'w> BlockContext<'w> { let bool_vector_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: Some(size), - kind: crate::ScalarKind::Bool, - width, + scalar: condition_scalar, pointer_space: None, })); @@ -1599,8 +1602,7 @@ impl<'w> BlockContext<'w> { let vector_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: Some(rows), - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), pointer_space: None, })); @@ -1650,7 +1652,10 @@ impl<'w> BlockContext<'w> { vector: &crate::TypeInner, ) { let (size, kind) = match *vector { - crate::TypeInner::Vector { size, kind, .. } => (size, kind), + crate::TypeInner::Vector { + size, + scalar: crate::Scalar { kind, .. }, + } => (size, kind), _ => unreachable!(), }; @@ -2194,14 +2199,14 @@ impl<'w> BlockContext<'w> { ), crate::AtomicFunction::Min => { let spirv_op = match *value_inner { - crate::TypeInner::Scalar { + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Sint, width: _, - } => spirv::Op::AtomicSMin, - crate::TypeInner::Scalar { + }) => spirv::Op::AtomicSMin, + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Uint, width: _, - } => spirv::Op::AtomicUMin, + }) => spirv::Op::AtomicUMin, _ => unimplemented!(), }; Instruction::atomic_binary( @@ -2216,14 +2221,14 @@ impl<'w> BlockContext<'w> { } crate::AtomicFunction::Max => { let spirv_op = match *value_inner { - crate::TypeInner::Scalar { + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Sint, width: _, - } => spirv::Op::AtomicSMax, - crate::TypeInner::Scalar { + }) => spirv::Op::AtomicSMax, + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Uint, width: _, - } => spirv::Op::AtomicUMax, + }) => spirv::Op::AtomicUMax, _ => unimplemented!(), }; Instruction::atomic_binary( @@ -2249,11 +2254,10 @@ impl<'w> BlockContext<'w> { } crate::AtomicFunction::Exchange { compare: Some(cmp) } => { let scalar_type_id = match *value_inner { - crate::TypeInner::Scalar { kind, width } => { + crate::TypeInner::Scalar(scalar) => { self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind, - width, + scalar, pointer_space: None, })) } @@ -2262,8 +2266,7 @@ impl<'w> BlockContext<'w> { let bool_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Bool, - width: crate::BOOL_WIDTH, + scalar: crate::Scalar::BOOL, pointer_space: None, })); diff --git a/naga/src/back/spv/image.rs b/naga/src/back/spv/image.rs index cb4fc557ee8..695c4298fa2 100644 --- a/naga/src/back/spv/image.rs +++ b/naga/src/back/spv/image.rs @@ -128,8 +128,7 @@ impl Load { crate::ImageClass::Depth { .. } => { ctx.get_type_id(LookupType::Local(LocalType::Value { vector_size: Some(crate::VectorSize::Quad), - kind: crate::ScalarKind::Float, - width: 4, + scalar: crate::Scalar::F32, pointer_space: None, })) } @@ -292,18 +291,16 @@ impl<'w> BlockContext<'w> { // Find the component type of `coordinates`, and figure out the size the // combined coordinate vector will have. - let (component_kind, size) = match *inner_ty { - Ti::Scalar { kind, width: 4 } => (kind, Some(Vs::Bi)), + let (component_scalar, size) = match *inner_ty { + Ti::Scalar(scalar @ crate::Scalar { width: 4, .. }) => (scalar, Some(Vs::Bi)), Ti::Vector { - kind, - width: 4, + scalar: scalar @ crate::Scalar { width: 4, .. }, size: Vs::Bi, - } => (kind, Some(Vs::Tri)), + } => (scalar, Some(Vs::Tri)), Ti::Vector { - kind, - width: 4, + scalar: scalar @ crate::Scalar { width: 4, .. }, size: Vs::Tri, - } => (kind, Some(Vs::Quad)), + } => (scalar, Some(Vs::Quad)), Ti::Vector { size: Vs::Quad, .. } => { return Err(Error::Validation("extending vec4 coordinate")); } @@ -317,16 +314,16 @@ impl<'w> BlockContext<'w> { let array_index_id = self.cached[array_index]; let ty = &self.fun_info[array_index].ty; let inner_ty = ty.inner_with(&self.ir_module.types); - let array_index_kind = if let Ti::Scalar { kind, width: 4 } = *inner_ty { - debug_assert!(matches!( - kind, - crate::ScalarKind::Sint | crate::ScalarKind::Uint - )); - kind - } else { - unreachable!("we only allow i32 and u32"); + let array_index_scalar = match *inner_ty { + Ti::Scalar( + scalar @ crate::Scalar { + kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint, + width: 4, + }, + ) => scalar, + _ => unreachable!("we only allow i32 and u32"), }; - let cast = match (component_kind, array_index_kind) { + let cast = match (component_scalar.kind, array_index_scalar.kind) { (crate::ScalarKind::Sint, crate::ScalarKind::Sint) | (crate::ScalarKind::Uint, crate::ScalarKind::Uint) => None, (crate::ScalarKind::Sint, crate::ScalarKind::Uint) @@ -341,8 +338,7 @@ impl<'w> BlockContext<'w> { let reconciled_array_index_id = if let Some(cast) = cast { let component_ty_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: component_kind, - width: 4, + scalar: component_scalar, pointer_space: None, })); let reconciled_id = self.gen_id(); @@ -360,8 +356,7 @@ impl<'w> BlockContext<'w> { // Find the SPIR-V type for the combined coordinates/index vector. let type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: size, - kind: component_kind, - width: 4, + scalar: component_scalar, pointer_space: None, })); @@ -532,8 +527,7 @@ impl<'w> BlockContext<'w> { let i32_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Sint, - width: 4, + scalar: crate::Scalar::I32, pointer_space: None, })); @@ -620,8 +614,7 @@ impl<'w> BlockContext<'w> { let bool_type_id = self.writer.get_bool_type_id(); let i32_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Sint, - width: 4, + scalar: crate::Scalar::I32, pointer_space: None, })); @@ -688,8 +681,7 @@ impl<'w> BlockContext<'w> { // Compare the coordinates against the bounds. let coords_bool_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: coordinates.size, - kind: crate::ScalarKind::Bool, - width: 1, + scalar: crate::Scalar::BOOL, pointer_space: None, })); let coords_conds_id = self.gen_id(); @@ -844,8 +836,7 @@ impl<'w> BlockContext<'w> { let sample_result_type_id = if needs_sub_access { self.get_type_id(LookupType::Local(LocalType::Value { vector_size: Some(crate::VectorSize::Quad), - kind: crate::ScalarKind::Float, - width: 4, + scalar: crate::Scalar::F32, pointer_space: None, })) } else { @@ -1045,8 +1036,7 @@ impl<'w> BlockContext<'w> { }; let extended_size_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: crate::Scalar::U32, pointer_space: None, })); @@ -1116,8 +1106,7 @@ impl<'w> BlockContext<'w> { }; let extended_size_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: Some(vec_size), - kind: crate::ScalarKind::Uint, - width: 4, + scalar: crate::Scalar::U32, pointer_space: None, })); let id_extended = self.gen_id(); diff --git a/naga/src/back/spv/mod.rs b/naga/src/back/spv/mod.rs index beea5226f31..38c65114100 100644 --- a/naga/src/back/spv/mod.rs +++ b/naga/src/back/spv/mod.rs @@ -276,8 +276,7 @@ enum LocalType { /// If `None`, this represents a scalar type. If `Some`, this represents /// a vector type of the given size. vector_size: Option, - kind: crate::ScalarKind, - width: crate::Bytes, + scalar: crate::Scalar, pointer_space: Option, }, /// A matrix of floating-point values. @@ -355,18 +354,14 @@ struct LookupFunctionType { fn make_local(inner: &crate::TypeInner) -> Option { Some(match *inner { - crate::TypeInner::Scalar { kind, width } | crate::TypeInner::Atomic { kind, width } => { - LocalType::Value { - vector_size: None, - kind, - width, - pointer_space: None, - } - } - crate::TypeInner::Vector { size, kind, width } => LocalType::Value { + crate::TypeInner::Scalar(scalar) | crate::TypeInner::Atomic(scalar) => LocalType::Value { + vector_size: None, + scalar, + pointer_space: None, + }, + crate::TypeInner::Vector { size, scalar } => LocalType::Value { vector_size: Some(size), - kind, - width, + scalar, pointer_space: None, }, crate::TypeInner::Matrix { @@ -384,13 +379,11 @@ fn make_local(inner: &crate::TypeInner) -> Option { }, crate::TypeInner::ValuePointer { size, - kind, - width, + scalar, space, } => LocalType::Value { vector_size: size, - kind, - width, + scalar, pointer_space: Some(helpers::map_storage_class(space)), }, crate::TypeInner::Image { diff --git a/naga/src/back/spv/ray.rs b/naga/src/back/spv/ray.rs index ed61129f929..bc2c4ce3c62 100644 --- a/naga/src/back/spv/ray.rs +++ b/naga/src/back/spv/ray.rs @@ -21,12 +21,10 @@ impl<'w> BlockContext<'w> { //Note: composite extract indices and types must match `generate_ray_desc_type` let desc_id = self.cached[descriptor]; let acc_struct_id = self.get_handle_id(acceleration_structure); - let width = 4; let flag_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Uint, - width, + scalar: crate::Scalar::U32, pointer_space: None, })); let ray_flags_id = self.gen_id(); @@ -46,8 +44,7 @@ impl<'w> BlockContext<'w> { let scalar_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::F32, pointer_space: None, })); let tmin_id = self.gen_id(); @@ -67,8 +64,7 @@ impl<'w> BlockContext<'w> { let vector_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: Some(crate::VectorSize::Tri), - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::F32, pointer_space: None, })); let ray_origin_id = self.gen_id(); @@ -115,7 +111,6 @@ impl<'w> BlockContext<'w> { query: Handle, block: &mut Block, ) -> spirv::Word { - let width = 4; let query_id = self.cached[query]; let intersection_id = self.writer.get_constant_scalar(crate::Literal::U32( spirv::RayQueryIntersection::RayQueryCommittedIntersectionKHR as _, @@ -123,8 +118,7 @@ impl<'w> BlockContext<'w> { let flag_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Uint, - width, + scalar: crate::Scalar::U32, pointer_space: None, })); let kind_id = self.gen_id(); @@ -178,8 +172,7 @@ impl<'w> BlockContext<'w> { let scalar_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::F32, pointer_space: None, })); let t_id = self.gen_id(); @@ -193,8 +186,7 @@ impl<'w> BlockContext<'w> { let barycentrics_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: Some(crate::VectorSize::Bi), - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::F32, pointer_space: None, })); let barycentrics_id = self.gen_id(); @@ -208,8 +200,7 @@ impl<'w> BlockContext<'w> { let bool_type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Bool, - width: crate::BOOL_WIDTH, + scalar: crate::Scalar::BOOL, pointer_space: None, })); let front_face_id = self.gen_id(); @@ -224,7 +215,7 @@ impl<'w> BlockContext<'w> { let transform_type_id = self.get_type_id(LookupType::Local(LocalType::Matrix { columns: crate::VectorSize::Quad, rows: crate::VectorSize::Tri, - width, + width: 4, })); let object_to_world_id = self.gen_id(); block.body.push(Instruction::ray_query_get_intersection( diff --git a/naga/src/back/spv/writer.rs b/naga/src/back/spv/writer.rs index c7aa030d1ad..85ecd511862 100644 --- a/naga/src/back/spv/writer.rs +++ b/naga/src/back/spv/writer.rs @@ -249,8 +249,7 @@ impl Writer { pub(super) fn get_uint_type_id(&mut self) -> Word { let local_type = LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: crate::Scalar::U32, pointer_space: None, }; self.get_type_id(local_type.into()) @@ -259,8 +258,7 @@ impl Writer { pub(super) fn get_float_type_id(&mut self) -> Word { let local_type = LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Float, - width: 4, + scalar: crate::Scalar::F32, pointer_space: None, }; self.get_type_id(local_type.into()) @@ -269,8 +267,7 @@ impl Writer { pub(super) fn get_uint3_type_id(&mut self) -> Word { let local_type = LocalType::Value { vector_size: Some(crate::VectorSize::Tri), - kind: crate::ScalarKind::Uint, - width: 4, + scalar: crate::Scalar::U32, pointer_space: None, }; self.get_type_id(local_type.into()) @@ -279,8 +276,7 @@ impl Writer { pub(super) fn get_float_pointer_type_id(&mut self, class: spirv::StorageClass) -> Word { let lookup_type = LookupType::Local(LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Float, - width: 4, + scalar: crate::Scalar::F32, pointer_space: Some(class), }); if let Some(&id) = self.lookup_type.get(&lookup_type) { @@ -298,8 +294,7 @@ impl Writer { pub(super) fn get_uint3_pointer_type_id(&mut self, class: spirv::StorageClass) -> Word { let lookup_type = LookupType::Local(LocalType::Value { vector_size: Some(crate::VectorSize::Tri), - kind: crate::ScalarKind::Uint, - width: 4, + scalar: crate::Scalar::U32, pointer_space: Some(class), }); if let Some(&id) = self.lookup_type.get(&lookup_type) { @@ -317,8 +312,7 @@ impl Writer { pub(super) fn get_bool_type_id(&mut self) -> Word { let local_type = LocalType::Value { vector_size: None, - kind: crate::ScalarKind::Bool, - width: 1, + scalar: crate::Scalar::BOOL, pointer_space: None, }; self.get_type_id(local_type.into()) @@ -327,8 +321,7 @@ impl Writer { pub(super) fn get_bool3_type_id(&mut self) -> Word { let local_type = LocalType::Value { vector_size: Some(crate::VectorSize::Tri), - kind: crate::ScalarKind::Bool, - width: 1, + scalar: crate::Scalar::BOOL, pointer_space: None, }; self.get_type_id(local_type.into()) @@ -813,18 +806,13 @@ impl Writer { )) } - fn make_scalar( - &mut self, - id: Word, - kind: crate::ScalarKind, - width: crate::Bytes, - ) -> Instruction { + fn make_scalar(&mut self, id: Word, scalar: crate::Scalar) -> Instruction { use crate::ScalarKind as Sk; - let bits = (width * BITS_PER_BYTE) as u32; - match kind { + let bits = (scalar.width * BITS_PER_BYTE) as u32; + match scalar.kind { Sk::Sint | Sk::Uint => { - let signedness = if kind == Sk::Sint { + let signedness = if scalar.kind == Sk::Sint { super::instructions::Signedness::Signed } else { super::instructions::Signedness::Unsigned @@ -905,20 +893,17 @@ impl Writer { let instruction = match local_ty { LocalType::Value { vector_size: None, - kind, - width, + scalar, pointer_space: None, - } => self.make_scalar(id, kind, width), + } => self.make_scalar(id, scalar), LocalType::Value { vector_size: Some(size), - kind, - width, + scalar, pointer_space: None, } => { let scalar_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind, - width, + scalar, pointer_space: None, })); Instruction::type_vector(id, scalar_id, size) @@ -930,8 +915,7 @@ impl Writer { } => { let vector_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: Some(rows), - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), pointer_space: None, })); Instruction::type_matrix(id, vector_id, columns) @@ -942,14 +926,12 @@ impl Writer { } LocalType::Value { vector_size, - kind, - width, + scalar, pointer_space: Some(class), } => { let type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size, - kind, - width, + scalar, pointer_space: None, })); Instruction::type_pointer(id, class, type_id) @@ -957,8 +939,10 @@ impl Writer { LocalType::Image(image) => { let local_type = LocalType::Value { vector_size: None, - kind: image.sampled_type, - width: 4, + scalar: crate::Scalar { + kind: image.sampled_type, + width: 4, + }, pointer_space: None, }; let type_id = self.get_type_id(LookupType::Local(local_type)); @@ -1071,8 +1055,8 @@ impl Writer { // These all have TypeLocal representations, so they should have been // handled by `write_type_declaration_local` above. - crate::TypeInner::Scalar { .. } - | crate::TypeInner::Atomic { .. } + crate::TypeInner::Scalar(_) + | crate::TypeInner::Atomic(_) | crate::TypeInner::Vector { .. } | crate::TypeInner::Matrix { .. } | crate::TypeInner::Pointer { .. } @@ -1162,11 +1146,10 @@ impl Writer { pub(super) fn get_constant_scalar_with( &mut self, value: u8, - kind: crate::ScalarKind, - width: crate::Bytes, + scalar: crate::Scalar, ) -> Result { Ok( - self.get_constant_scalar(crate::Literal::new(value, kind, width).ok_or( + self.get_constant_scalar(crate::Literal::new(value, scalar).ok_or( Error::Validation("Unexpected kind and/or width for Literal"), )?), ) @@ -1196,8 +1179,7 @@ impl Writer { } let type_id = self.get_type_id(LookupType::Local(LocalType::Value { vector_size: None, - kind: value.scalar_kind(), - width: value.width(), + scalar: value.scalar(), pointer_space: None, })); let instruction = match *value { @@ -1613,8 +1595,8 @@ impl Writer { // > shader, must be decorated Flat if class == spirv::StorageClass::Input && stage == crate::ShaderStage::Fragment { let is_flat = match ir_module.types[ty].inner { - crate::TypeInner::Scalar { kind, .. } - | crate::TypeInner::Vector { kind, .. } => match kind { + crate::TypeInner::Scalar(scalar) + | crate::TypeInner::Vector { scalar, .. } => match scalar.kind { Sk::Uint | Sk::Sint | Sk::Bool => true, Sk::Float => false, }, diff --git a/naga/src/back/wgsl/writer.rs b/naga/src/back/wgsl/writer.rs index 9a21d36edea..aaf083a9157 100644 --- a/naga/src/back/wgsl/writer.rs +++ b/naga/src/back/wgsl/writer.rs @@ -428,11 +428,11 @@ impl Writer { /// Adds no trailing or leading whitespace fn write_value_type(&mut self, module: &Module, inner: &TypeInner) -> BackendResult { match *inner { - TypeInner::Vector { size, kind, width } => write!( + TypeInner::Vector { size, scalar } => write!( self.out, "vec{}<{}>", back::vector_size_str(size), - scalar_kind_str(kind, width), + scalar_kind_str(scalar), )?, TypeInner::Sampler { comparison: false } => { write!(self.out, "sampler")?; @@ -454,7 +454,7 @@ impl Writer { Ic::Sampled { kind, multi } => ( "", if multi { "multisampled_" } else { "" }, - scalar_kind_str(kind, 4), + scalar_kind_str(crate::Scalar { kind, width: 4 }), "", ), Ic::Depth { multi } => { @@ -483,11 +483,11 @@ impl Writer { write!(self.out, "<{format_str}{storage_str}>")?; } } - TypeInner::Scalar { kind, width } => { - write!(self.out, "{}", scalar_kind_str(kind, width))?; + TypeInner::Scalar(scalar) => { + write!(self.out, "{}", scalar_kind_str(scalar))?; } - TypeInner::Atomic { kind, width } => { - write!(self.out, "atomic<{}>", scalar_kind_str(kind, width))?; + TypeInner::Atomic(scalar) => { + write!(self.out, "atomic<{}>", scalar_kind_str(scalar))?; } TypeInner::Array { base, @@ -526,14 +526,14 @@ impl Writer { TypeInner::Matrix { columns, rows, - width: _, + width, } => { write!( self.out, - //TODO: Can matrix be other than f32? - "mat{}x{}", + "mat{}x{}<{}>", back::vector_size_str(columns), back::vector_size_str(rows), + scalar_kind_str(crate::Scalar::float(width)) )?; } TypeInner::Pointer { base, space } => { @@ -554,13 +554,12 @@ impl Writer { } TypeInner::ValuePointer { size: None, - kind, - width, + scalar, space, } => { let (address, maybe_access) = address_space_str(space); if let Some(space) = address { - write!(self.out, "ptr<{}, {}", space, scalar_kind_str(kind, width))?; + write!(self.out, "ptr<{}, {}", space, scalar_kind_str(scalar))?; if let Some(access) = maybe_access { write!(self.out, ", {access}")?; } @@ -573,8 +572,7 @@ impl Writer { } TypeInner::ValuePointer { size: Some(size), - kind, - width, + scalar, space, } => { let (address, maybe_access) = address_space_str(space); @@ -584,7 +582,7 @@ impl Writer { "ptr<{}, vec{}<{}>", space, back::vector_size_str(size), - scalar_kind_str(kind, width) + scalar_kind_str(scalar) )?; if let Some(access) = maybe_access { write!(self.out, ", {access}")?; @@ -1432,7 +1430,11 @@ impl Writer { width, .. } => { - let scalar_kind_str = scalar_kind_str(kind, convert.unwrap_or(width)); + let scalar = crate::Scalar { + kind, + width: convert.unwrap_or(width), + }; + let scalar_kind_str = scalar_kind_str(scalar); write!( self.out, "mat{}x{}<{}>", @@ -1441,17 +1443,28 @@ impl Writer { scalar_kind_str )?; } - TypeInner::Vector { size, width, .. } => { + TypeInner::Vector { + size, + scalar: crate::Scalar { width, .. }, + } => { + let scalar = crate::Scalar { + kind, + width: convert.unwrap_or(width), + }; let vector_size_str = back::vector_size_str(size); - let scalar_kind_str = scalar_kind_str(kind, convert.unwrap_or(width)); + let scalar_kind_str = scalar_kind_str(scalar); if convert.is_some() { write!(self.out, "vec{vector_size_str}<{scalar_kind_str}>")?; } else { write!(self.out, "bitcast>")?; } } - TypeInner::Scalar { width, .. } => { - let scalar_kind_str = scalar_kind_str(kind, convert.unwrap_or(width)); + TypeInner::Scalar(crate::Scalar { width, .. }) => { + let scalar = crate::Scalar { + kind, + width: convert.unwrap_or(width), + }; + let scalar_kind_str = scalar_kind_str(scalar); if convert.is_some() { write!(self.out, "{scalar_kind_str}")? } else { @@ -1801,15 +1814,31 @@ const fn image_dimension_str(dim: crate::ImageDimension) -> &'static str { } } -const fn scalar_kind_str(kind: crate::ScalarKind, width: u8) -> &'static str { +const fn scalar_kind_str(scalar: crate::Scalar) -> &'static str { + use crate::Scalar; use crate::ScalarKind as Sk; - match (kind, width) { - (Sk::Float, 8) => "f64", - (Sk::Float, 4) => "f32", - (Sk::Sint, 4) => "i32", - (Sk::Uint, 4) => "u32", - (Sk::Bool, 1) => "bool", + match scalar { + Scalar { + kind: Sk::Float, + width: 8, + } => "f64", + Scalar { + kind: Sk::Float, + width: 4, + } => "f32", + Scalar { + kind: Sk::Sint, + width: 4, + } => "i32", + Scalar { + kind: Sk::Uint, + width: 4, + } => "u32", + Scalar { + kind: Sk::Bool, + width: 1, + } => "bool", _ => unreachable!(), } } diff --git a/naga/src/compact/expressions.rs b/naga/src/compact/expressions.rs index c1326e92bef..301bbe32405 100644 --- a/naga/src/compact/expressions.rs +++ b/naga/src/compact/expressions.rs @@ -1,8 +1,7 @@ use super::{HandleMap, HandleSet, ModuleMap}; -use crate::arena::{Arena, Handle, UniqueArena}; +use crate::arena::{Arena, Handle}; pub struct ExpressionTracer<'tracer> { - pub types: &'tracer UniqueArena, pub constants: &'tracer Arena, /// The arena in which we are currently tracing expressions. @@ -21,34 +20,51 @@ pub struct ExpressionTracer<'tracer> { /// the module's constant expression arena. pub expressions_used: &'tracer mut HandleSet, - /// The constant expression arena and its used map, if we haven't - /// switched to tracing constant expressions yet. - pub const_expressions: Option<( - &'tracer Arena, - &'tracer mut HandleSet, - )>, + /// The used set for the module's `const_expressions` arena. + /// + /// If `None`, we are already tracing the constant expressions, + /// and `expressions_used` already refers to their handle set. + pub const_expressions_used: Option<&'tracer mut HandleSet>, } impl<'tracer> ExpressionTracer<'tracer> { - pub fn trace_expression(&mut self, expr: Handle) { + /// Propagate usage through `self.expressions`, starting with `self.expressions_used`. + /// + /// Treat `self.expressions_used` as the initial set of "known + /// live" expressions, and follow through to identify all + /// transitively used expressions. + /// + /// Mark types, constants, and constant expressions used directly + /// by `self.expressions` as used. Items used indirectly are not + /// marked. + /// + /// [fe]: crate::Function::expressions + /// [ce]: crate::Module::const_expressions + pub fn trace_expressions(&mut self) { log::trace!( "entering trace_expression of {}", - if self.const_expressions.is_some() { + if self.const_expressions_used.is_some() { "function expressions" } else { "const expressions" } ); - let mut work_list = vec![expr]; - while let Some(expr) = work_list.pop() { - // If we've already seen this expression, no need to trace further. - if !self.expressions_used.insert(expr) { + + // We don't need recursion or a work list. Because an + // expression may only refer to other expressions that precede + // it in the arena, it suffices to make a single pass over the + // arena from back to front, marking the referents of used + // expressions as used themselves. + for (handle, expr) in self.expressions.iter().rev() { + // If this expression isn't used, it doesn't matter what it uses. + if !self.expressions_used.contains(handle) { continue; } + log::trace!("tracing new expression {:?}", expr); use crate::Expression as Ex; - match self.expressions[expr] { + match *expr { // Expressions that do not contain handles that need to be traced. Ex::Literal(_) | Ex::FunctionArgument(_) @@ -59,24 +75,34 @@ impl<'tracer> ExpressionTracer<'tracer> { Ex::Constant(handle) => { self.constants_used.insert(handle); - let constant = &self.constants[handle]; - self.trace_type(constant.ty); - self.trace_const_expression(constant.init); + // Constants and expressions are mutually recursive, which + // complicates our nice one-pass algorithm. However, since + // constants don't refer to each other, we can get around + // this by looking *through* each constant and marking its + // initializer as used. Since `expr` refers to the constant, + // and the constant refers to the initializer, it must + // precede `expr` in the arena. + let init = self.constants[handle].init; + match self.const_expressions_used { + Some(ref mut used) => used.insert(init), + None => self.expressions_used.insert(init), + } } - Ex::ZeroValue(ty) => self.trace_type(ty), + Ex::ZeroValue(ty) => self.types_used.insert(ty), Ex::Compose { ty, ref components } => { - self.trace_type(ty); - work_list.extend(components); + self.types_used.insert(ty); + self.expressions_used + .insert_iter(components.iter().cloned()); } - Ex::Access { base, index } => work_list.extend([base, index]), - Ex::AccessIndex { base, index: _ } => work_list.push(base), - Ex::Splat { size: _, value } => work_list.push(value), + Ex::Access { base, index } => self.expressions_used.insert_iter([base, index]), + Ex::AccessIndex { base, index: _ } => self.expressions_used.insert(base), + Ex::Splat { size: _, value } => self.expressions_used.insert(value), Ex::Swizzle { size: _, vector, pattern: _, - } => work_list.push(vector), - Ex::Load { pointer } => work_list.push(pointer), + } => self.expressions_used.insert(vector), + Ex::Load { pointer } => self.expressions_used.insert(pointer), Ex::ImageSample { image, sampler, @@ -87,20 +113,20 @@ impl<'tracer> ExpressionTracer<'tracer> { ref level, depth_ref, } => { - work_list.push(image); - work_list.push(sampler); - work_list.push(coordinate); - work_list.extend(array_index); - if let Some(offset) = offset { - self.trace_const_expression(offset); + self.expressions_used + .insert_iter([image, sampler, coordinate]); + self.expressions_used.insert_iter(array_index); + match self.const_expressions_used { + Some(ref mut used) => used.insert_iter(offset), + None => self.expressions_used.insert_iter(offset), } use crate::SampleLevel as Sl; match *level { Sl::Auto | Sl::Zero => {} - Sl::Exact(expr) | Sl::Bias(expr) => work_list.push(expr), - Sl::Gradient { x, y } => work_list.extend([x, y]), + Sl::Exact(expr) | Sl::Bias(expr) => self.expressions_used.insert(expr), + Sl::Gradient { x, y } => self.expressions_used.insert_iter([x, y]), } - work_list.extend(depth_ref); + self.expressions_used.insert_iter(depth_ref); } Ex::ImageLoad { image, @@ -109,33 +135,37 @@ impl<'tracer> ExpressionTracer<'tracer> { sample, level, } => { - work_list.push(image); - work_list.push(coordinate); - work_list.extend(array_index); - work_list.extend(sample); - work_list.extend(level); + self.expressions_used.insert(image); + self.expressions_used.insert(coordinate); + self.expressions_used.insert_iter(array_index); + self.expressions_used.insert_iter(sample); + self.expressions_used.insert_iter(level); } Ex::ImageQuery { image, ref query } => { - work_list.push(image); + self.expressions_used.insert(image); use crate::ImageQuery as Iq; match *query { - Iq::Size { level } => work_list.extend(level), + Iq::Size { level } => self.expressions_used.insert_iter(level), Iq::NumLevels | Iq::NumLayers | Iq::NumSamples => {} } } - Ex::Unary { op: _, expr } => work_list.push(expr), - Ex::Binary { op: _, left, right } => work_list.extend([left, right]), + Ex::Unary { op: _, expr } => self.expressions_used.insert(expr), + Ex::Binary { op: _, left, right } => { + self.expressions_used.insert_iter([left, right]); + } Ex::Select { condition, accept, reject, - } => work_list.extend([condition, accept, reject]), + } => self + .expressions_used + .insert_iter([condition, accept, reject]), Ex::Derivative { axis: _, ctrl: _, expr, - } => work_list.push(expr), - Ex::Relational { fun: _, argument } => work_list.push(argument), + } => self.expressions_used.insert(expr), + Ex::Relational { fun: _, argument } => self.expressions_used.insert(argument), Ex::Math { fun: _, arg, @@ -143,61 +173,26 @@ impl<'tracer> ExpressionTracer<'tracer> { arg2, arg3, } => { - work_list.push(arg); - work_list.extend(arg1); - work_list.extend(arg2); - work_list.extend(arg3); + self.expressions_used.insert(arg); + self.expressions_used.insert_iter(arg1); + self.expressions_used.insert_iter(arg2); + self.expressions_used.insert_iter(arg3); } Ex::As { expr, kind: _, convert: _, - } => work_list.push(expr), - Ex::AtomicResult { ty, comparison: _ } => self.trace_type(ty), - Ex::WorkGroupUniformLoadResult { ty } => self.trace_type(ty), - Ex::ArrayLength(expr) => work_list.push(expr), + } => self.expressions_used.insert(expr), + Ex::AtomicResult { ty, comparison: _ } => self.types_used.insert(ty), + Ex::WorkGroupUniformLoadResult { ty } => self.types_used.insert(ty), + Ex::ArrayLength(expr) => self.expressions_used.insert(expr), Ex::RayQueryGetIntersection { query, committed: _, - } => work_list.push(query), + } => self.expressions_used.insert(query), } } } - - fn trace_type(&mut self, ty: Handle) { - let mut types_used = super::types::TypeTracer { - types: self.types, - types_used: self.types_used, - }; - types_used.trace_type(ty); - } - - pub fn as_const_expression(&mut self) -> ExpressionTracer { - match self.const_expressions { - Some((ref mut exprs, ref mut exprs_used)) => ExpressionTracer { - expressions: exprs, - expressions_used: exprs_used, - types: self.types, - constants: self.constants, - types_used: self.types_used, - constants_used: self.constants_used, - const_expressions: None, - }, - None => ExpressionTracer { - types: self.types, - constants: self.constants, - expressions: self.expressions, - types_used: self.types_used, - constants_used: self.constants_used, - expressions_used: self.expressions_used, - const_expressions: None, - }, - } - } - - fn trace_const_expression(&mut self, const_expr: Handle) { - self.as_const_expression().trace_expression(const_expr); - } } impl ModuleMap { diff --git a/naga/src/compact/functions.rs b/naga/src/compact/functions.rs index 752c3eb7f18..b0d08c7e96e 100644 --- a/naga/src/compact/functions.rs +++ b/naga/src/compact/functions.rs @@ -1,10 +1,9 @@ use super::handle_set_map::HandleSet; use super::{FunctionMap, ModuleMap}; -use crate::arena::Handle; pub struct FunctionTracer<'a> { - pub module: &'a crate::Module, pub function: &'a crate::Function, + pub constants: &'a crate::Arena, pub types_used: &'a mut HandleSet, pub constants_used: &'a mut HandleSet, @@ -17,57 +16,43 @@ pub struct FunctionTracer<'a> { impl<'a> FunctionTracer<'a> { pub fn trace(&mut self) { for argument in self.function.arguments.iter() { - self.trace_type(argument.ty); + self.types_used.insert(argument.ty); } if let Some(ref result) = self.function.result { - self.trace_type(result.ty); + self.types_used.insert(result.ty); } for (_, local) in self.function.local_variables.iter() { - self.trace_type(local.ty); + self.types_used.insert(local.ty); if let Some(init) = local.init { - self.trace_expression(init); + self.expressions_used.insert(init); } } // Treat named expressions as alive, for the sake of our test suite, // which uses `let blah = expr;` to exercise lots of things. - for (value, _name) in &self.function.named_expressions { - self.trace_expression(*value); + for (&value, _name) in &self.function.named_expressions { + self.expressions_used.insert(value); } self.trace_block(&self.function.body); - } - - pub fn trace_type(&mut self, ty: Handle) { - self.as_type().trace_type(ty) - } - pub fn trace_expression(&mut self, expr: Handle) { - self.as_expression().trace_expression(expr); - } - - fn as_type(&mut self) -> super::types::TypeTracer { - super::types::TypeTracer { - types: &self.module.types, - types_used: self.types_used, - } + // Given that `trace_block` has marked the expressions used + // directly by statements, walk the arena to find all + // expressions used, directly or indirectly. + self.as_expression().trace_expressions(); } fn as_expression(&mut self) -> super::expressions::ExpressionTracer { super::expressions::ExpressionTracer { - types: &self.module.types, - constants: &self.module.constants, + constants: self.constants, expressions: &self.function.expressions, types_used: self.types_used, constants_used: self.constants_used, expressions_used: &mut self.expressions_used, - const_expressions: Some(( - &self.module.const_expressions, - &mut self.const_expressions_used, - )), + const_expressions_used: Some(&mut self.const_expressions_used), } } } diff --git a/naga/src/compact/handle_set_map.rs b/naga/src/compact/handle_set_map.rs index bf74d3f0b9d..c716ca82949 100644 --- a/naga/src/compact/handle_set_map.rs +++ b/naga/src/compact/handle_set_map.rs @@ -26,13 +26,23 @@ impl HandleSet { } /// Add `handle` to the set. - /// - /// Return `true` if the handle was not already in the set. In - /// other words, return true if it was newly inserted. - pub fn insert(&mut self, handle: Handle) -> bool { + pub fn insert(&mut self, handle: Handle) { + // Note that, oddly, `Handle::index` does not return a 1-based + // `Index`, but rather a zero-based `usize`. + self.members.insert(handle.index()); + } + + /// Add handles from `iter` to the set. + pub fn insert_iter(&mut self, iter: impl IntoIterator>) { + for handle in iter { + self.insert(handle); + } + } + + pub fn contains(&self, handle: Handle) -> bool { // Note that, oddly, `Handle::index` does not return a 1-based // `Index`, but rather a zero-based `usize`. - self.members.insert(handle.index()) + self.members.contains(handle.index()) } } @@ -148,6 +158,8 @@ impl HandleMap { // Build a zero-based end-exclusive range, given one-based handle indices. compacted = first1.get() - 1..last1.get(); } else { + // The range contains only a single live handle, which + // we identified with the first `find_map` call. compacted = first1.get() - 1..first1.get(); } } else { diff --git a/naga/src/compact/mod.rs b/naga/src/compact/mod.rs index 137f3bbe30c..6f6fe3d9da7 100644 --- a/naga/src/compact/mod.rs +++ b/naga/src/compact/mod.rs @@ -36,9 +36,9 @@ pub fn compact(module: &mut crate::Module) { { for (_, global) in module.global_variables.iter() { log::trace!("tracing global {:?}", global.name); - module_tracer.as_type().trace_type(global.ty); + module_tracer.types_used.insert(global.ty); if let Some(init) = global.init { - module_tracer.as_const_expression().trace_expression(init); + module_tracer.const_expressions_used.insert(init); } } } @@ -50,25 +50,23 @@ pub fn compact(module: &mut crate::Module) { for (handle, constant) in module.constants.iter() { if constant.name.is_some() { module_tracer.constants_used.insert(handle); - module_tracer.as_type().trace_type(constant.ty); - module_tracer - .as_const_expression() - .trace_expression(constant.init); + module_tracer.const_expressions_used.insert(constant.init); } } // We assume that all functions are used. // // Observe which types, constant expressions, constants, and - // expressions each function uses, and produce maps from - // pre-compaction to post-compaction handles. + // expressions each function uses, and produce maps for each + // function from pre-compaction to post-compaction expression + // handles. log::trace!("tracing functions"); let function_maps: Vec = module .functions .iter() .map(|(_, f)| { log::trace!("tracing function {:?}", f.name); - let mut function_tracer = module_tracer.enter_function(f); + let mut function_tracer = module_tracer.as_function(f); function_tracer.trace(); FunctionMap::from(function_tracer) }) @@ -81,12 +79,30 @@ pub fn compact(module: &mut crate::Module) { .iter() .map(|e| { log::trace!("tracing entry point {:?}", e.function.name); - let mut used = module_tracer.enter_function(&e.function); + let mut used = module_tracer.as_function(&e.function); used.trace(); FunctionMap::from(used) }) .collect(); + // Given that the above steps have marked all the constant + // expressions used directly by globals, constants, functions, and + // entry points, walk the constant expression arena to find all + // constant expressions used, directly or indirectly. + module_tracer.as_const_expression().trace_expressions(); + + // Constants' initializers are taken care of already, because + // expression tracing sees through constants. But we still need to + // note type usage. + for (handle, constant) in module.constants.iter() { + if module_tracer.constants_used.contains(handle) { + module_tracer.types_used.insert(constant.ty); + } + } + + // Propagate usage through types. + module_tracer.as_type().trace_types(); + // Now that we know what is used and what is never touched, // produce maps from the `Handle`s that appear in `module` now to // the corresponding `Handle`s that will refer to the same items @@ -189,15 +205,14 @@ impl<'module> ModuleTracer<'module> { ref predeclared_types, } = *special_types; - let mut type_tracer = self.as_type(); if let Some(ray_desc) = *ray_desc { - type_tracer.trace_type(ray_desc); + self.types_used.insert(ray_desc); } if let Some(ray_intersection) = *ray_intersection { - type_tracer.trace_type(ray_intersection); + self.types_used.insert(ray_intersection); } for (_, &handle) in predeclared_types { - type_tracer.trace_type(handle); + self.types_used.insert(handle); } } @@ -210,24 +225,22 @@ impl<'module> ModuleTracer<'module> { fn as_const_expression(&mut self) -> expressions::ExpressionTracer { expressions::ExpressionTracer { - types: &self.module.types, - constants: &self.module.constants, expressions: &self.module.const_expressions, + constants: &self.module.constants, types_used: &mut self.types_used, constants_used: &mut self.constants_used, expressions_used: &mut self.const_expressions_used, - const_expressions: None, + const_expressions_used: None, } } - pub fn enter_function<'tracer>( + pub fn as_function<'tracer>( &'tracer mut self, function: &'tracer crate::Function, ) -> FunctionTracer<'tracer> { FunctionTracer { - module: self.module, function, - + constants: &self.module.constants, types_used: &mut self.types_used, constants_used: &mut self.constants_used, const_expressions_used: &mut self.const_expressions_used, diff --git a/naga/src/compact/statements.rs b/naga/src/compact/statements.rs index e2739bc3cb4..e05fdc13e94 100644 --- a/naga/src/compact/statements.rs +++ b/naga/src/compact/statements.rs @@ -22,7 +22,7 @@ impl FunctionTracer<'_> { ref accept, ref reject, } => { - self.trace_expression(condition); + self.expressions_used.insert(condition); worklist.push(accept); worklist.push(reject); } @@ -30,7 +30,7 @@ impl FunctionTracer<'_> { selector, ref cases, } => { - self.trace_expression(selector); + self.expressions_used.insert(selector); for case in cases { worklist.push(&case.body); } @@ -41,15 +41,17 @@ impl FunctionTracer<'_> { break_if, } => { if let Some(break_if) = break_if { - self.trace_expression(break_if); + self.expressions_used.insert(break_if); } worklist.push(body); worklist.push(continuing); } - St::Return { value: Some(value) } => self.trace_expression(value), + St::Return { value: Some(value) } => { + self.expressions_used.insert(value); + } St::Store { pointer, value } => { - self.trace_expression(pointer); - self.trace_expression(value); + self.expressions_used.insert(pointer); + self.expressions_used.insert(value); } St::ImageStore { image, @@ -57,12 +59,12 @@ impl FunctionTracer<'_> { array_index, value, } => { - self.trace_expression(image); - self.trace_expression(coordinate); + self.expressions_used.insert(image); + self.expressions_used.insert(coordinate); if let Some(array_index) = array_index { - self.trace_expression(array_index); + self.expressions_used.insert(array_index); } - self.trace_expression(value); + self.expressions_used.insert(value); } St::Atomic { pointer, @@ -70,14 +72,14 @@ impl FunctionTracer<'_> { value, result, } => { - self.trace_expression(pointer); + self.expressions_used.insert(pointer); self.trace_atomic_function(fun); - self.trace_expression(value); - self.trace_expression(result); + self.expressions_used.insert(value); + self.expressions_used.insert(result); } St::WorkGroupUniformLoad { pointer, result } => { - self.trace_expression(pointer); - self.trace_expression(result); + self.expressions_used.insert(pointer); + self.expressions_used.insert(result); } St::Call { function: _, @@ -85,14 +87,14 @@ impl FunctionTracer<'_> { result, } => { for expr in arguments { - self.trace_expression(*expr); + self.expressions_used.insert(*expr); } if let Some(result) = result { - self.trace_expression(result); + self.expressions_used.insert(result); } } St::RayQuery { query, ref fun } => { - self.trace_expression(query); + self.expressions_used.insert(query); self.trace_ray_query_function(fun); } St::DebugPrintf { @@ -100,7 +102,7 @@ impl FunctionTracer<'_> { ref arguments, } => { for expr in arguments { - self.trace_expression(*expr); + self.expressions_used.insert(*expr); } } @@ -120,7 +122,9 @@ impl FunctionTracer<'_> { match *fun { Af::Exchange { compare: Some(expr), - } => self.trace_expression(expr), + } => { + self.expressions_used.insert(expr); + } Af::Exchange { compare: None } | Af::Add | Af::Subtract @@ -139,10 +143,12 @@ impl FunctionTracer<'_> { acceleration_structure, descriptor, } => { - self.trace_expression(acceleration_structure); - self.trace_expression(descriptor); + self.expressions_used.insert(acceleration_structure); + self.expressions_used.insert(descriptor); + } + Qf::Proceed { result } => { + self.expressions_used.insert(result); } - Qf::Proceed { result } => self.trace_expression(result), Qf::Terminate => {} } } diff --git a/naga/src/compact/types.rs b/naga/src/compact/types.rs index d11ab8a7310..b78619d9a80 100644 --- a/naga/src/compact/types.rs +++ b/naga/src/compact/types.rs @@ -7,16 +7,25 @@ pub struct TypeTracer<'a> { } impl<'a> TypeTracer<'a> { - pub fn trace_type(&mut self, ty: Handle) { - let mut work_list = vec![ty]; - while let Some(ty) = work_list.pop() { - // If we've already seen this type, no need to traverse further. - if !self.types_used.insert(ty) { + /// Propagate usage through `self.types`, starting with `self.types_used`. + /// + /// Treat `self.types_used` as the initial set of "known + /// live" types, and follow through to identify all + /// transitively used types. + pub fn trace_types(&mut self) { + // We don't need recursion or a work list. Because an + // expression may only refer to other expressions that precede + // it in the arena, it suffices to make a single pass over the + // arena from back to front, marking the referents of used + // expressions as used themselves. + for (handle, ty) in self.types.iter().rev() { + // If this type isn't used, it doesn't matter what it uses. + if !self.types_used.contains(handle) { continue; } use crate::TypeInner as Ti; - match self.types[ty].inner { + match ty.inner { // Types that do not contain handles. Ti::Scalar { .. } | Ti::Vector { .. } @@ -29,19 +38,19 @@ impl<'a> TypeTracer<'a> { | Ti::RayQuery => {} // Types that do contain handles. - Ti::Pointer { base, space: _ } => work_list.push(base), - Ti::Array { + Ti::Pointer { base, space: _ } + | Ti::Array { base, size: _, stride: _, - } => work_list.push(base), + } + | Ti::BindingArray { base, size: _ } => self.types_used.insert(base), Ti::Struct { ref members, span: _, } => { - work_list.extend(members.iter().map(|m| m.ty)); + self.types_used.insert_iter(members.iter().map(|m| m.ty)); } - Ti::BindingArray { base, size: _ } => work_list.push(base), } } } @@ -54,10 +63,10 @@ impl ModuleMap { use crate::TypeInner as Ti; match ty.inner { // Types that do not contain handles. - Ti::Scalar { .. } + Ti::Scalar(_) | Ti::Vector { .. } | Ti::Matrix { .. } - | Ti::Atomic { .. } + | Ti::Atomic(_) | Ti::ValuePointer { .. } | Ti::Image { .. } | Ti::Sampler { .. } diff --git a/naga/src/front/glsl/builtins.rs b/naga/src/front/glsl/builtins.rs index c68370645cd..afe404a7eb9 100644 --- a/naga/src/front/glsl/builtins.rs +++ b/naga/src/front/glsl/builtins.rs @@ -9,7 +9,7 @@ use super::{ use crate::{ BinaryOperator, DerivativeAxis as Axis, DerivativeControl as Ctrl, Expression, Handle, ImageClass, ImageDimension as Dim, ImageQuery, MathFunction, Module, RelationalFunction, - SampleLevel, ScalarKind as Sk, Span, Type, TypeInner, UnaryOperator, VectorSize, + SampleLevel, Scalar, ScalarKind as Sk, Span, Type, TypeInner, UnaryOperator, VectorSize, }; impl crate::ScalarKind { @@ -54,18 +54,17 @@ impl Module { } const fn make_coords_arg(number_of_components: usize, kind: Sk) -> TypeInner { - let width = 4; + let scalar = Scalar { kind, width: 4 }; match number_of_components { - 1 => TypeInner::Scalar { kind, width }, + 1 => TypeInner::Scalar(scalar), _ => TypeInner::Vector { size: match number_of_components { 2 => VectorSize::Bi, 3 => VectorSize::Tri, _ => VectorSize::Quad, }, - kind, - width, + scalar, }, } } @@ -98,7 +97,6 @@ pub fn inject_builtin( inject_double_builtin(declaration, module, name) } - let width = 4; match name { "texture" | "textureGrad" @@ -235,18 +233,12 @@ pub fn inject_builtin( let mut args = vec![image, vector]; if num_coords == 5 { - args.push(TypeInner::Scalar { - kind: Sk::Float, - width, - }); + args.push(TypeInner::Scalar(Scalar::F32)); } match level_type { TextureLevelType::Lod => { - args.push(TypeInner::Scalar { - kind: Sk::Float, - width, - }); + args.push(TypeInner::Scalar(Scalar::F32)); } TextureLevelType::Grad => { args.push(make_coords_arg(num_coords_from_dim, Sk::Float)); @@ -260,10 +252,7 @@ pub fn inject_builtin( } if bias { - args.push(TypeInner::Scalar { - kind: Sk::Float, - width, - }); + args.push(TypeInner::Scalar(Scalar::F32)); } declaration @@ -290,10 +279,7 @@ pub fn inject_builtin( let mut args = vec![image]; if !multi { - args.push(TypeInner::Scalar { - kind: Sk::Sint, - width, - }) + args.push(TypeInner::Scalar(Scalar::I32)) } declaration @@ -323,14 +309,7 @@ pub fn inject_builtin( let dim_value = image_dims_to_coords_size(dim); let coordinates = make_coords_arg(dim_value + arrayed as usize, Sk::Sint); - let mut args = vec![ - image, - coordinates, - TypeInner::Scalar { - kind: Sk::Sint, - width, - }, - ]; + let mut args = vec![image, coordinates, TypeInner::Scalar(Scalar::I32)]; if offset { args.push(make_coords_arg(dim_value, Sk::Sint)); @@ -441,8 +420,7 @@ pub fn inject_builtin( coordinates, TypeInner::Vector { size: VectorSize::Quad, - kind, - width, + scalar: Scalar { kind, width: 4 }, }, ]; @@ -464,7 +442,6 @@ fn inject_standard_builtins( module: &mut Module, name: &str, ) { - let width = 4; match name { "sampler1D" | "sampler1DArray" | "sampler2D" | "sampler2DArray" | "sampler2DMS" | "sampler2DMSArray" | "sampler3D" | "samplerCube" | "samplerCubeArray" => { @@ -544,12 +521,12 @@ fn inject_standard_builtins( 0b10 => Some(VectorSize::Tri), _ => Some(VectorSize::Quad), }; - let kind = Sk::Float; + let scalar = Scalar::F32; declaration.overloads.push(module.add_builtin( vec![match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }], match name { "sin" => MacroCall::MathFunction(MathFunction::Sin), @@ -595,15 +572,15 @@ fn inject_standard_builtins( 0b10 => Some(VectorSize::Tri), _ => Some(VectorSize::Quad), }; - let kind = match name { - "intBitsToFloat" => Sk::Sint, - _ => Sk::Uint, + let scalar = match name { + "intBitsToFloat" => Scalar::I32, + _ => Scalar::U32, }; declaration.overloads.push(module.add_builtin( vec![match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }], MacroCall::BitCast(Sk::Float), )) @@ -619,10 +596,10 @@ fn inject_standard_builtins( 0b10 => Some(VectorSize::Tri), _ => Some(VectorSize::Quad), }; - let kind = Sk::Float; + let scalar = Scalar::F32; let ty = || match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }; declaration.overloads.push( @@ -642,14 +619,14 @@ fn inject_standard_builtins( 0b10 => Some(VectorSize::Tri), _ => Some(VectorSize::Quad), }; - let kind = match bits >> 2 { - 0b0 => Sk::Float, - _ => Sk::Sint, + let scalar = match bits >> 2 { + 0b0 => Scalar::F32, + _ => Scalar::I32, }; let args = vec![match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }]; declaration.overloads.push(module.add_builtin( @@ -684,9 +661,9 @@ fn inject_standard_builtins( // bit 0 - int/uint // bit 1 through 2 - dims for bits in 0..0b1000 { - let kind = match bits & 0b1 { - 0b0 => Sk::Sint, - _ => Sk::Uint, + let scalar = match bits & 0b1 { + 0b0 => Scalar::I32, + _ => Scalar::U32, }; let size = match bits >> 1 { 0b00 => None, @@ -696,39 +673,27 @@ fn inject_standard_builtins( }; let ty = || match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }; let mut args = vec![ty()]; match fun { MathFunction::ExtractBits => { - args.push(TypeInner::Scalar { - kind: Sk::Sint, - width: 4, - }); - args.push(TypeInner::Scalar { - kind: Sk::Sint, - width: 4, - }); + args.push(TypeInner::Scalar(Scalar::I32)); + args.push(TypeInner::Scalar(Scalar::I32)); } MathFunction::InsertBits => { args.push(ty()); - args.push(TypeInner::Scalar { - kind: Sk::Sint, - width: 4, - }); - args.push(TypeInner::Scalar { - kind: Sk::Sint, - width: 4, - }); + args.push(TypeInner::Scalar(Scalar::I32)); + args.push(TypeInner::Scalar(Scalar::I32)); } _ => {} } // we need to cast the return type of findLsb / findMsb - let mc = if kind == Sk::Uint { + let mc = if scalar.kind == Sk::Uint { match mc { MacroCall::MathFunction(MathFunction::FindLsb) => MacroCall::FindLsbUint, MacroCall::MathFunction(MathFunction::FindMsb) => MacroCall::FindMsbUint, @@ -754,15 +719,13 @@ fn inject_standard_builtins( let ty = match fun { MathFunction::Pack4x8snorm | MathFunction::Pack4x8unorm => TypeInner::Vector { size: crate::VectorSize::Quad, - kind: Sk::Float, - width: 4, + scalar: Scalar::F32, }, MathFunction::Pack2x16unorm | MathFunction::Pack2x16snorm | MathFunction::Pack2x16float => TypeInner::Vector { size: crate::VectorSize::Bi, - kind: Sk::Float, - width: 4, + scalar: Scalar::F32, }, _ => unreachable!(), }; @@ -784,10 +747,7 @@ fn inject_standard_builtins( _ => unreachable!(), }; - let args = vec![TypeInner::Scalar { - kind: Sk::Uint, - width: 4, - }]; + let args = vec![TypeInner::Scalar(Scalar::U32)]; declaration .overloads @@ -808,10 +768,10 @@ fn inject_standard_builtins( 0b10 => Some(VectorSize::Tri), _ => Some(VectorSize::Quad), }; - let kind = Sk::Float; + let scalar = Scalar::F32; let ty = || match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }; let mut args = vec![ty()]; @@ -837,8 +797,7 @@ fn inject_standard_builtins( let args = vec![TypeInner::Vector { size, - kind: Sk::Bool, - width: crate::BOOL_WIDTH, + scalar: Scalar::BOOL, }]; let fun = match name { @@ -853,19 +812,19 @@ fn inject_standard_builtins( } "lessThan" | "greaterThan" | "lessThanEqual" | "greaterThanEqual" => { for bits in 0..0b1001 { - let (size, kind) = match bits { - 0b0000 => (VectorSize::Bi, Sk::Float), - 0b0001 => (VectorSize::Tri, Sk::Float), - 0b0010 => (VectorSize::Quad, Sk::Float), - 0b0011 => (VectorSize::Bi, Sk::Sint), - 0b0100 => (VectorSize::Tri, Sk::Sint), - 0b0101 => (VectorSize::Quad, Sk::Sint), - 0b0110 => (VectorSize::Bi, Sk::Uint), - 0b0111 => (VectorSize::Tri, Sk::Uint), - _ => (VectorSize::Quad, Sk::Uint), - }; - - let ty = || TypeInner::Vector { size, kind, width }; + let (size, scalar) = match bits { + 0b0000 => (VectorSize::Bi, Scalar::F32), + 0b0001 => (VectorSize::Tri, Scalar::F32), + 0b0010 => (VectorSize::Quad, Scalar::F32), + 0b0011 => (VectorSize::Bi, Scalar::I32), + 0b0100 => (VectorSize::Tri, Scalar::I32), + 0b0101 => (VectorSize::Quad, Scalar::I32), + 0b0110 => (VectorSize::Bi, Scalar::U32), + 0b0111 => (VectorSize::Tri, Scalar::U32), + _ => (VectorSize::Quad, Scalar::U32), + }; + + let ty = || TypeInner::Vector { size, scalar }; let args = vec![ty(), ty()]; let fun = MacroCall::Binary(match name { @@ -881,28 +840,22 @@ fn inject_standard_builtins( } "equal" | "notEqual" => { for bits in 0..0b1100 { - let (size, kind) = match bits { - 0b0000 => (VectorSize::Bi, Sk::Float), - 0b0001 => (VectorSize::Tri, Sk::Float), - 0b0010 => (VectorSize::Quad, Sk::Float), - 0b0011 => (VectorSize::Bi, Sk::Sint), - 0b0100 => (VectorSize::Tri, Sk::Sint), - 0b0101 => (VectorSize::Quad, Sk::Sint), - 0b0110 => (VectorSize::Bi, Sk::Uint), - 0b0111 => (VectorSize::Tri, Sk::Uint), - 0b1000 => (VectorSize::Quad, Sk::Uint), - 0b1001 => (VectorSize::Bi, Sk::Bool), - 0b1010 => (VectorSize::Tri, Sk::Bool), - _ => (VectorSize::Quad, Sk::Bool), - }; - - let width = if let Sk::Bool = kind { - crate::BOOL_WIDTH - } else { - width - }; - - let ty = || TypeInner::Vector { size, kind, width }; + let (size, scalar) = match bits { + 0b0000 => (VectorSize::Bi, Scalar::F32), + 0b0001 => (VectorSize::Tri, Scalar::F32), + 0b0010 => (VectorSize::Quad, Scalar::F32), + 0b0011 => (VectorSize::Bi, Scalar::I32), + 0b0100 => (VectorSize::Tri, Scalar::I32), + 0b0101 => (VectorSize::Quad, Scalar::I32), + 0b0110 => (VectorSize::Bi, Scalar::U32), + 0b0111 => (VectorSize::Tri, Scalar::U32), + 0b1000 => (VectorSize::Quad, Scalar::U32), + 0b1001 => (VectorSize::Bi, Scalar::BOOL), + 0b1010 => (VectorSize::Tri, Scalar::BOOL), + _ => (VectorSize::Quad, Scalar::BOOL), + }; + + let ty = || TypeInner::Vector { size, scalar }; let args = vec![ty(), ty()]; let fun = MacroCall::Binary(match name { @@ -919,10 +872,10 @@ fn inject_standard_builtins( // bit 0 through 1 - scalar kind // bit 2 through 4 - dims for bits in 0..0b11100 { - let kind = match bits & 0b11 { - 0b00 => Sk::Float, - 0b01 => Sk::Sint, - 0b10 => Sk::Uint, + let scalar = match bits & 0b11 { + 0b00 => Scalar::F32, + 0b01 => Scalar::I32, + 0b10 => Scalar::U32, _ => continue, }; let (size, second_size) = match bits >> 2 { @@ -937,12 +890,12 @@ fn inject_standard_builtins( let args = vec![ match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }, match second_size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }, ]; @@ -969,25 +922,25 @@ fn inject_standard_builtins( 0b10 => Some(VectorSize::Quad), _ => None, }; - let (kind, splatted, boolean) = match bits >> 2 { - 0b000 => (Sk::Sint, false, true), - 0b001 => (Sk::Uint, false, true), - 0b010 => (Sk::Float, false, true), - 0b011 => (Sk::Float, false, false), - _ => (Sk::Float, true, false), + let (scalar, splatted, boolean) = match bits >> 2 { + 0b000 => (Scalar::I32, false, true), + 0b001 => (Scalar::U32, false, true), + 0b010 => (Scalar::F32, false, true), + 0b011 => (Scalar::F32, false, false), + _ => (Scalar::F32, true, false), }; - let ty = |kind, width| match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + let ty = |scalar| match size { + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }; let args = vec![ - ty(kind, width), - ty(kind, width), + ty(scalar), + ty(scalar), match (boolean, splatted) { - (true, _) => ty(Sk::Bool, crate::BOOL_WIDTH), - (_, false) => TypeInner::Scalar { kind, width }, - _ => ty(kind, width), + (true, _) => ty(Scalar::BOOL), + (_, false) => TypeInner::Scalar(scalar), + _ => ty(scalar), }, ]; @@ -1009,10 +962,10 @@ fn inject_standard_builtins( // 0b11010 is the last element since splatted single elements // were already added for bits in 0..0b11011 { - let kind = match bits & 0b11 { - 0b00 => Sk::Float, - 0b01 => Sk::Sint, - 0b10 => Sk::Uint, + let scalar = match bits & 0b11 { + 0b00 => Scalar::F32, + 0b01 => Scalar::I32, + 0b10 => Scalar::U32, _ => continue, }; let size = match (bits >> 2) & 0b11 { @@ -1024,11 +977,11 @@ fn inject_standard_builtins( let splatted = bits & 0b10000 == 0b10000; let base_ty = || match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }; let limit_ty = || match splatted { - true => TypeInner::Scalar { kind, width }, + true => TypeInner::Scalar(scalar), false => base_ty(), }; @@ -1049,7 +1002,6 @@ fn inject_standard_builtins( /// Injects the builtins into declaration that need doubles fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Module, name: &str) { - let width = 8; match name { "abs" | "sign" => { // bits layout @@ -1061,11 +1013,11 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod 0b10 => Some(VectorSize::Tri), _ => Some(VectorSize::Quad), }; - let kind = Sk::Float; + let scalar = Scalar::F64; let args = vec![match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }]; declaration.overloads.push(module.add_builtin( @@ -1091,16 +1043,16 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod 0b101 => (Some(VectorSize::Tri), Some(VectorSize::Tri)), _ => (Some(VectorSize::Quad), Some(VectorSize::Quad)), }; - let kind = Sk::Float; + let scalar = Scalar::F64; let args = vec![ match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }, match second_size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }, ]; @@ -1127,24 +1079,24 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod 0b10 => Some(VectorSize::Tri), _ => None, }; - let kind = Sk::Float; + let scalar = Scalar::F64; let (splatted, boolean) = match bits >> 2 { 0b00 => (false, false), 0b01 => (false, true), _ => (true, false), }; - let ty = |kind, width| match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + let ty = |scalar| match size { + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }; let args = vec![ - ty(kind, width), - ty(kind, width), + ty(scalar), + ty(scalar), match (boolean, splatted) { - (true, _) => ty(Sk::Bool, crate::BOOL_WIDTH), - (_, false) => TypeInner::Scalar { kind, width }, - _ => ty(kind, width), + (true, _) => ty(Scalar::BOOL), + (_, false) => TypeInner::Scalar(scalar), + _ => ty(scalar), }, ]; @@ -1165,7 +1117,7 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod // 0b110 is the last element since splatted with single elements // is equal to normal single elements for bits in 0..0b111 { - let kind = Sk::Float; + let scalar = Scalar::F64; let size = match bits & 0b11 { 0b00 => Some(VectorSize::Bi), 0b01 => Some(VectorSize::Tri), @@ -1175,11 +1127,11 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod let splatted = bits & 0b100 == 0b100; let base_ty = || match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }; let limit_ty = || match splatted { - true => TypeInner::Scalar { kind, width }, + true => TypeInner::Scalar(scalar), false => base_ty(), }; @@ -1192,14 +1144,15 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod } "lessThan" | "greaterThan" | "lessThanEqual" | "greaterThanEqual" | "equal" | "notEqual" => { + let scalar = Scalar::F64; for bits in 0..0b11 { - let (size, kind) = match bits { - 0b00 => (VectorSize::Bi, Sk::Float), - 0b01 => (VectorSize::Tri, Sk::Float), - _ => (VectorSize::Quad, Sk::Float), + let size = match bits { + 0b00 => VectorSize::Bi, + 0b01 => VectorSize::Tri, + _ => VectorSize::Quad, }; - let ty = || TypeInner::Vector { size, kind, width }; + let ty = || TypeInner::Vector { size, scalar }; let args = vec![ty(), ty()]; let fun = MacroCall::Binary(match name { @@ -1227,6 +1180,10 @@ fn inject_common_builtin( name: &str, float_width: crate::Bytes, ) { + let float_scalar = Scalar { + kind: Sk::Float, + width: float_width, + }; match name { "ceil" | "round" | "roundEven" | "floor" | "fract" | "trunc" | "sqrt" | "inversesqrt" | "normalize" | "length" | "isinf" | "isnan" => { @@ -1243,13 +1200,9 @@ fn inject_common_builtin( let args = vec![match size { Some(size) => TypeInner::Vector { size, - kind: Sk::Float, - width: float_width, - }, - None => TypeInner::Scalar { - kind: Sk::Float, - width: float_width, + scalar: float_scalar, }, + None => TypeInner::Scalar(float_scalar), }]; let fun = match name { @@ -1280,16 +1233,9 @@ fn inject_common_builtin( 0b10 => Some(VectorSize::Tri), _ => Some(VectorSize::Quad), }; - let ty = |kind| match size { - Some(size) => TypeInner::Vector { - size, - kind, - width: float_width, - }, - None => TypeInner::Scalar { - kind, - width: float_width, - }, + let ty = |scalar| match size { + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }; let fun = match name { @@ -1300,15 +1246,14 @@ fn inject_common_builtin( _ => unreachable!(), }; - let second_kind = if fun == MacroCall::MathFunction(MathFunction::Ldexp) { - Sk::Sint - } else { - Sk::Float + let second_scalar = match fun { + MacroCall::MathFunction(MathFunction::Ldexp) => Scalar::I32, + _ => float_scalar, }; declaration .overloads - .push(module.add_builtin(vec![ty(Sk::Float), ty(second_kind)], fun)) + .push(module.add_builtin(vec![ty(float_scalar), ty(second_scalar)], fun)) } } "transpose" => { @@ -1389,13 +1334,9 @@ fn inject_common_builtin( args.push(match maybe_size { Some(size) => TypeInner::Vector { size, - kind: Sk::Float, - width: float_width, - }, - None => TypeInner::Scalar { - kind: Sk::Float, - width: float_width, + scalar: float_scalar, }, + None => TypeInner::Scalar(float_scalar), }) } @@ -1414,13 +1355,11 @@ fn inject_common_builtin( let args = vec![ TypeInner::Vector { size: VectorSize::Tri, - kind: Sk::Float, - width: float_width, + scalar: float_scalar, }, TypeInner::Vector { size: VectorSize::Tri, - kind: Sk::Float, - width: float_width, + scalar: float_scalar, }, ]; @@ -1447,13 +1386,11 @@ fn inject_common_builtin( let args = vec![ TypeInner::Vector { size: size1, - kind: Sk::Float, - width: float_width, + scalar: float_scalar, }, TypeInner::Vector { size: size2, - kind: Sk::Float, - width: float_width, + scalar: float_scalar, }, ]; @@ -1476,13 +1413,9 @@ fn inject_common_builtin( let ty = || match size { Some(size) => TypeInner::Vector { size, - kind: Sk::Float, - width: float_width, - }, - None => TypeInner::Scalar { - kind: Sk::Float, - width: float_width, + scalar: float_scalar, }, + None => TypeInner::Scalar(float_scalar), }; let args = vec![ty(), ty(), ty()]; @@ -1509,22 +1442,11 @@ fn inject_common_builtin( let ty = || match size { Some(size) => TypeInner::Vector { size, - kind: Sk::Float, - width: float_width, - }, - None => TypeInner::Scalar { - kind: Sk::Float, - width: float_width, + scalar: float_scalar, }, + None => TypeInner::Scalar(float_scalar), }; - let args = vec![ - ty(), - ty(), - TypeInner::Scalar { - kind: Sk::Float, - width: 4, - }, - ]; + let args = vec![ty(), ty(), TypeInner::Scalar(Scalar::F32)]; declaration .overloads .push(module.add_builtin(args, MacroCall::MathFunction(MathFunction::Refract))) @@ -1549,19 +1471,12 @@ fn inject_common_builtin( let base_ty = || match size { Some(size) => TypeInner::Vector { size, - kind: Sk::Float, - width: float_width, - }, - None => TypeInner::Scalar { - kind: Sk::Float, - width: float_width, + scalar: float_scalar, }, + None => TypeInner::Scalar(float_scalar), }; let ty = || match splatted { - true => TypeInner::Scalar { - kind: Sk::Float, - width: float_width, - }, + true => TypeInner::Scalar(float_scalar), false => base_ty(), }; declaration.overloads.push(module.add_builtin( @@ -1810,8 +1725,7 @@ impl MacroCall { name: None, inner: TypeInner::Vector { size, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: Scalar::U32, }, }, Span::default(), @@ -2100,7 +2014,7 @@ fn texture_call( let mut array_index = comps.array_index; if let Some(ref mut array_index_expr) = array_index { - ctx.conversion(array_index_expr, meta, Sk::Sint, 4)?; + ctx.conversion(array_index_expr, meta, Scalar::I32)?; } Ok(ctx.add_expression( diff --git a/naga/src/front/glsl/context.rs b/naga/src/front/glsl/context.rs index a54e718aa9c..b683ec00862 100644 --- a/naga/src/front/glsl/context.rs +++ b/naga/src/front/glsl/context.rs @@ -9,8 +9,8 @@ use super::{ }; use crate::{ front::Typifier, proc::Emitter, AddressSpace, Arena, BinaryOperator, Block, Expression, - FastHashMap, FunctionArgument, Handle, Literal, LocalVariable, RelationalFunction, ScalarKind, - Span, Statement, Type, TypeInner, VectorSize, + FastHashMap, FunctionArgument, Handle, Literal, LocalVariable, RelationalFunction, Scalar, + ScalarKind, Span, Statement, Type, TypeInner, VectorSize, }; use std::ops::Index; @@ -602,7 +602,7 @@ impl<'a> Context<'a> { match op { BinaryOperator::ShiftLeft | BinaryOperator::ShiftRight => { - self.implicit_conversion(&mut right, right_meta, ScalarKind::Uint, 4)? + self.implicit_conversion(&mut right, right_meta, Scalar::U32)? } _ => self .binary_implicit_conversion(&mut left, left_meta, &mut right, right_meta)?, @@ -824,9 +824,9 @@ impl<'a> Context<'a> { _ => self.add_expression(Expression::Binary { left, op, right }, meta)?, }, ( - &TypeInner::Scalar { + &TypeInner::Scalar(Scalar { width: left_width, .. - }, + }), &TypeInner::Matrix { rows, columns, @@ -911,9 +911,9 @@ impl<'a> Context<'a> { columns, width: left_width, }, - &TypeInner::Scalar { + &TypeInner::Scalar(Scalar { width: right_width, .. - }, + }), ) => { // Check that the two arguments have the same width if left_width != right_width { @@ -1100,37 +1100,24 @@ impl<'a> Context<'a> { // We need to do some custom implicit conversions since the two target expressions // are in different bodies - if let ( - Some((accept_power, accept_width, accept_kind)), - Some((reject_power, reject_width, reject_kind)), - ) = ( + if let (Some((accept_power, accept_scalar)), Some((reject_power, reject_scalar))) = ( // Get the components of both branches and calculate the type power self.expr_scalar_components(accept, accept_meta)? - .and_then(|(kind, width)| Some((type_power(kind, width)?, width, kind))), + .and_then(|scalar| Some((type_power(scalar)?, scalar))), self.expr_scalar_components(reject, reject_meta)? - .and_then(|(kind, width)| Some((type_power(kind, width)?, width, kind))), + .and_then(|scalar| Some((type_power(scalar)?, scalar))), ) { match accept_power.cmp(&reject_power) { std::cmp::Ordering::Less => { accept_body = self.with_body(accept_body, |ctx| { - ctx.conversion( - &mut accept, - accept_meta, - reject_kind, - reject_width, - )?; + ctx.conversion(&mut accept, accept_meta, reject_scalar)?; Ok(()) })?; } std::cmp::Ordering::Equal => {} std::cmp::Ordering::Greater => { reject_body = self.with_body(reject_body, |ctx| { - ctx.conversion( - &mut reject, - reject_meta, - accept_kind, - accept_width, - )?; + ctx.conversion(&mut reject, reject_meta, accept_scalar)?; Ok(()) })?; } @@ -1201,8 +1188,8 @@ impl<'a> Context<'a> { ref ty => ty, }; - if let Some((kind, width)) = scalar_components(ty) { - self.implicit_conversion(&mut value, value_meta, kind, width)?; + if let Some(scalar) = scalar_components(ty) { + self.implicit_conversion(&mut value, value_meta, scalar)?; } self.lower_store(pointer, value, meta)?; @@ -1218,13 +1205,13 @@ impl<'a> Context<'a> { }; let res = match *self.resolve_type(left, meta)? { - TypeInner::Scalar { kind, width } => { - let ty = TypeInner::Scalar { kind, width }; - Literal::one(kind, width).map(|i| (ty, i, None, None)) + TypeInner::Scalar(scalar) => { + let ty = TypeInner::Scalar(scalar); + Literal::one(scalar).map(|i| (ty, i, None, None)) } - TypeInner::Vector { size, kind, width } => { - let ty = TypeInner::Vector { size, kind, width }; - Literal::one(kind, width).map(|i| (ty, i, Some(size), None)) + TypeInner::Vector { size, scalar } => { + let ty = TypeInner::Vector { size, scalar }; + Literal::one(scalar).map(|i| (ty, i, Some(size), None)) } TypeInner::Matrix { columns, @@ -1236,8 +1223,11 @@ impl<'a> Context<'a> { rows, width, }; - Literal::one(ScalarKind::Float, width) - .map(|i| (ty, i, Some(rows), Some(columns))) + Literal::one(Scalar { + kind: ScalarKind::Float, + width, + }) + .map(|i| (ty, i, Some(rows), Some(columns))) } _ => None, }; @@ -1323,19 +1313,14 @@ impl<'a> Context<'a> { Expression::Literal(Literal::U32(size.get())), meta, )?; - self.forced_conversion( - &mut array_length, - meta, - ScalarKind::Sint, - 4, - )?; + self.forced_conversion(&mut array_length, meta, Scalar::I32)?; array_length } // let the error be handled in type checking if it's not a dynamic array _ => { let mut array_length = self .add_expression(Expression::ArrayLength(lowered_array), meta)?; - self.conversion(&mut array_length, meta, ScalarKind::Sint, 4)?; + self.conversion(&mut array_length, meta, Scalar::I32)?; array_length } } @@ -1376,7 +1361,7 @@ impl<'a> Context<'a> { &mut self, expr: Handle, meta: Span, - ) -> Result> { + ) -> Result> { let ty = self.resolve_type(expr, meta)?; Ok(scalar_components(ty)) } @@ -1384,21 +1369,20 @@ impl<'a> Context<'a> { pub fn expr_power(&mut self, expr: Handle, meta: Span) -> Result> { Ok(self .expr_scalar_components(expr, meta)? - .and_then(|(kind, width)| type_power(kind, width))) + .and_then(type_power)) } pub fn conversion( &mut self, expr: &mut Handle, meta: Span, - kind: ScalarKind, - width: crate::Bytes, + scalar: Scalar, ) -> Result<()> { *expr = self.add_expression( Expression::As { expr: *expr, - kind, - convert: Some(width), + kind: scalar.kind, + convert: Some(scalar.width), }, meta, )?; @@ -1410,14 +1394,13 @@ impl<'a> Context<'a> { &mut self, expr: &mut Handle, meta: Span, - kind: ScalarKind, - width: crate::Bytes, + scalar: Scalar, ) -> Result<()> { if let (Some(tgt_power), Some(expr_power)) = - (type_power(kind, width), self.expr_power(*expr, meta)?) + (type_power(scalar), self.expr_power(*expr, meta)?) { if tgt_power > expr_power { - self.conversion(expr, meta, kind, width)?; + self.conversion(expr, meta, scalar)?; } } @@ -1428,12 +1411,11 @@ impl<'a> Context<'a> { &mut self, expr: &mut Handle, meta: Span, - kind: ScalarKind, - width: crate::Bytes, + scalar: Scalar, ) -> Result<()> { - if let Some((expr_scalar_kind, expr_width)) = self.expr_scalar_components(*expr, meta)? { - if expr_scalar_kind != kind || expr_width != width { - self.conversion(expr, meta, kind, width)?; + if let Some(expr_scalar) = self.expr_scalar_components(*expr, meta)? { + if expr_scalar != scalar { + self.conversion(expr, meta, scalar)?; } } @@ -1450,21 +1432,17 @@ impl<'a> Context<'a> { let left_components = self.expr_scalar_components(*left, left_meta)?; let right_components = self.expr_scalar_components(*right, right_meta)?; - if let ( - Some((left_power, left_width, left_kind)), - Some((right_power, right_width, right_kind)), - ) = ( - left_components.and_then(|(kind, width)| Some((type_power(kind, width)?, width, kind))), - right_components - .and_then(|(kind, width)| Some((type_power(kind, width)?, width, kind))), + if let (Some((left_power, left_scalar)), Some((right_power, right_scalar))) = ( + left_components.and_then(|scalar| Some((type_power(scalar)?, scalar))), + right_components.and_then(|scalar| Some((type_power(scalar)?, scalar))), ) { match left_power.cmp(&right_power) { std::cmp::Ordering::Less => { - self.conversion(left, left_meta, right_kind, right_width)?; + self.conversion(left, left_meta, right_scalar)?; } std::cmp::Ordering::Equal => {} std::cmp::Ordering::Greater => { - self.conversion(right, right_meta, left_kind, left_width)?; + self.conversion(right, right_meta, left_scalar)?; } } } diff --git a/naga/src/front/glsl/functions.rs b/naga/src/front/glsl/functions.rs index 8bbef9162d8..b7e184afd7f 100644 --- a/naga/src/front/glsl/functions.rs +++ b/naga/src/front/glsl/functions.rs @@ -8,7 +8,7 @@ use super::{ }; use crate::{ front::glsl::types::type_power, proc::ensure_block_returns, AddressSpace, Block, EntryPoint, - Expression, Function, FunctionArgument, FunctionResult, Handle, Literal, LocalVariable, + Expression, Function, FunctionArgument, FunctionResult, Handle, Literal, LocalVariable, Scalar, ScalarKind, Span, Statement, StructMember, Type, TypeInner, }; use std::iter; @@ -20,7 +20,7 @@ struct ProxyWrite { /// A pointer to read the value of the store value: Handle, /// An optional conversion to be applied - convert: Option<(ScalarKind, crate::Bytes)>, + convert: Option, } impl Frontend { @@ -68,10 +68,14 @@ impl Frontend { let expr_is_bool = expr_type.scalar_kind() == Some(ScalarKind::Bool); // Special case: if casting from a bool, we need to use Select and not As. - match ctx.module.types[ty].inner.scalar_kind() { - Some(result_scalar_kind) if expr_is_bool && result_scalar_kind != ScalarKind::Bool => { - let l0 = Literal::zero(result_scalar_kind, 4).unwrap(); - let l1 = Literal::one(result_scalar_kind, 4).unwrap(); + match ctx.module.types[ty].inner.scalar() { + Some(result_scalar) if expr_is_bool && result_scalar.kind != ScalarKind::Bool => { + let result_scalar = Scalar { + width: 4, + ..result_scalar + }; + let l0 = Literal::zero(result_scalar).unwrap(); + let l1 = Literal::one(result_scalar).unwrap(); let mut reject = ctx.add_expression(Expression::Literal(l0), expr_meta)?; let mut accept = ctx.add_expression(Expression::Literal(l1), expr_meta)?; @@ -93,24 +97,16 @@ impl Frontend { } Ok(match ctx.module.types[ty].inner { - TypeInner::Vector { size, kind, width } if vector_size.is_none() => { - ctx.forced_conversion(&mut value, expr_meta, kind, width)?; + TypeInner::Vector { size, scalar } if vector_size.is_none() => { + ctx.forced_conversion(&mut value, expr_meta, scalar)?; if let TypeInner::Scalar { .. } = *ctx.resolve_type(value, expr_meta)? { ctx.add_expression(Expression::Splat { size, value }, meta)? } else { - self.vector_constructor( - ctx, - ty, - size, - kind, - width, - &[(value, expr_meta)], - meta, - )? + self.vector_constructor(ctx, ty, size, scalar, &[(value, expr_meta)], meta)? } } - TypeInner::Scalar { kind, width } => { + TypeInner::Scalar(scalar) => { let mut expr = value; if let TypeInner::Vector { .. } | TypeInner::Matrix { .. } = *ctx.resolve_type(value, expr_meta)? @@ -136,23 +132,23 @@ impl Frontend { ctx.add_expression( Expression::As { - kind, + kind: scalar.kind, expr, - convert: Some(width), + convert: Some(scalar.width), }, meta, )? } - TypeInner::Vector { size, kind, width } => { + TypeInner::Vector { size, scalar } => { if vector_size.map_or(true, |s| s != size) { value = ctx.vector_resize(size, value, expr_meta)?; } ctx.add_expression( Expression::As { - kind, + kind: scalar.kind, expr: value, - convert: Some(width), + convert: Some(scalar.width), }, meta, )? @@ -166,8 +162,8 @@ impl Frontend { let scalar_components = members .get(0) .and_then(|member| scalar_components(&ctx.module.types[member.ty].inner)); - if let Some((kind, width)) = scalar_components { - ctx.implicit_conversion(&mut value, expr_meta, kind, width)?; + if let Some(scalar) = scalar_components { + ctx.implicit_conversion(&mut value, expr_meta, scalar)?; } ctx.add_expression( @@ -181,8 +177,8 @@ impl Frontend { TypeInner::Array { base, .. } => { let scalar_components = scalar_components(&ctx.module.types[base].inner); - if let Some((kind, width)) = scalar_components { - ctx.implicit_conversion(&mut value, expr_meta, kind, width)?; + if let Some(scalar) = scalar_components { + ctx.implicit_conversion(&mut value, expr_meta, scalar)?; } ctx.add_expression( @@ -220,9 +216,13 @@ impl Frontend { // `Expression::As` doesn't support matrix width // casts so we need to do some extra work for casts - ctx.forced_conversion(&mut value, expr_meta, ScalarKind::Float, width)?; + let element_scalar = Scalar { + kind: ScalarKind::Float, + width, + }; + ctx.forced_conversion(&mut value, expr_meta, element_scalar)?; match *ctx.resolve_type(value, expr_meta)? { - TypeInner::Scalar { .. } => { + TypeInner::Scalar(_) => { // If a matrix is constructed with a single scalar value, then that // value is used to initialize all the values along the diagonal of // the matrix; the rest are given zeros. @@ -231,14 +231,13 @@ impl Frontend { name: None, inner: TypeInner::Vector { size: rows, - kind: ScalarKind::Float, - width, + scalar: element_scalar, }, }, meta, ); - let zero_literal = Literal::zero(ScalarKind::Float, width).unwrap(); + let zero_literal = Literal::zero(element_scalar).unwrap(); let zero = ctx.add_expression(Expression::Literal(zero_literal), meta)?; for i in 0..columns as u32 { @@ -268,8 +267,8 @@ impl Frontend { // (column i, row j) in the argument will be initialized from there. All // other components will be initialized to the identity matrix. - let zero_literal = Literal::zero(ScalarKind::Float, width).unwrap(); - let one_literal = Literal::one(ScalarKind::Float, width).unwrap(); + let zero_literal = Literal::zero(element_scalar).unwrap(); + let one_literal = Literal::one(element_scalar).unwrap(); let zero = ctx.add_expression(Expression::Literal(zero_literal), meta)?; let one = ctx.add_expression(Expression::Literal(one_literal), meta)?; @@ -279,8 +278,7 @@ impl Frontend { name: None, inner: TypeInner::Vector { size: rows, - kind: ScalarKind::Float, - width, + scalar: element_scalar, }, }, meta, @@ -360,15 +358,14 @@ impl Frontend { ctx: &mut Context, ty: Handle, size: crate::VectorSize, - kind: ScalarKind, - width: crate::Bytes, + scalar: Scalar, args: &[(Handle, Span)], meta: Span, ) -> Result> { let mut components = Vec::with_capacity(size as usize); for (mut arg, expr_meta) in args.iter().copied() { - ctx.forced_conversion(&mut arg, expr_meta, kind, width)?; + ctx.forced_conversion(&mut arg, expr_meta, scalar)?; if components.len() >= size as usize { break; @@ -429,8 +426,12 @@ impl Frontend { } => { let mut flattened = Vec::with_capacity(columns as usize * rows as usize); + let element_scalar = Scalar { + kind: ScalarKind::Float, + width, + }; for (mut arg, meta) in args.iter().copied() { - ctx.forced_conversion(&mut arg, meta, ScalarKind::Float, width)?; + ctx.forced_conversion(&mut arg, meta, element_scalar)?; match *ctx.resolve_type(arg, meta)? { TypeInner::Vector { size, .. } => { @@ -453,8 +454,7 @@ impl Frontend { name: None, inner: TypeInner::Vector { size: rows, - kind: ScalarKind::Float, - width, + scalar: element_scalar, }, }, meta, @@ -471,14 +471,14 @@ impl Frontend { } None } - TypeInner::Vector { size, kind, width } => { - return self.vector_constructor(ctx, ty, size, kind, width, &args, meta) + TypeInner::Vector { size, scalar } => { + return self.vector_constructor(ctx, ty, size, scalar, &args, meta) } TypeInner::Array { base, .. } => { for (mut arg, meta) in args.iter().copied() { let scalar_components = scalar_components(&ctx.module.types[base].inner); - if let Some((kind, width)) = scalar_components { - ctx.implicit_conversion(&mut arg, meta, kind, width)?; + if let Some(scalar) = scalar_components { + ctx.implicit_conversion(&mut arg, meta, scalar)?; } components.push(arg) @@ -503,8 +503,8 @@ impl Frontend { for ((mut arg, meta), scalar_components) in args.iter().copied().zip(struct_member_data.iter().copied()) { - if let Some((kind, width)) = scalar_components { - ctx.implicit_conversion(&mut arg, meta, kind, width)?; + if let Some(scalar) = scalar_components { + ctx.implicit_conversion(&mut arg, meta, scalar)?; } components.push(arg) @@ -813,8 +813,8 @@ impl Frontend { let scalar_comps = scalar_components(&ctx.module.types[*parameter].inner); // Apply implicit conversions as needed - if let Some((kind, width)) = scalar_comps { - ctx.implicit_conversion(&mut handle, meta, kind, width)?; + if let Some(scalar) = scalar_comps { + ctx.implicit_conversion(&mut handle, meta, scalar)?; } arguments.push(handle) @@ -850,8 +850,8 @@ impl Frontend { meta, )?; - if let Some((kind, width)) = proxy_write.convert { - ctx.conversion(&mut value, meta, kind, width)?; + if let Some(scalar) = proxy_write.convert { + ctx.conversion(&mut value, meta, scalar)?; } ctx.emit_restart(); @@ -893,10 +893,10 @@ impl Frontend { // If the argument is to be passed as a pointer but the type of the // expression returns a vector it must mean that it was for example // swizzled and it must be spilled into a local before calling - TypeInner::Vector { size, kind, width } => Some(ctx.module.types.insert( + TypeInner::Vector { size, scalar } => Some(ctx.module.types.insert( Type { name: None, - inner: TypeInner::Vector { size, kind, width }, + inner: TypeInner::Vector { size, scalar }, }, Span::default(), )), @@ -906,13 +906,12 @@ impl Frontend { TypeInner::Pointer { base, space } if space != AddressSpace::Function => Some(base), TypeInner::ValuePointer { size, - kind, - width, + scalar, space, } if space != AddressSpace::Function => { let inner = match size { - Some(size) => TypeInner::Vector { size, kind, width }, - None => TypeInner::Scalar { kind, width }, + Some(size) => TypeInner::Vector { size, scalar }, + None => TypeInner::Scalar(scalar), }; Some( @@ -1512,31 +1511,22 @@ fn conversion(target: &TypeInner, source: &TypeInner) -> Option { use ScalarKind::*; // Gather the `ScalarKind` and scalar width from both the target and the source - let (target_kind, target_width, source_kind, source_width) = match (target, source) { + let (target_scalar, source_scalar) = match (target, source) { // Conversions between scalars are allowed - ( - &TypeInner::Scalar { - kind: tgt_kind, - width: tgt_width, - }, - &TypeInner::Scalar { - kind: src_kind, - width: src_width, - }, - ) => (tgt_kind, tgt_width, src_kind, src_width), + (&TypeInner::Scalar(tgt_scalar), &TypeInner::Scalar(src_scalar)) => { + (tgt_scalar, src_scalar) + } // Conversions between vectors of the same size are allowed ( &TypeInner::Vector { - kind: tgt_kind, size: tgt_size, - width: tgt_width, + scalar: tgt_scalar, }, &TypeInner::Vector { - kind: src_kind, size: src_size, - width: src_width, + scalar: src_scalar, }, - ) if tgt_size == src_size => (tgt_kind, tgt_width, src_kind, src_width), + ) if tgt_size == src_size => (tgt_scalar, src_scalar), // Conversions between matrices of the same size are allowed ( &TypeInner::Matrix { @@ -1549,29 +1539,41 @@ fn conversion(target: &TypeInner, source: &TypeInner) -> Option { columns: src_cols, width: src_width, }, - ) if tgt_cols == src_cols && tgt_rows == src_rows => (Float, tgt_width, Float, src_width), + ) if tgt_cols == src_cols && tgt_rows == src_rows => { + (Scalar::float(tgt_width), Scalar::float(src_width)) + } _ => return None, }; // Check if source can be converted into target, if this is the case then the type // power of target must be higher than that of source - let target_power = type_power(target_kind, target_width); - let source_power = type_power(source_kind, source_width); + let target_power = type_power(target_scalar); + let source_power = type_power(source_scalar); if target_power < source_power { return None; } - Some( - match ((target_kind, target_width), (source_kind, source_width)) { - // A conversion from a float to a double is special - ((Float, 8), (Float, 4)) => Conversion::FloatToDouble, - // A conversion from an integer to a float is special - ((Float, 4), (Sint | Uint, _)) => Conversion::IntToFloat, - // A conversion from an integer to a double is special - ((Float, 8), (Sint | Uint, _)) => Conversion::IntToDouble, - _ => Conversion::Other, - }, - ) + Some(match (target_scalar, source_scalar) { + // A conversion from a float to a double is special + (Scalar::F64, Scalar::F32) => Conversion::FloatToDouble, + // A conversion from an integer to a float is special + ( + Scalar::F32, + Scalar { + kind: Sint | Uint, + width: _, + }, + ) => Conversion::IntToFloat, + // A conversion from an integer to a double is special + ( + Scalar::F64, + Scalar { + kind: Sint | Uint, + width: _, + }, + ) => Conversion::IntToDouble, + _ => Conversion::Other, + }) } /// Helper method returning all the non standard builtin variations needed @@ -1581,10 +1583,10 @@ fn builtin_required_variations<'a>(args: impl Iterator) -> for ty in args { match *ty { - TypeInner::ValuePointer { kind, width, .. } - | TypeInner::Scalar { kind, width } - | TypeInner::Vector { kind, width, .. } => { - if kind == ScalarKind::Float && width == 8 { + TypeInner::ValuePointer { scalar, .. } + | TypeInner::Scalar(scalar) + | TypeInner::Vector { scalar, .. } => { + if scalar == Scalar::F64 { variations |= BuiltinVariations::DOUBLE } } diff --git a/naga/src/front/glsl/offset.rs b/naga/src/front/glsl/offset.rs index 2d41778522a..56b20f5246e 100644 --- a/naga/src/front/glsl/offset.rs +++ b/naga/src/front/glsl/offset.rs @@ -16,7 +16,7 @@ use super::{ error::{Error, ErrorKind}, Span, }; -use crate::{proc::Alignment, Handle, Type, TypeInner, UniqueArena}; +use crate::{proc::Alignment, Handle, Scalar, Type, TypeInner, UniqueArena}; /// Struct with information needed for defining a struct member. /// @@ -53,12 +53,15 @@ pub fn calculate_offset( let (align, span) = match types[ty].inner { // 1. If the member is a scalar consuming N basic machine units, // the base alignment is N. - TypeInner::Scalar { width, .. } => (Alignment::from_width(width), width as u32), + TypeInner::Scalar(Scalar { width, .. }) => (Alignment::from_width(width), width as u32), // 2. If the member is a two- or four-component vector with components // consuming N basic machine units, the base alignment is 2N or 4N, respectively. // 3. If the member is a three-component vector with components consuming N // basic machine units, the base alignment is 4N. - TypeInner::Vector { size, width, .. } => ( + TypeInner::Vector { + size, + scalar: Scalar { width, .. }, + } => ( Alignment::from(size) * Alignment::from_width(width), size as u32 * width as u32, ), diff --git a/naga/src/front/glsl/parser/declarations.rs b/naga/src/front/glsl/parser/declarations.rs index 02ee2bedea4..fff56a60699 100644 --- a/naga/src/front/glsl/parser/declarations.rs +++ b/naga/src/front/glsl/parser/declarations.rs @@ -13,8 +13,8 @@ use crate::{ Error, ErrorKind, Frontend, Span, }, proc::Alignment, - AddressSpace, Expression, FunctionResult, Handle, ScalarKind, Statement, StructMember, Type, - TypeInner, + AddressSpace, Expression, FunctionResult, Handle, Scalar, ScalarKind, Statement, StructMember, + Type, TypeInner, }; use super::{DeclarationContext, ParsingContext, Result}; @@ -34,10 +34,10 @@ fn element_or_member_type( ) -> Handle { match types[ty].inner { // The child type of a vector is a scalar of the same kind and width - TypeInner::Vector { kind, width, .. } => types.insert( + TypeInner::Vector { scalar, .. } => types.insert( Type { name: None, - inner: TypeInner::Scalar { kind, width }, + inner: TypeInner::Scalar(scalar), }, Default::default(), ), @@ -48,8 +48,7 @@ fn element_or_member_type( name: None, inner: TypeInner::Vector { size: rows, - kind: ScalarKind::Float, - width, + scalar: Scalar::float(width), }, }, Default::default(), @@ -156,8 +155,8 @@ impl<'source> ParsingContext<'source> { let (mut init, init_meta) = ctx.lower_expect(stmt, frontend, expr, ExprPos::Rhs)?; let scalar_components = scalar_components(&ctx.module.types[ty].inner); - if let Some((kind, width)) = scalar_components { - ctx.implicit_conversion(&mut init, init_meta, kind, width)?; + if let Some(scalar) = scalar_components { + ctx.implicit_conversion(&mut init, init_meta, scalar)?; } Ok((init, init_meta)) @@ -233,9 +232,8 @@ impl<'source> ParsingContext<'source> { let (mut expr, init_meta) = self.parse_initializer(frontend, ty, ctx.ctx)?; let scalar_components = scalar_components(&ctx.ctx.module.types[ty].inner); - if let Some((kind, width)) = scalar_components { - ctx.ctx - .implicit_conversion(&mut expr, init_meta, kind, width)?; + if let Some(scalar) = scalar_components { + ctx.ctx.implicit_conversion(&mut expr, init_meta, scalar)?; } ctx.ctx.is_const = prev_const; @@ -509,10 +507,10 @@ impl<'source> ParsingContext<'source> { let (ty, meta) = self.parse_type_non_void(frontend, ctx)?; match ctx.module.types[ty].inner { - TypeInner::Scalar { + TypeInner::Scalar(Scalar { kind: ScalarKind::Float | ScalarKind::Sint, .. - } => {} + }) => {} _ => frontend.errors.push(Error { kind: ErrorKind::SemanticError( "Precision statement can only work on floats and ints".into(), diff --git a/naga/src/front/glsl/parser_tests.rs b/naga/src/front/glsl/parser_tests.rs index 1813a4ce49d..0f4fbab22fe 100644 --- a/naga/src/front/glsl/parser_tests.rs +++ b/naga/src/front/glsl/parser_tests.rs @@ -509,7 +509,7 @@ fn functions() { #[test] fn constants() { - use crate::{Constant, Expression, ScalarKind, Type, TypeInner}; + use crate::{Constant, Expression, Type, TypeInner}; let mut frontend = Frontend::default(); @@ -536,10 +536,7 @@ fn constants() { ty, &Type { name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Float, - width: 4 - } + inner: TypeInner::Scalar(crate::Scalar::F32) } ); diff --git a/naga/src/front/glsl/types.rs b/naga/src/front/glsl/types.rs index ffa879506e0..953c4a98edb 100644 --- a/naga/src/front/glsl/types.rs +++ b/naga/src/front/glsl/types.rs @@ -1,6 +1,6 @@ use super::{context::Context, Error, ErrorKind, Result, Span}; use crate::{ - proc::ResolveContext, Bytes, Expression, Handle, ImageClass, ImageDimension, ScalarKind, Type, + proc::ResolveContext, Expression, Handle, ImageClass, ImageDimension, Scalar, ScalarKind, Type, TypeInner, VectorSize, }; @@ -8,38 +8,23 @@ pub fn parse_type(type_name: &str) -> Option { match type_name { "bool" => Some(Type { name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Bool, - width: crate::BOOL_WIDTH, - }, + inner: TypeInner::Scalar(Scalar::BOOL), }), "float" => Some(Type { name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Float, - width: 4, - }, + inner: TypeInner::Scalar(Scalar::F32), }), "double" => Some(Type { name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Float, - width: 8, - }, + inner: TypeInner::Scalar(Scalar::F64), }), "int" => Some(Type { name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Sint, - width: 4, - }, + inner: TypeInner::Scalar(Scalar::I32), }), "uint" => Some(Type { name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Uint, - width: 4, - }, + inner: TypeInner::Scalar(Scalar::U32), }), "sampler" | "samplerShadow" => Some(Type { name: None, @@ -48,13 +33,13 @@ pub fn parse_type(type_name: &str) -> Option { }, }), word => { - fn kind_width_parse(ty: &str) -> Option<(ScalarKind, u8)> { + fn kind_width_parse(ty: &str) -> Option { Some(match ty { - "" => (ScalarKind::Float, 4), - "b" => (ScalarKind::Bool, crate::BOOL_WIDTH), - "i" => (ScalarKind::Sint, 4), - "u" => (ScalarKind::Uint, 4), - "d" => (ScalarKind::Float, 8), + "" => Scalar::F32, + "b" => Scalar::BOOL, + "i" => Scalar::I32, + "u" => Scalar::U32, + "d" => Scalar::F64, _ => return None, }) } @@ -73,12 +58,12 @@ pub fn parse_type(type_name: &str) -> Option { let kind = iter.next()?; let size = iter.next()?; - let (kind, width) = kind_width_parse(kind)?; + let scalar = kind_width_parse(kind)?; let size = size_parse(size)?; Some(Type { name: None, - inner: TypeInner::Vector { size, kind, width }, + inner: TypeInner::Vector { size, scalar }, }) }; @@ -87,7 +72,7 @@ pub fn parse_type(type_name: &str) -> Option { let kind = iter.next()?; let size = iter.next()?; - let (_, width) = kind_width_parse(kind)?; + let Scalar { width, .. } = kind_width_parse(kind)?; let (columns, rows) = if let Some(size) = size_parse(size) { (size, size) @@ -204,21 +189,21 @@ pub fn parse_type(type_name: &str) -> Option { } } -pub const fn scalar_components(ty: &TypeInner) -> Option<(ScalarKind, Bytes)> { +pub const fn scalar_components(ty: &TypeInner) -> Option { match *ty { - TypeInner::Scalar { kind, width } => Some((kind, width)), - TypeInner::Vector { kind, width, .. } => Some((kind, width)), - TypeInner::Matrix { width, .. } => Some((ScalarKind::Float, width)), - TypeInner::ValuePointer { kind, width, .. } => Some((kind, width)), + TypeInner::Scalar(scalar) + | TypeInner::Vector { scalar, .. } + | TypeInner::ValuePointer { scalar, .. } => Some(scalar), + TypeInner::Matrix { width, .. } => Some(Scalar::float(width)), _ => None, } } -pub const fn type_power(kind: ScalarKind, width: Bytes) -> Option { - Some(match kind { +pub const fn type_power(scalar: Scalar) -> Option { + Some(match scalar.kind { ScalarKind::Sint => 0, ScalarKind::Uint => 1, - ScalarKind::Float if width == 4 => 2, + ScalarKind::Float if scalar.width == 4 => 2, ScalarKind::Float => 3, ScalarKind::Bool => return None, }) diff --git a/naga/src/front/glsl/variables.rs b/naga/src/front/glsl/variables.rs index 794f181b56c..5af2b228f03 100644 --- a/naga/src/front/glsl/variables.rs +++ b/naga/src/front/glsl/variables.rs @@ -6,8 +6,8 @@ use super::{ }; use crate::{ AddressSpace, Binding, BuiltIn, Constant, Expression, GlobalVariable, Handle, Interpolation, - LocalVariable, ResourceBinding, ScalarKind, ShaderStage, SwizzleComponent, Type, TypeInner, - VectorSize, + LocalVariable, ResourceBinding, Scalar, ScalarKind, ShaderStage, SwizzleComponent, Type, + TypeInner, VectorSize, }; pub struct VarDeclaration<'a, 'key> { @@ -109,8 +109,7 @@ impl Frontend { "gl_Position" => BuiltInData { inner: TypeInner::Vector { size: VectorSize::Quad, - kind: ScalarKind::Float, - width: 4, + scalar: Scalar::F32, }, builtin: BuiltIn::Position { invariant: false }, mutable: true, @@ -119,8 +118,7 @@ impl Frontend { "gl_FragCoord" => BuiltInData { inner: TypeInner::Vector { size: VectorSize::Quad, - kind: ScalarKind::Float, - width: 4, + scalar: Scalar::F32, }, builtin: BuiltIn::Position { invariant: false }, mutable: false, @@ -129,8 +127,7 @@ impl Frontend { "gl_PointCoord" => BuiltInData { inner: TypeInner::Vector { size: VectorSize::Bi, - kind: ScalarKind::Float, - width: 4, + scalar: Scalar::F32, }, builtin: BuiltIn::PointCoord, mutable: false, @@ -143,8 +140,7 @@ impl Frontend { | "gl_LocalInvocationID" => BuiltInData { inner: TypeInner::Vector { size: VectorSize::Tri, - kind: ScalarKind::Uint, - width: 4, + scalar: Scalar::U32, }, builtin: match name { "gl_GlobalInvocationID" => BuiltIn::GlobalInvocationId, @@ -158,19 +154,13 @@ impl Frontend { storage: StorageQualifier::Input, }, "gl_FrontFacing" => BuiltInData { - inner: TypeInner::Scalar { - kind: ScalarKind::Bool, - width: crate::BOOL_WIDTH, - }, + inner: TypeInner::Scalar(Scalar::BOOL), builtin: BuiltIn::FrontFacing, mutable: false, storage: StorageQualifier::Input, }, "gl_PointSize" | "gl_FragDepth" => BuiltInData { - inner: TypeInner::Scalar { - kind: ScalarKind::Float, - width: 4, - }, + inner: TypeInner::Scalar(Scalar::F32), builtin: match name { "gl_PointSize" => BuiltIn::PointSize, "gl_FragDepth" => BuiltIn::FragDepth, @@ -183,10 +173,7 @@ impl Frontend { let base = ctx.module.types.insert( Type { name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Float, - width: 4, - }, + inner: TypeInner::Scalar(Scalar::F32), }, meta, ); @@ -219,10 +206,7 @@ impl Frontend { }; BuiltInData { - inner: TypeInner::Scalar { - kind: ScalarKind::Uint, - width: 4, - }, + inner: TypeInner::Scalar(Scalar::U32), builtin, mutable: false, storage: StorageQualifier::Input, diff --git a/naga/src/front/spv/image.rs b/naga/src/front/spv/image.rs index ee58c7ba140..0f25dd626b0 100644 --- a/naga/src/front/spv/image.rs +++ b/naga/src/front/spv/image.rs @@ -1,4 +1,7 @@ -use crate::arena::{Handle, UniqueArena}; +use crate::{ + arena::{Handle, UniqueArena}, + Scalar, +}; use super::{Error, LookupExpression, LookupHelper as _}; @@ -61,8 +64,11 @@ fn extract_image_coordinates( ctx: &mut super::BlockContext, ) -> (Handle, Option>) { let (given_size, kind) = match ctx.type_arena[coordinate_ty].inner { - crate::TypeInner::Scalar { kind, .. } => (None, kind), - crate::TypeInner::Vector { size, kind, .. } => (Some(size), kind), + crate::TypeInner::Scalar(Scalar { kind, .. }) => (None, kind), + crate::TypeInner::Vector { + size, + scalar: Scalar { kind, .. }, + } => (Some(size), kind), ref other => unreachable!("Unexpected texture coordinate {:?}", other), }; @@ -73,8 +79,7 @@ fn extract_image_coordinates( name: None, inner: crate::TypeInner::Vector { size, - kind, - width: 4, + scalar: Scalar { kind, width: 4 }, }, }) .expect("Required coordinate type should have been set up by `parse_type_image`!") diff --git a/naga/src/front/spv/mod.rs b/naga/src/front/spv/mod.rs index 1a3fce6d753..2d676fad665 100644 --- a/naga/src/front/spv/mod.rs +++ b/naga/src/front/spv/mod.rs @@ -2833,22 +2833,22 @@ impl> Frontend { let value_lexp = self.lookup_expression.lookup(value_id)?; let ty_lookup = self.lookup_type.lookup(result_type_id)?; - let (kind, width) = match ctx.type_arena[ty_lookup.handle].inner { - crate::TypeInner::Scalar { kind, width } - | crate::TypeInner::Vector { kind, width, .. } => (kind, width), - crate::TypeInner::Matrix { width, .. } => (crate::ScalarKind::Float, width), + let scalar = match ctx.type_arena[ty_lookup.handle].inner { + crate::TypeInner::Scalar(scalar) + | crate::TypeInner::Vector { scalar, .. } => scalar, + crate::TypeInner::Matrix { width, .. } => crate::Scalar::float(width), _ => return Err(Error::InvalidAsType(ty_lookup.handle)), }; let expr = crate::Expression::As { expr: get_expr_handle!(value_id, value_lexp), - kind, - convert: if kind == crate::ScalarKind::Bool { + kind: scalar.kind, + convert: if scalar.kind == crate::ScalarKind::Bool { Some(crate::BOOL_WIDTH) } else if inst.op == Op::Bitcast { None } else { - Some(width) + Some(scalar.width) }, }; self.lookup_expression.insert( @@ -3236,10 +3236,10 @@ impl> Frontend { let selector_lty = self.lookup_type.lookup(selector_lexp.type_id)?; let selector_handle = get_expr_handle!(selector, selector_lexp); let selector = match ctx.type_arena[selector_lty.handle].inner { - crate::TypeInner::Scalar { + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Uint, width: _, - } => { + }) => { // IR expects a signed integer, so do a bitcast ctx.expressions.append( crate::Expression::As { @@ -3250,10 +3250,10 @@ impl> Frontend { span, ) } - crate::TypeInner::Scalar { + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Sint, width: _, - } => selector_handle, + }) => selector_handle, ref other => unimplemented!("Unexpected selector {:?}", other), }; @@ -4127,10 +4127,7 @@ impl> Frontend { self.switch(ModuleState::Type, inst.op)?; inst.expect(2)?; let id = self.next()?; - let inner = crate::TypeInner::Scalar { - kind: crate::ScalarKind::Bool, - width: crate::BOOL_WIDTH, - }; + let inner = crate::TypeInner::Scalar(crate::Scalar::BOOL); self.lookup_type.insert( id, LookupType { @@ -4158,14 +4155,14 @@ impl> Frontend { let id = self.next()?; let width = self.next()?; let sign = self.next()?; - let inner = crate::TypeInner::Scalar { + let inner = crate::TypeInner::Scalar(crate::Scalar { kind: match sign { 0 => crate::ScalarKind::Uint, 1 => crate::ScalarKind::Sint, _ => return Err(Error::InvalidSign(sign)), }, width: map_width(width)?, - }; + }); self.lookup_type.insert( id, LookupType { @@ -4192,10 +4189,7 @@ impl> Frontend { inst.expect(3)?; let id = self.next()?; let width = self.next()?; - let inner = crate::TypeInner::Scalar { - kind: crate::ScalarKind::Float, - width: map_width(width)?, - }; + let inner = crate::TypeInner::Scalar(crate::Scalar::float(map_width(width)?)); self.lookup_type.insert( id, LookupType { @@ -4223,15 +4217,14 @@ impl> Frontend { let id = self.next()?; let type_id = self.next()?; let type_lookup = self.lookup_type.lookup(type_id)?; - let (kind, width) = match module.types[type_lookup.handle].inner { - crate::TypeInner::Scalar { kind, width } => (kind, width), + let scalar = match module.types[type_lookup.handle].inner { + crate::TypeInner::Scalar(scalar) => scalar, _ => return Err(Error::InvalidInnerType(type_id)), }; let component_count = self.next()?; let inner = crate::TypeInner::Vector { size: map_vector_size(component_count)?, - kind, - width, + scalar, }; self.lookup_type.insert( id, @@ -4264,10 +4257,10 @@ impl> Frontend { let vector_type_lookup = self.lookup_type.lookup(vector_type_id)?; let inner = match module.types[vector_type_lookup.handle].inner { - crate::TypeInner::Vector { size, width, .. } => crate::TypeInner::Matrix { + crate::TypeInner::Vector { size, scalar } => crate::TypeInner::Matrix { columns: map_vector_size(num_columns)?, rows: size, - width, + width: scalar.width, }, _ => return Err(Error::InvalidInnerType(vector_type_id)), }; @@ -4644,11 +4637,10 @@ impl> Frontend { crate::Type { name: None, inner: { - let kind = crate::ScalarKind::Float; - let width = 4; + let scalar = crate::Scalar::F32; match dim.required_coordinate_size() { - None => crate::TypeInner::Scalar { kind, width }, - Some(size) => crate::TypeInner::Vector { size, kind, width }, + None => crate::TypeInner::Scalar(scalar), + Some(size) => crate::TypeInner::Vector { size, scalar }, } }, }, @@ -4753,30 +4745,30 @@ impl> Frontend { let ty = type_lookup.handle; let literal = match module.types[ty].inner { - crate::TypeInner::Scalar { + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Uint, width, - } => { + }) => { let low = self.next()?; match width { 4 => crate::Literal::U32(low), _ => return Err(Error::InvalidTypeWidth(width as u32)), } } - crate::TypeInner::Scalar { + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Sint, width, - } => { + }) => { let low = self.next()?; match width { 4 => crate::Literal::I32(low as i32), _ => return Err(Error::InvalidTypeWidth(width as u32)), } } - crate::TypeInner::Scalar { + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Float, width, - } => { + }) => { let low = self.next()?; match width { 4 => crate::Literal::F32(f32::from_bits(low)), @@ -5050,17 +5042,15 @@ impl> Frontend { | crate::BuiltIn::SampleIndex | crate::BuiltIn::VertexIndex | crate::BuiltIn::PrimitiveIndex - | crate::BuiltIn::LocalInvocationIndex => Some(crate::TypeInner::Scalar { - kind: crate::ScalarKind::Uint, - width: 4, - }), + | crate::BuiltIn::LocalInvocationIndex => { + Some(crate::TypeInner::Scalar(crate::Scalar::U32)) + } crate::BuiltIn::GlobalInvocationId | crate::BuiltIn::LocalInvocationId | crate::BuiltIn::WorkGroupId | crate::BuiltIn::WorkGroupSize => Some(crate::TypeInner::Vector { size: crate::VectorSize::Tri, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: crate::Scalar::U32, }), _ => None, }; diff --git a/naga/src/front/type_gen.rs b/naga/src/front/type_gen.rs index 0c608504c91..efab3d64afa 100644 --- a/naga/src/front/type_gen.rs +++ b/naga/src/front/type_gen.rs @@ -25,24 +25,17 @@ impl crate::Module { return handle; } - let width = 4; let ty_flag = self.types.insert( crate::Type { name: None, - inner: crate::TypeInner::Scalar { - width, - kind: crate::ScalarKind::Uint, - }, + inner: crate::TypeInner::Scalar(crate::Scalar::U32), }, Span::UNDEFINED, ); let ty_scalar = self.types.insert( crate::Type { name: None, - inner: crate::TypeInner::Scalar { - width, - kind: crate::ScalarKind::Float, - }, + inner: crate::TypeInner::Scalar(crate::Scalar::F32), }, Span::UNDEFINED, ); @@ -51,8 +44,7 @@ impl crate::Module { name: None, inner: crate::TypeInner::Vector { size: crate::VectorSize::Tri, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::F32, }, }, Span::UNDEFINED, @@ -127,24 +119,17 @@ impl crate::Module { return handle; } - let width = 4; let ty_flag = self.types.insert( crate::Type { name: None, - inner: crate::TypeInner::Scalar { - width, - kind: crate::ScalarKind::Uint, - }, + inner: crate::TypeInner::Scalar(crate::Scalar::U32), }, Span::UNDEFINED, ); let ty_scalar = self.types.insert( crate::Type { name: None, - inner: crate::TypeInner::Scalar { - width, - kind: crate::ScalarKind::Float, - }, + inner: crate::TypeInner::Scalar(crate::Scalar::F32), }, Span::UNDEFINED, ); @@ -152,9 +137,8 @@ impl crate::Module { crate::Type { name: None, inner: crate::TypeInner::Vector { - width, size: crate::VectorSize::Bi, - kind: crate::ScalarKind::Float, + scalar: crate::Scalar::F32, }, }, Span::UNDEFINED, @@ -162,10 +146,7 @@ impl crate::Module { let ty_bool = self.types.insert( crate::Type { name: None, - inner: crate::TypeInner::Scalar { - width: crate::BOOL_WIDTH, - kind: crate::ScalarKind::Bool, - }, + inner: crate::TypeInner::Scalar(crate::Scalar::BOOL), }, Span::UNDEFINED, ); @@ -175,7 +156,7 @@ impl crate::Module { inner: crate::TypeInner::Matrix { columns: crate::VectorSize::Quad, rows: crate::VectorSize::Tri, - width, + width: 4, }, }, Span::UNDEFINED, @@ -277,28 +258,26 @@ impl crate::Module { } let ty = match special_type { - crate::PredeclaredType::AtomicCompareExchangeWeakResult { kind, width } => { + crate::PredeclaredType::AtomicCompareExchangeWeakResult(scalar) => { let bool_ty = self.types.insert( crate::Type { name: None, - inner: crate::TypeInner::Scalar { - kind: crate::ScalarKind::Bool, - width: crate::BOOL_WIDTH, - }, + inner: crate::TypeInner::Scalar(crate::Scalar::BOOL), }, Span::UNDEFINED, ); let scalar_ty = self.types.insert( crate::Type { name: None, - inner: crate::TypeInner::Scalar { kind, width }, + inner: crate::TypeInner::Scalar(scalar), }, Span::UNDEFINED, ); crate::Type { name: Some(format!( - "__atomic_compare_exchange_result<{kind:?},{width}>" + "__atomic_compare_exchange_result<{:?},{}>", + scalar.kind, scalar.width, )), inner: crate::TypeInner::Struct { members: vec![ @@ -323,10 +302,7 @@ impl crate::Module { let float_ty = self.types.insert( crate::Type { name: None, - inner: crate::TypeInner::Scalar { - kind: crate::ScalarKind::Float, - width, - }, + inner: crate::TypeInner::Scalar(crate::Scalar::float(width)), }, Span::UNDEFINED, ); @@ -337,8 +313,7 @@ impl crate::Module { name: None, inner: crate::TypeInner::Vector { size, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }, }, Span::UNDEFINED, @@ -379,10 +354,7 @@ impl crate::Module { let float_ty = self.types.insert( crate::Type { name: None, - inner: crate::TypeInner::Scalar { - kind: crate::ScalarKind::Float, - width, - }, + inner: crate::TypeInner::Scalar(crate::Scalar::float(width)), }, Span::UNDEFINED, ); @@ -390,10 +362,10 @@ impl crate::Module { let int_ty = self.types.insert( crate::Type { name: None, - inner: crate::TypeInner::Scalar { + inner: crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Sint, width, - }, + }), }, Span::UNDEFINED, ); @@ -404,8 +376,7 @@ impl crate::Module { name: None, inner: crate::TypeInner::Vector { size, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }, }, Span::UNDEFINED, @@ -415,8 +386,10 @@ impl crate::Module { name: None, inner: crate::TypeInner::Vector { size, - kind: crate::ScalarKind::Sint, - width, + scalar: crate::Scalar { + kind: crate::ScalarKind::Sint, + width, + }, }, }, Span::UNDEFINED, diff --git a/naga/src/front/wgsl/error.rs b/naga/src/front/wgsl/error.rs index d3708c7ef85..a04268fee87 100644 --- a/naga/src/front/wgsl/error.rs +++ b/naga/src/front/wgsl/error.rs @@ -1,4 +1,5 @@ use crate::front::wgsl::parse::lexer::Token; +use crate::front::wgsl::Scalar; use crate::proc::{Alignment, ConstantEvaluatorError, ResolveError}; use crate::{SourceLocation, Span}; use codespan_reporting::diagnostic::{Diagnostic, Label}; @@ -139,7 +140,7 @@ pub enum Error<'a> { UnexpectedComponents(Span), UnexpectedOperationInConstContext(Span), BadNumber(Span, NumberError), - BadMatrixScalarKind(Span, crate::ScalarKind, u8), + BadMatrixScalarKind(Span, Scalar), BadAccessor(Span), BadTexture(Span), BadTypeCast { @@ -149,8 +150,7 @@ pub enum Error<'a> { }, BadTextureSampleType { span: Span, - kind: crate::ScalarKind, - width: u8, + scalar: Scalar, }, BadIncrDecrReferenceType(Span), InvalidResolve(ResolveError), @@ -307,10 +307,10 @@ impl<'a> Error<'a> { labels: vec![(bad_span, err.to_string().into())], notes: vec![], }, - Error::BadMatrixScalarKind(span, kind, width) => ParseError { + Error::BadMatrixScalarKind(span, scalar) => ParseError { message: format!( "matrix scalar type must be floating-point, but found `{}`", - kind.to_wgsl(width) + scalar.to_wgsl() ), labels: vec![(span, "must be floating-point (e.g. `f32`)".into())], notes: vec![], @@ -330,10 +330,10 @@ impl<'a> Error<'a> { labels: vec![(bad_span, "unknown scalar type".into())], notes: vec!["Valid scalar types are f32, f64, i32, u32, bool".into()], }, - Error::BadTextureSampleType { span, kind, width } => ParseError { + Error::BadTextureSampleType { span, scalar } => ParseError { message: format!( "texture sample type must be one of f32, i32 or u32, but found {}", - kind.to_wgsl(width) + scalar.to_wgsl() ), labels: vec![(span, "must be one of f32, i32 or u32".into())], notes: vec![], diff --git a/naga/src/front/wgsl/lower/construction.rs b/naga/src/front/wgsl/lower/construction.rs index 912713f9112..7c06f1804ee 100644 --- a/naga/src/front/wgsl/lower/construction.rs +++ b/naga/src/front/wgsl/lower/construction.rs @@ -65,7 +65,7 @@ impl Constructor<(Handle, &crate::TypeInner)> { format!("mat{}x{}", columns as u32, rows as u32,) } Self::PartialArray => "array".to_string(), - Self::Type((handle, _inner)) => ctx.format_type(handle), + Self::Type((handle, _inner)) => handle.to_wgsl(&ctx.module.to_ctx()), } } } @@ -185,11 +185,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ty_inner: &crate::TypeInner::Scalar { .. }, .. }, - Constructor::Type((_, &crate::TypeInner::Scalar { kind, width })), + Constructor::Type((_, &crate::TypeInner::Scalar(scalar))), ) => crate::Expression::As { expr: component, - kind, - convert: Some(width), + kind: scalar.kind, + convert: Some(scalar.width), }, // Vector conversion (vector -> vector) @@ -203,14 +203,13 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { _, &crate::TypeInner::Vector { size: dst_size, - kind: dst_kind, - width: dst_width, + scalar: dst_scalar, }, )), ) if dst_size == src_size => crate::Expression::As { expr: component, - kind: dst_kind, - convert: Some(dst_width), + kind: dst_scalar.kind, + convert: Some(dst_scalar.width), }, // Vector conversion (vector -> vector) - partial @@ -294,23 +293,17 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ( Components::One { component, - ty_inner: - &crate::TypeInner::Scalar { - kind: src_kind, - width: src_width, - .. - }, + ty_inner: &crate::TypeInner::Scalar(src_scalar), .. }, Constructor::Type(( _, &crate::TypeInner::Vector { size, - kind: dst_kind, - width: dst_width, + scalar: dst_scalar, }, )), - ) if dst_kind == src_kind || dst_width == src_width => crate::Expression::Splat { + ) if dst_scalar == src_scalar => crate::Expression::Splat { size, value: component, }, @@ -320,8 +313,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { Components::Many { components, first_component_ty_inner: - &crate::TypeInner::Scalar { kind, width } - | &crate::TypeInner::Vector { kind, width, .. }, + &crate::TypeInner::Scalar(scalar) | &crate::TypeInner::Vector { scalar, .. }, .. }, Constructor::PartialVector { size }, @@ -333,9 +325,9 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { &crate::TypeInner::Scalar { .. } | &crate::TypeInner::Vector { .. }, .. }, - Constructor::Type((_, &crate::TypeInner::Vector { size, width, kind })), + Constructor::Type((_, &crate::TypeInner::Vector { size, scalar })), ) => { - let inner = crate::TypeInner::Vector { size, kind, width }; + let inner = crate::TypeInner::Vector { size, scalar }; let ty = ctx.ensure_type_exists(inner); crate::Expression::Compose { ty, components } } @@ -344,7 +336,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ( Components::Many { components, - first_component_ty_inner: &crate::TypeInner::Scalar { width, .. }, + first_component_ty_inner: &crate::TypeInner::Scalar(crate::Scalar { width, .. }), .. }, Constructor::PartialMatrix { columns, rows }, @@ -365,8 +357,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { )), ) => { let vec_ty = ctx.ensure_type_exists(crate::TypeInner::Vector { - width, - kind: crate::ScalarKind::Float, + scalar: crate::Scalar::float(width), size: rows, }); @@ -395,7 +386,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ( Components::Many { components, - first_component_ty_inner: &crate::TypeInner::Vector { width, .. }, + first_component_ty_inner: + &crate::TypeInner::Vector { + scalar: crate::Scalar { width, .. }, + .. + }, .. }, Constructor::PartialMatrix { columns, rows }, @@ -460,7 +455,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { // Bad conversion (type cast) (Components::One { span, ty_inner, .. }, constructor) => { - let from_type = ctx.format_typeinner(ty_inner); + let from_type = ty_inner.to_wgsl(&ctx.module.to_ctx()); return Err(Error::BadTypeCast { span, from_type, @@ -516,13 +511,13 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ctx: &mut ExpressionContext<'source, '_, 'out>, ) -> Result>, Error<'source>> { let handle = match *constructor { - ast::ConstructorType::Scalar { width, kind } => { - let ty = ctx.ensure_type_exists(crate::TypeInner::Scalar { width, kind }); + ast::ConstructorType::Scalar(scalar) => { + let ty = ctx.ensure_type_exists(scalar.to_inner_scalar()); Constructor::Type(ty) } ast::ConstructorType::PartialVector { size } => Constructor::PartialVector { size }, - ast::ConstructorType::Vector { size, kind, width } => { - let ty = ctx.ensure_type_exists(crate::TypeInner::Vector { size, kind, width }); + ast::ConstructorType::Vector { size, scalar } => { + let ty = ctx.ensure_type_exists(scalar.to_inner_vector(size)); Constructor::Type(ty) } ast::ConstructorType::PartialMatrix { columns, rows } => { diff --git a/naga/src/front/wgsl/lower/mod.rs b/naga/src/front/wgsl/lower/mod.rs index a8f6e9d1be5..ffe6b8a5124 100644 --- a/naga/src/front/wgsl/lower/mod.rs +++ b/naga/src/front/wgsl/lower/mod.rs @@ -7,7 +7,6 @@ use crate::front::wgsl::parse::{ast, conv}; use crate::front::Typifier; use crate::proc::{ ensure_block_returns, Alignment, ConstantEvaluator, Emitter, Layouter, ResolveContext, - TypeResolution, }; use crate::{Arena, FastHashMap, FastIndexMap, Handle, Span}; @@ -59,6 +58,8 @@ macro_rules! resolve_inner_binary { /// Returns a &[`TypeResolution`]. /// /// See the documentation of [`resolve_inner!`] for why this macro is necessary. +/// +/// [`TypeResolution`]: crate::proc::TypeResolution macro_rules! resolve { ($ctx:ident, $expr:expr) => {{ $ctx.grow_types($expr)?; @@ -486,6 +487,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { /// [`resolve_inner!`] or [`resolve_inner_binary!`]. /// /// [`self.typifier`]: ExpressionContext::typifier + /// [`TypeResolution`]: crate::proc::TypeResolution /// [`register_type`]: Self::register_type /// [`Typifier`]: Typifier fn grow_types( @@ -632,25 +634,6 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { } } - fn format_typeinner(&self, inner: &crate::TypeInner) -> String { - inner.to_wgsl(self.module.to_ctx()) - } - - fn format_type(&self, handle: Handle) -> String { - let ty = &self.module.types[handle]; - match ty.name { - Some(ref name) => name.clone(), - None => self.format_typeinner(&ty.inner), - } - } - - fn format_type_resolution(&self, resolution: &TypeResolution) -> String { - match *resolution { - TypeResolution::Handle(handle) => self.format_type(handle), - TypeResolution::Value(ref inner) => self.format_typeinner(inner), - } - } - fn ensure_type_exists(&mut self, inner: crate::TypeInner) -> Handle { self.as_global().ensure_type_exists(inner) } @@ -925,22 +908,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { if let Some(explicit) = explicit_ty { if explicit != inferred_type { - let ty = &ctx.module.types[explicit]; - let expected = ty - .name - .clone() - .unwrap_or_else(|| ty.inner.to_wgsl(ctx.module.to_ctx())); - - let ty = &ctx.module.types[inferred_type]; - let got = ty - .name - .clone() - .unwrap_or_else(|| ty.inner.to_wgsl(ctx.module.to_ctx())); - + let gctx = ctx.module.to_ctx(); return Err(Error::InitializationTypeMismatch { name: c.name.span, - expected, - got, + expected: explicit.to_wgsl(&gctx), + got: inferred_type.to_wgsl(&gctx), }); } } @@ -1128,10 +1100,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { .inner .equivalent(&ctx.module.types[init_ty].inner, &ctx.module.types) { + let gctx = &ctx.module.to_ctx(); return Err(Error::InitializationTypeMismatch { name: l.name.span, - expected: ctx.format_type(ty), - got: ctx.format_type(init_ty), + expected: ty.to_wgsl(gctx), + got: init_ty.to_wgsl(gctx), }); } } @@ -1166,10 +1139,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { .inner .equivalent(initializer_ty, &ctx.module.types) { + let gctx = &ctx.module.to_ctx(); return Err(Error::InitializationTypeMismatch { name: v.name.span, - expected: ctx.format_type(explicit), - got: ctx.format_typeinner(initializer_ty), + expected: explicit.to_wgsl(gctx), + got: initializer_ty.to_wgsl(gctx), }); } explicit @@ -1413,22 +1387,19 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { }; let mut ectx = ctx.as_expression(block, &mut emitter); - let (kind, width) = match *resolve_inner!(ectx, target_handle) { + let scalar = match *resolve_inner!(ectx, target_handle) { crate::TypeInner::ValuePointer { - size: None, - kind, - width, - .. - } => (kind, width), + size: None, scalar, .. + } => scalar, crate::TypeInner::Pointer { base, .. } => match ectx.module.types[base].inner { - crate::TypeInner::Scalar { kind, width } => (kind, width), + crate::TypeInner::Scalar(scalar) => scalar, _ => return Err(Error::BadIncrDecrReferenceType(value_span)), }, _ => return Err(Error::BadIncrDecrReferenceType(value_span)), }; - let literal = match kind { + let literal = match scalar.kind { crate::ScalarKind::Sint | crate::ScalarKind::Uint => { - crate::Literal::one(kind, width) + crate::Literal::one(scalar) .ok_or(Error::BadIncrDecrReferenceType(value_span))? } _ => return Err(Error::BadIncrDecrReferenceType(value_span)), @@ -1611,21 +1582,17 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { match *inner { crate::TypeInner::Pointer { base, .. } => &ctx.module.types[base].inner, crate::TypeInner::ValuePointer { - size: None, - kind, - width, - .. + size: None, scalar, .. } => { - temp_inner = crate::TypeInner::Scalar { kind, width }; + temp_inner = crate::TypeInner::Scalar(scalar); &temp_inner } crate::TypeInner::ValuePointer { size: Some(size), - kind, - width, + scalar, .. } => { - temp_inner = crate::TypeInner::Vector { size, kind, width }; + temp_inner = crate::TypeInner::Vector { size, scalar }; &temp_inner } _ => unreachable!( @@ -1682,22 +1649,23 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let expr = self.expression(expr, ctx)?; let to_resolved = self.resolve_ast_type(to, &mut ctx.as_global())?; - let kind = match ctx.module.types[to_resolved].inner { - crate::TypeInner::Scalar { kind, .. } => kind, - crate::TypeInner::Vector { kind, .. } => kind, + let element_scalar = match ctx.module.types[to_resolved].inner { + crate::TypeInner::Scalar(scalar) => scalar, + crate::TypeInner::Vector { scalar, .. } => scalar, _ => { let ty = resolve!(ctx, expr); + let gctx = &ctx.module.to_ctx(); return Err(Error::BadTypeCast { - from_type: ctx.format_type_resolution(ty), + from_type: ty.to_wgsl(gctx), span: ty_span, - to_type: ctx.format_type(to_resolved), + to_type: to_resolved.to_wgsl(gctx), }); } }; Typed::Plain(crate::Expression::As { expr, - kind, + kind: element_scalar.kind, convert: None, }) } @@ -1788,10 +1756,10 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ) && { matches!( resolve_inner!(ctx, argument), - &crate::TypeInner::Scalar { + &crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Bool, .. - } + }) ) }; @@ -1831,10 +1799,14 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { if fun == crate::MathFunction::Modf || fun == crate::MathFunction::Frexp { if let Some((size, width)) = match *resolve_inner!(ctx, arg) { - crate::TypeInner::Scalar { width, .. } => Some((None, width)), - crate::TypeInner::Vector { size, width, .. } => { - Some((Some(size), width)) + crate::TypeInner::Scalar(crate::Scalar { width, .. }) => { + Some((None, width)) } + crate::TypeInner::Vector { + size, + scalar: crate::Scalar { width, .. }, + .. + } => Some((Some(size), width)), _ => None, } { ctx.module.generate_predeclared_type( @@ -1979,13 +1951,12 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { args.finish()?; let expression = match *resolve_inner!(ctx, value) { - crate::TypeInner::Scalar { kind, width } => { + crate::TypeInner::Scalar(scalar) => { crate::Expression::AtomicResult { ty: ctx.module.generate_predeclared_type( - crate::PredeclaredType::AtomicCompareExchangeWeakResult { - kind, - width, - }, + crate::PredeclaredType::AtomicCompareExchangeWeakResult( + scalar, + ), ), comparison: true, } @@ -2582,10 +2553,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ctx: &mut GlobalContext<'source, '_, '_>, ) -> Result, Error<'source>> { let inner = match ctx.types[handle] { - ast::Type::Scalar { kind, width } => crate::TypeInner::Scalar { kind, width }, - ast::Type::Vector { size, kind, width } => { - crate::TypeInner::Vector { size, kind, width } - } + ast::Type::Scalar(scalar) => scalar.to_inner_scalar(), + ast::Type::Vector { size, scalar } => scalar.to_inner_vector(size), ast::Type::Matrix { rows, columns, @@ -2595,7 +2564,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { rows, width, }, - ast::Type::Atomic { kind, width } => crate::TypeInner::Atomic { kind, width }, + ast::Type::Atomic(scalar) => scalar.to_inner_atomic(), ast::Type::Pointer { base, space } => { let base = self.resolve_ast_type(base, ctx)?; crate::TypeInner::Pointer { base, space } diff --git a/naga/src/front/wgsl/mod.rs b/naga/src/front/wgsl/mod.rs index 56834d5d926..b6151fe1c03 100644 --- a/naga/src/front/wgsl/mod.rs +++ b/naga/src/front/wgsl/mod.rs @@ -10,6 +10,7 @@ mod lower; mod parse; #[cfg(test)] mod tests; +mod to_wgsl; use crate::front::wgsl::error::Error; use crate::front::wgsl::parse::Parser; @@ -17,6 +18,7 @@ use thiserror::Error; pub use crate::front::wgsl::error::ParseError; use crate::front::wgsl::lower::Lowerer; +use crate::Scalar; pub struct Frontend { parser: Parser, @@ -45,259 +47,3 @@ impl Frontend { pub fn parse_str(source: &str) -> Result { Frontend::new().parse(source) } - -impl crate::StorageFormat { - const fn to_wgsl(self) -> &'static str { - use crate::StorageFormat as Sf; - match self { - Sf::R8Unorm => "r8unorm", - Sf::R8Snorm => "r8snorm", - Sf::R8Uint => "r8uint", - Sf::R8Sint => "r8sint", - Sf::R16Uint => "r16uint", - Sf::R16Sint => "r16sint", - Sf::R16Float => "r16float", - Sf::Rg8Unorm => "rg8unorm", - Sf::Rg8Snorm => "rg8snorm", - Sf::Rg8Uint => "rg8uint", - Sf::Rg8Sint => "rg8sint", - Sf::R32Uint => "r32uint", - Sf::R32Sint => "r32sint", - Sf::R32Float => "r32float", - Sf::Rg16Uint => "rg16uint", - Sf::Rg16Sint => "rg16sint", - Sf::Rg16Float => "rg16float", - Sf::Rgba8Unorm => "rgba8unorm", - Sf::Rgba8Snorm => "rgba8snorm", - Sf::Rgba8Uint => "rgba8uint", - Sf::Rgba8Sint => "rgba8sint", - Sf::Bgra8Unorm => "bgra8unorm", - Sf::Rgb10a2Uint => "rgb10a2uint", - Sf::Rgb10a2Unorm => "rgb10a2unorm", - Sf::Rg11b10Float => "rg11b10float", - Sf::Rg32Uint => "rg32uint", - Sf::Rg32Sint => "rg32sint", - Sf::Rg32Float => "rg32float", - Sf::Rgba16Uint => "rgba16uint", - Sf::Rgba16Sint => "rgba16sint", - Sf::Rgba16Float => "rgba16float", - Sf::Rgba32Uint => "rgba32uint", - Sf::Rgba32Sint => "rgba32sint", - Sf::Rgba32Float => "rgba32float", - Sf::R16Unorm => "r16unorm", - Sf::R16Snorm => "r16snorm", - Sf::Rg16Unorm => "rg16unorm", - Sf::Rg16Snorm => "rg16snorm", - Sf::Rgba16Unorm => "rgba16unorm", - Sf::Rgba16Snorm => "rgba16snorm", - } - } -} - -impl crate::TypeInner { - /// Formats the type as it is written in wgsl. - /// - /// For example `vec3`. - /// - /// Note: The names of a `TypeInner::Struct` is not known. Therefore this method will simply return "struct" for them. - fn to_wgsl(&self, gctx: crate::proc::GlobalCtx) -> String { - use crate::TypeInner as Ti; - - match *self { - Ti::Scalar { kind, width } => kind.to_wgsl(width), - Ti::Vector { size, kind, width } => { - format!("vec{}<{}>", size as u32, kind.to_wgsl(width)) - } - Ti::Matrix { - columns, - rows, - width, - } => { - format!( - "mat{}x{}<{}>", - columns as u32, - rows as u32, - crate::ScalarKind::Float.to_wgsl(width), - ) - } - Ti::Atomic { kind, width } => { - format!("atomic<{}>", kind.to_wgsl(width)) - } - Ti::Pointer { base, .. } => { - let base = &gctx.types[base]; - let name = base.name.as_deref().unwrap_or("unknown"); - format!("ptr<{name}>") - } - Ti::ValuePointer { kind, width, .. } => { - format!("ptr<{}>", kind.to_wgsl(width)) - } - Ti::Array { base, size, .. } => { - let member_type = &gctx.types[base]; - let base = member_type.name.as_deref().unwrap_or("unknown"); - match size { - crate::ArraySize::Constant(size) => format!("array<{base}, {size}>"), - crate::ArraySize::Dynamic => format!("array<{base}>"), - } - } - Ti::Struct { .. } => { - // TODO: Actually output the struct? - "struct".to_string() - } - Ti::Image { - dim, - arrayed, - class, - } => { - let dim_suffix = match dim { - crate::ImageDimension::D1 => "_1d", - crate::ImageDimension::D2 => "_2d", - crate::ImageDimension::D3 => "_3d", - crate::ImageDimension::Cube => "_cube", - }; - let array_suffix = if arrayed { "_array" } else { "" }; - - let class_suffix = match class { - crate::ImageClass::Sampled { multi: true, .. } => "_multisampled", - crate::ImageClass::Depth { multi: false } => "_depth", - crate::ImageClass::Depth { multi: true } => "_depth_multisampled", - crate::ImageClass::Sampled { multi: false, .. } - | crate::ImageClass::Storage { .. } => "", - }; - - let type_in_brackets = match class { - crate::ImageClass::Sampled { kind, .. } => { - // Note: The only valid widths are 4 bytes wide. - // The lexer has already verified this, so we can safely assume it here. - // https://gpuweb.github.io/gpuweb/wgsl/#sampled-texture-type - let element_type = kind.to_wgsl(4); - format!("<{element_type}>") - } - crate::ImageClass::Depth { multi: _ } => String::new(), - crate::ImageClass::Storage { format, access } => { - if access.contains(crate::StorageAccess::STORE) { - format!("<{},write>", format.to_wgsl()) - } else { - format!("<{}>", format.to_wgsl()) - } - } - }; - - format!("texture{class_suffix}{dim_suffix}{array_suffix}{type_in_brackets}") - } - Ti::Sampler { .. } => "sampler".to_string(), - Ti::AccelerationStructure => "acceleration_structure".to_string(), - Ti::RayQuery => "ray_query".to_string(), - Ti::BindingArray { base, size, .. } => { - let member_type = &gctx.types[base]; - let base = member_type.name.as_deref().unwrap_or("unknown"); - match size { - crate::ArraySize::Constant(size) => format!("binding_array<{base}, {size}>"), - crate::ArraySize::Dynamic => format!("binding_array<{base}>"), - } - } - } - } -} - -mod type_inner_tests { - - #[test] - fn to_wgsl() { - use std::num::NonZeroU32; - - let mut types = crate::UniqueArena::new(); - - let mytype1 = types.insert( - crate::Type { - name: Some("MyType1".to_string()), - inner: crate::TypeInner::Struct { - members: vec![], - span: 0, - }, - }, - Default::default(), - ); - let mytype2 = types.insert( - crate::Type { - name: Some("MyType2".to_string()), - inner: crate::TypeInner::Struct { - members: vec![], - span: 0, - }, - }, - Default::default(), - ); - - let gctx = crate::proc::GlobalCtx { - types: &types, - constants: &crate::Arena::new(), - const_expressions: &crate::Arena::new(), - }; - let array = crate::TypeInner::Array { - base: mytype1, - stride: 4, - size: crate::ArraySize::Constant(unsafe { NonZeroU32::new_unchecked(32) }), - }; - assert_eq!(array.to_wgsl(gctx), "array"); - - let mat = crate::TypeInner::Matrix { - rows: crate::VectorSize::Quad, - columns: crate::VectorSize::Bi, - width: 8, - }; - assert_eq!(mat.to_wgsl(gctx), "mat2x4"); - - let ptr = crate::TypeInner::Pointer { - base: mytype2, - space: crate::AddressSpace::Storage { - access: crate::StorageAccess::default(), - }, - }; - assert_eq!(ptr.to_wgsl(gctx), "ptr"); - - let img1 = crate::TypeInner::Image { - dim: crate::ImageDimension::D2, - arrayed: false, - class: crate::ImageClass::Sampled { - kind: crate::ScalarKind::Float, - multi: true, - }, - }; - assert_eq!(img1.to_wgsl(gctx), "texture_multisampled_2d"); - - let img2 = crate::TypeInner::Image { - dim: crate::ImageDimension::Cube, - arrayed: true, - class: crate::ImageClass::Depth { multi: false }, - }; - assert_eq!(img2.to_wgsl(gctx), "texture_depth_cube_array"); - - let img3 = crate::TypeInner::Image { - dim: crate::ImageDimension::D2, - arrayed: false, - class: crate::ImageClass::Depth { multi: true }, - }; - assert_eq!(img3.to_wgsl(gctx), "texture_depth_multisampled_2d"); - - let array = crate::TypeInner::BindingArray { - base: mytype1, - size: crate::ArraySize::Constant(unsafe { NonZeroU32::new_unchecked(32) }), - }; - assert_eq!(array.to_wgsl(gctx), "binding_array"); - } -} - -impl crate::ScalarKind { - /// Format a scalar kind+width as a type is written in wgsl. - /// - /// Examples: `f32`, `u64`, `bool`. - fn to_wgsl(self, width: u8) -> String { - let prefix = match self { - crate::ScalarKind::Sint => "i", - crate::ScalarKind::Uint => "u", - crate::ScalarKind::Float => "f", - crate::ScalarKind::Bool => return "bool".to_string(), - }; - format!("{}{}", prefix, width * 8) - } -} diff --git a/naga/src/front/wgsl/parse/ast.rs b/naga/src/front/wgsl/parse/ast.rs index 6c3571822a7..72771c44edf 100644 --- a/naga/src/front/wgsl/parse/ast.rs +++ b/naga/src/front/wgsl/parse/ast.rs @@ -1,4 +1,5 @@ use crate::front::wgsl::parse::number::Number; +use crate::front::wgsl::Scalar; use crate::{Arena, FastIndexSet, Handle, Span}; use std::hash::Hash; @@ -212,24 +213,17 @@ pub enum ArraySize<'a> { #[derive(Debug)] pub enum Type<'a> { - Scalar { - kind: crate::ScalarKind, - width: crate::Bytes, - }, + Scalar(Scalar), Vector { size: crate::VectorSize, - kind: crate::ScalarKind, - width: crate::Bytes, + scalar: Scalar, }, Matrix { columns: crate::VectorSize, rows: crate::VectorSize, width: crate::Bytes, }, - Atomic { - kind: crate::ScalarKind, - width: crate::Bytes, - }, + Atomic(Scalar), Pointer { base: Handle>, space: crate::AddressSpace, @@ -344,10 +338,7 @@ pub struct SwitchCase<'a> { #[derive(Debug)] pub enum ConstructorType<'a> { /// A scalar type or conversion: `f32(1)`. - Scalar { - kind: crate::ScalarKind, - width: crate::Bytes, - }, + Scalar(Scalar), /// A vector construction whose component type is inferred from the /// argument: `vec3(1.0)`. @@ -357,8 +348,7 @@ pub enum ConstructorType<'a> { /// `vec3(1.0)`. Vector { size: crate::VectorSize, - kind: crate::ScalarKind, - width: crate::Bytes, + scalar: Scalar, }, /// A matrix construction whose component type is inferred from the diff --git a/naga/src/front/wgsl/parse/conv.rs b/naga/src/front/wgsl/parse/conv.rs index 51977173d6b..08f1e392857 100644 --- a/naga/src/front/wgsl/parse/conv.rs +++ b/naga/src/front/wgsl/parse/conv.rs @@ -1,4 +1,5 @@ use super::Error; +use crate::front::wgsl::Scalar; use crate::Span; pub fn map_address_space(word: &str, span: Span) -> Result> { @@ -103,14 +104,30 @@ pub fn map_storage_format(word: &str, span: Span) -> Result Option<(crate::ScalarKind, crate::Bytes)> { +pub fn get_scalar_type(word: &str) -> Option { + use crate::ScalarKind as Sk; match word { - // "f16" => Some((crate::ScalarKind::Float, 2)), - "f32" => Some((crate::ScalarKind::Float, 4)), - "f64" => Some((crate::ScalarKind::Float, 8)), - "i32" => Some((crate::ScalarKind::Sint, 4)), - "u32" => Some((crate::ScalarKind::Uint, 4)), - "bool" => Some((crate::ScalarKind::Bool, crate::BOOL_WIDTH)), + // "f16" => Some(Scalar { kind: Sk::Float, width: 2 }), + "f32" => Some(Scalar { + kind: Sk::Float, + width: 4, + }), + "f64" => Some(Scalar { + kind: Sk::Float, + width: 8, + }), + "i32" => Some(Scalar { + kind: Sk::Sint, + width: 4, + }), + "u32" => Some(Scalar { + kind: Sk::Uint, + width: 4, + }), + "bool" => Some(Scalar { + kind: Sk::Bool, + width: crate::BOOL_WIDTH, + }), _ => None, } } diff --git a/naga/src/front/wgsl/parse/lexer.rs b/naga/src/front/wgsl/parse/lexer.rs index fce6c2e415b..fd87e54ad99 100644 --- a/naga/src/front/wgsl/parse/lexer.rs +++ b/naga/src/front/wgsl/parse/lexer.rs @@ -1,6 +1,7 @@ use super::{number::consume_number, Error, ExpectedToken}; use crate::front::wgsl::error::NumberError; use crate::front::wgsl::parse::{conv, Number}; +use crate::front::wgsl::Scalar; use crate::Span; type TokenSpan<'a> = (Token<'a>, Span); @@ -382,9 +383,7 @@ impl<'a> Lexer<'a> { } /// Parses a generic scalar type, for example ``. - pub(in crate::front::wgsl) fn next_scalar_generic( - &mut self, - ) -> Result<(crate::ScalarKind, crate::Bytes), Error<'a>> { + pub(in crate::front::wgsl) fn next_scalar_generic(&mut self) -> Result> { self.expect_generic_paren('<')?; let pair = match self.next() { (Token::Word(word), span) => { @@ -401,11 +400,11 @@ impl<'a> Lexer<'a> { /// Returns the span covering the inner type, excluding the brackets. pub(in crate::front::wgsl) fn next_scalar_generic_with_span( &mut self, - ) -> Result<(crate::ScalarKind, crate::Bytes, Span), Error<'a>> { + ) -> Result<(Scalar, Span), Error<'a>> { self.expect_generic_paren('<')?; let pair = match self.next() { (Token::Word(word), span) => conv::get_scalar_type(word) - .map(|(a, b)| (a, b, span)) + .map(|scalar| (scalar, span)) .ok_or(Error::UnknownScalarType(span)), (_, span) => Err(Error::UnknownScalarType(span)), }?; diff --git a/naga/src/front/wgsl/parse/mod.rs b/naga/src/front/wgsl/parse/mod.rs index 12a20e7beba..312ee34e698 100644 --- a/naga/src/front/wgsl/parse/mod.rs +++ b/naga/src/front/wgsl/parse/mod.rs @@ -1,6 +1,7 @@ use crate::front::wgsl::error::{Error, ExpectedToken}; use crate::front::wgsl::parse::lexer::{Lexer, Token}; use crate::front::wgsl::parse::number::Number; +use crate::front::wgsl::Scalar; use crate::front::SymbolTable; use crate::{Arena, FastIndexSet, Handle, ShaderStage, Span}; @@ -277,8 +278,8 @@ impl Parser { span: Span, ctx: &mut ExpressionContext<'a, '_, '_>, ) -> Result>, Error<'a>> { - if let Some((kind, width)) = conv::get_scalar_type(word) { - return Ok(Some(ast::ConstructorType::Scalar { kind, width })); + if let Some(scalar) = conv::get_scalar_type(word) { + return Ok(Some(ast::ConstructorType::Scalar(scalar))); } let partial = match word { @@ -288,22 +289,25 @@ impl Parser { "vec2i" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Bi, - kind: crate::ScalarKind::Sint, - width: 4, + scalar: Scalar { + kind: crate::ScalarKind::Sint, + width: 4, + }, })) } "vec2u" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Bi, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: Scalar { + kind: crate::ScalarKind::Uint, + width: 4, + }, })) } "vec2f" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Bi, - kind: crate::ScalarKind::Float, - width: 4, + scalar: Scalar::F32, })) } "vec3" => ast::ConstructorType::PartialVector { @@ -312,22 +316,19 @@ impl Parser { "vec3i" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Tri, - kind: crate::ScalarKind::Sint, - width: 4, + scalar: Scalar::I32, })) } "vec3u" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Tri, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: Scalar::U32, })) } "vec3f" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Tri, - kind: crate::ScalarKind::Float, - width: 4, + scalar: Scalar::F32, })) } "vec4" => ast::ConstructorType::PartialVector { @@ -336,22 +337,19 @@ impl Parser { "vec4i" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Quad, - kind: crate::ScalarKind::Sint, - width: 4, + scalar: Scalar::I32, })) } "vec4u" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Quad, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: Scalar::U32, })) } "vec4f" => { return Ok(Some(ast::ConstructorType::Vector { size: crate::VectorSize::Quad, - kind: crate::ScalarKind::Float, - width: 4, + scalar: Scalar::F32, })) } "mat2x2" => ast::ConstructorType::PartialMatrix { @@ -483,18 +481,18 @@ impl Parser { // parse component type if present match (lexer.peek().0, partial) { (Token::Paren('<'), ast::ConstructorType::PartialVector { size }) => { - let (kind, width) = lexer.next_scalar_generic()?; - Ok(Some(ast::ConstructorType::Vector { size, kind, width })) + let scalar = lexer.next_scalar_generic()?; + Ok(Some(ast::ConstructorType::Vector { size, scalar })) } (Token::Paren('<'), ast::ConstructorType::PartialMatrix { columns, rows }) => { - let (kind, width, span) = lexer.next_scalar_generic_with_span()?; - match kind { + let (scalar, span) = lexer.next_scalar_generic_with_span()?; + match scalar.kind { crate::ScalarKind::Float => Ok(Some(ast::ConstructorType::Matrix { columns, rows, - width, + width: scalar.width, })), - _ => Err(Error::BadMatrixScalarKind(span, kind, width)), + _ => Err(Error::BadMatrixScalarKind(span, scalar)), } } (Token::Paren('<'), ast::ConstructorType::PartialArray) => { @@ -1049,14 +1047,14 @@ impl Parser { columns: crate::VectorSize, rows: crate::VectorSize, ) -> Result, Error<'a>> { - let (kind, width, span) = lexer.next_scalar_generic_with_span()?; - match kind { + let (scalar, span) = lexer.next_scalar_generic_with_span()?; + match scalar.kind { crate::ScalarKind::Float => Ok(ast::Type::Matrix { columns, rows, - width, + width: scalar.width, }), - _ => Err(Error::BadMatrixScalarKind(span, kind, width)), + _ => Err(Error::BadMatrixScalarKind(span, scalar)), } } @@ -1066,79 +1064,85 @@ impl Parser { word: &'a str, ctx: &mut ExpressionContext<'a, '_, '_>, ) -> Result>, Error<'a>> { - if let Some((kind, width)) = conv::get_scalar_type(word) { - return Ok(Some(ast::Type::Scalar { kind, width })); + if let Some(scalar) = conv::get_scalar_type(word) { + return Ok(Some(ast::Type::Scalar(scalar))); } Ok(Some(match word { "vec2" => { - let (kind, width) = lexer.next_scalar_generic()?; + let scalar = lexer.next_scalar_generic()?; ast::Type::Vector { size: crate::VectorSize::Bi, - kind, - width, + scalar, } } "vec2i" => ast::Type::Vector { size: crate::VectorSize::Bi, - kind: crate::ScalarKind::Sint, - width: 4, + scalar: Scalar { + kind: crate::ScalarKind::Sint, + width: 4, + }, }, "vec2u" => ast::Type::Vector { size: crate::VectorSize::Bi, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: Scalar { + kind: crate::ScalarKind::Uint, + width: 4, + }, }, "vec2f" => ast::Type::Vector { size: crate::VectorSize::Bi, - kind: crate::ScalarKind::Float, - width: 4, + scalar: Scalar::F32, }, "vec3" => { - let (kind, width) = lexer.next_scalar_generic()?; + let scalar = lexer.next_scalar_generic()?; ast::Type::Vector { size: crate::VectorSize::Tri, - kind, - width, + scalar, } } "vec3i" => ast::Type::Vector { size: crate::VectorSize::Tri, - kind: crate::ScalarKind::Sint, - width: 4, + scalar: Scalar { + kind: crate::ScalarKind::Sint, + width: 4, + }, }, "vec3u" => ast::Type::Vector { size: crate::VectorSize::Tri, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: Scalar { + kind: crate::ScalarKind::Uint, + width: 4, + }, }, "vec3f" => ast::Type::Vector { size: crate::VectorSize::Tri, - kind: crate::ScalarKind::Float, - width: 4, + scalar: Scalar::F32, }, "vec4" => { - let (kind, width) = lexer.next_scalar_generic()?; + let scalar = lexer.next_scalar_generic()?; ast::Type::Vector { size: crate::VectorSize::Quad, - kind, - width, + scalar, } } "vec4i" => ast::Type::Vector { size: crate::VectorSize::Quad, - kind: crate::ScalarKind::Sint, - width: 4, + scalar: Scalar { + kind: crate::ScalarKind::Sint, + width: 4, + }, }, "vec4u" => ast::Type::Vector { size: crate::VectorSize::Quad, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: Scalar { + kind: crate::ScalarKind::Uint, + width: 4, + }, }, "vec4f" => ast::Type::Vector { size: crate::VectorSize::Quad, - kind: crate::ScalarKind::Float, - width: 4, + scalar: Scalar::F32, }, "mat2x2" => { self.matrix_scalar_type(lexer, crate::VectorSize::Bi, crate::VectorSize::Bi)? @@ -1213,8 +1217,8 @@ impl Parser { width: 4, }, "atomic" => { - let (kind, width) = lexer.next_scalar_generic()?; - ast::Type::Atomic { kind, width } + let scalar = lexer.next_scalar_generic()?; + ast::Type::Atomic(scalar) } "ptr" => { lexer.expect_generic_paren('<')?; @@ -1261,84 +1265,111 @@ impl Parser { "sampler" => ast::Type::Sampler { comparison: false }, "sampler_comparison" => ast::Type::Sampler { comparison: true }, "texture_1d" => { - let (kind, width, span) = lexer.next_scalar_generic_with_span()?; - Self::check_texture_sample_type(kind, width, span)?; + let (scalar, span) = lexer.next_scalar_generic_with_span()?; + Self::check_texture_sample_type(scalar, span)?; ast::Type::Image { dim: crate::ImageDimension::D1, arrayed: false, - class: crate::ImageClass::Sampled { kind, multi: false }, + class: crate::ImageClass::Sampled { + kind: scalar.kind, + multi: false, + }, } } "texture_1d_array" => { - let (kind, width, span) = lexer.next_scalar_generic_with_span()?; - Self::check_texture_sample_type(kind, width, span)?; + let (scalar, span) = lexer.next_scalar_generic_with_span()?; + Self::check_texture_sample_type(scalar, span)?; ast::Type::Image { dim: crate::ImageDimension::D1, arrayed: true, - class: crate::ImageClass::Sampled { kind, multi: false }, + class: crate::ImageClass::Sampled { + kind: scalar.kind, + multi: false, + }, } } "texture_2d" => { - let (kind, width, span) = lexer.next_scalar_generic_with_span()?; - Self::check_texture_sample_type(kind, width, span)?; + let (scalar, span) = lexer.next_scalar_generic_with_span()?; + Self::check_texture_sample_type(scalar, span)?; ast::Type::Image { dim: crate::ImageDimension::D2, arrayed: false, - class: crate::ImageClass::Sampled { kind, multi: false }, + class: crate::ImageClass::Sampled { + kind: scalar.kind, + multi: false, + }, } } "texture_2d_array" => { - let (kind, width, span) = lexer.next_scalar_generic_with_span()?; - Self::check_texture_sample_type(kind, width, span)?; + let (scalar, span) = lexer.next_scalar_generic_with_span()?; + Self::check_texture_sample_type(scalar, span)?; ast::Type::Image { dim: crate::ImageDimension::D2, arrayed: true, - class: crate::ImageClass::Sampled { kind, multi: false }, + class: crate::ImageClass::Sampled { + kind: scalar.kind, + multi: false, + }, } } "texture_3d" => { - let (kind, width, span) = lexer.next_scalar_generic_with_span()?; - Self::check_texture_sample_type(kind, width, span)?; + let (scalar, span) = lexer.next_scalar_generic_with_span()?; + Self::check_texture_sample_type(scalar, span)?; ast::Type::Image { dim: crate::ImageDimension::D3, arrayed: false, - class: crate::ImageClass::Sampled { kind, multi: false }, + class: crate::ImageClass::Sampled { + kind: scalar.kind, + multi: false, + }, } } "texture_cube" => { - let (kind, width, span) = lexer.next_scalar_generic_with_span()?; - Self::check_texture_sample_type(kind, width, span)?; + let (scalar, span) = lexer.next_scalar_generic_with_span()?; + Self::check_texture_sample_type(scalar, span)?; ast::Type::Image { dim: crate::ImageDimension::Cube, arrayed: false, - class: crate::ImageClass::Sampled { kind, multi: false }, + class: crate::ImageClass::Sampled { + kind: scalar.kind, + multi: false, + }, } } "texture_cube_array" => { - let (kind, width, span) = lexer.next_scalar_generic_with_span()?; - Self::check_texture_sample_type(kind, width, span)?; + let (scalar, span) = lexer.next_scalar_generic_with_span()?; + Self::check_texture_sample_type(scalar, span)?; ast::Type::Image { dim: crate::ImageDimension::Cube, arrayed: true, - class: crate::ImageClass::Sampled { kind, multi: false }, + class: crate::ImageClass::Sampled { + kind: scalar.kind, + multi: false, + }, } } "texture_multisampled_2d" => { - let (kind, width, span) = lexer.next_scalar_generic_with_span()?; - Self::check_texture_sample_type(kind, width, span)?; + let (scalar, span) = lexer.next_scalar_generic_with_span()?; + Self::check_texture_sample_type(scalar, span)?; ast::Type::Image { dim: crate::ImageDimension::D2, arrayed: false, - class: crate::ImageClass::Sampled { kind, multi: true }, + class: crate::ImageClass::Sampled { + kind: scalar.kind, + multi: true, + }, } } "texture_multisampled_2d_array" => { - let (kind, width, span) = lexer.next_scalar_generic_with_span()?; - Self::check_texture_sample_type(kind, width, span)?; + let (scalar, span) = lexer.next_scalar_generic_with_span()?; + Self::check_texture_sample_type(scalar, span)?; ast::Type::Image { dim: crate::ImageDimension::D2, arrayed: true, - class: crate::ImageClass::Sampled { kind, multi: true }, + class: crate::ImageClass::Sampled { + kind: scalar.kind, + multi: true, + }, } } "texture_depth_2d" => ast::Type::Image { @@ -1414,16 +1445,15 @@ impl Parser { })) } - const fn check_texture_sample_type( - kind: crate::ScalarKind, - width: u8, - span: Span, - ) -> Result<(), Error<'static>> { + const fn check_texture_sample_type(scalar: Scalar, span: Span) -> Result<(), Error<'static>> { use crate::ScalarKind::*; // Validate according to https://gpuweb.github.io/gpuweb/wgsl/#sampled-texture-type - match (kind, width) { - (Float | Sint | Uint, 4) => Ok(()), - _ => Err(Error::BadTextureSampleType { span, kind, width }), + match scalar { + Scalar { + kind: Float | Sint | Uint, + width: 4, + } => Ok(()), + _ => Err(Error::BadTextureSampleType { span, scalar }), } } diff --git a/naga/src/front/wgsl/to_wgsl.rs b/naga/src/front/wgsl/to_wgsl.rs new file mode 100644 index 00000000000..7af3debc4c4 --- /dev/null +++ b/naga/src/front/wgsl/to_wgsl.rs @@ -0,0 +1,283 @@ +//! Producing the WGSL forms of types, for use in error messages. + +use crate::proc::GlobalCtx; +use crate::Handle; + +impl crate::proc::TypeResolution { + pub fn to_wgsl(&self, gctx: &GlobalCtx) -> String { + match *self { + crate::proc::TypeResolution::Handle(handle) => handle.to_wgsl(gctx), + crate::proc::TypeResolution::Value(ref inner) => inner.to_wgsl(gctx), + } + } +} + +impl Handle { + /// Formats the type as it is written in wgsl. + /// + /// For example `vec3`. + pub fn to_wgsl(self, gctx: &GlobalCtx) -> String { + let ty = &gctx.types[self]; + match ty.name { + Some(ref name) => name.clone(), + None => ty.inner.to_wgsl(gctx), + } + } +} + +impl crate::TypeInner { + /// Formats the type as it is written in wgsl. + /// + /// For example `vec3`. + /// + /// Note: `TypeInner::Struct` doesn't include the name of the + /// struct type. Therefore this method will simply return "struct" + /// for them. + pub fn to_wgsl(&self, gctx: &GlobalCtx) -> String { + use crate::TypeInner as Ti; + + match *self { + Ti::Scalar(scalar) => scalar.to_wgsl(), + Ti::Vector { size, scalar } => { + format!("vec{}<{}>", size as u32, scalar.to_wgsl()) + } + Ti::Matrix { + columns, + rows, + width, + } => { + format!( + "mat{}x{}<{}>", + columns as u32, + rows as u32, + crate::Scalar::float(width).to_wgsl(), + ) + } + Ti::Atomic(scalar) => { + format!("atomic<{}>", scalar.to_wgsl()) + } + Ti::Pointer { base, .. } => { + let base = &gctx.types[base]; + let name = base.name.as_deref().unwrap_or("unknown"); + format!("ptr<{name}>") + } + Ti::ValuePointer { scalar, .. } => { + format!("ptr<{}>", scalar.to_wgsl()) + } + Ti::Array { base, size, .. } => { + let member_type = &gctx.types[base]; + let base = member_type.name.as_deref().unwrap_or("unknown"); + match size { + crate::ArraySize::Constant(size) => format!("array<{base}, {size}>"), + crate::ArraySize::Dynamic => format!("array<{base}>"), + } + } + Ti::Struct { .. } => { + // TODO: Actually output the struct? + "struct".to_string() + } + Ti::Image { + dim, + arrayed, + class, + } => { + let dim_suffix = match dim { + crate::ImageDimension::D1 => "_1d", + crate::ImageDimension::D2 => "_2d", + crate::ImageDimension::D3 => "_3d", + crate::ImageDimension::Cube => "_cube", + }; + let array_suffix = if arrayed { "_array" } else { "" }; + + let class_suffix = match class { + crate::ImageClass::Sampled { multi: true, .. } => "_multisampled", + crate::ImageClass::Depth { multi: false } => "_depth", + crate::ImageClass::Depth { multi: true } => "_depth_multisampled", + crate::ImageClass::Sampled { multi: false, .. } + | crate::ImageClass::Storage { .. } => "", + }; + + let type_in_brackets = match class { + crate::ImageClass::Sampled { kind, .. } => { + // Note: The only valid widths are 4 bytes wide. + // The lexer has already verified this, so we can safely assume it here. + // https://gpuweb.github.io/gpuweb/wgsl/#sampled-texture-type + let element_type = crate::Scalar { kind, width: 4 }.to_wgsl(); + format!("<{element_type}>") + } + crate::ImageClass::Depth { multi: _ } => String::new(), + crate::ImageClass::Storage { format, access } => { + if access.contains(crate::StorageAccess::STORE) { + format!("<{},write>", format.to_wgsl()) + } else { + format!("<{}>", format.to_wgsl()) + } + } + }; + + format!("texture{class_suffix}{dim_suffix}{array_suffix}{type_in_brackets}") + } + Ti::Sampler { .. } => "sampler".to_string(), + Ti::AccelerationStructure => "acceleration_structure".to_string(), + Ti::RayQuery => "ray_query".to_string(), + Ti::BindingArray { base, size, .. } => { + let member_type = &gctx.types[base]; + let base = member_type.name.as_deref().unwrap_or("unknown"); + match size { + crate::ArraySize::Constant(size) => format!("binding_array<{base}, {size}>"), + crate::ArraySize::Dynamic => format!("binding_array<{base}>"), + } + } + } + } +} + +impl crate::Scalar { + /// Format a scalar kind+width as a type is written in wgsl. + /// + /// Examples: `f32`, `u64`, `bool`. + pub fn to_wgsl(self) -> String { + let prefix = match self.kind { + crate::ScalarKind::Sint => "i", + crate::ScalarKind::Uint => "u", + crate::ScalarKind::Float => "f", + crate::ScalarKind::Bool => return "bool".to_string(), + }; + format!("{}{}", prefix, self.width * 8) + } +} + +impl crate::StorageFormat { + pub const fn to_wgsl(self) -> &'static str { + use crate::StorageFormat as Sf; + match self { + Sf::R8Unorm => "r8unorm", + Sf::R8Snorm => "r8snorm", + Sf::R8Uint => "r8uint", + Sf::R8Sint => "r8sint", + Sf::R16Uint => "r16uint", + Sf::R16Sint => "r16sint", + Sf::R16Float => "r16float", + Sf::Rg8Unorm => "rg8unorm", + Sf::Rg8Snorm => "rg8snorm", + Sf::Rg8Uint => "rg8uint", + Sf::Rg8Sint => "rg8sint", + Sf::R32Uint => "r32uint", + Sf::R32Sint => "r32sint", + Sf::R32Float => "r32float", + Sf::Rg16Uint => "rg16uint", + Sf::Rg16Sint => "rg16sint", + Sf::Rg16Float => "rg16float", + Sf::Rgba8Unorm => "rgba8unorm", + Sf::Rgba8Snorm => "rgba8snorm", + Sf::Rgba8Uint => "rgba8uint", + Sf::Rgba8Sint => "rgba8sint", + Sf::Bgra8Unorm => "bgra8unorm", + Sf::Rgb10a2Uint => "rgb10a2uint", + Sf::Rgb10a2Unorm => "rgb10a2unorm", + Sf::Rg11b10Float => "rg11b10float", + Sf::Rg32Uint => "rg32uint", + Sf::Rg32Sint => "rg32sint", + Sf::Rg32Float => "rg32float", + Sf::Rgba16Uint => "rgba16uint", + Sf::Rgba16Sint => "rgba16sint", + Sf::Rgba16Float => "rgba16float", + Sf::Rgba32Uint => "rgba32uint", + Sf::Rgba32Sint => "rgba32sint", + Sf::Rgba32Float => "rgba32float", + Sf::R16Unorm => "r16unorm", + Sf::R16Snorm => "r16snorm", + Sf::Rg16Unorm => "rg16unorm", + Sf::Rg16Snorm => "rg16snorm", + Sf::Rgba16Unorm => "rgba16unorm", + Sf::Rgba16Snorm => "rgba16snorm", + } + } +} + +mod tests { + #[test] + fn to_wgsl() { + use std::num::NonZeroU32; + + let mut types = crate::UniqueArena::new(); + + let mytype1 = types.insert( + crate::Type { + name: Some("MyType1".to_string()), + inner: crate::TypeInner::Struct { + members: vec![], + span: 0, + }, + }, + Default::default(), + ); + let mytype2 = types.insert( + crate::Type { + name: Some("MyType2".to_string()), + inner: crate::TypeInner::Struct { + members: vec![], + span: 0, + }, + }, + Default::default(), + ); + + let gctx = crate::proc::GlobalCtx { + types: &types, + constants: &crate::Arena::new(), + const_expressions: &crate::Arena::new(), + }; + let array = crate::TypeInner::Array { + base: mytype1, + stride: 4, + size: crate::ArraySize::Constant(unsafe { NonZeroU32::new_unchecked(32) }), + }; + assert_eq!(array.to_wgsl(&gctx), "array"); + + let mat = crate::TypeInner::Matrix { + rows: crate::VectorSize::Quad, + columns: crate::VectorSize::Bi, + width: 8, + }; + assert_eq!(mat.to_wgsl(&gctx), "mat2x4"); + + let ptr = crate::TypeInner::Pointer { + base: mytype2, + space: crate::AddressSpace::Storage { + access: crate::StorageAccess::default(), + }, + }; + assert_eq!(ptr.to_wgsl(&gctx), "ptr"); + + let img1 = crate::TypeInner::Image { + dim: crate::ImageDimension::D2, + arrayed: false, + class: crate::ImageClass::Sampled { + kind: crate::ScalarKind::Float, + multi: true, + }, + }; + assert_eq!(img1.to_wgsl(&gctx), "texture_multisampled_2d"); + + let img2 = crate::TypeInner::Image { + dim: crate::ImageDimension::Cube, + arrayed: true, + class: crate::ImageClass::Depth { multi: false }, + }; + assert_eq!(img2.to_wgsl(&gctx), "texture_depth_cube_array"); + + let img3 = crate::TypeInner::Image { + dim: crate::ImageDimension::D2, + arrayed: false, + class: crate::ImageClass::Depth { multi: true }, + }; + assert_eq!(img3.to_wgsl(&gctx), "texture_depth_multisampled_2d"); + + let array = crate::TypeInner::BindingArray { + base: mytype1, + size: crate::ArraySize::Constant(unsafe { NonZeroU32::new_unchecked(32) }), + }; + assert_eq!(array.to_wgsl(&gctx), "binding_array"); + } +} diff --git a/naga/src/lib.rs b/naga/src/lib.rs index 4b13802465a..31a3813d9b7 100644 --- a/naga/src/lib.rs +++ b/naga/src/lib.rs @@ -472,6 +472,19 @@ pub enum ScalarKind { Bool, } +/// Characteristics of a scalar type. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub struct Scalar { + /// How the value's bits are to be interpreted. + pub kind: ScalarKind, + + /// This size of the value in bytes. + pub width: Bytes, +} + /// Size of an array. #[repr(u8)] #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] @@ -677,13 +690,9 @@ pub struct Type { #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub enum TypeInner { /// Number of integral or floating-point kind. - Scalar { kind: ScalarKind, width: Bytes }, + Scalar(Scalar), /// Vector of numbers. - Vector { - size: VectorSize, - kind: ScalarKind, - width: Bytes, - }, + Vector { size: VectorSize, scalar: Scalar }, /// Matrix of floats. Matrix { columns: VectorSize, @@ -691,7 +700,7 @@ pub enum TypeInner { width: Bytes, }, /// Atomic scalar. - Atomic { kind: ScalarKind, width: Bytes }, + Atomic(Scalar), /// Pointer to another type. /// /// Pointers to scalars and vectors should be treated as equivalent to @@ -737,8 +746,7 @@ pub enum TypeInner { /// [`TypeResolution::Value`]: proc::TypeResolution::Value ValuePointer { size: Option, - kind: ScalarKind, - width: Bytes, + scalar: Scalar, space: AddressSpace, }, @@ -1970,10 +1978,7 @@ pub struct EntryPoint { #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub enum PredeclaredType { - AtomicCompareExchangeWeakResult { - kind: ScalarKind, - width: Bytes, - }, + AtomicCompareExchangeWeakResult(Scalar), ModfResult { size: Option, width: Bytes, diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index a65bbf52021..b9247b3c857 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -404,7 +404,7 @@ impl<'a> ConstantEvaluator<'a> { let expr = self.check_and_get(expr)?; match convert { - Some(width) => self.cast(expr, kind, width, span), + Some(width) => self.cast(expr, crate::Scalar { kind, width }, span), None => Err(ConstantEvaluatorError::NotImplemented( "bitcast built-in function".into(), )), @@ -462,12 +462,11 @@ impl<'a> ConstantEvaluator<'a> { ) -> Result, ConstantEvaluatorError> { match self.expressions[value] { Expression::Literal(literal) => { - let kind = literal.scalar_kind(); - let width = literal.width(); + let scalar = literal.scalar(); let ty = self.types.insert( Type { name: None, - inner: TypeInner::Vector { size, kind, width }, + inner: TypeInner::Vector { size, scalar }, }, span, ); @@ -479,7 +478,7 @@ impl<'a> ConstantEvaluator<'a> { } Expression::ZeroValue(ty) => { let inner = match self.types[ty].inner { - TypeInner::Scalar { kind, width } => TypeInner::Vector { size, kind, width }, + TypeInner::Scalar(scalar) => TypeInner::Vector { size, scalar }, _ => return Err(ConstantEvaluatorError::SplatScalarOnly), }; let res_ty = self.types.insert(Type { name: None, inner }, span); @@ -498,14 +497,10 @@ impl<'a> ConstantEvaluator<'a> { pattern: [crate::SwizzleComponent; 4], ) -> Result, ConstantEvaluatorError> { let mut get_dst_ty = |ty| match self.types[ty].inner { - crate::TypeInner::Vector { - size: _, - kind, - width, - } => Ok(self.types.insert( + crate::TypeInner::Vector { size: _, scalar } => Ok(self.types.insert( Type { name: None, - inner: crate::TypeInner::Vector { size, kind, width }, + inner: crate::TypeInner::Vector { size, scalar }, }, span, )), @@ -611,7 +606,10 @@ impl<'a> ConstantEvaluator<'a> { && matches!( self.types[ty0].inner, crate::TypeInner::Vector { - kind: crate::ScalarKind::Float, + scalar: crate::Scalar { + kind: ScalarKind::Float, + .. + }, .. } ) => @@ -709,7 +707,10 @@ impl<'a> ConstantEvaluator<'a> { && matches!( self.types[ty0].inner, crate::TypeInner::Vector { - kind: crate::ScalarKind::Float, + scalar: crate::Scalar { + kind: ScalarKind::Float, + .. + }, .. } ) => @@ -831,10 +832,10 @@ impl<'a> ConstantEvaluator<'a> { Expression::ZeroValue(ty) if matches!( self.types[ty].inner, - crate::TypeInner::Scalar { - kind: crate::ScalarKind::Uint, + crate::TypeInner::Scalar(crate::Scalar { + kind: ScalarKind::Uint, .. - } + }) ) => { Ok(0) @@ -873,18 +874,17 @@ impl<'a> ConstantEvaluator<'a> { span: Span, ) -> Result, ConstantEvaluatorError> { match self.types[ty].inner { - TypeInner::Scalar { kind, width } => { + TypeInner::Scalar(scalar) => { let expr = Expression::Literal( - Literal::zero(kind, width) - .ok_or(ConstantEvaluatorError::TypeNotConstructible)?, + Literal::zero(scalar).ok_or(ConstantEvaluatorError::TypeNotConstructible)?, ); self.register_evaluated_expr(expr, span) } - TypeInner::Vector { size, kind, width } => { + TypeInner::Vector { size, scalar } => { let scalar_ty = self.types.insert( Type { name: None, - inner: TypeInner::Scalar { kind, width }, + inner: TypeInner::Scalar(scalar), }, span, ); @@ -905,8 +905,7 @@ impl<'a> ConstantEvaluator<'a> { name: None, inner: TypeInner::Vector { size: rows, - kind: ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }, }, span, @@ -943,43 +942,44 @@ impl<'a> ConstantEvaluator<'a> { } } - /// Convert the scalar components of `expr` to `kind` and `target_width`. + /// Convert the scalar components of `expr` to `target`. /// /// Treat `span` as the location of the resulting expression. pub fn cast( &mut self, expr: Handle, - kind: ScalarKind, - target_width: crate::Bytes, + target: crate::Scalar, span: Span, ) -> Result, ConstantEvaluatorError> { + use crate::Scalar as Sc; + let expr = self.eval_zero_value_and_splat(expr, span)?; let expr = match self.expressions[expr] { Expression::Literal(literal) => { - let literal = match (kind, target_width) { - (ScalarKind::Sint, 4) => Literal::I32(match literal { + let literal = match target { + Sc::I32 => Literal::I32(match literal { Literal::I32(v) => v, Literal::U32(v) => v as i32, Literal::F32(v) => v as i32, Literal::Bool(v) => v as i32, Literal::F64(_) => return Err(ConstantEvaluatorError::InvalidCastArg), }), - (ScalarKind::Uint, 4) => Literal::U32(match literal { + Sc::U32 => Literal::U32(match literal { Literal::I32(v) => v as u32, Literal::U32(v) => v, Literal::F32(v) => v as u32, Literal::Bool(v) => v as u32, Literal::F64(_) => return Err(ConstantEvaluatorError::InvalidCastArg), }), - (ScalarKind::Float, 4) => Literal::F32(match literal { + Sc::F32 => Literal::F32(match literal { Literal::I32(v) => v as f32, Literal::U32(v) => v as f32, Literal::F32(v) => v, Literal::Bool(v) => v as u32 as f32, Literal::F64(_) => return Err(ConstantEvaluatorError::InvalidCastArg), }), - (ScalarKind::Bool, crate::BOOL_WIDTH) => Literal::Bool(match literal { + Sc::BOOL => Literal::Bool(match literal { Literal::I32(v) => v != 0, Literal::U32(v) => v != 0, Literal::F32(v) => v != 0.0, @@ -997,20 +997,19 @@ impl<'a> ConstantEvaluator<'a> { let ty_inner = match self.types[ty].inner { TypeInner::Vector { size, .. } => TypeInner::Vector { size, - kind, - width: target_width, + scalar: target, }, TypeInner::Matrix { columns, rows, .. } => TypeInner::Matrix { columns, rows, - width: target_width, + width: target.width, }, _ => return Err(ConstantEvaluatorError::InvalidCastArg), }; let mut components = src_components.clone(); for component in &mut components { - *component = self.cast(*component, kind, target_width, span)?; + *component = self.cast(*component, target, span)?; } let ty = self.types.insert( @@ -1305,10 +1304,7 @@ mod tests { let scalar_ty = types.insert( Type { name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Sint, - width: 4, - }, + inner: TypeInner::Scalar(crate::Scalar::I32), }, Default::default(), ); @@ -1318,8 +1314,7 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Bi, - kind: ScalarKind::Sint, - width: 4, + scalar: crate::Scalar::I32, }, }, Default::default(), @@ -1441,10 +1436,7 @@ mod tests { let scalar_ty = types.insert( Type { name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Sint, - width: 4, - }, + inner: TypeInner::Scalar(crate::Scalar::I32), }, Default::default(), ); @@ -1509,8 +1501,7 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Tri, - kind: ScalarKind::Float, - width: 4, + scalar: crate::Scalar::F32, }, }, Default::default(), @@ -1649,10 +1640,7 @@ mod tests { let i32_ty = types.insert( Type { name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Sint, - width: 4, - }, + inner: TypeInner::Scalar(crate::Scalar::I32), }, Default::default(), ); @@ -1662,8 +1650,7 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Bi, - kind: ScalarKind::Sint, - width: 4, + scalar: crate::Scalar::I32, }, }, Default::default(), @@ -1733,10 +1720,7 @@ mod tests { let i32_ty = types.insert( Type { name: None, - inner: TypeInner::Scalar { - kind: ScalarKind::Sint, - width: 4, - }, + inner: TypeInner::Scalar(crate::Scalar::I32), }, Default::default(), ); @@ -1746,8 +1730,7 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Bi, - kind: ScalarKind::Sint, - width: 4, + scalar: crate::Scalar::I32, }, }, Default::default(), diff --git a/naga/src/proc/layouter.rs b/naga/src/proc/layouter.rs index 4c52e5ec81e..9ac8d069433 100644 --- a/naga/src/proc/layouter.rs +++ b/naga/src/proc/layouter.rs @@ -171,17 +171,16 @@ impl Layouter { for (ty_handle, ty) in gctx.types.iter().skip(self.layouts.len()) { let size = ty.inner.size(gctx); let layout = match ty.inner { - Ti::Scalar { width, .. } | Ti::Atomic { width, .. } => { - let alignment = Alignment::new(width as u32) + Ti::Scalar(scalar) | Ti::Atomic(scalar) => { + let alignment = Alignment::new(scalar.width as u32) .ok_or(LayoutErrorInner::NonPowerOfTwoWidth.with(ty_handle))?; TypeLayout { size, alignment } } Ti::Vector { size: vec_size, - width, - .. + scalar, } => { - let alignment = Alignment::new(width as u32) + let alignment = Alignment::new(scalar.width as u32) .ok_or(LayoutErrorInner::NonPowerOfTwoWidth.with(ty_handle))?; TypeLayout { size, diff --git a/naga/src/proc/mod.rs b/naga/src/proc/mod.rs index 8a67610587f..89d49528a74 100644 --- a/naga/src/proc/mod.rs +++ b/naga/src/proc/mod.rs @@ -77,6 +77,52 @@ impl super::ScalarKind { } } +impl super::Scalar { + pub const I32: Self = Self { + kind: crate::ScalarKind::Sint, + width: 4, + }; + pub const U32: Self = Self { + kind: crate::ScalarKind::Uint, + width: 4, + }; + pub const F32: Self = Self { + kind: crate::ScalarKind::Float, + width: 4, + }; + pub const F64: Self = Self { + kind: crate::ScalarKind::Float, + width: 8, + }; + pub const BOOL: Self = Self { + kind: crate::ScalarKind::Bool, + width: crate::BOOL_WIDTH, + }; + + /// Construct a float `Scalar` with the given width. + /// + /// This is especially common when dealing with + /// `TypeInner::Matrix`, where the scalar kind is implicit. + pub const fn float(width: crate::Bytes) -> Self { + Self { + kind: crate::ScalarKind::Float, + width, + } + } + + pub const fn to_inner_scalar(self) -> crate::TypeInner { + crate::TypeInner::Scalar(self) + } + + pub const fn to_inner_vector(self, size: crate::VectorSize) -> crate::TypeInner { + crate::TypeInner::Vector { size, scalar: self } + } + + pub const fn to_inner_atomic(self) -> crate::TypeInner { + crate::TypeInner::Atomic(self) + } +} + impl PartialEq for crate::Literal { fn eq(&self, other: &Self) -> bool { match (*self, *other) { @@ -118,8 +164,8 @@ impl std::hash::Hash for crate::Literal { } impl crate::Literal { - pub const fn new(value: u8, kind: crate::ScalarKind, width: crate::Bytes) -> Option { - match (value, kind, width) { + pub const fn new(value: u8, scalar: crate::Scalar) -> Option { + match (value, scalar.kind, scalar.width) { (value, crate::ScalarKind::Float, 8) => Some(Self::F64(value as _)), (value, crate::ScalarKind::Float, 4) => Some(Self::F32(value as _)), (value, crate::ScalarKind::Uint, 4) => Some(Self::U32(value as _)), @@ -130,12 +176,12 @@ impl crate::Literal { } } - pub const fn zero(kind: crate::ScalarKind, width: crate::Bytes) -> Option { - Self::new(0, kind, width) + pub const fn zero(scalar: crate::Scalar) -> Option { + Self::new(0, scalar) } - pub const fn one(kind: crate::ScalarKind, width: crate::Bytes) -> Option { - Self::new(1, kind, width) + pub const fn one(scalar: crate::Scalar) -> Option { + Self::new(1, scalar) } pub const fn width(&self) -> crate::Bytes { @@ -145,44 +191,41 @@ impl crate::Literal { Self::Bool(_) => 1, } } - pub const fn scalar_kind(&self) -> crate::ScalarKind { + pub const fn scalar(&self) -> crate::Scalar { match *self { - Self::F64(_) | Self::F32(_) => crate::ScalarKind::Float, - Self::U32(_) => crate::ScalarKind::Uint, - Self::I32(_) => crate::ScalarKind::Sint, - Self::Bool(_) => crate::ScalarKind::Bool, + Self::F64(_) => crate::Scalar::F64, + Self::F32(_) => crate::Scalar::F32, + Self::U32(_) => crate::Scalar::U32, + Self::I32(_) => crate::Scalar::I32, + Self::Bool(_) => crate::Scalar::BOOL, } } + pub const fn scalar_kind(&self) -> crate::ScalarKind { + self.scalar().kind + } pub const fn ty_inner(&self) -> crate::TypeInner { - crate::TypeInner::Scalar { - kind: self.scalar_kind(), - width: self.width(), - } + crate::TypeInner::Scalar(self.scalar()) } } pub const POINTER_SPAN: u32 = 4; impl super::TypeInner { - pub const fn scalar_kind(&self) -> Option { + pub const fn scalar(&self) -> Option { + use crate::TypeInner as Ti; match *self { - super::TypeInner::Scalar { kind, .. } | super::TypeInner::Vector { kind, .. } => { - Some(kind) - } - super::TypeInner::Matrix { .. } => Some(super::ScalarKind::Float), + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => Some(scalar), + Ti::Matrix { width, .. } => Some(super::Scalar::float(width)), _ => None, } } - pub const fn scalar_width(&self) -> Option { - // Multiply by 8 to get the bit width - match *self { - super::TypeInner::Scalar { width, .. } | super::TypeInner::Vector { width, .. } => { - Some(width * 8) - } - super::TypeInner::Matrix { width, .. } => Some(width * 8), - _ => None, - } + pub fn scalar_kind(&self) -> Option { + self.scalar().map(|scalar| scalar.kind) + } + + pub fn scalar_width(&self) -> Option { + self.scalar().map(|scalar| scalar.width * 8) } pub const fn pointer_space(&self) -> Option { @@ -206,12 +249,8 @@ impl super::TypeInner { /// Get the size of this type. pub fn size(&self, _gctx: GlobalCtx) -> u32 { match *self { - Self::Scalar { kind: _, width } | Self::Atomic { kind: _, width } => width as u32, - Self::Vector { - size, - kind: _, - width, - } => size as u32 * width as u32, + Self::Scalar(scalar) | Self::Atomic(scalar) => scalar.width as u32, + Self::Vector { size, scalar } => size as u32 * scalar.width as u32, // matrices are treated as arrays of aligned columns Self::Matrix { columns, @@ -255,16 +294,14 @@ impl super::TypeInner { use crate::TypeInner as Ti; match *self { Ti::Pointer { base, space } => match types[base].inner { - Ti::Scalar { kind, width } => Some(Ti::ValuePointer { + Ti::Scalar(scalar) => Some(Ti::ValuePointer { size: None, - kind, - width, + scalar, space, }), - Ti::Vector { size, kind, width } => Some(Ti::ValuePointer { + Ti::Vector { size, scalar } => Some(Ti::ValuePointer { size: Some(size), - kind, - width, + scalar, space, }), _ => None, @@ -318,13 +355,10 @@ impl super::TypeInner { pub fn component_type(&self, index: usize) -> Option { Some(match *self { - Self::Vector { kind, width, .. } => { - TypeResolution::Value(crate::TypeInner::Scalar { kind, width }) - } + Self::Vector { scalar, .. } => TypeResolution::Value(crate::TypeInner::Scalar(scalar)), Self::Matrix { rows, width, .. } => TypeResolution::Value(crate::TypeInner::Vector { size: rows, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }), Self::Array { base, @@ -628,7 +662,7 @@ impl GlobalCtx<'_> { match arena[handle] { crate::Expression::Literal(literal) => Some(literal), crate::Expression::ZeroValue(ty) => match gctx.types[ty].inner { - crate::TypeInner::Scalar { kind, width } => crate::Literal::zero(kind, width), + crate::TypeInner::Scalar(scalar) => crate::Literal::zero(scalar), _ => None, }, _ => None, diff --git a/naga/src/proc/typifier.rs b/naga/src/proc/typifier.rs index ad9eec94d2a..a111cc844f6 100644 --- a/naga/src/proc/typifier.rs +++ b/naga/src/proc/typifier.rs @@ -119,8 +119,8 @@ impl Clone for TypeResolution { match *self { Self::Handle(handle) => Self::Handle(handle), Self::Value(ref v) => Self::Value(match *v { - Ti::Scalar { kind, width } => Ti::Scalar { kind, width }, - Ti::Vector { size, kind, width } => Ti::Vector { size, kind, width }, + Ti::Scalar(scalar) => Ti::Scalar(scalar), + Ti::Vector { size, scalar } => Ti::Vector { size, scalar }, Ti::Matrix { rows, columns, @@ -133,13 +133,11 @@ impl Clone for TypeResolution { Ti::Pointer { base, space } => Ti::Pointer { base, space }, Ti::ValuePointer { size, - kind, - width, + scalar, space, } => Ti::ValuePointer { size, - kind, - width, + scalar, space, }, _ => unreachable!("Unexpected clone type: {:?}", v), @@ -243,36 +241,24 @@ impl<'a> ResolveContext<'a> { Ti::Array { base, .. } => TypeResolution::Handle(base), Ti::Matrix { rows, width, .. } => TypeResolution::Value(Ti::Vector { size: rows, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }), - Ti::Vector { - size: _, - kind, - width, - } => TypeResolution::Value(Ti::Scalar { kind, width }), + Ti::Vector { size: _, scalar } => TypeResolution::Value(Ti::Scalar(scalar)), Ti::ValuePointer { size: Some(_), - kind, - width, + scalar, space, } => TypeResolution::Value(Ti::ValuePointer { size: None, - kind, - width, + scalar, space, }), Ti::Pointer { base, space } => { TypeResolution::Value(match types[base].inner { Ti::Array { base, .. } => Ti::Pointer { base, space }, - Ti::Vector { - size: _, - kind, - width, - } => Ti::ValuePointer { + Ti::Vector { size: _, scalar } => Ti::ValuePointer { size: None, - kind, - width, + scalar, space, }, // Matrices are only dynamically indexed behind a pointer @@ -281,9 +267,8 @@ impl<'a> ResolveContext<'a> { rows, width, } => Ti::ValuePointer { - kind: crate::ScalarKind::Float, size: Some(rows), - width, + scalar: crate::Scalar::float(width), space, }, Ti::BindingArray { base, .. } => Ti::Pointer { base, space }, @@ -307,11 +292,11 @@ impl<'a> ResolveContext<'a> { }, crate::Expression::AccessIndex { base, index } => { match *past(base)?.inner_with(types) { - Ti::Vector { size, kind, width } => { + Ti::Vector { size, scalar } => { if index >= size as u32 { return Err(ResolveError::OutOfBoundsIndex { expr: base, index }); } - TypeResolution::Value(Ti::Scalar { kind, width }) + TypeResolution::Value(Ti::Scalar(scalar)) } Ti::Matrix { columns, @@ -323,8 +308,7 @@ impl<'a> ResolveContext<'a> { } TypeResolution::Value(crate::TypeInner::Vector { size: rows, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }) } Ti::Array { base, .. } => TypeResolution::Handle(base), @@ -336,8 +320,7 @@ impl<'a> ResolveContext<'a> { } Ti::ValuePointer { size: Some(size), - kind, - width, + scalar, space, } => { if index >= size as u32 { @@ -345,8 +328,7 @@ impl<'a> ResolveContext<'a> { } TypeResolution::Value(Ti::ValuePointer { size: None, - kind, - width, + scalar, space, }) } @@ -355,14 +337,13 @@ impl<'a> ResolveContext<'a> { space, } => TypeResolution::Value(match types[ty_base].inner { Ti::Array { base, .. } => Ti::Pointer { base, space }, - Ti::Vector { size, kind, width } => { + Ti::Vector { size, scalar } => { if index >= size as u32 { return Err(ResolveError::OutOfBoundsIndex { expr: base, index }); } Ti::ValuePointer { size: None, - kind, - width, + scalar, space, } } @@ -376,8 +357,7 @@ impl<'a> ResolveContext<'a> { } Ti::ValuePointer { size: Some(rows), - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), space, } } @@ -410,9 +390,7 @@ impl<'a> ResolveContext<'a> { } } crate::Expression::Splat { size, value } => match *past(value)?.inner_with(types) { - Ti::Scalar { kind, width } => { - TypeResolution::Value(Ti::Vector { size, kind, width }) - } + Ti::Scalar(scalar) => TypeResolution::Value(Ti::Vector { size, scalar }), ref other => { log::error!("Scalar type {:?}", other); return Err(ResolveError::InvalidScalar(value)); @@ -423,11 +401,9 @@ impl<'a> ResolveContext<'a> { vector, pattern: _, } => match *past(vector)?.inner_with(types) { - Ti::Vector { - size: _, - kind, - width, - } => TypeResolution::Value(Ti::Vector { size, kind, width }), + Ti::Vector { size: _, scalar } => { + TypeResolution::Value(Ti::Vector { size, scalar }) + } ref other => { log::error!("Vector type {:?}", other); return Err(ResolveError::InvalidVector(vector)); @@ -464,20 +440,19 @@ impl<'a> ResolveContext<'a> { } crate::Expression::Load { pointer } => match *past(pointer)?.inner_with(types) { Ti::Pointer { base, space: _ } => { - if let Ti::Atomic { kind, width } = types[base].inner { - TypeResolution::Value(Ti::Scalar { kind, width }) + if let Ti::Atomic(scalar) = types[base].inner { + TypeResolution::Value(Ti::Scalar(scalar)) } else { TypeResolution::Handle(base) } } Ti::ValuePointer { size, - kind, - width, + scalar, space: _, } => TypeResolution::Value(match size { - Some(size) => Ti::Vector { size, kind, width }, - None => Ti::Scalar { kind, width }, + Some(size) => Ti::Vector { size, scalar }, + None => Ti::Scalar(scalar), }), ref other => { log::error!("Pointer type {:?}", other); @@ -490,11 +465,13 @@ impl<'a> ResolveContext<'a> { .. } => match *past(image)?.inner_with(types) { Ti::Image { class, .. } => TypeResolution::Value(Ti::Vector { - kind: match class { - crate::ImageClass::Sampled { kind, multi: _ } => kind, - _ => crate::ScalarKind::Float, + scalar: crate::Scalar { + kind: match class { + crate::ImageClass::Sampled { kind, multi: _ } => kind, + _ => crate::ScalarKind::Float, + }, + width: 4, }, - width: 4, size: crate::VectorSize::Quad, }), ref other => { @@ -505,18 +482,16 @@ impl<'a> ResolveContext<'a> { crate::Expression::ImageSample { image, .. } | crate::Expression::ImageLoad { image, .. } => match *past(image)?.inner_with(types) { Ti::Image { class, .. } => TypeResolution::Value(match class { - crate::ImageClass::Depth { multi: _ } => Ti::Scalar { - kind: crate::ScalarKind::Float, - width: 4, - }, + crate::ImageClass::Depth { multi: _ } => Ti::Scalar(crate::Scalar::F32), crate::ImageClass::Sampled { kind, multi: _ } => Ti::Vector { - kind, - width: 4, + scalar: crate::Scalar { kind, width: 4 }, size: crate::VectorSize::Quad, }, crate::ImageClass::Storage { format, .. } => Ti::Vector { - kind: format.into(), - width: 4, + scalar: crate::Scalar { + kind: format.into(), + width: 4, + }, size: crate::VectorSize::Quad, }, }), @@ -528,19 +503,14 @@ impl<'a> ResolveContext<'a> { crate::Expression::ImageQuery { image, query } => TypeResolution::Value(match query { crate::ImageQuery::Size { level: _ } => match *past(image)?.inner_with(types) { Ti::Image { dim, .. } => match dim { - crate::ImageDimension::D1 => Ti::Scalar { - kind: crate::ScalarKind::Uint, - width: 4, - }, + crate::ImageDimension::D1 => Ti::Scalar(crate::Scalar::U32), crate::ImageDimension::D2 | crate::ImageDimension::Cube => Ti::Vector { size: crate::VectorSize::Bi, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: crate::Scalar::U32, }, crate::ImageDimension::D3 => Ti::Vector { size: crate::VectorSize::Tri, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: crate::Scalar::U32, }, }, ref other => { @@ -550,10 +520,7 @@ impl<'a> ResolveContext<'a> { }, crate::ImageQuery::NumLevels | crate::ImageQuery::NumLayers - | crate::ImageQuery::NumSamples => Ti::Scalar { - kind: crate::ScalarKind::Uint, - width: 4, - }, + | crate::ImageQuery::NumSamples => Ti::Scalar(crate::Scalar::U32), }), crate::Expression::Unary { expr, .. } => past(expr)?.clone(), crate::Expression::Binary { op, left, right } => match op { @@ -585,8 +552,7 @@ impl<'a> ResolveContext<'a> { &Ti::Vector { .. }, ) => TypeResolution::Value(Ti::Vector { size: rows, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }), ( &Ti::Vector { .. }, @@ -597,8 +563,7 @@ impl<'a> ResolveContext<'a> { }, ) => TypeResolution::Value(Ti::Vector { size: columns, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }), (&Ti::Scalar { .. }, _) => res_right.clone(), (_, &Ti::Scalar { .. }) => res_left.clone(), @@ -618,11 +583,10 @@ impl<'a> ResolveContext<'a> { | crate::BinaryOperator::GreaterEqual | crate::BinaryOperator::LogicalAnd | crate::BinaryOperator::LogicalOr => { - let kind = crate::ScalarKind::Bool; - let width = crate::BOOL_WIDTH; + let scalar = crate::Scalar::BOOL; let inner = match *past(left)?.inner_with(types) { - Ti::Scalar { .. } => Ti::Scalar { kind, width }, - Ti::Vector { size, .. } => Ti::Vector { size, kind, width }, + Ti::Scalar { .. } => Ti::Scalar(scalar), + Ti::Vector { size, .. } => Ti::Vector { size, scalar }, ref other => { return Err(ResolveError::IncompatibleOperands(format!( "{op:?}({other:?}, _)" @@ -643,20 +607,13 @@ impl<'a> ResolveContext<'a> { crate::Expression::Derivative { expr, .. } => past(expr)?.clone(), crate::Expression::Relational { fun, argument } => match fun { crate::RelationalFunction::All | crate::RelationalFunction::Any => { - TypeResolution::Value(Ti::Scalar { - kind: crate::ScalarKind::Bool, - width: crate::BOOL_WIDTH, - }) + TypeResolution::Value(Ti::Scalar(crate::Scalar::BOOL)) } crate::RelationalFunction::IsNan | crate::RelationalFunction::IsInf => { match *past(argument)?.inner_with(types) { - Ti::Scalar { .. } => TypeResolution::Value(Ti::Scalar { - kind: crate::ScalarKind::Bool, - width: crate::BOOL_WIDTH, - }), + Ti::Scalar { .. } => TypeResolution::Value(Ti::Scalar(crate::Scalar::BOOL)), Ti::Vector { size, .. } => TypeResolution::Value(Ti::Vector { - kind: crate::ScalarKind::Bool, - width: crate::BOOL_WIDTH, + scalar: crate::Scalar::BOOL, size, }), ref other => { @@ -714,14 +671,16 @@ impl<'a> ResolveContext<'a> { Mf::Pow => res_arg.clone(), Mf::Modf | Mf::Frexp => { let (size, width) = match res_arg.inner_with(types) { - &Ti::Scalar { + &Ti::Scalar(crate::Scalar { kind: crate::ScalarKind::Float, - width, - } => (None, width), + width, + }) => (None, width), &Ti::Vector { - kind: crate::ScalarKind::Float, + scalar: crate::Scalar { + kind: crate::ScalarKind::Float, + width, + }, size, - width, } => (Some(size), width), ref other => return Err(ResolveError::IncompatibleOperands(format!("{fun:?}({other:?}, _)"))) @@ -740,10 +699,9 @@ impl<'a> ResolveContext<'a> { // geometry Mf::Dot => match *res_arg.inner_with(types) { Ti::Vector { - kind, size: _, - width, - } => TypeResolution::Value(Ti::Scalar { kind, width }), + scalar, + } => TypeResolution::Value(Ti::Scalar(scalar)), ref other => return Err(ResolveError::IncompatibleOperands( format!("{fun:?}({other:?}, _)") @@ -754,7 +712,14 @@ impl<'a> ResolveContext<'a> { format!("{fun:?}(_, None)") ))?; match (res_arg.inner_with(types), past(arg1)?.inner_with(types)) { - (&Ti::Vector {kind: _, size: columns,width}, &Ti::Vector{ size: rows, .. }) => TypeResolution::Value(Ti::Matrix { columns, rows, width }), + ( + &Ti::Vector { size: columns, scalar }, + &Ti::Vector{ size: rows, .. } + ) => TypeResolution::Value(Ti::Matrix { + columns, + rows, + width: scalar.width + }), (left, right) => return Err(ResolveError::IncompatibleOperands( format!("{fun:?}({left:?}, {right:?})") @@ -764,8 +729,8 @@ impl<'a> ResolveContext<'a> { Mf::Cross => res_arg.clone(), Mf::Distance | Mf::Length => match *res_arg.inner_with(types) { - Ti::Scalar {width,kind} | - Ti::Vector {width,kind,size:_} => TypeResolution::Value(Ti::Scalar { kind, width }), + Ti::Scalar(scalar) | + Ti::Vector {scalar,size:_} => TypeResolution::Value(Ti::Scalar(scalar)), ref other => return Err(ResolveError::IncompatibleOperands( format!("{fun:?}({other:?})") )), @@ -814,7 +779,7 @@ impl<'a> ResolveContext<'a> { Ti::Matrix { width, .. - } => TypeResolution::Value(Ti::Scalar { kind: crate::ScalarKind::Float, width }), + } => TypeResolution::Value(Ti::Scalar(crate::Scalar::float(width))), ref other => return Err(ResolveError::IncompatibleOperands( format!("{fun:?}({other:?})") )), @@ -828,10 +793,17 @@ impl<'a> ResolveContext<'a> { Mf::InsertBits | Mf::FindLsb | Mf::FindMsb => match *res_arg.inner_with(types) { - Ti::Scalar { kind: kind @ (crate::ScalarKind::Sint | crate::ScalarKind::Uint), width } => - TypeResolution::Value(Ti::Scalar { kind, width }), - Ti::Vector { size, kind: kind @ (crate::ScalarKind::Sint | crate::ScalarKind::Uint), width } => - TypeResolution::Value(Ti::Vector { size, kind, width }), + Ti::Scalar(scalar @ crate::Scalar { + kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint, + .. + }) => TypeResolution::Value(Ti::Scalar(scalar)), + Ti::Vector { + size, + scalar: scalar @ crate::Scalar { + kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint, + .. + } + } => TypeResolution::Value(Ti::Vector { size, scalar }), ref other => return Err(ResolveError::IncompatibleOperands( format!("{fun:?}({other:?})") )), @@ -841,13 +813,19 @@ impl<'a> ResolveContext<'a> { Mf::Pack4x8unorm | Mf::Pack2x16snorm | Mf::Pack2x16unorm | - Mf::Pack2x16float => TypeResolution::Value(Ti::Scalar { kind: crate::ScalarKind::Uint, width: 4 }), + Mf::Pack2x16float => TypeResolution::Value(Ti::Scalar(crate::Scalar::U32)), // data unpacking Mf::Unpack4x8snorm | - Mf::Unpack4x8unorm => TypeResolution::Value(Ti::Vector { size: crate::VectorSize::Quad, kind: crate::ScalarKind::Float, width: 4 }), + Mf::Unpack4x8unorm => TypeResolution::Value(Ti::Vector { + size: crate::VectorSize::Quad, + scalar: crate::Scalar::F32 + }), Mf::Unpack2x16snorm | Mf::Unpack2x16unorm | - Mf::Unpack2x16float => TypeResolution::Value(Ti::Vector { size: crate::VectorSize::Bi, kind: crate::ScalarKind::Float, width: 4 }), + Mf::Unpack2x16float => TypeResolution::Value(Ti::Vector { + size: crate::VectorSize::Bi, + scalar: crate::Scalar::F32 + }), } } crate::Expression::As { @@ -855,18 +833,21 @@ impl<'a> ResolveContext<'a> { kind, convert, } => match *past(expr)?.inner_with(types) { - Ti::Scalar { kind: _, width } => TypeResolution::Value(Ti::Scalar { - kind, - width: convert.unwrap_or(width), - }), + Ti::Scalar(crate::Scalar { width, .. }) => { + TypeResolution::Value(Ti::Scalar(crate::Scalar { + kind, + width: convert.unwrap_or(width), + })) + } Ti::Vector { - kind: _, size, - width, + scalar: crate::Scalar { kind: _, width }, } => TypeResolution::Value(Ti::Vector { - kind, size, - width: convert.unwrap_or(width), + scalar: crate::Scalar { + kind, + width: convert.unwrap_or(width), + }, }), Ti::Matrix { columns, @@ -890,14 +871,12 @@ impl<'a> ResolveContext<'a> { .ok_or(ResolveError::FunctionReturnsVoid)?; TypeResolution::Handle(result.ty) } - crate::Expression::ArrayLength(_) => TypeResolution::Value(Ti::Scalar { - kind: crate::ScalarKind::Uint, - width: 4, - }), - crate::Expression::RayQueryProceedResult => TypeResolution::Value(Ti::Scalar { - kind: crate::ScalarKind::Bool, - width: crate::BOOL_WIDTH, - }), + crate::Expression::ArrayLength(_) => { + TypeResolution::Value(Ti::Scalar(crate::Scalar::U32)) + } + crate::Expression::RayQueryProceedResult => { + TypeResolution::Value(Ti::Scalar(crate::Scalar::BOOL)) + } crate::Expression::RayQueryGetIntersection { .. } => { let result = self .special_types diff --git a/naga/src/valid/analyzer.rs b/naga/src/valid/analyzer.rs index d6c0bf8ea49..3c4af7607d9 100644 --- a/naga/src/valid/analyzer.rs +++ b/naga/src/valid/analyzer.rs @@ -159,10 +159,10 @@ impl ExpressionInfo { ref_count: 0, assignable_global: None, // this doesn't matter at this point, will be overwritten - ty: TypeResolution::Value(crate::TypeInner::Scalar { + ty: TypeResolution::Value(crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Bool, width: 0, - }), + })), } } } @@ -1079,8 +1079,7 @@ fn uniform_control_flow() { name: None, inner: crate::TypeInner::Vector { size: crate::VectorSize::Bi, - kind: crate::ScalarKind::Float, - width: 4, + scalar: crate::Scalar::F32, }, }, Default::default(), diff --git a/naga/src/valid/compose.rs b/naga/src/valid/compose.rs index 87bc2352ceb..b392de57b01 100644 --- a/naga/src/valid/compose.rs +++ b/naga/src/valid/compose.rs @@ -24,19 +24,15 @@ pub fn validate_compose( match gctx.types[self_ty_handle].inner { // vectors are composed from scalars or other vectors - Ti::Vector { size, kind, width } => { + Ti::Vector { size, scalar } => { let mut total = 0; for (index, comp_res) in component_resolutions.enumerate() { total += match *comp_res.inner_with(gctx.types) { - Ti::Scalar { - kind: comp_kind, - width: comp_width, - } if comp_kind == kind && comp_width == width => 1, + Ti::Scalar(comp_scalar) if comp_scalar == scalar => 1, Ti::Vector { size: comp_size, - kind: comp_kind, - width: comp_width, - } if comp_kind == kind && comp_width == width => comp_size as u32, + scalar: comp_scalar, + } if comp_scalar == scalar => comp_size as u32, ref other => { log::error!("Vector component[{}] type {:?}", index, other); return Err(ComposeError::ComponentType { @@ -60,8 +56,7 @@ pub fn validate_compose( } => { let inner = Ti::Vector { size: rows, - kind: crate::ScalarKind::Float, - width, + scalar: crate::Scalar::float(width), }; if columns as usize != component_resolutions.len() { return Err(ComposeError::ComponentCount { diff --git a/naga/src/valid/expression.rs b/naga/src/valid/expression.rs index f77844b4b1e..dc70c2e6102 100644 --- a/naga/src/valid/expression.rs +++ b/naga/src/valid/expression.rs @@ -221,7 +221,7 @@ impl super::Validator { info: &FunctionInfo, mod_info: &ModuleInfo, ) -> Result { - use crate::{Expression as E, ScalarKind as Sk, TypeInner as Ti}; + use crate::{Expression as E, Scalar as Sc, ScalarKind as Sk, TypeInner as Ti}; let resolver = ExpressionTypeResolver { root, @@ -246,10 +246,10 @@ impl super::Validator { }; match resolver[index] { //TODO: only allow one of these - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Sint | Sk::Uint, - width: _, - } => {} + .. + }) => {} ref other => { log::error!("Indexing by {:?}", other); return Err(ExpressionError::InvalidIndexType(index)); @@ -412,10 +412,10 @@ impl super::Validator { } if let Some(expr) = array_index { match resolver[expr] { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Sint | Sk::Uint, - width: _, - } => {} + .. + }) => {} _ => return Err(ExpressionError::InvalidImageArrayIndexType(expr)), } } @@ -452,13 +452,15 @@ impl super::Validator { crate::ImageDimension::D3 | crate::ImageDimension::Cube => 3, }; match resolver[coordinate] { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float, .. - } if num_components == 1 => {} + }) if num_components == 1 => {} Ti::Vector { size, - kind: Sk::Float, - .. + scalar: + Sc { + kind: Sk::Float, .. + }, } if size as u32 == num_components => {} _ => return Err(ExpressionError::InvalidImageCoordinateType(dim, coordinate)), } @@ -466,11 +468,10 @@ impl super::Validator { // check constant offset if let Some(const_expr) = offset { match *mod_info[const_expr].inner_with(&module.types) { - Ti::Scalar { kind: Sk::Sint, .. } if num_components == 1 => {} + Ti::Scalar(Sc { kind: Sk::Sint, .. }) if num_components == 1 => {} Ti::Vector { size, - kind: Sk::Sint, - .. + scalar: Sc { kind: Sk::Sint, .. }, } if size as u32 == num_components => {} _ => { return Err(ExpressionError::InvalidSampleOffset(dim, const_expr)); @@ -481,9 +482,9 @@ impl super::Validator { // check depth reference type if let Some(expr) = depth_ref { match resolver[expr] { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float, .. - } => {} + }) => {} _ => return Err(ExpressionError::InvalidDepthReference(expr)), } match level { @@ -518,44 +519,48 @@ impl super::Validator { crate::SampleLevel::Zero => ShaderStages::all(), crate::SampleLevel::Exact(expr) => { match resolver[expr] { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float, .. - } => {} + }) => {} _ => return Err(ExpressionError::InvalidSampleLevelExactType(expr)), } ShaderStages::all() } crate::SampleLevel::Bias(expr) => { match resolver[expr] { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float, .. - } => {} + }) => {} _ => return Err(ExpressionError::InvalidSampleLevelBiasType(expr)), } ShaderStages::FRAGMENT } crate::SampleLevel::Gradient { x, y } => { match resolver[x] { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float, .. - } if num_components == 1 => {} + }) if num_components == 1 => {} Ti::Vector { size, - kind: Sk::Float, - .. + scalar: + Sc { + kind: Sk::Float, .. + }, } if size as u32 == num_components => {} _ => { return Err(ExpressionError::InvalidSampleLevelGradientType(dim, x)) } } match resolver[y] { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float, .. - } if num_components == 1 => {} + }) if num_components == 1 => {} Ti::Vector { size, - kind: Sk::Float, - .. + scalar: + Sc { + kind: Sk::Float, .. + }, } if size as u32 == num_components => {} _ => { return Err(ExpressionError::InvalidSampleLevelGradientType(dim, y)) @@ -592,10 +597,10 @@ impl super::Validator { } if let Some(expr) = array_index { match resolver[expr] { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Sint | Sk::Uint, width: _, - } => {} + }) => {} _ => return Err(ExpressionError::InvalidImageArrayIndexType(expr)), } } @@ -669,7 +674,7 @@ impl super::Validator { let right_inner = &resolver[right]; let good = match op { Bo::Add | Bo::Subtract => match *left_inner { - Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind { + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => match scalar.kind { Sk::Uint | Sk::Sint | Sk::Float => left_inner == right_inner, Sk::Bool => false, }, @@ -677,7 +682,7 @@ impl super::Validator { _ => false, }, Bo::Divide | Bo::Modulo => match *left_inner { - Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind { + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => match scalar.kind { Sk::Uint | Sk::Sint | Sk::Float => left_inner == right_inner, Sk::Bool => false, }, @@ -690,52 +695,62 @@ impl super::Validator { }; let types_match = match (left_inner, right_inner) { // Straight scalar and mixed scalar/vector. - (&Ti::Scalar { kind: kind1, .. }, &Ti::Scalar { kind: kind2, .. }) - | (&Ti::Vector { kind: kind1, .. }, &Ti::Scalar { kind: kind2, .. }) - | (&Ti::Scalar { kind: kind1, .. }, &Ti::Vector { kind: kind2, .. }) => { - kind1 == kind2 - } + (&Ti::Scalar(scalar1), &Ti::Scalar(scalar2)) + | ( + &Ti::Vector { + scalar: scalar1, .. + }, + &Ti::Scalar(scalar2), + ) + | ( + &Ti::Scalar(scalar1), + &Ti::Vector { + scalar: scalar2, .. + }, + ) => scalar1 == scalar2, // Scalar/matrix. ( - &Ti::Scalar { + &Ti::Scalar(Sc { kind: Sk::Float, .. - }, + }), &Ti::Matrix { .. }, ) | ( &Ti::Matrix { .. }, - &Ti::Scalar { + &Ti::Scalar(Sc { kind: Sk::Float, .. - }, + }), ) => true, // Vector/vector. ( &Ti::Vector { - kind: kind1, size: size1, - .. + scalar: scalar1, }, &Ti::Vector { - kind: kind2, size: size2, - .. + scalar: scalar2, }, - ) => kind1 == kind2 && size1 == size2, + ) => scalar1 == scalar2 && size1 == size2, // Matrix * vector. ( &Ti::Matrix { columns, .. }, &Ti::Vector { - kind: Sk::Float, size, - .. + scalar: + Sc { + kind: Sk::Float, .. + }, }, ) => columns == size, // Vector * matrix. ( &Ti::Vector { - kind: Sk::Float, size, - .. + scalar: + Sc { + kind: Sk::Float, .. + }, }, &Ti::Matrix { rows, .. }, ) => size == rows, @@ -744,24 +759,14 @@ impl super::Validator { } _ => false, }; - let left_width = match *left_inner { - Ti::Scalar { width, .. } - | Ti::Vector { width, .. } - | Ti::Matrix { width, .. } => width, - _ => 0, - }; - let right_width = match *right_inner { - Ti::Scalar { width, .. } - | Ti::Vector { width, .. } - | Ti::Matrix { width, .. } => width, - _ => 0, - }; + let left_width = left_inner.scalar_width().unwrap_or(0); + let right_width = right_inner.scalar_width().unwrap_or(0); kind_allowed && types_match && left_width == right_width } Bo::Equal | Bo::NotEqual => left_inner.is_sized() && left_inner == right_inner, Bo::Less | Bo::LessEqual | Bo::Greater | Bo::GreaterEqual => { match *left_inner { - Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind { + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => match scalar.kind { Sk::Uint | Sk::Sint | Sk::Float => left_inner == right_inner, Sk::Bool => false, }, @@ -772,16 +777,18 @@ impl super::Validator { } } Bo::LogicalAnd | Bo::LogicalOr => match *left_inner { - Ti::Scalar { kind: Sk::Bool, .. } | Ti::Vector { kind: Sk::Bool, .. } => { - left_inner == right_inner - } + Ti::Scalar(Sc { kind: Sk::Bool, .. }) + | Ti::Vector { + scalar: Sc { kind: Sk::Bool, .. }, + .. + } => left_inner == right_inner, ref other => { log::error!("Op {:?} left type {:?}", op, other); false } }, Bo::And | Bo::InclusiveOr => match *left_inner { - Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind { + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => match scalar.kind { Sk::Bool | Sk::Sint | Sk::Uint => left_inner == right_inner, Sk::Float => false, }, @@ -791,7 +798,7 @@ impl super::Validator { } }, Bo::ExclusiveOr => match *left_inner { - Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind { + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => match scalar.kind { Sk::Sint | Sk::Uint => left_inner == right_inner, Sk::Bool | Sk::Float => false, }, @@ -801,27 +808,26 @@ impl super::Validator { } }, Bo::ShiftLeft | Bo::ShiftRight => { - let (base_size, base_kind) = match *left_inner { - Ti::Scalar { kind, .. } => (Ok(None), kind), - Ti::Vector { size, kind, .. } => (Ok(Some(size)), kind), + let (base_size, base_scalar) = match *left_inner { + Ti::Scalar(scalar) => (Ok(None), scalar), + Ti::Vector { size, scalar } => (Ok(Some(size)), scalar), ref other => { log::error!("Op {:?} base type {:?}", op, other); - (Err(()), Sk::Bool) + (Err(()), Sc::BOOL) } }; let shift_size = match *right_inner { - Ti::Scalar { kind: Sk::Uint, .. } => Ok(None), + Ti::Scalar(Sc { kind: Sk::Uint, .. }) => Ok(None), Ti::Vector { size, - kind: Sk::Uint, - .. + scalar: Sc { kind: Sk::Uint, .. }, } => Ok(Some(size)), ref other => { log::error!("Op {:?} shift type {:?}", op, other); Err(()) } }; - match base_kind { + match base_scalar.kind { Sk::Sint | Sk::Uint => base_size.is_ok() && base_size == shift_size, Sk::Float | Sk::Bool => false, } @@ -850,10 +856,10 @@ impl super::Validator { let accept_inner = &resolver[accept]; let reject_inner = &resolver[reject]; let condition_good = match resolver[condition] { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Bool, width: _, - } => { + }) => { // When `condition` is a single boolean, `accept` and // `reject` can be vectors or scalars. match *accept_inner { @@ -863,8 +869,11 @@ impl super::Validator { } Ti::Vector { size, - kind: Sk::Bool, - width: _, + scalar: + Sc { + kind: Sk::Bool, + width: _, + }, } => match *accept_inner { Ti::Vector { size: other_size, .. @@ -880,11 +889,15 @@ impl super::Validator { } E::Derivative { expr, .. } => { match resolver[expr] { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float, .. - } + }) | Ti::Vector { - kind: Sk::Float, .. + scalar: + Sc { + kind: Sk::Float, .. + }, + .. } => {} _ => return Err(ExpressionError::InvalidDerivative), } @@ -895,19 +908,18 @@ impl super::Validator { let argument_inner = &resolver[argument]; match fun { Rf::All | Rf::Any => match *argument_inner { - Ti::Vector { kind: Sk::Bool, .. } => {} + Ti::Vector { + scalar: Sc { kind: Sk::Bool, .. }, + .. + } => {} ref other => { log::error!("All/Any of type {:?}", other); return Err(ExpressionError::InvalidBooleanVector(argument)); } }, Rf::IsNan | Rf::IsInf => match *argument_inner { - Ti::Scalar { - kind: Sk::Float, .. - } - | Ti::Vector { - kind: Sk::Float, .. - } => {} + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } + if scalar.kind == Sk::Float => {} ref other => { log::error!("Float test of type {:?}", other); return Err(ExpressionError::InvalidFloatArgument(argument)); @@ -936,7 +948,9 @@ impl super::Validator { return Err(ExpressionError::WrongArgumentCount(fun)); } let good = match *arg_ty { - Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => kind != Sk::Bool, + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => { + scalar.kind != Sk::Bool + } _ => false, }; if !good { @@ -949,7 +963,9 @@ impl super::Validator { _ => return Err(ExpressionError::WrongArgumentCount(fun)), }; let good = match *arg_ty { - Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => kind != Sk::Bool, + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => { + scalar.kind != Sk::Bool + } _ => false, }; if !good { @@ -969,7 +985,9 @@ impl super::Validator { _ => return Err(ExpressionError::WrongArgumentCount(fun)), }; let good = match *arg_ty { - Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => kind != Sk::Bool, + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => { + scalar.kind != Sk::Bool + } _ => false, }; if !good { @@ -1021,12 +1039,8 @@ impl super::Validator { return Err(ExpressionError::WrongArgumentCount(fun)); } match *arg_ty { - Ti::Scalar { - kind: Sk::Float, .. - } - | Ti::Vector { - kind: Sk::Float, .. - } => {} + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } + if scalar.kind == Sk::Float => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), } } @@ -1035,12 +1049,16 @@ impl super::Validator { return Err(ExpressionError::WrongArgumentCount(fun)); } match *arg_ty { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float | Sk::Sint, .. - } + }) | Ti::Vector { - kind: Sk::Float | Sk::Sint, + scalar: + Sc { + kind: Sk::Float | Sk::Sint, + .. + }, .. } => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), @@ -1052,12 +1070,8 @@ impl super::Validator { _ => return Err(ExpressionError::WrongArgumentCount(fun)), }; match *arg_ty { - Ti::Scalar { - kind: Sk::Float, .. - } - | Ti::Vector { - kind: Sk::Float, .. - } => {} + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } + if scalar.kind == Sk::Float => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), } if arg1_ty != arg_ty { @@ -1072,16 +1086,10 @@ impl super::Validator { if arg1_ty.is_some() || arg2_ty.is_some() || arg3_ty.is_some() { return Err(ExpressionError::WrongArgumentCount(fun)); } - if !matches!( - *arg_ty, - Ti::Scalar { - kind: Sk::Float, - .. - } | Ti::Vector { - kind: Sk::Float, - .. - }, - ) { + if !matches!(*arg_ty, + Ti::Scalar(scalar) | Ti::Vector { scalar, .. } + if scalar.kind == Sk::Float) + { return Err(ExpressionError::InvalidArgumentType(fun, 1, arg)); } } @@ -1091,24 +1099,25 @@ impl super::Validator { _ => return Err(ExpressionError::WrongArgumentCount(fun)), }; let size0 = match *arg_ty { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float, .. - } => None, + }) => None, Ti::Vector { - kind: Sk::Float, + scalar: + Sc { + kind: Sk::Float, .. + }, size, - .. } => Some(size), _ => { return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)); } }; let good = match *arg1_ty { - Ti::Scalar { kind: Sk::Sint, .. } if size0.is_none() => true, + Ti::Scalar(Sc { kind: Sk::Sint, .. }) if size0.is_none() => true, Ti::Vector { size, - kind: Sk::Sint, - .. + scalar: Sc { kind: Sk::Sint, .. }, } if Some(size) == size0 => true, _ => false, }; @@ -1127,7 +1136,11 @@ impl super::Validator { }; match *arg_ty { Ti::Vector { - kind: Sk::Float | Sk::Sint | Sk::Uint, + scalar: + Sc { + kind: Sk::Float | Sk::Sint | Sk::Uint, + .. + }, .. } => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), @@ -1147,7 +1160,11 @@ impl super::Validator { }; match *arg_ty { Ti::Vector { - kind: Sk::Float, .. + scalar: + Sc { + kind: Sk::Float, .. + }, + .. } => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), } @@ -1167,7 +1184,11 @@ impl super::Validator { match *arg_ty { Ti::Vector { - kind: Sk::Float, .. + scalar: + Sc { + kind: Sk::Float, .. + }, + .. } => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), } @@ -1183,13 +1204,17 @@ impl super::Validator { match (arg_ty, arg2_ty) { ( &Ti::Vector { - width: vector_width, + scalar: + Sc { + width: vector_width, + .. + }, .. }, - &Ti::Scalar { + &Ti::Scalar(Sc { width: scalar_width, kind: Sk::Float, - }, + }), ) if vector_width == scalar_width => {} _ => { return Err(ExpressionError::InvalidArgumentType( @@ -1206,7 +1231,11 @@ impl super::Validator { } match *arg_ty { Ti::Vector { - kind: Sk::Float, .. + scalar: + Sc { + kind: Sk::Float, .. + }, + .. } => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), } @@ -1217,11 +1246,15 @@ impl super::Validator { _ => return Err(ExpressionError::WrongArgumentCount(fun)), }; match *arg_ty { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float, .. - } + }) | Ti::Vector { - kind: Sk::Float, .. + scalar: + Sc { + kind: Sk::Float, .. + }, + .. } => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), } @@ -1246,13 +1279,16 @@ impl super::Validator { _ => return Err(ExpressionError::WrongArgumentCount(fun)), }; let arg_width = match *arg_ty { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float, width, - } + }) | Ti::Vector { - kind: Sk::Float, - width, + scalar: + Sc { + kind: Sk::Float, + width, + }, .. } => width, _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), @@ -1266,10 +1302,10 @@ impl super::Validator { } // the last argument can always be a scalar match *arg2_ty { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Float, width, - } if width == arg_width => {} + }) if width == arg_width => {} _ if arg2_ty == arg_ty => {} _ => { return Err(ExpressionError::InvalidArgumentType( @@ -1311,12 +1347,16 @@ impl super::Validator { return Err(ExpressionError::WrongArgumentCount(fun)); } match *arg_ty { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Sint | Sk::Uint, .. - } + }) | Ti::Vector { - kind: Sk::Sint | Sk::Uint, + scalar: + Sc { + kind: Sk::Sint | Sk::Uint, + .. + }, .. } => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), @@ -1328,12 +1368,16 @@ impl super::Validator { _ => return Err(ExpressionError::WrongArgumentCount(fun)), }; match *arg_ty { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Sint | Sk::Uint, .. - } + }) | Ti::Vector { - kind: Sk::Sint | Sk::Uint, + scalar: + Sc { + kind: Sk::Sint | Sk::Uint, + .. + }, .. } => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), @@ -1346,7 +1390,7 @@ impl super::Validator { )); } match *arg2_ty { - Ti::Scalar { kind: Sk::Uint, .. } => {} + Ti::Scalar(Sc { kind: Sk::Uint, .. }) => {} _ => { return Err(ExpressionError::InvalidArgumentType( fun, @@ -1356,7 +1400,7 @@ impl super::Validator { } } match *arg3_ty { - Ti::Scalar { kind: Sk::Uint, .. } => {} + Ti::Scalar(Sc { kind: Sk::Uint, .. }) => {} _ => { return Err(ExpressionError::InvalidArgumentType( fun, @@ -1372,18 +1416,22 @@ impl super::Validator { _ => return Err(ExpressionError::WrongArgumentCount(fun)), }; match *arg_ty { - Ti::Scalar { + Ti::Scalar(Sc { kind: Sk::Sint | Sk::Uint, .. - } + }) | Ti::Vector { - kind: Sk::Sint | Sk::Uint, + scalar: + Sc { + kind: Sk::Sint | Sk::Uint, + .. + }, .. } => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), } match *arg1_ty { - Ti::Scalar { kind: Sk::Uint, .. } => {} + Ti::Scalar(Sc { kind: Sk::Uint, .. }) => {} _ => { return Err(ExpressionError::InvalidArgumentType( fun, @@ -1393,7 +1441,7 @@ impl super::Validator { } } match *arg2_ty { - Ti::Scalar { kind: Sk::Uint, .. } => {} + Ti::Scalar(Sc { kind: Sk::Uint, .. }) => {} _ => { return Err(ExpressionError::InvalidArgumentType( fun, @@ -1410,8 +1458,10 @@ impl super::Validator { match *arg_ty { Ti::Vector { size: crate::VectorSize::Bi, - kind: Sk::Float, - .. + scalar: + Sc { + kind: Sk::Float, .. + }, } => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), } @@ -1423,8 +1473,10 @@ impl super::Validator { match *arg_ty { Ti::Vector { size: crate::VectorSize::Quad, - kind: Sk::Float, - .. + scalar: + Sc { + kind: Sk::Float, .. + }, } => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), } @@ -1438,7 +1490,7 @@ impl super::Validator { return Err(ExpressionError::WrongArgumentCount(fun)); } match *arg_ty { - Ti::Scalar { kind: Sk::Uint, .. } => {} + Ti::Scalar(Sc { kind: Sk::Uint, .. }) => {} _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), } } @@ -1450,14 +1502,18 @@ impl super::Validator { kind, convert, } => { - let base_width = match resolver[expr] { - crate::TypeInner::Scalar { width, .. } - | crate::TypeInner::Vector { width, .. } - | crate::TypeInner::Matrix { width, .. } => width, + let mut base_scalar = match resolver[expr] { + crate::TypeInner::Scalar(scalar) | crate::TypeInner::Vector { scalar, .. } => { + scalar + } + crate::TypeInner::Matrix { width, .. } => crate::Scalar::float(width), _ => return Err(ExpressionError::InvalidCastArgument), }; - let width = convert.unwrap_or(base_width); - if self.check_width(kind, width).is_err() { + base_scalar.kind = kind; + if let Some(width) = convert { + base_scalar.width = width; + } + if self.check_width(base_scalar).is_err() { return Err(ExpressionError::InvalidCastArgument); } ShaderStages::all() @@ -1465,10 +1521,12 @@ impl super::Validator { E::CallResult(function) => mod_info.functions[function.index()].available_stages, E::AtomicResult { ty, comparison } => { let scalar_predicate = |ty: &crate::TypeInner| match ty { - &crate::TypeInner::Scalar { - kind: kind @ (crate::ScalarKind::Uint | crate::ScalarKind::Sint), - width, - } => self.check_width(kind, width).is_ok(), + &crate::TypeInner::Scalar( + scalar @ Sc { + kind: crate::ScalarKind::Uint | crate::ScalarKind::Sint, + .. + }, + ) => self.check_width(scalar).is_ok(), _ => false, }; let good = match &module.types[ty].inner { @@ -1569,9 +1627,7 @@ impl super::Validator { } pub fn validate_literal(&self, literal: crate::Literal) -> Result<(), LiteralError> { - let kind = literal.scalar_kind(); - let width = literal.width(); - self.check_width(kind, width)?; + self.check_width(literal.scalar())?; check_literal_value(literal)?; Ok(()) diff --git a/naga/src/valid/function.rs b/naga/src/valid/function.rs index 83704f30cda..a350320a0b1 100644 --- a/naga/src/valid/function.rs +++ b/naga/src/valid/function.rs @@ -352,9 +352,9 @@ impl super::Validator { context: &BlockContext, ) -> Result<(), WithSpan> { let pointer_inner = context.resolve_type(pointer, &self.valid_expression_set)?; - let (ptr_kind, ptr_width) = match *pointer_inner { + let ptr_scalar = match *pointer_inner { crate::TypeInner::Pointer { base, .. } => match context.types[base].inner { - crate::TypeInner::Atomic { kind, width } => (kind, width), + crate::TypeInner::Atomic(scalar) => scalar, ref other => { log::error!("Atomic pointer to type {:?}", other); return Err(AtomicError::InvalidPointer(pointer) @@ -372,7 +372,7 @@ impl super::Validator { let value_inner = context.resolve_type(value, &self.valid_expression_set)?; match *value_inner { - crate::TypeInner::Scalar { width, kind } if kind == ptr_kind && width == ptr_width => {} + crate::TypeInner::Scalar(scalar) if scalar == ptr_scalar => {} ref other => { log::error!("Atomic operand type {:?}", other); return Err(AtomicError::InvalidOperand(value) @@ -394,12 +394,8 @@ impl super::Validator { match context.expressions[result] { crate::Expression::AtomicResult { ty, comparison } if { - let scalar_predicate = |ty: &crate::TypeInner| { - *ty == crate::TypeInner::Scalar { - kind: ptr_kind, - width: ptr_width, - } - }; + let scalar_predicate = + |ty: &crate::TypeInner| *ty == crate::TypeInner::Scalar(ptr_scalar); match &context.types[ty].inner { ty if !comparison => scalar_predicate(ty), &crate::TypeInner::Struct { ref members, .. } if comparison => { @@ -452,10 +448,10 @@ impl super::Validator { ref reject, } => { match *context.resolve_type(condition, &self.valid_expression_set)? { - Ti::Scalar { + Ti::Scalar(crate::Scalar { kind: crate::ScalarKind::Bool, width: _, - } => {} + }) => {} _ => { return Err(FunctionError::InvalidIfType(condition) .with_span_handle(condition, context.expressions)) @@ -567,10 +563,10 @@ impl super::Validator { if let Some(condition) = break_if { match *context.resolve_type(condition, &self.valid_expression_set)? { - Ti::Scalar { + Ti::Scalar(crate::Scalar { kind: crate::ScalarKind::Bool, width: _, - } => {} + }) => {} _ => { return Err(FunctionError::InvalidIfType(condition) .with_span_handle(condition, context.expressions)) @@ -672,21 +668,19 @@ impl super::Validator { let good = match *pointer_ty { Ti::Pointer { base, space: _ } => match context.types[base].inner { - Ti::Atomic { kind, width } => *value_ty == Ti::Scalar { kind, width }, + Ti::Atomic(scalar) => *value_ty == Ti::Scalar(scalar), ref other => value_ty == other, }, Ti::ValuePointer { size: Some(size), - kind, - width, + scalar, space: _, - } => *value_ty == Ti::Vector { size, kind, width }, + } => *value_ty == Ti::Vector { size, scalar }, Ti::ValuePointer { size: None, - kind, - width, + scalar, space: _, - } => *value_ty == Ti::Scalar { kind, width }, + } => *value_ty == Ti::Scalar(scalar), _ => false, }; if !good { @@ -775,10 +769,10 @@ impl super::Validator { } if let Some(expr) = array_index { match *context.resolve_type(expr, &self.valid_expression_set)? { - Ti::Scalar { + Ti::Scalar(crate::Scalar { kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint, width: _, - } => {} + }) => {} _ => { return Err(FunctionError::InvalidImageStore( ExpressionError::InvalidImageArrayIndexType(expr), @@ -790,9 +784,11 @@ impl super::Validator { match class { crate::ImageClass::Storage { format, .. } => { crate::TypeInner::Vector { - kind: format.into(), size: crate::VectorSize::Quad, - width: 4, + scalar: crate::Scalar { + kind: format.into(), + width: 4, + }, } } _ => { diff --git a/naga/src/valid/handles.rs b/naga/src/valid/handles.rs index 9a1ac02a1af..c2aa6bf3d6e 100644 --- a/naga/src/valid/handles.rs +++ b/naga/src/valid/handles.rs @@ -684,10 +684,7 @@ fn constant_deps() { let i32_handle = types.insert( Type { name: None, - inner: TypeInner::Scalar { - kind: crate::ScalarKind::Sint, - width: 4, - }, + inner: TypeInner::Scalar(crate::Scalar::I32), }, nowhere, ); diff --git a/naga/src/valid/interface.rs b/naga/src/valid/interface.rs index 6c41ece81f3..2e50f671606 100644 --- a/naga/src/valid/interface.rs +++ b/naga/src/valid/interface.rs @@ -142,9 +142,7 @@ impl VaryingContext<'_> { ty: Handle, binding: &crate::Binding, ) -> Result<(), VaryingError> { - use crate::{ - BuiltIn as Bi, ScalarKind as Sk, ShaderStage as St, TypeInner as Ti, VectorSize as Vs, - }; + use crate::{BuiltIn as Bi, ShaderStage as St, TypeInner as Ti, VectorSize as Vs}; let ty_inner = &self.types[ty].inner; match *binding { @@ -174,44 +172,30 @@ impl VaryingContext<'_> { return Err(VaryingError::UnsupportedCapability(required)); } - let width = 4; let (visible, type_good) = match built_in { Bi::BaseInstance | Bi::BaseVertex | Bi::InstanceIndex | Bi::VertexIndex => ( self.stage == St::Vertex && !self.output, - *ty_inner - == Ti::Scalar { - kind: Sk::Uint, - width, - }, + *ty_inner == Ti::Scalar(crate::Scalar::U32), ), Bi::ClipDistance | Bi::CullDistance => ( self.stage == St::Vertex && self.output, match *ty_inner { Ti::Array { base, .. } => { - self.types[base].inner - == Ti::Scalar { - kind: Sk::Float, - width, - } + self.types[base].inner == Ti::Scalar(crate::Scalar::F32) } _ => false, }, ), Bi::PointSize => ( self.stage == St::Vertex && self.output, - *ty_inner - == Ti::Scalar { - kind: Sk::Float, - width, - }, + *ty_inner == Ti::Scalar(crate::Scalar::F32), ), Bi::PointCoord => ( self.stage == St::Fragment && !self.output, *ty_inner == Ti::Vector { size: Vs::Bi, - kind: Sk::Float, - width, + scalar: crate::Scalar::F32, }, ), Bi::Position { .. } => ( @@ -223,8 +207,7 @@ impl VaryingContext<'_> { *ty_inner == Ti::Vector { size: Vs::Quad, - kind: Sk::Float, - width, + scalar: crate::Scalar::F32, }, ), Bi::ViewIndex => ( @@ -232,59 +215,31 @@ impl VaryingContext<'_> { St::Vertex | St::Fragment => !self.output, St::Compute => false, }, - *ty_inner - == Ti::Scalar { - kind: Sk::Sint, - width, - }, + *ty_inner == Ti::Scalar(crate::Scalar::I32), ), Bi::FragDepth => ( self.stage == St::Fragment && self.output, - *ty_inner - == Ti::Scalar { - kind: Sk::Float, - width, - }, + *ty_inner == Ti::Scalar(crate::Scalar::F32), ), Bi::FrontFacing => ( self.stage == St::Fragment && !self.output, - *ty_inner - == Ti::Scalar { - kind: Sk::Bool, - width: crate::BOOL_WIDTH, - }, + *ty_inner == Ti::Scalar(crate::Scalar::BOOL), ), Bi::PrimitiveIndex => ( self.stage == St::Fragment && !self.output, - *ty_inner - == Ti::Scalar { - kind: Sk::Uint, - width, - }, + *ty_inner == Ti::Scalar(crate::Scalar::U32), ), Bi::SampleIndex => ( self.stage == St::Fragment && !self.output, - *ty_inner - == Ti::Scalar { - kind: Sk::Uint, - width, - }, + *ty_inner == Ti::Scalar(crate::Scalar::U32), ), Bi::SampleMask => ( self.stage == St::Fragment, - *ty_inner - == Ti::Scalar { - kind: Sk::Uint, - width, - }, + *ty_inner == Ti::Scalar(crate::Scalar::U32), ), Bi::LocalInvocationIndex => ( self.stage == St::Compute && !self.output, - *ty_inner - == Ti::Scalar { - kind: Sk::Uint, - width, - }, + *ty_inner == Ti::Scalar(crate::Scalar::U32), ), Bi::GlobalInvocationId | Bi::LocalInvocationId @@ -295,8 +250,7 @@ impl VaryingContext<'_> { *ty_inner == Ti::Vector { size: Vs::Tri, - kind: Sk::Uint, - width, + scalar: crate::Scalar::U32, }, ), }; diff --git a/naga/src/valid/mod.rs b/naga/src/valid/mod.rs index c24dbe900ce..316e35f6177 100644 --- a/naga/src/valid/mod.rs +++ b/naga/src/valid/mod.rs @@ -266,19 +266,25 @@ impl crate::TypeInner { #[cfg(feature = "validate")] const fn image_storage_coordinates(&self) -> Option { match *self { - Self::Scalar { + Self::Scalar(crate::Scalar { kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint, .. - } => Some(crate::ImageDimension::D1), + }) => Some(crate::ImageDimension::D1), Self::Vector { size: crate::VectorSize::Bi, - kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint, - .. + scalar: + crate::Scalar { + kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint, + .. + }, } => Some(crate::ImageDimension::D2), Self::Vector { size: crate::VectorSize::Tri, - kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint, - .. + scalar: + crate::Scalar { + kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint, + .. + }, } => Some(crate::ImageDimension::D3), _ => None, } @@ -351,10 +357,11 @@ impl Validator { ValidationError::from(e).with_span_handle(handle, &module.types) })?; - let placeholder = TypeResolution::Value(crate::TypeInner::Scalar { + // These should all get overwritten. + let placeholder = TypeResolution::Value(crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Bool, width: 0, - }); + })); let mut mod_info = ModuleInfo { type_flags: Vec::with_capacity(module.types.len()), @@ -484,9 +491,5 @@ fn validate_atomic_compare_exchange_struct( && members[0].name.as_deref() == Some("old_value") && scalar_predicate(&types[members[0].ty].inner) && members[1].name.as_deref() == Some("exchanged") - && types[members[1].ty].inner - == crate::TypeInner::Scalar { - kind: crate::ScalarKind::Bool, - width: crate::BOOL_WIDTH, - } + && types[members[1].ty].inner == crate::TypeInner::Scalar(crate::Scalar::BOOL) } diff --git a/naga/src/valid/type.rs b/naga/src/valid/type.rs index a5321178c17..12d5663f40e 100644 --- a/naga/src/valid/type.rs +++ b/naga/src/valid/type.rs @@ -224,15 +224,11 @@ impl super::Validator { } } - pub(super) const fn check_width( - &self, - kind: crate::ScalarKind, - width: crate::Bytes, - ) -> Result<(), WidthError> { - let good = match kind { - crate::ScalarKind::Bool => width == crate::BOOL_WIDTH, + pub(super) const fn check_width(&self, scalar: crate::Scalar) -> Result<(), WidthError> { + let good = match scalar.kind { + crate::ScalarKind::Bool => scalar.width == crate::BOOL_WIDTH, crate::ScalarKind::Float => { - if width == 8 { + if scalar.width == 8 { if !self.capabilities.contains(Capabilities::FLOAT64) { return Err(WidthError::MissingCapability { name: "f64", @@ -241,15 +237,15 @@ impl super::Validator { } true } else { - width == 4 + scalar.width == 4 } } - crate::ScalarKind::Sint | crate::ScalarKind::Uint => width == 4, + crate::ScalarKind::Sint | crate::ScalarKind::Uint => scalar.width == 4, }; if good { Ok(()) } else { - Err(WidthError::Invalid(kind, width)) + Err(WidthError::Invalid(scalar.kind, scalar.width)) } } @@ -266,9 +262,9 @@ impl super::Validator { ) -> Result { use crate::TypeInner as Ti; Ok(match gctx.types[handle].inner { - Ti::Scalar { kind, width } => { - self.check_width(kind, width)?; - let shareable = if kind.is_numeric() { + Ti::Scalar(scalar) => { + self.check_width(scalar)?; + let shareable = if scalar.kind.is_numeric() { TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE } else { TypeFlags::empty() @@ -280,12 +276,12 @@ impl super::Validator { | TypeFlags::ARGUMENT | TypeFlags::CONSTRUCTIBLE | shareable, - Alignment::from_width(width), + Alignment::from_width(scalar.width), ) } - Ti::Vector { size, kind, width } => { - self.check_width(kind, width)?; - let shareable = if kind.is_numeric() { + Ti::Vector { size, scalar } => { + self.check_width(scalar)?; + let shareable = if scalar.kind.is_numeric() { TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE } else { TypeFlags::empty() @@ -298,7 +294,7 @@ impl super::Validator { | TypeFlags::ARGUMENT | TypeFlags::CONSTRUCTIBLE | shareable, - Alignment::from(size) * Alignment::from_width(width), + Alignment::from(size) * Alignment::from_width(scalar.width), ) } Ti::Matrix { @@ -306,7 +302,7 @@ impl super::Validator { rows, width, } => { - self.check_width(crate::ScalarKind::Float, width)?; + self.check_width(crate::Scalar::float(width))?; TypeInfo::new( TypeFlags::DATA | TypeFlags::SIZED @@ -317,7 +313,7 @@ impl super::Validator { Alignment::from(rows) * Alignment::from_width(width), ) } - Ti::Atomic { kind, width } => { + Ti::Atomic(crate::Scalar { kind, width }) => { let good = match kind { crate::ScalarKind::Bool | crate::ScalarKind::Float => false, crate::ScalarKind::Sint | crate::ScalarKind::Uint => width == 4, @@ -373,8 +369,7 @@ impl super::Validator { } Ti::ValuePointer { size: _, - kind, - width, + scalar, space, } => { // ValuePointer should be treated the same way as the equivalent @@ -384,7 +379,7 @@ impl super::Validator { // However, some cases are trivial: All our implicit base types // are DATA and SIZED, so we can never return // `InvalidPointerBase` or `InvalidPointerToUnsized`. - self.check_width(kind, width)?; + self.check_width(scalar)?; // `Validator::validate_function` actually checks the address // space of pointer arguments explicitly before checking the diff --git a/naga/tests/in/glsl/double-math-functions.frag b/naga/tests/in/glsl/double-math-functions.frag new file mode 100644 index 00000000000..78f53f9ef65 --- /dev/null +++ b/naga/tests/in/glsl/double-math-functions.frag @@ -0,0 +1,34 @@ +#version 450 + +void main() { + dvec4 a = dvec4(1.0); + dvec4 b = dvec4(2.0); + dmat4 m = dmat4(a, b, a, b); + int i = 5; + + dvec4 ceilOut = ceil(a); + dvec4 roundOut = round(a); + dvec4 floorOut = floor(a); + dvec4 fractOut = fract(a); + dvec4 truncOut = trunc(a); + dvec4 absOut = abs(a); + dvec4 sqrtOut = sqrt(a); + dvec4 inversesqrtOut = inversesqrt(a); + dvec4 signOut = sign(a); + dmat4 transposeOut = transpose(m); + dvec4 normalizeOut = normalize(a); + double lengthOut = length(a); + double determinantOut = determinant(m); + double modOut = mod(a.x, b.x); + double dotOut = dot(a, b); + dvec4 maxOut = max(a, b); + dvec4 minOut = min(a, b); + dvec4 reflectOut = reflect(a, b); + dvec3 crossOut = cross(a.xyz, b.xyz); + double distanceOut = distance(a, b); + dvec4 stepOut = step(a, b); + double ldexpOut = ldexp(a.x, i); + double smoothStepScalar = smoothstep(0.0, 1.0, 0.5); + dvec4 smoothStepVector = smoothstep(dvec4(0.0), dvec4(1.0), dvec4(0.5)); + dvec4 smoothStepMixed = smoothstep(0.0, 1.0, dvec4(0.5)); +} diff --git a/naga/tests/out/analysis/access.info.ron b/naga/tests/out/analysis/access.info.ron index 93eda7f396a..d59fb2a5098 100644 --- a/naga/tests/out/analysis/access.info.ron +++ b/naga/tests/out/analysis/access.info.ron @@ -55,10 +55,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -79,10 +79,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -168,8 +168,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -182,8 +184,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -228,8 +232,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -242,8 +248,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -279,8 +287,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -293,8 +303,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -305,10 +317,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -343,8 +355,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -366,8 +380,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -378,10 +394,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -425,8 +441,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -439,8 +457,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -451,10 +471,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -498,8 +518,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -521,8 +543,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -533,10 +557,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -545,10 +569,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -559,8 +583,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -570,10 +596,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -584,8 +610,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -595,10 +623,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -609,8 +637,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -650,10 +680,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -692,10 +722,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -706,8 +736,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -717,10 +749,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -731,8 +763,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -742,10 +776,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -756,8 +790,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -790,8 +826,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -802,10 +840,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -816,8 +854,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -850,8 +890,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -862,10 +904,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -876,8 +918,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -901,8 +945,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -915,8 +961,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -927,10 +975,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -953,8 +1001,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -976,8 +1026,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -988,10 +1040,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1023,8 +1075,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -1037,8 +1091,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -1049,10 +1105,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1084,8 +1140,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -1107,8 +1165,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -1119,10 +1179,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ], sampling: [], @@ -1152,10 +1212,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -1176,10 +1236,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -1322,8 +1382,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1336,8 +1398,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1394,8 +1458,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1408,8 +1474,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1457,8 +1525,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1471,8 +1541,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1483,10 +1555,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1533,8 +1605,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1556,8 +1630,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1568,10 +1644,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1627,8 +1703,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1641,8 +1719,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1653,10 +1733,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1712,8 +1792,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1735,8 +1817,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1747,10 +1831,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1789,10 +1873,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -1864,10 +1948,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1878,8 +1962,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1889,10 +1975,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1903,8 +1989,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1914,10 +2002,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1928,8 +2016,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1939,10 +2029,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1953,8 +2043,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1999,8 +2091,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2011,10 +2105,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2025,8 +2119,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -2071,8 +2167,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2083,10 +2181,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2097,8 +2195,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -2134,8 +2234,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2148,8 +2250,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2160,10 +2264,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2198,8 +2302,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2221,8 +2327,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2233,10 +2341,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2280,8 +2388,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2294,8 +2404,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2306,10 +2418,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2353,8 +2465,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2376,8 +2490,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2388,10 +2504,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ], sampling: [], @@ -2517,10 +2633,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ], sampling: [], @@ -2559,10 +2675,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2573,8 +2689,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -2584,10 +2702,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2598,8 +2716,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -2650,10 +2770,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2683,10 +2803,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2769,10 +2889,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -2811,8 +2931,10 @@ assignable_global: Some(2), ty: Value(ValuePointer( size: Some(Tri), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD | STORE"), ), @@ -2827,8 +2949,10 @@ assignable_global: Some(2), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD | STORE"), ), @@ -2841,10 +2965,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2909,10 +3033,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -2921,10 +3045,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -2933,10 +3057,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3070,10 +3194,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3082,10 +3206,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3094,10 +3218,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3106,10 +3230,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3139,10 +3263,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3172,10 +3296,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3225,8 +3349,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Sint, - width: 4, + scalar: ( + kind: Sint, + width: 4, + ), )), ), ( @@ -3238,8 +3364,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3251,8 +3379,10 @@ assignable_global: None, ty: Value(Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3262,10 +3392,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3334,8 +3464,10 @@ assignable_global: Some(2), ty: Value(ValuePointer( size: Some(Tri), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD | STORE"), ), @@ -3350,8 +3482,10 @@ assignable_global: Some(2), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD | STORE"), ), @@ -3364,10 +3498,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3404,10 +3538,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3418,8 +3552,10 @@ assignable_global: None, ty: Value(Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3429,10 +3565,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3443,8 +3579,10 @@ assignable_global: None, ty: Value(Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3454,10 +3592,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3468,8 +3606,10 @@ assignable_global: None, ty: Value(Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3479,10 +3619,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3493,8 +3633,10 @@ assignable_global: None, ty: Value(Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3541,10 +3683,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3555,8 +3697,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), )), ), ( @@ -3566,10 +3710,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3580,8 +3724,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), )), ), ( @@ -3656,10 +3802,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3691,10 +3837,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3705,8 +3851,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ], @@ -3737,10 +3885,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3761,10 +3909,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3775,8 +3923,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3786,10 +3936,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3800,8 +3950,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3831,27 +3983,27 @@ ), ], const_expression_types: [ - Value(Scalar( + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Uint, width: 4, - )), + ))), Handle(2), - Value(Scalar( + Value(Scalar(( kind: Sint, width: 4, - )), + ))), Handle(4), ], ) \ No newline at end of file diff --git a/naga/tests/out/analysis/collatz.info.ron b/naga/tests/out/analysis/collatz.info.ron index 5b32bf44ad4..040e71c7e7e 100644 --- a/naga/tests/out/analysis/collatz.info.ron +++ b/naga/tests/out/analysis/collatz.info.ron @@ -47,10 +47,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -80,10 +80,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -92,10 +92,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Bool, width: 1, - )), + ))), ), ( uniformity: ( @@ -113,10 +113,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -134,10 +134,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -146,10 +146,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Bool, width: 1, - )), + ))), ), ( uniformity: ( @@ -167,10 +167,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -188,10 +188,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -218,10 +218,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -248,10 +248,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -334,10 +334,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -388,10 +388,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( diff --git a/naga/tests/out/analysis/shadow.info.ron b/naga/tests/out/analysis/shadow.info.ron index 3553f9030b8..bd46d9187fe 100644 --- a/naga/tests/out/analysis/shadow.info.ron +++ b/naga/tests/out/analysis/shadow.info.ron @@ -119,10 +119,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -131,10 +131,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Bool, width: 1, - )), + ))), ), ( uniformity: ( @@ -143,10 +143,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -155,10 +155,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -194,10 +194,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -226,8 +226,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -246,10 +248,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -258,10 +260,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -270,10 +272,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -282,10 +284,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -303,10 +305,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -315,10 +317,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -345,10 +347,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -357,10 +359,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -378,10 +380,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -390,10 +392,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -402,10 +404,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ], sampling: [], @@ -695,8 +697,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: None, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), space: Uniform, )), ), @@ -707,10 +711,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -719,10 +723,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -731,10 +735,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Bool, width: 1, - )), + ))), ), ( uniformity: ( @@ -832,8 +836,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -923,8 +929,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -937,10 +945,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1002,8 +1010,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -1016,10 +1026,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1081,8 +1091,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -1095,10 +1107,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1118,8 +1130,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Private, )), ), @@ -1130,10 +1144,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1144,8 +1158,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Private, )), ), @@ -1156,10 +1172,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1170,8 +1186,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Private, )), ), @@ -1182,10 +1200,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1221,10 +1239,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1304,8 +1322,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -1318,10 +1338,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1383,8 +1403,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -1397,10 +1419,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1462,8 +1484,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -1476,10 +1500,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1643,81 +1667,81 @@ ), ], const_expression_types: [ - Value(Scalar( + Value(Scalar(( kind: Float, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Float, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Float, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Float, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Float, width: 4, - )), + ))), Handle(1), Handle(1), Handle(1), Handle(2), - Value(Scalar( + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), + ))), ], ) \ No newline at end of file diff --git a/naga/tests/out/glsl/push-constants.main.Fragment.glsl b/naga/tests/out/glsl/push-constants.main.Fragment.glsl index fa1be9f61f1..8131e9e8976 100644 --- a/naga/tests/out/glsl/push-constants.main.Fragment.glsl +++ b/naga/tests/out/glsl/push-constants.main.Fragment.glsl @@ -9,14 +9,14 @@ struct PushConstants { struct FragmentIn { vec4 color; }; -uniform PushConstants pc; +uniform PushConstants _push_constant_binding_fs; layout(location = 0) smooth in vec4 _vs2fs_location0; layout(location = 0) out vec4 _fs2p_location0; void main() { FragmentIn in_ = FragmentIn(_vs2fs_location0); - float _e4 = pc.multiplier; + float _e4 = _push_constant_binding_fs.multiplier; _fs2p_location0 = (in_.color * _e4); return; } diff --git a/naga/tests/out/glsl/push-constants.vert_main.Vertex.glsl b/naga/tests/out/glsl/push-constants.vert_main.Vertex.glsl index 27cd7037abf..4519dc4c6c2 100644 --- a/naga/tests/out/glsl/push-constants.vert_main.Vertex.glsl +++ b/naga/tests/out/glsl/push-constants.vert_main.Vertex.glsl @@ -9,14 +9,14 @@ struct PushConstants { struct FragmentIn { vec4 color; }; -uniform PushConstants pc; +uniform PushConstants _push_constant_binding_vs; layout(location = 0) in vec2 _p2vs_location0; void main() { vec2 pos = _p2vs_location0; uint vi = uint(gl_VertexID); - float _e5 = pc.multiplier; + float _e5 = _push_constant_binding_vs.multiplier; gl_Position = vec4(((float(vi) * _e5) * pos), 0.0, 1.0); return; } diff --git a/naga/tests/out/ir/access.compact.ron b/naga/tests/out/ir/access.compact.ron index 65f9622f2e3..2f668786e22 100644 --- a/naga/tests/out/ir/access.compact.ron +++ b/naga/tests/out/ir/access.compact.ron @@ -2,25 +2,27 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Tri, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Sint, width: 4, - ), + )), ), ( name: Some("GlobalConst"), @@ -88,10 +90,10 @@ ), ( name: None, - inner: Atomic( + inner: Atomic(( kind: Sint, width: 4, - ), + )), ), ( name: None, @@ -105,8 +107,10 @@ name: None, inner: Vector( size: Bi, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( @@ -195,8 +199,10 @@ name: None, inner: Vector( size: Bi, - kind: Sint, - width: 4, + scalar: ( + kind: Sint, + width: 4, + ), ), ), ( @@ -231,10 +237,10 @@ ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Float, width: 4, - ), + )), ), ( name: None, @@ -263,8 +269,10 @@ name: None, inner: Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( diff --git a/naga/tests/out/ir/access.ron b/naga/tests/out/ir/access.ron index 77d95dd58fa..f484189bf48 100644 --- a/naga/tests/out/ir/access.ron +++ b/naga/tests/out/ir/access.ron @@ -2,25 +2,27 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Tri, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Sint, width: 4, - ), + )), ), ( name: Some("GlobalConst"), @@ -88,10 +90,10 @@ ), ( name: None, - inner: Atomic( + inner: Atomic(( kind: Sint, width: 4, - ), + )), ), ( name: None, @@ -105,8 +107,10 @@ name: None, inner: Vector( size: Bi, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( @@ -195,16 +199,20 @@ name: None, inner: Vector( size: Bi, - kind: Sint, - width: 4, + scalar: ( + kind: Sint, + width: 4, + ), ), ), ( name: None, inner: Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( @@ -239,10 +247,10 @@ ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Float, width: 4, - ), + )), ), ( name: None, @@ -271,8 +279,10 @@ name: None, inner: Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( @@ -296,16 +306,20 @@ name: None, inner: Vector( size: Quad, - kind: Sint, - width: 4, + scalar: ( + kind: Sint, + width: 4, + ), ), ), ( name: None, inner: Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( diff --git a/naga/tests/out/ir/collatz.compact.ron b/naga/tests/out/ir/collatz.compact.ron index 7cad54b713d..cfc3bfa0ee4 100644 --- a/naga/tests/out/ir/collatz.compact.ron +++ b/naga/tests/out/ir/collatz.compact.ron @@ -2,10 +2,10 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, @@ -33,8 +33,10 @@ name: None, inner: Vector( size: Tri, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ], diff --git a/naga/tests/out/ir/collatz.ron b/naga/tests/out/ir/collatz.ron index 8146909c1ec..effde120a50 100644 --- a/naga/tests/out/ir/collatz.ron +++ b/naga/tests/out/ir/collatz.ron @@ -2,10 +2,10 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, @@ -33,8 +33,10 @@ name: None, inner: Vector( size: Tri, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ], diff --git a/naga/tests/out/ir/shadow.compact.ron b/naga/tests/out/ir/shadow.compact.ron index 9ca6799c212..9cda0a4940e 100644 --- a/naga/tests/out/ir/shadow.compact.ron +++ b/naga/tests/out/ir/shadow.compact.ron @@ -2,40 +2,46 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Float, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( name: None, inner: Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( @@ -50,17 +56,19 @@ ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Sint, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Quad, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( diff --git a/naga/tests/out/ir/shadow.ron b/naga/tests/out/ir/shadow.ron index 07bf66fcc8b..b045750a293 100644 --- a/naga/tests/out/ir/shadow.ron +++ b/naga/tests/out/ir/shadow.ron @@ -2,47 +2,53 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Float, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Bool, width: 1, - ), + )), ), ( name: None, inner: Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( @@ -63,10 +69,10 @@ ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Sint, width: 4, - ), + )), ), ( name: None, @@ -86,8 +92,10 @@ name: None, inner: Vector( size: Quad, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( diff --git a/naga/tests/out/wgsl/double-math-functions.frag.wgsl b/naga/tests/out/wgsl/double-math-functions.frag.wgsl new file mode 100644 index 00000000000..d21d99f4de8 --- /dev/null +++ b/naga/tests/out/wgsl/double-math-functions.frag.wgsl @@ -0,0 +1,107 @@ +fn main_1() { + var a: vec4; + var b: vec4; + var m: mat4x4; + var i: i32 = 5; + var ceilOut: vec4; + var roundOut: vec4; + var floorOut: vec4; + var fractOut: vec4; + var truncOut: vec4; + var absOut: vec4; + var sqrtOut: vec4; + var inversesqrtOut: vec4; + var signOut: vec4; + var transposeOut: mat4x4; + var normalizeOut: vec4; + var lengthOut: f64; + var determinantOut: f64; + var modOut: f64; + var dotOut: f64; + var maxOut: vec4; + var minOut: vec4; + var reflectOut: vec4; + var crossOut: vec3; + var distanceOut: f64; + var stepOut: vec4; + var ldexpOut: f64; + var smoothStepScalar: f64; + var smoothStepVector: vec4; + var smoothStepMixed: vec4; + + a = vec4(f64(1.0)); + b = vec4(f64(2.0)); + let _e8 = a; + let _e9 = b; + let _e10 = a; + let _e11 = b; + m = mat4x4(vec4(_e8.x, _e8.y, _e8.z, _e8.w), vec4(_e9.x, _e9.y, _e9.z, _e9.w), vec4(_e10.x, _e10.y, _e10.z, _e10.w), vec4(_e11.x, _e11.y, _e11.z, _e11.w)); + let _e37 = a; + ceilOut = ceil(_e37); + let _e41 = a; + roundOut = round(_e41); + let _e45 = a; + floorOut = floor(_e45); + let _e49 = a; + fractOut = fract(_e49); + let _e53 = a; + truncOut = trunc(_e53); + let _e57 = a; + absOut = abs(_e57); + let _e61 = a; + sqrtOut = sqrt(_e61); + let _e65 = a; + inversesqrtOut = inverseSqrt(_e65); + let _e69 = a; + signOut = sign(_e69); + let _e73 = m; + transposeOut = transpose(_e73); + let _e77 = a; + normalizeOut = normalize(_e77); + let _e81 = a; + lengthOut = length(_e81); + let _e85 = m; + determinantOut = determinant(_e85); + let _e88 = a; + let _e90 = b; + let _e92 = a; + let _e94 = b; + modOut = (_e92.x - (floor((_e92.x / _e94.x)) * _e94.x)); + let _e103 = a; + let _e104 = b; + dotOut = dot(_e103, _e104); + let _e109 = a; + let _e110 = b; + maxOut = max(_e109, _e110); + let _e115 = a; + let _e116 = b; + minOut = min(_e115, _e116); + let _e121 = a; + let _e122 = b; + reflectOut = reflect(_e121, _e122); + let _e125 = a; + let _e127 = b; + let _e129 = a; + let _e131 = b; + crossOut = cross(_e129.xyz, _e131.xyz); + let _e137 = a; + let _e138 = b; + distanceOut = distance(_e137, _e138); + let _e143 = a; + let _e144 = b; + stepOut = step(_e143, _e144); + let _e147 = a; + let _e150 = a; + let _e152 = i; + ldexpOut = ldexp(_e150.x, _e152); + smoothStepScalar = f64(smoothstep(0.0, 1.0, 0.5)); + smoothStepVector = smoothstep(vec4(f64(0.0)), vec4(f64(1.0)), vec4(f64(0.5))); + smoothStepMixed = smoothstep(vec4(f64(0.0)), vec4(f64(1.0)), vec4(f64(0.5))); + return; +} + +@fragment +fn main() { + main_1(); + return; +} diff --git a/tests/src/image.rs b/tests/src/image.rs index 0e3ea9ea8e5..ee8fa941875 100644 --- a/tests/src/image.rs +++ b/tests/src/image.rs @@ -388,7 +388,7 @@ fn copy_texture_to_buffer_with_aspect( aspect: TextureAspect, ) { let (block_width, block_height) = texture.format().block_dimensions(); - let block_size = texture.format().block_size(Some(aspect)).unwrap(); + let block_size = texture.format().block_copy_size(Some(aspect)).unwrap(); let bytes_per_row = align_to( (texture.width() / block_width) * block_size, COPY_BYTES_PER_ROW_ALIGNMENT, @@ -501,7 +501,7 @@ impl ReadbackBuffers { let mut buffer_depth_bytes_per_row = (texture.width() / block_width) * texture .format() - .block_size(Some(TextureAspect::DepthOnly)) + .block_copy_size(Some(TextureAspect::DepthOnly)) .unwrap_or(4); if should_align_buffer_size { buffer_depth_bytes_per_row = @@ -515,7 +515,7 @@ impl ReadbackBuffers { (texture.width() / block_width) * texture .format() - .block_size(Some(TextureAspect::StencilOnly)) + .block_copy_size(Some(TextureAspect::StencilOnly)) .unwrap_or(4), COPY_BYTES_PER_ROW_ALIGNMENT, ); @@ -542,8 +542,8 @@ impl ReadbackBuffers { buffer_stencil: Some(buffer_stencil), } } else { - let mut bytes_per_row = - (texture.width() / block_width) * texture.format().block_size(None).unwrap_or(4); + let mut bytes_per_row = (texture.width() / block_width) + * texture.format().block_copy_size(None).unwrap_or(4); if should_align_buffer_size { bytes_per_row = align_to(bytes_per_row, COPY_BYTES_PER_ROW_ALIGNMENT); } @@ -581,7 +581,7 @@ impl ReadbackBuffers { device.poll(Maintain::Wait); let (block_width, block_height) = self.texture_format.block_dimensions(); let expected_bytes_per_row = (self.texture_width / block_width) - * self.texture_format.block_size(aspect).unwrap_or(4); + * self.texture_format.block_copy_size(aspect).unwrap_or(4); let expected_buffer_size = expected_bytes_per_row * (self.texture_height / block_height) * self.texture_depth_or_array_layers; @@ -625,12 +625,16 @@ impl ReadbackBuffers { buffer_zero && stencil_buffer_zero } - pub fn check_buffer_contents(&self, device: &Device, expected_data: &[u8]) -> bool { - let result = self - .retrieve_buffer(device, &self.buffer, self.buffer_aspect()) - .iter() - .eq(expected_data.iter()); + pub fn assert_buffer_contents(&self, device: &Device, expected_data: &[u8]) { + let result_buffer = self.retrieve_buffer(device, &self.buffer, self.buffer_aspect()); + assert!( + result_buffer.len() >= expected_data.len(), + "Result buffer ({}) smaller than expected buffer ({})", + result_buffer.len(), + expected_data.len() + ); + let result_buffer = &result_buffer[..expected_data.len()]; + assert_eq!(result_buffer, expected_data); self.buffer.unmap(); - result } } diff --git a/tests/src/native.rs b/tests/src/native.rs index 8c3dd2fb192..2d0fc7c7eea 100644 --- a/tests/src/native.rs +++ b/tests/src/native.rs @@ -82,7 +82,7 @@ pub fn main() -> MainResult { &std::fs::read_to_string(format!("{}/../.gpuconfig", env!("CARGO_MANIFEST_DIR"))) .context("Failed to read .gpuconfig, did you run the tests via `cargo xtask test`?")? }; - let report = GpuReport::from_json(config_text).context("Could not pare .gpuconfig JSON")?; + let report = GpuReport::from_json(config_text).context("Could not parse .gpuconfig JSON")?; let mut test_guard = TEST_LIST.lock(); execute_native(test_guard.drain(..).flat_map(|test| { diff --git a/tests/tests/device.rs b/tests/tests/device.rs index 108c7cc26a6..2288fd0cb65 100644 --- a/tests/tests/device.rs +++ b/tests/tests/device.rs @@ -448,3 +448,35 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne buffer_for_unmap.unmap(); }); }); + +#[gpu_test] +static DEVICE_DESTROY_THEN_LOST: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters(TestParameters::default()) + .run_sync(|ctx| { + // This test checks that when device.destroy is called, the provided + // DeviceLostClosure is called with reason DeviceLostReason::Destroyed. + let was_called = std::sync::Arc::::new(false.into()); + + // Set a LoseDeviceCallback on the device. + let was_called_clone = was_called.clone(); + let callback = Box::new(move |reason, _m| { + was_called_clone.store(true, std::sync::atomic::Ordering::SeqCst); + assert!( + matches!(reason, wgt::DeviceLostReason::Destroyed), + "Device lost info reason should match DeviceLostReason::Destroyed." + ); + }); + ctx.device.set_device_lost_callback(callback); + + // Destroy the device. + ctx.device.destroy(); + + // Make sure the device queues are empty, which ensures that the closure + // has been called. + assert!(ctx.device.poll(wgpu::Maintain::Wait)); + + assert!( + was_called.load(std::sync::atomic::Ordering::SeqCst), + "Device lost callback should have been called." + ); + }); diff --git a/tests/tests/gpu.rs b/tests/tests/gpu.rs index a5fbcde9da9..efa15df60c5 100644 --- a/tests/tests/gpu.rs +++ b/tests/tests/gpu.rs @@ -1,4 +1,5 @@ mod regression { + mod issue_3349; mod issue_3457; mod issue_4024; mod issue_4122; @@ -15,10 +16,12 @@ mod device; mod encoder; mod external_texture; mod instance; +mod life_cycle; mod occlusion_query; mod partially_bounded_arrays; mod pipeline; mod poll; +mod push_constants; mod query_set; mod queue_transfer; mod resource_descriptor_accessor; diff --git a/tests/tests/life_cycle.rs b/tests/tests/life_cycle.rs new file mode 100644 index 00000000000..c838dea1431 --- /dev/null +++ b/tests/tests/life_cycle.rs @@ -0,0 +1,95 @@ +use wgpu_test::{fail, gpu_test, GpuTestConfiguration}; + +#[gpu_test] +static BUFFER_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { + let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: 256, + usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }); + + buffer.destroy(); + + buffer.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + fail(&ctx.device, || { + buffer + .slice(..) + .map_async(wgpu::MapMode::Write, move |_| {}); + }); + + buffer.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + buffer.destroy(); + + buffer.destroy(); + + let descriptor = wgpu::BufferDescriptor { + label: None, + size: 256, + usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }; + + // Scopes to mix up the drop/poll ordering. + { + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + } + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + ctx.device.poll(wgpu::MaintainBase::Wait); + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + { + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + let buffer = ctx.device.create_buffer(&descriptor); + ctx.device.poll(wgpu::MaintainBase::Wait); + buffer.destroy(); + } + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + ctx.device.poll(wgpu::MaintainBase::Wait); +}); + +#[gpu_test] +static TEXTURE_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { + let texture = ctx.device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width: 128, + height: 128, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, // multisampling is not supported for clear + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Snorm, + usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }); + + texture.destroy(); + + texture.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + texture.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + texture.destroy(); + + texture.destroy(); +}); diff --git a/tests/tests/partially_bounded_arrays/mod.rs b/tests/tests/partially_bounded_arrays/mod.rs index acadaad67b3..5a41ae8f29c 100644 --- a/tests/tests/partially_bounded_arrays/mod.rs +++ b/tests/tests/partially_bounded_arrays/mod.rs @@ -97,9 +97,6 @@ static PARTIALLY_BOUNDED_ARRAY: GpuTestConfiguration = GpuTestConfiguration::new ctx.queue.submit(Some(encoder.finish())); - assert!( - readback_buffers - .check_buffer_contents(device, bytemuck::bytes_of(&[4.0f32, 3.0, 2.0, 1.0])), - "texture storage values are incorrect!" - ); + readback_buffers + .assert_buffer_contents(device, bytemuck::bytes_of(&[4.0f32, 3.0, 2.0, 1.0])); }); diff --git a/tests/tests/push_constants.rs b/tests/tests/push_constants.rs new file mode 100644 index 00000000000..e39000173c4 --- /dev/null +++ b/tests/tests/push_constants.rs @@ -0,0 +1,151 @@ +use std::num::NonZeroU64; + +use wgpu_test::{gpu_test, GpuTestConfiguration, TestParameters, TestingContext}; + +/// We want to test that partial updates to push constants work as expected. +/// +/// As such, we dispatch two compute passes, one which writes the values +/// before a parital update, and one which writes the values after the partial update. +/// +/// If the update code is working correctly, the values not written to by the second update +/// will remain unchanged. +#[gpu_test] +static PARTIAL_UPDATE: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters( + TestParameters::default() + .features(wgpu::Features::PUSH_CONSTANTS) + .limits(wgpu::Limits { + max_push_constant_size: 32, + ..Default::default() + }), + ) + .run_sync(partial_update_test); + +const SHADER: &str = r#" + struct Pc { + offset: u32, + vector: vec4f, + } + + var pc: Pc; + + @group(0) @binding(0) + var output: array; + + @compute @workgroup_size(1) + fn main() { + output[pc.offset] = pc.vector; + } +"#; + +fn partial_update_test(ctx: TestingContext) { + let sm = ctx + .device + .create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("shader"), + source: wgpu::ShaderSource::Wgsl(SHADER.into()), + }); + + let bgl = ctx + .device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("bind_group_layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::COMPUTE, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: false }, + has_dynamic_offset: false, + min_binding_size: NonZeroU64::new(16), + }, + count: None, + }], + }); + + let gpu_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { + label: Some("gpu_buffer"), + size: 32, + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }); + + let cpu_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { + label: Some("cpu_buffer"), + size: 32, + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, + mapped_at_creation: false, + }); + + let bind_group = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("bind_group"), + layout: &bgl, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: gpu_buffer.as_entire_binding(), + }], + }); + + let pipeline_layout = ctx + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("pipeline_layout"), + bind_group_layouts: &[&bgl], + push_constant_ranges: &[wgpu::PushConstantRange { + stages: wgpu::ShaderStages::COMPUTE, + range: 0..32, + }], + }); + + let pipeline = ctx + .device + .create_compute_pipeline(&wgpu::ComputePipelineDescriptor { + label: Some("pipeline"), + layout: Some(&pipeline_layout), + module: &sm, + entry_point: "main", + }); + + let mut encoder = ctx + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("encoder"), + }); + + { + let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { + label: Some("compute_pass"), + timestamp_writes: None, + }); + cpass.set_pipeline(&pipeline); + cpass.set_bind_group(0, &bind_group, &[]); + + // -- Dispatch 0 -- + + // Dispatch number + cpass.set_push_constants(0, bytemuck::bytes_of(&[0_u32])); + // Update the whole vector. + cpass.set_push_constants(16, bytemuck::bytes_of(&[1.0_f32, 2.0, 3.0, 4.0])); + cpass.dispatch_workgroups(1, 1, 1); + + // -- Dispatch 1 -- + + // Dispatch number + cpass.set_push_constants(0, bytemuck::bytes_of(&[1_u32])); + // Update just the y component of the vector. + cpass.set_push_constants(20, bytemuck::bytes_of(&[5.0_f32])); + cpass.dispatch_workgroups(1, 1, 1); + } + + encoder.copy_buffer_to_buffer(&gpu_buffer, 0, &cpu_buffer, 0, 32); + ctx.queue.submit([encoder.finish()]); + cpu_buffer.slice(..).map_async(wgpu::MapMode::Read, |_| ()); + ctx.device.poll(wgpu::Maintain::Wait); + + let data = cpu_buffer.slice(..).get_mapped_range(); + + let floats: &[f32] = bytemuck::cast_slice(&data); + + // first 4 floats the initial value + // second 4 floats the first update + assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 1.0, 5.0, 3.0, 4.0]); +} diff --git a/tests/tests/regression/issue_3349.fs.wgsl b/tests/tests/regression/issue_3349.fs.wgsl new file mode 100644 index 00000000000..d6a5ea5ceb3 --- /dev/null +++ b/tests/tests/regression/issue_3349.fs.wgsl @@ -0,0 +1,46 @@ +struct ShaderData { + a: f32, + b: f32, + c: f32, + d: f32, +} + +@group(0) @binding(0) +var data1: ShaderData; + +var data2: ShaderData; + +struct FsIn { + @builtin(position) position: vec4f, + @location(0) data1: vec4f, + @location(1) data2: vec4f, +} + +@fragment +fn fs_main(fs_in: FsIn) -> @location(0) vec4f { + let floored = vec2u(floor(fs_in.position.xy)); + // We're outputting a 2x2 image, each pixel coming from a different source + let serial = floored.x + floored.y * 2u; + + switch serial { + // (0, 0) - uniform buffer from the vertex shader + case 0u: { + return fs_in.data1; + } + // (1, 0) - push constant from the vertex shader + case 1u: { + return fs_in.data2; + } + // (0, 1) - uniform buffer from the fragment shader + case 2u: { + return vec4f(data1.a, data1.b, data1.c, data1.d); + } + // (1, 1) - push constant from the fragment shader + case 3u: { + return vec4f(data2.a, data2.b, data2.c, data2.d); + } + default: { + return vec4f(0.0); + } + } +} diff --git a/tests/tests/regression/issue_3349.rs b/tests/tests/regression/issue_3349.rs new file mode 100644 index 00000000000..5db5575ddf1 --- /dev/null +++ b/tests/tests/regression/issue_3349.rs @@ -0,0 +1,178 @@ +use wgpu::util::DeviceExt; +use wgpu_test::{ + gpu_test, image::ReadbackBuffers, GpuTestConfiguration, TestParameters, TestingContext, +}; + +/// We thought we had an OpenGL bug that, when running without explicit in-shader locations, +/// we will not properly bind uniform buffers to both the vertex and fragment +/// shaders. This turned out to not reproduce at all with this test case. +/// +/// However, it also caught issues with the push constant implementation, +/// making sure that it works correctly with different definitions for the push constant +/// block in vertex and fragment shaders. +/// +/// This test needs to be able to run on GLES 3.0 +/// +/// What this test does is render a 2x2 texture. Each pixel corresponds to a different +/// data source. +/// +/// top left: Vertex Shader / Uniform Buffer +/// top right: Vertex Shader / Push Constant +/// bottom left: Fragment Shader / Uniform Buffer +/// bottom right: Fragment Shader / Push Constant +/// +/// We then validate the data is correct from every position. +#[gpu_test] +static MULTI_STAGE_DATA_BINDING: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters( + TestParameters::default() + .features(wgpu::Features::PUSH_CONSTANTS) + .limits(wgpu::Limits { + max_push_constant_size: 16, + ..Default::default() + }), + ) + .run_sync(multi_stage_data_binding_test); + +fn multi_stage_data_binding_test(ctx: TestingContext) { + // We use different shader modules to allow us to use different + // types for the uniform and push constant blocks between stages. + let vs_sm = ctx + .device + .create_shader_module(wgpu::include_wgsl!("issue_3349.vs.wgsl")); + + let fs_sm = ctx + .device + .create_shader_module(wgpu::include_wgsl!("issue_3349.fs.wgsl")); + + // We start with u8s then convert to float, to make sure we don't have + // cross-vendor rounding issues unorm. + let input_as_unorm: [u8; 4] = [25_u8, 50, 75, 100]; + let input = input_as_unorm.map(|v| v as f32 / 255.0); + + let buffer = ctx + .device + .create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("buffer"), + contents: bytemuck::cast_slice(&input), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + + let bgl = ctx + .device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("bgl"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + }); + + let bg = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("bg"), + layout: &bgl, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + }], + }); + + let pll = ctx + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("pll"), + bind_group_layouts: &[&bgl], + push_constant_ranges: &[wgpu::PushConstantRange { + stages: wgpu::ShaderStages::VERTEX_FRAGMENT, + range: 0..16, + }], + }); + + let pipeline = ctx + .device + .create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("pipeline"), + layout: Some(&pll), + vertex: wgpu::VertexState { + module: &vs_sm, + entry_point: "vs_main", + buffers: &[], + }, + fragment: Some(wgpu::FragmentState { + module: &fs_sm, + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState::default(), + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + }); + + let texture = ctx.device.create_texture(&wgpu::TextureDescriptor { + label: Some("texture"), + size: wgpu::Extent3d { + width: 2, + height: 2, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + // Important: NOT srgb. + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::RENDER_ATTACHMENT, + view_formats: &[], + }); + + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + + let mut encoder = ctx + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("encoder"), + }); + + { + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("rpass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + + rpass.set_pipeline(&pipeline); + rpass.set_bind_group(0, &bg, &[]); + rpass.set_push_constants( + wgpu::ShaderStages::VERTEX_FRAGMENT, + 0, + bytemuck::cast_slice(&input), + ); + rpass.draw(0..3, 0..1); + } + + let buffers = ReadbackBuffers::new(&ctx.device, &texture); + buffers.copy_from(&ctx.device, &mut encoder, &texture); + ctx.queue.submit([encoder.finish()]); + + let result = input_as_unorm.repeat(4); + buffers.assert_buffer_contents(&ctx.device, &result); +} diff --git a/tests/tests/regression/issue_3349.vs.wgsl b/tests/tests/regression/issue_3349.vs.wgsl new file mode 100644 index 00000000000..85992a756b7 --- /dev/null +++ b/tests/tests/regression/issue_3349.vs.wgsl @@ -0,0 +1,22 @@ +@group(0) @binding(0) +var data1: vec4f; + +// D3DCompile requires this to be a struct +struct Pc { + inner: vec4f, +} + +var data2: Pc; + +struct VsOut { + @builtin(position) position: vec4f, + @location(0) data1: vec4f, + @location(1) data2: vec4f, +} + +@vertex +fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> VsOut { + let uv = vec2f(f32((vertexIndex << 1u) & 2u), f32(vertexIndex & 2u)); + let position = vec4f(uv * 2.0 - 1.0, 0.0, 1.0); + return VsOut(position, data1, data2.inner); +} diff --git a/tests/tests/scissor_tests/mod.rs b/tests/tests/scissor_tests/mod.rs index d53d31cdace..40801a343ad 100644 --- a/tests/tests/scissor_tests/mod.rs +++ b/tests/tests/scissor_tests/mod.rs @@ -94,7 +94,7 @@ fn scissor_test_impl(ctx: &TestingContext, scissor_rect: Rect, expected_data: [u readback_buffer.copy_from(&ctx.device, &mut encoder, &texture); ctx.queue.submit(Some(encoder.finish())); } - assert!(readback_buffer.check_buffer_contents(&ctx.device, &expected_data)); + readback_buffer.assert_buffer_contents(&ctx.device, &expected_data); } #[gpu_test] diff --git a/tests/tests/shader/mod.rs b/tests/tests/shader/mod.rs index 923958b741f..79fb6e073e4 100644 --- a/tests/tests/shader/mod.rs +++ b/tests/tests/shader/mod.rs @@ -41,6 +41,8 @@ impl InputStorageType { struct ShaderTest { /// Human readable name name: String, + /// Header text. This is arbitrary code injected at the top of the shader. Replaces {{header}} + header: String, /// This text will be the body of the `Input` struct. Replaces "{{input_members}}" /// in the shader_test shader. custom_struct_members: String, @@ -133,6 +135,7 @@ impl ShaderTest { ) -> Self { Self { name, + header: String::new(), custom_struct_members, body, input_type: String::from("CustomStruct"), @@ -145,6 +148,12 @@ impl ShaderTest { } } + fn header(mut self, header: String) -> Self { + self.header = header; + + self + } + /// Add another set of possible outputs. If any of the given /// output values are seen it's considered a success (i.e. this is OR, not AND). /// @@ -273,6 +282,7 @@ fn shader_input_output_test( // This isn't terribly efficient but the string is short and it's a test. // The body and input members are the longest part, so do them last. let mut processed = source + .replace("{{header}}", &test.header) .replace("{{storage_type}}", storage_type.as_str()) .replace("{{input_type}}", &test.input_type) .replace("{{output_type}}", &test.output_type) diff --git a/tests/tests/shader/shader_test.wgsl b/tests/tests/shader/shader_test.wgsl index efe8692bd5b..91c86365746 100644 --- a/tests/tests/shader/shader_test.wgsl +++ b/tests/tests/shader/shader_test.wgsl @@ -1,3 +1,5 @@ +{{header}} + struct CustomStruct { {{input_members}} } diff --git a/tests/tests/shader/struct_layout.rs b/tests/tests/shader/struct_layout.rs index f17dceac081..a7460b9abdf 100644 --- a/tests/tests/shader/struct_layout.rs +++ b/tests/tests/shader/struct_layout.rs @@ -99,7 +99,7 @@ fn create_struct_layout_tests(storage_type: InputStorageType) -> Vec } } - // https://github.com/gfx-rs/naga/issues/1785 + // https://github.com/gfx-rs/wgpu/issues/4371 let failures = if storage_type == InputStorageType::Uniform && rows == 2 { Backends::GL } else { @@ -171,6 +171,51 @@ fn create_struct_layout_tests(storage_type: InputStorageType) -> Vec } } + // Nested struct and array test. + // + // This tries to exploit all the weird edge cases of the struct layout algorithm. + { + let header = + String::from("struct Inner { scalar: f32, member: array, 2>, scalar2: f32 }"); + let members = String::from("inner: Inner, scalar3: f32, vector: vec3, scalar4: f32"); + let direct = String::from( + "\ + output[0] = bitcast(input.inner.scalar); + output[1] = bitcast(input.inner.member[0].x); + output[2] = bitcast(input.inner.member[0].y); + output[3] = bitcast(input.inner.member[0].z); + output[4] = bitcast(input.inner.member[1].x); + output[5] = bitcast(input.inner.member[1].y); + output[6] = bitcast(input.inner.member[1].z); + output[7] = bitcast(input.inner.scalar2); + output[8] = bitcast(input.scalar3); + output[9] = bitcast(input.vector.x); + output[10] = bitcast(input.vector.y); + output[11] = bitcast(input.vector.z); + output[12] = bitcast(input.scalar4); + ", + ); + + tests.push( + ShaderTest::new( + String::from("nested struct and array"), + members, + direct, + &input_values, + &[ + 0, // inner.scalar + 4, 5, 6, // inner.member[0] + 8, 9, 10, // inner.member[1] + 12, // scalar2 + 16, // scalar3 + 20, 21, 22, // vector + 23, // scalar4 + ], + ) + .header(header), + ); + } + tests } @@ -215,8 +260,7 @@ static PUSH_CONSTANT_INPUT: GpuTestConfiguration = GpuTestConfiguration::new() .limits(Limits { max_push_constant_size: MAX_BUFFER_SIZE as u32, ..Limits::downlevel_defaults() - }) - .expect_fail(FailureCase::backend(Backends::GL)), + }), ) .run_sync(|ctx| { shader_input_output_test( diff --git a/tests/tests/shader_primitive_index/mod.rs b/tests/tests/shader_primitive_index/mod.rs index e5157a7c93f..13ba76a3288 100644 --- a/tests/tests/shader_primitive_index/mod.rs +++ b/tests/tests/shader_primitive_index/mod.rs @@ -192,5 +192,5 @@ fn pulling_common( } readback_buffer.copy_from(&ctx.device, &mut encoder, &color_texture); ctx.queue.submit(Some(encoder.finish())); - assert!(readback_buffer.check_buffer_contents(&ctx.device, expected)); + readback_buffer.assert_buffer_contents(&ctx.device, expected); } diff --git a/tests/tests/zero_init_texture_after_discard.rs b/tests/tests/zero_init_texture_after_discard.rs index 584cfdb7b87..82d6ba85d5c 100644 --- a/tests/tests/zero_init_texture_after_discard.rs +++ b/tests/tests/zero_init_texture_after_discard.rs @@ -167,7 +167,7 @@ impl<'ctx> TestCase<'ctx> { }); ctx.queue.submit([encoder.finish()]); } else { - let block_size = format.block_size(None).unwrap(); + let block_size = format.block_copy_size(None).unwrap(); let bytes_per_row = texture.width() * block_size; // Size for tests is chosen so that we don't need to care about buffer alignments. diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 1481dbe1e6f..214060a2953 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -331,7 +331,7 @@ fn clear_texture_via_buffer_copies( let mut zero_buffer_copy_regions = Vec::new(); let buffer_copy_pitch = alignments.buffer_copy_pitch.get() as u32; let (block_width, block_height) = texture_desc.format.block_dimensions(); - let block_size = texture_desc.format.block_size(None).unwrap(); + let block_size = texture_desc.format.block_copy_size(None).unwrap(); let bytes_per_row_alignment = get_lowest_common_denom(buffer_copy_pitch, block_size); diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index 10eb80f426d..86c52d11ee0 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -254,7 +254,7 @@ pub(crate) fn validate_linear_texture_data( let offset = layout.offset; - let block_size = format.block_size(Some(aspect)).unwrap() as BufferAddress; + let block_size = format.block_copy_size(Some(aspect)).unwrap() as BufferAddress; let (block_width, block_height) = format.block_dimensions(); let block_width = block_width as BufferAddress; let block_height = block_height as BufferAddress; diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index d8f1c0f5d04..1d9f48ead03 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -3,7 +3,9 @@ use crate::device::trace; use crate::{ binding_model::{self, BindGroupLayout}, command, conv, - device::{life::WaitIdleError, map_buffer, queue, Device, DeviceError, HostMap}, + device::{ + life::WaitIdleError, map_buffer, queue, Device, DeviceError, DeviceLostClosure, HostMap, + }, global::Global, hal_api::HalApi, hub::Token, @@ -26,7 +28,9 @@ use wgt::{BufferAddress, TextureFormat}; use std::{borrow::Cow, iter, mem, ops::Range, ptr}; -use super::{BufferMapPendingClosure, ImplicitPipelineIds, InvalidDevice, UserClosures}; +use super::{ + BufferMapPendingClosure, ImplicitPipelineIds, InvalidDevice, UserClosures, IMPLICIT_FAILURE, +}; impl Global { pub fn adapter_is_surface_supported( @@ -492,7 +496,7 @@ impl Global { log::trace!("Buffer::destroy {buffer_id:?}"); let (mut buffer_guard, _) = hub.buffers.write(&mut token); let buffer = buffer_guard - .get_mut(buffer_id) + .get_and_mark_destroyed(buffer_id) .map_err(|_| resource::DestroyError::Invalid)?; let device = &mut device_guard[buffer.device_id.value]; @@ -547,7 +551,7 @@ impl Global { let (ref_count, last_submit_index, device_id) = { let (mut buffer_guard, _) = hub.buffers.write(&mut token); - match buffer_guard.get_mut(buffer_id) { + match buffer_guard.get_occupied_or_destroyed_mut(buffer_id) { Ok(buffer) => { let ref_count = buffer.life_guard.ref_count.take().unwrap(); let last_submit_index = buffer.life_guard.life_count(); @@ -797,7 +801,7 @@ impl Global { let (mut texture_guard, _) = hub.textures.write(&mut token); let texture = texture_guard - .get_mut(texture_id) + .get_and_mark_destroyed(texture_id) .map_err(|_| resource::DestroyError::Invalid)?; let device = &mut device_guard[texture.device_id.value]; @@ -851,7 +855,7 @@ impl Global { let (ref_count, last_submit_index, device_id) = { let (mut texture_guard, _) = hub.textures.write(&mut token); - match texture_guard.get_mut(texture_id) { + match texture_guard.get_occupied_or_destroyed_mut(texture_id) { Ok(texture) => { let ref_count = texture.life_guard.ref_count.take().unwrap(); let last_submit_index = texture.life_guard.life_count(); @@ -1849,6 +1853,7 @@ impl Global { let fid = hub.render_pipelines.prepare(id_in); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); + let implicit_error_context = implicit_context.clone(); let (adapter_guard, mut token) = hub.adapters.read(&mut token); let (device_guard, mut token) = hub.devices.read(&mut token); @@ -1897,6 +1902,24 @@ impl Global { }; let id = fid.assign_error(desc.label.borrow_or_default(), &mut token); + + // We also need to assign errors to the implicit pipeline layout and the + // implicit bind group layout. We have to remove any existing entries first. + let (mut pipeline_layout_guard, mut token) = hub.pipeline_layouts.write(&mut token); + let (mut bgl_guard, _token) = hub.bind_group_layouts.write(&mut token); + if let Some(ref ids) = implicit_error_context { + if pipeline_layout_guard.contains(ids.root_id) { + pipeline_layout_guard.remove(ids.root_id); + } + pipeline_layout_guard.insert_error(ids.root_id, IMPLICIT_FAILURE); + for &bgl_id in ids.group_ids.iter() { + if bgl_guard.contains(bgl_id) { + bgl_guard.remove(bgl_id); + } + bgl_guard.insert_error(bgl_id, IMPLICIT_FAILURE); + } + } + (id, Some(error)) } @@ -2022,6 +2045,7 @@ impl Global { let fid = hub.compute_pipelines.prepare(id_in); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); + let implicit_error_context = implicit_context.clone(); let (device_guard, mut token) = hub.devices.read(&mut token); let error = loop { @@ -2041,7 +2065,6 @@ impl Global { implicit_context: implicit_context.clone(), }); } - let pipeline = match device.create_compute_pipeline( device_id, desc, @@ -2066,6 +2089,24 @@ impl Global { }; let id = fid.assign_error(desc.label.borrow_or_default(), &mut token); + + // We also need to assign errors to the implicit pipeline layout and the + // implicit bind group layout. We have to remove any existing entries first. + let (mut pipeline_layout_guard, mut token) = hub.pipeline_layouts.write(&mut token); + let (mut bgl_guard, _token) = hub.bind_group_layouts.write(&mut token); + if let Some(ref ids) = implicit_error_context { + if pipeline_layout_guard.contains(ids.root_id) { + pipeline_layout_guard.remove(ids.root_id); + } + pipeline_layout_guard.insert_error(ids.root_id, IMPLICIT_FAILURE); + for &bgl_id in ids.group_ids.iter() { + if bgl_guard.contains(bgl_id) { + bgl_guard.remove(bgl_id); + } + bgl_guard.insert_error(bgl_id, IMPLICIT_FAILURE); + } + } + (id, Some(error)) } @@ -2633,6 +2674,21 @@ impl Global { } } + pub fn device_set_device_lost_closure( + &self, + device_id: DeviceId, + device_lost_closure: DeviceLostClosure, + ) { + let hub = A::hub(self); + let mut token = Token::root(); + + let (mut device_guard, mut token) = hub.devices.write(&mut token); + if let Ok(device) = device_guard.get_mut(device_id) { + let mut life_tracker = device.lock_life(&mut token); + life_tracker.device_lost_closure = Some(device_lost_closure); + } + } + pub fn device_destroy(&self, device_id: DeviceId) { log::trace!("Device::destroy {device_id:?}"); @@ -2644,36 +2700,26 @@ impl Global { // Follow the steps at // https://gpuweb.github.io/gpuweb/#dom-gpudevice-destroy. - // It's legal to call destroy multiple times, but if the device - // is already invalid, there's nothing more to do. There's also - // no need to return an error. - if !device.valid { - return; - } - // The last part of destroy is to lose the device. The spec says // delay that until all "currently-enqueued operations on any - // queue on this device are completed." - - // TODO: implement this delay. - - // Finish by losing the device. - - // TODO: associate this "destroyed" reason more tightly with - // the GPUDeviceLostReason defined in webgpu.idl. - device.lose(Some("destroyed")); + // queue on this device are completed." This is accomplished by + // setting valid to false, and then relying upon maintain to + // check for empty queues and a DeviceLostClosure. At that time, + // the DeviceLostClosure will be called with "destroyed" as the + // reason. + device.valid = false; } } - pub fn device_lose(&self, device_id: DeviceId, reason: Option<&str>) { - log::trace!("Device::lose {device_id:?}"); + pub fn device_mark_lost(&self, device_id: DeviceId, message: &str) { + log::trace!("Device::mark_lost {device_id:?}"); let hub = A::hub(self); let mut token = Token::root(); - let (mut device_guard, _) = hub.devices.write(&mut token); + let (mut device_guard, mut token) = hub.devices.write(&mut token); if let Ok(device) = device_guard.get_mut(device_id) { - device.lose(reason); + device.lose(&mut token, message); } } diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index e1d01ccaba9..dc27bc43e03 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -3,7 +3,7 @@ use crate::device::trace; use crate::{ device::{ queue::{EncoderInFlight, SubmittedWorkDoneClosure, TempResource}, - DeviceError, + DeviceError, DeviceLostClosure, }, hal_api::HalApi, hub::{Hub, Token}, @@ -313,6 +313,11 @@ pub(super) struct LifetimeTracker { /// must happen _after_ all mapped buffer callbacks are mapped, so we defer them /// here until the next time the device is maintained. work_done_closures: SmallVec<[SubmittedWorkDoneClosure; 1]>, + + /// Closure to be called on "lose the device". This is invoked directly by + /// device.lose or by the UserCallbacks returned from maintain when the device + /// has been destroyed and its queues are empty. + pub device_lost_closure: Option, } impl LifetimeTracker { @@ -326,6 +331,7 @@ impl LifetimeTracker { free_resources: NonReferencedResources::new(), ready_to_map: Vec::new(), work_done_closures: SmallVec::new(), + device_lost_closure: None, } } @@ -834,21 +840,22 @@ impl LifetimeTracker { for stored in self.mapped.drain(..) { let resource_id = stored.value; - let buf = &buffer_guard[resource_id]; - - let submit_index = buf.life_guard.life_count(); - log::trace!( - "Mapping of {:?} at submission {:?} gets assigned to active {:?}", - resource_id, - submit_index, - self.active.iter().position(|a| a.index == submit_index) - ); - - self.active - .iter_mut() - .find(|a| a.index == submit_index) - .map_or(&mut self.ready_to_map, |a| &mut a.mapped) - .push(resource_id); + // The buffer may have been destroyed since the map request. + if let Ok(buf) = buffer_guard.get(resource_id.0) { + let submit_index = buf.life_guard.life_count(); + log::trace!( + "Mapping of {:?} at submission {:?} gets assigned to active {:?}", + resource_id, + submit_index, + self.active.iter().position(|a| a.index == submit_index) + ); + + self.active + .iter_mut() + .find(|a| a.index == submit_index) + .map_or(&mut self.ready_to_map, |a| &mut a.mapped) + .push(resource_id); + } } } @@ -873,7 +880,13 @@ impl LifetimeTracker { Vec::with_capacity(self.ready_to_map.len()); let mut trackers = trackers.lock(); for buffer_id in self.ready_to_map.drain(..) { - let buffer = &mut buffer_guard[buffer_id]; + let buffer = match buffer_guard.get_occupied_or_destroyed_mut(buffer_id.0) { + Ok(buf) => buf, + Err(..) => { + // The buffer may have been destroyed since the map request. + continue; + } + }; if buffer.life_guard.ref_count.is_none() && trackers.buffers.remove_abandoned(buffer_id) { buffer.map_state = resource::BufferMapState::Idle; diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index eca1375604c..1d89d54796e 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -12,8 +12,9 @@ use crate::{ use arrayvec::ArrayVec; use hal::Device as _; use smallvec::SmallVec; +use std::os::raw::c_char; use thiserror::Error; -use wgt::{BufferAddress, TextureFormat}; +use wgt::{BufferAddress, DeviceLostReason, TextureFormat}; use std::{iter, num::NonZeroU32, ptr}; @@ -169,12 +170,15 @@ pub type BufferMapPendingClosure = (BufferMapOperation, BufferAccessResult); pub struct UserClosures { pub mappings: Vec, pub submissions: SmallVec<[queue::SubmittedWorkDoneClosure; 1]>, + pub device_lost_invocations: SmallVec<[DeviceLostInvocation; 1]>, } impl UserClosures { fn extend(&mut self, other: Self) { self.mappings.extend(other.mappings); self.submissions.extend(other.submissions); + self.device_lost_invocations + .extend(other.device_lost_invocations); } fn fire(self) { @@ -189,6 +193,98 @@ impl UserClosures { for closure in self.submissions { closure.call(); } + for invocation in self.device_lost_invocations { + invocation + .closure + .call(invocation.reason, invocation.message); + } + } +} + +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] +pub type DeviceLostCallback = Box; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +pub type DeviceLostCallback = Box; + +#[repr(C)] +pub struct DeviceLostClosureC { + pub callback: unsafe extern "C" fn(user_data: *mut u8, reason: u8, message: *const c_char), + pub user_data: *mut u8, +} + +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] +unsafe impl Send for DeviceLostClosureC {} + +pub struct DeviceLostClosure { + // We wrap this so creating the enum in the C variant can be unsafe, + // allowing our call function to be safe. + inner: DeviceLostClosureInner, +} + +pub struct DeviceLostInvocation { + closure: DeviceLostClosure, + reason: DeviceLostReason, + message: String, +} + +enum DeviceLostClosureInner { + Rust { callback: DeviceLostCallback }, + C { inner: DeviceLostClosureC }, +} + +impl DeviceLostClosure { + pub fn from_rust(callback: DeviceLostCallback) -> Self { + Self { + inner: DeviceLostClosureInner::Rust { callback }, + } + } + + /// # Safety + /// + /// - The callback pointer must be valid to call with the provided `user_data` + /// pointer. + /// + /// - Both pointers must point to `'static` data, as the callback may happen at + /// an unspecified time. + pub unsafe fn from_c(inner: DeviceLostClosureC) -> Self { + Self { + inner: DeviceLostClosureInner::C { inner }, + } + } + + #[allow(trivial_casts)] + pub(crate) fn call(self, reason: DeviceLostReason, message: String) { + match self.inner { + DeviceLostClosureInner::Rust { callback } => callback(reason, message), + // SAFETY: the contract of the call to from_c says that this unsafe is sound. + DeviceLostClosureInner::C { inner } => unsafe { + // We need to pass message as a c_char typed pointer. To avoid trivial + // conversion warnings on some platforms, we use the allow lint. + (inner.callback)( + inner.user_data, + reason as u8, + message.as_ptr() as *const c_char, + ) + }, + } } } diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index a49c8f91f85..213d5cdea60 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -697,7 +697,7 @@ impl Global { let block_size = dst .desc .format - .block_size(Some(destination.aspect)) + .block_copy_size(Some(destination.aspect)) .unwrap(); let bytes_per_row_alignment = get_lowest_common_denom(device.alignments.buffer_copy_pitch.get() as u32, block_size); @@ -1110,13 +1110,12 @@ impl Global { // it, so make sure to set_size on it. used_surface_textures.set_size(texture_guard.len()); + // TODO: ideally we would use `get_and_mark_destroyed` but the code here + // wants to consume the command buffer. #[allow(unused_mut)] - let mut cmdbuf = match hub - .command_buffers - .unregister_locked(cmb_id, &mut *command_buffer_guard) - { - Some(cmdbuf) => cmdbuf, - None => continue, + let mut cmdbuf = match command_buffer_guard.replace_with_error(cmb_id) { + Ok(cmdbuf) => cmdbuf, + Err(_) => continue, }; if cmdbuf.device_id.value.0 != queue_id { diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 0e290ec2dda..2577ee77cb0 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -8,8 +8,8 @@ use crate::{ command, conv, device::life::WaitIdleError, device::{ - AttachmentData, CommandAllocator, MissingDownlevelFlags, MissingFeatures, - RenderPassContext, CLEANUP_WAIT_MS, + AttachmentData, CommandAllocator, DeviceLostInvocation, MissingDownlevelFlags, + MissingFeatures, RenderPassContext, CLEANUP_WAIT_MS, }, hal_api::HalApi, hal_label, @@ -34,7 +34,7 @@ use hal::{CommandEncoder as _, Device as _}; use parking_lot::{Mutex, MutexGuard}; use smallvec::SmallVec; use thiserror::Error; -use wgt::{TextureFormat, TextureSampleType, TextureViewDimension}; +use wgt::{DeviceLostReason, TextureFormat, TextureSampleType, TextureViewDimension}; use std::{borrow::Cow, iter, num::NonZeroU32}; @@ -315,9 +315,24 @@ impl Device { let mapping_closures = life_tracker.handle_mapping(hub, &self.raw, &self.trackers, token); life_tracker.cleanup(&self.raw); + // Detect if we have been destroyed and now need to lose the device. + // If we are invalid (set at start of destroy) and our queue is empty, + // and we have a DeviceLostClosure, return the closure to be called by + // our caller. This will complete the steps for both destroy and for + // "lose the device". + let mut device_lost_invocations = SmallVec::new(); + if !self.valid && life_tracker.queue_empty() && life_tracker.device_lost_closure.is_some() { + device_lost_invocations.push(DeviceLostInvocation { + closure: life_tracker.device_lost_closure.take().unwrap(), + reason: DeviceLostReason::Destroyed, + message: String::new(), + }); + } + let closures = UserClosures { mappings: mapping_closures, submissions: submission_closures, + device_lost_invocations, }; Ok((closures, life_tracker.queue_empty())) } @@ -342,42 +357,90 @@ impl Device { let (sampler_guard, _) = hub.samplers.read(&mut token); for id in trackers.buffers.used() { - if buffer_guard[id].life_guard.ref_count.is_none() { + if buffer_guard + .get_occupied_or_destroyed(id.0) + .unwrap() + .life_guard + .ref_count + .is_none() + { self.temp_suspected.buffers.push(id); } } for id in trackers.textures.used() { - if texture_guard[id].life_guard.ref_count.is_none() { + if texture_guard + .get_occupied_or_destroyed(id.0) + .unwrap() + .life_guard + .ref_count + .is_none() + { self.temp_suspected.textures.push(id); } } for id in trackers.views.used() { - if texture_view_guard[id].life_guard.ref_count.is_none() { + if texture_view_guard + .get_occupied_or_destroyed(id.0) + .unwrap() + .life_guard + .ref_count + .is_none() + { self.temp_suspected.texture_views.push(id); } } for id in trackers.bind_groups.used() { - if bind_group_guard[id].life_guard.ref_count.is_none() { + if bind_group_guard + .get_occupied_or_destroyed(id.0) + .unwrap() + .life_guard + .ref_count + .is_none() + { self.temp_suspected.bind_groups.push(id); } } for id in trackers.samplers.used() { - if sampler_guard[id].life_guard.ref_count.is_none() { + if sampler_guard + .get_occupied_or_destroyed(id.0) + .unwrap() + .life_guard + .ref_count + .is_none() + { self.temp_suspected.samplers.push(id); } } for id in trackers.compute_pipelines.used() { - if compute_pipe_guard[id].life_guard.ref_count.is_none() { + if compute_pipe_guard + .get_occupied_or_destroyed(id.0) + .unwrap() + .life_guard + .ref_count + .is_none() + { self.temp_suspected.compute_pipelines.push(id); } } for id in trackers.render_pipelines.used() { - if render_pipe_guard[id].life_guard.ref_count.is_none() { + if render_pipe_guard + .get_occupied_or_destroyed(id.0) + .unwrap() + .life_guard + .ref_count + .is_none() + { self.temp_suspected.render_pipelines.push(id); } } for id in trackers.query_sets.used() { - if query_set_guard[id].life_guard.ref_count.is_none() { + if query_set_guard + .get_occupied_or_destroyed(id.0) + .unwrap() + .life_guard + .ref_count + .is_none() + { self.temp_suspected.query_sets.push(id); } } @@ -1329,18 +1392,19 @@ impl Device { self.features.contains(wgt::Features::DEBUG_PRINTF), ); - let debug_source = if self.instance_flags.contains(wgt::InstanceFlags::DEBUG) { - Some(hal::DebugSource { - file_name: Cow::Owned( - desc.label - .as_ref() - .map_or("shader".to_string(), |l| l.to_string()), - ), - source_code: Cow::Owned(source.clone()), - }) - } else { - None - }; + let debug_source = + if self.instance_flags.contains(wgt::InstanceFlags::DEBUG) && !source.is_empty() { + Some(hal::DebugSource { + file_name: Cow::Owned( + desc.label + .as_ref() + .map_or("shader".to_string(), |l| l.to_string()), + ), + source_code: Cow::Owned(source.clone()), + }) + } else { + None + }; let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all(), caps) .validate(&module) @@ -3307,17 +3371,23 @@ impl Device { }) } - pub(crate) fn lose(&mut self, _reason: Option<&str>) { + pub(crate) fn lose<'this, 'token: 'this>( + &'this mut self, + token: &mut Token<'token, Self>, + message: &str, + ) { // Follow the steps at https://gpuweb.github.io/gpuweb/#lose-the-device. // Mark the device explicitly as invalid. This is checked in various // places to prevent new work from being submitted. self.valid = false; - // The following steps remain in "lose the device": // 1) Resolve the GPUDevice device.lost promise. - - // TODO: triggger this passively or actively, and supply the reason. + let mut life_tracker = self.lock_life(token); + if life_tracker.device_lost_closure.is_some() { + let device_lost_closure = life_tracker.device_lost_closure.take().unwrap(); + device_lost_closure.call(DeviceLostReason::Unknown, message.to_string()); + } // 2) Complete any outstanding mapAsync() steps. // 3) Complete any outstanding onSubmittedWorkDone() steps. diff --git a/wgpu-core/src/storage.rs b/wgpu-core/src/storage.rs index 07387b01941..09d93d637d0 100644 --- a/wgpu-core/src/storage.rs +++ b/wgpu-core/src/storage.rs @@ -14,6 +14,10 @@ pub(crate) enum Element { /// epoch. Occupied(T, Epoch), + /// Like `Occupied`, but the resource has been marked as destroyed + /// and hasn't been dropped yet. + Destroyed(T, Epoch), + /// Like `Occupied`, but an error occurred when creating the /// resource. /// @@ -68,9 +72,11 @@ impl Storage { let (index, epoch, _) = id.unzip(); match self.map.get(index as usize) { Some(&Element::Vacant) => false, - Some(&Element::Occupied(_, storage_epoch) | &Element::Error(storage_epoch, _)) => { - storage_epoch == epoch - } + Some( + &Element::Occupied(_, storage_epoch) + | &Element::Destroyed(_, storage_epoch) + | &Element::Error(storage_epoch, _), + ) => storage_epoch == epoch, None => false, } } @@ -87,7 +93,9 @@ impl Storage { let (result, storage_epoch) = match self.map.get(index as usize) { Some(&Element::Occupied(ref v, epoch)) => (Ok(Some(v)), epoch), Some(&Element::Vacant) => return Ok(None), - Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch), + Some(&Element::Error(epoch, ..)) | Some(&Element::Destroyed(.., epoch)) => { + (Err(InvalidId), epoch) + } None => return Err(InvalidId), }; assert_eq!( @@ -106,6 +114,7 @@ impl Storage { Some(&Element::Occupied(ref v, epoch)) => (Ok(v), epoch), Some(&Element::Vacant) => panic!("{}[{}] does not exist", self.kind, index), Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch), + Some(&Element::Destroyed(.., epoch)) => (Err(InvalidId), epoch), None => return Err(InvalidId), }; assert_eq!( @@ -124,6 +133,46 @@ impl Storage { Some(&mut Element::Occupied(ref mut v, epoch)) => (Ok(v), epoch), Some(&mut Element::Vacant) | None => panic!("{}[{}] does not exist", self.kind, index), Some(&mut Element::Error(epoch, ..)) => (Err(InvalidId), epoch), + Some(&mut Element::Destroyed(.., epoch)) => (Err(InvalidId), epoch), + }; + assert_eq!( + epoch, storage_epoch, + "{}[{}] is no longer alive", + self.kind, index + ); + result + } + + /// Like `get_mut`, but returns the element even if it is destroyed. + /// + /// In practice, most API entry points should use `get`/`get_mut` so that a + /// destroyed resource leads to a validation error. This should be used internally + /// in places where we want to do some manipulation potentially after the element + /// was destroyed (for example the drop implementation). + pub(crate) fn get_occupied_or_destroyed_mut(&mut self, id: I) -> Result<&mut T, InvalidId> { + let (index, epoch, _) = id.unzip(); + let (result, storage_epoch) = match self.map.get_mut(index as usize) { + Some(&mut Element::Occupied(ref mut v, epoch)) + | Some(&mut Element::Destroyed(ref mut v, epoch)) => (Ok(v), epoch), + Some(&mut Element::Vacant) | None => panic!("{}[{}] does not exist", self.kind, index), + Some(&mut Element::Error(epoch, ..)) => (Err(InvalidId), epoch), + }; + assert_eq!( + epoch, storage_epoch, + "{}[{}] is no longer alive", + self.kind, index + ); + result + } + + pub(crate) fn get_occupied_or_destroyed(&self, id: I) -> Result<&T, InvalidId> { + let (index, epoch, _) = id.unzip(); + let (result, storage_epoch) = match self.map.get(index as usize) { + Some(&Element::Occupied(ref v, epoch)) | Some(&Element::Destroyed(ref v, epoch)) => { + (Ok(v), epoch) + } + Some(&Element::Vacant) | None => panic!("{}[{}] does not exist", self.kind, index), + Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch), }; assert_eq!( epoch, storage_epoch, @@ -137,7 +186,7 @@ impl Storage { match self.map[id as usize] { Element::Occupied(ref v, _) => v, Element::Vacant => panic!("{}[{}] does not exist", self.kind, id), - Element::Error(_, _) => panic!(""), + Element::Error(_, _) | Element::Destroyed(..) => panic!(""), } } @@ -169,6 +218,42 @@ impl Storage { self.insert_impl(index as usize, Element::Error(epoch, label.to_string())) } + pub(crate) fn replace_with_error(&mut self, id: I) -> Result { + let (index, epoch, _) = id.unzip(); + match std::mem::replace( + &mut self.map[index as usize], + Element::Error(epoch, String::new()), + ) { + Element::Vacant => panic!("Cannot access vacant resource"), + Element::Occupied(value, storage_epoch) => { + assert_eq!(epoch, storage_epoch); + Ok(value) + } + _ => Err(InvalidId), + } + } + + pub(crate) fn get_and_mark_destroyed(&mut self, id: I) -> Result<&mut T, InvalidId> { + let (index, epoch, _) = id.unzip(); + let slot = &mut self.map[index as usize]; + // borrowck dance: we have to move the element out before we can replace it + // with another variant with the same value. + if let &mut Element::Occupied(..) = slot { + if let Element::Occupied(value, storage_epoch) = + std::mem::replace(slot, Element::Vacant) + { + debug_assert_eq!(storage_epoch, epoch); + *slot = Element::Destroyed(value, storage_epoch); + } + } + + if let Element::Destroyed(ref mut value, ..) = *slot { + Ok(value) + } else { + Err(InvalidId) + } + } + pub(crate) fn force_replace(&mut self, id: I, value: T) { let (index, epoch, _) = id.unzip(); self.map[index as usize] = Element::Occupied(value, epoch); @@ -177,7 +262,7 @@ impl Storage { pub(crate) fn remove(&mut self, id: I) -> Option { let (index, epoch, _) = id.unzip(); match std::mem::replace(&mut self.map[index as usize], Element::Vacant) { - Element::Occupied(value, storage_epoch) => { + Element::Occupied(value, storage_epoch) | Element::Destroyed(value, storage_epoch) => { assert_eq!(epoch, storage_epoch); Some(value) } @@ -224,7 +309,7 @@ impl Storage { }; for element in self.map.iter() { match *element { - Element::Occupied(..) => report.num_occupied += 1, + Element::Occupied(..) | Element::Destroyed(..) => report.num_occupied += 1, Element::Vacant => report.num_vacant += 1, Element::Error(..) => report.num_error += 1, } diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 1bf318bbaa5..a9c88edf126 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -57,13 +57,18 @@ impl NumericDimension { #[derive(Clone, Copy, Debug)] pub struct NumericType { dim: NumericDimension, - kind: naga::ScalarKind, - width: naga::Bytes, + scalar: naga::Scalar, } impl fmt::Display for NumericType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}{}{}", self.kind, self.width * 8, self.dim) + write!( + f, + "{:?}{}{}", + self.scalar.kind, + self.scalar.width * 8, + self.dim + ) } } @@ -592,77 +597,76 @@ impl Resource { impl NumericType { fn from_vertex_format(format: wgt::VertexFormat) -> Self { - use naga::{ScalarKind as Sk, VectorSize as Vs}; + use naga::{Scalar, VectorSize as Vs}; use wgt::VertexFormat as Vf; - let (dim, kind, width) = match format { - Vf::Uint32 => (NumericDimension::Scalar, Sk::Uint, 4), + let (dim, scalar) = match format { + Vf::Uint32 => (NumericDimension::Scalar, Scalar::U32), Vf::Uint8x2 | Vf::Uint16x2 | Vf::Uint32x2 => { - (NumericDimension::Vector(Vs::Bi), Sk::Uint, 4) + (NumericDimension::Vector(Vs::Bi), Scalar::U32) } - Vf::Uint32x3 => (NumericDimension::Vector(Vs::Tri), Sk::Uint, 4), + Vf::Uint32x3 => (NumericDimension::Vector(Vs::Tri), Scalar::U32), Vf::Uint8x4 | Vf::Uint16x4 | Vf::Uint32x4 => { - (NumericDimension::Vector(Vs::Quad), Sk::Uint, 4) + (NumericDimension::Vector(Vs::Quad), Scalar::U32) } - Vf::Sint32 => (NumericDimension::Scalar, Sk::Sint, 4), + Vf::Sint32 => (NumericDimension::Scalar, Scalar::I32), Vf::Sint8x2 | Vf::Sint16x2 | Vf::Sint32x2 => { - (NumericDimension::Vector(Vs::Bi), Sk::Sint, 4) + (NumericDimension::Vector(Vs::Bi), Scalar::I32) } - Vf::Sint32x3 => (NumericDimension::Vector(Vs::Tri), Sk::Sint, 4), + Vf::Sint32x3 => (NumericDimension::Vector(Vs::Tri), Scalar::I32), Vf::Sint8x4 | Vf::Sint16x4 | Vf::Sint32x4 => { - (NumericDimension::Vector(Vs::Quad), Sk::Sint, 4) + (NumericDimension::Vector(Vs::Quad), Scalar::I32) } - Vf::Float32 => (NumericDimension::Scalar, Sk::Float, 4), + Vf::Float32 => (NumericDimension::Scalar, Scalar::F32), Vf::Unorm8x2 | Vf::Snorm8x2 | Vf::Unorm16x2 | Vf::Snorm16x2 | Vf::Float16x2 - | Vf::Float32x2 => (NumericDimension::Vector(Vs::Bi), Sk::Float, 4), - Vf::Float32x3 => (NumericDimension::Vector(Vs::Tri), Sk::Float, 4), + | Vf::Float32x2 => (NumericDimension::Vector(Vs::Bi), Scalar::F32), + Vf::Float32x3 => (NumericDimension::Vector(Vs::Tri), Scalar::F32), Vf::Unorm8x4 | Vf::Snorm8x4 | Vf::Unorm16x4 | Vf::Snorm16x4 | Vf::Float16x4 - | Vf::Float32x4 => (NumericDimension::Vector(Vs::Quad), Sk::Float, 4), - Vf::Float64 => (NumericDimension::Scalar, Sk::Float, 8), - Vf::Float64x2 => (NumericDimension::Vector(Vs::Bi), Sk::Float, 8), - Vf::Float64x3 => (NumericDimension::Vector(Vs::Tri), Sk::Float, 8), - Vf::Float64x4 => (NumericDimension::Vector(Vs::Quad), Sk::Float, 8), + | Vf::Float32x4 => (NumericDimension::Vector(Vs::Quad), Scalar::F32), + Vf::Float64 => (NumericDimension::Scalar, Scalar::F64), + Vf::Float64x2 => (NumericDimension::Vector(Vs::Bi), Scalar::F64), + Vf::Float64x3 => (NumericDimension::Vector(Vs::Tri), Scalar::F64), + Vf::Float64x4 => (NumericDimension::Vector(Vs::Quad), Scalar::F64), }; NumericType { dim, - kind, //Note: Shader always sees data as int, uint, or float. // It doesn't know if the original is normalized in a tighter form. - width, + scalar, } } fn from_texture_format(format: wgt::TextureFormat) -> Self { - use naga::{ScalarKind as Sk, VectorSize as Vs}; + use naga::{Scalar, VectorSize as Vs}; use wgt::TextureFormat as Tf; - let (dim, kind) = match format { + let (dim, scalar) = match format { Tf::R8Unorm | Tf::R8Snorm | Tf::R16Float | Tf::R32Float => { - (NumericDimension::Scalar, Sk::Float) + (NumericDimension::Scalar, Scalar::F32) } - Tf::R8Uint | Tf::R16Uint | Tf::R32Uint => (NumericDimension::Scalar, Sk::Uint), - Tf::R8Sint | Tf::R16Sint | Tf::R32Sint => (NumericDimension::Scalar, Sk::Sint), + Tf::R8Uint | Tf::R16Uint | Tf::R32Uint => (NumericDimension::Scalar, Scalar::U32), + Tf::R8Sint | Tf::R16Sint | Tf::R32Sint => (NumericDimension::Scalar, Scalar::I32), Tf::Rg8Unorm | Tf::Rg8Snorm | Tf::Rg16Float | Tf::Rg32Float => { - (NumericDimension::Vector(Vs::Bi), Sk::Float) + (NumericDimension::Vector(Vs::Bi), Scalar::F32) } Tf::Rg8Uint | Tf::Rg16Uint | Tf::Rg32Uint => { - (NumericDimension::Vector(Vs::Bi), Sk::Uint) + (NumericDimension::Vector(Vs::Bi), Scalar::U32) } Tf::Rg8Sint | Tf::Rg16Sint | Tf::Rg32Sint => { - (NumericDimension::Vector(Vs::Bi), Sk::Sint) + (NumericDimension::Vector(Vs::Bi), Scalar::I32) } - Tf::R16Snorm | Tf::R16Unorm => (NumericDimension::Scalar, Sk::Float), - Tf::Rg16Snorm | Tf::Rg16Unorm => (NumericDimension::Vector(Vs::Bi), Sk::Float), - Tf::Rgba16Snorm | Tf::Rgba16Unorm => (NumericDimension::Vector(Vs::Quad), Sk::Float), + Tf::R16Snorm | Tf::R16Unorm => (NumericDimension::Scalar, Scalar::F32), + Tf::Rg16Snorm | Tf::Rg16Unorm => (NumericDimension::Vector(Vs::Bi), Scalar::F32), + Tf::Rgba16Snorm | Tf::Rgba16Unorm => (NumericDimension::Vector(Vs::Quad), Scalar::F32), Tf::Rgba8Unorm | Tf::Rgba8UnormSrgb | Tf::Rgba8Snorm @@ -670,14 +674,14 @@ impl NumericType { | Tf::Bgra8UnormSrgb | Tf::Rgb10a2Unorm | Tf::Rgba16Float - | Tf::Rgba32Float => (NumericDimension::Vector(Vs::Quad), Sk::Float), + | Tf::Rgba32Float => (NumericDimension::Vector(Vs::Quad), Scalar::F32), Tf::Rgba8Uint | Tf::Rgba16Uint | Tf::Rgba32Uint | Tf::Rgb10a2Uint => { - (NumericDimension::Vector(Vs::Quad), Sk::Uint) + (NumericDimension::Vector(Vs::Quad), Scalar::U32) } Tf::Rgba8Sint | Tf::Rgba16Sint | Tf::Rgba32Sint => { - (NumericDimension::Vector(Vs::Quad), Sk::Sint) + (NumericDimension::Vector(Vs::Quad), Scalar::I32) } - Tf::Rg11b10Float => (NumericDimension::Vector(Vs::Tri), Sk::Float), + Tf::Rg11b10Float => (NumericDimension::Vector(Vs::Tri), Scalar::F32), Tf::Stencil8 | Tf::Depth16Unorm | Tf::Depth32Float @@ -686,7 +690,7 @@ impl NumericType { | Tf::Depth24PlusStencil8 => { panic!("Unexpected depth format") } - Tf::Rgb9e5Ufloat => (NumericDimension::Vector(Vs::Tri), Sk::Float), + Tf::Rgb9e5Ufloat => (NumericDimension::Vector(Vs::Tri), Scalar::F32), Tf::Bc1RgbaUnorm | Tf::Bc1RgbaUnormSrgb | Tf::Bc2RgbaUnorm @@ -698,36 +702,35 @@ impl NumericType { | Tf::Etc2Rgb8A1Unorm | Tf::Etc2Rgb8A1UnormSrgb | Tf::Etc2Rgba8Unorm - | Tf::Etc2Rgba8UnormSrgb => (NumericDimension::Vector(Vs::Quad), Sk::Float), + | Tf::Etc2Rgba8UnormSrgb => (NumericDimension::Vector(Vs::Quad), Scalar::F32), Tf::Bc4RUnorm | Tf::Bc4RSnorm | Tf::EacR11Unorm | Tf::EacR11Snorm => { - (NumericDimension::Scalar, Sk::Float) + (NumericDimension::Scalar, Scalar::F32) } Tf::Bc5RgUnorm | Tf::Bc5RgSnorm | Tf::EacRg11Unorm | Tf::EacRg11Snorm => { - (NumericDimension::Vector(Vs::Bi), Sk::Float) + (NumericDimension::Vector(Vs::Bi), Scalar::F32) } Tf::Bc6hRgbUfloat | Tf::Bc6hRgbFloat | Tf::Etc2Rgb8Unorm | Tf::Etc2Rgb8UnormSrgb => { - (NumericDimension::Vector(Vs::Tri), Sk::Float) + (NumericDimension::Vector(Vs::Tri), Scalar::F32) } Tf::Astc { block: _, channel: _, - } => (NumericDimension::Vector(Vs::Quad), Sk::Float), + } => (NumericDimension::Vector(Vs::Quad), Scalar::F32), }; NumericType { dim, - kind, //Note: Shader always sees data as int, uint, or float. // It doesn't know if the original is normalized in a tighter form. - width: 4, + scalar, } } fn is_subtype_of(&self, other: &NumericType) -> bool { - if self.width > other.width { + if self.scalar.width > other.scalar.width { return false; } - if self.kind != other.kind { + if self.scalar.kind != other.scalar.kind { return false; } match (self.dim, other.dim) { @@ -742,7 +745,7 @@ impl NumericType { } fn is_compatible_with(&self, other: &NumericType) -> bool { - if self.kind != other.kind { + if self.scalar.kind != other.scalar.kind { return false; } match (self.dim, other.dim) { @@ -778,15 +781,13 @@ impl Interface { arena: &naga::UniqueArena, ) { let numeric_ty = match arena[ty].inner { - naga::TypeInner::Scalar { kind, width } => NumericType { + naga::TypeInner::Scalar(scalar) => NumericType { dim: NumericDimension::Scalar, - kind, - width, + scalar, }, - naga::TypeInner::Vector { size, kind, width } => NumericType { + naga::TypeInner::Vector { size, scalar } => NumericType { dim: NumericDimension::Vector(size), - kind, - width, + scalar, }, naga::TypeInner::Matrix { columns, @@ -794,8 +795,7 @@ impl Interface { width, } => NumericType { dim: NumericDimension::Matrix(columns, rows), - kind: naga::ScalarKind::Float, - width, + scalar: naga::Scalar::float(width), }, naga::TypeInner::Struct { ref members, .. } => { for member in members { diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 261a148f262..6d1d056b56a 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -96,7 +96,7 @@ rustc-hash = "1.1" log = "0.4" # backend: Gles -glow = { version = "0.13", optional = true } +glow = { version = "0.13", git = "https://github.com/grovesNL/glow.git", rev = "29ff917a2b2ff7ce0a81b2cc5681de6d4735b36e", optional = true } [dependencies.wgt] package = "wgpu-types" @@ -180,7 +180,9 @@ features = ["wgsl-in"] [dev-dependencies] cfg-if = "1" env_logger = "0.10" -winit = { version = "0.29.2", features = [ "android-native-activity" ] } # for "halmark" example +winit = { version = "0.29.2", features = [ + "android-native-activity", +] } # for "halmark" example [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] glutin = "0.29.1" # for "gles" example diff --git a/wgpu-hal/src/dx11/command.rs b/wgpu-hal/src/dx11/command.rs index 17cd5a22d2e..3bbdf0a7eed 100644 --- a/wgpu-hal/src/dx11/command.rs +++ b/wgpu-hal/src/dx11/command.rs @@ -96,7 +96,7 @@ impl crate::CommandEncoder for super::CommandEncoder { &mut self, layout: &super::PipelineLayout, stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ) { todo!() diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index 719e63a36f0..2ea6ad4ab27 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -39,7 +39,7 @@ impl crate::BufferTextureCopy { let actual = self.buffer_layout.bytes_per_row.unwrap_or_else(|| { // this may happen for single-line updates let block_size = format - .block_size(Some(self.texture_base.aspect.map())) + .block_copy_size(Some(self.texture_base.aspect.map())) .unwrap(); (self.size.width / block_width) * block_size }); @@ -911,15 +911,16 @@ impl crate::CommandEncoder for super::CommandEncoder { &mut self, layout: &super::PipelineLayout, _stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ) { + let offset_words = offset_bytes as usize / 4; + let info = layout.shared.root_constant_info.as_ref().unwrap(); self.pass.root_elements[info.root_index as usize] = super::RootElement::Constant; - self.pass.constant_data[(offset as usize)..(offset as usize + data.len())] - .copy_from_slice(data); + self.pass.constant_data[offset_words..(offset_words + data.len())].copy_from_slice(data); if self.pass.layout.signature == layout.shared.signature { self.pass.dirty_root_elements |= 1 << info.root_index; diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index d0f659f4610..64bcf3109be 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -327,7 +327,7 @@ impl crate::CommandEncoder for Encoder { &mut self, layout: &Resource, stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ) { } diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 1234b972921..abbbe8d4274 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -8,7 +8,6 @@ struct TextureSlotDesc { sampler_index: Option, } -#[derive(Default)] pub(super) struct State { topology: u32, primitive: super::PrimitiveState, @@ -30,10 +29,41 @@ pub(super) struct State { instance_vbuf_mask: usize, dirty_vbuf_mask: usize, active_first_instance: u32, - push_offset_to_uniform: ArrayVec, + push_constant_descs: ArrayVec, + // The current state of the push constant data block. + current_push_constant_data: [u32; super::MAX_PUSH_CONSTANTS], end_of_pass_timestamp: Option, } +impl Default for State { + fn default() -> Self { + Self { + topology: Default::default(), + primitive: Default::default(), + index_format: Default::default(), + index_offset: Default::default(), + vertex_buffers: Default::default(), + vertex_attributes: Default::default(), + color_targets: Default::default(), + stencil: Default::default(), + depth_bias: Default::default(), + alpha_to_coverage_enabled: Default::default(), + samplers: Default::default(), + texture_slots: Default::default(), + render_size: Default::default(), + resolve_attachments: Default::default(), + invalidate_attachments: Default::default(), + has_pass_label: Default::default(), + instance_vbuf_mask: Default::default(), + dirty_vbuf_mask: Default::default(), + active_first_instance: Default::default(), + push_constant_descs: Default::default(), + current_push_constant_data: [0; super::MAX_PUSH_CONSTANTS], + end_of_pass_timestamp: Default::default(), + } + } +} + impl super::CommandBuffer { fn clear(&mut self) { self.label = None; @@ -176,10 +206,7 @@ impl super::CommandEncoder { fn set_pipeline_inner(&mut self, inner: &super::PipelineInner) { self.cmd_buffer.commands.push(C::SetProgram(inner.program)); - self.state.push_offset_to_uniform.clear(); - self.state - .push_offset_to_uniform - .extend(inner.uniforms.iter().cloned()); + self.state.push_constant_descs = inner.push_constant_descs.clone(); // rebind textures, if needed let mut dirty_textures = 0u32; @@ -729,24 +756,46 @@ impl crate::CommandEncoder for super::CommandEncoder { &mut self, _layout: &super::PipelineLayout, _stages: wgt::ShaderStages, - start_offset: u32, + offset_bytes: u32, data: &[u32], ) { - let range = self.cmd_buffer.add_push_constant_data(data); - - let end = start_offset + data.len() as u32 * 4; - let mut offset = start_offset; - while offset < end { - let uniform = self.state.push_offset_to_uniform[offset as usize / 4].clone(); - let size = uniform.size; - if uniform.location.is_none() { - panic!("No uniform for push constant"); + // There is nothing preventing the user from trying to update a single value within + // a vector or matrix in the set_push_constant call, as to the user, all of this is + // just memory. However OpenGL does not allow parital uniform updates. + // + // As such, we locally keep a copy of the current state of the push constant memory + // block. If the user tries to update a single value, we have the data to update the entirety + // of the uniform. + let start_words = offset_bytes / 4; + let end_words = start_words + data.len() as u32; + self.state.current_push_constant_data[start_words as usize..end_words as usize] + .copy_from_slice(data); + + // We iterate over the uniform list as there may be multiple uniforms that need + // updating from the same push constant memory (one for each shader stage). + // + // Additionally, any statically unused uniform descs will have been removed from this list + // by OpenGL, so the uniform list is not contiguous. + for uniform in self.state.push_constant_descs.iter().cloned() { + let uniform_size_words = uniform.size_bytes / 4; + let uniform_start_words = uniform.offset / 4; + let uniform_end_words = uniform_start_words + uniform_size_words; + + // Is true if any word within the uniform binding was updated + let needs_updating = + start_words < uniform_end_words || uniform_start_words <= end_words; + + if needs_updating { + let uniform_data = &self.state.current_push_constant_data + [uniform_start_words as usize..uniform_end_words as usize]; + + let range = self.cmd_buffer.add_push_constant_data(uniform_data); + + self.cmd_buffer.commands.push(C::SetPushConstants { + uniform, + offset: range.start, + }); } - self.cmd_buffer.commands.push(C::SetPushConstants { - uniform, - offset: range.start + offset, - }); - offset += size; } } diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index c0ad4054d7c..3fb8383a511 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -417,108 +417,6 @@ pub(super) fn map_storage_access(access: wgt::StorageTextureAccess) -> u32 { } } -pub(super) fn is_sampler(glsl_uniform_type: u32) -> bool { - match glsl_uniform_type { - glow::INT_SAMPLER_1D - | glow::INT_SAMPLER_1D_ARRAY - | glow::INT_SAMPLER_2D - | glow::INT_SAMPLER_2D_ARRAY - | glow::INT_SAMPLER_2D_MULTISAMPLE - | glow::INT_SAMPLER_2D_MULTISAMPLE_ARRAY - | glow::INT_SAMPLER_2D_RECT - | glow::INT_SAMPLER_3D - | glow::INT_SAMPLER_CUBE - | glow::INT_SAMPLER_CUBE_MAP_ARRAY - | glow::UNSIGNED_INT_SAMPLER_1D - | glow::UNSIGNED_INT_SAMPLER_1D_ARRAY - | glow::UNSIGNED_INT_SAMPLER_2D - | glow::UNSIGNED_INT_SAMPLER_2D_ARRAY - | glow::UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE - | glow::UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY - | glow::UNSIGNED_INT_SAMPLER_2D_RECT - | glow::UNSIGNED_INT_SAMPLER_3D - | glow::UNSIGNED_INT_SAMPLER_CUBE - | glow::UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY - | glow::SAMPLER_1D - | glow::SAMPLER_1D_SHADOW - | glow::SAMPLER_1D_ARRAY - | glow::SAMPLER_1D_ARRAY_SHADOW - | glow::SAMPLER_2D - | glow::SAMPLER_2D_SHADOW - | glow::SAMPLER_2D_ARRAY - | glow::SAMPLER_2D_ARRAY_SHADOW - | glow::SAMPLER_2D_MULTISAMPLE - | glow::SAMPLER_2D_MULTISAMPLE_ARRAY - | glow::SAMPLER_2D_RECT - | glow::SAMPLER_2D_RECT_SHADOW - | glow::SAMPLER_3D - | glow::SAMPLER_CUBE - | glow::SAMPLER_CUBE_MAP_ARRAY - | glow::SAMPLER_CUBE_MAP_ARRAY_SHADOW - | glow::SAMPLER_CUBE_SHADOW => true, - _ => false, - } -} - -pub(super) fn is_image(glsl_uniform_type: u32) -> bool { - match glsl_uniform_type { - glow::INT_IMAGE_1D - | glow::INT_IMAGE_1D_ARRAY - | glow::INT_IMAGE_2D - | glow::INT_IMAGE_2D_ARRAY - | glow::INT_IMAGE_2D_MULTISAMPLE - | glow::INT_IMAGE_2D_MULTISAMPLE_ARRAY - | glow::INT_IMAGE_2D_RECT - | glow::INT_IMAGE_3D - | glow::INT_IMAGE_CUBE - | glow::INT_IMAGE_CUBE_MAP_ARRAY - | glow::UNSIGNED_INT_IMAGE_1D - | glow::UNSIGNED_INT_IMAGE_1D_ARRAY - | glow::UNSIGNED_INT_IMAGE_2D - | glow::UNSIGNED_INT_IMAGE_2D_ARRAY - | glow::UNSIGNED_INT_IMAGE_2D_MULTISAMPLE - | glow::UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY - | glow::UNSIGNED_INT_IMAGE_2D_RECT - | glow::UNSIGNED_INT_IMAGE_3D - | glow::UNSIGNED_INT_IMAGE_CUBE - | glow::UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY - | glow::IMAGE_1D - | glow::IMAGE_1D_ARRAY - | glow::IMAGE_2D - | glow::IMAGE_2D_ARRAY - | glow::IMAGE_2D_MULTISAMPLE - | glow::IMAGE_2D_MULTISAMPLE_ARRAY - | glow::IMAGE_2D_RECT - | glow::IMAGE_3D - | glow::IMAGE_CUBE - | glow::IMAGE_CUBE_MAP_ARRAY => true, - _ => false, - } -} - -pub(super) fn is_atomic_counter(glsl_uniform_type: u32) -> bool { - glsl_uniform_type == glow::UNSIGNED_INT_ATOMIC_COUNTER -} - -pub(super) fn is_opaque_type(glsl_uniform_type: u32) -> bool { - is_sampler(glsl_uniform_type) - || is_image(glsl_uniform_type) - || is_atomic_counter(glsl_uniform_type) -} - -pub(super) fn uniform_byte_size(glsl_uniform_type: u32) -> u32 { - match glsl_uniform_type { - glow::FLOAT | glow::INT => 4, - glow::FLOAT_VEC2 | glow::INT_VEC2 => 8, - glow::FLOAT_VEC3 | glow::INT_VEC3 => 12, - glow::FLOAT_VEC4 | glow::INT_VEC4 => 16, - glow::FLOAT_MAT2 => 16, - glow::FLOAT_MAT3 => 36, - glow::FLOAT_MAT4 => 64, - _ => panic!("Unsupported uniform datatype! {glsl_uniform_type:#X}"), - } -} - pub(super) fn is_layered_target(target: u32) -> bool { match target { glow::TEXTURE_2D | glow::TEXTURE_CUBE_MAP => false, diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index a0048c5ec29..7934c4be01a 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -23,6 +23,7 @@ struct CompilationContext<'a> { layout: &'a super::PipelineLayout, sampler_map: &'a mut super::SamplerBindMap, name_binding_map: &'a mut NameBindingMap, + push_constant_items: &'a mut Vec, multiview: Option, } @@ -53,7 +54,7 @@ impl CompilationContext<'_> { Some(name) => name.clone(), None => continue, }; - log::debug!( + log::trace!( "Rebind buffer: {:?} -> {}, register={:?}, slot={}", var.name.as_ref(), &name, @@ -101,6 +102,8 @@ impl CompilationContext<'_> { naga::ShaderStage::Compute => {} } } + + *self.push_constant_items = reflection_info.push_constant_items; } } @@ -279,7 +282,7 @@ impl super::Device { unsafe fn create_pipeline<'a>( &self, gl: &glow::Context, - shaders: ArrayVec, 3>, + shaders: ArrayVec, { crate::MAX_CONCURRENT_SHADER_STAGES }>, layout: &super::PipelineLayout, #[cfg_attr(target_arch = "wasm32", allow(unused))] label: Option<&str>, multiview: Option, @@ -327,7 +330,7 @@ impl super::Device { unsafe fn create_program<'a>( gl: &glow::Context, - shaders: ArrayVec, 3>, + shaders: ArrayVec, { crate::MAX_CONCURRENT_SHADER_STAGES }>, layout: &super::PipelineLayout, #[cfg_attr(target_arch = "wasm32", allow(unused))] label: Option<&str>, multiview: Option, @@ -348,16 +351,22 @@ impl super::Device { } let mut name_binding_map = NameBindingMap::default(); + let mut push_constant_items = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new(); let mut sampler_map = [None; super::MAX_TEXTURE_SLOTS]; let mut has_stages = wgt::ShaderStages::empty(); - let mut shaders_to_delete = arrayvec::ArrayVec::<_, 3>::new(); + let mut shaders_to_delete = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new(); - for (naga_stage, stage) in shaders { + for &(naga_stage, stage) in &shaders { has_stages |= map_naga_stage(naga_stage); + let pc_item = { + push_constant_items.push(Vec::new()); + push_constant_items.last_mut().unwrap() + }; let context = CompilationContext { layout, sampler_map: &mut sampler_map, name_binding_map: &mut name_binding_map, + push_constant_items: pc_item, multiview, }; @@ -409,6 +418,7 @@ impl super::Device { match register { super::BindingRegister::UniformBuffers => { let index = unsafe { gl.get_uniform_block_index(program, name) }.unwrap(); + log::trace!("\tBinding slot {slot} to block index {index}"); unsafe { gl.uniform_block_binding(program, index, slot as _) }; } super::BindingRegister::StorageBuffers => { @@ -429,41 +439,38 @@ impl super::Device { } } - let mut uniforms: [super::UniformDesc; super::MAX_PUSH_CONSTANTS] = - [None; super::MAX_PUSH_CONSTANTS].map(|_: Option<()>| Default::default()); - let count = unsafe { gl.get_active_uniforms(program) }; - let mut offset = 0; - - for uniform in 0..count { - let glow::ActiveUniform { utype, name, .. } = - unsafe { gl.get_active_uniform(program, uniform) }.unwrap(); - - if conv::is_opaque_type(utype) { - continue; - } - - if let Some(location) = unsafe { gl.get_uniform_location(program, &name) } { - if uniforms[offset / 4].location.is_some() { - panic!("Offset already occupied") + let mut uniforms = ArrayVec::new(); + + for (stage_idx, stage_items) in push_constant_items.into_iter().enumerate() { + for item in stage_items { + let naga_module = &shaders[stage_idx].1.module.naga.module; + let type_inner = &naga_module.types[item.ty].inner; + + let location = unsafe { gl.get_uniform_location(program, &item.access_path) }; + + log::trace!( + "push constant item: name={}, ty={:?}, offset={}, location={:?}", + item.access_path, + type_inner, + item.offset, + location, + ); + + if let Some(location) = location { + uniforms.push(super::PushConstantDesc { + location, + offset: item.offset, + size_bytes: type_inner.size(naga_module.to_ctx()), + ty: type_inner.clone(), + }); } - - // `size` will always be 1 so we need to guess the real size from the type - let uniform_size = conv::uniform_byte_size(utype); - - uniforms[offset / 4] = super::UniformDesc { - location: Some(location), - size: uniform_size, - utype, - }; - - offset += uniform_size as usize; } } Ok(Arc::new(super::PipelineInner { program, sampler_map, - uniforms, + push_constant_descs: uniforms, })) } } diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index bfc55e634f7..0af5ad4a6ed 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -108,6 +108,8 @@ const MAX_SAMPLERS: usize = 16; const MAX_VERTEX_ATTRIBUTES: usize = 16; const ZERO_BUFFER_SIZE: usize = 256 << 10; const MAX_PUSH_CONSTANTS: usize = 64; +// We have to account for each push constant may need to be set for every shader. +const MAX_PUSH_CONSTANT_COMMANDS: usize = MAX_PUSH_CONSTANTS * crate::MAX_CONCURRENT_SHADER_STAGES; impl crate::Api for Api { type Instance = Instance; @@ -483,11 +485,12 @@ struct VertexBufferDesc { stride: u32, } -#[derive(Clone, Debug, Default)] -struct UniformDesc { - location: Option, - size: u32, - utype: u32, +#[derive(Clone, Debug)] +struct PushConstantDesc { + location: glow::UniformLocation, + ty: naga::TypeInner, + offset: u32, + size_bytes: u32, } #[cfg(all( @@ -495,13 +498,13 @@ struct UniformDesc { feature = "fragile-send-sync-non-atomic-wasm", not(target_feature = "atomics") ))] -unsafe impl Sync for UniformDesc {} +unsafe impl Sync for PushConstantDesc {} #[cfg(all( target_arch = "wasm32", feature = "fragile-send-sync-non-atomic-wasm", not(target_feature = "atomics") ))] -unsafe impl Send for UniformDesc {} +unsafe impl Send for PushConstantDesc {} /// For each texture in the pipeline layout, store the index of the only /// sampler (in this layout) that the texture is used with. @@ -510,7 +513,7 @@ type SamplerBindMap = [Option; MAX_TEXTURE_SLOTS]; struct PipelineInner { program: glow::Program, sampler_map: SamplerBindMap, - uniforms: [UniformDesc; MAX_PUSH_CONSTANTS], + push_constant_descs: ArrayVec, } #[derive(Clone, Debug)] @@ -882,7 +885,7 @@ enum Command { PushDebugGroup(Range), PopDebugGroup, SetPushConstants { - uniform: UniformDesc, + uniform: PushConstantDesc, /// Offset from the start of the `data_bytes` offset: u32, }, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 6125363aa7b..3b87ae7b729 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -564,7 +564,7 @@ impl super::Queue { ref copy, } => { let (block_width, block_height) = dst_format.block_dimensions(); - let block_size = dst_format.block_size(None).unwrap(); + let block_size = dst_format.block_copy_size(None).unwrap(); let format_desc = self.shared.describe_texture_format(dst_format); let row_texels = copy .buffer_layout @@ -702,7 +702,7 @@ impl super::Queue { dst_target: _, ref copy, } => { - let block_size = src_format.block_size(None).unwrap(); + let block_size = src_format.block_copy_size(None).unwrap(); if src_format.is_compressed() { log::error!("Not implemented yet: compressed texture copy to buffer"); return; @@ -1441,64 +1441,217 @@ impl super::Queue { ref uniform, offset, } => { - fn get_data(data: &[u8], offset: u32) -> &[T] { - let raw = &data[(offset as usize)..]; - unsafe { - slice::from_raw_parts( - raw.as_ptr() as *const _, - raw.len() / mem::size_of::(), - ) - } + // T must be POD + // + // This function is absolutely sketchy and we really should be using bytemuck. + unsafe fn get_data(data: &[u8], offset: u32) -> &[T; COUNT] { + let data_required = mem::size_of::() * COUNT; + + let raw = &data[(offset as usize)..][..data_required]; + + debug_assert_eq!(data_required, raw.len()); + + let slice: &[T] = + unsafe { slice::from_raw_parts(raw.as_ptr() as *const _, COUNT) }; + + slice.try_into().unwrap() } - let location = uniform.location.as_ref(); + let location = Some(&uniform.location); - match uniform.utype { - glow::FLOAT => { - let data = get_data::(data_bytes, offset)[0]; + match uniform.ty { + // + // --- Float 1-4 Component --- + // + naga::TypeInner::Scalar(naga::Scalar::F32) => { + let data = unsafe { get_data::(data_bytes, offset)[0] }; unsafe { gl.uniform_1_f32(location, data) }; } - glow::FLOAT_VEC2 => { - let data = get_data::<[f32; 2]>(data_bytes, offset)[0]; - unsafe { gl.uniform_2_f32_slice(location, &data) }; + naga::TypeInner::Vector { + size: naga::VectorSize::Bi, + scalar: naga::Scalar::F32, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_2_f32_slice(location, data) }; } - glow::FLOAT_VEC3 => { - let data = get_data::<[f32; 3]>(data_bytes, offset)[0]; - unsafe { gl.uniform_3_f32_slice(location, &data) }; + naga::TypeInner::Vector { + size: naga::VectorSize::Tri, + scalar: naga::Scalar::F32, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_3_f32_slice(location, data) }; } - glow::FLOAT_VEC4 => { - let data = get_data::<[f32; 4]>(data_bytes, offset)[0]; - unsafe { gl.uniform_4_f32_slice(location, &data) }; + naga::TypeInner::Vector { + size: naga::VectorSize::Quad, + scalar: naga::Scalar::F32, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_4_f32_slice(location, data) }; } - glow::INT => { - let data = get_data::(data_bytes, offset)[0]; + + // + // --- Int 1-4 Component --- + // + naga::TypeInner::Scalar(naga::Scalar::I32) => { + let data = unsafe { get_data::(data_bytes, offset)[0] }; unsafe { gl.uniform_1_i32(location, data) }; } - glow::INT_VEC2 => { - let data = get_data::<[i32; 2]>(data_bytes, offset)[0]; - unsafe { gl.uniform_2_i32_slice(location, &data) }; + naga::TypeInner::Vector { + size: naga::VectorSize::Bi, + scalar: naga::Scalar::I32, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_2_i32_slice(location, data) }; + } + naga::TypeInner::Vector { + size: naga::VectorSize::Tri, + scalar: naga::Scalar::I32, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_3_i32_slice(location, data) }; } - glow::INT_VEC3 => { - let data = get_data::<[i32; 3]>(data_bytes, offset)[0]; - unsafe { gl.uniform_3_i32_slice(location, &data) }; + naga::TypeInner::Vector { + size: naga::VectorSize::Quad, + scalar: naga::Scalar::I32, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_4_i32_slice(location, data) }; + } + + // + // --- Uint 1-4 Component --- + // + naga::TypeInner::Scalar(naga::Scalar::U32) => { + let data = unsafe { get_data::(data_bytes, offset)[0] }; + unsafe { gl.uniform_1_u32(location, data) }; } - glow::INT_VEC4 => { - let data = get_data::<[i32; 4]>(data_bytes, offset)[0]; - unsafe { gl.uniform_4_i32_slice(location, &data) }; + naga::TypeInner::Vector { + size: naga::VectorSize::Bi, + scalar: naga::Scalar::U32, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_2_u32_slice(location, data) }; } - glow::FLOAT_MAT2 => { - let data = get_data::<[f32; 4]>(data_bytes, offset)[0]; - unsafe { gl.uniform_matrix_2_f32_slice(location, false, &data) }; + naga::TypeInner::Vector { + size: naga::VectorSize::Tri, + scalar: naga::Scalar::U32, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_3_u32_slice(location, data) }; + } + naga::TypeInner::Vector { + size: naga::VectorSize::Quad, + scalar: naga::Scalar::U32, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_4_u32_slice(location, data) }; + } + + // + // --- Matrix 2xR --- + // + naga::TypeInner::Matrix { + columns: naga::VectorSize::Bi, + rows: naga::VectorSize::Bi, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_2_f32_slice(location, false, data) }; + } + naga::TypeInner::Matrix { + columns: naga::VectorSize::Bi, + rows: naga::VectorSize::Tri, + width: 4, + } => { + // repack 2 vec3s into 6 values. + let unpacked_data = unsafe { get_data::(data_bytes, offset) }; + #[rustfmt::skip] + let packed_data = [ + unpacked_data[0], unpacked_data[1], unpacked_data[2], + unpacked_data[4], unpacked_data[5], unpacked_data[6], + ]; + unsafe { gl.uniform_matrix_2x3_f32_slice(location, false, &packed_data) }; + } + naga::TypeInner::Matrix { + columns: naga::VectorSize::Bi, + rows: naga::VectorSize::Quad, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_2x4_f32_slice(location, false, data) }; + } + + // + // --- Matrix 3xR --- + // + naga::TypeInner::Matrix { + columns: naga::VectorSize::Tri, + rows: naga::VectorSize::Bi, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_3x2_f32_slice(location, false, data) }; + } + naga::TypeInner::Matrix { + columns: naga::VectorSize::Tri, + rows: naga::VectorSize::Tri, + width: 4, + } => { + // repack 3 vec3s into 9 values. + let unpacked_data = unsafe { get_data::(data_bytes, offset) }; + #[rustfmt::skip] + let packed_data = [ + unpacked_data[0], unpacked_data[1], unpacked_data[2], + unpacked_data[4], unpacked_data[5], unpacked_data[6], + unpacked_data[8], unpacked_data[9], unpacked_data[10], + ]; + unsafe { gl.uniform_matrix_3_f32_slice(location, false, &packed_data) }; + } + naga::TypeInner::Matrix { + columns: naga::VectorSize::Tri, + rows: naga::VectorSize::Quad, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_3x4_f32_slice(location, false, data) }; + } + + // + // --- Matrix 4xR --- + // + naga::TypeInner::Matrix { + columns: naga::VectorSize::Quad, + rows: naga::VectorSize::Bi, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_4x2_f32_slice(location, false, data) }; } - glow::FLOAT_MAT3 => { - let data = get_data::<[f32; 9]>(data_bytes, offset)[0]; - unsafe { gl.uniform_matrix_3_f32_slice(location, false, &data) }; + naga::TypeInner::Matrix { + columns: naga::VectorSize::Quad, + rows: naga::VectorSize::Tri, + width: 4, + } => { + // repack 4 vec3s into 12 values. + let unpacked_data = unsafe { get_data::(data_bytes, offset) }; + #[rustfmt::skip] + let packed_data = [ + unpacked_data[0], unpacked_data[1], unpacked_data[2], + unpacked_data[4], unpacked_data[5], unpacked_data[6], + unpacked_data[8], unpacked_data[9], unpacked_data[10], + unpacked_data[12], unpacked_data[13], unpacked_data[14], + ]; + unsafe { gl.uniform_matrix_4x3_f32_slice(location, false, &packed_data) }; } - glow::FLOAT_MAT4 => { - let data = get_data::<[f32; 16]>(data_bytes, offset)[0]; - unsafe { gl.uniform_matrix_4_f32_slice(location, false, &data) }; + naga::TypeInner::Matrix { + columns: naga::VectorSize::Quad, + rows: naga::VectorSize::Quad, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_4_f32_slice(location, false, data) }; } - _ => panic!("Unsupported uniform datatype!"), + _ => panic!("Unsupported uniform datatype: {:?}!", uniform.ty), } } } diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 2e989499e46..6c8e36ab7ce 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -97,6 +97,9 @@ use bitflags::bitflags; use thiserror::Error; use wgt::{WasmNotSend, WasmNotSync}; +// - Vertex + Fragment +// - Compute +pub const MAX_CONCURRENT_SHADER_STAGES: usize = 2; pub const MAX_ANISOTROPY: u8 = 16; pub const MAX_BIND_GROUPS: usize = 8; pub const MAX_VERTEX_BUFFERS: usize = 16; @@ -500,11 +503,19 @@ pub trait CommandEncoder: WasmNotSend + WasmNotSync + fmt::Debug { dynamic_offsets: &[wgt::DynamicOffset], ); + /// Sets a range in push constant data. + /// + /// IMPORTANT: while the data is passed as words, the offset is in bytes! + /// + /// # Safety + /// + /// - `offset_bytes` must be a multiple of 4. + /// - The range of push constants written must be valid for the pipeline layout at draw time. unsafe fn set_push_constants( &mut self, layout: &A::PipelineLayout, stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ); diff --git a/wgpu-hal/src/metal/command.rs b/wgpu-hal/src/metal/command.rs index c4b37f99325..5196e0447d4 100644 --- a/wgpu-hal/src/metal/command.rs +++ b/wgpu-hal/src/metal/command.rs @@ -798,17 +798,17 @@ impl crate::CommandEncoder for super::CommandEncoder { &mut self, layout: &super::PipelineLayout, stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ) { let state_pc = &mut self.state.push_constants; if state_pc.len() < layout.total_push_constants as usize { state_pc.resize(layout.total_push_constants as usize, 0); } - assert_eq!(offset as usize % WORD_SIZE, 0); + debug_assert_eq!(offset_bytes as usize % WORD_SIZE, 0); - let offset = offset as usize / WORD_SIZE; - state_pc[offset..offset + data.len()].copy_from_slice(data); + let offset_words = offset_bytes as usize / WORD_SIZE; + state_pc[offset_words..offset_words + data.len()].copy_from_slice(data); if stages.contains(wgt::ShaderStages::COMPUTE) { self.state.compute.as_ref().unwrap().set_bytes( @@ -1104,48 +1104,55 @@ impl crate::CommandEncoder for super::CommandEncoder { let raw = self.raw_cmd_buf.as_ref().unwrap(); objc::rc::autoreleasepool(|| { - let descriptor = metal::ComputePassDescriptor::new(); - - let mut sba_index = 0; - let mut next_sba_descriptor = || { - let sba_descriptor = descriptor - .sample_buffer_attachments() - .object_at(sba_index) - .unwrap(); - sba_index += 1; - sba_descriptor - }; + // TimeStamp Queries and ComputePassDescriptor were both introduced in Metal 2.3 (macOS 11, iOS 14) + // and we currently only need ComputePassDescriptor for timestamp queries + let encoder = if self.shared.private_caps.timestamp_query_support.is_empty() { + raw.new_compute_command_encoder() + } else { + let descriptor = metal::ComputePassDescriptor::new(); + + let mut sba_index = 0; + let mut next_sba_descriptor = || { + let sba_descriptor = descriptor + .sample_buffer_attachments() + .object_at(sba_index) + .unwrap(); + sba_index += 1; + sba_descriptor + }; + + for (set, index) in self.state.pending_timer_queries.drain(..) { + let sba_descriptor = next_sba_descriptor(); + sba_descriptor.set_sample_buffer(set.counter_sample_buffer.as_ref().unwrap()); + sba_descriptor.set_start_of_encoder_sample_index(index as _); + sba_descriptor.set_end_of_encoder_sample_index(metal::COUNTER_DONT_SAMPLE); + } - for (set, index) in self.state.pending_timer_queries.drain(..) { - let sba_descriptor = next_sba_descriptor(); - sba_descriptor.set_sample_buffer(set.counter_sample_buffer.as_ref().unwrap()); - sba_descriptor.set_start_of_encoder_sample_index(index as _); - sba_descriptor.set_end_of_encoder_sample_index(metal::COUNTER_DONT_SAMPLE); - } + if let Some(timestamp_writes) = desc.timestamp_writes.as_ref() { + let sba_descriptor = next_sba_descriptor(); + sba_descriptor.set_sample_buffer( + timestamp_writes + .query_set + .counter_sample_buffer + .as_ref() + .unwrap(), + ); - if let Some(timestamp_writes) = desc.timestamp_writes.as_ref() { - let sba_descriptor = next_sba_descriptor(); - sba_descriptor.set_sample_buffer( - timestamp_writes - .query_set - .counter_sample_buffer - .as_ref() - .unwrap(), - ); + sba_descriptor.set_start_of_encoder_sample_index( + timestamp_writes + .beginning_of_pass_write_index + .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), + ); + sba_descriptor.set_end_of_encoder_sample_index( + timestamp_writes + .end_of_pass_write_index + .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), + ); + } - sba_descriptor.set_start_of_encoder_sample_index( - timestamp_writes - .beginning_of_pass_write_index - .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), - ); - sba_descriptor.set_end_of_encoder_sample_index( - timestamp_writes - .end_of_pass_write_index - .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), - ); - } + raw.compute_command_encoder_with_descriptor(descriptor) + }; - let encoder = raw.compute_command_encoder_with_descriptor(descriptor); if let Some(label) = desc.label { encoder.set_label(label); } diff --git a/wgpu-hal/src/vulkan/command.rs b/wgpu-hal/src/vulkan/command.rs index 391b754d335..52226f34ebd 100644 --- a/wgpu-hal/src/vulkan/command.rs +++ b/wgpu-hal/src/vulkan/command.rs @@ -23,7 +23,7 @@ impl super::Texture { buffer_offset: r.buffer_layout.offset, buffer_row_length: r.buffer_layout.bytes_per_row.map_or(0, |bpr| { let block_size = format - .block_size(Some(r.texture_base.aspect.map())) + .block_copy_size(Some(r.texture_base.aspect.map())) .unwrap(); block_width * (bpr / block_size) }), @@ -600,7 +600,7 @@ impl crate::CommandEncoder for super::CommandEncoder { &mut self, layout: &super::PipelineLayout, stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ) { unsafe { @@ -608,7 +608,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.active, layout.raw, conv::map_shader_stage(stages), - offset, + offset_bytes, slice::from_raw_parts(data.as_ptr() as _, data.len() * 4), ) }; diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index 71b8a877c9b..c27fdf9f72f 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -451,8 +451,7 @@ pub fn map_vk_present_mode(mode: vk::PresentModeKHR) -> Option } else if mode == vk::PresentModeKHR::FIFO { Some(wgt::PresentMode::Fifo) } else if mode == vk::PresentModeKHR::FIFO_RELAXED { - //Some(wgt::PresentMode::Relaxed) - None + Some(wgt::PresentMode::FifoRelaxed) } else { log::warn!("Unrecognized present mode {:?}", mode); None diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index d88b48ef735..8eb2935a32b 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -1588,7 +1588,7 @@ impl crate::Device for super::Device { multiview: desc.multiview, ..Default::default() }; - let mut stages = ArrayVec::<_, 2>::new(); + let mut stages = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new(); let mut vertex_buffers = Vec::with_capacity(desc.vertex_buffers.len()); let mut vertex_attributes = Vec::new(); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index e8ac73f2e14..236f1462cc6 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -2823,7 +2823,9 @@ impl TextureFormat { } } - /// Returns the dimension of a block of texels. + /// Returns the dimension of a [block](https://gpuweb.github.io/gpuweb/#texel-block) of texels. + /// + /// Uncompressed formats have a block dimension of `(1, 1)`. pub fn block_dimensions(&self) -> (u32, u32) { match *self { Self::R8Unorm @@ -3235,14 +3237,34 @@ impl TextureFormat { } } - /// Returns the [texel block size](https://gpuweb.github.io/gpuweb/#texel-block-size) - /// of this format. + /// The number of bytes one [texel block](https://gpuweb.github.io/gpuweb/#texel-block) occupies during an image copy, if applicable. + /// + /// Known as the [texel block copy footprint](https://gpuweb.github.io/gpuweb/#texel-block-copy-footprint). + /// + /// Note that for uncompressed formats this is the same as the size of a single texel, + /// since uncompressed formats have a block size of 1x1. /// /// Returns `None` if any of the following are true: /// - the format is combined depth-stencil and no `aspect` was provided /// - the format is `Depth24Plus` /// - the format is `Depth24PlusStencil8` and `aspect` is depth. + #[deprecated(since = "0.19.0", note = "Use `block_copy_size` instead.")] pub fn block_size(&self, aspect: Option) -> Option { + self.block_copy_size(aspect) + } + + /// The number of bytes one [texel block](https://gpuweb.github.io/gpuweb/#texel-block) occupies during an image copy, if applicable. + /// + /// Known as the [texel block copy footprint](https://gpuweb.github.io/gpuweb/#texel-block-copy-footprint). + /// + /// Note that for uncompressed formats this is the same as the size of a single texel, + /// since uncompressed formats have a block size of 1x1. + /// + /// Returns `None` if any of the following are true: + /// - the format is combined depth-stencil and no `aspect` was provided + /// - the format is `Depth24Plus` + /// - the format is `Depth24PlusStencil8` and `aspect` is depth. + pub fn block_copy_size(&self, aspect: Option) -> Option { match *self { Self::R8Unorm | Self::R8Snorm | Self::R8Uint | Self::R8Sint => Some(1), @@ -6717,3 +6739,15 @@ mod send_sync { )))] impl WasmNotSync for T {} } + +/// Reason for "lose the device". +/// +/// Corresponds to [WebGPU `GPUDeviceLostReason`](https://gpuweb.github.io/gpuweb/#enumdef-gpudevicelostreason). +#[repr(u8)] +#[derive(Debug, Copy, Clone)] +pub enum DeviceLostReason { + /// Triggered by driver + Unknown = 0, + /// After Device::destroy + Destroyed = 1, +} diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index e705d34e928..1a12a5601ed 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -22,6 +22,7 @@ use std::{ sync::Arc, }; use wgc::command::{bundle_ffi::*, compute_ffi::*, render_ffi::*}; +use wgc::device::DeviceLostClosure; use wgc::id::TypedId; use wgt::{WasmNotSend, WasmNotSync}; @@ -1217,7 +1218,7 @@ impl crate::Context for Context { if let Some(cause) = error { if let wgc::pipeline::CreateRenderPipelineError::Internal { stage, ref error } = cause { log::error!("Shader translation error for stage {:?}: {}", stage, error); - log::error!("Please report it to https://github.com/gfx-rs/naga"); + log::error!("Please report it to https://github.com/gfx-rs/wgpu"); } self.handle_error( &device_data.error_sink, @@ -1262,12 +1263,12 @@ impl crate::Context for Context { )); if let Some(cause) = error { if let wgc::pipeline::CreateComputePipelineError::Internal(ref error) = cause { - log::warn!( + log::error!( "Shader translation error for stage {:?}: {}", wgt::ShaderStages::COMPUTE, error ); - log::warn!("Please report it to https://github.com/gfx-rs/naga"); + log::error!("Please report it to https://github.com/gfx-rs/wgpu"); } self.handle_error( &device_data.error_sink, @@ -1455,14 +1456,30 @@ impl crate::Context for Context { wgc::gfx_select!(device => global.device_drop(*device)); } + fn device_set_device_lost_callback( + &self, + device: &Self::DeviceId, + _device_data: &Self::DeviceData, + device_lost_callback: crate::context::DeviceLostCallback, + ) { + let global = &self.0; + let device_lost_closure = DeviceLostClosure::from_rust(device_lost_callback); + wgc::gfx_select!(device => global.device_set_device_lost_closure(*device, device_lost_closure)); + } fn device_destroy(&self, device: &Self::DeviceId, _device_data: &Self::DeviceData) { let global = &self.0; wgc::gfx_select!(device => global.device_destroy(*device)); } - fn device_lose(&self, device: &Self::DeviceId, _device_data: &Self::DeviceData) { - // TODO: accept a reason, and pass it to device_lose. + fn device_mark_lost( + &self, + device: &Self::DeviceId, + _device_data: &Self::DeviceData, + message: &str, + ) { + // We do not provide a reason to device_lose, because all reasons other than + // destroyed (which this is not) are "unknown". let global = &self.0; - wgc::gfx_select!(device => global.device_lose(*device, None)); + wgc::gfx_select!(device => global.device_mark_lost(*device, message)); } fn device_poll( &self, @@ -2327,6 +2344,11 @@ impl crate::Context for Context { Ok(index) => index, Err(err) => self.handle_error_fatal(err, "Queue::submit"), }; + + for cmdbuf in &temp_command_buffers { + wgc::gfx_select!(*queue => global.command_buffer_drop(*cmdbuf)); + } + (Unused, index) } diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index f07d6f620a6..30d67d8643e 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1937,12 +1937,26 @@ impl crate::context::Context for Context { device_data.0.destroy(); } - fn device_lose(&self, _device: &Self::DeviceId, _device_data: &Self::DeviceData) { + fn device_mark_lost( + &self, + _device: &Self::DeviceId, + _device_data: &Self::DeviceData, + _message: &str, + ) { // TODO: figure out the GPUDevice implementation of this, including resolving // the device.lost promise, which will require a different invocation pattern // with a callback. } + fn device_set_device_lost_callback( + &self, + _device: &Self::DeviceId, + _device_data: &Self::DeviceData, + _device_lost_callback: crate::context::DeviceLostCallback, + ) { + unimplemented!(); + } + fn device_poll( &self, _device: &Self::DeviceId, diff --git a/wgpu/src/context.rs b/wgpu/src/context.rs index 52fbe14df33..0d1e95f3b99 100644 --- a/wgpu/src/context.rs +++ b/wgpu/src/context.rs @@ -2,7 +2,7 @@ use std::{any::Any, fmt::Debug, future::Future, num::NonZeroU64, ops::Range, pin use wgt::{ strict_assert, strict_assert_eq, AdapterInfo, BufferAddress, BufferSize, Color, - DownlevelCapabilities, DynamicOffset, Extent3d, Features, ImageDataLayout, + DeviceLostReason, DownlevelCapabilities, DynamicOffset, Extent3d, Features, ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits, ShaderStages, SurfaceStatus, TextureFormat, TextureFormatFeatures, WasmNotSend, WasmNotSync, }; @@ -269,8 +269,19 @@ pub trait Context: Debug + WasmNotSend + WasmNotSync + Sized { desc: &RenderBundleEncoderDescriptor, ) -> (Self::RenderBundleEncoderId, Self::RenderBundleEncoderData); fn device_drop(&self, device: &Self::DeviceId, device_data: &Self::DeviceData); + fn device_set_device_lost_callback( + &self, + device: &Self::DeviceId, + device_data: &Self::DeviceData, + device_lost_callback: DeviceLostCallback, + ); fn device_destroy(&self, device: &Self::DeviceId, device_data: &Self::DeviceData); - fn device_lose(&self, device: &Self::DeviceId, device_data: &Self::DeviceData); + fn device_mark_lost( + &self, + device: &Self::DeviceId, + device_data: &Self::DeviceData, + message: &str, + ); fn device_poll( &self, device: &Self::DeviceId, @@ -1199,6 +1210,22 @@ pub type SubmittedWorkDoneCallback = Box; ) )))] pub type SubmittedWorkDoneCallback = Box; +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] +pub type DeviceLostCallback = Box; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +pub type DeviceLostCallback = Box; /// An object safe variant of [`Context`] implemented by all types that implement [`Context`]. pub(crate) trait DynContext: Debug + WasmNotSend + WasmNotSync { @@ -1365,8 +1392,14 @@ pub(crate) trait DynContext: Debug + WasmNotSend + WasmNotSync { desc: &RenderBundleEncoderDescriptor, ) -> (ObjectId, Box); fn device_drop(&self, device: &ObjectId, device_data: &crate::Data); + fn device_set_device_lost_callback( + &self, + device: &ObjectId, + device_data: &crate::Data, + device_lost_callback: DeviceLostCallback, + ); fn device_destroy(&self, device: &ObjectId, device_data: &crate::Data); - fn device_lose(&self, device: &ObjectId, device_data: &crate::Data); + fn device_mark_lost(&self, device: &ObjectId, device_data: &crate::Data, message: &str); fn device_poll(&self, device: &ObjectId, device_data: &crate::Data, maintain: Maintain) -> bool; fn device_on_uncaptured_error( @@ -2428,16 +2461,27 @@ where Context::device_drop(self, &device, device_data) } + fn device_set_device_lost_callback( + &self, + device: &ObjectId, + device_data: &crate::Data, + device_lost_callback: DeviceLostCallback, + ) { + let device = ::from(*device); + let device_data = downcast_ref(device_data); + Context::device_set_device_lost_callback(self, &device, device_data, device_lost_callback) + } + fn device_destroy(&self, device: &ObjectId, device_data: &crate::Data) { let device = ::from(*device); let device_data = downcast_ref(device_data); Context::device_destroy(self, &device, device_data) } - fn device_lose(&self, device: &ObjectId, device_data: &crate::Data) { + fn device_mark_lost(&self, device: &ObjectId, device_data: &crate::Data, message: &str) { let device = ::from(*device); let device_data = downcast_ref(device_data); - Context::device_lose(self, &device, device_data) + Context::device_mark_lost(self, &device, device_data, message) } fn device_poll( diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 6c202a04a96..914e234f1da 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -32,19 +32,19 @@ pub use wgt::{ BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState, BufferAddress, BufferBindingType, BufferSize, BufferUsages, Color, ColorTargetState, ColorWrites, CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, DepthBiasState, - DepthStencilState, DeviceType, DownlevelCapabilities, DownlevelFlags, Dx12Compiler, - DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, Gles3MinorVersion, - ImageDataLayout, ImageSubresourceRange, IndexFormat, InstanceDescriptor, InstanceFlags, Limits, - MultisampleState, Origin2d, Origin3d, PipelineStatisticsTypes, PolygonMode, PowerPreference, - PredefinedColorSpace, PresentMode, PresentationTimestamp, PrimitiveState, PrimitiveTopology, - PushConstantRange, QueryType, RenderBundleDepthStencil, SamplerBindingType, SamplerBorderColor, - ShaderLocation, ShaderModel, ShaderStages, StencilFaceState, StencilOperation, StencilState, - StorageTextureAccess, SurfaceCapabilities, SurfaceStatus, TextureAspect, TextureDimension, - TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType, - TextureUsages, TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode, - WasmNotSend, WasmNotSync, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, - PUSH_CONSTANT_ALIGNMENT, QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, - VERTEX_STRIDE_ALIGNMENT, + DepthStencilState, DeviceLostReason, DeviceType, DownlevelCapabilities, DownlevelFlags, + Dx12Compiler, DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, + Gles3MinorVersion, ImageDataLayout, ImageSubresourceRange, IndexFormat, InstanceDescriptor, + InstanceFlags, Limits, MultisampleState, Origin2d, Origin3d, PipelineStatisticsTypes, + PolygonMode, PowerPreference, PredefinedColorSpace, PresentMode, PresentationTimestamp, + PrimitiveState, PrimitiveTopology, PushConstantRange, QueryType, RenderBundleDepthStencil, + SamplerBindingType, SamplerBorderColor, ShaderLocation, ShaderModel, ShaderStages, + StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, SurfaceCapabilities, + SurfaceStatus, TextureAspect, TextureDimension, TextureFormat, TextureFormatFeatureFlags, + TextureFormatFeatures, TextureSampleType, TextureUsages, TextureViewDimension, VertexAttribute, + VertexFormat, VertexStepMode, WasmNotSend, WasmNotSync, COPY_BUFFER_ALIGNMENT, + COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, + QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT, }; #[cfg(any( @@ -2811,6 +2811,19 @@ impl Device { pub fn destroy(&self) { DynContext::device_destroy(&*self.context, &self.id, self.data.as_ref()) } + + /// Set a DeviceLostCallback on this device. + pub fn set_device_lost_callback( + &self, + callback: impl FnOnce(DeviceLostReason, String) + Send + 'static, + ) { + DynContext::device_set_device_lost_callback( + &*self.context, + &self.id, + self.data.as_ref(), + Box::new(callback), + ) + } } impl Drop for Device { diff --git a/wgpu/src/util/device.rs b/wgpu/src/util/device.rs index 2d6f0ed7fe8..f8e02421eb2 100644 --- a/wgpu/src/util/device.rs +++ b/wgpu/src/util/device.rs @@ -88,7 +88,7 @@ impl DeviceExt for crate::Device { // Will return None only if it's a combined depth-stencil format // If so, default to 4, validation will fail later anyway since the depth or stencil // aspect needs to be written to individually - let block_size = desc.format.block_size(None).unwrap_or(4); + let block_size = desc.format.block_copy_size(None).unwrap_or(4); let (block_width, block_height) = desc.format.block_dimensions(); let layer_iterations = desc.array_layer_count();