Skip to content

Commit c31bb13

Browse files
committed
Better handling of arguments
1 parent 39b5704 commit c31bb13

File tree

8 files changed

+261
-191
lines changed

8 files changed

+261
-191
lines changed

packages/typegpu-sdf/src/2d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ export const sdBezierApprox = tgpu.fn(
153153
});
154154

155155
export const sdPie = tgpu.fn([vec2f, vec2f, f32], f32)((p, c, r) => {
156-
const p_w = p;
156+
const p_w = vec2f(p);
157157
p_w.x = abs(p.x);
158158
const l = length(p_w) - r;
159159
const m = length(p_w.sub(c.mul(clamp(dot(p_w, c), 0, r))));

packages/typegpu/src/data/ref.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { stitch } from '../core/resolve/stitch.ts';
2-
import { invariant } from '../errors.ts';
2+
import { invariant, WgslTypeError } from '../errors.ts';
33
import { inCodegenMode } from '../execMode.ts';
44
import { setName } from '../shared/meta.ts';
55
import { $internal, $ownSnippet, $resolve } from '../shared/symbols.ts';
@@ -46,6 +46,12 @@ export interface ref<T> {
4646

4747
export const ref: DualFn<<T>(value: T) => ref<T>> = (() => {
4848
const gpuImpl = (value: Snippet) => {
49+
if (value.origin === 'argument') {
50+
throw new WgslTypeError(
51+
stitch`d.ref(${value}) is illegal, cannot take a reference of an argument. Copy the value locally first, and take a reference of the copy.`,
52+
);
53+
}
54+
4955
/**
5056
* Pointer type only exists if the ref was created from a reference (buttery-butter).
5157
*
@@ -161,10 +167,7 @@ export function derefSnippet(snippet: Snippet): Snippet {
161167
invariant(isPtr(snippet.dataType), 'Only pointers can be dereferenced');
162168

163169
const innerType = snippet.dataType.inner;
164-
const origin =
165-
isNaturallyEphemeral(innerType) && snippet.origin !== 'argument'
166-
? 'runtime'
167-
: snippet.origin;
170+
const origin = isNaturallyEphemeral(innerType) ? 'runtime' : snippet.origin;
168171

169172
if (snippet.value instanceof RefOperator) {
170173
return snip(stitch`${snippet.value.snippet}`, innerType, origin);

packages/typegpu/src/tgsl/wgslGenerator.ts

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,26 @@ ${this.ctx.pre}}`;
717717
);
718718
}
719719

720+
// Arguments cannot be returned from functions without copying. A simple example why is:
721+
// const identity = (x) => {
722+
// 'use gpu';
723+
// return x;
724+
// };
725+
//
726+
// const foo = (arg: d.v3f) => {
727+
// 'use gpu';
728+
// const marg = identity(arg);
729+
// marg.x = 1; // 'marg's origin would be 'runtime', so we wouldn't be able to track this misuse.
730+
// };
731+
if (
732+
returnSnippet.origin === 'argument' &&
733+
!isEphemeralSnippet(returnSnippet)
734+
) {
735+
throw new WgslTypeError(
736+
stitch`Cannot return references to arguments, returning '${returnSnippet}'. Copy the argument before returning it.`,
737+
);
738+
}
739+
720740
if (
721741
!expectedReturnType &&
722742
!isEphemeralSnippet(returnSnippet) &&
@@ -794,6 +814,10 @@ ${this.ctx.pre}else ${alternate}`;
794814
);
795815
}
796816

817+
const ephemeral = isEphemeralSnippet(eq);
818+
let dataType = eq.dataType as wgsl.AnyWgslData;
819+
const naturallyEphemeral = wgsl.isNaturallyEphemeral(dataType);
820+
797821
if (isLooseData(eq.dataType)) {
798822
throw new Error(
799823
`Cannot create variable '${rawId}' with loose data type.`,
@@ -821,14 +845,9 @@ ${this.ctx.pre}else ${alternate}`;
821845
};`;
822846
}
823847

824-
let dataType = eq.dataType as wgsl.AnyWgslData;
825-
826848
// Assigning a reference to a `const` variable means we store the pointer
827849
// of the rhs.
828-
if (
829-
!isEphemeralSnippet(eq) ||
830-
(eq.origin === 'argument' && !wgsl.isNaturallyEphemeral(dataType))
831-
) {
850+
if (!ephemeral) {
832851
// Referential
833852
if (stmtType === NODE.let) {
834853
const rhsStr = this.ctx.resolve(eq.value).value;
@@ -866,11 +885,32 @@ ${this.ctx.pre}else ${alternate}`;
866885
}
867886
} else {
868887
// Non-referential
869-
if (
870-
stmtType === NODE.const &&
871-
wgsl.isNaturallyEphemeral(dataType)
872-
) {
873-
varType = eq.origin === 'constant' ? 'const' : 'let';
888+
889+
if (eq.origin === 'argument') {
890+
if (stmtType === NODE.let) {
891+
const rhsStr = this.ctx.resolve(eq.value).value;
892+
const rhsTypeStr =
893+
this.ctx.resolve(toStorable(eq.dataType as wgsl.StorableData))
894+
.value;
895+
896+
throw new WgslTypeError(
897+
`'let ${rawId} = ${rhsStr}' is invalid, because references to arguments cannot be assigned to 'let' variable declarations.
898+
-----
899+
- Try 'let ${rawId} = ${rhsTypeStr}(${rhsStr})' if you need to reassign '${rawId}' later
900+
- Try 'const ${rawId} = ${rhsStr}' if you won't reassign '${rawId}' later.
901+
-----`,
902+
);
903+
}
904+
varType = 'let';
905+
}
906+
907+
if (stmtType === NODE.const) {
908+
if (eq.origin === 'argument') {
909+
// Arguments cannot be mutated, so we 'let' them be (kill me)
910+
varType = 'let';
911+
} else if (naturallyEphemeral) {
912+
varType = eq.origin === 'constant' ? 'const' : 'let';
913+
}
874914
}
875915
}
876916

packages/typegpu/tests/examples/individual/gravity.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,9 @@ describe('gravity example', () => {
270270
var lightColor = vec3f(1, 0.8999999761581421, 0.8999999761581421);
271271
var textureColor = textureSample(celestialBodyTextures_9, sampler_10, input.uv, input.sphereTextureIndex).xyz;
272272
var ambient = ((textureColor * lightColor) * input.ambientLightFactor);
273-
let normal = (&input.normals);
273+
let normal = input.normals;
274274
var lightDirection = normalize((lightSource_11 - input.worldPosition));
275-
let cosTheta = dot((*normal), lightDirection);
275+
let cosTheta = dot(normal, lightDirection);
276276
var diffuse = ((textureColor * lightColor) * max(0f, cosTheta));
277277
var litColor = (ambient + diffuse);
278278
return vec4f(litColor.xyz, 1f);

0 commit comments

Comments
 (0)