Creating and Using Pointers
To work with pointers, WGSL provides two fundamental operators: the Address-of (&) operator to create a pointer, and the Dereference (*) operator to read or write the memory it references.
1. Creating Pointers: The Address-of (&) Operator
You can get a pointer to a variable (or part of a variable) by applying the & operator:
- Whole Variables: If
xis a variable, then&xis a pointer referring to all the memory allocated forx. - Sub-components / Composites: You can also take the address of a specific sub-member inside a structure or an array:
- If
chairis a custom struct with a memberlegs(an array of 4 values), then taking&chair.legs[3]returns a pointer pointing strictly to the last index of that sub-array.
2. Using Pointers: The Dereference (*) Operator
To access or modify the memory a pointer points to, you must apply the * operator to turn the pointer back into an active memory Reference.
In the WGSL type system:
phas typeptr<AS, T>.*phas typeref<AS, T>(a Reference).
What happens to *p depends entirely on where it appears in your code:
-
Writing to Memory (L-Value): If
*pappears on the left-hand side of an assignment, a write occurs. -
Reading from Memory (R-Value): If
*pappears anywhere else, the pointer is dereferenced and the value is read out.
Interactive Pointer-Stack Memory Visualizer
This page features an interactive Pointer-Stack Memory Visualizer (visible in the right-hand panel on desktop, or integrated below on mobile). Click the navigation dots or directly select lines inside the code card to trace how GPU stack frames allocate variables, resolve address-of (&) bindings, and execute dereference (*) reads and writes step-by-step in real-time.
Visualizing Pointer Memory Tracing
The diagram below shows how a pointer px resides in the thread stack frame as a compile-time alias pointing to the storage cell of variable x:
px = &x stores the address of x. Dereferencing *px directly reads or writes to x's storage.
Playpen Exercise
In the accompanying shader code playground, we declare a global variable age in the private address space.
Our helper function happy_birthday() takes a pointer age_ptr to the age variable, reads the value out, increments it, and writes the incremented value back to memory.
Click Run to compile and execute the shader, observing the updated age value!
/*
* Copyright ©2026 Michael R. Bernstein. All new modifications licensed under Apache 2.0.
* Upstream lineage ©2023 governed by original BSD 3-Clause. See README.md.
*/
fn f() {
var x: f32 = 1.5;
let px = &x; // Get a pointer to x
*px = 3.0; // Update x through px.
// Now x is 3.0
}
var<private> age: f32;
fn happy_birthday() {
let age_ptr = &age; // Get a pointer.
*age_ptr = *age_ptr + 1; // Updates 'age'
}
fn run_main() {
age = 18.0;
happy_birthday();
// Now age is 19.0
}
fn run_test_age() -> f32 {
run_main();
return age;
}