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 +1 -1
- package/core/buffer/buffer.js +17 -53
- package/core/function/tgpuFragmentFn.d.ts +1 -1
- package/core/pipeline/computePipeline.d.ts +1 -1
- package/core/root/init.d.ts +1 -0
- package/core/root/init.js +6 -0
- package/core/root/rootTypes.d.ts +21 -15
- package/core/slot/accessor.js +1 -1
- package/data/dataIO.d.ts +11 -0
- package/data/dataIO.js +45 -1
- package/data/dataTypes.js +2 -11
- package/data/partialIO.d.ts +8 -0
- package/data/partialIO.js +6 -1
- package/index.d.ts +3 -1
- package/index.js +3 -1
- package/indexNamedExports.d.ts +2 -0
- package/package.js +1 -1
- package/package.json +1 -1
- package/resolutionCtx.js +1 -2
- package/shared/stringify.js +1 -0
- package/shared/tseynit.js +90 -0
- package/tgsl/accessIndex.js +2 -1
- package/tgsl/consoleLog/deserializers.js +1 -1
- package/tgsl/consoleLog/logGenerator.js +1 -6
- package/tgsl/consoleLog/types.d.ts +4 -5
- package/tgsl/generationHelpers.d.ts +2 -1
- package/tgsl/jsPolyfills.d.ts +25 -0
- package/tgsl/jsPolyfills.js +44 -0
- package/tgsl/wgslGenerator.js +35 -37
- package/tgsl/consoleLog/types.js +0 -12
- package/tgsl/math.js +0 -45
package/README.md
CHANGED
package/core/buffer/buffer.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { $internal } from "../../shared/symbols.js";
|
|
2
2
|
import { getName, setName } from "../../shared/meta.js";
|
|
3
|
-
import {
|
|
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 {
|
|
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)
|
|
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
|
-
|
|
138
|
+
writeToArrayBuffer(mapped, this.dataType, data, options);
|
|
174
139
|
return;
|
|
175
140
|
}
|
|
176
|
-
if (!(data instanceof ArrayBuffer && data === this.#hostBuffer))
|
|
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
|
|
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
|
-
|
|
190
|
-
const
|
|
191
|
-
for (const { data, gpuOffset } of instructions)
|
|
192
|
-
}
|
|
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
|
|
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 =
|
|
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 =
|
|
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";
|
package/core/root/init.d.ts
CHANGED
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)));
|
package/core/root/rootTypes.d.ts
CHANGED
|
@@ -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 `
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
package/core/slot/accessor.js
CHANGED
|
@@ -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]() {
|
package/data/dataIO.d.ts
ADDED
|
@@ -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 {
|
|
602
|
+
export { calculateOffsets, readFromArrayBuffer, writeData, writeToArrayBuffer };
|
package/data/dataTypes.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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 };
|
package/indexNamedExports.d.ts
CHANGED
|
@@ -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
package/package.json
CHANGED
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 ${
|
|
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);
|
package/shared/stringify.js
CHANGED
|
@@ -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 };
|
package/tgsl/accessIndex.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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 };
|
package/tgsl/wgslGenerator.js
CHANGED
|
@@ -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 {
|
|
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 "./
|
|
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 '${
|
|
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")
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
|
278
|
-
if (
|
|
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
|
|
292
|
-
|
|
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
|
-
|
|
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
|
|
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(`
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
452
|
-
if (returnSnippet.origin === "argument" && !isNaturallyEphemeral(returnSnippet.dataType) && this.ctx.topFunctionScope?.functionType === "normal") throw new WgslTypeError(
|
|
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 =
|
|
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(`
|
|
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 =
|
|
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 =
|
|
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(
|
|
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;
|
package/tgsl/consoleLog/types.js
DELETED
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 };
|