typegpu 0.11.3 → 0.11.4

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
 
3
- ![TypeGPU (light mode)](/apps/typegpu-docs/public/typegpu-logo-light.svg#gh-light-mode-only)
3
+ ![TypeGPU (light mode)](https://typegpu.com/typegpu-logo-light.svg#gh-light-mode-only)
4
4
 
5
5
 
6
6
  [Website](https://docs.swmansion.com/TypeGPU) —
@@ -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;
@@ -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";
@@ -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.
@@ -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]() {
@@ -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 };
package/data/dataIO.js CHANGED
@@ -1,8 +1,13 @@
1
+ import { getName } from "../shared/meta.js";
2
+ import { isWgslArray } from "./wgslTypes.js";
1
3
  import { vec2f, vec2h, vec2i, vec2u, vec3f, vec3h, vec3i, vec3u, vec4f, vec4h, vec4i, vec4u } from "./vector.js";
2
4
  import { alignmentOf, customAlignmentOf } from "./alignmentOf.js";
5
+ import { roundUp } from "../mathUtils.js";
3
6
  import { sizeOf } from "./sizeOf.js";
4
7
  import { mat2x2f, mat3x3f, mat4x4f } from "./matrix.js";
5
8
  import alignIO_default from "./alignIO.js";
9
+ import { getCompiledWriter } from "./compiledIO.js";
10
+ import { BufferReader, BufferWriter, getSystemEndianness } from "typed-binary";
6
11
 
7
12
  //#region src/data/dataIO.ts
8
13
  const dataWriters = {
@@ -553,6 +558,45 @@ function readData(input, schema) {
553
558
  if (!reader) throw new Error(`Cannot read data of type '${schema.type}'.`);
554
559
  return reader(input, schema);
555
560
  }
561
+ const endianness = getSystemEndianness();
562
+ function calculateOffsets(options, schema, data) {
563
+ const bufferSize = sizeOf(schema);
564
+ const startOffset = options?.startOffset ?? 0;
565
+ let naturalSize = void 0;
566
+ if (isWgslArray(schema) && Array.isArray(data)) naturalSize = data.length * roundUp(sizeOf(schema.elementType), alignmentOf(schema.elementType));
567
+ else if (ArrayBuffer.isView(data) || data instanceof ArrayBuffer) naturalSize = data.byteLength;
568
+ const naturalEndOffset = naturalSize !== void 0 ? Math.min(startOffset + naturalSize, bufferSize) : void 0;
569
+ return {
570
+ startOffset,
571
+ endOffset: options?.endOffset ?? naturalEndOffset ?? bufferSize
572
+ };
573
+ }
574
+ function writeToArrayBuffer(buffer, schema, data, options) {
575
+ const { startOffset, endOffset } = calculateOffsets(options, schema, data);
576
+ if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
577
+ const src = data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
578
+ const regionSize = endOffset - startOffset;
579
+ if (src.byteLength !== regionSize) console.warn(`Buffer size mismatch: expected ${regionSize} bytes, got ${src.byteLength}. ` + (src.byteLength < regionSize ? "Data truncated." : "Excess ignored."));
580
+ const copyLen = Math.min(src.byteLength, regionSize);
581
+ new Uint8Array(buffer).set(src.subarray(0, copyLen), startOffset);
582
+ return;
583
+ }
584
+ const dataView = new DataView(buffer);
585
+ const isLittleEndian = endianness === "little";
586
+ const compiledWriter = getCompiledWriter(schema);
587
+ if (compiledWriter) try {
588
+ compiledWriter(dataView, startOffset, data, isLittleEndian, endOffset);
589
+ return;
590
+ } catch (error) {
591
+ console.error(`Error when using compiled writer for data type '${schema.type}' (${getName(schema) ?? "unnamed"}) - this is likely a bug, please submit an issue at https://github.com/software-mansion/TypeGPU/issues\nUsing fallback writer instead.`, error);
592
+ }
593
+ const writer = new BufferWriter(buffer);
594
+ writer.seekTo(startOffset);
595
+ writeData(writer, schema, data);
596
+ }
597
+ function readFromArrayBuffer(buffer, schema) {
598
+ return readData(new BufferReader(buffer), schema);
599
+ }
556
600
 
557
601
  //#endregion
558
- export { readData, writeData };
602
+ export { calculateOffsets, readFromArrayBuffer, writeData, writeToArrayBuffer };
package/data/dataTypes.js CHANGED
@@ -1,5 +1,4 @@
1
- import { $internal, isMarkedInternal } from "../shared/symbols.js";
2
- import { setName } from "../shared/meta.js";
1
+ import { isMarkedInternal } from "../shared/symbols.js";
3
2
  import { vertexFormats } from "../shared/vertexFormat.js";
4
3
  import { isAlignAttrib, isDecorated, isLocationAttrib, isPtr, isSizeAttrib, isWgslData } from "./wgslTypes.js";
5
4
 
@@ -89,14 +88,6 @@ var MatrixColumnsAccess = class {
89
88
  this.matrix = matrix;
90
89
  }
91
90
  };
92
- var ConsoleLog = class {
93
- [$internal] = true;
94
- op;
95
- constructor(op) {
96
- this.op = op;
97
- setName(this, "consoleLog");
98
- }
99
- };
100
91
 
101
92
  //#endregion
102
- export { ConsoleLog, InfixDispatch, MatrixColumnsAccess, UnknownData, getCustomAlignment, getCustomLocation, getCustomSize, isData, isDisarray, isLooseData, isLooseDecorated, isUnstruct, undecorate, unptr };
93
+ export { InfixDispatch, MatrixColumnsAccess, UnknownData, getCustomAlignment, getCustomLocation, getCustomSize, isData, isDisarray, isLooseData, isLooseDecorated, isUnstruct, undecorate, unptr };
@@ -0,0 +1,8 @@
1
+ import { BaseData } from "./wgslTypes.js";
2
+ import { InferPatch } from "../shared/repr.js";
3
+
4
+ //#region src/data/partialIO.d.ts
5
+
6
+ declare function patchArrayBuffer<T extends BaseData>(buffer: ArrayBuffer, schema: T, data: InferPatch<T>): void;
7
+ //#endregion
8
+ export { patchArrayBuffer };
package/data/partialIO.js CHANGED
@@ -110,6 +110,11 @@ function getPatchInstructions(schema, data, targetBuffer) {
110
110
  });
111
111
  return instructions;
112
112
  }
113
+ function patchArrayBuffer(buffer, schema, data) {
114
+ const instructions = getPatchInstructions(schema, data, buffer);
115
+ const mappedView = new Uint8Array(buffer);
116
+ for (const { data: data$1, gpuOffset } of instructions) mappedView.set(data$1, gpuOffset);
117
+ }
113
118
 
114
119
  //#endregion
115
- export { convertPartialToPatch, getPatchInstructions };
120
+ export { convertPartialToPatch, getPatchInstructions, patchArrayBuffer };
package/index.d.ts CHANGED
@@ -38,6 +38,8 @@ import { index_d_exports as index_d_exports$2 } from "./std/index.js";
38
38
  import { index_d_exports } from "./common/index.js";
