typegpu 0.12.5 → 0.12.7

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.
Files changed (99) hide show
  1. package/common/index.d.ts +1 -0
  2. package/common/index.js +1 -0
  3. package/common/writeChannels.d.ts +31 -0
  4. package/common/writeChannels.js +32 -0
  5. package/common/writeSoA.js +16 -0
  6. package/core/buffer/buffer.js +47 -11
  7. package/core/commandEncoder/attachments.js +5 -2
  8. package/core/commandEncoder/computePass.d.ts +13 -0
  9. package/core/commandEncoder/computePass.js +5 -2
  10. package/core/commandEncoder/renderPass.d.ts +18 -4
  11. package/core/commandEncoder/renderPass.js +6 -2
  12. package/core/declare/tgpuDeclare.d.ts +11 -0
  13. package/core/declare/tgpuDeclare.js +1 -1
  14. package/core/function/autoIO.js +4 -2
  15. package/core/function/ioSchema.d.ts +7 -2
  16. package/core/function/ioSchema.js +41 -15
  17. package/core/function/tgpuFragmentFn.d.ts +1 -1
  18. package/core/function/tgpuFragmentFn.js +2 -1
  19. package/core/function/tgpuVertexFn.js +2 -1
  20. package/core/immediate/immediateVar.d.ts +52 -0
  21. package/core/immediate/immediateVar.js +149 -0
  22. package/core/pipeline/computePipeline.d.ts +17 -0
  23. package/core/pipeline/computePipeline.js +23 -9
  24. package/core/pipeline/connectAttachmentToShader.d.ts +2 -2
  25. package/core/pipeline/connectAttachmentToShader.js +16 -21
  26. package/core/pipeline/connectTargetsToShader.d.ts +5 -1
  27. package/core/pipeline/connectTargetsToShader.js +23 -18
  28. package/core/pipeline/drawState.d.ts +8 -4
  29. package/core/pipeline/drawState.js +41 -51
  30. package/core/pipeline/priors.js +1 -0
  31. package/core/pipeline/renderPipeline.d.ts +22 -4
  32. package/core/pipeline/renderPipeline.js +25 -13
  33. package/core/resolve/namespace.js +2 -2
  34. package/core/root/init.js +3 -0
  35. package/core/root/rootTypes.d.ts +17 -2
  36. package/core/slot/accessor.d.ts +1 -1
  37. package/core/slot/accessor.js +72 -5
  38. package/core/slot/slotTypes.d.ts +2 -1
  39. package/core/texture/texture.d.ts +20 -14
  40. package/core/texture/texture.js +78 -69
  41. package/core/texture/textureUtils.d.ts +3 -6
  42. package/core/texture/textureUtils.js +142 -165
  43. package/core/texture/textureWrite.d.ts +61 -0
  44. package/core/texture/textureWrite.js +59 -0
  45. package/data/autoStruct.d.ts +1 -1
  46. package/data/autoStruct.js +8 -4
  47. package/data/dataIO.d.ts +2 -2
  48. package/data/deepEqual.js +19 -9
  49. package/data/matrix.js +10 -3
  50. package/data/partialIO.d.ts +8 -1
  51. package/data/partialIO.js +36 -19
  52. package/data/ref.js +2 -2
  53. package/data/snippet.d.ts +11 -5
  54. package/data/snippet.js +9 -4
  55. package/data/wgslTypes.d.ts +4 -1
  56. package/errors.d.ts +7 -0
  57. package/errors.js +15 -0
  58. package/indexNamedExports.d.ts +5 -2
  59. package/indexNamedExports.js +2 -1
  60. package/internal.d.ts +2 -1
  61. package/internal.js +1 -1
  62. package/nameUtils.d.ts +7 -0
  63. package/nameUtils.js +60 -0
  64. package/package.json +2 -2
  65. package/resolutionCtx.d.ts +5 -0
  66. package/resolutionCtx.js +11 -0
  67. package/serial/restore.d.ts +3 -1
  68. package/serial/restore.js +2 -0
  69. package/shared/meta.js +1 -1
  70. package/shared/symbols.js +1 -1
  71. package/shared/tseynit.d.ts +1 -0
  72. package/shared/tseynit.js +80 -44
  73. package/std/atomic.d.ts +13 -0
  74. package/std/atomic.js +63 -29
  75. package/std/boolean.js +9 -10
  76. package/std/derivative.js +14 -9
  77. package/std/index.d.ts +4 -4
  78. package/std/index.js +5 -5
  79. package/std/numeric.d.ts +5 -1
  80. package/std/numeric.js +3 -3
  81. package/std/operators.js +9 -4
  82. package/std/packing.d.ts +61 -1
  83. package/std/packing.js +214 -25
  84. package/std/subgroup.d.ts +4 -0
  85. package/std/subgroup.js +34 -0
  86. package/std/texture.d.ts +15 -2
  87. package/std/texture.js +48 -0
  88. package/tgpuUnstable.d.ts +1 -0
  89. package/tgpuUnstable.js +1 -0
  90. package/tgsl/accessIndex.js +19 -23
  91. package/tgsl/conversion.d.ts +2 -0
  92. package/tgsl/conversion.js +3 -0
  93. package/tgsl/forOfUtils.js +6 -6
  94. package/tgsl/generationHelpers.js +2 -2
  95. package/tgsl/shaderGenerator.d.ts +1 -1
  96. package/tgsl/wgslGenerator.d.ts +5 -0
  97. package/tgsl/wgslGenerator.js +288 -58
  98. package/types.d.ts +9 -1
  99. package/types.js +5 -0
