typegpu 0.11.4 → 0.11.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,4 @@
1
- import { invariant } from "./errors.js";
2
-
3
- //#region src/nameRegistry.ts
1
+ //#region src/nameUtils.ts
4
2
  const bannedTokens = new Set([
5
3
  "alias",
6
4
  "break",
@@ -344,106 +342,64 @@ const builtins = new Set([
344
342
  "quadSwapX",
345
343
  "quadSwapY"
346
344
  ]);
345
+ /* @__NO_SIDE_EFFECTS__ */
347
346
  function sanitizePrimer(primer) {
348
- if (primer) return primer.replaceAll(/\s/g, "_").replaceAll(/[^\w\d]/g, "");
347
+ if (primer) {
348
+ const base = primer.replaceAll(/\s/g, "_").replaceAll(/[^\w\d]/g, "");
349
+ if (base === "_" || base === "" || base.startsWith("__")) return "item";
350
+ return base;
351
+ }
349
352
  return "item";
350
353
  }
351
354
  /**
352
355
  * A function for checking whether an identifier needs renaming.
353
356
  * Throws if provided with an invalid identifier that cannot be easily renamed.
354
357
  * @example
355
- * isValidIdentifier("ident"); // true
356
- * isValidIdentifier("struct"); // false
357
- * isValidIdentifier("struct_1"); // false
358
- * isValidIdentifier("_"); // ERROR
359
- * isValidIdentifier("my variable"); // ERROR
358
+ * validateIdentifier("ident"); // { success: true }
359
+ * validateIdentifier("struct"); // { success: false, error: "Identifiers cannot start with reserved keywords." }
360
+ * validateIdentifier("struct_1"); { success: false, error: "Identifiers cannot start with reserved keywords." }
361
+ * validateIdentifier("_"); // { success: false }
362
+ * validateIdentifier("my variable"); // { success: false, error: "Identifiers cannot contain whitespace." }
360
363
  */
361
- function isValidIdentifier(ident) {
362
- if (ident === "_" || ident.startsWith("__") || /\s/.test(ident)) throw new Error(`Invalid identifier '${ident}'. Choose an identifier without whitespaces or leading underscores.`);
364
+ /* @__NO_SIDE_EFFECTS__ */
365
+ function validateIdentifier(ident) {
366
+ if (ident === "_") return { success: false };
367
+ if (/\s/.test(ident)) return {
368
+ success: false,
369
+ error: `Identifiers cannot contain whitespace.`
370
+ };
371
+ if (ident.startsWith("__")) return {
372
+ success: false,
373
+ error: `Identifiers cannot start with double underscores.`
374
+ };
363
375
  const prefix = ident.split("_")[0];
364
- return !bannedTokens.has(prefix) && !builtins.has(prefix);
376
+ if (bannedTokens.has(prefix) || builtins.has(prefix)) return {
377
+ success: false,
378
+ error: `Identifiers cannot start with reserved keywords.`
379
+ };
380
+ return { success: true };
365
381
  }
366
382
  /**
367
- * Same as `isValidIdentifier`, except does not check for builtin clashes.
383
+ * Same as `validateIdentifier`, except does not check for builtin clashes.
368
384
  */
369
- function isValidProp(ident) {
370
- if (ident === "_" || ident.startsWith("__") || /\s/.test(ident)) throw new Error(`Invalid identifier '${ident}'. Choose an identifier without whitespaces or leading underscores.`);
385
+ /* @__NO_SIDE_EFFECTS__ */
386
+ function validateProp(ident) {
387
+ if (ident === "_") return { success: false };
388
+ if (/\s/.test(ident)) return {
389
+ success: false,
390
+ error: `Identifiers cannot contain whitespace.`
391
+ };
392
+ if (ident.startsWith("__")) return {
393
+ success: false,
394
+ error: `Identifiers cannot start with double underscores.`
395
+ };
371
396
  const prefix = ident.split("_")[0];
372
- return !bannedTokens.has(prefix);
397
+ if (bannedTokens.has(prefix)) return {
398
+ success: false,
399
+ error: `Identifiers cannot start with reserved keywords.`
400
+ };
401
+ return { success: true };
373
402
  }
374
- var NameRegistryImpl = class {
375
- #usedNames;
376
- #scopeStack;
377
- constructor() {
378
- this.#usedNames = new Set([...bannedTokens, ...builtins]);
379
- this.#scopeStack = [];
380
- }
381
- get #usedBlockScopeNames() {
382
- return this.#scopeStack[this.#scopeStack.length - 1]?.usedBlockScopeNames;
383
- }
384
- makeUnique(primer, global) {
385
- const sanitizedPrimer = sanitizePrimer(primer);
386
- const name = this.getUniqueVariant(sanitizedPrimer);
387
- if (global) this.#usedNames.add(name);
388
- else this.#usedBlockScopeNames?.add(name);
389
- return name;
390
- }
391
- #isUsedInBlocksBefore(name) {
392
- const functionScopeIndex = this.#scopeStack.findLastIndex((scope) => scope.type === "functionScope");
393
- return this.#scopeStack.slice(functionScopeIndex + 1).some((scope) => scope.usedBlockScopeNames.has(name));
394
- }
395
- makeValid(primer) {
396
- if (isValidIdentifier(primer) && !this.#usedNames.has(primer) && !this.#isUsedInBlocksBefore(primer)) {
397
- this.#usedBlockScopeNames?.add(primer);
398
- return primer;
399
- }
400
- return this.makeUnique(primer, false);
401
- }
402
- isUsed(name) {
403
- return this.#usedNames.has(name) || this.#isUsedInBlocksBefore(name);
404
- }
405
- pushFunctionScope() {
406
- this.#scopeStack.push({ type: "functionScope" });
407
- this.#scopeStack.push({
408
- type: "blockScope",
409
- usedBlockScopeNames: /* @__PURE__ */ new Set()
410
- });
411
- }
412
- popFunctionScope() {
413
- const functionScopeIndex = this.#scopeStack.findLastIndex((scope) => scope.type === "functionScope");
414
- if (functionScopeIndex === -1) throw new Error("Tried to pop function scope when no scope was present.");
415
- this.#scopeStack.splice(functionScopeIndex);
416
- }
417
- pushBlockScope() {
418
- this.#scopeStack.push({
419
- type: "blockScope",
420
- usedBlockScopeNames: /* @__PURE__ */ new Set()
421
- });
422
- }
423
- popBlockScope() {
424
- invariant(this.#scopeStack[this.#scopeStack.length - 1]?.type === "blockScope", "Tried to pop block scope, but it is not present");
425
- this.#scopeStack.pop();
426
- }
427
- };
428
- var RandomNameRegistry = class extends NameRegistryImpl {
429
- #lastUniqueId = 0;
430
- getUniqueVariant(base) {
431
- let name = `${base}_${this.#lastUniqueId++}`;
432
- while (this.isUsed(name)) name = `${base}_${this.#lastUniqueId++}`;
433
- return name;
434
- }
435
- };
436
- var StrictNameRegistry = class extends NameRegistryImpl {
437
- getUniqueVariant(base) {
438
- let index = 0;
439
- let name = base;
440
- while (this.isUsed(name)) {
441
- index++;
442
- name = `${base}_${index}`;
443
- }
444
- return name;
445
- }
446
- };
447
403
 