39
39
  import { MissingBindGroupsError, MissingLinksError, MissingSlotValueError, MissingVertexBuffersError, NotUniformError, ResolutionError } from "./errors.js";
40
40
  import { WgslGenerator } from "./tgsl/wgslGenerator.js";
41
+ import { readFromArrayBuffer, writeToArrayBuffer } from "./data/dataIO.js";
42
+ import { patchArrayBuffer } from "./data/partialIO.js";
41
43
  import { TgpuRenderPipelineDescriptor } from "./indexNamedExports.js";
42
44
 
43
45
  //#region src/index.d.ts
@@ -68,4 +70,4 @@ declare const tgpu: {
68
70
  '~unstable': typeof tgpuUnstable_d_exports;
69
71
  };
70
72
  //#endregion
71
- export { AutoFragmentIn, AutoFragmentOut, _AutoVertexIn as AutoVertexIn, AutoVertexOut, BindLayoutEntry, ColorAttachment, Configurable, Eventual, ExtractBindGroupInputFromLayout, INTERNAL_GlobalExt, IndexFlag, InitFromDeviceOptions, InitOptions, LayoutEntryToInput, MissingBindGroupsError, MissingLinksError, MissingSlotValueError, MissingVertexBuffersError, Namespace, NotUniformError, RawCodeSnippetOrigin, RenderFlag, ResolutionError, SampledFlag, ShaderGenerator, Storage, StorageFlag, TextureProps, TgpuAccessor, TgpuBindGroup, TgpuBindGroupLayout, TgpuBuffer, TgpuBufferMutable, TgpuBufferReadonly, TgpuBufferUniform, TgpuComparisonSampler, TgpuComptime, TgpuComputeFn, TgpuComputeFnShell, TgpuComputePipeline, TgpuConst, TgpuDeclare, TgpuFixedComparisonSampler, TgpuFixedSampler, TgpuFn, TgpuFnShell, TgpuFragmentFn, TgpuFragmentFnShell, TgpuGenericFn, TgpuGuardedComputePipeline, TgpuLayoutComparisonSampler, TgpuLayoutEntry, TgpuLayoutExternalTexture, TgpuLayoutSampler, TgpuLayoutStorage, TgpuLayoutTexture, TgpuLayoutUniform, TgpuLazy, TgpuMutable, TgpuMutableAccessor, TgpuPrimitiveState, TgpuQuerySet, TgpuRawCodeSnippet, TgpuReadonly, TgpuRenderPipeline, TgpuRenderPipelineDescriptor, TgpuRoot, TgpuSampler, TgpuSlot, TgpuTexture, TgpuTextureView, TgpuUniform, TgpuVar, TgpuVertexFn, TgpuVertexFnShell, TgpuVertexLayout, Uniform, UniformFlag, ValidUsagesFor, ValidateBufferSchema, ValidateStorageSchema, ValidateUniformSchema, VariableScope, Vertex, VertexFlag, WgslGenerator, WithBinding, WithCompute, WithFragment, WithVertex, Withable, index_d_exports as common, index_d_exports$1 as d, tgpu as default, tgpu, isAccessor, isBuffer, isBufferShorthand, isComparisonSampler, isLazy, isMutableAccessor, isSampler, isSlot, isTexture, isTgpuComputeFn, isTgpuFn, isTgpuFragmentFn, isTgpuVertexFn, isUsableAsRender, isUsableAsSampled, isUsableAsStorage, isUsableAsUniform, isUsableAsVertex, isVariable, index_d_exports$2 as std };
73
+ export { AutoFragmentIn, AutoFragmentOut, _AutoVertexIn as AutoVertexIn, AutoVertexOut, BindLayoutEntry, ColorAttachment, Configurable, Eventual, ExtractBindGroupInputFromLayout, INTERNAL_GlobalExt, IndexFlag, InitFromDeviceOptions, InitOptions, LayoutEntryToInput, MissingBindGroupsError, MissingLinksError, MissingSlotValueError, MissingVertexBuffersError, Namespace, NotUniformError, RawCodeSnippetOrigin, RenderFlag, ResolutionError, SampledFlag, ShaderGenerator, Storage, StorageFlag, TextureProps, TgpuAccessor, TgpuBindGroup, TgpuBindGroupLayout, TgpuBuffer, TgpuBufferMutable, TgpuBufferReadonly, TgpuBufferUniform, TgpuComparisonSampler, TgpuComptime, TgpuComputeFn, TgpuComputeFnShell, TgpuComputePipeline, TgpuConst, TgpuDeclare, TgpuFixedComparisonSampler, TgpuFixedSampler, TgpuFn, TgpuFnShell, TgpuFragmentFn, TgpuFragmentFnShell, TgpuGenericFn, TgpuGuardedComputePipeline, TgpuLayoutComparisonSampler, TgpuLayoutEntry, TgpuLayoutExternalTexture, TgpuLayoutSampler, TgpuLayoutStorage, TgpuLayoutTexture, TgpuLayoutUniform, TgpuLazy, TgpuMutable, TgpuMutableAccessor, TgpuPrimitiveState, TgpuQuerySet, TgpuRawCodeSnippet, TgpuReadonly, TgpuRenderPipeline, TgpuRenderPipelineDescriptor, TgpuRoot, TgpuSampler, TgpuSlot, TgpuTexture, TgpuTextureView, TgpuUniform, TgpuVar, TgpuVertexFn, TgpuVertexFnShell, TgpuVertexLayout, Uniform, UniformFlag, ValidUsagesFor, ValidateBufferSchema, ValidateStorageSchema, ValidateUniformSchema, VariableScope, Vertex, VertexFlag, WgslGenerator, WithBinding, WithCompute, WithFragment, WithVertex, Withable, index_d_exports as common, index_d_exports$1 as d, tgpu as default, tgpu, isAccessor, isBuffer, isBufferShorthand, isComparisonSampler, isLazy, isMutableAccessor, isSampler, isSlot, isTexture, isTgpuComputeFn, isTgpuFn, isTgpuFragmentFn, isTgpuVertexFn, isUsableAsRender, isUsableAsSampled, isUsableAsStorage, isUsableAsUniform, isUsableAsVertex, isVariable, patchArrayBuffer, readFromArrayBuffer, index_d_exports$2 as std, writeToArrayBuffer };
package/index.js CHANGED
@@ -2,6 +2,8 @@ import { MissingBindGroupsError, MissingLinksError, MissingSlotValueError, Missi
2
2
  import { isAccessor, isLazy, isMutableAccessor, isSlot } from "./core/slot/slotTypes.js";
3
3
  import { shaderGenerator_members_exports } from "./tgsl/shaderGenerator_members.js";
4
4
  import { isTgpuFn } from "./core/function/tgpuFn.js";
5
+ import { readFromArrayBuffer, writeToArrayBuffer } from "./data/dataIO.js";
6
+ import { patchArrayBuffer } from "./data/partialIO.js";
5
7
  import { isUsableAsStorage } from "./extension.js";
6
8
  import { isUsableAsUniform } from "./core/buffer/bufferUsage.js";
7
9
  import { isBuffer, isUsableAsVertex } from "./core/buffer/buffer.js";
@@ -23,4 +25,4 @@ import { common_exports } from "./common/index.js";
23
25
  var src_default = tgpu_exports;
24
26
 
25
27
  //#endregion
26
- export { MissingBindGroupsError, MissingLinksError, MissingSlotValueError, MissingVertexBuffersError, NotUniformError, ResolutionError, shaderGenerator_members_exports as ShaderGenerator, WgslGenerator, common_exports as common, data_exports as d, src_default as default, isAccessor, isBuffer, isBufferShorthand, isComparisonSampler, isLazy, isMutableAccessor, isSampler, isSlot, isTexture, isTgpuComputeFn, isTgpuFn, isTgpuFragmentFn, isTgpuVertexFn, isUsableAsRender, isUsableAsSampled, isUsableAsStorage, isUsableAsUniform, isUsableAsVertex, isVariable, std_exports as std, tgpu_exports as tgpu };
28
+ export { MissingBindGroupsError, MissingLinksError, MissingSlotValueError, MissingVertexBuffersError, NotUniformError, ResolutionError, shaderGenerator_members_exports as ShaderGenerator, WgslGenerator, common_exports as common, data_exports as d, src_default as default, isAccessor, isBuffer, isBufferShorthand, isComparisonSampler, isLazy, isMutableAccessor, isSampler, isSlot, isTexture, isTgpuComputeFn, isTgpuFn, isTgpuFragmentFn, isTgpuVertexFn, isUsableAsRender, isUsableAsSampled, isUsableAsStorage, isUsableAsUniform, isUsableAsVertex, isVariable, patchArrayBuffer, readFromArrayBuffer, std_exports as std, tgpu_exports as tgpu, writeToArrayBuffer };
@@ -32,6 +32,8 @@ import { index_d_exports as index_d_exports$1 } from "./std/index.js";
32
32
  import { index_d_exports as index_d_exports$2 } from "./common/index.js";
33
33
  import { MissingBindGroupsError, MissingLinksError, MissingSlotValueError, MissingVertexBuffersError, NotUniformError, ResolutionError } from "./errors.js";
34
34
  import { WgslGenerator } from "./tgsl/wgslGenerator.js";
35
+ import { readFromArrayBuffer, writeToArrayBuffer } from "./data/dataIO.js";
36
+ import { patchArrayBuffer } from "./data/partialIO.js";
35
37
 
36
38
  //#region src/indexNamedExports.d.ts
37
39
 
package/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.11.3";
2
+ var version = "0.11.4";
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.3",
3
+ "version": "0.11.4",
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
@@ -560,9 +560,8 @@ var ResolutionCtxImpl = class {
560
560
  if (schema.elementCount !== item.length) throw new WgslTypeError(`Cannot create value of type '${schema}' from an array of length: ${item.length}`);
561
561
  return snip(stitch`array<${this.resolve(schema.elementType)}, ${schema.elementCount}>(${item.map((element) => snip(element, schema.elementType, "runtime"))})`, schema, "runtime");
562
562
  }
563
- if (Array.isArray(item)) return snip(stitch`array(${item.map((element) => this.resolve(element))})`, UnknownData, "runtime");
564
563
  if (schema && isWgslStruct(schema)) return snip(stitch`${this.resolve(schema)}(${Object.entries(schema.propTypes).map(([key, propType]) => snip(item[key], propType, "runtime"))})`, schema, "runtime");
565
- throw new WgslTypeError(`Value ${item} (as json: ${safeStringify(item)}) is not resolvable${schema ? ` to type ${safeStringify(schema)}` : ""}`);
564
+ throw new WgslTypeError(`Value ${safeStringify(item)} is not resolvable${schema ? ` to type ${safeStringify(schema)}` : ""}`);
566
565
  }
