typegpu 0.11.3 → 0.11.5

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 (59) hide show
  1. package/README.md +4 -2
  2. package/core/buffer/buffer.js +17 -53
  3. package/core/buffer/bufferUsage.js +2 -2
  4. package/core/constant/tgpuConstant.js +1 -1
  5. package/core/function/fnCore.js +12 -6
  6. package/core/function/tgpuFragmentFn.d.ts +1 -1
  7. package/core/pipeline/computePipeline.d.ts +1 -1
  8. package/core/pipeline/computePipeline.js +1 -1
  9. package/core/pipeline/renderPipeline.js +1 -1
  10. package/core/resolve/namespace.d.ts +2 -11
  11. package/core/resolve/namespace.js +7 -24
  12. package/core/resolve/resolveData.js +3 -2
  13. package/core/resolve/tgpuResolve.js +1 -1
  14. package/core/root/init.d.ts +1 -0
  15. package/core/root/init.js +6 -0
  16. package/core/root/rootTypes.d.ts +21 -15
  17. package/core/sampler/sampler.js +2 -2
  18. package/core/simulate/tgpuSimulate.js +1 -1
  19. package/core/slot/accessor.js +1 -1
  20. package/core/texture/externalTexture.js +1 -1
  21. package/core/texture/texture.js +2 -2
  22. package/core/variable/tgpuVariable.js +1 -1
  23. package/data/autoStruct.js +3 -2
  24. package/data/dataIO.d.ts +11 -0
  25. package/data/dataIO.js +45 -1
  26. package/data/dataTypes.d.ts +1 -1
  27. package/data/dataTypes.js +2 -11
  28. package/data/partialIO.d.ts +8 -0
  29. package/data/partialIO.js +6 -1
  30. package/data/struct.js +3 -2
  31. package/data/wgslTypes.d.ts +16 -16
  32. package/index.d.ts +3 -1
  33. package/index.js +3 -1
  34. package/indexNamedExports.d.ts +2 -0
  35. package/{nameRegistry.js → nameUtils.js} +46 -90
  36. package/package.js +1 -1
  37. package/package.json +1 -1
  38. package/resolutionCtx.js +64 -30
  39. package/shared/stringify.js +1 -0
  40. package/shared/tseynit.js +90 -0
  41. package/std/copy.d.ts +7 -0
  42. package/std/copy.js +27 -0
  43. package/std/index.d.ts +3 -2
  44. package/std/index.js +3 -1
  45. package/tgpuUnstable.js +1 -1
  46. package/tgsl/accessIndex.js +2 -1
  47. package/tgsl/consoleLog/deserializers.js +1 -1
  48. package/tgsl/consoleLog/logGenerator.js +1 -6
  49. package/tgsl/consoleLog/types.d.ts +4 -5
  50. package/tgsl/conversion.js +4 -1
  51. package/tgsl/generationHelpers.d.ts +2 -1
  52. package/tgsl/jsPolyfills.d.ts +25 -0
  53. package/tgsl/jsPolyfills.js +44 -0
  54. package/tgsl/wgslGenerator.d.ts +20 -2
  55. package/tgsl/wgslGenerator.js +114 -57
  56. package/types.d.ts +29 -2
  57. package/nameRegistry.d.ts +0 -30
  58. package/tgsl/consoleLog/types.js +0 -12
  59. package/tgsl/math.js +0 -45
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  <div align="center">
2
2
 