448
404
  //#endregion
449
- export { RandomNameRegistry, StrictNameRegistry, isValidProp };
405
+ export { bannedTokens, builtins, sanitizePrimer, validateIdentifier, validateProp };
package/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.11.4";
2
+ var version = "0.11.6";
3
3
 
4
4
  //#endregion
5
5
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typegpu",
3
- "version": "0.11.4",
3
+ "version": "0.11.6",
4
4
  "description": "A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.",
5
5
  "keywords": [
6
6
  "compute",
package/resolutionCtx.js CHANGED
@@ -12,12 +12,12 @@ import { safeStringify } from "./shared/stringify.js";
12
12
  import { getBestConversion } from "./tgsl/conversion.js";
13
13
  import { bool } from "./data/numeric.js";
14
14
  import { coerceToSnippet, concretize, numericLiteralToSnippet } from "./tgsl/generationHelpers.js";
15
+ import { sanitizePrimer, validateIdentifier } from "./nameUtils.js";
15
16
  import { createIoSchema } from "./core/function/ioSchema.js";
16
17
  import { AutoStruct } from "./data/autoStruct.js";
17
18
  import { EntryInputRouter } from "./core/function/entryInputRouter.js";
18
19
  import { accessProp } from "./tgsl/accessProp.js";
19
20
  import { isTgpuFn } from "./core/function/tgpuFn.js";
20
- import { getUniqueName } from "./core/resolve/namespace.js";
21
21
  import { ConfigurableImpl } from "./core/root/configurableImpl.js";
22
22
  import { naturalsExcept } from "./shared/generators.js";
23
23
  import { TgpuBindGroupImpl, bindGroupLayout } from "./tgpuBindGroupLayout.js";
@@ -50,6 +50,9 @@ var ItemStateStackImpl = class {
50
50
  get topFunctionScope() {
51
51
  return this._stack.findLast((e) => e.type === "functionScope");
52
52
  }
53
+ get topBlockScope() {
54
+ return this._stack.findLast((e) => e.type === "blockScope");
55
+ }
53
56
  pushItem() {
54
57
  this._itemDepth++;
55
58
  this._stack.push({
@@ -70,7 +73,9 @@ var ItemStateStackImpl = class {
70
73
  argAccess,
71
74
  returnType,
72
75
  externalMap,
73
- reportedReturnTypes: /* @__PURE__ */ new Set()
76
+ reportedReturnTypes: /* @__PURE__ */ new Set(),
77
+ placeholderForVariable: /* @__PURE__ */ new Map(),
78
+ modifiedVariables: /* @__PURE__ */ new Set()
74
79
  };
75
80
  this._stack.push(scope);
76
81
  return scope;
@@ -78,6 +83,7 @@ var ItemStateStackImpl = class {
78
83
  pushBlockScope() {
79
84
  this._stack.push({
80
85
  type: "blockScope",
86
+ takenLocalIdentifiers: /* @__PURE__ */ new Set(),
81
87
  declarations: /* @__PURE__ */ new Map(),
82
88
  externals: /* @__PURE__ */ new Map()
83
89
  });
@@ -116,6 +122,16 @@ var ItemStateStackImpl = class {
116
122
  }
117
123
  }
118
124
  }
125
+ isIdentifierTakenLocally(id) {
126
+ for (let i = this._stack.length - 1; i >= 0; --i) {
127
+ const layer = this._stack[i];
128
+ if (layer?.type === "functionScope") return false;
129
+ if (layer?.type === "blockScope") {
130
+ if (layer.takenLocalIdentifiers.has(id)) return true;
131
+ }
132
+ }
133
+ return false;
134
+ }
119
135
  defineBlockVariable(id, snippet) {
120
136
  if (snippet.dataType === UnknownData) throw Error(`Tried to define variable '${id}' of unknown type`);
121
137
  for (let i = this._stack.length - 1; i >= 0; --i) {
@@ -232,17 +248,41 @@ var ResolutionCtxImpl = class {
232
248
  fixedBindings = [];
233
249
  enableExtensions;
234
250
  expectedType;
251
+ /**
252
+ * A counter used to generate unique identifiers for globally-scoped definitions in the 'random' strategy.
253
+ */
254
+ #lastUniqueId = 0;
235
255
  constructor(opts) {
236
256
  this.enableExtensions = opts.enableExtensions;
237
257
  this.gen = opts.shaderGenerator ?? wgslGenerator_default;
238
258
  this.#logGenerator = opts.root ? new LogGeneratorImpl(opts.root) : new LogGeneratorNullImpl();
239
259
  this.#namespaceInternal = opts.namespace[$internal];
240
260
  }
241
- getUniqueName(resource) {
242
- return getUniqueName(this.#namespaceInternal, resource);
261
+ isIdentifierTaken(name) {
262
+ return this.#namespaceInternal.takenGlobalIdentifiers.has(name) || this._itemStateStack.isIdentifierTakenLocally(name);
243
263
  }
244
- makeNameValid(name) {
245
- return this.#namespaceInternal.nameRegistry.makeValid(name);
264
+ makeUniqueIdentifier(primer = "item", scope) {
265
+ if (scope === "block" && (/* @__PURE__ */ validateIdentifier(primer)).success && !this.isIdentifierTaken(primer)) {
266
+ this.reserveIdentifier(primer, "block");
267
+ return primer;
268
+ }
269
+ const base = /* @__PURE__ */ sanitizePrimer(primer);
270
+ let index = 0;
271
+ const random = this.#namespaceInternal.strategy === "random";
272
+ let name = random ? `${base}_${this.#lastUniqueId++}` : base;
273
+ while (this.isIdentifierTaken(name)) name = random ? `${base}_${this.#lastUniqueId++}` : `${base}_${++index}`;
274
+ this.reserveIdentifier(name, scope);
275
+ return name;
276
+ }
277
+ reserveIdentifier(name, scope) {
278
+ if (scope === "block") {
279
+ const blockScope = this._itemStateStack.topBlockScope;
280
+ if (blockScope) {
281
+ blockScope.takenLocalIdentifiers.add(name);
282
+ return;
283
+ }
284
+ }
285
+ this.#namespaceInternal.takenGlobalIdentifiers.add(name);
246
286
  }
247
287
  get pre() {
248
288
  return this._indentController.pre;
@@ -281,11 +321,9 @@ var ResolutionCtxImpl = class {
281
321
  scope.reportedReturnTypes.add(dataType);
282
322
  }
283
323
  pushBlockScope() {
284
- this.#namespaceInternal.nameRegistry.pushBlockScope();
285
324
  this._itemStateStack.pushBlockScope();
286
325
  }
287
326
  popBlockScope() {
288
- this.#namespaceInternal.nameRegistry.popBlockScope();
289
327
  this._itemStateStack.pop("blockScope");
290
328
  }
291
329
  setBlockExternals(externals) {
@@ -301,28 +339,27 @@ var ResolutionCtxImpl = class {
301
339
  return this.#logGenerator.logResources;
302
340
  }
303
341
  fnToWgsl(options) {
304
- let fnScopePushed = false;
305
342
  try {
306
- this.#namespaceInternal.nameRegistry.pushFunctionScope();
343
+ const scope = this._itemStateStack.pushFunctionScope(options.functionType, {}, options.returnType, options.externalMap);
344
+ this._itemStateStack.pushBlockScope();
307
345
  const args = [];
308
- const argAccess = {};
309
346
  if (options.entryInput) {
310
347
  const { dataSchema, positionalArgs } = options.entryInput;
311
348
  const firstParam = options.params[0];
312
- const structArg = dataSchema ? createArgument(this.makeNameValid("_arg_0"), dataSchema) : void 0;
349
+ const structArg = dataSchema ? createArgument(this.makeUniqueIdentifier("_arg_0", "block"), dataSchema) : void 0;
313
350
  if (structArg) args.push(structArg);
314
351
  if (firstParam?.type === FuncParameterType.destructuredObject) for (const { name, alias } of firstParam.props) {
315
352
  const argInfo = positionalArgs.find((a) => a.schemaKey === name);
316
353
  if (argInfo) {
317
- const arg = createArgument(this.makeNameValid(alias), argInfo.type);
354
+ const arg = createArgument(this.makeUniqueIdentifier(alias, "block"), argInfo.type);
318
355
  args.push(arg);
319
- argAccess[alias] = arg.access;
320
- } else if (structArg) argAccess[alias] = createArgumentPropAccess(structArg.access, name);
356
+ scope.argAccess[alias] = arg.access;
357
+ } else if (structArg) scope.argAccess[alias] = createArgumentPropAccess(structArg.access, name);
321
358
  }
322
359
  else if (firstParam?.type === FuncParameterType.identifier) {
323
360
  const proxyEntries = [];
324
361
  for (const a of positionalArgs) {
325
- const arg = createArgument(this.makeNameValid(`_arg_${a.schemaKey}`), a.type);
362
+ const arg = createArgument(this.makeUniqueIdentifier(a.schemaKey, "block"), a.type);
326
363
  args.push(arg);
327
364
  proxyEntries.push({
328
365
  schemaKey: a.schemaKey,
@@ -330,31 +367,31 @@ var ResolutionCtxImpl = class {
330
367
  });
331
368
  }
332
369
  const router = new EntryInputRouter(structArg?.access, proxyEntries);
333
- argAccess[firstParam.name] = () => snip("N/A", router, "argument");
370
+ scope.argAccess[firstParam.name] = () => snip("N/A", router, "argument");
334
371
  } else for (const a of positionalArgs) {
335
- const argName = this.makeNameValid(`_arg_${a.schemaKey}`);
372
+ const argName = this.makeUniqueIdentifier(`_arg_${a.schemaKey}`, "block");
336
373
  const arg = createArgument(argName, a.type);
337
374
  args.push(arg);
338
- argAccess[argName] = arg.access;
375
+ scope.argAccess[argName] = arg.access;
339
376
  }
340
377
  } else for (const [i, argType] of options.argTypes.entries()) {
341
378
  const astParam = options.params[i];
342
379
  const origin = isPtr(argType) ? argType.addressSpace === "storage" ? argType.access === "read" ? "readonly" : "mutable" : argType.addressSpace : "argument";
343
380
  switch (astParam?.type) {
344
381
  case FuncParameterType.identifier: {
345
- const arg = createArgument(this.makeNameValid(astParam.name), argType, origin);
382
+ const arg = createArgument(this.makeUniqueIdentifier(astParam.name, "block"), argType, origin);
346
383
  args.push(arg);
347
- argAccess[astParam.name] = arg.access;
384
+ scope.argAccess[astParam.name] = arg.access;
348
385
  break;
349
386
  }
350
387
  case FuncParameterType.destructuredObject: {
351
- const objArg = createArgument(this.makeNameValid(`_arg_${i}`), argType, origin);
388
+ const objArg = createArgument(this.makeUniqueIdentifier(`_arg_${i}`, "block"), argType, origin);
352
389
  args.push(objArg);
353
- for (const { name, alias } of astParam.props) argAccess[alias] = createArgumentPropAccess(objArg.access, name);
390
+ for (const { name, alias } of astParam.props) scope.argAccess[alias] = createArgumentPropAccess(objArg.access, name);
354
391
  break;
355
392
  }
356
393
  case void 0: if (!(argType instanceof AutoStruct)) args.push({
357
- name: this.makeNameValid(`_arg_${i}`),
394
+ name: this.makeUniqueIdentifier(`_arg_${i}`, "block"),
358
395
  access: () => {
359
396
  throw new Error(`Unreachable: Accessing an argument that wasn't named in the function signature`);
360
397
  },
@@ -363,8 +400,6 @@ var ResolutionCtxImpl = class {
363
400
  });
364
401
  }
365
402
  }
366
- const scope = this._itemStateStack.pushFunctionScope(options.functionType, argAccess, options.returnType, options.externalMap);
367
- fnScopePushed = true;
368
403
  let returnType;
369
404
  const code = this.gen.functionDefinition({
370
405
  functionType: options.functionType,
@@ -395,8 +430,8 @@ var ResolutionCtxImpl = class {
395
430
  returnType
396
431
  };
397
432
  } finally {
398
- if (fnScopePushed) this._itemStateStack.pop("functionScope");
399
- this.#namespaceInternal.nameRegistry.popFunctionScope();
433
+ this._itemStateStack.pop("blockScope");
434
+ this._itemStateStack.pop("functionScope");
400
435
  }
401
436
  }
402
437
  addDeclaration(declaration) {
package/std/copy.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { DualFn } from "../types.js";
2
+
3
+ //#region src/std/copy.d.ts
4
+ declare function cpuCopy<T>(e: T): T;
5
+ declare const copy: DualFn<typeof cpuCopy>;
6
+ //#endregion
7
+ export { copy };
package/std/copy.js ADDED
@@ -0,0 +1,27 @@
1
+ import { WORKAROUND_getSchema, isMatInstance, isVecInstance } from "../data/wgslTypes.js";
2
+ import { stitch } from "../core/resolve/stitch.js";
3
+ import { dualImpl } from "../core/function/dualImpl.js";
4
+
5
+ //#region src/std/copy.ts
6
+ function cpuCopy(e) {
7
+ if (isVecInstance(e) || isMatInstance(e)) return WORKAROUND_getSchema(e)(e);
8
+ if (Array.isArray(e)) return e.map(cpuCopy);
9
+ if (typeof e === "object" && e !== null) return Object.fromEntries(Object.entries(e).map(([key, value]) => [key, cpuCopy(value)]));
10
+ return e;
11
+ }
12
+ const copy = dualImpl({
13
+ name: "copy",
14
+ signature: (arg) => {
15
+ return {
16
+ argTypes: [arg],
17
+ returnType: arg
18
+ };
19
+ },
20
+ normalImpl: cpuCopy,
21
+ codegenImpl(_ctx, [a]) {
22
+ return stitch`${a}`;
23
+ }
24
+ });
25
+
26
+ //#endregion
27
+ export { copy };
package/std/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { identity2, identity3, identity4, rotationX4, rotationY4, rotationZ4, scaling4, translation4 } from "../data/matrix.js";
2
+ import { copy } from "./copy.js";
2
3
  import { discard } from "./discard.js";
3
4
  import { abs, acos, acosh, asin, asinh, atan, atan2, atanh, ceil, clamp, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, degrees, determinant, distance, dot, dot4I8Packed, dot4U8Packed, exp, exp2, extractBits, faceForward, firstLeadingBit, firstTrailingBit, floor, fma, fract, frexp, insertBits, inverseSqrt, ldexp, length, log, log2, max, min, mix, modf, normalize, pow, quantizeToF16, radians, reflect, refract, reverseBits, round, saturate, sign, sin, sinh, smoothstep, sqrt, step, tan, tanh, transpose, trunc } from "./numeric.js";
4
5
  import { add, bitShiftLeft, bitShiftRight, div, mod, mul, neg, sub } from "./operators.js";
@@ -16,7 +17,7 @@ import { range } from "./range.js";
16
17
 
17
18
  //#region src/std/index.d.ts
18
19
  declare namespace index_d_exports {
19
- export { abs, acos, acosh, add, all, allEq, and, any, arrayLength, asin, asinh, atan, atan2, atanh, atomicAdd, atomicAnd, atomicLoad, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, bitShiftLeft, bitShiftRight, bitcastU32toF32, bitcastU32toI32, ceil, clamp, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, degrees, determinant, discard, distance, div, dot, dot4I8Packed, dot4U8Packed, dpdx, dpdxCoarse, dpdxFine, dpdy, dpdyCoarse, dpdyFine, eq, exp, exp2, extensionEnabled, extractBits, faceForward, firstLeadingBit, firstTrailingBit, floor, fma, fract, frexp, fwidth, fwidthCoarse, fwidthFine, ge, gt, identity2, identity3, identity4, insertBits, inverseSqrt, isCloseTo, ldexp, le, length, log, log2, lt, max, min, mix, mod, modf, mul, ne, neg, normalize, not, or, pack2x16float, pack4x8unorm, pow, quantizeToF16, radians, range, reflect, refract, reverseBits, rotateX4, rotateY4, rotateZ4, rotationX4, rotationY4, rotationZ4, round, saturate, scale4, scaling4, select, sign, sin, sinh, smoothstep, sqrt, step, storageBarrier, sub, subgroupAdd, subgroupAll, subgroupAnd, subgroupAny, subgroupBallot, subgroupBroadcast, subgroupBroadcastFirst, subgroupElect, subgroupExclusiveAdd, subgroupExclusiveMul, subgroupInclusiveAdd, subgroupInclusiveMul, subgroupMax, subgroupMin, subgroupMul, subgroupOr, subgroupShuffle, subgroupShuffleDown, subgroupShuffleUp, subgroupShuffleXor, subgroupXor, tan, tanh, textureBarrier, textureDimensions, textureGather, textureLoad, textureSample, textureSampleBaseClampToEdge, textureSampleBias, textureSampleCompare, textureSampleCompareLevel, textureSampleGrad, textureSampleLevel, textureStore, translate4, translation4, transpose, trunc, unpack2x16float, unpack4x8unorm, workgroupBarrier };
20
+ export { abs, acos, acosh, add, all, allEq, and, any, arrayLength, asin, asinh, atan, atan2, atanh, atomicAdd, atomicAnd, atomicLoad, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, bitShiftLeft, bitShiftRight, bitcastU32toF32, bitcastU32toI32, ceil, clamp, copy, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, degrees, determinant, discard, distance, div, dot, dot4I8Packed, dot4U8Packed, dpdx, dpdxCoarse, dpdxFine, dpdy, dpdyCoarse, dpdyFine, eq, exp, exp2, extensionEnabled, extractBits, faceForward, firstLeadingBit, firstTrailingBit, floor, fma, fract, frexp, fwidth, fwidthCoarse, fwidthFine, ge, gt, identity2, identity3, identity4, insertBits, inverseSqrt, isCloseTo, ldexp, le, length, log, log2, lt, max, min, mix, mod, modf, mul, ne, neg, normalize, not, or, pack2x16float, pack4x8unorm, pow, quantizeToF16, radians, range, reflect, refract, reverseBits, rotateX4, rotateY4, rotateZ4, rotationX4, rotationY4, rotationZ4, round, saturate, scale4, scaling4, select, sign, sin, sinh, smoothstep, sqrt, step, storageBarrier, sub, subgroupAdd, subgroupAll, subgroupAnd, subgroupAny, subgroupBallot, subgroupBroadcast, subgroupBroadcastFirst, subgroupElect, subgroupExclusiveAdd, subgroupExclusiveMul, subgroupInclusiveAdd, subgroupInclusiveMul, subgroupMax, subgroupMin, subgroupMul, subgroupOr, subgroupShuffle, subgroupShuffleDown, subgroupShuffleUp, subgroupShuffleXor, subgroupXor, tan, tanh, textureBarrier, textureDimensions, textureGather, textureLoad, textureSample, textureSampleBaseClampToEdge, textureSampleBias, textureSampleCompare, textureSampleCompareLevel, textureSampleGrad, textureSampleLevel, textureStore, translate4, translation4, transpose, trunc, unpack2x16float, unpack4x8unorm, workgroupBarrier };
20
21
  }
21
22
  //#endregion
22
- export { abs, acos, acosh, add, all, allEq, and, any, arrayLength, asin, asinh, atan, atan2, atanh, atomicAdd, atomicAnd, atomicLoad, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, bitShiftLeft, bitShiftRight, bitcastU32toF32, bitcastU32toI32, ceil, clamp, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, degrees, determinant, discard, distance, div, dot, dot4I8Packed, dot4U8Packed, dpdx, dpdxCoarse, dpdxFine, dpdy, dpdyCoarse, dpdyFine, eq, exp, exp2, extensionEnabled, extractBits, faceForward, firstLeadingBit, firstTrailingBit, floor, fma, fract, frexp, fwidth, fwidthCoarse, fwidthFine, ge, gt, identity2, identity3, identity4, index_d_exports, insertBits, inverseSqrt, isCloseTo, ldexp, le, length, log, log2, lt, max, min, mix, mod, modf, mul, ne, neg, normalize, not, or, pack2x16float, pack4x8unorm, pow, quantizeToF16, radians, range, reflect, refract, reverseBits, rotateX4, rotateY4, rotateZ4, rotationX4, rotationY4, rotationZ4, round, saturate, scale4, scaling4, select, sign, sin, sinh, smoothstep, sqrt, step, storageBarrier, sub, subgroupAdd, subgroupAll, subgroupAnd, subgroupAny, subgroupBallot, subgroupBroadcast, subgroupBroadcastFirst, subgroupElect, subgroupExclusiveAdd, subgroupExclusiveMul, subgroupInclusiveAdd, subgroupInclusiveMul, subgroupMax, subgroupMin, subgroupMul, subgroupOr, subgroupShuffle, subgroupShuffleDown, subgroupShuffleUp, subgroupShuffleXor, subgroupXor, tan, tanh, textureBarrier, textureDimensions, textureGather, textureLoad, textureSample, textureSampleBaseClampToEdge, textureSampleBias, textureSampleCompare, textureSampleCompareLevel, textureSampleGrad, textureSampleLevel, textureStore, translate4, translation4, transpose, trunc, unpack2x16float, unpack4x8unorm, workgroupBarrier };
23
+ export { abs, acos, acosh, add, all, allEq, and, any, arrayLength, asin, asinh, atan, atan2, atanh, atomicAdd, atomicAnd, atomicLoad, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, bitShiftLeft, bitShiftRight, bitcastU32toF32, bitcastU32toI32, ceil, clamp, copy, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, degrees, determinant, discard, distance, div, dot, dot4I8Packed, dot4U8Packed, dpdx, dpdxCoarse, dpdxFine, dpdy, dpdyCoarse, dpdyFine, eq, exp, exp2, extensionEnabled, extractBits, faceForward, firstLeadingBit, firstTrailingBit, floor, fma, fract, frexp, fwidth, fwidthCoarse, fwidthFine, ge, gt, identity2, identity3, identity4, index_d_exports, insertBits, inverseSqrt, isCloseTo, ldexp, le, length, log, log2, lt, max, min, mix, mod, modf, mul, ne, neg, normalize, not, or, pack2x16float, pack4x8unorm, pow, quantizeToF16, radians, range, reflect, refract, reverseBits, rotateX4, rotateY4, rotateZ4, rotationX4, rotationY4, rotationZ4, round, saturate, scale4, scaling4, select, sign, sin, sinh, smoothstep, sqrt, step, storageBarrier, sub, subgroupAdd, subgroupAll, subgroupAnd, subgroupAny, subgroupBallot, subgroupBroadcast, subgroupBroadcastFirst, subgroupElect, subgroupExclusiveAdd, subgroupExclusiveMul, subgroupInclusiveAdd, subgroupInclusiveMul, subgroupMax, subgroupMin, subgroupMul, subgroupOr, subgroupShuffle, subgroupShuffleDown, subgroupShuffleUp, subgroupShuffleXor, subgroupXor, tan, tanh, textureBarrier, textureDimensions, textureGather, textureLoad, textureSample, textureSampleBaseClampToEdge, textureSampleBias, textureSampleCompare, textureSampleCompareLevel, textureSampleGrad, textureSampleLevel, textureStore, translate4, translation4, transpose, trunc, unpack2x16float, unpack4x8unorm, workgroupBarrier };
package/std/index.js CHANGED
@@ -7,6 +7,7 @@ import { range } from "./range.js";
7
7
  import { bitcastU32toF32, bitcastU32toI32 } from "./bitcast.js";
8
8
  import { pack2x16float, pack4x8unorm, unpack2x16float, unpack4x8unorm } from "./packing.js";
9
9
  import { all, allEq, and, any, eq, ge, gt, isCloseTo, le, lt, ne, not, or, select } from "./boolean.js";
10
+ import { copy } from "./copy.js";
10
11
  import { discard } from "./discard.js";
11
12
  import { rotateX4, rotateY4, rotateZ4, scale4, translate4 } from "./matrix.js";
12
13
  import { atomicAdd, atomicAnd, atomicLoad, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, storageBarrier, textureBarrier, workgroupBarrier } from "./atomic.js";
@@ -46,6 +47,7 @@ var std_exports = /* @__PURE__ */ __export({
46
47
  bitcastU32toI32: () => bitcastU32toI32,
47
48
  ceil: () => ceil,
48
49
  clamp: () => clamp,
50
+ copy: () => copy,
49
51
  cos: () => cos,
50
52
  cosh: () => cosh,
51
53
  countLeadingZeros: () => countLeadingZeros,
@@ -179,4 +181,4 @@ var std_exports = /* @__PURE__ */ __export({
179
181
  });
180
182
 
181
183
  //#endregion
182
- export { abs, acos, acosh, add, all, allEq, and, any, arrayLength, asin, asinh, atan, atan2, atanh, atomicAdd, atomicAnd, atomicLoad, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, bitShiftLeft, bitShiftRight, bitcastU32toF32, bitcastU32toI32, ceil, clamp, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, degrees, determinant, discard, distance, div, dot, dot4I8Packed, dot4U8Packed, dpdx, dpdxCoarse, dpdxFine, dpdy, dpdyCoarse, dpdyFine, eq, exp, exp2, extensionEnabled, extractBits, faceForward, firstLeadingBit, firstTrailingBit, floor, fma, fract, frexp, fwidth, fwidthCoarse, fwidthFine, ge, gt, identity2, identity3, identity4, insertBits, inverseSqrt, isCloseTo, ldexp, le, length, log, log2, lt, max, min, mix, mod, modf, mul, ne, neg, normalize, not, or, pack2x16float, pack4x8unorm, pow, quantizeToF16, radians, range, reflect, refract, reverseBits, rotateX4, rotateY4, rotateZ4, rotationX4, rotationY4, rotationZ4, round, saturate, scale4, scaling4, select, sign, sin, sinh, smoothstep, sqrt, std_exports, step, storageBarrier, sub, subgroupAdd, subgroupAll, subgroupAnd, subgroupAny, subgroupBallot, subgroupBroadcast, subgroupBroadcastFirst, subgroupElect, subgroupExclusiveAdd, subgroupExclusiveMul, subgroupInclusiveAdd, subgroupInclusiveMul, subgroupMax, subgroupMin, subgroupMul, subgroupOr, subgroupShuffle, subgroupShuffleDown, subgroupShuffleUp, subgroupShuffleXor, subgroupXor, tan, tanh, textureBarrier, textureDimensions, textureGather, textureLoad, textureSample, textureSampleBaseClampToEdge, textureSampleBias, textureSampleCompare, textureSampleCompareLevel, textureSampleGrad, textureSampleLevel, textureStore, translate4, translation4, transpose, trunc, unpack2x16float, unpack4x8unorm, workgroupBarrier };
184
+ export { abs, acos, acosh, add, all, allEq, and, any, arrayLength, asin, asinh, atan, atan2, atanh, atomicAdd, atomicAnd, atomicLoad, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, bitShiftLeft, bitShiftRight, bitcastU32toF32, bitcastU32toI32, ceil, clamp, copy, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, degrees, determinant, discard, distance, div, dot, dot4I8Packed, dot4U8Packed, dpdx, dpdxCoarse, dpdxFine, dpdy, dpdyCoarse, dpdyFine, eq, exp, exp2, extensionEnabled, extractBits, faceForward, firstLeadingBit, firstTrailingBit, floor, fma, fract, frexp, fwidth, fwidthCoarse, fwidthFine, ge, gt, identity2, identity3, identity4, insertBits, inverseSqrt, isCloseTo, ldexp, le, length, log, log2, lt, max, min, mix, mod, modf, mul, ne, neg, normalize, not, or, pack2x16float, pack4x8unorm, pow, quantizeToF16, radians, range, reflect, refract, reverseBits, rotateX4, rotateY4, rotateZ4, rotationX4, rotationY4, rotationZ4, round, saturate, scale4, scaling4, select, sign, sin, sinh, smoothstep, sqrt, std_exports, step, storageBarrier, sub, subgroupAdd, subgroupAll, subgroupAnd, subgroupAny, subgroupBallot, subgroupBroadcast, subgroupBroadcastFirst, subgroupElect, subgroupExclusiveAdd, subgroupExclusiveMul, subgroupInclusiveAdd, subgroupInclusiveMul, subgroupMax, subgroupMin, subgroupMul, subgroupOr, subgroupShuffle, subgroupShuffleDown, subgroupShuffleUp, subgroupShuffleXor, subgroupXor, tan, tanh, textureBarrier, textureDimensions, textureGather, textureLoad, textureSample, textureSampleBaseClampToEdge, textureSampleBias, textureSampleCompare, textureSampleCompareLevel, textureSampleGrad, textureSampleLevel, textureStore, translate4, translation4, transpose, trunc, unpack2x16float, unpack4x8unorm, workgroupBarrier };
package/tgpuUnstable.js CHANGED
@@ -2,9 +2,9 @@ import { __export } from "./_virtual/rolldown_runtime.js";
2
2
  import { comptime } from "./core/function/comptime.js";
3
3
  import { constant } from "./core/constant/tgpuConstant.js";
4
4
  import { fn } from "./core/function/tgpuFn.js";
5
- import { namespace } from "./core/resolve/namespace.js";
6
5
  import { slot } from "./core/slot/slot.js";
7
6
  import { privateVar, workgroupVar } from "./core/variable/tgpuVariable.js";
7
+ import { namespace } from "./core/resolve/namespace.js";
8
8
  import { computeFn } from "./core/function/tgpuComputeFn.js";
9
9
  import { vertexLayout } from "./core/vertexLayout/vertexLayout.js";
10
10
  import { lazy } from "./core/slot/lazy.js";
@@ -158,7 +158,10 @@ function getBestConversion(types, targetTypes) {
158
158
  if (implicitResult) return implicitResult;
159
159
  }
160
160
  function applyActionToSnippet(ctx, snippet, action, targetType) {
161
- if (action.action === "none") return snip(snippet.value, targetType, snippet.origin);
161
+ if (action.action === "none") {
162
+ if (targetType === snippet.dataType) return snippet;
163
+ return snip(snippet.value, targetType, snippet.origin);
164
+ }
162
165
  switch (action.action) {
163
166
  case "ref": return snip(new RefOperator(snippet, targetType), targetType, snippet.origin);
164
167
  case "deref": return derefSnippet(snippet);
@@ -13,9 +13,14 @@ declare class WgslGenerator implements ShaderGenerator {
13
13
  initGenerator(ctx: GenerationCtx): void;
14
14
  protected get ctx(): GenerationCtx;
15
15
  _block([_, statements]: tinyest.Block, externalMap?: ExternalMap): string;
16
+ _blockStatement(block: tinyest.Block, externalMap?: ExternalMap): string;
16
17
  refVariable(id: string, dataType: StorableData): string;
17
- blockVariable(varType: 'var' | 'let' | 'const', id: string, dataType: BaseData | UnknownData, origin: Origin): Snippet;
18
- protected emitVarDecl(pre: string, keyword: 'var' | 'let' | 'const', name: string, _dataType: BaseData | UnknownData, rhsStr: string): string;
18
+ blockVariable(varType: 'var' | 'let' | 'const' | '<deferred>', id: string, dataType: BaseData | UnknownData, origin: Origin): Snippet;
19
+ /**
20
+ * Creates a variable declaration string.
21
+ * `keyword` may be a placeholder filled in later.
22
+ */
23
+ protected emitVarDecl(pre: string, keyword: 'var' | 'let' | 'const' | `#VAR_${number}#`, name: string, _dataType: BaseData | UnknownData, rhsStr: string): string;
19
24
  _identifier(id: string): Snippet;
20
25
  /**
21
26
  * A wrapper for `generateExpression` that updates `ctx.expectedType`
@@ -33,6 +38,19 @@ declare class WgslGenerator implements ShaderGenerator {
33
38
  typeInstantiation(schema: BaseData, args: readonly Snippet[]): ResolvedSnippet;
34
39
  _return(statement: tinyest.Return): string;
35
40
  _statement(statement: tinyest.Statement): string;
41
+ /**
42
+ * Attempts a member access lookup to mark a variable as modified.
43
+ * @example
44
+ * // given `let a; a = 1;`
45
+ * tryMarkModified('a') // `a` is marked in the function scope
46
+ *
47
+ * // given `const obj; obj.prop = 1;`
48
+ * tryMarkModified('obj.prop') // `obj` is marked in the function scope
49
+ *
50
+ * // given `this.buffer.$;`
51
+ * tryMarkModified('this.buffer.$') // `this` is not marked, since there is no placeholder for it
52
+ */
53
+ private tryMarkModified;
36
54
  }
37
55
  //#endregion
38
56
  export { WgslGenerator };