567
566
  resolveSnippet(snippet) {
568
567
  return snip(this.resolve(snippet.value, snippet.dataType).value, snippet.dataType, snippet.origin);
@@ -2,6 +2,7 @@ import { isMatInstance, isVecInstance } from "../data/wgslTypes.js";
2
2
 
3
3
  //#region src/shared/stringify.ts
4
4
  function safeStringify(item) {
5
+ if (Array.isArray(item)) return `[${item.map(safeStringify).join(", ")}]`;
5
6
  const asString = String(item);
6
7
  if (asString !== "[object Object]") return asString;
7
8
  try {
@@ -0,0 +1,90 @@
1
+ import * as tinyest from "tinyest";
2
+
3
+ //#region src/shared/tseynit.ts
4
+ const { NodeTypeCatalog: NODE } = tinyest;
5
+ function stringifyNode(node) {
6
+ if (isExpression(node)) return stringifyExpression(node, "");
7
+ return stringifyStatement(node, "");
8
+ }
9
+ function stringifyStatement(node, ident) {
10
+ if (isExpression(node)) return `${ident}${stringifyExpression(node, ident)};`;
11
+ if (node[0] === NODE.block) return `{\n${node[1].map((n) => stringifyStatement(n, ident + " ")).join("\n")}\n${ident}}`;
12
+ if (node[0] === NODE.return) return `${ident}return${node[1] === void 0 ? "" : ` ${stringifyExpression(node[1], "")}`};`;
13
+ if (node[0] === NODE.if) {
14
+ const base = `${ident}if (${stringifyExpression(node[1], ident)}) ${stringifyStatement(node[2], ident)}`;
15
+ if (node[3] !== void 0) return `${base} else ${stringifyStatement(node[3], ident)}`;
16
+ return base;
17
+ }
18
+ if (node[0] === NODE.let) {
19
+ if (node[2] !== void 0) return `${ident}let ${node[1]} = ${stringifyExpression(node[2], ident)};`;
20
+ return `${ident}let ${node[1]};`;
21
+ }
22
+ if (node[0] === NODE.const) {
23
+ if (node[2] !== void 0) return `${ident}const ${node[1]} = ${stringifyExpression(node[2], ident)};`;
24
+ return `${ident}const ${node[1]};`;
25
+ }
26
+ if (node[0] === NODE.for) {
27
+ const init = node[1] ? stringifyStatement(node[1], "") : ";";
28
+ const cond = node[2] ? stringifyExpression(node[2], ident) : "";
29
+ const update = node[3] ? stringifyStatement(node[3], "") : "";
30
+ const body = stringifyStatement(node[4], ident);
31
+ return `${ident}for (${init} ${cond}; ${update.slice(0, -1)}) ${body}`;
32
+ }
33
+ if (node[0] === NODE.while) return `${ident}while (${stringifyExpression(node[1], ident)}) ${stringifyStatement(node[2], ident)}`;
34
+ if (node[0] === NODE.continue) return `${ident}continue;`;
35
+ if (node[0] === NODE.break) return `${ident}break;`;
36
+ if (node[0] === NODE.forOf) return `${ident}for (${node[1][0] === NODE.const ? "const" : "let"} ${node[1][1]} of ${stringifyExpression(node[2], ident)}) ${stringifyStatement(node[3], ident)}`;
37
+ assertExhaustive(node);
38
+ }
39
+ function stringifyExpression(node, ident) {
40
+ if (typeof node === "string") return node;
41
+ if (typeof node === "boolean") return `${node}`;
42
+ if (node[0] === NODE.numericLiteral) return node[1];
43
+ if (node[0] === NODE.stringLiteral) return JSON.stringify(node[1]);
44
+ if (node[0] === NODE.arrayExpr) return `[${node[1].map((n) => stringifyExpression(n, ident)).join(", ")}]`;
45
+ if (node[0] === NODE.binaryExpr) return `${wrapIfComplex(node[1], ident)} ${node[2]} ${wrapIfComplex(node[3], ident)}`;
46
+ if (node[0] === NODE.assignmentExpr) return `${stringifyExpression(node[1], ident)} ${node[2]} ${stringifyExpression(node[3], ident)}`;
47
+ if (node[0] === NODE.logicalExpr) return `${wrapIfComplex(node[1], ident)} ${node[2]} ${wrapIfComplex(node[3], ident)}`;
48
+ if (node[0] === NODE.unaryExpr) {
49
+ const sep = node[1].length > 1 ? " " : "";
50
+ return `${node[1]}${sep}${wrapIfComplex(node[2], ident)}`;
51
+ }
52
+ if (node[0] === NODE.call) return `${wrapIfComplex(node[1], ident)}(${node[2].map((n) => stringifyExpression(n, ident)).join(", ")})`;
53
+ if (node[0] === NODE.memberAccess) {
54
+ if (Array.isArray(node[1]) && node[1][0] === NODE.numericLiteral) return `(${stringifyExpression(node[1], ident)}).${node[2]}`;
55
+ return `${wrapIfComplex(node[1], ident)}.${node[2]}`;
56
+ }
57
+ if (node[0] === NODE.indexAccess) return `${wrapIfComplex(node[1], ident)}[${stringifyExpression(node[2], ident)}]`;
58
+ if (node[0] === NODE.preUpdate) return `${node[1]}${wrapIfComplex(node[2], ident)}`;
59
+ if (node[0] === NODE.postUpdate) return `${wrapIfComplex(node[2], ident)}${node[1]}`;
60
+ if (node[0] === NODE.objectExpr) return `{ ${Object.entries(node[1]).map(([key, val]) => `${key}: ${stringifyExpression(val, ident)}`).join(", ")} }`;
61
+ if (node[0] === NODE.conditionalExpr) return `${wrapIfComplex(node[1], ident)} ? ${wrapIfComplex(node[2], ident)} : ${wrapIfComplex(node[3], ident)}`;
62
+ assertExhaustive(node);
63
+ }
64
+ function assertExhaustive(value) {
65
+ throw new Error(`'${JSON.stringify(value)}' was not handled by the stringify function.`);
66
+ }
67
+ function isExpression(node) {
68
+ if (typeof node === "string" || typeof node === "boolean" || node[0] === NODE.numericLiteral || node[0] === NODE.stringLiteral || node[0] === NODE.arrayExpr || node[0] === NODE.binaryExpr || node[0] === NODE.assignmentExpr || node[0] === NODE.logicalExpr || node[0] === NODE.unaryExpr || node[0] === NODE.call || node[0] === NODE.memberAccess || node[0] === NODE.indexAccess || node[0] === NODE.preUpdate || node[0] === NODE.postUpdate || node[0] === NODE.objectExpr || node[0] === NODE.conditionalExpr) return true;
69
+ return false;
70
+ }
71
+ const SIMPLE_NODES = [
72
+ NODE.memberAccess,
73
+ NODE.indexAccess,
74
+ NODE.call,
75
+ NODE.arrayExpr,
76
+ NODE.stringLiteral,
77
+ NODE.numericLiteral
78
+ ];
79
+ /**
80
+ * Stringifies expression, and wraps it in parentheses if they cannot be trivially omitted
81
+ */
82
+ function wrapIfComplex(node, ident) {
83
+ const s = stringifyExpression(node, ident);
84
+ if (typeof node === "string" || typeof node === "boolean") return s;
85
+ if (SIMPLE_NODES.includes(node[0])) return s;
86
+ return `(${s})`;
87
+ }
88
+
89
+ //#endregion
90
+ export { stringifyNode };
@@ -4,7 +4,7 @@ import { isEphemeralSnippet, snip } from "../data/snippet.js";
4
4
  import { isKnownAtComptime } from "../types.js";
5
5
  import { stitch } from "../core/resolve/stitch.js";
6
6
  import { derefSnippet } from "../data/ref.js";
7
- import { coerceToSnippet } from "./generationHelpers.js";
7
+ import { ArrayExpression, coerceToSnippet } from "./generationHelpers.js";
8
8
  import { vec2f, vec3f, vec4f } from "../data/vector.js";
9
9
  import { accessProp } from "./accessProp.js";
10
10
 
@@ -28,6 +28,7 @@ function accessIndex(target, indexArg) {
28
28
  else if (!isTargetEphemeral && !isElementNatEph) origin = target.origin;
29
29
  else if (isIndexConstant && target.origin === "constant") origin = "constant";
30
30
  else origin = "runtime";
31
+ if (target.value instanceof ArrayExpression && isKnownAtComptime(index)) return target.value.elements[index.value];
31
32
  return snip(isKnownAtComptime(target) && isKnownAtComptime(index) ? target.value[index.value] : stitch`${target}[${index}]`, elementType, origin);
32
33
  }
33
34
  if (isVec(target.dataType)) return snip(isKnownAtComptime(target) && isKnownAtComptime(index) ? target.value[index.value] : stitch`${target}[${index}]`, target.dataType.primitive, target.origin === "constant" || target.origin === "constant-tgpu-const-ref" ? "constant" : "runtime");
@@ -103,7 +103,7 @@ function logDataFromGPU(resources) {
103
103
  const { argTypes, op } = logIdToMeta.get(id);
104
104
  const results = deserializeAndStringify(new Uint32Array(serializedData), argTypes);
105
105
  if (results.length === 0) results.push("");
106
- console[op](`%c${options.messagePrefix}%c ${results[0]}`, "background: #936ff5; color: white;", "color: inherit; background: none", ...results.slice(1));
106
+ op.bind(console)(`%c${options.messagePrefix}%c ${results[0]}`, "background: #936ff5; color: white;", "color: inherit; background: none", ...results.slice(1));
107
107
  });
108
108
  });
