Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
e5068dd
Tracking referentiality
iwoplaza Sep 26, 2025
c5189be
More progress on the implementation
iwoplaza Sep 27, 2025
eb8f520
Mostly works now
iwoplaza Sep 27, 2025
5312d1d
Track ref address space
iwoplaza Sep 27, 2025
52124a7
Enforcing copy when assigning
iwoplaza Sep 27, 2025
07ed411
JS const with ref value is WGSL let with pointer
iwoplaza Sep 27, 2025
ba2a4ff
Fix ptr return types, and invalid ref and deref op order
iwoplaza Sep 27, 2025
7b7e5dc
Const statements
iwoplaza Sep 27, 2025
9a75b1e
Not allowing references to be returned from a function (unless it's a
iwoplaza Sep 27, 2025
5dc3884
Move member access exceptions to `accessProp` so that it's shared with
iwoplaza Sep 27, 2025
755d13b
Better indexing
iwoplaza Sep 27, 2025
ec2657f
Indexing arrays at comptime
iwoplaza Sep 27, 2025
8497a35
Constant tracking
iwoplaza Sep 27, 2025
cc349ff
Infix
iwoplaza Sep 27, 2025
77ac0cc
Apply formatting
iwoplaza Sep 27, 2025
04fa183
Merge branch 'main' into feat/ref-value
iwoplaza Oct 7, 2025
aee85a6
A few tweaks
iwoplaza Oct 7, 2025
5173502
Update wgslGenerator.ts
iwoplaza Oct 7, 2025
c3bf598
Fixes
iwoplaza Oct 7, 2025
40b3f7a
Self review
iwoplaza Oct 7, 2025
7c5900b
Update accessor.ts
iwoplaza Oct 7, 2025
50741ce
More tweaks
iwoplaza Oct 7, 2025
4dff99e
Merge branch 'main' into feat/ref-value
iwoplaza Oct 7, 2025
51c2919
Apply suggestion from @aleksanderkatan
iwoplaza Oct 8, 2025
b035d45
Apply suggestion from @aleksanderkatan
iwoplaza Oct 8, 2025
3932b2f
Update stable-fluid.test.ts
iwoplaza Oct 9, 2025
62936f8
Simplify 3D Fish compute
iwoplaza Oct 9, 2025
14c7282
Update compute.ts
iwoplaza Oct 9, 2025
e90832d
Review fixes
iwoplaza Oct 9, 2025
549bc71
Merge branch 'main' into feat/ref-value
iwoplaza Oct 10, 2025
e3b3bba
Merge branch 'main' into feat/ref-value
iwoplaza Oct 13, 2025
1e2df56
Updates after changing 'kernel' to 'use gpu'
iwoplaza Oct 13, 2025
bbc0508
feat: Better constant handling for ref/value tracking (#1801)
iwoplaza Oct 16, 2025
1f8392e
Merge branch 'main' into feat/ref-value
iwoplaza Oct 30, 2025
3824a3a
Update snapshots
iwoplaza Oct 30, 2025
b4f2c0b
Rename ref to origin
iwoplaza Oct 31, 2025
beb2295
Explicit refs
iwoplaza Nov 1, 2025
808deef
Merge branch 'main' into feat/ref-value
iwoplaza Nov 3, 2025
109dbe9
Implicit function pointers don't cause shell-less functions to generate
iwoplaza Nov 3, 2025
0fdadf5
Using std.neg when resolving unary `-` operator, and emitting `let` when
iwoplaza Nov 3, 2025
04fb153
Fix Disco example
iwoplaza Nov 3, 2025
2a6527e
🦕
iwoplaza Nov 3, 2025
59f2618
Updating gravity example
iwoplaza Nov 3, 2025
f85150b
More updates
iwoplaza Nov 3, 2025
05270d0
Update gravity.test.ts
iwoplaza Nov 3, 2025
66b89cf
Fixed!
iwoplaza Nov 3, 2025
2ed5955
Update Gravity code
iwoplaza Nov 3, 2025
4ccdd96
Working on umiform refs
iwoplaza Nov 4, 2025
dbcd394
Merge branch 'main' into feat/ref-value
iwoplaza Nov 4, 2025
07ee6b7
Writing internal docs about shader generation
iwoplaza Nov 4, 2025
79252cb
More useful refs
iwoplaza Nov 4, 2025
c853f5c
Simplify and document
iwoplaza Nov 4, 2025
21776b3
Test for updating a whole struct, returning refs
iwoplaza Nov 4, 2025
b1fe352
Updates
iwoplaza Nov 4, 2025
5805cac
Simplify implicit pointer dereferencing
iwoplaza Nov 5, 2025
37914d5
Merge branch 'main' into feat/ref-value
iwoplaza Nov 6, 2025
685479d
More tests and restrictions
iwoplaza Nov 6, 2025
171af79
More test coverage for argument origin tracking
iwoplaza Nov 6, 2025
c6b0537
Update shader-generation.mdx
iwoplaza Nov 6, 2025
b3e979e
Update shader-generation.mdx
iwoplaza Nov 6, 2025
e0b5cc7
🦕
iwoplaza Nov 6, 2025
39b5704
Merge branch 'main' into feat/ref-value
iwoplaza Nov 6, 2025
c31bb13
Better handling of arguments
iwoplaza Nov 6, 2025
6003bc3
Update pointers.ts
iwoplaza Nov 6, 2025
74d1291
Fix for referencing implicit pointers
iwoplaza Nov 7, 2025
5466542
feat: Inspect vector type in shader function
iwoplaza Nov 6, 2025
305f49e
Better
iwoplaza Nov 6, 2025
44c351b
Tweaks
iwoplaza Nov 6, 2025
0db2fb4
Merge branch 'main' into feat/comptime-vector-type-predicate
iwoplaza Dec 6, 2025
7f28896
Fixes
iwoplaza Dec 7, 2025
4375e8d
Update generationHelpers.ts
iwoplaza Dec 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
More tests and restrictions
  • Loading branch information
iwoplaza committed Nov 6, 2025
commit 685479d9a56ae5b771e8e40b8914042fc90e7e44
3 changes: 0 additions & 3 deletions packages/typegpu/src/core/variable/tgpuVariable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import type { InferGPU } from '../../shared/repr.ts';
import {
$gpuValueOf,
$internal,
$isRef,
$ownSnippet,
$resolve,
} from '../../shared/symbols.ts';
Expand Down Expand Up @@ -78,7 +77,6 @@ export function isVariable<T extends TgpuVar>(
class TgpuVarImpl<TScope extends VariableScope, TDataType extends AnyData>
implements TgpuVar<TScope, TDataType>, SelfResolvable {
readonly [$internal] = {};
readonly [$isRef]: true;
readonly #scope: TScope;
readonly #dataType: TDataType;
readonly #initialValue: InferGPU<TDataType> | undefined;
Expand All @@ -88,7 +86,6 @@ class TgpuVarImpl<TScope extends VariableScope, TDataType extends AnyData>
dataType: TDataType,
initialValue?: InferGPU<TDataType> | undefined,
) {
this[$isRef] = true;
this.#scope = scope;
this.#dataType = dataType;
this.#initialValue = initialValue;
Expand Down
23 changes: 16 additions & 7 deletions packages/typegpu/src/data/ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { stitch } from '../core/resolve/stitch.ts';
import { invariant } from '../errors.ts';
import { inCodegenMode } from '../execMode.ts';
import { setName } from '../shared/meta.ts';
import { $internal, $isRef, $ownSnippet, $resolve } from '../shared/symbols.ts';
import { $internal, $ownSnippet, $resolve } from '../shared/symbols.ts';
import type { ResolutionCtx, SelfResolvable } from '../types.ts';
import { UnknownData } from './dataTypes.ts';
import type { DualFn } from './dualFn.ts';
Expand All @@ -19,9 +19,15 @@ import {
// Public API
// ----------

/**
* A reference to a value `T`. Can be passed to other functions to give them
* mutable access to the underlying value.
*
* Conceptually, it represents a WGSL pointer.
*/
export interface ref<T> {
readonly [$internal]: unknown;
readonly [$isRef]: true;
readonly type: 'ref';

/**
* Derefences the reference, and gives access to the underlying value.
Expand All @@ -38,7 +44,6 @@ export interface ref<T> {
$: T;
}

// TODO: Restrict calls to this function only from within TypeGPU functions
export const ref: DualFn<<T>(value: T) => ref<T>> = (() => {
const gpuImpl = (value: Snippet) => {
/**
Expand Down Expand Up @@ -84,19 +89,23 @@ export const ref: DualFn<<T>(value: T) => ref<T>> = (() => {
return impl as unknown as DualFn<<T>(value: T) => ref<T>>;
})();

export function isRef<T>(value: unknown | ref<T>): value is ref<T> {
return value instanceof refImpl;
}

// --------------
// Implementation
// --------------

class refImpl<T> implements ref<T> {
#value: T;
readonly [$internal]: true;
readonly [$isRef]: true;
readonly type: 'ref';
#value: T;

constructor(value: T) {
this.#value = value;
this[$internal] = true;
this[$isRef] = true;
this.type = 'ref';
this.#value = value;
}

get $(): T {
Expand Down
10 changes: 0 additions & 10 deletions packages/typegpu/src/shared/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,6 @@ export const $invalidSchemaReason = Symbol(
`typegpu:${version}:$invalidSchemaReason`,
);

/**
* A symbol that identifies objects that act as references
* (values returned from d.ref(), buffer usages, ...)
*/
export const $isRef = Symbol(`typegpu:${version}:$isRef`);

export function isRef(value: unknown): value is { [$isRef]: true } {
return !!(value as { [$isRef]: true })?.[$isRef];
}

export function isMarkedInternal(
value: unknown,
): value is { [$internal]: Record<string, unknown> | true } {
Expand Down
3 changes: 1 addition & 2 deletions packages/typegpu/src/std/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import { dualImpl } from '../core/function/dualImpl.ts';
import { stitch } from '../core/resolve/stitch.ts';
import { abstractInt, u32 } from '../data/numeric.ts';
import { ptrFn } from '../data/ptr.ts';
import type { ref } from '../data/ref.ts';
import { isRef, type ref } from '../data/ref.ts';
import { isPtr, isWgslArray, type StorableData } from '../data/wgslTypes.ts';
import { isRef } from '../shared/symbols.ts';

const sizeOfPointedToArray = (dataType: unknown) =>
isPtr(dataType) && isWgslArray(dataType.inner)
Expand Down
6 changes: 5 additions & 1 deletion packages/typegpu/src/tgsl/generationHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ import type { ShelllessRepository } from './shellless.ts';
import { add, div, mul, sub } from '../std/operators.ts';
import { $internal } from '../shared/symbols.ts';
import { stitch } from '../core/resolve/stitch.ts';
import { derefSnippet } from '../data/ref.ts';
import { derefSnippet, isRef } from '../data/ref.ts';

type SwizzleableType = 'f' | 'h' | 'i' | 'u' | 'b';
type SwizzleLength = 1 | 2 | 3 | 4;
Expand Down Expand Up @@ -428,6 +428,10 @@ export function coerceToSnippet(value: unknown): Snippet {
return value;
}

if (isRef(value)) {
throw new Error('Cannot use refs (d.ref(...)) from the outer scope.');
}

// Maybe the value can tell us what snippet it is
const ownSnippet = getOwnSnippet(value);
if (ownSnippet) {
Expand Down
16 changes: 14 additions & 2 deletions packages/typegpu/tests/ref.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,20 @@ import { it } from './utils/extendedIt.ts';
import { asWgsl } from './utils/parseResolved.ts';

describe('ref', () => {
it.skip('fails when created outside of a TypeGPU function', () => {
expect(() => d.ref(0)).toThrowErrorMatchingInlineSnapshot();
it('fails when using a ref as an external', () => {
const sup = d.ref(0);

const foo = () => {
'use gpu';
sup.$ += 1;
};

expect(() => asWgsl(foo)).toThrowErrorMatchingInlineSnapshot(`
[Error: Resolution of the following tree failed:
- <root>
- fn*:foo
- fn*:foo(): Cannot use refs (d.ref(...)) from the outer scope.]
`);
});

it('creates a regular looking variable in WGSL', () => {
Expand Down
26 changes: 26 additions & 0 deletions packages/typegpu/tests/tgsl/shellless.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,32 @@ describe('shellless', () => {
`);
});

it('generates private pointer params when passing a private variable ref to a function', ({ root }) => {
const foo = tgpu.privateVar(d.vec3f);

const sumComponents = (vec: d.ref<d.v3f>) => {
'use gpu';
return vec.$.x + vec.$.y + vec.$.z;
};

const main = () => {
'use gpu';
sumComponents(d.ref(foo.$));
};

expect(asWgsl(main)).toMatchInlineSnapshot(`
"fn sumComponents(vec: ptr<private, vec3f>) -> f32 {
return (((*vec).x + (*vec).y) + (*vec).z);
}

var<private> foo: vec3f;

fn main() {
sumComponents((&foo));
}"
`);
});

it('generates uniform pointer params when passing a fixed uniform ref to a function', ({ root }) => {
const posUniform = root.createUniform(d.vec3f);

Expand Down
Loading