pubusecrate::span::{SourceLocation, Span, SpanContext, WithSpan}; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; use diagnostic_filter::DiagnosticFilterNode; #[cfg(feature = "deserialize")] use serde::Deserialize; #[cfg(feature = "serialize")] use serde::Serialize;
/// Width of a boolean type, in bytes. pubconst BOOL_WIDTH: Bytes = 1;
/// Width of abstract types, in bytes. pubconst ABSTRACT_WIDTH: Bytes = 8;
/// Hash map that is faster but not resilient to DoS attacks. pubtype FastHashMap<K, T> = rustc_hash::FxHashMap<K, T>; /// Hash set that is faster but not resilient to DoS attacks. pubtype FastHashSet<K> = rustc_hash::FxHashSet<K>;
/// Insertion-order-preserving hash set (`IndexSet<K>`), but with the same /// hasher as `FastHashSet<K>` (faster but not resilient to DoS attacks). pubtype FastIndexSet<K> =
indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
/// Insertion-order-preserving hash map (`IndexMap<K, V>`), but with the same /// hasher as `FastHashMap<K, V>` (faster but not resilient to DoS attacks). pubtype FastIndexMap<K, V> =
indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
/// Map of expressions that have associated variable names pub(crate) type NamedExpressions = FastIndexMap<Handle<Expression>, String>;
/// Early fragment tests. /// /// In a standard situation, if a driver determines that it is possible to switch on early depth test, it will. /// /// Typical situations when early depth test is switched off: /// - Calling `discard` in a shader. /// - Writing to the depth buffer, unless ConservativeDepth is enabled. /// /// To use in a shader: /// - GLSL: `layout(early_fragment_tests) in;` /// - HLSL: `Attribute earlydepthstencil` /// - SPIR-V: `ExecutionMode EarlyFragmentTests` /// - WGSL: `@early_depth_test` /// /// For more, see: /// - <https://www.khronos.org/opengl/wiki/Early_Fragment_Test#Explicit_specification> /// - <https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-attributes-earlydepthstencil> /// - <https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Execution_Mode> #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct EarlyDepthTest { pub conservative: Option<ConservativeDepth>,
} /// Enables adjusting depth without disabling early Z. /// /// To use in a shader: /// - GLSL: `layout (depth_<greater/less/unchanged/any>) out float gl_FragDepth;` /// - `depth_any` option behaves as if the layout qualifier was not present. /// - HLSL: `SV_DepthGreaterEqual`/`SV_DepthLessEqual`/`SV_Depth` /// - SPIR-V: `ExecutionMode Depth<Greater/Less/Unchanged>` /// - WGSL: `@early_depth_test(greater_equal/less_equal/unchanged)` /// /// For more, see: /// - <https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_conservative_depth.txt> /// - <https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics#system-value-semantics> /// - <https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Execution_Mode> #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum ConservativeDepth { /// Shader may rewrite depth only with a value greater than calculated.
GreaterEqual,
/// Shader may rewrite depth smaller than one that would have been written without the modification.
LessEqual,
/// Shader may not rewrite depth value.
Unchanged,
}
/// Stage of the programmable pipeline. #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[allow(missing_docs)] // The names are self evident pubenum ShaderStage {
Vertex,
Fragment,
Compute,
}
/// Size of an array. #[repr(u8)] #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum ArraySize { /// The array size is constant.
Constant(std::num::NonZeroU32), /// The array size is an override-expression.
Pending(PendingArraySize), /// The array size can change at runtime.
Dynamic,
}
/// The interpolation qualifier of a binding or struct field. #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum Interpolation { /// The value will be interpolated in a perspective-correct fashion. /// Also known as "smooth" in glsl.
Perspective, /// Indicates that linear, non-perspective, correct /// interpolation must be used. /// Also known as "no_perspective" in glsl.
Linear, /// Indicates that no interpolation will be performed.
Flat,
}
/// The sampling qualifiers of a binding or struct field. #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum Sampling { /// Interpolate the value at the center of the pixel.
Center,
/// Interpolate the value at a point that lies within all samples covered by /// the fragment within the current primitive. In multisampling, use a /// single value for all samples in the primitive.
Centroid,
/// Interpolate the value at each sample location. In multisampling, invoke /// the fragment shader once per sample.
Sample,
/// Use the value provided by the first vertex of the current primitive.
First,
/// Use the value provided by the first or last vertex of the current primitive. The exact /// choice is implementation-dependent.
Either,
}
/// Member of a user-defined structure. // Clone is used only for error reporting and is not intended for end users #[derive(Clone, Debug, Eq, Hash, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct StructMember { pub name: Option<String>, /// Type of the field. pub ty: Handle<Type>, /// For I/O structs, defines the binding. pub binding: Option<Binding>, /// Offset from the beginning from the struct. pub offset: u32,
}
/// The number of dimensions an image has. #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum ImageDimension { /// 1D image
D1, /// 2D image
D2, /// 3D image
D3, /// Cube map
Cube,
}
bitflags::bitflags! { /// Flags describing an image. #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pubstruct StorageAccess: u32 { /// Storage can be used as a source for load ops. const LOAD = 0x1; /// Storage can be used as a target for store ops. const STORE = 0x2; /// Storage can be used as a target for atomic ops. const ATOMIC = 0x4;
}
}
/// A data type declared in the module. #[derive(Clone, Debug, Eq, Hash, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstructType { /// The name of the type, if any. pub name: Option<String>, /// Inner structure that depends on the kind of the type. pub inner: TypeInner,
}
/// Enum with additional information, depending on the kind of type. #[derive(Clone, Debug, Eq, Hash, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum TypeInner { /// Number of integral or floating-point kind.
Scalar(Scalar), /// Vector of numbers.
Vector { size: VectorSize, scalar: Scalar }, /// Matrix of numbers.
Matrix {
columns: VectorSize,
rows: VectorSize,
scalar: Scalar,
}, /// Atomic scalar.
Atomic(Scalar), /// Pointer to another type. /// /// Pointers to scalars and vectors should be treated as equivalent to /// [`ValuePointer`] types. Use the [`TypeInner::equivalent`] method to /// compare types in a way that treats pointers correctly. /// /// ## Pointers to non-`SIZED` types /// /// The `base` type of a pointer may be a non-[`SIZED`] type like a /// dynamically-sized [`Array`], or a [`Struct`] whose last member is a /// dynamically sized array. Such pointers occur as the types of /// [`GlobalVariable`] or [`AccessIndex`] expressions referring to /// dynamically-sized arrays. /// /// However, among pointers to non-`SIZED` types, only pointers to `Struct`s /// are [`DATA`]. Pointers to dynamically sized `Array`s cannot be passed as /// arguments, stored in variables, or held in arrays or structures. Their /// only use is as the types of `AccessIndex` expressions. /// /// [`SIZED`]: valid::TypeFlags::SIZED /// [`DATA`]: valid::TypeFlags::DATA /// [`Array`]: TypeInner::Array /// [`Struct`]: TypeInner::Struct /// [`ValuePointer`]: TypeInner::ValuePointer /// [`GlobalVariable`]: Expression::GlobalVariable /// [`AccessIndex`]: Expression::AccessIndex
Pointer {
base: Handle<Type>,
space: AddressSpace,
},
/// Pointer to a scalar or vector. /// /// A `ValuePointer` type is equivalent to a `Pointer` whose `base` is a /// `Scalar` or `Vector` type. This is for use in [`TypeResolution::Value`] /// variants; see the documentation for [`TypeResolution`] for details. /// /// Use the [`TypeInner::equivalent`] method to compare types that could be /// pointers, to ensure that `Pointer` and `ValuePointer` types are /// recognized as equivalent. /// /// [`TypeResolution`]: proc::TypeResolution /// [`TypeResolution::Value`]: proc::TypeResolution::Value
ValuePointer {
size: Option<VectorSize>,
scalar: Scalar,
space: AddressSpace,
},
/// Homogeneous list of elements. /// /// The `base` type must be a [`SIZED`], [`DATA`] type. /// /// ## Dynamically sized arrays /// /// An `Array` is [`SIZED`] unless its `size` is [`Dynamic`]. /// Dynamically-sized arrays may only appear in a few situations: /// /// - They may appear as the type of a [`GlobalVariable`], or as the last /// member of a [`Struct`]. /// /// - They may appear as the base type of a [`Pointer`]. An /// [`AccessIndex`] expression referring to a struct's final /// unsized array member would have such a pointer type. However, such /// pointer types may only appear as the types of such intermediate /// expressions. They are not [`DATA`], and cannot be stored in /// variables, held in arrays or structs, or passed as parameters. /// /// [`SIZED`]: crate::valid::TypeFlags::SIZED /// [`DATA`]: crate::valid::TypeFlags::DATA /// [`Dynamic`]: ArraySize::Dynamic /// [`Struct`]: TypeInner::Struct /// [`Pointer`]: TypeInner::Pointer /// [`AccessIndex`]: Expression::AccessIndex
Array {
base: Handle<Type>,
size: ArraySize,
stride: u32,
},
/// User-defined structure. /// /// There must always be at least one member. /// /// A `Struct` type is [`DATA`], and the types of its members must be /// `DATA` as well. /// /// Member types must be [`SIZED`], except for the final member of a /// struct, which may be a dynamically sized [`Array`]. The /// `Struct` type itself is `SIZED` when all its members are `SIZED`. /// /// [`DATA`]: crate::valid::TypeFlags::DATA /// [`SIZED`]: crate::valid::TypeFlags::SIZED /// [`Array`]: TypeInner::Array Struct {
members: Vec<StructMember>, //TODO: should this be unaligned?
span: u32,
}, /// Possibly multidimensional array of texels.
Image {
dim: ImageDimension,
arrayed: bool, //TODO: consider moving `multisampled: bool` out
class: ImageClass,
}, /// Can be used to sample values from images.
Sampler { comparison: bool },
/// Opaque object representing an acceleration structure of geometry.
AccelerationStructure,
/// Locally used handle for ray queries.
RayQuery,
/// Array of bindings. /// /// A `BindingArray` represents an array where each element draws its value /// from a separate bound resource. The array's element type `base` may be /// [`Image`], [`Sampler`], or any type that would be permitted for a global /// in the [`Uniform`] or [`Storage`] address spaces. Only global variables /// may be binding arrays; on the host side, their values are provided by /// [`TextureViewArray`], [`SamplerArray`], or [`BufferArray`] /// bindings. /// /// Since each element comes from a distinct resource, a binding array of /// images could have images of varying sizes (but not varying dimensions; /// they must all have the same `Image` type). Or, a binding array of /// buffers could have elements that are dynamically sized arrays, each with /// a different length. /// /// Binding arrays are in the same address spaces as their underlying type. /// As such, referring to an array of images produces an [`Image`] value /// directly (as opposed to a pointer). The only operation permitted on /// `BindingArray` values is indexing, which works transparently: indexing /// a binding array of samplers yields a [`Sampler`], indexing a pointer to the /// binding array of storage buffers produces a pointer to the storage struct. /// /// Unlike textures and samplers, binding arrays are not [`ARGUMENT`], so /// they cannot be passed as arguments to functions. /// /// Naga's WGSL front end supports binding arrays with the type syntax /// `binding_array<T, N>`. /// /// [`Image`]: TypeInner::Image /// [`Sampler`]: TypeInner::Sampler /// [`Uniform`]: AddressSpace::Uniform /// [`Storage`]: AddressSpace::Storage /// [`TextureViewArray`]: https://docs.rs/wgpu/latest/wgpu/enum.BindingResource.html#variant.TextureViewArray /// [`SamplerArray`]: https://docs.rs/wgpu/latest/wgpu/enum.BindingResource.html#variant.SamplerArray /// [`BufferArray`]: https://docs.rs/wgpu/latest/wgpu/enum.BindingResource.html#variant.BufferArray /// [`DATA`]: crate::valid::TypeFlags::DATA /// [`ARGUMENT`]: crate::valid::TypeFlags::ARGUMENT /// [naga#1864]: https://github.com/gfx-rs/naga/issues/1864
BindingArray { base: Handle<Type>, size: ArraySize },
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum Literal { /// May not be NaN or infinity.
F64(f64), /// May not be NaN or infinity.
F32(f32),
U32(u32),
I32(i32),
U64(u64),
I64(i64),
Bool(bool),
AbstractInt(i64),
AbstractFloat(f64),
}
/// The default value of the pipeline-overridable constant. /// /// This [`Handle`] refers to [`Module::global_expressions`], not /// any [`Function::expressions`] arena. pub init: Option<Handle<Expression>>,
}
/// The value of the constant. /// /// This [`Handle`] refers to [`Module::global_expressions`], not /// any [`Function::expressions`] arena. pub init: Handle<Expression>,
}
/// Describes how an input/output variable is to be bound. #[derive(Clone, Debug, Eq, PartialEq, Hash)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum Binding { /// Built-in shader variable.
BuiltIn(BuiltIn),
/// Indexed location. /// /// Values passed from the [`Vertex`] stage to the [`Fragment`] stage must /// have their `interpolation` defaulted (i.e. not `None`) by the front end /// as appropriate for that language. /// /// For other stages, we permit interpolations even though they're ignored. /// When a front end is parsing a struct type, it usually doesn't know what /// stages will be using it for IO, so it's easiest if it can apply the /// defaults to anything with a `Location` binding, just in case. /// /// For anything other than floating-point scalars and vectors, the /// interpolation must be `Flat`. /// /// [`Vertex`]: crate::ShaderStage::Vertex /// [`Fragment`]: crate::ShaderStage::Fragment
Location {
location: u32, /// Indicates the 2nd input to the blender when dual-source blending.
second_blend_source: bool,
interpolation: Option<Interpolation>,
sampling: Option<Sampling>,
},
}
/// Pipeline binding information for global resources. #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct ResourceBinding { /// The bind group index. pub group: u32, /// Binding number within the group. pub binding: u32,
}
/// Variable defined at module level. #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct GlobalVariable { /// Name of the variable, if any. pub name: Option<String>, /// How this variable is to be stored. pub space: AddressSpace, /// For resources, defines the binding point. pub binding: Option<ResourceBinding>, /// The type of this variable. pub ty: Handle<Type>, /// Initial value for this variable. /// /// This refers to an [`Expression`] in [`Module::global_expressions`]. pub init: Option<Handle<Expression>>,
}
/// Variable defined at function level. #[derive(Clone, Debug)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct LocalVariable { /// Name of the variable, if any. pub name: Option<String>, /// The type of this variable. pub ty: Handle<Type>, /// Initial value for this variable. /// /// This handle refers to an expression in this `LocalVariable`'s function's /// [`expressions`] arena, but it is required to be an evaluated override /// expression. /// /// [`expressions`]: Function::expressions pub init: Option<Handle<Expression>>,
}
/// Operation that can be applied on a single value. #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum UnaryOperator {
Negate,
LogicalNot,
BitwiseNot,
}
/// Operation that can be applied on two values. /// /// ## Arithmetic type rules /// /// The arithmetic operations `Add`, `Subtract`, `Multiply`, `Divide`, and /// `Modulo` can all be applied to [`Scalar`] types other than [`Bool`], or /// [`Vector`]s thereof. Both operands must have the same type. /// /// `Add` and `Subtract` can also be applied to [`Matrix`] values. Both operands /// must have the same type. /// /// `Multiply` supports additional cases: /// /// - A [`Matrix`] or [`Vector`] can be multiplied by a scalar [`Float`], /// either on the left or the right. /// /// - A [`Matrix`] on the left can be multiplied by a [`Vector`] on the right /// if the matrix has as many columns as the vector has components (`matCxR /// * VecC`). /// /// - A [`Vector`] on the left can be multiplied by a [`Matrix`] on the right /// if the matrix has as many rows as the vector has components (`VecR * /// matCxR`). /// /// - Two matrices can be multiplied if the left operand has as many columns /// as the right operand has rows (`matNxR * matCxN`). /// /// In all the above `Multiply` cases, the byte widths of the underlying scalar /// types of both operands must be the same. /// /// Note that `Multiply` supports mixed vector and scalar operations directly, /// whereas the other arithmetic operations require an explicit [`Splat`] for /// mixed-type use. /// /// [`Scalar`]: TypeInner::Scalar /// [`Vector`]: TypeInner::Vector /// [`Matrix`]: TypeInner::Matrix /// [`Float`]: ScalarKind::Float /// [`Bool`]: ScalarKind::Bool /// [`Splat`]: Expression::Splat #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum BinaryOperator {
Add,
Subtract,
Multiply,
Divide, /// Equivalent of the WGSL's `%` operator or SPIR-V's `OpFRem`
Modulo,
Equal,
NotEqual,
Less,
LessEqual,
Greater,
GreaterEqual,
And,
ExclusiveOr,
InclusiveOr,
LogicalAnd,
LogicalOr,
ShiftLeft, /// Right shift carries the sign of signed integers only.
ShiftRight,
}
/// Function on an atomic value. /// /// Note: these do not include load/store, which use the existing /// [`Expression::Load`] and [`Statement::Store`]. /// /// All `Handle<Expression>` values here refer to an expression in /// [`Function::expressions`]. #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum AtomicFunction {
Add,
Subtract,
And,
ExclusiveOr,
InclusiveOr,
Min,
Max,
Exchange { compare: Option<Handle<Expression>> },
}
/// Hint at which precision to compute a derivative. #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum DerivativeControl {
Coarse,
Fine,
None,
}
/// Axis on which to compute a derivative. #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum DerivativeAxis {
X,
Y,
Width,
}
/// Built-in shader function for testing relation between values. #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum RelationalFunction {
All,
Any,
IsNan,
IsInf,
}
/// Sampling modifier to control the level of detail. /// /// All `Handle<Expression>` values here refer to an expression in /// [`Function::expressions`]. #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum SampleLevel {
Auto,
Zero,
Exact(Handle<Expression>),
Bias(Handle<Expression>),
Gradient {
x: Handle<Expression>,
y: Handle<Expression>,
},
}
/// Type of an image query. /// /// All `Handle<Expression>` values here refer to an expression in /// [`Function::expressions`]. #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum ImageQuery { /// Get the size at the specified level. /// /// The return value is a `u32` for 1D images, and a `vecN<u32>` /// for an image with dimensions N > 2.
Size { /// If `None`, the base level is considered.
level: Option<Handle<Expression>>,
}, /// Get the number of mipmap levels, a `u32`.
NumLevels, /// Get the number of array layers, a `u32`.
NumLayers, /// Get the number of samples, a `u32`.
NumSamples,
}
/// Component selection for a vector swizzle. #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum SwizzleComponent {
X = 0,
Y = 1,
Z = 2,
W = 3,
}
/// The specific behavior of a [`SubgroupGather`] statement. /// /// All `Handle<Expression>` values here refer to an expression in /// [`Function::expressions`]. /// /// [`SubgroupGather`]: Statement::SubgroupGather #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum GatherMode { /// All gather from the active lane with the smallest index
BroadcastFirst, /// All gather from the same lane at the index given by the expression
Broadcast(Handle<Expression>), /// Each gathers from a different lane at the index given by the expression
Shuffle(Handle<Expression>), /// Each gathers from their lane plus the shift given by the expression
ShuffleDown(Handle<Expression>), /// Each gathers from their lane minus the shift given by the expression
ShuffleUp(Handle<Expression>), /// Each gathers from their lane xored with the given by the expression
ShuffleXor(Handle<Expression>),
}
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum SubgroupOperation {
All = 0,
Any = 1,
Add = 2,
Mul = 3,
Min = 4,
Max = 5,
And = 6,
Or = 7,
Xor = 8,
}
bitflags::bitflags! { /// Memory barrier flags. #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pubstruct Barrier: u32 { /// Barrier affects all [`AddressSpace::Storage`] accesses. const STORAGE = 1 << 0; /// Barrier affects all [`AddressSpace::WorkGroup`] accesses. const WORK_GROUP = 1 << 1; /// Barrier synchronizes execution across all invocations within a subgroup that execute this instruction. const SUB_GROUP = 1 << 2;
}
}
/// An expression that can be evaluated to obtain a value. /// /// This is a Single Static Assignment (SSA) scheme similar to SPIR-V. /// /// When an `Expression` variant holds `Handle<Expression>` fields, they refer /// to another expression in the same arena, unless explicitly noted otherwise. /// One `Arena<Expression>` may only refer to a different arena indirectly, via /// [`Constant`] or [`Override`] expressions, which hold handles for their /// respective types. /// /// [`Constant`]: Expression::Constant /// [`Override`]: Expression::Override #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum Expression { /// Literal.
Literal(Literal), /// Constant value.
Constant(Handle<Constant>), /// Pipeline-overridable constant. Override(Handle<Override>), /// Zero value of a type.
ZeroValue(Handle<Type>), /// Composite expression.
Compose {
ty: Handle<Type>,
components: Vec<Handle<Expression>>,
},
/// Array access with a computed index. /// /// ## Typing rules /// /// The `base` operand must be some composite type: [`Vector`], [`Matrix`], /// [`Array`], a [`Pointer`] to one of those, or a [`ValuePointer`] with a /// `size`. /// /// The `index` operand must be an integer, signed or unsigned. /// /// Indexing a [`Vector`] or [`Array`] produces a value of its element type. /// Indexing a [`Matrix`] produces a [`Vector`]. /// /// Indexing a [`Pointer`] to any of the above produces a pointer to the /// element/component type, in the same [`space`]. In the case of [`Array`], /// the result is an actual [`Pointer`], but for vectors and matrices, there /// may not be any type in the arena representing the component's type, so /// those produce [`ValuePointer`] types equivalent to the appropriate /// [`Pointer`]. /// /// ## Dynamic indexing restrictions /// /// To accommodate restrictions in some of the shader languages that Naga /// targets, it is not permitted to subscript a matrix with a dynamically /// computed index unless that matrix appears behind a pointer. In other /// words, if the inner type of `base` is [`Matrix`], then `index` must be a /// constant. But if the type of `base` is a [`Pointer`] to an matrix, then /// the index may be any expression of integer type. /// /// You can use the [`Expression::is_dynamic_index`] method to determine /// whether a given index expression requires matrix base operands to be /// behind a pointer. /// /// (It would be simpler to always require the use of `AccessIndex` when /// subscripting matrices that are not behind pointers, but to accommodate /// existing front ends, Naga also permits `Access`, with a restricted /// `index`.) /// /// [`Vector`]: TypeInner::Vector /// [`Matrix`]: TypeInner::Matrix /// [`Array`]: TypeInner::Array /// [`Pointer`]: TypeInner::Pointer /// [`space`]: TypeInner::Pointer::space /// [`ValuePointer`]: TypeInner::ValuePointer /// [`Float`]: ScalarKind::Float
Access {
base: Handle<Expression>,
index: Handle<Expression>,
}, /// Access the same types as [`Access`], plus [`Struct`] with a known index. /// /// [`Access`]: Expression::Access /// [`Struct`]: TypeInner::Struct
AccessIndex {
base: Handle<Expression>,
index: u32,
}, /// Splat scalar into a vector.
Splat {
size: VectorSize,
value: Handle<Expression>,
}, /// Vector swizzle.
Swizzle {
size: VectorSize,
vector: Handle<Expression>,
pattern: [SwizzleComponent; 4],
},
/// Reference a function parameter, by its index. /// /// A `FunctionArgument` expression evaluates to a pointer to the argument's /// value. You must use a [`Load`] expression to retrieve its value, or a /// [`Store`] statement to assign it a new value. /// /// [`Load`]: Expression::Load /// [`Store`]: Statement::Store
FunctionArgument(u32),
/// Reference a global variable. /// /// If the given `GlobalVariable`'s [`space`] is [`AddressSpace::Handle`], /// then the variable stores some opaque type like a sampler or an image, /// and a `GlobalVariable` expression referring to it produces the /// variable's value directly. /// /// For any other address space, a `GlobalVariable` expression produces a /// pointer to the variable's value. You must use a [`Load`] expression to /// retrieve its value, or a [`Store`] statement to assign it a new value. /// /// [`space`]: GlobalVariable::space /// [`Load`]: Expression::Load /// [`Store`]: Statement::Store
GlobalVariable(Handle<GlobalVariable>),
/// Reference a local variable. /// /// A `LocalVariable` expression evaluates to a pointer to the variable's value. /// You must use a [`Load`](Expression::Load) expression to retrieve its value, /// or a [`Store`](Statement::Store) statement to assign it a new value.
LocalVariable(Handle<LocalVariable>),
/// Load a value indirectly. /// /// For [`TypeInner::Atomic`] the result is a corresponding scalar. /// For other types behind the `pointer<T>`, the result is `T`.
Load { pointer: Handle<Expression> }, /// Sample a point from a sampled or a depth image.
ImageSample {
image: Handle<Expression>,
sampler: Handle<Expression>, /// If Some(), this operation is a gather operation /// on the selected component.
gather: Option<SwizzleComponent>,
coordinate: Handle<Expression>,
array_index: Option<Handle<Expression>>, /// This refers to an expression in [`Module::global_expressions`].
offset: Option<Handle<Expression>>,
level: SampleLevel,
depth_ref: Option<Handle<Expression>>,
},
/// Load a texel from an image. /// /// For most images, this returns a four-element vector of the same /// [`ScalarKind`] as the image. If the format of the image does not have /// four components, default values are provided: the first three components /// (typically R, G, and B) default to zero, and the final component /// (typically alpha) defaults to one. /// /// However, if the image's [`class`] is [`Depth`], then this returns a /// [`Float`] scalar value. /// /// [`ScalarKind`]: ScalarKind /// [`class`]: TypeInner::Image::class /// [`Depth`]: ImageClass::Depth /// [`Float`]: ScalarKind::Float
ImageLoad { /// The image to load a texel from. This must have type [`Image`]. (This /// will necessarily be a [`GlobalVariable`] or [`FunctionArgument`] /// expression, since no other expressions are allowed to have that /// type.) /// /// [`Image`]: TypeInner::Image /// [`GlobalVariable`]: Expression::GlobalVariable /// [`FunctionArgument`]: Expression::FunctionArgument
image: Handle<Expression>,
/// The coordinate of the texel we wish to load. This must be a scalar /// for [`D1`] images, a [`Bi`] vector for [`D2`] images, and a [`Tri`] /// vector for [`D3`] images. (Array indices, sample indices, and /// explicit level-of-detail values are supplied separately.) Its /// component type must be [`Sint`]. /// /// [`D1`]: ImageDimension::D1 /// [`D2`]: ImageDimension::D2 /// [`D3`]: ImageDimension::D3 /// [`Bi`]: VectorSize::Bi /// [`Tri`]: VectorSize::Tri /// [`Sint`]: ScalarKind::Sint
coordinate: Handle<Expression>,
/// The index into an arrayed image. If the [`arrayed`] flag in /// `image`'s type is `true`, then this must be `Some(expr)`, where /// `expr` is a [`Sint`] scalar. Otherwise, it must be `None`. /// /// [`arrayed`]: TypeInner::Image::arrayed /// [`Sint`]: ScalarKind::Sint
array_index: Option<Handle<Expression>>,
/// A sample index, for multisampled [`Sampled`] and [`Depth`] images. /// /// [`Sampled`]: ImageClass::Sampled /// [`Depth`]: ImageClass::Depth
sample: Option<Handle<Expression>>,
/// A level of detail, for mipmapped images. /// /// This must be present when accessing non-multisampled /// [`Sampled`] and [`Depth`] images, even if only the /// full-resolution level is present (in which case the only /// valid level is zero). /// /// [`Sampled`]: ImageClass::Sampled /// [`Depth`]: ImageClass::Depth
level: Option<Handle<Expression>>,
},
/// Query information from an image.
ImageQuery {
image: Handle<Expression>,
query: ImageQuery,
}, /// Apply an unary operator.
Unary {
op: UnaryOperator,
expr: Handle<Expression>,
}, /// Apply a binary operator.
Binary {
op: BinaryOperator,
left: Handle<Expression>,
right: Handle<Expression>,
}, /// Select between two values based on a condition. /// /// Note that, because expressions have no side effects, it is unobservable /// whether the non-selected branch is evaluated.
Select { /// Boolean expression
condition: Handle<Expression>,
accept: Handle<Expression>,
reject: Handle<Expression>,
}, /// Compute the derivative on an axis.
Derivative {
axis: DerivativeAxis,
ctrl: DerivativeControl,
expr: Handle<Expression>,
}, /// Call a relational function.
Relational {
fun: RelationalFunction,
argument: Handle<Expression>,
}, /// Call a math function
Math {
fun: MathFunction,
arg: Handle<Expression>,
arg1: Option<Handle<Expression>>,
arg2: Option<Handle<Expression>>,
arg3: Option<Handle<Expression>>,
}, /// Cast a simple type to another kind. As { /// Source expression, which can only be a scalar or a vector.
expr: Handle<Expression>, /// Target scalar kind.
kind: ScalarKind, /// If provided, converts to the specified byte width. /// Otherwise, bitcast.
convert: Option<Bytes>,
}, /// Result of calling another function.
CallResult(Handle<Function>),
/// Result of an atomic operation. /// /// This expression must be referred to by the [`result`] field of exactly one /// [`Atomic`][stmt] statement somewhere in the same function. Let `T` be the /// scalar type contained by the [`Atomic`][type] value that the statement /// operates on. /// /// If `comparison` is `false`, then `ty` must be the scalar type `T`. /// /// If `comparison` is `true`, then `ty` must be a [`Struct`] with two members: /// /// - A member named `old_value`, whose type is `T`, and /// /// - A member named `exchanged`, of type [`BOOL`]. /// /// [`result`]: Statement::Atomic::result /// [stmt]: Statement::Atomic /// [type]: TypeInner::Atomic /// [`Struct`]: TypeInner::Struct /// [`BOOL`]: Scalar::BOOL
AtomicResult { ty: Handle<Type>, comparison: bool },
/// Result of a [`WorkGroupUniformLoad`] statement. /// /// [`WorkGroupUniformLoad`]: Statement::WorkGroupUniformLoad
WorkGroupUniformLoadResult { /// The type of the result
ty: Handle<Type>,
}, /// Get the length of an array. /// The expression must resolve to a pointer to an array with a dynamic size. /// /// This doesn't match the semantics of spirv's `OpArrayLength`, which must be passed /// a pointer to a structure containing a runtime array in its' last field.
ArrayLength(Handle<Expression>),
/// Result of a [`Proceed`] [`RayQuery`] statement. /// /// [`Proceed`]: RayQueryFunction::Proceed /// [`RayQuery`]: Statement::RayQuery
RayQueryProceedResult,
/// Return an intersection found by `query`. /// /// If `committed` is true, return the committed result available when
RayQueryGetIntersection {
query: Handle<Expression>,
committed: bool,
}, /// Result of a [`SubgroupBallot`] statement. /// /// [`SubgroupBallot`]: Statement::SubgroupBallot
SubgroupBallotResult, /// Result of a [`SubgroupCollectiveOperation`] or [`SubgroupGather`] statement. /// /// [`SubgroupCollectiveOperation`]: Statement::SubgroupCollectiveOperation /// [`SubgroupGather`]: Statement::SubgroupGather
SubgroupOperationResult { ty: Handle<Type> },
}
pubuse block::Block;
/// The value of the switch case. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum SwitchValue {
I32(i32),
U32(u32),
Default,
}
/// A case for a switch statement. // Clone is used only for error reporting and is not intended for end users #[derive(Clone, Debug)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct SwitchCase { /// Value, upon which the case is considered true. pub value: SwitchValue, /// Body of the case. pub body: Block, /// If true, the control flow continues to the next case in the list, /// or default. pub fall_through: bool,
}
/// An operation that a [`RayQuery` statement] applies to its [`query`] operand. /// /// [`RayQuery` statement]: Statement::RayQuery /// [`query`]: Statement::RayQuery::query #[derive(Clone, Debug)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum RayQueryFunction { /// Initialize the `RayQuery` object.
Initialize { /// The acceleration structure within which this query should search for hits. /// /// The expression must be an [`AccelerationStructure`]. /// /// [`AccelerationStructure`]: TypeInner::AccelerationStructure
acceleration_structure: Handle<Expression>,
#[allow(rustdoc::private_intra_doc_links)] /// A struct of detailed parameters for the ray query. /// /// This expression should have the struct type given in /// [`SpecialTypes::ray_desc`]. This is available in the WGSL /// front end as the `RayDesc` type.
descriptor: Handle<Expression>,
},
/// Start or continue the query given by the statement's [`query`] operand. /// /// After executing this statement, the `result` expression is a /// [`Bool`] scalar indicating whether there are more intersection /// candidates to consider. /// /// [`query`]: Statement::RayQuery::query /// [`Bool`]: ScalarKind::Bool
Proceed {
result: Handle<Expression>,
},
Terminate,
}
//TODO: consider removing `Clone`. It's not valid to clone `Statement::Emit` anyway. /// Instructions which make up an executable block. /// /// `Handle<Expression>` and `Range<Expression>` values in `Statement` variants /// refer to expressions in [`Function::expressions`], unless otherwise noted. // Clone is used only for error reporting and is not intended for end users #[derive(Clone, Debug)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum Statement { /// Emit a range of expressions, visible to all statements that follow in this block. /// /// See the [module-level documentation][emit] for details. /// /// [emit]: index.html#expression-evaluation-time
Emit(Range<Expression>), /// A block containing more statements, to be executed sequentially.
Block(Block), /// Conditionally executes one of two blocks, based on the value of the condition. /// /// Naga IR does not have "phi" instructions. If you need to use /// values computed in an `accept` or `reject` block after the `If`, /// store them in a [`LocalVariable`]. If {
condition: Handle<Expression>, //bool
accept: Block,
reject: Block,
}, /// Conditionally executes one of multiple blocks, based on the value of the selector. /// /// Each case must have a distinct [`value`], exactly one of which must be /// [`Default`]. The `Default` may appear at any position, and covers all /// values not explicitly appearing in other cases. A `Default` appearing in /// the midst of the list of cases does not shadow the cases that follow. /// /// Some backend languages don't support fallthrough (HLSL due to FXC, /// WGSL), and may translate fallthrough cases in the IR by duplicating /// code. However, all backend languages do support cases selected by /// multiple values, like `case 1: case 2: case 3: { ... }`. This is /// represented in the IR as a series of fallthrough cases with empty /// bodies, except for the last. /// /// Naga IR does not have "phi" instructions. If you need to use /// values computed in a [`SwitchCase::body`] block after the `Switch`, /// store them in a [`LocalVariable`]. /// /// [`value`]: SwitchCase::value /// [`body`]: SwitchCase::body /// [`Default`]: SwitchValue::Default
Switch {
selector: Handle<Expression>,
cases: Vec<SwitchCase>,
},
/// Executes a block repeatedly. /// /// Each iteration of the loop executes the `body` block, followed by the /// `continuing` block. /// /// Executing a [`Break`], [`Return`] or [`Kill`] statement exits the loop. /// /// A [`Continue`] statement in `body` jumps to the `continuing` block. The /// `continuing` block is meant to be used to represent structures like the /// third expression of a C-style `for` loop head, to which `continue` /// statements in the loop's body jump. /// /// The `continuing` block and its substatements must not contain `Return` /// or `Kill` statements, or any `Break` or `Continue` statements targeting /// this loop. (It may have `Break` and `Continue` statements targeting /// loops or switches nested within the `continuing` block.) Expressions /// emitted in `body` are in scope in `continuing`. /// /// If present, `break_if` is an expression which is evaluated after the /// continuing block. Expressions emitted in `body` or `continuing` are /// considered to be in scope. If the expression's value is true, control /// continues after the `Loop` statement, rather than branching back to the /// top of body as usual. The `break_if` expression corresponds to a "break /// if" statement in WGSL, or a loop whose back edge is an /// `OpBranchConditional` instruction in SPIR-V. /// /// Naga IR does not have "phi" instructions. If you need to use /// values computed in a `body` or `continuing` block after the /// `Loop`, store them in a [`LocalVariable`]. /// /// [`Break`]: Statement::Break /// [`Continue`]: Statement::Continue /// [`Kill`]: Statement::Kill /// [`Return`]: Statement::Return /// [`break if`]: Self::Loop::break_if Loop {
body: Block,
continuing: Block,
break_if: Option<Handle<Expression>>,
},
/// Exits the innermost enclosing [`Loop`] or [`Switch`]. /// /// A `Break` statement may only appear within a [`Loop`] or [`Switch`] /// statement. It may not break out of a [`Loop`] from within the loop's /// `continuing` block. /// /// [`Loop`]: Statement::Loop /// [`Switch`]: Statement::Switch Break,
/// Skips to the `continuing` block of the innermost enclosing [`Loop`]. /// /// A `Continue` statement may only appear within the `body` block of the /// innermost enclosing [`Loop`] statement. It must not appear within that /// loop's `continuing` block. /// /// [`Loop`]: Statement::Loop Continue,
/// Returns from the function (possibly with a value). /// /// `Return` statements are forbidden within the `continuing` block of a /// [`Loop`] statement. /// /// [`Loop`]: Statement::Loop Return { value: Option<Handle<Expression>> },
/// Aborts the current shader execution. /// /// `Kill` statements are forbidden within the `continuing` block of a /// [`Loop`] statement. /// /// [`Loop`]: Statement::Loop
Kill,
/// Synchronize invocations within the work group. /// The `Barrier` flags control which memory accesses should be synchronized. /// If empty, this becomes purely an execution barrier.
Barrier(Barrier), /// Stores a value at an address. /// /// For [`TypeInner::Atomic`] type behind the pointer, the value /// has to be a corresponding scalar. /// For other types behind the `pointer<T>`, the value is `T`. /// /// This statement is a barrier for any operations on the /// `Expression::LocalVariable` or `Expression::GlobalVariable` /// that is the destination of an access chain, started /// from the `pointer`.
Store {
pointer: Handle<Expression>,
value: Handle<Expression>,
}, /// Stores a texel value to an image. /// /// The `image`, `coordinate`, and `array_index` fields have the same /// meanings as the corresponding operands of an [`ImageLoad`] expression; /// see that documentation for details. Storing into multisampled images or /// images with mipmaps is not supported, so there are no `level` or /// `sample` operands. /// /// This statement is a barrier for any operations on the corresponding /// [`Expression::GlobalVariable`] for this image. /// /// [`ImageLoad`]: Expression::ImageLoad
ImageStore {
image: Handle<Expression>,
coordinate: Handle<Expression>,
array_index: Option<Handle<Expression>>,
value: Handle<Expression>,
}, /// Atomic function.
Atomic { /// Pointer to an atomic value. /// /// This must be a [`Pointer`] to an [`Atomic`] value. The atomic's /// scalar type may be [`I32`] or [`U32`]. /// /// If [`SHADER_INT64_ATOMIC_MIN_MAX`] or [`SHADER_INT64_ATOMIC_ALL_OPS`] are /// enabled, this may also be [`I64`] or [`U64`]. /// /// If [`SHADER_FLOAT32_ATOMIC`] is enabled, this may be [`F32`]. /// /// [`Pointer`]: TypeInner::Pointer /// [`Atomic`]: TypeInner::Atomic /// [`I32`]: Scalar::I32 /// [`U32`]: Scalar::U32 /// [`SHADER_INT64_ATOMIC_MIN_MAX`]: crate::valid::Capabilities::SHADER_INT64_ATOMIC_MIN_MAX /// [`SHADER_INT64_ATOMIC_ALL_OPS`]: crate::valid::Capabilities::SHADER_INT64_ATOMIC_ALL_OPS /// [`SHADER_FLOAT32_ATOMIC`]: crate::valid::Capabilities::SHADER_FLOAT32_ATOMIC /// [`I64`]: Scalar::I64 /// [`U64`]: Scalar::U64 /// [`F32`]: Scalar::F32
pointer: Handle<Expression>,
/// Function to run on the atomic value. /// /// If [`pointer`] refers to a 64-bit atomic value, then: /// /// - The [`SHADER_INT64_ATOMIC_ALL_OPS`] capability allows any [`AtomicFunction`] /// value here. /// /// - The [`SHADER_INT64_ATOMIC_MIN_MAX`] capability allows /// [`AtomicFunction::Min`] and [`AtomicFunction::Max`] /// in the [`Storage`] address space here. /// /// - If neither of those capabilities are present, then 64-bit scalar /// atomics are not allowed. /// /// If [`pointer`] refers to a 32-bit floating-point atomic value, then: /// /// - The [`SHADER_FLOAT32_ATOMIC`] capability allows [`AtomicFunction::Add`], /// [`AtomicFunction::Subtract`], and [`AtomicFunction::Exchange { compare: None }`] /// in the [`Storage`] address space here. /// /// [`AtomicFunction::Exchange { compare: None }`]: AtomicFunction::Exchange /// [`pointer`]: Statement::Atomic::pointer /// [`Storage`]: AddressSpace::Storage /// [`SHADER_INT64_ATOMIC_MIN_MAX`]: crate::valid::Capabilities::SHADER_INT64_ATOMIC_MIN_MAX /// [`SHADER_INT64_ATOMIC_ALL_OPS`]: crate::valid::Capabilities::SHADER_INT64_ATOMIC_ALL_OPS /// [`SHADER_FLOAT32_ATOMIC`]: crate::valid::Capabilities::SHADER_FLOAT32_ATOMIC
fun: AtomicFunction,
/// Value to use in the function. /// /// This must be a scalar of the same type as [`pointer`]'s atomic's scalar type. /// /// [`pointer`]: Statement::Atomic::pointer
value: Handle<Expression>,
/// [`AtomicResult`] expression representing this function's result. /// /// If [`fun`] is [`Exchange { compare: None }`], this must be `Some`, /// as otherwise that operation would be equivalent to a simple [`Store`] /// to the atomic. /// /// Otherwise, this may be `None` if the return value of the operation is not needed. /// /// If `pointer` refers to a 64-bit atomic value, [`SHADER_INT64_ATOMIC_MIN_MAX`] /// is enabled, and [`SHADER_INT64_ATOMIC_ALL_OPS`] is not, this must be `None`. /// /// [`AtomicResult`]: crate::Expression::AtomicResult /// [`fun`]: Statement::Atomic::fun /// [`Store`]: Statement::Store /// [`Exchange { compare: None }`]: AtomicFunction::Exchange /// [`SHADER_INT64_ATOMIC_MIN_MAX`]: crate::valid::Capabilities::SHADER_INT64_ATOMIC_MIN_MAX /// [`SHADER_INT64_ATOMIC_ALL_OPS`]: crate::valid::Capabilities::SHADER_INT64_ATOMIC_ALL_OPS
result: Option<Handle<Expression>>,
}, /// Performs an atomic operation on a texel value of an image. /// /// Doing atomics on images with mipmaps is not supported, so there is no /// `level` operand.
ImageAtomic { /// The image to perform an atomic operation on. This must have type /// [`Image`]. (This will necessarily be a [`GlobalVariable`] or /// [`FunctionArgument`] expression, since no other expressions are /// allowed to have that type.) /// /// [`Image`]: TypeInner::Image /// [`GlobalVariable`]: Expression::GlobalVariable /// [`FunctionArgument`]: Expression::FunctionArgument
image: Handle<Expression>,
/// The coordinate of the texel we wish to load. This must be a scalar /// for [`D1`] images, a [`Bi`] vector for [`D2`] images, and a [`Tri`] /// vector for [`D3`] images. (Array indices, sample indices, and /// explicit level-of-detail values are supplied separately.) Its /// component type must be [`Sint`]. /// /// [`D1`]: ImageDimension::D1 /// [`D2`]: ImageDimension::D2 /// [`D3`]: ImageDimension::D3 /// [`Bi`]: VectorSize::Bi /// [`Tri`]: VectorSize::Tri /// [`Sint`]: ScalarKind::Sint
coordinate: Handle<Expression>,
/// The index into an arrayed image. If the [`arrayed`] flag in /// `image`'s type is `true`, then this must be `Some(expr)`, where /// `expr` is a [`Sint`] scalar. Otherwise, it must be `None`. /// /// [`arrayed`]: TypeInner::Image::arrayed /// [`Sint`]: ScalarKind::Sint
array_index: Option<Handle<Expression>>,
/// The kind of atomic operation to perform on the texel.
fun: AtomicFunction,
/// The value with which to perform the atomic operation.
value: Handle<Expression>,
}, /// Load uniformly from a uniform pointer in the workgroup address space. /// /// Corresponds to the [`workgroupUniformLoad`](https://www.w3.org/TR/WGSL/#workgroupUniformLoad-builtin) /// built-in function of wgsl, and has the same barrier semantics
WorkGroupUniformLoad { /// This must be of type [`Pointer`] in the [`WorkGroup`] address space /// /// [`Pointer`]: TypeInner::Pointer /// [`WorkGroup`]: AddressSpace::WorkGroup
pointer: Handle<Expression>, /// The [`WorkGroupUniformLoadResult`] expression representing this load's result. /// /// [`WorkGroupUniformLoadResult`]: Expression::WorkGroupUniformLoadResult
result: Handle<Expression>,
}, /// Calls a function. /// /// If the `result` is `Some`, the corresponding expression has to be /// `Expression::CallResult`, and this statement serves as a barrier for any /// operations on that expression.
Call {
function: Handle<Function>,
arguments: Vec<Handle<Expression>>,
result: Option<Handle<Expression>>,
},
RayQuery { /// The [`RayQuery`] object this statement operates on. /// /// [`RayQuery`]: TypeInner::RayQuery
query: Handle<Expression>,
/// The specific operation we're performing on `query`.
fun: RayQueryFunction,
}, /// Calculate a bitmask using a boolean from each active thread in the subgroup
SubgroupBallot { /// The [`SubgroupBallotResult`] expression representing this load's result. /// /// [`SubgroupBallotResult`]: Expression::SubgroupBallotResult
result: Handle<Expression>, /// The value from this thread to store in the ballot
predicate: Option<Handle<Expression>>,
}, /// Gather a value from another active thread in the subgroup
SubgroupGather { /// Specifies which thread to gather from
mode: GatherMode, /// The value to broadcast over
argument: Handle<Expression>, /// The [`SubgroupOperationResult`] expression representing this load's result. /// /// [`SubgroupOperationResult`]: Expression::SubgroupOperationResult
result: Handle<Expression>,
}, /// Compute a collective operation across all active threads in the subgroup
SubgroupCollectiveOperation { /// What operation to compute
op: SubgroupOperation, /// How to combine the results
collective_op: CollectiveOperation, /// The value to compute over
argument: Handle<Expression>, /// The [`SubgroupOperationResult`] expression representing this load's result. /// /// [`SubgroupOperationResult`]: Expression::SubgroupOperationResult
result: Handle<Expression>,
},
}
/// A function argument. #[derive(Clone, Debug)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct FunctionArgument { /// Name of the argument, if any. pub name: Option<String>, /// Type of the argument. pub ty: Handle<Type>, /// For entry points, an argument has to have a binding /// unless it's a structure. pub binding: Option<Binding>,
}
/// A function result. #[derive(Clone, Debug)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct FunctionResult { /// Type of the result. pub ty: Handle<Type>, /// For entry points, the result has to have a binding /// unless it's a structure. pub binding: Option<Binding>,
}
/// A function defined in the module. #[derive(Debug, Default, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct Function { /// Name of the function, if any. pub name: Option<String>, /// Information about function argument. pub arguments: Vec<FunctionArgument>, /// The result of this function, if any. pub result: Option<FunctionResult>, /// Local variables defined and used in the function. pub local_variables: Arena<LocalVariable>, /// Expressions used inside this function. /// /// If an [`Expression`] is in this arena, then its subexpressions are in this /// arena too. In other words, every `Handle<Expression>` in this arena /// refers to an [`Expression`] in this arena too. The only way this arena /// can refer to [`Module::global_expressions`] is indirectly, via /// [`Constant`] and [`Override`] expressions, which hold handles for their /// respective types. /// /// An [`Expression`] must occur before all other [`Expression`]s that use /// its value. /// /// [`Constant`]: Expression::Constant /// [`Override`]: Expression::Override pub expressions: Arena<Expression>, /// Map of expressions that have associated variable names pub named_expressions: NamedExpressions, /// Block of instructions comprising the body of the function. pub body: Block, /// The leaf of all diagnostic filter rules tree (stored in [`Module::diagnostic_filters`]) /// parsed on this function. /// /// In WGSL, this corresponds to `@diagnostic(…)` attributes. /// /// See [`DiagnosticFilterNode`] for details on how the tree is represented and used in /// validation. pub diagnostic_filter_leaf: Option<Handle<DiagnosticFilterNode>>,
}
/// The main function for a pipeline stage. /// /// An [`EntryPoint`] is a [`Function`] that serves as the main function for a /// graphics or compute pipeline stage. For example, an `EntryPoint` whose /// [`stage`] is [`ShaderStage::Vertex`] can serve as a graphics pipeline's /// vertex shader. /// /// Since an entry point is called directly by the graphics or compute pipeline, /// not by other WGSL functions, you must specify what the pipeline should pass /// as the entry point's arguments, and what values it will return. For example, /// a vertex shader needs a vertex's attributes as its arguments, but if it's /// used for instanced draw calls, it will also want to know the instance id. /// The vertex shader's return value will usually include an output vertex /// position, and possibly other attributes to be interpolated and passed along /// to a fragment shader. /// /// To specify this, the arguments and result of an `EntryPoint`'s [`function`] /// must each have a [`Binding`], or be structs whose members all have /// `Binding`s. This associates every value passed to or returned from the entry /// point with either a [`BuiltIn`] or a [`Location`]: /// /// - A [`BuiltIn`] has special semantics, usually specific to its pipeline /// stage. For example, the result of a vertex shader can include a /// [`BuiltIn::Position`] value, which determines the position of a vertex /// of a rendered primitive. Or, a compute shader might take an argument /// whose binding is [`BuiltIn::WorkGroupSize`], through which the compute /// pipeline would pass the number of invocations in your workgroup. /// /// - A [`Location`] indicates user-defined IO to be passed from one pipeline /// stage to the next. For example, a vertex shader might also produce a /// `uv` texture location as a user-defined IO value. /// /// In other words, the pipeline stage's input and output interface are /// determined by the bindings of the arguments and result of the `EntryPoint`'s /// [`function`]. /// /// [`Function`]: crate::Function /// [`Location`]: Binding::Location /// [`function`]: EntryPoint::function /// [`stage`]: EntryPoint::stage #[derive(Debug, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct EntryPoint { /// Name of this entry point, visible externally. /// /// Entry point names for a given `stage` must be distinct within a module. pub name: String, /// Shader stage. pub stage: ShaderStage, /// Early depth test for fragment stages. pub early_depth_test: Option<EarlyDepthTest>, /// Workgroup size for compute stages pub workgroup_size: [u32; 3], /// Override expressions for workgroup size in the global_expressions arena pub workgroup_size_overrides: Option<[Option<Handle<Expression>>; 3]>, /// The entrance function. pub function: Function,
}
/// Return types predeclared for the frexp, modf, and atomicCompareExchangeWeak built-in functions. /// /// These cannot be spelled in WGSL source. /// /// Stored in [`SpecialTypes::predeclared_types`] and created by [`Module::generate_predeclared_type`]. #[derive(Debug, PartialEq, Eq, Hash, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubenum PredeclaredType {
AtomicCompareExchangeWeakResult(Scalar),
ModfResult {
size: Option<VectorSize>,
scalar: Scalar,
},
FrexpResult {
size: Option<VectorSize>,
scalar: Scalar,
},
}
/// Set of special types that can be optionally generated by the frontends. #[derive(Debug, Default, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct SpecialTypes { /// Type for `RayDesc`. /// /// Call [`Module::generate_ray_desc_type`] to populate this if /// needed and return the handle. pub ray_desc: Option<Handle<Type>>,
/// Type for `RayIntersection`. /// /// Call [`Module::generate_ray_intersection_type`] to populate /// this if needed and return the handle. pub ray_intersection: Option<Handle<Type>>,
/// Types for predeclared wgsl types instantiated on demand. /// /// Call [`Module::generate_predeclared_type`] to populate this if /// needed and return the handle. pub predeclared_types: FastIndexMap<PredeclaredType, Handle<Type>>,
}
bitflags::bitflags! { /// Ray flags used when casting rays. /// Matching vulkan constants can be found in /// https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/KHR/ray_common/ray_flags_section.txt #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pubstruct RayFlag: u32 { /// Force all intersections to be treated as opaque. const FORCE_OPAQUE = 0x1; /// Force all intersections to be treated as non-opaque. const FORCE_NO_OPAQUE = 0x2; /// Stop traversal after the first hit. const TERMINATE_ON_FIRST_HIT = 0x4; /// Don't execute the closest hit shader. const SKIP_CLOSEST_HIT_SHADER = 0x8; /// Cull back facing geometry. const CULL_BACK_FACING = 0x10; /// Cull front facing geometry. const CULL_FRONT_FACING = 0x20; /// Cull opaque geometry. const CULL_OPAQUE = 0x40; /// Cull non-opaque geometry. const CULL_NO_OPAQUE = 0x80; /// Skip triangular geometry. const SKIP_TRIANGLES = 0x100; /// Skip axis-aligned bounding boxes. const SKIP_AABBS = 0x200;
}
}
/// Type of a ray query intersection. /// Matching vulkan constants can be found in /// <https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/KHR/SPV_KHR_ray_query.asciidoc> /// but the actual values are different for candidate intersections. #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pubenum RayQueryIntersection { /// No intersection found. /// Matches `RayQueryCommittedIntersectionNoneKHR`. #[default]
None = 0, /// Intersecting with triangles. /// Matches `RayQueryCommittedIntersectionTriangleKHR` and `RayQueryCandidateIntersectionTriangleKHR`.
Triangle = 1, /// Intersecting with generated primitives. /// Matches `RayQueryCommittedIntersectionGeneratedKHR`.
Generated = 2, /// Intersecting with Axis Aligned Bounding Boxes. /// Matches `RayQueryCandidateIntersectionAABBKHR`.
Aabb = 3,
}
/// Shader module. /// /// A module is a set of constants, global variables and functions, as well as /// the types required to define them. /// /// Some functions are marked as entry points, to be used in a certain shader stage. /// /// To create a new module, use the `Default` implementation. /// Alternatively, you can load an existing shader using one of the [available front ends][front]. /// /// When finished, you can export modules using one of the [available backends][back]. #[derive(Debug, Default, Clone)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pubstruct Module { /// Arena for the types defined in this module. pub types: UniqueArena<Type>, /// Dictionary of special type handles. pub special_types: SpecialTypes, /// Arena for the constants defined in this module. pub constants: Arena<Constant>, /// Arena for the pipeline-overridable constants defined in this module. pub overrides: Arena<Override>, /// Arena for the global variables defined in this module. pub global_variables: Arena<GlobalVariable>, /// [Constant expressions] and [override expressions] used by this module. /// /// If an expression is in this arena, then its subexpressions are in this /// arena too. In other words, every `Handle<Expression>` in this arena /// refers to an [`Expression`] in this arena too. /// /// Each `Expression` must occur in the arena before any /// `Expression` that uses its value. /// /// [Constant expressions]: index.html#constant-expressions /// [override expressions]: index.html#override-expressions pub global_expressions: Arena<Expression>, /// Arena for the functions defined in this module. /// /// Each function must appear in this arena strictly before all its callers. /// Recursion is not supported. pub functions: Arena<Function>, /// Entry points. pub entry_points: Vec<EntryPoint>, /// Arena for all diagnostic filter rules parsed in this module, including those in functions /// and statements. /// /// This arena contains elements of a _tree_ of diagnostic filter rules. When nodes are built /// by a front-end, they refer to a parent scope pub diagnostic_filters: Arena<DiagnosticFilterNode>, /// The leaf of all diagnostic filter rules tree parsed from directives in this module. /// /// In WGSL, this corresponds to `diagnostic(…);` directives. /// /// See [`DiagnosticFilterNode`] for details on how the tree is represented and used in /// validation. pub diagnostic_filter_leaf: Option<Handle<DiagnosticFilterNode>>,
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.50 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.