3
- ![TypeGPU (light mode)](/apps/typegpu-docs/public/typegpu-logo-light.svg#gh-light-mode-only)
4
-
3
+ <picture>
4
+ <source srcset="https://typegpu.com/typegpu-logo-dark.svg" media="(prefers-color-scheme: dark)" />
5
+ <img src="https://typegpu.com/typegpu-logo-light.svg" />
6
+ </picture>
5
7
 
6
8
  [Website](https://docs.swmansion.com/TypeGPU) —
7
9
  [Documentation](https://docs.swmansion.com/TypeGPU/getting-started)
@@ -1,15 +1,12 @@
1
1
  import { $internal } from "../../shared/symbols.js";
2
2
  import { getName, setName } from "../../shared/meta.js";
3
- import { isWgslArray, isWgslData } from "../../data/wgslTypes.js";
3
+ import { isWgslData } from "../../data/wgslTypes.js";
4
4
  import { isGPUBuffer } from "../../types.js";
5
- import { alignmentOf } from "../../data/alignmentOf.js";
6
- import { roundUp } from "../../mathUtils.js";
7
5
  import { sizeOf } from "../../data/sizeOf.js";
8
6
  import { getCompiledWriter } from "../../data/compiledIO.js";
9
- import { readData, writeData } from "../../data/dataIO.js";
10
- import { convertPartialToPatch, getPatchInstructions } from "../../data/partialIO.js";
7
+ import { calculateOffsets, readFromArrayBuffer, writeToArrayBuffer } from "../../data/dataIO.js";
8
+ import { convertPartialToPatch, getPatchInstructions, patchArrayBuffer } from "../../data/partialIO.js";
11
9
  import { mutable, readonly, uniform } from "./bufferUsage.js";
12
- import { BufferReader, BufferWriter, getSystemEndianness } from "typed-binary";
13
10
 
14
11
  //#region src/core/buffer/buffer.ts
15
12
  const usageToUsageConstructor = {
@@ -27,7 +24,6 @@ function isBuffer(value) {
27
24
  function isUsableAsVertex(buffer) {
28
25
  return !!buffer.usableAsVertex;
29
26
  }
30
- const endianness = getSystemEndianness();
31
27
  var TgpuBufferImpl = class {
32
28
  [$internal] = true;
33
29
  resourceType = "buffer";
@@ -74,7 +70,7 @@ var TgpuBufferImpl = class {
74
70
  });
75
71
  if (this.initial || this.#initialCallback) {
76
72
  if (this.#initialCallback) this.#initialCallback(this);
77
- else if (this.initial) this.#writeToTarget(this.#getMappedRange(), this.initial);
73
+ else if (this.initial) writeToArrayBuffer(this.#getMappedRange(), this.dataType, this.initial);
78
74
  this.#unmapBuffer();
79
75
  }
80
76
  }
@@ -134,62 +130,30 @@ var TgpuBufferImpl = class {
134
130
  compileWriter() {
135
131
  getCompiledWriter(this.dataType);
136
132
  }
137
- #writeToTarget(target, data, options) {
138
- const startOffset = options?.startOffset ?? 0;
139
- const endOffset = options?.endOffset ?? target.byteLength;
140
- if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
141
- const src = data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
142
- const regionSize = endOffset - startOffset;
143
- if (src.byteLength !== regionSize) console.warn(`Buffer size mismatch: expected ${regionSize} bytes, got ${src.byteLength}. ` + (src.byteLength < regionSize ? "Data truncated." : "Excess ignored."));
144
- const copyLen = Math.min(src.byteLength, regionSize);
145
- new Uint8Array(target).set(src.subarray(0, copyLen), startOffset);
146
- return;
147
- }
148
- const dataView = new DataView(target);
149
- const isLittleEndian = endianness === "little";
150
- const compiledWriter = getCompiledWriter(this.dataType);
151
- if (compiledWriter) try {
152
- compiledWriter(dataView, startOffset, data, isLittleEndian, endOffset);
153
- return;
154
- } catch (error) {
155
- console.error(`Error when using compiled writer for buffer ${getName(this) ?? "<unnamed>"} - this is likely a bug, please submit an issue at https://github.com/software-mansion/TypeGPU/issues\nUsing fallback writer instead.`, error);
156
- }
157
- const writer = new BufferWriter(target);
158
- writer.seekTo(startOffset);
159
- writeData(writer, this.dataType, data);
160
- }
161
133
  write(data, options) {
162
134
  const gpuBuffer = this.buffer;
163
- const bufferSize = sizeOf(this.dataType);
164
- const startOffset = options?.startOffset ?? 0;
165
- let naturalSize = void 0;
166
- if (isWgslArray(this.dataType) && Array.isArray(data)) naturalSize = data.length * roundUp(sizeOf(this.dataType.elementType), alignmentOf(this.dataType.elementType));
167
- else if (ArrayBuffer.isView(data) || data instanceof ArrayBuffer) naturalSize = data.byteLength;
168
- const naturalEndOffset = naturalSize !== void 0 ? Math.min(startOffset + naturalSize, bufferSize) : void 0;
169
- const size = (options?.endOffset ?? naturalEndOffset ?? bufferSize) - startOffset;
170
135
  if (gpuBuffer.mapState === "mapped") {
171
136
  const mapped = this.#getMappedRange();
172
137
  if (data instanceof ArrayBuffer && data === mapped) return;
173
- this.#writeToTarget(mapped, data, options);
138
+ writeToArrayBuffer(mapped, this.dataType, data, options);
174
139
  return;
175
140
  }
176
- if (!(data instanceof ArrayBuffer && data === this.#hostBuffer)) this.#writeToTarget(this.#hostBuffer, data, options);
141
+ if (!(data instanceof ArrayBuffer && data === this.#hostBuffer)) writeToArrayBuffer(this.#hostBuffer, this.dataType, data, options);
142
+ const { startOffset, endOffset } = calculateOffsets(options, this.dataType, data);
143
+ const size = endOffset - startOffset;
177
144
  this.#device.queue.writeBuffer(gpuBuffer, startOffset, this.#hostBuffer, startOffset, size);
178
145
  }
179
146
  /** @deprecated Use {@link patch} instead. */
180
147
  writePartial(data) {
181
- this.#applyInstructions(getPatchInstructions(this.dataType, convertPartialToPatch(this.dataType, data), this.#hostBuffer));
148
+ this.patch(convertPartialToPatch(this.dataType, data));
182
149
  }
183
150
  patch(data) {
184
- this.#applyInstructions(getPatchInstructions(this.dataType, data, this.#hostBuffer));
185
- }
186
- #applyInstructions(instructions) {
187
151
  const gpuBuffer = this.buffer;
188
- if (gpuBuffer.mapState === "mapped") {
189
- const mappedRange = this.#getMappedRange();
190
- const mappedView = new Uint8Array(mappedRange);
191
- for (const { data, gpuOffset } of instructions) mappedView.set(data, gpuOffset);
192
- } else for (const { data, gpuOffset } of instructions) this.#device.queue.writeBuffer(gpuBuffer, gpuOffset, data);
152
+ if (gpuBuffer.mapState === "mapped") patchArrayBuffer(this.#getMappedRange(), this.dataType, data);
153
+ else {
154
+ const instructions = getPatchInstructions(this.dataType, data, this.#hostBuffer);
155
+ for (const { data: data$1, gpuOffset } of instructions) this.#device.queue.writeBuffer(gpuBuffer, gpuOffset, data$1);
156
+ }
193
157
  }
194
158
  clear() {
195
159
  const gpuBuffer = this.buffer;
@@ -210,10 +174,10 @@ var TgpuBufferImpl = class {
210
174
  }
211
175
  async read() {
212
176
  const gpuBuffer = this.buffer;
213
- if (gpuBuffer.mapState === "mapped") return readData(new BufferReader(this.#getMappedRange()), this.dataType);
177
+ if (gpuBuffer.mapState === "mapped") return readFromArrayBuffer(this.#getMappedRange(), this.dataType);
214
178
  if (gpuBuffer.usage & GPUBufferUsage.MAP_READ) {
215
179
  await gpuBuffer.mapAsync(GPUMapMode.READ);
216
- const res$1 = readData(new BufferReader(this.#getMappedRange()), this.dataType);
180
+ const res$1 = readFromArrayBuffer(this.#getMappedRange(), this.dataType);
217
181
  this.#unmapBuffer();
218
182
  return res$1;
219
183
  }
@@ -225,7 +189,7 @@ var TgpuBufferImpl = class {
225
189
  commandEncoder.copyBufferToBuffer(gpuBuffer, 0, stagingBuffer, 0, sizeOf(this.dataType));
226
190
  this.#device.queue.submit([commandEncoder.finish()]);
227
191
  await stagingBuffer.mapAsync(GPUMapMode.READ, 0, sizeOf(this.dataType));
228
- const res = readData(new BufferReader(stagingBuffer.getMappedRange()), this.dataType);
192
+ const res = readFromArrayBuffer(stagingBuffer.getMappedRange(), this.dataType);
229
193
  stagingBuffer.unmap();
230
194
  stagingBuffer.destroy();
231
195
  return res;
@@ -36,7 +36,7 @@ var TgpuFixedBufferImpl = class {
36
36
  }
37
37
  [$resolve](ctx) {
38
38
  const dataType = this.buffer.dataType;
39
- const id = ctx.getUniqueName(this);
39
+ const id = ctx.makeUniqueIdentifier(getName(this), "global");
40
40
  const { group, binding } = ctx.allocateFixedEntry(this.usage === "uniform" ? { uniform: dataType } : {
41
41
  storage: dataType,
42
42
  access: this.usage
@@ -103,7 +103,7 @@ var TgpuLaidOutBufferImpl = class {
103
103
  setName(this, membership.key);
104
104
  }
105
105
  [$resolve](ctx) {
106
- const id = ctx.getUniqueName(this);
106
+ const id = ctx.makeUniqueIdentifier(getName(this), "global");
107
107
  const group = ctx.allocateLayoutEntry(this.#membership.layout);
108
108
  const usage = usageToVarTemplateMap[this.usage];
109
109
  ctx.addDeclaration(`@group(${group}) @binding(${this.#membership.idx}) var<${usage}> ${id}: ${ctx.resolve(this.dataType).value};`);
@@ -37,7 +37,7 @@ var TgpuConstImpl = class {
37
37
  return this;
38
38
  }
39
39
  [$resolve](ctx) {
40
- const id = ctx.getUniqueName(this);
40
+ const id = ctx.makeUniqueIdentifier(getName(this), "global");
41
41
  const resolvedDataType = ctx.resolve(this.dataType).value;
42
42
  const resolvedValue = ctx.resolve(this.#value, this.dataType).value;
43
43
  ctx.addDeclaration(`const ${id}: ${resolvedDataType} = ${resolvedValue};`);
@@ -5,6 +5,7 @@ import { undecorate } from "../../data/dataTypes.js";
5
5
  import { snip } from "../../data/snippet.js";
6
6
  import { MissingLinksError } from "../../errors.js";
7
7
  import { getAttributesString } from "../../data/attributes.js";
8
+ import { validateIdentifier } from "../../nameUtils.js";
8
9
  import { applyExternals, replaceExternalsInWgsl } from "../resolve/externals.js";
9
10
  import { extractArgs } from "./extractArgs.js";
10
11
 
@@ -29,21 +30,26 @@ function createFnCore(implementation, functionType, workgroupSize) {
29
30
  else if (functionType === "vertex") attributes = `@vertex `;
30
31
  else if (functionType === "fragment") attributes = `@fragment `;
31
32
  for (const externals of externalsToApply) applyExternals(externalMap, externals);
32
- const id = ctx.getUniqueName(this);
33
+ const id = ctx.makeUniqueIdentifier(getName(this), "global");
33
34
  if (typeof implementation === "string") {
34
35
  if (!returnType) throw new Error("Explicit return type is required for string implementation");
35
- const validArgNames = entryInput ? Object.fromEntries(entryInput.positionalArgs.map((a) => [a.schemaKey, ctx.makeNameValid(a.schemaKey)])) : void 0;
36
- if (validArgNames && Object.keys(validArgNames).length > 0) applyExternals(externalMap, { in: validArgNames });
36
+ if (entryInput) {
37
+ for (const arg of entryInput.positionalArgs) {
38
+ const result = /* @__PURE__ */ validateIdentifier(arg.schemaKey);
39
+ if (!result.success) throw new Error(`Invalid argument name "${arg.schemaKey}"${result.error ? `: ${result.error}` : ""}`);
40
+ }
41
+ applyExternals(externalMap, { in: Object.fromEntries(entryInput.positionalArgs.map((a) => [a.schemaKey, a.schemaKey])) });
42
+ }
37
43
  const replacedImpl = replaceExternalsInWgsl(ctx, externalMap, implementation);
38
44
  let header = "";
39
45
  let body = "";
40
- if (functionType !== "normal" && entryInput && validArgNames) {
46
+ if (functionType !== "normal" && entryInput) {
41
47
  const { dataSchema, positionalArgs } = entryInput;
42
48
  const parts = [];
43
49
  if (dataSchema && isArgUsedInBody("in", replacedImpl)) parts.push(`in: ${ctx.resolve(dataSchema).value}`);
44
50
  for (const a of positionalArgs) {
45
- const argName = validArgNames[a.schemaKey] ?? "";
46
- if (argName !== "" && isArgUsedInBody(argName, replacedImpl)) parts.push(`${getAttributesString(a.type)}${argName}: ${ctx.resolve(a.type).value}`);
51
+ const argName = a.schemaKey;
52
+ if (isArgUsedInBody(argName, replacedImpl)) parts.push(`${getAttributesString(a.type)}${argName}: ${ctx.resolve(a.type).value}`);
47
53
  }
48
54
  const input = `(${parts.join(", ")})`;
49
55
  const attributes$1 = isWgslData(returnType) ? getAttributesString(returnType) : "";
@@ -2,9 +2,9 @@ import { TgpuNamable } from "../../shared/meta.js";
2
2
  import { $internal } from "../../shared/symbols.js";
3
3
  import { Prettify } from "../../shared/utilityTypes.js";
4
4
  import { AnyFragmentInputBuiltin, AnyFragmentOutputBuiltin, OmitBuiltins } from "../../builtin.js";
5
+ import { InstanceToSchema } from "../../data/instanceToSchema.js";
5
6
  import { BaseIOData, IOLayout, IORecord, InferIO } from "./fnTypes.js";
6
7
  import { AnyAutoCustoms, AutoFragmentIn, AutoFragmentOut } from "./autoIO.js";
7
- import { InstanceToSchema } from "../../data/instanceToSchema.js";
8
8
  import { IOLayoutToSchema } from "./ioSchema.js";
9
9
  import { BaseData, Decorated, Interpolate, Location, Vec4f, Vec4i, Vec4u, WgslStruct } from "../../data/wgslTypes.js";
10
10
  import { UndecorateRecord } from "../../data/dataTypes.js";
@@ -3,8 +3,8 @@ import { $internal } from "../../shared/symbols.js";
3
3
  import { AnyComputeBuiltin } from "../../builtin.js";
4
4
  import "../querySet/querySet.js";
5
5
  import "../../data/snippet.js";
6
- import "../../tgsl/consoleLog/types.js";
7
6
  import { IORecord } from "../function/fnTypes.js";
7
+ import "../../tgsl/consoleLog/types.js";
8
8
  import { TgpuComputeFn } from "../function/tgpuComputeFn.js";
9
9
  import "../slot/slotTypes.js";
10
10
  import { PrimitiveOffsetInfo } from "../../data/offsetUtils.js";
@@ -3,10 +3,10 @@ import { PERF, getName, setName } from "../../shared/meta.js";
3
3
  import { Void } from "../../data/wgslTypes.js";
4
4
  import { snip } from "../../data/snippet.js";
5
5
  import { isGPUBuffer } from "../../types.js";
6
- import { namespace } from "../resolve/namespace.js";
7
6
  import { isBindGroup } from "../../tgpuBindGroupLayout.js";
8
7
  import { resolve } from "../../resolutionCtx.js";
9
8
  import { isGPUCommandEncoder, isGPUComputePassEncoder } from "./typeGuards.js";
9
+ import { namespace } from "../resolve/namespace.js";
10
10
  import { applyBindGroups } from "./applyPipelineState.js";
11
11
  import { logDataFromGPU } from "../../tgsl/consoleLog/deserializers.js";
12
12
  import { wgslExtensionToFeatureName, wgslExtensions } from "../../wgslExtensions.js";
@@ -7,12 +7,12 @@ import { isGPUBuffer } from "../../types.js";
7
7
  import { formatToWGSLType } from "../../data/vertexFormatData.js";
8
8
  import { sizeOf } from "../../data/sizeOf.js";
9
9
  import { isBuiltin } from "../../data/attributes.js";
10
- import { namespace } from "../resolve/namespace.js";
11
10
  import { isTexture, isTextureView } from "../texture/texture.js";
12
11
  import { isBindGroup, isBindGroupLayout } from "../../tgpuBindGroupLayout.js";
13
12
  import { connectAttributesToShader } from "../vertexLayout/connectAttributesToShader.js";
14
13
  import { resolve } from "../../resolutionCtx.js";
15
14
  import { isGPUCommandEncoder, isGPURenderBundleEncoder, isGPURenderPassEncoder } from "./typeGuards.js";
15
+ import { namespace } from "../resolve/namespace.js";
16
16
  import { applyBindGroups, applyVertexBuffers } from "./applyPipelineState.js";
17
17
  import { logDataFromGPU } from "../../tgsl/consoleLog/deserializers.js";
18
18
  import { wgslExtensionToFeatureName, wgslExtensions } from "../../wgslExtensions.js";
@@ -2,13 +2,13 @@ import { $internal } from "../../shared/symbols.js";
2
2
  import { ResolvedSnippet } from "../../data/snippet.js";
3
3
  import { ShelllessRepository } from "../../tgsl/shellless.js";
4
4
  import { TgpuLazy, TgpuSlot } from "../slot/slotTypes.js";
5
- import { NameRegistry } from "../../nameRegistry.js";
6
5
 
7
6
  //#region src/core/resolve/namespace.d.ts
8
7
  type SlotToValueMap = Map<TgpuSlot<unknown>, unknown>;
9
8
  interface NamespaceInternal {
10
- readonly nameRegistry: NameRegistry;
9
+ readonly takenGlobalIdentifiers: Set<string>;
11
10
  readonly shelllessRepo: ShelllessRepository;
11
+ readonly strategy: 'random' | 'strict';
12
12
  memoizedResolves: WeakMap<object, {
13
13
  slotToValueMap: SlotToValueMap;
14
14
  result: ResolvedSnippet;
@@ -17,18 +17,9 @@ interface NamespaceInternal {
17
17
  slotToValueMap: SlotToValueMap;
18
18
  result: unknown;
19
19
  }[]>;
20
- listeners: { [K in keyof NamespaceEventMap]: Set<(event: NamespaceEventMap[K]) => void> };
21
20
  }
22
- type NamespaceEventMap = {
23
- name: {
24
- target: object;
25
- name: string;
26
- };
27
- };
28
- type DetachListener = () => void;
29
21
  interface Namespace {
30
22
  readonly [$internal]: NamespaceInternal;
31
- on<TEvent extends keyof NamespaceEventMap>(event: TEvent, listener: (event: NamespaceEventMap[TEvent]) => void): DetachListener;
32
23
  }
33
24
  interface NamespaceOptions {
34
25
  names?: 'random' | 'strict' | undefined;
@@ -1,41 +1,24 @@
1
1
  import { $internal } from "../../shared/symbols.js";
2
- import { getName } from "../../shared/meta.js";
3
- import { RandomNameRegistry, StrictNameRegistry } from "../../nameRegistry.js";
2
+ import { bannedTokens, builtins } from "../../nameUtils.js";
4
3
  import { ShelllessRepository } from "../../tgsl/shellless.js";
5
4
 
6
5
  //#region src/core/resolve/namespace.ts
7
6
  var NamespaceImpl = class {
8
7
  [$internal];
9
- constructor(nameRegistry) {
8
+ constructor(strategy) {
10
9
  this[$internal] = {
11
- nameRegistry,
10
+ strategy,
11
+ takenGlobalIdentifiers: new Set([...bannedTokens, ...builtins]),
12
12
  shelllessRepo: new ShelllessRepository(),
13
13
  memoizedResolves: /* @__PURE__ */ new WeakMap(),
14
- memoizedLazy: /* @__PURE__ */ new WeakMap(),
15
- listeners: { name: /* @__PURE__ */ new Set() }
14
+ memoizedLazy: /* @__PURE__ */ new WeakMap()
16
15
  };
17
16
  }
18
- on(event, listener) {
19
- if (event === "name") {
20
- const listeners = this[$internal].listeners.name;
21
- listeners.add(listener);
22
- return () => listeners.delete(listener);
23
- }
24
- throw new Error(`Unsupported event: ${event}`);
25
- }
26
17
  };
27
- function getUniqueName(namespace$1, resource) {
28
- const name = namespace$1.nameRegistry.makeUnique(getName(resource), true);
29
- for (const listener of namespace$1.listeners.name) listener({
30
- target: resource,
31
- name
32
- });
33
- return name;
34
- }
35
18
  function namespace(options) {
36
19
  const { names = "strict" } = options ?? {};
37
- return new NamespaceImpl(names === "strict" ? new StrictNameRegistry() : new RandomNameRegistry());
20
+ return new NamespaceImpl(names);
38
21
  }
39
22
 
40
23
  //#endregion
41
- export { getUniqueName, namespace };
24
+ export { namespace };
@@ -1,4 +1,5 @@
1
1
  import { $internal } from "../../shared/symbols.js";
2
+ import { getName } from "../../shared/meta.js";
2
3
  import { isLooseData } from "../../data/dataTypes.js";
3
4
  import { assertExhaustive } from "../../shared/utilityTypes.js";
4
5
  import { formatToWGSLType } from "../../data/vertexFormatData.js";
@@ -61,7 +62,7 @@ function resolveStructProperty(ctx, [key, property]) {
61
62
  */
62
63
  function resolveStruct(ctx, struct) {
63
64
  if (struct[$internal].isAbstruct) throw new Error("Cannot resolve abstract struct types to WGSL.");
64
- const id = ctx.getUniqueName(struct);
65
+ const id = ctx.makeUniqueIdentifier(getName(struct), "global");
65
66
  ctx.addDeclaration(`\
66
67
  struct ${id} {
67
68
  ${Object.entries(struct.propTypes).map((prop) => resolveStructProperty(ctx, prop)).join("")}\
@@ -84,7 +85,7 @@ ${Object.entries(struct.propTypes).map((prop) => resolveStructProperty(ctx, prop
84
85
  * ```
85
86
  */
86
87
  function resolveUnstruct(ctx, unstruct) {
87
- const id = ctx.getUniqueName(unstruct);
88
+ const id = ctx.makeUniqueIdentifier(getName(unstruct), "global");
88
89
  ctx.addDeclaration(`\
89
90
  struct ${id} {
90
91
  ${Object.entries(unstruct.propTypes).map((prop) => isAttribute(prop[1]) ? resolveStructProperty(ctx, [prop[0], formatToWGSLType[prop[1].format]]) : resolveStructProperty(ctx, prop)).join("")}
@@ -2,10 +2,10 @@ import { $internal, $resolve } from "../../shared/symbols.js";
2
2
  import { Void } from "../../data/wgslTypes.js";
3
3
  import { snip } from "../../data/snippet.js";
4
4
  import { applyExternals, replaceExternalsInWgsl } from "./externals.js";
5
- import { namespace } from "./namespace.js";
6
5
  import { isBindGroupLayout } from "../../tgpuBindGroupLayout.js";
7
6
  import { resolve } from "../../resolutionCtx.js";
8
7
  import { isPipeline } from "../pipeline/typeGuards.js";
8
+ import { namespace } from "./namespace.js";
9
9
 
10
10
  //#region src/core/resolve/tgpuResolve.ts
11
11
  function resolveWithContext(arg0, options) {
@@ -1,3 +1,4 @@
1
+ import "../querySet/querySet.js";
1
2
  import "../buffer/bufferShorthand.js";
2
3
  import { LogGeneratorOptions } from "../../tgsl/consoleLog/types.js";
3
4
  import "../pipeline/computePipeline.js";
package/core/root/init.js CHANGED
@@ -54,6 +54,12 @@ var TgpuGuardedComputePipelineImpl = class TgpuGuardedComputePipelineImpl {
54
54
  with(bindGroupOrEncoder) {
55
55
  return new TgpuGuardedComputePipelineImpl(this.#root, this.#pipeline.with(bindGroupOrEncoder), this.#sizeUniform, this.#workgroupSize);
56
56
  }
57
+ withPerformanceCallback(callback) {
58
+ return new TgpuGuardedComputePipelineImpl(this.#root, this.#pipeline.withPerformanceCallback(callback), this.#sizeUniform, this.#workgroupSize);
59
+ }
60
+ withTimestampWrites(options) {
61
+ return new TgpuGuardedComputePipelineImpl(this.#root, this.#pipeline.withTimestampWrites(options), this.#sizeUniform, this.#workgroupSize);
62
+ }
57
63
  dispatchThreads(...threads) {
58
64
  const sanitizedSize = toVec3(threads);
59
65
  const workgroupCount = ceil(vec3f(sanitizedSize).div(vec3f(this.#workgroupSize)));
@@ -4,14 +4,14 @@ import { Assume, Mutable, OmitProps, Prettify } from "../../shared/utilityTypes.
4
4
  import { WgslComparisonSamplerProps, WgslSamplerProps } from "../../data/sampler.js";
5
5
  import { AnyComputeBuiltin, AnyFragmentInputBuiltin, OmitBuiltins } from "../../builtin.js";
6
6
  import { TgpuQuerySet } from "../querySet/querySet.js";
7
+ import { InstanceToSchema } from "../../data/instanceToSchema.js";
7
8
  import { TgpuMutable, TgpuReadonly, TgpuUniform } from "../buffer/bufferShorthand.js";
8
- import { LogGeneratorOptions } from "../../tgsl/consoleLog/types.js";
9
9
  import { IORecord } from "../function/fnTypes.js";
10
+ import { LogGeneratorOptions } from "../../tgsl/consoleLog/types.js";
10
11
  import { TgpuComputeFn } from "../function/tgpuComputeFn.js";
11
12
  import { Eventual, TgpuAccessor, TgpuMutableAccessor, TgpuSlot } from "../slot/slotTypes.js";
12
13
  import { TgpuComputePipeline } from "../pipeline/computePipeline.js";
13
14
  import { AnyAutoCustoms, AutoFragmentIn, AutoFragmentOut, AutoVertexIn, AutoVertexOut } from "../function/autoIO.js";
14
- import { InstanceToSchema } from "../../data/instanceToSchema.js";
15
15
  import { FragmentInConstrained, FragmentOutConstrained, TgpuFragmentFn, VertexOutToVarying } from "../function/tgpuFragmentFn.js";
16
16
  import { TgpuVertexFn } from "../function/tgpuVertexFn.js";
17
17
  import { AttribRecordToDefaultDataTypes, LayoutToAllowedAttribs } from "../vertexLayout/vertexAttribute.js";
@@ -40,6 +40,20 @@ interface TgpuGuardedComputePipeline<TArgs extends number[] = number[]> extends
40
40
  * Analogous to `TgpuComputePipeline.with(encoder)`.
41
41
  */
42
42
  with(encoder: GPUCommandEncoder): TgpuGuardedComputePipeline<TArgs>;
43
+ /**
44
+ * Returns a pipeline wrapper with the given performance callback attached.
45
+ * Analogous to `TgpuComputePipeline.withPerformanceCallback(callback)`.
46
+ */
47
+ withPerformanceCallback(callback: (start: bigint, end: bigint) => void | Promise<void>): TgpuGuardedComputePipeline<TArgs>;
48
+ /**
49
+ * Returns a pipeline wrapper with the given timestamp writes configuration.
50
+ * Analogous to `TgpuComputePipeline.withTimestampWrites(options)`.
51
+ */
52
+ withTimestampWrites(options: {
53
+ querySet: TgpuQuerySet<'timestamp'> | GPUQuerySet;
54
+ beginningOfPassWriteIndex?: number;
55
+ endOfPassWriteIndex?: number;
56
+ }): TgpuGuardedComputePipeline<TArgs>;
43
57
  /**
44
58
  * Dispatches the pipeline.
45
59
  * Unlike `TgpuComputePipeline.dispatchWorkgroups()`, this method takes in the
@@ -166,7 +180,7 @@ interface WithBinding extends Withable<WithBinding> {
166
180
  })): TgpuRenderPipeline<NormalizeOutput<TFragmentOut>> | TgpuRenderPipeline<Void>;
167
181
  /**
168
182
  * Creates a compute pipeline that executes the given callback in an exact number of threads.
169
- * This is different from `withCompute(...).createPipeline()` in that it does a bounds check on the
183
+ * This is different from `createComputePipeline()` in that it does a bounds check on the
170
184
  * thread id, where as regular pipelines do not and work in units of workgroups.
171
185
  *
172
186
  * @param callback A function converted to WGSL and executed on the GPU.
@@ -473,10 +487,8 @@ interface TgpuRoot extends Unwrapper, WithBinding {
473
487
  * Typed wrapper around a GPUBuffer.
474
488
  *
475
489
  * @param typeSchema The type of data that this buffer will hold.
476
- * @param initial The initial value of the buffer. (optional)
490
+ * @param initial Either initial value of the buffer, or an initializer to execute on the mapped buffer. (optional)
477
491
  */
478
- createBuffer<TData extends AnyData>(typeSchema: ValidateBufferSchema<TData>, initializer: (buffer: TgpuBuffer<NoInfer<TData>>) => void): TgpuBuffer<TData>;
479
- createBuffer<TData extends AnyData>(typeSchema: ValidateBufferSchema<TData>, initial?: InferInput<NoInfer<TData>>): TgpuBuffer<TData>;
480
492
  createBuffer<TData extends AnyData>(typeSchema: ValidateBufferSchema<TData>, initial?: ((buffer: TgpuBuffer<NoInfer<TData>>) => void) | InferInput<NoInfer<TData>>): TgpuBuffer<TData>;
481
493
  /**
482
494
  * Allocates memory on the GPU, allows passing data between host and shader.
@@ -494,10 +506,8 @@ interface TgpuRoot extends Unwrapper, WithBinding {
494
506
  * use {@link TgpuRoot.createBuffer}.
495
507
  *
496
508
  * @param typeSchema The type of data that this buffer will hold.
497
- * @param initial The initial value of the buffer. (optional)
509
+ * @param initial Either initial value of the buffer, or an initializer to execute on the mapped buffer. (optional)
498
510
  */
499
- createUniform<TData extends AnyWgslData>(typeSchema: ValidateUniformSchema<TData>, initializer: (buffer: TgpuBuffer<NoInfer<TData>>) => void): TgpuUniform<TData>;
500
- createUniform<TData extends AnyWgslData>(typeSchema: ValidateUniformSchema<TData>, initial?: InferInput<NoInfer<TData>>): TgpuUniform<TData>;
501
511
  createUniform<TData extends AnyWgslData>(typeSchema: ValidateUniformSchema<TData>, initial?: ((buffer: TgpuBuffer<NoInfer<TData>>) => void) | InferInput<NoInfer<TData>>): TgpuUniform<TData>;
502
512
  /**
503
513
  * Allocates memory on the GPU, allows passing data between host and shader.
@@ -514,10 +524,8 @@ interface TgpuRoot extends Unwrapper, WithBinding {
514
524
  * use {@link TgpuRoot.createBuffer}.
515
525
  *
516
526
  * @param typeSchema The type of data that this buffer will hold.
517
- * @param initial The initial value of the buffer. (optional)
527
+ * @param initial Either initial value of the buffer, or an initializer to execute on the mapped buffer. (optional)
518
528
  */
519
- createMutable<TData extends AnyWgslData>(typeSchema: ValidateStorageSchema<TData>, initializer: (buffer: TgpuBuffer<NoInfer<TData>>) => void): TgpuMutable<TData>;
520
- createMutable<TData extends AnyWgslData>(typeSchema: ValidateStorageSchema<TData>, initial?: InferInput<NoInfer<TData>>): TgpuMutable<TData>;
521
529
  createMutable<TData extends AnyWgslData>(typeSchema: ValidateStorageSchema<TData>, initial?: ((buffer: TgpuBuffer<NoInfer<TData>>) => void) | InferInput<NoInfer<TData>>): TgpuMutable<TData>;
522
530
  /**
523
531
  * Allocates memory on the GPU, allows passing data between host and shader.
@@ -534,10 +542,8 @@ interface TgpuRoot extends Unwrapper, WithBinding {
534
542
  * use {@link TgpuRoot.createBuffer}.
535
543
  *
536
544
  * @param typeSchema The type of data that this buffer will hold.
537
- * @param initial The initial value of the buffer. (optional)
545
+ * @param initial Either initial value of the buffer, or an initializer to execute on the mapped buffer. (optional)
538
546
  */
539
- createReadonly<TData extends AnyWgslData>(typeSchema: ValidateStorageSchema<TData>, initializer: (buffer: TgpuBuffer<NoInfer<TData>>) => void): TgpuReadonly<TData>;
540
- createReadonly<TData extends AnyWgslData>(typeSchema: ValidateStorageSchema<TData>, initial?: InferInput<NoInfer<TData>>): TgpuReadonly<TData>;
541
547
  createReadonly<TData extends AnyWgslData>(typeSchema: ValidateStorageSchema<TData>, initial?: ((buffer: TgpuBuffer<NoInfer<TData>>) => void) | InferInput<NoInfer<TData>>): TgpuReadonly<TData>;
542
548
  /**
543
549
  * Allocates memory on the GPU, allows passing data between host and shader.
@@ -32,7 +32,7 @@ var TgpuLaidOutSamplerImpl = class {
32
32
  setName(this, membership.key);
33
33
  }
34
34
  [$resolve](ctx) {
35
- const id = ctx.getUniqueName(this);
35
+ const id = ctx.makeUniqueIdentifier(getName(this), "global");
36
36
  const group = ctx.allocateLayoutEntry(this.#membership.layout);
37
37
  ctx.addDeclaration(`@group(${group}) @binding(${this.#membership.idx}) var ${id}: ${ctx.resolve(this.schema).value};`);
38
38
  return snip(id, this.schema, "handle");
@@ -82,7 +82,7 @@ var TgpuFixedSamplerImpl = class {
82
82
  this.#filtering = props.minFilter === "linear" || props.magFilter === "linear" || props.mipmapFilter === "linear";
83
83
  }
84
84
  [$resolve](ctx) {
85
- const id = ctx.getUniqueName(this);
85
+ const id = ctx.makeUniqueIdentifier(getName(this), "global");
86
86
  const { group, binding } = ctx.allocateFixedEntry(this.schema.type === "sampler_comparison" ? { sampler: "comparison" } : { sampler: this.#filtering ? "filtering" : "non-filtering" }, this);
87
87
  ctx.addDeclaration(`@group(${group}) @binding(${binding}) var ${id}: ${ctx.resolve(this.schema).value};`);
88
88
  return snip(id, this.schema, "handle");
@@ -1,8 +1,8 @@
1
1
  import { SimulationState } from "../../types.js";
2
2
  import { getResolutionCtx, provideCtx } from "../../execMode.js";
3
- import { namespace } from "../resolve/namespace.js";
4
3
  import wgslGenerator_default from "../../tgsl/wgslGenerator.js";
5
4
  import { ResolutionCtxImpl } from "../../resolutionCtx.js";
5
+ import { namespace } from "../resolve/namespace.js";
6
6
 
7
7
  //#region src/core/simulate/tgpuSimulate.ts
8
8
  /**
@@ -25,7 +25,7 @@ var AccessorBase = class {
25
25
  constructor(schemaOrConstructor, defaultValue = void 0) {
26
26
  this.schema = isData(schemaOrConstructor) ? schemaOrConstructor : schemaOrConstructor(0);
27
27
  this.defaultValue = defaultValue;
28
- this.slot = slot(defaultValue);
28
+ this.slot = (() => slot(defaultValue))();
29
29
  this[$getNameForward] = this.slot;
30
30
  }
31
31
  get [$gpuValueOf]() {
@@ -17,7 +17,7 @@ var TgpuExternalTextureImpl = class {
17
17
  setName(this, membership.key);
18
18
  }
19
19
  [$resolve](ctx) {
20
- const id = ctx.getUniqueName(this);
20
+ const id = ctx.makeUniqueIdentifier(getName(this), "global");
21
21
  const group = ctx.allocateLayoutEntry(this.#membership.layout);
22
22
  ctx.addDeclaration(`@group(${group}) @binding(${this.#membership.idx}) var ${id}: ${ctx.resolve(this.schema).value};`);
23
23
  return snip(id, textureExternal(), "handle");
@@ -246,7 +246,7 @@ var TgpuFixedTextureViewImpl = class {
246
246
  return `textureView:${getName(this) ?? "<unnamed>"}`;
247
247
  }
248
248
  [$resolve](ctx) {
249
- const id = ctx.getUniqueName(this);
249
+ const id = ctx.makeUniqueIdentifier(getName(this), "global");
250
250
  const { group, binding } = ctx.allocateFixedEntry(isWgslStorageTexture(this.schema) ? { storageTexture: this.schema } : {
251
251
  texture: this.schema,
252
252
  sampleType: this.#descriptor?.sampleType ?? this.schema.bindingSampleType[0]
@@ -269,7 +269,7 @@ var TgpuLaidOutTextureViewImpl = class {
269
269
  return `textureView:${getName(this) ?? "<unnamed>"}`;
270
270
  }
271
271
  [$resolve](ctx) {
272
- const id = ctx.getUniqueName(this);
272
+ const id = ctx.makeUniqueIdentifier(getName(this), "global");
273
273
  const group = ctx.allocateLayoutEntry(this.#membership.layout);
274
274
  ctx.addDeclaration(`@group(${group}) @binding(${this.#membership.idx}) var ${id}: ${ctx.resolve(this.schema).value};`);
275
275
  return snip(id, this.schema, "handle");
@@ -42,7 +42,7 @@ var TgpuVarImpl = class {
42
42
  this.#initialValue = initialValue;
43
43
  }
44
44
  [$resolve](ctx) {
45
- const id = ctx.getUniqueName(this);
45
+ const id = ctx.makeUniqueIdentifier(getName(this), "global");
46
46
  const pre = `var<${this.#scope}> ${id}: ${ctx.resolve(this.#dataType).value}`;
47
47
  if (this.#initialValue) ctx.addDeclaration(`${pre} = ${ctx.resolve(this.#initialValue, this.#dataType).value};`);
48
48
  else ctx.addDeclaration(`${pre};`);
@@ -1,6 +1,6 @@
1
1
  import { $internal, $resolve } from "../shared/symbols.js";
2
2
  import { getName, setName } from "../shared/meta.js";
3
- import { isValidProp } from "../nameRegistry.js";
3
+ import { validateProp } from "../nameUtils.js";
4
4
  import { createIoSchema } from "../core/function/ioSchema.js";
5
5
 
6
6
  //#region src/data/autoStruct.ts
@@ -49,7 +49,8 @@ var AutoStruct = class {
49
49
  if (!alloc) {
50
50
  const wgslKey = key.replaceAll("$", "");
51
51
  if (this.#usedWgslKeys.has(wgslKey)) throw new Error(`Property name '${wgslKey}' causes naming clashes. Choose a different name.`);
52
- if (!isValidProp(wgslKey)) throw new Error(`Property key '${key}' is a reserved WGSL word. Choose a different name.`);
52
+ const result = /* @__PURE__ */ validateProp(wgslKey);
53
+ if (!result.success) throw new Error(`Invalid property key '${key}'${result.error ? `: ${result.error}` : ""}`);
53
54
  this.#usedWgslKeys.add(wgslKey);
54
55
  alloc = {
55
56
  prop: wgslKey,
@@ -0,0 +1,11 @@
1
+ import { BufferWriteOptions } from "../core/buffer/buffer.js";
2
+ import { BaseData } from "./wgslTypes.js";
3
+ import { Infer, InferInput } from "../shared/repr.js";
4
+ import "typed-binary";
5
+
6
+ //#region src/data/dataIO.d.ts
7
+
8
+ declare function writeToArrayBuffer<T extends BaseData>(buffer: ArrayBuffer, schema: T, data: InferInput<T> | ArrayBuffer, options?: BufferWriteOptions): void;
9
+ declare function readFromArrayBuffer<T extends BaseData>(buffer: ArrayBuffer, schema: T): Infer<T>;
10
+ //#endregion
11
+ export { readFromArrayBuffer, writeToArrayBuffer };