@@ -0,0 +1,59 @@
1
+ export function origin3d([x = 0, y = 0, z = 0] = []) {
2
+ return { x, y, z };
3
+ }
4
+ export function mipLevelSize({ size, dimension }, mipLevel) {
5
+ const scale = (value = 1) => Math.max(1, value >> mipLevel);
6
+ return [scale(size[0]), scale(size[1]), dimension === '3d' ? scale(size[2]) : (size[2] ?? 1)];
7
+ }
8
+ /** The size of the written region: `size`, or the rest of the mip level past `origin` */
9
+ export function writeRegionSize(texture, options) {
10
+ const [mipWidth, mipHeight] = mipLevelSize(texture, options.mipLevel ?? 0);
11
+ const [x = 0, y = 0] = options.origin ?? [];
12
+ const [width = mipWidth - x, height = mipHeight - y] = options.size ?? [];
13
+ return [width, height];
14
+ }
15
+ function imageSize(source) {
16
+ const { videoWidth, videoHeight } = source;
17
+ if (videoWidth && videoHeight) {
18
+ return [videoWidth, videoHeight];
19
+ }
20
+ const { naturalWidth, naturalHeight } = source;
21
+ if (naturalWidth && naturalHeight) {
22
+ return [naturalWidth, naturalHeight];
23
+ }
24
+ const { codedWidth, codedHeight } = source;
25
+ if (codedWidth && codedHeight) {
26
+ return [codedWidth, codedHeight];
27
+ }
28
+ const { width, height } = source;
29
+ if (width && height) {
30
+ return [width, height];
31
+ }
32
+ throw new Error('Cannot determine dimensions of the provided image source.');
33
+ }
34
+ export function sameSize(a, b) {
35
+ return a[0] === b[0] && a[1] === b[1];
36
+ }
37
+ export function resolveImageWrite(texture, source, options, layer = options.origin?.[2] ?? 0) {
38
+ const [x = 0, y = 0] = options.origin ?? [];
39
+ const [sourceX = 0, sourceY = 0] = options.sourceOrigin ?? [];
40
+ const [imageWidth, imageHeight] = imageSize(source);
41
+ const [sourceWidth = imageWidth - sourceX, sourceHeight = imageHeight - sourceY] = options.sourceSize ?? [];
42
+ let sourceSize = [sourceWidth, sourceHeight];
43
+ let size = writeRegionSize(texture, options);
44
+ if (options.fit === 'clip') {
45
+ sourceSize = size = [Math.min(sourceSize[0], size[0]), Math.min(sourceSize[1], size[1])];
46
+ }
47
+ else if (options.fit !== 'stretch' && !sameSize(sourceSize, size)) {
48
+ throw new Error(`Texture write source size ${sourceSize.join('x')} does not match target size ${size.join('x')}. Pass fit: 'stretch' to scale the source or fit: 'clip' to copy the overlapping region.`);
49
+ }
50
+ return {
51
+ source,
52
+ sourceOrigin: { x: sourceX, y: sourceY },
53
+ sourceSize,
54
+ origin: { x, y, z: layer },
55
+ size,
56
+ mipLevel: options.mipLevel ?? 0,
57
+ options,
58
+ };
59
+ }
@@ -12,7 +12,7 @@ export declare class AutoStruct implements BaseData, SelfResolvable {
12
12
  [$internal]: Record<string, never>;
13
13
  type: 'auto-struct';
14
14
  readonly [$repr]: Record<string, unknown>;
15
- constructor(validProps: Record<string, BaseData>, typeForExtraProps: BaseData | undefined, locations?: Record<string, number>);
15
+ constructor(validProps: Record<string, BaseData>, typeForExtraProps: BaseData | undefined, locations?: Record<string, number>, autoInterpolateIntegers?: boolean);
16
16
  /**
17
17
  * Used for accessing builtins, varying and attributes in code.
18
18
  */
@@ -22,11 +22,17 @@ export class AutoStruct {
22
22
  #locations;
23
23
  #cachedStruct;
24
24
  #typeForExtraProps;
25
- constructor(validProps, typeForExtraProps, locations) {
25
+ #autoInterpolateIntegers;
26
+ static {
27
+ AutoStruct.prototype[$internal] = {};
28
+ AutoStruct.prototype.type = 'auto-struct';
29
+ }
30
+ constructor(validProps, typeForExtraProps, locations, autoInterpolateIntegers = false) {
26
31
  this.#validProps = validProps;
27
32
  this.#typeForExtraProps = typeForExtraProps;
28
33
  this.#allocated = {};
29
34
  this.#locations = locations;
35
+ this.#autoInterpolateIntegers = autoInterpolateIntegers;
30
36
  this.#usedWgslKeys = new Set();
31
37
  }
32
38
  /**
@@ -67,7 +73,7 @@ export class AutoStruct {
67
73
  if (!this.#cachedStruct) {
68
74
  this.#cachedStruct = createIoSchema(Object.fromEntries(Object.values(this.#allocated).map((alloc) => {
69
75
  return [alloc.prop, alloc.type];
70
- })), this.#locations);
76
+ })), this.#locations, this.#autoInterpolateIntegers);
71
77
  const ownName = getName(this);
72
78
  // Passing the given name forward
73
79
  if (ownName) {
@@ -83,5 +89,3 @@ export class AutoStruct {
83
89
  return `auto-struct:${getName(this) ?? '<unnamed>'}`;
84
90
  }
85
91
  }
86
- AutoStruct.prototype[$internal] = {};
87
- AutoStruct.prototype.type = 'auto-struct';
package/data/dataIO.d.ts CHANGED
@@ -5,9 +5,9 @@ import { type BaseData } from './wgslTypes.ts';
5
5
  import type { BufferWriteOptions } from '../core/buffer/buffer.ts';
6
6
  export declare function writeData<TData extends wgsl.BaseData>(output: ISerialOutput, schema: TData, value: Infer<TData>): void;
7
7
  export declare function readData<TData extends wgsl.BaseData>(input: ISerialInput, schema: TData): Infer<TData>;
8
- export declare function calculateOffsets<T extends BaseData>(options: BufferWriteOptions | undefined, schema: T, data: InferInput<T> | ArrayBuffer): {
8
+ export declare function calculateOffsets<T extends BaseData>(options: BufferWriteOptions | undefined, schema: T, data: InferInput<T> | ArrayBuffer | ArrayBufferView): {
9
9
  startOffset: number;
10
10
  endOffset: number;
11
11
  };
12
- export declare function writeToArrayBuffer<T extends BaseData>(buffer: ArrayBuffer, schema: T, data: InferInput<T> | ArrayBuffer, options?: BufferWriteOptions): void;
12
+ export declare function writeToArrayBuffer<T extends BaseData>(buffer: ArrayBuffer, schema: T, data: InferInput<T> | ArrayBuffer | ArrayBufferView, options?: BufferWriteOptions): void;
13
13
  export declare function readFromArrayBuffer<T extends BaseData>(buffer: ArrayBuffer, schema: T): Infer<T>;
package/data/deepEqual.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { isDisarray, isLooseDecorated, isUnstruct } from "./dataTypes.js";
2
+ import { isWgslStorageTexture, isWgslTexture } from "./texture.js";
2
3
  import { isAtomic, isDecorated, isPtr, isWgslArray, isWgslStruct } from "./wgslTypes.js";
3
4
  /**
4
5
  * Performs a deep comparison of two TypeGPU data schemas.
@@ -53,11 +54,20 @@ export function deepEqual(a, b) {
53
54
  if (isPtr(a) && isPtr(b)) {
54
55
  return (a.addressSpace === b.addressSpace &&
55
56
  a.access === b.access &&
57
+ a.implicit === b.implicit &&
56
58
  deepEqual(a.inner, b.inner));
57
59
  }
58
60
  if (isAtomic(a) && isAtomic(b)) {
59
61
  return deepEqual(a.inner, b.inner);
60
62
  }
63
+ if (isWgslTexture(a) && isWgslTexture(b)) {
64
+ // Dimension and multisampling are already encoded in the type
65
+ return deepEqual(a.sampleType, b.sampleType);
66
+ }
67
+ if (isWgslStorageTexture(a) && isWgslStorageTexture(b)) {
68
+ // Dimension is already encoded in the type
69
+ return a.format === b.format && a.access === b.access;
70
+ }
61
71
  if ((isDecorated(a) && isDecorated(b)) || (isLooseDecorated(a) && isLooseDecorated(b))) {
62
72
  if (!deepEqual(a.inner, b.inner)) {
63
73
  return false;
@@ -65,18 +75,18 @@ export function deepEqual(a, b) {
65
75
  if (a.attribs.length !== b.attribs.length) {
66
76
  return false;
67
77
  }
68
- // Create comparable string representations for each attribute
69
- const getAttrKey = (attr) => {
70
- const anyAttr = attr;
71
- return `${anyAttr.type}(${(anyAttr.params ?? []).join(',')})`;
72
- };
73
- const attrsA = a.attribs.map(getAttrKey);
74
- const attrsB = b.attribs.map(getAttrKey);
75
- for (let i = 0; i < attrsA.length; i++) {
76
- if (attrsA[i] !== attrsB[i]) {
78
+ for (let i = 0; i < a.attribs.length; i++) {
79
+ const attrA = a.attribs[i];
80
+ const attrB = b.attribs[i];
81
+ const paramsA = attrA.params ?? [];
82
+ const paramsB = attrB.params ?? [];
83
+ if (attrA.type !== attrB.type ||
84
+ paramsA.length !== paramsB.length ||
85
+ paramsA.some((param, idx) => param !== paramsB[idx])) {
77
86
  return false;
78
87
  }
79
88
  }
89
+ return true;
80
90
  }
81
91
  // All other types have been checked for equality at the start
82
92
  return true;
package/data/matrix.js CHANGED
@@ -8,7 +8,7 @@ import { numericLiteralToSnippet } from "../tgsl/generationHelpers.js";
8
8
  import { f32 } from "./numeric.js";
9
9
  import {} from "./snippet.js";
10
10
  import { vec2f, vec3f, vec4f } from "./vector.js";
11
- import { isVec, } from "./wgslTypes.js";
11
+ import { isMat, isMatInstance, isVec, } from "./wgslTypes.js";
12
12
  export class MatBase {
13
13
  }
14
14
  function createMatSchema(options) {
@@ -18,7 +18,14 @@ function createMatSchema(options) {
18
18
  normalImpl: (...args) => {
19
19
  const elements = [];
20
20
  for (const arg of args) {
21
- if (typeof arg === 'number') {
21
+ if (isMatInstance(arg)) {
22
+ for (const column of arg.columns) {
23
+ for (const elem of column) {
24
+ elements.push(elem);
25
+ }
26
+ }
27
+ }
28
+ else if (typeof arg === 'number') {
22
29
  elements.push(arg);
23
30
  }
24
31
  else {
@@ -35,7 +42,7 @@ function createMatSchema(options) {
35
42
  }
36
43
  return new options.MatImpl(...elements);
37
44
  },
38
- argTypes: (...args) => args.map((arg) => (isVec(arg) ? arg : f32)),
45
+ argTypes: (...args) => args.map((arg) => (isVec(arg) || isMat(arg) ? arg : f32)),
39
46
  codegenImpl: (ctx, args) => ctx.gen.typeInstantiation(schema, args),
40
47
  });
41
48
  const schema = Object.assign(construct, {
@@ -4,10 +4,17 @@ import type { InferPatch } from '../shared/repr.ts';
4
4
  export interface WriteInstruction {
5
5
  data: Uint8Array<ArrayBuffer>;
6
6
  gpuOffset: number;
7
+ /** How many bytes to upload. Can be larger than `data`, e.g. to cover trailing padding. */
8
+ uploadSize: number;
7
9
  }
8
10
  /**
9
11
  * Converts `{idx, value}[]` sparse arrays into `Record<number, T>` format.
10
12
  */
11
13
  export declare function convertPartialToPatch(schema: wgsl.BaseData, data: unknown): unknown;
12
- export declare function getPatchInstructions<TData extends wgsl.BaseData>(schema: TData, data: unknown, targetBuffer?: ArrayBuffer): WriteInstruction[];
14
+ /**
15
+ * @param validateRange Called for every byte range that is about to be written, before any data
16
+ * is written into `targetBuffer`. Returns how many bytes to upload for that range.
17
+ * Throwing from it leaves `targetBuffer` untouched.
18
+ */
19
+ export declare function getPatchInstructions<TData extends wgsl.BaseData>(schema: TData, data: unknown, targetBuffer?: ArrayBuffer, validateRange?: (start: number, end: number) => number): WriteInstruction[];
13
20
  export declare function patchArrayBuffer<T extends BaseData>(buffer: ArrayBuffer, schema: T, data: InferPatch<T>): void;
package/data/partialIO.js CHANGED
@@ -37,7 +37,12 @@ export function convertPartialToPatch(schema, data) {
37
37
  return data;
38
38
  }
39
39
  const isLittleEndian = getSystemEndianness() === 'little';
40
- export function getPatchInstructions(schema, data, targetBuffer) {
40
+ /**
41
+ * @param validateRange Called for every byte range that is about to be written, before any data
42
+ * is written into `targetBuffer`. Returns how many bytes to upload for that range.
43
+ * Throwing from it leaves `targetBuffer` untouched.
44
+ */
45
+ export function getPatchInstructions(schema, data, targetBuffer, validateRange) {
41
46
  const totalSize = sizeOf(schema);
42
47
  if (totalSize === 0 || data === undefined || data === null) {
43
48
  return [];
@@ -46,6 +51,8 @@ export function getPatchInstructions(schema, data, targetBuffer) {
46
51
  const writer = new BufferWriter(buf);
47
52
  const compiledView = new DataView(buf);
48
53
  const segments = [];
54
+ // Deferred until every range is validated
55
+ const pendingWrites = [];
49
56
  function collect(node, value, offset, padding) {
50
57
  if (value === undefined || value === null) {
51
58
  return;
@@ -67,7 +74,9 @@ export function getPatchInstructions(schema, data, targetBuffer) {
67
74
  const elementPadding = elementSize - sizeOf(arrSchema.elementType);
68
75
  if (ArrayBuffer.isView(value)) {
69
76
  const copyLen = Math.min(value.byteLength, arrSchema.elementCount * elementSize);
70
- new Uint8Array(buf, offset, copyLen).set(new Uint8Array(value.buffer, value.byteOffset, copyLen));
77
+ pendingWrites.push(() => {
78
+ new Uint8Array(buf, offset, copyLen).set(new Uint8Array(value.buffer, value.byteOffset, copyLen));
79
+ });
71
80
  segments.push({ start: offset, end: offset + copyLen, padding });
72
81
  return;
73
82
  }
@@ -88,17 +97,19 @@ export function getPatchInstructions(schema, data, targetBuffer) {
88
97
  }
89
98
  const leafSize = sizeOf(node);
90
99
  const compiledWriter = getCompiledWriter(node);
91
- if (compiledWriter) {
92
- compiledWriter(compiledView, offset, value, isLittleEndian, offset + leafSize);
93
- }
94
- else {
95
- writer.seekTo(offset);
96
- writeData(writer, node, value);
97
- }
100
+ pendingWrites.push(() => {
101
+ if (compiledWriter) {
102
+ compiledWriter(compiledView, offset, value, isLittleEndian, offset + leafSize);
103
+ }
104
+ else {
105
+ writer.seekTo(offset);
106
+ writeData(writer, node, value);
107
+ }
108
+ });
98
109
  segments.push({ start: offset, end: offset + leafSize, padding });
99
110
  }
100
111
  collect(schema, data, 0);
101
- const instructions = [];
112
+ const runs = [];
102
113
  let run = null;
103
114
  for (const seg of segments) {
104
115
  if (run && seg.start === run.end + (run.padding ?? 0)) {
@@ -106,21 +117,27 @@ export function getPatchInstructions(schema, data, targetBuffer) {
106
117
  }
107
118
  else {
108
119
  if (run) {
109
- instructions.push({
110
- gpuOffset: run.start,
111
- data: new Uint8Array(buf, run.start, run.end - run.start).slice(),
112
- });
120
+ runs.push(run);
113
121
  }
114
122
  run = seg;
115
123
  }
116
124
  }
117
125
  if (run) {
118
- instructions.push({
119
- gpuOffset: run.start,
120
- data: new Uint8Array(buf, run.start, run.end - run.start).slice(),
121
- });
126
+ runs.push(run);
127
+ }
128
+ const uploads = runs.map(({ start, end }) => ({
129
+ start,
130
+ end,
131
+ uploadSize: validateRange?.(start, end) ?? end - start,
132
+ }));
133
+ for (const write of pendingWrites) {
134
+ write();
122
135
  }
123
- return instructions;
136
+ return uploads.map(({ start, end, uploadSize }) => ({
137
+ gpuOffset: start,
138
+ data: new Uint8Array(buf, start, end - start).slice(),
139
+ uploadSize,
140
+ }));
124
141
  }
125
142
  export function patchArrayBuffer(buffer, schema, data) {
126
143
  const instructions = getPatchInstructions(schema, data, buffer);
package/data/ref.js CHANGED
@@ -4,7 +4,7 @@ import { setName } from "../shared/meta.js";
4
4
  import { $gpuCallable, $internal, $ownSnippet, $resolve } from "../shared/symbols.js";
5
5
  import { UnknownData } from "./dataTypes.js";
6
6
  import { createPtrFromOrigin, explicitFrom } from "./ptr.js";
7
- import { isAlias, snip, withDataType } from "./snippet.js";
7
+ import { isStoredInMemory, snip, withDataType, } from "./snippet.js";
8
8
  import { isNaturallyEphemeral, isPtr } from "./wgslTypes.js";
9
9
  export const _ref = (() => {
10
10
  const impl = ((value) => INTERNAL_createRef(value));
@@ -23,7 +23,7 @@ export const _ref = (() => {
23
23
  - Try 'd.ref(${typeStr}(${value}));' instead to create a new referencable value.
24
24
  -----`);
25
25
  }
26
- if (isAlias(value) && isNaturallyEphemeral(value.dataType)) {
26
+ if (isStoredInMemory(value) && isNaturallyEphemeral(value.dataType)) {
27
27
  const typeStr = ctx.resolve(value.dataType).value;
28
28
  throw new WgslTypeError(stitch `d.ref(${value}) is illegal, cannot take a reference to a scalar value.
29
29
  -----
package/data/snippet.d.ts CHANGED
@@ -1,36 +1,41 @@
1
1
  import type { UnknownData } from './dataTypes.ts';
2
2
  import { type BaseData } from './wgslTypes.ts';
3
- export type Origin = 'uniform' | 'readonly' | 'mutable' | 'workgroup' | 'private' | 'handle' | 'function' | 'local-def' | 'constant-immutable-def' | 'runtime-immutable-def' | 'argument' | 'runtime' | 'constant';
3
+ export type Origin = 'uniform' | 'readonly' | 'mutable' | 'workgroup' | 'private' | 'handle' | 'immediate' | 'function' | 'local-def' | 'constant-immutable-def' | 'runtime-immutable-def' | 'argument' | 'runtime' | 'constant';
4
4
  /**
5
5
  * What happens to a snippet's origin when it's deep copied in JS, and left as is in WGSL?
6
6
  * e.g. `vec3f(vec3f(0, 1, 2))`
7
7
  */
8
8
  export declare function fallthroughCopyOrigin(origin: Origin): Origin;
9
9
  /**
10
- * Whether a snippet aliases a value that lives outside the current expression.
10
+ * Whether a snippet refers to a value already stored in memory.
11
11
  *
12
12
  * @example
13
13
  * ```ts
14
14
  * function foo(a: number) {
15
+ * 'use gpu';
15
16
  * const color = d.vec3f(1, 2, 3);
16
17
  * return color * a;
17
18
  * }
18
19
  *
19
- * // References:
20
+ * // Stored in memory:
20
21
  * // - color
21
22
  * // - a
22
23
  * //
23
- * // Not references:
24
+ * // Ephemeral values:
24
25
  * // - d.vec3f(1, 2, 3)
25
26
  * // - color * a
26
27
  * ```
27
28
  */
28
- export declare function isAlias(snippet: Snippet): boolean;
29
+ export declare function isStoredInMemory(snippet: Snippet): boolean;
29
30
  export declare const originToPtrParams: {
30
31
  readonly uniform: {
31
32
  readonly space: "uniform";
32
33
  readonly access: "read";
33
34
  };
35
+ readonly immediate: {
36
+ readonly space: "immediate";
37
+ readonly access: "read";
38
+ };
34
39
  readonly readonly: {
35
40
  readonly space: "storage";
36
41
  readonly access: "read";
@@ -57,6 +62,7 @@ export declare const originToPtrParams: {
57
62
  };
58
63
  };
59
64
  export type OriginToPtrParams = typeof originToPtrParams;
65
+ export declare function isAddressableOrigin(origin: Origin): origin is keyof OriginToPtrParams;
60
66
  export interface Snippet {
61
67
  readonly value: unknown;
62
68
  /**
package/data/snippet.js CHANGED
@@ -16,29 +16,31 @@ export function fallthroughCopyOrigin(origin) {
16
16
  return 'runtime';
17
17
  }
18
18
  /**
19
- * Whether a snippet aliases a value that lives outside the current expression.
19
+ * Whether a snippet refers to a value already stored in memory.
20
20
  *
21
21
  * @example
22
22
  * ```ts
23
23
  * function foo(a: number) {
24
+ * 'use gpu';
24
25
  * const color = d.vec3f(1, 2, 3);
25
26
  * return color * a;
26
27
  * }
27
28
  *
28
- * // References:
29
+ * // Stored in memory:
29
30
  * // - color
30
31
  * // - a
31
32
  * //
32
- * // Not references:
33
+ * // Ephemeral values:
33
34
  * // - d.vec3f(1, 2, 3)
34
35
  * // - color * a
35
36
  * ```
36
37
  */
37
- export function isAlias(snippet) {
38
+ export function isStoredInMemory(snippet) {
38
39
  return !(snippet.origin === 'runtime' || snippet.origin === 'constant');
39
40
  }
40
41
  export const originToPtrParams = {
41
42
  uniform: { space: 'uniform', access: 'read' },
43
+ immediate: { space: 'immediate', access: 'read' },
42
44
  readonly: { space: 'storage', access: 'read' },
43
45
  mutable: { space: 'storage', access: 'read-write' },
44
46
  workgroup: { space: 'workgroup', access: 'read-write' },
@@ -47,6 +49,9 @@ export const originToPtrParams = {
47
49
  // Local declarations are also in the `function` address space
48
50
  'local-def': { space: 'function', access: 'read-write' },
49
51
  };
52
+ export function isAddressableOrigin(origin) {
53
+ return origin in originToPtrParams;
54
+ }
50
55
  class SnippetImpl {
51
56
  value;
52
57
  dataType;
@@ -709,6 +709,7 @@ export interface Mat2x2f extends BaseData {
709
709
  readonly [$validUniformSchema]: true;
710
710
  (...elements: [number, number, number, number]): m2x2f;
711
711
  (...columns: [v2f, v2f]): m2x2f;
712
+ (other: m2x2f): m2x2f;
712
713
  (): m2x2f;
713
714
  identity(): m2x2f;
714
715
  }
@@ -724,6 +725,7 @@ export interface Mat3x3f extends BaseData {
724
725
  readonly [$validUniformSchema]: true;
725
726
  (...elements: [number, number, number, number, number, number, number, number, number]): m3x3f;
726
727
  (...columns: [v3f, v3f, v3f]): m3x3f;
728
+ (other: m3x3f): m3x3f;
727
729
  (): m3x3f;
728
730
  identity(): m3x3f;
729
731
  }
@@ -739,6 +741,7 @@ export interface Mat4x4f extends BaseData {
739
741
  readonly [$validUniformSchema]: true;
740
742
  (...elements: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]): m4x4f;
741
743
  (...columns: [v4f, v4f, v4f, v4f]): m4x4f;
744
+ (other: m4x4f): m4x4f;
742
745
  (): m4x4f;
743
746
  identity(): m4x4f;
744
747
  translation(vec: v3f): m4x4f;
@@ -810,7 +813,7 @@ export interface WgslStruct<out TProps extends Record<string, BaseData> = Record
810
813
  }
811
814
  /** @deprecated Just use `WgslStruct` without any type parameters */
812
815
  export type AnyWgslStruct = WgslStruct;
813
- export type AddressSpace = 'uniform' | 'storage' | 'workgroup' | 'private' | 'function' | 'handle';
816
+ export type AddressSpace = 'uniform' | 'storage' | 'workgroup' | 'private' | 'function' | 'handle' | 'immediate';
814
817
  export type Access = 'read' | 'write' | 'read-write';
815
818
  export interface Ptr<TAddr extends AddressSpace = AddressSpace, TInner extends BaseData = BaseData, TAccess extends Access = Access> extends BaseData {
816
819
  readonly type: 'ptr';
package/errors.d.ts CHANGED
@@ -3,6 +3,7 @@ import type { TgpuSlot } from './core/slot/slotTypes.ts';
3
3
  import type { TgpuVertexLayout } from './core/vertexLayout/vertexLayout.ts';
4
4
  import type { BaseData } from './data/wgslTypes.ts';
5
5
  import type { TgpuBindGroupLayout } from './tgpuBindGroupLayout.ts';
6
+ import type * as tinyest from 'tinyest';
6
7
  /**
7
8
  * Inspired by: https://github.com/alexreardon/tiny-invariant/blob/master/src/tiny-invariant.ts
8
9
  */
@@ -51,6 +52,9 @@ export declare class MissingBindGroupsError extends Error {
51
52
  export declare class MissingVertexBuffersError extends Error {
52
53
  constructor(layouts: Iterable<TgpuVertexLayout>);
53
54
  }
55
+ export declare class MissingImmediatesError extends Error {
56
+ constructor(name: string | undefined);
57
+ }
54
58
  export declare class IllegalVarAccessError extends Error {
55
59
  constructor(msg: string);
56
60
  }
@@ -60,6 +64,9 @@ export declare class IllegalBufferAccessError extends Error {
60
64
  export declare class WgslTypeError extends Error {
61
65
  constructor(msg: string);
62
66
  }
67
+ export declare class WgslForbiddenStatementError extends Error {
68
+ constructor(node: tinyest.AnyNode);
69
+ }
63
70
  export declare class SignatureNotSupportedError extends Error {
64
71
  constructor(actual: BaseData[], candidates: BaseData[]);
65
72
  }
package/errors.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { getName, hasTinyestMetadata } from "./shared/meta.js";
2
2
  import { DEV, TEST } from "./shared/env.js";
3
+ import { stringifyNode } from "./shared/tseynit.js";
3
4
  const prefix = 'Invariant failed';
4
5
  /**
5
6
  * Inspired by: https://github.com/alexreardon/tiny-invariant/blob/master/src/tiny-invariant.ts
@@ -115,6 +116,13 @@ export class MissingVertexBuffersError extends Error {
115
116
  Object.setPrototypeOf(this, MissingVertexBuffersError.prototype);
116
117
  }
117
118
  }
119
+ export class MissingImmediatesError extends Error {
120
+ constructor(name) {
121
+ super(`Missing value for immediate variable '${name ?? '<unnamed>'}'. Please provide it using pipeline.with(immediate, value), pass.setImmediates(immediate, value), or give the variable a default value`);
122
+ // Set the prototype explicitly.
123
+ Object.setPrototypeOf(this, MissingImmediatesError.prototype);
124
+ }
125
+ }
118
126
  export class IllegalVarAccessError extends Error {
119
127
  constructor(msg) {
120
128
  super(msg);
@@ -136,6 +144,13 @@ export class WgslTypeError extends Error {
136
144
  Object.setPrototypeOf(this, WgslTypeError.prototype);
137
145
  }
138
146
  }
147
+ export class WgslForbiddenStatementError extends Error {
148
+ constructor(node) {
149
+ super(`Expression statements like '${stringifyNode(node)};' are forbidden in WGSL. Remove the statement, or use the result in code (for example, assign it to a variable).`);
150
+ // Set the prototype explicitly.
151
+ Object.setPrototypeOf(this, WgslForbiddenStatementError.prototype);
152
+ }
153
+ }
139
154
  export class SignatureNotSupportedError extends Error {
140
155
  constructor(actual, candidates) {
141
156
  super(`Unsupported data types: ${actual
@@ -1,7 +1,7 @@
1
1
  export * as d from './data/index.ts';
2
2
  export * as std from './std/index.ts';
3
3
  export * as common from './common/index.ts';
4
- export { MissingBindGroupsError, MissingSlotValueError, MissingVertexBuffersError, NotUniformError, ResolutionError, } from './errors.ts';
4
+ export { MissingBindGroupsError, MissingImmediatesError, MissingSlotValueError, MissingVertexBuffersError, NotUniformError, ResolutionError, } from './errors.ts';
5
5
  export { isAccessor, isLazy, isMutableAccessor, isSlot } from './core/slot/slotTypes.ts';
6
6
  export { isComparisonSampler, isSampler } from './core/sampler/sampler.ts';
7
7
  export { isTexture } from './core/texture/texture.ts';
@@ -17,6 +17,7 @@ export { isComputePipeline, isPipeline, isRenderPipeline } from './core/pipeline
17
17
  export { isQuerySet } from './core/querySet/querySet.ts';
18
18
  export { isVariable } from './core/variable/tgpuVariable.ts';
19
19
  export { isVertexLayout } from './core/vertexLayout/vertexLayout.ts';
20
+ export { isImmediateVar } from './core/immediate/immediateVar.ts';
20
21
  export type {
21
22
  /** @deprecated Import from 'typegpu/~internal' instead */ ShaderGenerator, } from './tgsl/shaderGenerator.ts';
22
23
  export {
@@ -40,12 +41,14 @@ export type { TgpuBufferMutable, TgpuBufferReadonly, TgpuBufferUniform, } from '
40
41
  export type { TgpuBufferBinding, TgpuMutable, TgpuReadonly, TgpuUniform, } from './core/buffer/bufferBinding.ts';
41
42
  export type { Eventual, TgpuAccessor, TgpuLazy, TgpuMutableAccessor, TgpuSlot, } from './core/slot/slotTypes.ts';
42
43
  export type { RawCodeSnippetOrigin, TgpuRawCodeSnippet, } from './core/rawCodeSnippet/tgpuRawCodeSnippet.ts';
43
- export type { TextureWriteFit, TextureWriteOptions, TgpuTexture, TgpuTextureView, } from './core/texture/texture.ts';
44
+ export type { TgpuTexture, TgpuTextureView } from './core/texture/texture.ts';
45
+ export type { TextureBlobWriteOptions, TextureChannel, TextureCopyOptions, TextureRawWriteOptions, TextureWriteFit, TextureWriteOptions, } from './core/texture/textureWrite.ts';
44
46
  export type { TextureProps } from './core/texture/textureProps.ts';
45
47
  export type { RenderFlag, SampledFlag } from './core/texture/usageExtension.ts';
46
48
  export type { InitFromDeviceOptions, InitOptions } from './core/root/init.ts';
47
49
  export type { TgpuConst } from './core/constant/tgpuConstant.ts';
48
50
  export type { TgpuVar, VariableScope } from './core/variable/tgpuVariable.ts';
51
+ export type { TgpuImmediateVar } from './core/immediate/immediateVar.ts';
49
52
  export type { TgpuComparisonSampler, TgpuFixedComparisonSampler, TgpuFixedSampler, TgpuSampler, } from './core/sampler/sampler.ts';
50
53
  export type { TgpuQuerySet } from './core/querySet/querySet.ts';
51
54
  export type { ExtractBindGroupInputFromLayout, LayoutEntryToInput, TgpuBindGroup, TgpuBindGroupLayout, TgpuLayoutComparisonSampler, TgpuLayoutEntry, TgpuLayoutExternalTexture, TgpuLayoutSampler, TgpuLayoutStorage, TgpuLayoutTexture, TgpuLayoutUniform, } from './tgpuBindGroupLayout.ts';
@@ -2,7 +2,7 @@
2
2
  export * as d from "./data/index.js";
3
3
  export * as std from "./std/index.js";
4
4
  export * as common from "./common/index.js";
5
- export { MissingBindGroupsError, MissingSlotValueError, MissingVertexBuffersError, NotUniformError, ResolutionError, } from "./errors.js";
5
+ export { MissingBindGroupsError, MissingImmediatesError, MissingSlotValueError, MissingVertexBuffersError, NotUniformError, ResolutionError, } from "./errors.js";
6
6
  export { isAccessor, isLazy, isMutableAccessor, isSlot } from "./core/slot/slotTypes.js";
7
7
  export { isComparisonSampler, isSampler } from "./core/sampler/sampler.js";
8
8
  export { isTexture } from "./core/texture/texture.js";
@@ -18,6 +18,7 @@ export { isComputePipeline, isPipeline, isRenderPipeline } from "./core/pipeline
18
18
  export { isQuerySet } from "./core/querySet/querySet.js";
19
19
  export { isVariable } from "./core/variable/tgpuVariable.js";
20
20
  export { isVertexLayout } from "./core/vertexLayout/vertexLayout.js";
21
+ export { isImmediateVar } from "./core/immediate/immediateVar.js";
21
22
  export {
22
23
  /** @deprecated Import from 'typegpu/~internal' instead */ WgslGenerator, } from "./tgsl/wgslGenerator.js";
23
24
  export { readFromArrayBuffer, writeToArrayBuffer } from "./data/dataIO.js";
package/internal.d.ts CHANGED
@@ -5,7 +5,7 @@ export { UnknownData } from './data/dataTypes.ts';
5
5
  export { getName, setName } from './shared/meta.ts';
6
6
  export { WgslGenerator } from './tgsl/wgslGenerator.ts';
7
7
  export { snip, withValue, withDataType, withSideEffects } from './data/snippet.ts';
8
- export { stringifyNode } from './shared/tseynit.ts';
8
+ export { stringifyNode, stringifyObjectProperty } from './shared/tseynit.ts';
9
9
  export { dualImpl } from './core/function/dualImpl.ts';
10
10
  export { isNonTransferableResource, isTransferableResource, restoreResource, snapshotResource, } from './serial/registry.ts';
11
11
  export type { TgpuResourceSnapshot, TransferableResourceType } from './serial/registry.ts';
@@ -13,4 +13,5 @@ export type { RestoreContext } from './serial/types.ts';
13
13
  export { deserializeDataSchema, serializeDataSchema, type SerializedDataSchema, } from './serial/schema.ts';
14
14
  export type { ResolutionCtx, FunctionArgument } from './types.ts';
15
15
  export type { Snippet, ResolvedSnippet, Origin } from './data/snippet.ts';
16
+ export type { AutoStruct } from './data/autoStruct.ts';
16
17
  export type { ShaderGenerator, ResolvedStatement, BinaryOperator, ShaderGeneratorClass, FunctionDefinitionOptions, ConstantDefinitionOptions, VariableDefinitionOptions, } from './tgsl/shaderGenerator.ts';
package/internal.js CHANGED
@@ -6,7 +6,7 @@ export { UnknownData } from "./data/dataTypes.js";
6
6
  export { getName, setName } from "./shared/meta.js";
7
7
  export { WgslGenerator } from "./tgsl/wgslGenerator.js";
8
8
  export { snip, withValue, withDataType, withSideEffects } from "./data/snippet.js";
9
- export { stringifyNode } from "./shared/tseynit.js";
9
+ export { stringifyNode, stringifyObjectProperty } from "./shared/tseynit.js";
10
10
  export { dualImpl } from "./core/function/dualImpl.js";
11
11
  export { isNonTransferableResource, isTransferableResource, restoreResource, snapshotResource, } from "./serial/registry.js";
12
12
  export { deserializeDataSchema, serializeDataSchema, } from "./serial/schema.js";
package/nameUtils.d.ts CHANGED
@@ -1,4 +1,11 @@
1
1
  export declare const bannedTokens: Set<string>;
2
+ /**
3
+ * Predeclared enumerants that appear as template parameters, e.g. `var<storage, read_write>` or
4
+ * `texture_storage_2d<rgba8unorm, write>`. A module-scope or local declaration with one of these names
5
+ * would shadow the enumerant, so a template using it would refer to the declaration instead.
6
+ * Unlike `bannedTokens`, these remain valid as struct member names, which never shadow anything.
7
+ */
8
+ export declare const templateEnumerants: Set<string>;
2
9
  export declare const builtins: Set<string>;
3
10
  /**
4
11
  * Sanitizes the primer so that it is compliant with WGSL guidelines.