109
109
  indexBuffer.read().then((totalCalls) => {
@@ -12,7 +12,6 @@ import { shaderStageSlot } from "../../core/slot/internalSlots.js";
12
12
  import { arrayOf } from "../../data/array.js";
13
13
  import { atomic } from "../../data/atomic.js";
14
14
  import { createLoggingFunction } from "./serializers.js";
15
- import { supportedLogOps } from "./types.js";
16
15
 
17
16
  //#region src/tgsl/consoleLog/logGenerator.ts
18
17
  const defaultOptions = {
@@ -56,11 +55,7 @@ var LogGeneratorImpl = class {
56
55
  */
57
56
  generateLog(ctx, op, args) {
58
57
  if (shaderStageSlot.$ === "vertex") {
59
- console.warn(`'console.${op}' is not supported in vertex shaders.`);
60
- return fallbackSnippet;
61
- }
62
- if (!supportedLogOps.includes(op)) {
63
- console.warn(`Unsupported log method '${op}'.`);
58
+ console.warn(`'console' operations are not supported in vertex shaders.`);
64
59
  return fallbackSnippet;
65
60
  }
66
61
  const id = this.#firstUnusedId++;
@@ -1,10 +1,11 @@
1
1
  import "../../data/snippet.js";
2
2
  import { TgpuMutable } from "../../core/buffer/bufferShorthand.js";
3
3
  import "../generationHelpers.js";
4
+ import { supportedLogOps } from "../jsPolyfills.js";
4
5
  import { AnyWgslData, Atomic, U32, WgslArray, WgslStruct } from "../../data/wgslTypes.js";
5
6
 
6
7
  //#region src/tgsl/consoleLog/types.d.ts
7
-
8
+ type SupportedLogOp = ReturnType<typeof supportedLogOps>[number];
8
9
  /**
9
10
  * Options for configuring GPU log generation.
10
11
  */
@@ -32,7 +33,7 @@ type SerializedLogCallData = WgslStruct<{
32
33
  serializedData: WgslArray<U32>;
33
34
  }>;
34
35
  interface LogMeta {
35
- op: SupportedLogOps;
36
+ op: SupportedLogOp;
36
37
  argTypes: (string | AnyWgslData)[];
37
38
  }
38
39
  /**
@@ -49,7 +50,5 @@ interface LogResources {
49
50
  options: Required<LogGeneratorOptions>;
50
51
  logIdToMeta: Map<number, LogMeta>;
51
52
  }
52
- declare const supportedLogOps: readonly ["log", "debug", "info", "warn", "error", "clear"];
53
- type SupportedLogOps = (typeof supportedLogOps)[number];
54
53
  //#endregion
55
- export { LogGeneratorOptions, LogResources };
54
+ export { LogGeneratorOptions, LogResources, SupportedLogOp };
@@ -1,5 +1,6 @@
1
1
  import { Snippet } from "../data/snippet.js";
2
2
  import { ShelllessRepository } from "./shellless.js";
3
+ import { SupportedLogOp } from "./consoleLog/types.js";
3
4
  import { FunctionScopeLayer, ResolutionCtx } from "../types.js";
4
5
  import { BaseData } from "../data/wgslTypes.js";
5
6
 
@@ -21,7 +22,7 @@ type GenerationCtx = ResolutionCtx & {
21
22
  dedent(): string;
22
23
  pushBlockScope(): void;
23
24
  popBlockScope(): void;
24
- generateLog(op: string, args: Snippet[]): Snippet;
25
+ generateLog(op: SupportedLogOp, args: Snippet[]): Snippet;
25
26
  getById(id: string): Snippet | null;
26
27
  defineVariable(id: string, snippet: Snippet): void;
27
28
  setBlockExternals(externals: Record<string, Snippet>): void;
@@ -0,0 +1,25 @@
1
+ import "../core/function/fnTypes.js";
2
+ import "../types.js";
3
+
4
+ //#region src/tgsl/jsPolyfills.d.ts
5
+ declare const supportedLogOps: () => readonly [{
6
+ (...data: any[]): void;
7
+ (message?: any, ...optionalParams: any[]): void;
8
+ }, {
9
+ (...data: any[]): void;
10
+ (message?: any, ...optionalParams: any[]): void;
11
+ }, {
12
+ (...data: any[]): void;
13
+ (message?: any, ...optionalParams: any[]): void;
14
+ }, {
15
+ (...data: any[]): void;
16
+ (message?: any, ...optionalParams: any[]): void;
17
+ }, {
18
+ (...data: any[]): void;
19
+ (message?: any, ...optionalParams: any[]): void;
20
+ }, {
21
+ (): void;
22
+ (): void;
23
+ }];
24
+ //#endregion
25
+ export { supportedLogOps };
@@ -0,0 +1,44 @@
1
+ import { f32 } from "../data/numeric.js";
2
+ import { abs, acos, acosh, asin, asinh, atan, atan2, atanh, ceil, cos, cosh, countLeadingZeros, exp, floor, log, log2, max, min, pow, sign, sin, sinh, sqrt, tan, tanh, trunc } from "../std/numeric.js";
3
+
4
+ //#region src/tgsl/jsPolyfills.ts
5
+ const mathToStd = new Map([
6
+ [Math.abs, abs],
7
+ [Math.acos, acos],
8
+ [Math.acosh, acosh],
9
+ [Math.asin, asin],
10
+ [Math.asinh, asinh],
11
+ [Math.atan, atan],
12
+ [Math.atan2, atan2],
13
+ [Math.atanh, atanh],
14
+ [Math.ceil, ceil],
15
+ [Math.cos, cos],
16
+ [Math.cosh, cosh],
17
+ [Math.exp, exp],
18
+ [Math.floor, floor],
19
+ [Math.fround, f32],
20
+ [Math.clz32, countLeadingZeros],
21
+ [Math.trunc, trunc],
22
+ [Math.log, log],
23
+ [Math.log2, log2],
24
+ [Math.pow, pow],
25
+ [Math.sign, sign],
26
+ [Math.sin, sin],
27
+ [Math.sinh, sinh],
28
+ [Math.sqrt, sqrt],
29
+ [Math.tan, tan],
30
+ [Math.tanh, tanh],
31
+ [Math.max, max],
32
+ [Math.min, min]
33
+ ]);
34
+ const supportedLogOps = () => [
35
+ console.log,
36
+ console.debug,
37
+ console.info,
38
+ console.warn,
39
+ console.error,
40
+ console.clear
41
+ ];
42
+
43
+ //#endregion
44
+ export { mathToStd, supportedLogOps };
@@ -1,7 +1,7 @@
1
1
  import { $gpuCallable, $internal, $providing, isMarkedInternal } from "../shared/symbols.js";
2
2
  import { getName } from "../shared/meta.js";
3
3
  import { Void, isBool, isNaturallyEphemeral, isNumericSchema, isPtr, isVec, isWgslArray, isWgslStruct } from "../data/wgslTypes.js";
4
- import { ConsoleLog, InfixDispatch, UnknownData, isLooseData, unptr } from "../data/dataTypes.js";
4
+ import { InfixDispatch, UnknownData, unptr } from "../data/dataTypes.js";
5
5
  import { fallthroughCopyOrigin, isEphemeralOrigin, isEphemeralSnippet, snip } from "../data/snippet.js";
6
6
  import { ResolutionError, WgslTypeError, invariant } from "../errors.js";
7
7
  import { isGPUCallable, isKnownAtComptime } from "../types.js";
@@ -24,9 +24,10 @@ import { arrayOf } from "../data/array.js";
24
24
  import { pow } from "../std/numeric.js";
25
25
  import { resolveData } from "../core/resolve/resolveData.js";
26
26
  import { UnrollableIterable } from "../core/unroll/tgpuUnroll.js";
27
- import { mathToStd } from "./math.js";
27
+ import { mathToStd, supportedLogOps } from "./jsPolyfills.js";
28
28
  import { isTgpuRange } from "../std/range.js";
29
29
  import { getElementSnippet, getElementType, getLoopVarKind, getRangeSnippets } from "./forOfUtils.js";
30
+ import { stringifyNode } from "../shared/tseynit.js";
30
31
  import * as tinyest from "tinyest";
31
32
 
32
33
  //#region src/tgsl/wgslGenerator.ts
@@ -225,8 +226,9 @@ ${this.ctx.pre}}`;
225
226
  return snip(rhsStr$1, bool, "runtime");
226
227
  }
227
228
  const rhsExpr = this._expression(rhs);
228
- if (rhsExpr.value instanceof RefOperator) throw new WgslTypeError(stitch`Cannot assign a ref to an existing variable '${lhsExpr}', define a new variable instead.`);
229
+ if (rhsExpr.value instanceof RefOperator) throw new WgslTypeError(stitch`Cannot assign a ref to an existing variable '${stringifyNode(lhs)}', define a new variable instead.`);
229
230
  if (op === "==") throw new Error("Please use the === operator instead of ==");
231
+ if (op === "!=") throw new Error("Please use the !== operator instead of !=");
230
232
  if (op === "===" && isKnownAtComptime(lhsExpr) && isKnownAtComptime(rhsExpr)) return snip(lhsExpr.value === rhsExpr.value, bool, "constant");
231
233
  if (lhsExpr.dataType === UnknownData) throw new WgslTypeError(`Left-hand side of '${op}' is of unknown type`);
232
234
  if (rhsExpr.dataType === UnknownData) throw new WgslTypeError(`Right-hand side of '${op}' is of unknown type`);
@@ -250,10 +252,13 @@ ${this.ctx.pre}}`;
250
252
  const rhsStr = this.ctx.resolve(convRhs.value, convRhs.dataType).value;
251
253
  const type = operatorToType(convLhs.dataType, op, convRhs.dataType);
252
254
  if (exprType === NODE.assignmentExpr) {
253
- if (convLhs.origin === "constant" || convLhs.origin === "constant-tgpu-const-ref" || convLhs.origin === "runtime-tgpu-const-ref") throw new WgslTypeError(`'${lhsStr} = ${rhsStr}' is invalid, because ${lhsStr} is a constant. This error may also occur when assigning to a value defined outside of a TypeGPU function's scope.`);
254
- if (lhsExpr.origin === "argument") throw new WgslTypeError(`'${lhsStr} ${op} ${rhsStr}' is invalid, because non-pointer arguments cannot be mutated.`);
255
- if (op === "=" && rhsExpr.origin === "argument" && !isNaturallyEphemeral(rhsExpr.dataType)) throw new WgslTypeError(`'${lhsStr} = ${rhsStr}' is invalid, because argument references cannot be assigned.\n-----\nTry '${lhsStr} = ${this.ctx.resolve(rhsExpr.dataType).value}(${rhsStr})' to copy the value instead.\n-----`);
256
- if (op === "=" && !isEphemeralSnippet(rhsExpr)) throw new WgslTypeError(`'${lhsStr} = ${rhsStr}' is invalid, because references cannot be assigned.\n-----\nTry '${lhsStr} = ${this.ctx.resolve(rhsExpr.dataType).value}(${rhsStr})' to copy the value instead.\n-----`);
255
+ if (convLhs.origin === "constant" || convLhs.origin === "constant-tgpu-const-ref" || convLhs.origin === "runtime-tgpu-const-ref") {
256
+ if (isKnownAtComptime(convLhs)) throw new WgslTypeError(`'${stringifyNode(expression)}' is invalid, because the left side is defined outside of the shader, and therefore is immutable during its execution. Try using tgpu.privateVar or buffers.`);
257
+ throw new WgslTypeError(`'${stringifyNode(expression)}' is invalid, because the left side is a constant.`);
258
+ }
259
+ if (lhsExpr.origin === "argument") throw new WgslTypeError(`'${stringifyNode(expression)}' is invalid, because non-pointer arguments cannot be mutated.`);
260
+ if (op === "=" && rhsExpr.origin === "argument" && !isNaturallyEphemeral(rhsExpr.dataType)) throw new WgslTypeError(`'${stringifyNode(expression)}' is invalid, because argument references cannot be assigned.\n-----\nTry '${stringifyNode(lhs)} = ${this.ctx.resolve(rhsExpr.dataType).value}(${stringifyNode(rhs)})' to copy the value instead.\n-----`);
261
+ if (op === "=" && !isEphemeralSnippet(rhsExpr)) throw new WgslTypeError(`'${stringifyNode(expression)}' is invalid, because references cannot be assigned.\n-----\nTry '${stringifyNode(lhs)} = ${this.ctx.resolve(rhsExpr.dataType).value}(${stringifyNode(rhs)})' to copy the value instead.\n-----`);
257
262
  }
258
263
  return snip(parenthesizedOps.includes(op) ? `(${lhsStr} ${OP_MAP[op] ?? op} ${rhsStr})` : `${lhsStr} ${OP_MAP[op] ?? op} ${rhsStr}`, type, "runtime");
259
264
  }
@@ -274,37 +279,28 @@ ${this.ctx.pre}}`;
274
279
  }
275
280
  if (expression[0] === NODE.memberAccess) {
276
281
  const [_, targetNode, property] = expression;
277
- const target = this._expression(targetNode);
278
- if (target.value === console) return snip(new ConsoleLog(property), UnknownData, "runtime");
279
- if (target.value === Math) {
280
- if (property in mathToStd && mathToStd[property]) return snip(mathToStd[property], UnknownData, "runtime");
281
- if (typeof Math[property] === "function") throw new Error(`Unsupported functionality 'Math.${property}'. Use an std alternative, or implement the function manually.`);
282
- }
283
- const accessed = accessProp(target, property);
284
- if (!accessed) throw new Error(stitch`Property '${property}' not found on value '${target}' of type ${this.ctx.resolve(target.dataType)}`);
282
+ const accessed = accessProp(this._expression(targetNode), property);
283
+ if (!accessed) throw new Error(`Property '${property}' not found on '${stringifyNode(targetNode)}'`);
285
284
  return accessed;
286
285
  }
287
286
  if (expression[0] === NODE.indexAccess) {
288
287
  const [_, targetNode, propertyNode] = expression;
289
288
  const target = this._expression(targetNode);
290
289
  const inProperty = this._expression(propertyNode);
291
- const property = convertToCommonType(this.ctx, [inProperty], [u32, i32], false)?.[0] ?? inProperty;
292
- const accessed = accessIndex(target, property);
293
- if (!accessed) {
294
- const targetStr = this.ctx.resolve(target.value, target.dataType).value;
295
- const propertyStr = this.ctx.resolve(property.value, property.dataType).value;
296
- throw new Error(`Index access '${targetStr}[${propertyStr}]' is invalid. If the value is an array, to address this, consider one of the following approaches: (1) declare the array using 'tgpu.const', (2) store the array in a buffer, or (3) define the array within the GPU function scope.`);
297
- }
290
+ const accessed = accessIndex(target, convertToCommonType(this.ctx, [inProperty], [u32, i32], false)?.[0] ?? inProperty);
291
+ if (!accessed) throw new Error(`Index access '${stringifyNode(expression)}' is invalid. If the value is an array, to address this, consider one of the following approaches: (1) declare the array using 'tgpu.const', (2) store the array in a buffer, or (3) define the array within the GPU function scope.`);
298
292
  return accessed;
299
293
  }
300
294
  if (expression[0] === NODE.numericLiteral) {
301
295
  const type = typeof expression[1] === "string" ? numericLiteralToSnippet(parseNumericString(expression[1])) : numericLiteralToSnippet(expression[1]);
302
- if (!type) throw new Error(`Invalid numeric literal ${expression[1]}`);
296
+ invariant(type, `Expected ${stringifyNode(expression)} to be valid numeric literal`);
303
297
  return type;
304
298
  }
305
299
  if (expression[0] === NODE.call) {
306
300
  const [_, calleeNode, argNodes] = expression;
307
- const callee = this._expression(calleeNode);
301
+ const _callee = this._expression(calleeNode);
302
+ const callee = mathToStd.has(_callee.value) ? snip(mathToStd.get(_callee.value), UnknownData, "runtime") : _callee;
303
+ if (supportedLogOps().includes(callee.value)) return this.ctx.generateLog(callee.value, argNodes.map((arg) => this._expression(arg)));
308
304
  if (isWgslStruct(callee.value)) {
309
305
  if (argNodes.length > 1) throw new WgslTypeError("Struct schemas should always be called with at most 1 argument");
310
306
  if (!argNodes[0]) return snip(`${this.ctx.resolve(callee.value).value}()`, callee.value, "runtime");
@@ -324,14 +320,13 @@ ${this.ctx.pre}}`;
324
320
  const rhs = this._expression(argNodes[0]);
325
321
  return callee.value.operator(this.ctx, [callee.value.lhs, rhs]);
326
322
  }
327
- if (callee.value instanceof ConsoleLog) return this.ctx.generateLog(callee.value.op, argNodes.map((arg) => this._expression(arg)));
328
323
  if (isGPUCallable(callee.value)) {
329
324
  const callable = callee.value[$gpuCallable];
330
325
  const strictSignature = callable.strictSignature;
331
326
  let convertedArguments;
332
327
  if (strictSignature) convertedArguments = argNodes.map((arg, i) => {
333
328
  const argType = strictSignature.argTypes[i];
334
- if (!argType) throw new WgslTypeError(`Function '${getName(callee.value)}' was called with too many arguments`);
329
+ if (!argType) throw new WgslTypeError(`Call '${stringifyNode(expression)}' is invalid since the function expected fewer arguments`);
335
330
  return this._typedExpression(arg, argType);
336
331
  });
337
332
  else convertedArguments = argNodes.map((arg) => this._expression(arg));
@@ -361,6 +356,10 @@ ${this.ctx.pre}}`;
361
356
  }));
362
357
  if (shelllessCall) return shelllessCall;
363
358
  }
359
+ const maybeMathMethod = Object.getOwnPropertyNames(Math).find((prop) => Math[prop] === callee.value);
360
+ if (maybeMathMethod) throw new Error(`Unsupported Math functionality 'Math.${maybeMathMethod}()'. Use an std alternative, or implement the function manually.`);
361
+ const maybeConsoleMethod = Object.getOwnPropertyNames(console).find((prop) => console[prop] === callee.value);
362
+ if (maybeConsoleMethod) throw new Error(`Unsupported console functionality 'console.${maybeConsoleMethod}()'.`);
364
363
  throw new Error(`Function '${getName(callee.value) ?? String(callee.value)}' is not marked with the 'use gpu' directive and cannot be used in a shader`);
365
364
  }
366
365
  if (expression[0] === NODE.objectExpr) {
@@ -391,7 +390,7 @@ ${this.ctx.pre}}`;
391
390
  const convertedSnippets = convertStructValues(this.ctx, structType, entries);
392
391
  return snip(stitch`${this.ctx.resolve(structType).value}(${convertedSnippets})`, structType, "runtime");
393
392
  }
394
- throw new WgslTypeError(`No target type could be inferred for object with keys [${Object.keys(obj).join(", ")}], please wrap the object in the corresponding schema.`);
393
+ throw new WgslTypeError(`No target type could be inferred for object '${stringifyNode(expression)}', please wrap the object in the corresponding schema.`);
395
394
  }
396
395
  if (expression[0] === NODE.arrayExpr) {
397
396
  const [_, valueNodes] = expression;
@@ -406,7 +405,7 @@ ${this.ctx.pre}}`;
406
405
  const valuesSnippets = valueNodes.map((value) => this._expression(value));
407
406
  if (valuesSnippets.length === 0) throw new WgslTypeError("Cannot infer the type of an empty array literal.");
408
407
  const converted = convertToCommonType(this.ctx, valuesSnippets);
409
- if (!converted) throw new WgslTypeError("The given values cannot be automatically converted to a common type. Consider wrapping the array in an appropriate schema");
408
+ if (!converted) throw new WgslTypeError(`Values '${stringifyNode(expression)}' cannot be automatically converted to a common type. Consider wrapping the array in an appropriate schema`);
410
409
  values = converted;
411
410
  elemType = concretize(values[0]?.dataType);
412
411
  }
@@ -417,7 +416,7 @@ ${this.ctx.pre}}`;
417
416
  const [_, test, consequent, alternative] = expression;
418
417
  const testExpression = this._expression(test);
419
418
  if (isKnownAtComptime(testExpression)) return testExpression.value ? this._expression(consequent) : this._expression(alternative);
420
- else throw new Error(`Ternary operator is only supported for comptime-known checks (used with '${testExpression.value}'). For runtime checks, please use 'std.select' or if/else statements.`);
419
+ else throw new Error(`Ternary operator '${stringifyNode(expression)}' is invalid, because only comptime-known checks are supported. For runtime checks, please use 'std.select' or if/else statements.`);
421
420
  }
422
421
  if (expression[0] === NODE.stringLiteral) return snip(expression[1], UnknownData, "constant");
423
422
  if (expression[0] === NODE.preUpdate) throw new Error("Cannot use pre-updates in TypeGPU functions.");
@@ -448,10 +447,10 @@ ${this.ctx.pre}}`;
448
447
  if (returnNode !== void 0) {
449
448
  const expectedReturnType = this.ctx.topFunctionReturnType;
450
449
  let returnSnippet = expectedReturnType ? this._typedExpression(returnNode, expectedReturnType) : this._expression(returnNode);
451
- if (returnSnippet.value instanceof RefOperator) throw new WgslTypeError(stitch`Cannot return references, returning '${returnSnippet.value.snippet}'`);
452
- if (returnSnippet.origin === "argument" && !isNaturallyEphemeral(returnSnippet.dataType) && this.ctx.topFunctionScope?.functionType === "normal") throw new WgslTypeError(stitch`Cannot return references to arguments, returning '${returnSnippet}'. Copy the argument before returning it.`);
450
+ if (returnSnippet.value instanceof RefOperator) throw new WgslTypeError(`Cannot return '${stringifyNode(returnNode)}' because it is a d.ref`);
451
+ if (returnSnippet.origin === "argument" && !isNaturallyEphemeral(returnSnippet.dataType) && this.ctx.topFunctionScope?.functionType === "normal") throw new WgslTypeError(`'${stringifyNode(statement)}' is invalid, cannot return references to arguments. Copy the argument before returning it.`);
453
452
  if (!expectedReturnType && !isEphemeralSnippet(returnSnippet) && returnSnippet.origin !== "this-function") {
454
- const str = this.ctx.resolve(returnSnippet.value, returnSnippet.dataType).value;
453
+ const str = stringifyNode(returnNode);
455
454
  const typeStr = this.ctx.resolve(unptr(returnSnippet.dataType)).value;
456
455
  throw new WgslTypeError(`'return ${str};' is invalid, cannot return references.
457
456
  -----
@@ -495,11 +494,10 @@ ${this.ctx.pre}else ${alternate}`;
495
494
  let varType = "var";
496
495
  const [stmtType, rawId, rawValue] = statement;
497
496
  const eq = rawValue !== void 0 ? this._expression(rawValue) : void 0;
498
- if (!eq) throw new Error(`Cannot create variable '${rawId}' without an initial value.`);
497
+ if (!eq) throw new Error(`'${stringifyNode(statement)}' is invalid because all variables need initializers.`);
499
498
  const ephemeral = isEphemeralSnippet(eq);
500
499
  let dataType = eq.dataType;
501
500
  const naturallyEphemeral = isNaturallyEphemeral(dataType);
502
- if (isLooseData(eq.dataType)) throw new Error(`Cannot create variable '${rawId}' with loose data type.`);
503
501
  if (eq.value instanceof RefOperator) {
504
502
  if (eq.dataType !== UnknownData) throw new WgslTypeError(`Cannot store d.ref() in a variable if it references another value. Copy the value passed into d.ref() instead.`);
505
503
  const refSnippet = eq.value.snippet;
@@ -508,7 +506,7 @@ ${this.ctx.pre}else ${alternate}`;
508
506
  }
509
507
  if (!ephemeral) {
510
508
  if (stmtType === NODE.let) {
511
- const rhsStr$1 = this.ctx.resolve(eq.value).value;
509
+ const rhsStr$1 = stringifyNode(rawValue ?? "");
512
510
  const rhsTypeStr = this.ctx.resolve(unptr(eq.dataType)).value;
513
511
  throw new WgslTypeError(`'let ${rawId} = ${rhsStr$1}' is invalid, because references cannot be assigned to 'let' variable declarations.
514
512
  -----
@@ -532,7 +530,7 @@ ${this.ctx.pre}else ${alternate}`;
532
530
  else if (naturallyEphemeral) varType = eq.origin === "constant" ? "const" : "let";
533
531
  } else if (eq.origin === "argument") {
534
532
  if (!naturallyEphemeral) {
535
- const rhsStr$1 = this.ctx.resolve(eq.value).value;
533
+ const rhsStr$1 = stringifyNode(rawValue ?? "");
536
534
  const rhsTypeStr = this.ctx.resolve(unptr(eq.dataType)).value;
537
535
  throw new WgslTypeError(`'let ${rawId} = ${rhsStr$1}' is invalid, because references to arguments cannot be assigned to 'let' variable declarations.
538
536
  -----
@@ -600,7 +598,7 @@ ${this.ctx.pre}else ${alternate}`;
600
598
  if (length === 0) return "";
601
599
  const { value } = iterableSnippet;
602
600
  const elements = isTgpuRange(value) ? value.map((i) => coerceToSnippet(i)) : value instanceof ArrayExpression ? value.elements : Array.from({ length }, (_$1, i) => getElementSnippet(iterableSnippet, snip(i, u32, "constant")));
603
- if (isEphemeralSnippet(elements[0]) && !isNaturallyEphemeral(elements[0]?.dataType)) throw new WgslTypeError("Cannot unroll loop. The elements of iterable are emphemeral but not naturally ephemeral.");
601
+ if (isEphemeralSnippet(elements[0]) && !isNaturallyEphemeral(elements[0]?.dataType)) throw new WgslTypeError(`Cannot unroll '${stringifyNode(iterable)}'. The elements of iterable are constructed in place but are not value types.`);
604
602
  return elements.map((e, i) => `${this.ctx.pre}// unrolled iteration #${i}\n${this.ctx.pre}${this._block(blockified, { [originalLoopVarName]: e })}`).join("\n");
605
603
  }
606
604
  this.#unrolling = false;
@@ -1,12 +0,0 @@
1
- //#region src/tgsl/consoleLog/types.ts
2
- const supportedLogOps = [
3
- "log",
4
- "debug",
5
- "info",
6
- "warn",
7
- "error",
8
- "clear"
9
- ];
10
-
11
- //#endregion
12
- export { supportedLogOps };
package/tgsl/math.js DELETED
@@ -1,45 +0,0 @@
1
- import { f32 } from "../data/numeric.js";
2
- import { abs, acos, acosh, asin, asinh, atan, atan2, atanh, ceil, cos, cosh, countLeadingZeros, exp, floor, log, log2, max, min, pow, sign, sin, sinh, sqrt, tan, tanh, trunc } from "../std/numeric.js";
3
-
4
- //#region src/tgsl/math.ts
5
- const mathToStd = {
6
- abs,
7
- acos,
8
- acosh,
9
- asin,
10
- asinh,
11
- atan,
12
- atan2,
13
- atanh,
14
- ceil,
15
- cos,
16
- cosh,
17
- exp,
18
- floor,
19
- fround: f32,
20
- clz32: countLeadingZeros,
21
- trunc,
22
- log,
23
- log2,
24
- pow,
25
- sign,
26
- sin,
27
- sinh,
28
- sqrt,
29
- tan,
30
- tanh,
31
- max,
32
- min,
33
- cbrt: void 0,
34
- log10: void 0,
35
- log1p: void 0,
36
- f16round: void 0,
37
- hypot: void 0,
38
- expm1: void 0,
39
- random: void 0,
40
- imul: void 0,
41
- round: void 0
42
- };
43
-
44
- //#endregion
45
- export { mathToStd };