### Example using hypothetical extensions Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Example showing the enable directive for hypothetical f16 and rounding_mode_f16 extensions, including a redundant enable directive and an attribute enabled by the extension. ```wgsl // Enable a hypothetical IEEE binary16 floating point extension. enable f16; // Assuming the f16 extension enables use of the f16 type: // - as function return value // - as the type for let declaration // - as a type constructor, with an i32 argument // - as operands to the division operator: / fn halve_it(x: f16) -> f16 { let two: f16 = f16(2); return x / two; }; enable f16; // A redundant enable directive is ok. // Enable a hypothetical extension adding syntax for controlling // the rounding mode on f16 arithmetic. enable rounding_mode_f16; [[round_to_even_f16]] // Attribute enabled by the rounding_mode_f16 extension fn triple_it(x: f16) -> f16 { return x * f16(3); // Uses round-to-even. }; ``` -------------------------------- ### WGSL simple functions example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Example of a user-defined function 'add_two' with two parameters and a return type, and a compute shader entry point 'main' that calls it. ```wgsl // Declare the add_two function. // It has two formal paramters, i and b. // It has a return type of i32. // It has a body with a return statement. fn add_two(i: i32, b: f32) -> i32 { return i + 2; // A formal parameter is available for use in the body. } // A compute shader entry point function, 'main'. // It has no specified return type. // It invokes the ordinary_two function, and captures // the resulting value in the named value 'two'. [[stage(compute)]] fn main() { let six: i32 = add_two(4, 5.0); } ``` -------------------------------- ### WGSL vector access example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows how to access vector components using convenience names and array subscripting. Demonstrates that swizzles can be reordered and duplicated, and that array indexing starts at zero. ```wgsl var a: vec3 = vec3(1., 2., 3.); var b: f32 = a.y; // b = 2.0 var c: vec2 = a.bb; // c = (3.0, 3.0) var d: vec3 = a.zyx; // d = (3.0, 2.0, 1.0) var e: f32 = a[1]; // e = 2.0 ``` -------------------------------- ### For to Loop Transformation Example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows a for loop and its equivalent loop statement transformation. The for loop initializer runs once, the condition is checked at the start of each iteration, and the continuing statement runs at the end of the body. ```wgsl for(var i: i32 = 0; i < 4; i = i + 1) { if (a == 0) { continue; } a = a + 2; } ``` ```wgsl { // Introduce new scope for loop variable i var i: i32 = 0; var a: i32 = 0; loop { if (!(i < 4)) { break; } if (a == 0) { continue; } a = a + 2; continuing { i = i + 1; } } } ``` -------------------------------- ### Pointer Type Example with Comments Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Illustrates pointer type declarations in WGSL source, showing the fully parameterized form in comments. The example includes pointers to i32 and array in different storage classes, with implied read_write access mode. ```wgsl fn my_function( // 'ptr' is the type of a pointer value that references // storage for keeping an 'i32' value, using memory locations in the 'function' // storage class. Here 'i32' is the pointee type. // The implied access mode is 'read_write'. See below for access mode defaults. ptr_int: ptr, // 'ptr,read_write>' is the type of a pointer value that // refers to storage for keeping an array of 50 elements of type 'f32', using // memory locations in the 'private' storage class. // Here the pointee type is 'array'. // The implied access mode is 'read_write'. See below for access mode defaults. ptr_array: ptr> ) { } ``` -------------------------------- ### Zero-valued arrays example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows how to create a zero-valued array using the type followed by empty parentheses, and the equivalent explicit constructor with zero elements. ```wgsl array() // The zero-valued array of two booleans. array(false, false) // The same value, written explicitly. ``` -------------------------------- ### Variable decorations example in WGSL Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows how group and binding attributes map to SPIR-V decorations DescriptorSet and Binding. The example uses group(4) and binding(3). ```wgsl [[group(4), binding(3)]] OpDecorate %variable DescriptorSet 4 OpDecorate %variable Binding 3 ``` -------------------------------- ### Component-wise addition example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Illustrates component-wise addition of two vec3 vectors, with comments showing each component result. ```wgsl let x : vec3 = a + b; // a and b are vec3 // x[0] = a[0] + b[0] // x[1] = a[1] + b[1] // x[2] = a[2] + b[2] ``` -------------------------------- ### Zero-valued vectors example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows how to create zero-valued vectors using the type followed by empty parentheses, and the equivalent explicit constructor with zero elements. ```wgsl vec2() // The zero-valued vector of two f32 elements. vec2(0.0, 0.0) // The same value, written explicitly. vec3() // The zero-valued vector of three i32 elements. vec3(0, 0, 0) // The same value, written explicitly. ``` -------------------------------- ### WGSL Loop with continue Example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 The equivalent WGSL loop using continue to skip even iterations. ```wgsl var a: i32 = 2; var i: i32 = 0; loop { if (i >= 4) { break; } let step: i32 = 1; i = i + 1; if (i % 2 == 0) { continue; } a = a * 2; } ``` -------------------------------- ### Type Declarations Example with SPIR-V Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Examples of WGSL type declarations and their corresponding SPIR-V instructions, showing how identifiers, scalars, vectors, arrays, and matrices map to SPIR-V types. ```wgsl identifier Allows to specify types created by the type command bool %1 = OpTypeBool f32 %2 = OpTypeFloat 32 i32 %3 = OpTypeInt 32 1 u32 %4 = OpTypeInt 32 0 vec2 %7 = OpTypeVector %float 2 array %uint_4 = OpConstant %uint 4 %9 = OpTypeArray %float %uint_4 [[stride(32)]] array OpDecorate %9 ArrayStride 32 %uint_4 = OpConstant %uint 4 %9 = OpTypeArray %float %uint_4 array %rtarr = OpTypeRuntimeArray %float mat2x3 %vec = OpTypeVector %float 3 %6 = OpTypeMatrix %vec 2 ``` -------------------------------- ### Vector type example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows a vector of two f32 components. ```wgsl vec2 // is a vector of two f32s. ``` -------------------------------- ### SPIR-V examples for constants Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows how WGSL constant expressions map to SPIR-V instructions. Each line pairs a WGSL constant with its corresponding SPIR-V OpConstant or OpConstantComposite instruction. ```spirv -1 %a = OpConstant %int -1 2 %b = OpConstant %uint 2 3.2 %c = OpConstant %float 3.2 true %d = OpConstantTrue false %e = OpConstant False vec4(1.2, 2.3, 3.4, 2.3) %f0 = OpConstant %float 1.2 %f1 = OpConstant %float 2.3 %f2 = OpConstant %float 3.4 %f = OpConstantComposite %v4float %f0 %f1 %f2 %f1 ``` -------------------------------- ### GLSL Loop with continue Example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 A GLSL for loop that uses continue to skip even iterations. ```glsl int a = 2; let int step = 1; for (int i = 0; i < 4; i += step) { if (i % 2 == 0) continue; a *= 2; } ``` -------------------------------- ### Zero-valued structures example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Defines a Student structure and demonstrates three ways to create its zero value: using Student(), explicit zero arguments, and zero-valued members. ```wgsl struct Student { grade: i32; GPA: f32; attendance: array; }; fn func() { var s: Student; // The zero value for Student s = Student(); // The same value, written explicitly. s = Student(0, 0.0, array(false, false, false, false)); // The same value, written with zero-valued members. s = Student(i32(), f32(), array()); } ``` -------------------------------- ### Type Alias Grammar and Example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Grammar rule for type aliases and an example showing two type alias declarations: one for a fixed-size array and one for a runtime-sized array with a stride attribute. ```wgsl type_alias : TYPE IDENT EQUAL type_decl ``` ```wgsl type Arr = array; type RTArr = [[stride(16)]] array>; ``` -------------------------------- ### GLSL Loop Example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 A simple GLSL for loop that doubles a variable four times. ```glsl int a = 2; for (int i = 0; i < 4; i++) { a *= 2; } ``` -------------------------------- ### Assignment examples Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Examples of assignment statements in WGSL, including variable assignment, struct field assignment, vector component assignment, pointer dereference assignment, and copying a struct. ```wgsl struct S { age: i32; weight: f32; }; var person: S; fn f() { var a: i32 = 20; a = 30; // Replace the contents of 'a' with 30. person.age = 31; // Write 31 into the age field of the person variable. var uv: vec2; uv.y = 1.25; // Place 1.25 into the second component of uv. let uv_x_ptr: ptr = &uv.x; *uv_x_ptr = 2.5; // Place 2.5 into the first component of uv. var friend: S; // Copy the contents of the 'person' variable into the 'friend' variable. friend = person; } ``` -------------------------------- ### Matrix type example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows a 2-column, 3-row matrix of 32-bit floats, equivalent to two column vectors of type vec3. ```wgsl mat2x3 // This is a 2 column, 3 row matrix of 32-bit floats. // Equivalently, it is 2 column vectors of type vec3. ``` -------------------------------- ### WGSL Entry Point Example: vertex, fragment, and compute shaders Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows three entry point declarations: a vertex shader returning a builtin position, a fragment shader taking a builtin position and returning a location 0 color, and a compute shader with no return type. Each includes SPIR-V comments showing the expected OpEntryPoint and decorations. ```wgsl [[stage(vertex)]] fn vert_main() -> [[builtin(position)]] vec4 { return vec4(0.0, 0.0, 0.0, 1.0); } // OpEntryPoint Vertex %vert_main "vert_main" %return_value // OpDecorate %return_value BuiltIn Position // %float = OpTypeFloat 32 // %v4float = OpTypeVector %float 4 // %ptr = OpTypePointer Output %v4float // %return_value = OpVariable %ptr Output [[stage(fragment)]] fn frag_main([[builtin(position)]] coord_in: vec4) -> [[location(0)]] vec4 { return vec4(coord_in.x, coord_in.y, 0.0, 1.0); } // OpEntryPoint Fragment %frag_main "frag_main" %return_value %coord_in // OpDecorate %return_value Location 0 // %float = OpTypeFloat 32 // %v4float = OpTypeVector %float 4 // %ptr = OpTypePointer Output %v4float // %return_value = OpVariable %ptr Output [[stage(compute)]] fn comp_main() { } // OpEntryPoint GLCompute %comp_main "comp_main" ``` -------------------------------- ### WGSL structure with runtime array and block attribute Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 WGSL example showing a runtime-sized array with stride attribute and a block-decorated structure containing it. ```WGSL // Runtime Array type RTArr = [[stride(16)]] array>; [[block]] struct S { a: f32; b: f32; data: RTArr; }; ``` -------------------------------- ### WGSL structure layout example with implicit member sizes, alignments, and strides Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows a WGSL struct 'A' with members of types f32 and vec2. The comments indicate the alignment and size of the struct and each member, including implicit padding at the end. This example illustrates the structure layout rules defined in section 4.3.7.2. ```wgsl struct A { // align(8) size(24) u: f32; // offset(0) align(4) size(4) v: f32; // offset(4) align(4) size(4) w: vec2; // offset(8) align(8) size(8) x: f32; // offset(16) align(4) size(4) // -- implicit struct size padding -- // offset(20) size(4) }; ``` -------------------------------- ### Access Modes for Buffers Example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows how to declare storage and uniform buffers with different access modes. Storage buffers default to read-only, while read_write allows both read and write. Uniform buffers are always read-only and have more restrictive layout rules. ```wgsl // Storage buffers [[group(0), binding(0)]] var buf1: Buffer; // Can read, cannot write. [[group(0), binding(0)]] var buf2: Buffer; // Can read, cannot write. [[group(0), binding(1)]] var buf3: Buffer; // Can both read and write. // Uniform buffer. Always read-only, and has more restrictive layout rules. struct ParamsTable {}; [[group(0), binding(2)]] var params: ParamsTable; // Can read, cannot write. ``` -------------------------------- ### Pipeline-overridable constants example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Demonstrates `let` declarations with the `override` attribute. Shows explicit pipeline constant IDs, optional initializers, and the requirement that constants without initializers must be overridden at pipeline creation time. ```wgsl [[override(0)]] let has_point_light: bool = true; // Algorithmic control [[override(1200)]] let specular_param: f32 = 2.3; // Numeric control [[override(1300)]] let gain: f32; // Must be overridden [[override]] let width: f32 = 0.0; // Specifed at the API level using // the name "width". [[override]] let depth: f32; // Specifed at the API level using // the name "depth". // Must be overridden. ``` -------------------------------- ### Mapping workgroupBarrier and storageBarrier to SPIR-V Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Example showing how storageBarrier and workgroupBarrier map to SPIR-V OpControlBarrier instructions, including execution scope, memory scope, and memory semantics. Also shows that consecutive barriers can be combined into a single OpControlBarrier. ```wgsl storageBarrier(); // Maps to: // Execution Scope is Workgroup = %uint_2 // Memory Scope is Device = %uint_1 // Memory Semantics are AcquireRelease | UniformMemory (0x8 | 0x40) = %uint_72 // OpControlBarrier %uint_2 %uint_1 %uint_72 workgroupBarrier(); // Maps to: // Execution and Memory Scope are Workgroup = %uint_2 // Memory semantics are AcquireRelease | WorkgroupMemory (0x8 | 0x100) = %uint_264 // OpControlBarrier %uint_2 %uint_2 %uint_264 workgroupBarrier(); storageBarrier(); // Or, equivalently: storageBarrier(); workgroupBarrier(); // Could be mapped to a single OpControlBarrier: // Execution scope is Workgroup = %uint_2 // Memory Scope is Device = %uint_1 // Memory semantics are AcquireRelease | UniformMemory | WorkgroupMemory // (0x8 | 0x40 | 0x100) = %uint_328 // OpControlBarrier %uint_2 %uint_1 %uint_328 ``` -------------------------------- ### WGSL declaration and scope example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 This example demonstrates valid and invalid WGSL declarations, illustrating scope rules for variables, functions, and parameters. It shows that reusing built-in function names (like 'modf') is invalid, and that declarations with the same end scope are not allowed. The comments in the code indicate the scope of each declared identifier. ```wgsl // Invalid, cannot reuse built-in function names. var modf: f32 = 0.0; // Valid, foo_1 is in scope until the end of the program. var foo: f32 = 0.0; // foo_1 // Valid, bar_1 is in scope until the end of the program. var bar: u32 = 0u; // bar_1 // Valid, my_func_1 is in scope until the end of the program. // Valid, foo_2 is in scope until the end of the function. fn my_func(foo: f32) { // my_func_1, foo_2 // Any reference to 'foo' resolves to the function parameter. // Invalid, the scope of foo_3 ends at the of the function. var foo: f32; // foo_3 // Valid, bar_2 is in scope until the end of the function. var bar: u32; // bar_2 // References to 'bar' resolve to bar_2 { // Valid, bar_3 is in scope until the end of the compound statement. var bar: u32; // bar_3 // References to 'bar' resolve to bar_3 // Invalid, bar_4 has the same end scope as bar_3. var bar: i32; // bar_4 // Valid, i_1 is in scope until the end of the for loop for (var i: i32 = 0; i < 10; i = i + 1) { // i_1 // Invalid, i_2 has the same end scope as i_1. var i: i32 = 1; // i_2. } } // Invalid, bar_5 has the same end scope as bar_2. var bar: u32; // bar_5 } // Invalid, bar_6 has the same end scope as bar_1. var bar: u32 = 1u; // bar_6 // Invalid, my_func_2 has the same end scope as my_func_1. fn my_func() { } // my_func_2 // Valid, my_foo_1 is in scope until the end of the program. fn my_foo( // Valid, my_foo_2 is in scope until the end of the function. my_foo: i32 // my_foo_2 ) { } ``` -------------------------------- ### WGSL Loop Example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 The equivalent WGSL loop using a loop statement with an explicit break condition. ```wgsl let a: i32 = 2; var i: i32 = 0; // <1> loop { if (i >= 4) { break; } a = a * 2; i = i + 1; } ``` -------------------------------- ### WGSL structure with f32 and vec4 members Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Simple WGSL structure example with two members: a f32 and a vec4. ```WGSL struct my_struct { a: f32; b: vec4; }; ``` -------------------------------- ### Sample translation for reading a variable multiple times Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 SPIR-V representation of the previous WGSL example, showing each variable access as an OpLoad and arithmetic operations. ```spirv %temp_1 = OpLoad %float %x %temp_2 = OpLoad %float %x %temp_3 = OpFMul %float %temp_1 %temp_2 %temp_4 = OpLoad %float %x %temp_5 = OpFAdd %float %temp_3 %temp_4 %y = OpFAdd %float %temp_5 %one ``` -------------------------------- ### Module constants example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows two module-scope `let` declarations: one with explicit type `f32` and one with inferred type `vec3`. The initializer is required when no attributes are present. ```wgsl // The golden ratio. let golden: f32 = 1.61803398875; // The second unit vector for three dimensions, with inferred type. let e2 = vec3(0,1,0); ``` -------------------------------- ### WGSL Loop with continue and continuing Example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 A WGSL loop that uses a continuing construct to update the loop variable. ```wgsl var a: i32 = 2; var i: i32 = 0; loop { if (i >= 4) { break; } let step: i32 = 1; if (i % 2 == 0) { continue; } a = a * 2; continuing { // <2> i = i + step; } } ``` -------------------------------- ### Component reference from a composite reference Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows how to form references to components of composite types (vector, matrix, array, structure) and how the access mode is preserved. The example includes a struct definition, a private variable, and a function with assignments and a let declaration, illustrating the type rules for reference expressions. ```wgsl struct S { age: i32; weight: f32; }; var person: S; // Uses of 'person' denote the reference to the storage underlying the variable, // and will have type ref. fn f() { var uv: vec2; // Uses of 'uv' denote the reference to the storage underlying the variable, // and will have type ref,read_write>. // Evaluate the left-hand side of the assignment: // Evaluate 'uv.x' to yield a reference: // 1. First evaluate 'uv', yielding a reference to the storage for // the 'uv' variable. The result has type ref,read_write>. // 2. Then apply the '.x' vector access phrase, yielding a reference to // the storage for the first component of the vector pointed at by the // reference value from the previous step. // The result has type ref. // Evaluating the right-hand side of the assignment yields the f32 value 1.0. // Store the f32 value 1.0 into the storage memory locations referenced by uv.x. uv.x = 1.0; // Evaluate the left-hand side of the assignment: // Evaluate 'uv[1]' to yield a reference: // 1. First evaluate 'uv', yielding a reference to the storage for // the 'uv' variable. The result has type ref,read_write>. // 2. Then apply the '[1]' array index phrase, yielding a reference to // the storage for second component of the vector referenced from // the previous step. The result has type ref. // Evaluating the right-hand side of the assignment yields the f32 value 2.0. // Store the f32 value 2.0 into the storage memory locations referenced by uv[1]. uv[1] = 2.0; var m: mat3x2; // When evaluating 'm[2]': // 1. First evaluate 'm', yielding a reference to the storage for // the 'm' variable. The result has type ref,read_write>. // 2. Then apply the '[2]' array index phrase, yielding a reference to // the storage for the third column vector pointed at by the reference // value from the previous step. // Therefore the 'm[2]' expression has type ref,read_write>. // The 'let' declaration is for type vec2, so the declaration // statement requires the initializer to be of type vec2. // The Load Rule applies (because no other type rule can apply), and // the evaluation of the initializer yields the vec2 value loaded // from the memory locations referenced by 'm[2]' at the time the declaration // is executed. let p_m_col2: vec2 = m[2]; } ``` -------------------------------- ### Discard Statement Example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Example of using the discard statement in a fragment shader to terminate the invocation and prevent the fragment from being processed downstream. The helper function discards if the position is too shallow, and the main function sets a flag and emits red only if the discard was not executed. ```wgsl var will_emit_color: bool = false; fn discard_if_shallow(pos: vec4) { if (pos.z < 0.001) { // If this is executed, then the will_emit_color flag will // never be set to true. discard; } will_emit_color = true; } [[stage(fragment)]] fn main([[builtin(position)]] coord_in: vec4) -> [[location(0)]] vec4 { discard_if_shallow(coord_in); // Set the flag and emit red, but only if the helper function // did not execute the discard statement. will_emit_color = true; return vec4(1.0, 0.0, 0.0, 1.0); } ``` -------------------------------- ### Function scope variables and constants example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows declarations of function-scope variables and constants in WGSL, including explicit storage class, optional storage decoration, initializers, type inference, and let-declared constants without storage class. ```wgsl fn f() { var count: u32; // A variable in function storage class. var delta: i32; // Another variable in the function storage class. var sum: f32 = 0.0; // A function storage class variable with initializer. var pi = 3.14159; // Infer the f32 store type from the initializer. let unit: i32 = 1; // Let-declared constants don’t use a storage class. } ``` -------------------------------- ### WGSL structure declaration with two members Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Basic WGSL structure example with two members: an i32 and a vec2. Shows the syntax with semicolons after each member. ```WGSL // A structure with two members. struct Data { a: i32; b: vec2; }; ``` -------------------------------- ### Reference types enable simple use of variables Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Example WGSL compute shader showing how reference types allow idiomatic variable usage. The variable 'i' has reference type ref. The load rule automatically dereferences 'i' in expressions like 'i + 1', and assignments update the memory locations. The example demonstrates reading, adding, and assigning values, with the right-hand side evaluated before assignment. ```wgsl [[stage(compute)]] fn main() { // 'i' has reference type ref // The memory locations for 'i' store the i32 value 0. var i: i32 = 0; // 'i + 1' can only match a type rule where the 'i' subexpression is of type i32. // So the expression 'i + 1' has type i32, and at evaluation, the 'i' subexpression // evaluates to the i32 value stored in the memory locations for 'i' at the time // of evaluation. let one: i32 = i + 1; // Update the value in the locations referenced by 'i' so they hold the value 2. i = one + 1; // Update the value in the locations referenced by 'i' so they hold the value 5. // The evaluation of the right-hand-side occurs before the assignment takes effect. i = i + 3; } ``` -------------------------------- ### Pointer from a Variable: Using Unary '&' Operator Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Demonstrates how to create pointers from variables in different storage classes using the unary '&' operator. The access mode defaults to read_write for function storage class, and the example shows how the name 'x' can be shadowed in a function scope. ```wgsl // Declare a variable in the private storage class, for storing an f32 value. var x: f32; fn f() { // Declare a variable in the function storage class, for storing an i32 value. var y: i32; // The name 'x' resolves to the module-scope variable 'x', // and has reference type ref. // Applying the unary '&' operator converts the reference to a pointer. // The access mode is the same as the access mode of the original variable, so // the fully specified type is ptr. But read_write // is the default access mode for function storage class, so read_write does not // have to be spelled in this case let x_ptr: ptr = &x; // The name 'y' resolves to the function-scope variable 'y', // and has reference type ref. // Applying the unary '&' operator converts the reference to a pointer. // The access mode defaults to 'read_write'. let y_ptr: ptr = &y; // A new variable, distinct from the variable declared at module scope. var x: u32; // Here, the name 'x' resolves to the function-scope variable 'x' declared in // the previous statement, and has type ref. // Applying the unary '&' operator converts the reference to a pointer. // The acces mode defaults to 'read_write'. let inner_x_ptr: ptr = &x; } ``` -------------------------------- ### Using a pointer as a short name for part of a variable Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Demonstrates forming a pointer to a specific element of a storage buffer using the address-of operator '&'. The example defines a 'Particle' struct, a 'System' struct with an array of particles, and a compute shader that uses a pointer to access and modify a particle's position. ```wgsl struct Particle { position: vec3; velocity: vec3; }; [[block]] struct System { active_index: i32; timestep: f32; particles: array; }; [[group(0), binding(0)]] var system: System; [[stage(compute)]] fn main() { // Form a pointer to a specific Particle in storage memory. let active_particle: ptr = &system.particles[system.active_index]; let delta_position: vec3 = (*active_particle).velocity * system.timestep; let current_position: vec3 = (*active_particle).position; (*active_particle).position = delta_position + current_position; } ``` -------------------------------- ### Returning a reference returns the value loaded via the reference Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows that returning a reference from a function returns the loaded value, not the reference itself. The example defines a private variable 'age', a function 'get_age' that returns 'age', and a caller that sets 'age' to 21 and copies the result. The comments explain the load rule applied when returning a reference. ```wgsl var age: i32; fn get_age() -> i32 { // The type of the expression in the return statement must be 'i32' since it // must match the declared return type of the function. // The 'age' expression is of type ref. // Apply the Load Rule, since the store type of the reference matches the // required type of the expression, and no other type rule applies. // The evaluation of 'age' in this context is the i32 value loaded from the // memory locations referenced by 'age' at the time the return statement is // executed. return age; } fn caller() { age = 21; // The copy_age constant will get the i32 value 21. let copy_age: i32 = get_age(); } ``` -------------------------------- ### WGSL workgroup_size Attribute Example Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Demonstrates the workgroup_size attribute on compute shaders, including explicit dimensions, a single dimension with defaults, a pipeline-overridable constant, and an error case where workgroup_size is missing. SPIR-V comments show the expected LocalSize execution modes. ```wgsl [[ stage(compute), workgroup_size(8,4,1) ]] fn sorter() { } // OpEntryPoint GLCompute %sorter "sorter" // OpExecutionMode %sorter LocalSize 8 4 1 [[ stage(compute), workgroup_size(8u) ]] fn reverser() { } // OpEntryPoint GLCompute %reverser "reverser" // OpExecutionMode %reverser LocalSize 8 1 1 // Using an pipeline-overridable constant. [[override(42)]] let block_width = 12u; [[ stage(compute), workgroup_size(block_width) ]] fn shuffler() { } // The SPIR-V translation uses a WorkgroupSize-decorated constant, // where the first component is an OpSpecConstant decorated with // SpecID 42, and with default value 12, and second and third components // use defaulted values of 1. // Error: workgroup_size must be specified on compute shader [[ stage(compute) ]] fn bad_shader() { } ``` -------------------------------- ### step Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Returns 0.0 if the first argument is less than the second, otherwise 1.0. ```APIDOC ## step ### Description Returns 0.0 if e1 is less than e2, and 1.0 otherwise. Component-wise when T is a vector. ### Signature `step(e1: T, e2: T) -> T` ### Parameters - **e1** (T) - The edge. - **e2** (T) - The value to test. ### Preconditions - T is f32 or vecN ### Returns - **T** - 0.0 or 1.0. ``` -------------------------------- ### Continue Statement Grammar Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Grammar for the continue_statement production. A continue statement transfers control in the nearest-enclosing loop statement, either forward to the continuing statement or backward to the start of the next iteration. ```wgsl continue_statement : CONTINUE ``` -------------------------------- ### Mixing builtins and user-defined IO Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows structures that mix builtin variables (front_facing, frag_depth) with user-defined location attributes, and a fragment shader that uses them as input and output. ```wgsl // Mixed builtins and user-defined inputs. struct MyInputs { [[location(0)]] x: vec4; [[builtin(front_facing)]] y: bool; [[location(1)]] z: u32; }; struct MyOutputs { [[builtin(frag_depth)]] x: f32; [[location(0)]] y: vec4; }; [[stage(fragment)]] fn fragShader(in1: MyInputs) -> MyOutputs { // ... } ``` -------------------------------- ### WGSL built-in variables with SPIR-V decorations Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Declares vertex, fragment, and compute shader entry points using WGSL built-in variables, with SPIR-V decoration comments for each. Shows how built-in variables map to SPIR-V decorations like Position, VertexIndex, FragDepth, and LocalInvocationId. ```wgsl struct VertexOutput { [[builtin(position)]] my_pos: vec4; // OpDecorate %my_pos BuiltIn Position // %float = OpTypeFloat 32 // %v4float = OpTypeVector %float 4 // %ptr = OpTypePointer Output %v4float // %my_pos = OpVariable %ptr Output }; [[stage(vertex)]] fn vs_main( [[builtin(vertex_index)]] my_index: u32, // OpDecorate %my_index BuiltIn VertexIndex // %uint = OpTypeInt 32 0 // %ptr = OpTypePointer Input %uint // %my_index = OpVariable %ptr Input [[builtin(instance_index)]] my_inst_index: u32, // OpDecorate %my_inst_index BuiltIn InstanceIndex ) -> VertexOutput; struct FragmentOutput { [[builtin(frag_depth)]] depth: f32; // OpDecorate %depth BuiltIn FragDepth [[builtin(sample_mask)]] mask_out: u32; // OpDecorate %mask_out BuiltIn SampleMask ; an output variable }; [[stage(fragment)]] fn fs_main( [[builtin(front_facing)]] is_front: bool, // OpDecorate %is_front BuiltIn FrontFacing [[builtin(position)]] coord: vec4, // OpDecorate %coord BuiltIn FragCoord [[builtin(sample_index)]] my_sample_index: u32, // OpDecorate %my_sample_index BuiltIn SampleId [[builtin(sample_mask_in)]] mask_in: u32, // OpDecorate %mask_in BuiltIn SampleMask ; an input variable // OpDecorate %mask_in Flat ) -> FragmentOutput; [[stage(compute)]] fn cs_main( [[builtin(local_invocation_id)]] local_id: vec3, // OpDecorate %local_id BuiltIn LocalInvocationId [[builtin(local_invocation_index)]] local_index: u32, // OpDecorate %local_index BuiltIn LocalInvocationIndex [[builtin(global_invocation_id)]] global_id: vec3, // OpDecorate %global_id BuiltIn GlobalInvocationId ); ``` -------------------------------- ### WGSL structure layout with explicit size and align decorations Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows a [[block]] structure using explicit [[size(16)]] and [[align(16)]] decorations on members, and an explicit [[stride(32)]] on an array. The comments annotate offsets, alignments, and sizes, demonstrating how explicit decorations override default layout rules for a uniform buffer. ```wgsl struct A { // align(8) size(32) u: f32; // offset(0) align(4) size(4) v: f32; // offset(4) align(4) size(4) w: vec2; // offset(8) align(8) size(8) [[size(16)]] x: f32; // offset(16) align(4) size(16) }; [[block]] struct B { // align(16) size(208) a: vec2; // offset(0) align(8) size(8) // -- implicit member alignment padding -- // offset(8) size(8) b: vec3; // offset(16) align(16) size(12) c: f32; // offset(28) align(4) size(4) d: f32; // offset(32) align(4) size(4) // -- implicit member alignment padding -- // offset(36) size(12) [[align(16)]] e: A; // offset(48) align(16) size(32) f: vec3; // offset(80) align(16) size(12) // -- implicit member alignment padding -- // offset(92) size(4) g: [[stride(32)]] array; // offset(96) align(8) size(96) h: i32; // offset(192) align(4) size(4) // -- implicit struct size padding -- // offset(196) size(12) }; [[group(0), binding(0)]] var uniform_buffer: B; ``` -------------------------------- ### Variable initial values Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows a var without initializer (initialized to zero) and a var with initializer re-evaluated each loop iteration. The loop executes five times, with i taking values 0-5 and twice taking 0,2,4,6,8. ```wgsl var i: i32; // Initial value is 0. Not recommended style. loop { var twice: i32 = 2 * i; // Re-evaluated each iteration. i = i + 1; if (i == 5) { break; } } ``` -------------------------------- ### smoothStep Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Performs smooth Hermite interpolation between 0 and 1. ```APIDOC ## smoothStep ### Description Returns the smooth Hermite interpolation between 0 and 1. Component-wise when T is a vector. ### Signature `smoothStep(e1: T, e2: T, e3: T) -> T` ### Parameters - **e1** (T) - The lower edge. - **e2** (T) - The upper edge. - **e3** (T) - The value to interpolate. ### Preconditions - T is f32 or vecN ### Returns - **T** - The interpolated value. ``` -------------------------------- ### WGSL structure equivalent of a three-element array Source: https://www.w3.org/TR/2021/WD-WGSL-20210713 Shows the layout equivalence for a [[stride(S)]] array type as a structure with three members, each decorated with [[size(S)]]. This illustrates how array elements are laid out with the given stride. ```wgsl struct Array { [[size(S)]] element_0: T; [[size(S)]] element_1: T; [[size(S)]] element_2: T; }; ```