typegpu 0.12.7 → 0.12.8
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/core/function/autoIO.js +2 -2
- package/core/function/comptime.js +7 -5
- package/core/function/createCallableSchema.js +4 -3
- package/core/function/dualImpl.js +20 -19
- package/core/function/ioSchema.d.ts +10 -0
- package/core/function/ioSchema.js +37 -16
- package/core/function/tgpuFn.d.ts +11 -1
- package/core/function/tgpuFn.js +9 -2
- package/core/pipeline/renderPipeline.d.ts +4 -2
- package/core/pipeline/renderPipeline.js +12 -10
- package/core/pipeline/timeable.js +15 -2
- package/core/root/configurableImpl.js +1 -2
- package/core/texture/externalTexture.d.ts +1 -1
- package/core/texture/externalTexture.js +3 -1
- package/core/texture/texture.d.ts +1 -1
- package/core/texture/texture.js +4 -1
- package/core/unroll/tgpuUnroll.d.ts +4 -3
- package/core/unroll/tgpuUnroll.js +7 -1
- package/core/valueProxyUtils.d.ts +4 -2
- package/core/valueProxyUtils.js +4 -2
- package/data/compiledIO.js +12 -9
- package/data/dataIO.d.ts +10 -6
- package/data/dataIO.js +19 -4
- package/data/dataTypes.d.ts +0 -5
- package/data/dataTypes.js +0 -6
- package/data/matrixColumnsAccess.d.ts +8 -0
- package/data/matrixColumnsAccess.js +15 -0
- package/data/offsetUtils.js +181 -102
- package/data/ref.d.ts +12 -5
- package/data/ref.js +50 -23
- package/data/snippet.d.ts +7 -0
- package/data/snippet.js +9 -0
- package/data/struct.js +3 -0
- package/data/wgslTypes.d.ts +3 -3
- package/package.json +1 -1
- package/resolutionCtx.js +1 -1
- package/shared/meta.js +1 -1
- package/shared/symbols.d.ts +5 -0
- package/shared/symbols.js +6 -1
- package/std/numeric.js +1 -4
- package/std/packing.js +10 -10
- package/tgpuLogger.d.ts +1 -1
- package/tgpuLogger.js +0 -2
- package/tgsl/accessIndex.js +18 -15
- package/tgsl/accessProp.js +10 -7
- package/tgsl/conversion.js +3 -2
- package/tgsl/forOfUtils.js +2 -2
- package/tgsl/generationHelpers.d.ts +4 -3
- package/tgsl/generationHelpers.js +16 -3
- package/tgsl/infixDispatch.d.ts +4 -1
- package/tgsl/infixDispatch.js +13 -1
- package/tgsl/makeDereferenceable.d.ts +1 -1
- package/tgsl/makeDereferenceable.js +3 -1
- package/tgsl/shellless.js +5 -9
- package/tgsl/stringifySnippet.d.ts +9 -0
- package/tgsl/stringifySnippet.js +24 -0
- package/tgsl/wgslGenerator.d.ts +1 -0
- package/tgsl/wgslGenerator.js +98 -66
- package/types.d.ts +23 -2
- package/types.js +30 -5
package/data/snippet.js
CHANGED
|
@@ -49,9 +49,18 @@ export const originToPtrParams = {
|
|
|
49
49
|
// Local declarations are also in the `function` address space
|
|
50
50
|
'local-def': { space: 'function', access: 'read-write' },
|
|
51
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* Whether values of this origin can have their address taken.
|
|
54
|
+
*/
|
|
52
55
|
export function isAddressableOrigin(origin) {
|
|
53
56
|
return origin in originToPtrParams;
|
|
54
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Whether values of this origin can be mutated.
|
|
60
|
+
*/
|
|
61
|
+
export function isMutableOrigin(origin) {
|
|
62
|
+
return isAddressableOrigin(origin) && originToPtrParams[origin].access === 'read-write';
|
|
63
|
+
}
|
|
55
64
|
class SnippetImpl {
|
|
56
65
|
value;
|
|
57
66
|
dataType;
|
package/data/struct.js
CHANGED
|
@@ -17,6 +17,9 @@ import { schemaCallWrapper } from "./schemaCallWrapper.js";
|
|
|
17
17
|
* each entry describing one struct member.
|
|
18
18
|
*/
|
|
19
19
|
export function struct(props) {
|
|
20
|
+
if (Object.keys(props).length === 0) {
|
|
21
|
+
throw new Error('Cannot create struct schema with no properties.');
|
|
22
|
+
}
|
|
20
23
|
return INTERNAL_createStruct(props, false);
|
|
21
24
|
}
|
|
22
25
|
export function abstruct(props) {
|
package/data/wgslTypes.d.ts
CHANGED
|
@@ -704,7 +704,7 @@ export interface Mat2x2f extends BaseData {
|
|
|
704
704
|
readonly type: 'mat2x2f';
|
|
705
705
|
readonly primitive: F32;
|
|
706
706
|
readonly [$repr]: m2x2f;
|
|
707
|
-
readonly [$inRepr]: m2x2f | readonly number
|
|
707
|
+
readonly [$inRepr]: m2x2f | readonly [number, number, number, number] | Float32Array;
|
|
708
708
|
readonly [$validStorageSchema]: true;
|
|
709
709
|
readonly [$validUniformSchema]: true;
|
|
710
710
|
(...elements: [number, number, number, number]): m2x2f;
|
|
@@ -720,7 +720,7 @@ export interface Mat3x3f extends BaseData {
|
|
|
720
720
|
readonly type: 'mat3x3f';
|
|
721
721
|
readonly primitive: F32;
|
|
722
722
|
readonly [$repr]: m3x3f;
|
|
723
|
-
readonly [$inRepr]: m3x3f | readonly number
|
|
723
|
+
readonly [$inRepr]: m3x3f | readonly [number, number, number, number, number, number, number, number, number] | Float32Array;
|
|
724
724
|
readonly [$validStorageSchema]: true;
|
|
725
725
|
readonly [$validUniformSchema]: true;
|
|
726
726
|
(...elements: [number, number, number, number, number, number, number, number, number]): m3x3f;
|
|
@@ -736,7 +736,7 @@ export interface Mat4x4f extends BaseData {
|
|
|
736
736
|
readonly type: 'mat4x4f';
|
|
737
737
|
readonly primitive: F32;
|
|
738
738
|
readonly [$repr]: m4x4f;
|
|
739
|
-
readonly [$inRepr]: m4x4f | readonly number
|
|
739
|
+
readonly [$inRepr]: m4x4f | readonly [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number] | Float32Array;
|
|
740
740
|
readonly [$validStorageSchema]: true;
|
|
741
741
|
readonly [$validUniformSchema]: true;
|
|
742
742
|
(...elements: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]): m4x4f;
|
package/package.json
CHANGED
package/resolutionCtx.js
CHANGED
|
@@ -417,7 +417,7 @@ export class ResolutionCtxImpl {
|
|
|
417
417
|
return this._indentController.dedent();
|
|
418
418
|
}
|
|
419
419
|
getDedented(code) {
|
|
420
|
-
return code.replaceAll(`\n${INDENT[1]}`, '\n');
|
|
420
|
+
return code.replaceAll(`\n${INDENT[1]}`, '\n').replaceAll(new RegExp(`^${INDENT[1]}`, 'g'), '');
|
|
421
421
|
}
|
|
422
422
|
withResetIndentLevel(callback) {
|
|
423
423
|
return this._indentController.withResetLevel(callback);
|
package/shared/meta.js
CHANGED
package/shared/symbols.d.ts
CHANGED
|
@@ -18,6 +18,11 @@ export declare const $providing: unique symbol;
|
|
|
18
18
|
* Objects can provide the snippet that represents them.
|
|
19
19
|
*/
|
|
20
20
|
export declare const $ownSnippet: unique symbol;
|
|
21
|
+
/**
|
|
22
|
+
* Objects can provide the value that they represent at comptime (e.g. when passed
|
|
23
|
+
* into comptime functions), or signal that they are not known at comptime.
|
|
24
|
+
*/
|
|
25
|
+
export declare const $comptimeValueOf: unique symbol;
|
|
21
26
|
export declare const $resolve: unique symbol;
|
|
22
27
|
/**
|
|
23
28
|
* A way for a schema to provide casting behavior, without the need to be explicitly
|
package/shared/symbols.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = "0.12.
|
|
1
|
+
const version = "0.12.8";
|
|
2
2
|
export const $internal = Symbol(`typegpu:${version}:$internal`);
|
|
3
3
|
/** A plain record of all definitional state of a resource, surviving transfer between runtimes */
|
|
4
4
|
export const $soul = Symbol(`typegpu:${version}:$soul`);
|
|
@@ -19,6 +19,11 @@ export const $providing = Symbol(`typegpu:${version}:$providing`);
|
|
|
19
19
|
* Objects can provide the snippet that represents them.
|
|
20
20
|
*/
|
|
21
21
|
export const $ownSnippet = Symbol(`typegpu:${version}:$ownSnippet`);
|
|
22
|
+
/**
|
|
23
|
+
* Objects can provide the value that they represent at comptime (e.g. when passed
|
|
24
|
+
* into comptime functions), or signal that they are not known at comptime.
|
|
25
|
+
*/
|
|
26
|
+
export const $comptimeValueOf = Symbol(`typegpu:${version}:$comptimeValueOf`);
|
|
22
27
|
export const $resolve = Symbol(`typegpu:${version}:$resolve`);
|
|
23
28
|
/**
|
|
24
29
|
* A way for a schema to provide casting behavior, without the need to be explicitly
|
package/std/numeric.js
CHANGED
|
@@ -747,10 +747,7 @@ export const round = dualImpl({
|
|
|
747
747
|
});
|
|
748
748
|
function cpuSaturate(value) {
|
|
749
749
|
assertKind(value, floatKind);
|
|
750
|
-
|
|
751
|
-
return Math.max(0, Math.min(1, value));
|
|
752
|
-
}
|
|
753
|
-
throw new MissingCpuImplError('CPU implementation for saturate on vectors not implemented yet. Please submit an issue at https://github.com/software-mansion/TypeGPU/issues');
|
|
750
|
+
return generalizeFn((value) => clampScalar(value, 0, 1), [value]);
|
|
754
751
|
}
|
|
755
752
|
export const saturate = dualImpl({
|
|
756
753
|
name: 'saturate',
|
package/std/packing.js
CHANGED
|
@@ -96,7 +96,7 @@ export const unpack4x8unorm = dualImpl({
|
|
|
96
96
|
return vec4f(reader.readUint8() / 255, reader.readUint8() / 255, reader.readUint8() / 255, reader.readUint8() / 255);
|
|
97
97
|
},
|
|
98
98
|
signature: { argTypes: [u32], returnType: vec4f },
|
|
99
|
-
codegenImpl: (
|
|
99
|
+
codegenImpl: (ctx, [e]) => ctx.gen.emitCall('unpack4x8unorm', [], [e]),
|
|
100
100
|
sideEffects: false,
|
|
101
101
|
});
|
|
102
102
|
/**
|
|
@@ -110,7 +110,7 @@ export const unpack4x8snorm = dualImpl({
|
|
|
110
110
|
return vec4f(Math.max(reader.readInt8() / 127, -1), Math.max(reader.readInt8() / 127, -1), Math.max(reader.readInt8() / 127, -1), Math.max(reader.readInt8() / 127, -1));
|
|
111
111
|
},
|
|
112
112
|
signature: { argTypes: [u32], returnType: vec4f },
|
|
113
|
-
codegenImpl: (
|
|
113
|
+
codegenImpl: (ctx, [e]) => ctx.gen.emitCall('unpack4x8snorm', [], [e]),
|
|
114
114
|
sideEffects: false,
|
|
115
115
|
});
|
|
116
116
|
/**
|
|
@@ -124,7 +124,7 @@ export const unpack4xI8 = dualImpl({
|
|
|
124
124
|
return vec4i(reader.readInt8(), reader.readInt8(), reader.readInt8(), reader.readInt8());
|
|
125
125
|
},
|
|
126
126
|
signature: { argTypes: [u32], returnType: vec4i },
|
|
127
|
-
codegenImpl: (
|
|
127
|
+
codegenImpl: (ctx, [e]) => ctx.gen.emitCall('unpack4xI8', [], [e]),
|
|
128
128
|
sideEffects: false,
|
|
129
129
|
});
|
|
130
130
|
/**
|
|
@@ -138,7 +138,7 @@ export const unpack4xU8 = dualImpl({
|
|
|
138
138
|
return vec4u(reader.readUint8(), reader.readUint8(), reader.readUint8(), reader.readUint8());
|
|
139
139
|
},
|
|
140
140
|
signature: { argTypes: [u32], returnType: vec4u },
|
|
141
|
-
codegenImpl: (
|
|
141
|
+
codegenImpl: (ctx, [e]) => ctx.gen.emitCall('unpack4xU8', [], [e]),
|
|
142
142
|
sideEffects: false,
|
|
143
143
|
});
|
|
144
144
|
/**
|
|
@@ -182,7 +182,7 @@ export const pack4x8unorm = dualImpl({
|
|
|
182
182
|
writer.writeUint8(Math.floor(0.5 + 255 * clampScalar(e.w, 0, 1)));
|
|
183
183
|
}),
|
|
184
184
|
signature: { argTypes: [vec4f], returnType: u32 },
|
|
185
|
-
codegenImpl: (
|
|
185
|
+
codegenImpl: (ctx, [e]) => ctx.gen.emitCall('pack4x8unorm', [], [e]),
|
|
186
186
|
sideEffects: false,
|
|
187
187
|
});
|
|
188
188
|
/**
|
|
@@ -198,7 +198,7 @@ export const pack4x8snorm = dualImpl({
|
|
|
198
198
|
writer.writeInt8(Math.floor(0.5 + 127 * clampScalar(e.w, -1, 1)));
|
|
199
199
|
}),
|
|
200
200
|
signature: { argTypes: [vec4f], returnType: u32 },
|
|
201
|
-
codegenImpl: (
|
|
201
|
+
codegenImpl: (ctx, [e]) => ctx.gen.emitCall('pack4x8snorm', [], [e]),
|
|
202
202
|
sideEffects: false,
|
|
203
203
|
});
|
|
204
204
|
/**
|
|
@@ -214,7 +214,7 @@ export const pack4xI8 = dualImpl({
|
|
|
214
214
|
writer.writeInt8(e.w);
|
|
215
215
|
}),
|
|
216
216
|
signature: { argTypes: [vec4i], returnType: u32 },
|
|
217
|
-
codegenImpl: (
|
|
217
|
+
codegenImpl: (ctx, [e]) => ctx.gen.emitCall('pack4xI8', [], [e]),
|
|
218
218
|
sideEffects: false,
|
|
219
219
|
});
|
|
220
220
|
/**
|
|
@@ -230,7 +230,7 @@ export const pack4xU8 = dualImpl({
|
|
|
230
230
|
writer.writeUint8(e.w);
|
|
231
231
|
}),
|
|
232
232
|
signature: { argTypes: [vec4u], returnType: u32 },
|
|
233
|
-
codegenImpl: (
|
|
233
|
+
codegenImpl: (ctx, [e]) => ctx.gen.emitCall('pack4xU8', [], [e]),
|
|
234
234
|
sideEffects: false,
|
|
235
235
|
});
|
|
236
236
|
/**
|
|
@@ -246,7 +246,7 @@ export const pack4xI8Clamp = dualImpl({
|
|
|
246
246
|
writer.writeInt8(clampScalar(e.w, -128, 127));
|
|
247
247
|
}),
|
|
248
248
|
signature: { argTypes: [vec4i], returnType: u32 },
|
|
249
|
-
codegenImpl: (
|
|
249
|
+
codegenImpl: (ctx, [e]) => ctx.gen.emitCall('pack4xI8Clamp', [], [e]),
|
|
250
250
|
sideEffects: false,
|
|
251
251
|
});
|
|
252
252
|
/**
|
|
@@ -262,6 +262,6 @@ export const pack4xU8Clamp = dualImpl({
|
|
|
262
262
|
writer.writeUint8(clampScalar(e.w, 0, 255));
|
|
263
263
|
}),
|
|
264
264
|
signature: { argTypes: [vec4u], returnType: u32 },
|
|
265
|
-
codegenImpl: (
|
|
265
|
+
codegenImpl: (ctx, [e]) => ctx.gen.emitCall('pack4xU8Clamp', [], [e]),
|
|
266
266
|
sideEffects: false,
|
|
267
267
|
});
|
package/tgpuLogger.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare const warningTypes: readonly ["deprecated", "suspicious", "fallback", "precision-loss", "implicit-conversion", "webgpu-feature-missing", "webgpu-limits-exceeded", "
|
|
1
|
+
declare const warningTypes: readonly ["deprecated", "suspicious", "fallback", "precision-loss", "implicit-conversion", "webgpu-feature-missing", "webgpu-limits-exceeded", "log-limit-exceeded", "external-omitted", "uniform-schema-misaligned"];
|
|
2
2
|
type WarningType = (typeof warningTypes)[number];
|
|
3
3
|
interface Logger {
|
|
4
4
|
warn(type: WarningType, ...args: unknown[]): void;
|
package/tgpuLogger.js
CHANGED
|
@@ -7,7 +7,6 @@ const warningTypes = [
|
|
|
7
7
|
'implicit-conversion',
|
|
8
8
|
'webgpu-feature-missing',
|
|
9
9
|
'webgpu-limits-exceeded',
|
|
10
|
-
'locations-mismatched',
|
|
11
10
|
'log-limit-exceeded',
|
|
12
11
|
'external-omitted',
|
|
13
12
|
'uniform-schema-misaligned',
|
|
@@ -21,7 +20,6 @@ export class TgpuLogger {
|
|
|
21
20
|
this.#initialEnabledWarnings = [
|
|
22
21
|
'webgpu-feature-missing',
|
|
23
22
|
'webgpu-limits-exceeded',
|
|
24
|
-
'locations-mismatched',
|
|
25
23
|
'log-limit-exceeded',
|
|
26
24
|
'external-omitted',
|
|
27
25
|
];
|
package/tgsl/accessIndex.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { stitch } from "../core/resolve/stitch.js";
|
|
2
|
-
import { isDisarray
|
|
2
|
+
import { isDisarray } from "../data/dataTypes.js";
|
|
3
|
+
import { MatrixColumnsAccess } from "../data/matrixColumnsAccess.js";
|
|
3
4
|
import { derefSnippet } from "../data/ref.js";
|
|
4
5
|
import { snip } from "../data/snippet.js";
|
|
5
6
|
import { vec2f, vec3f, vec4f } from "../data/vector.js";
|
|
6
|
-
import { isPtr, isVec, isWgslArray
|
|
7
|
-
import {
|
|
7
|
+
import { isPtr, isVec, isWgslArray } from "../data/wgslTypes.js";
|
|
8
|
+
import { asComptime } from "../types.js";
|
|
8
9
|
import { accessProp } from "./accessProp.js";
|
|
9
10
|
import { ArrayExpression, coerceToSnippet } from "./generationHelpers.js";
|
|
10
11
|
const indexableTypeToResult = {
|
|
@@ -30,24 +31,27 @@ function deriveIndexAccessOrigin(targetOrigin, indexOrigin) {
|
|
|
30
31
|
}
|
|
31
32
|
export function accessIndex(target, indexArg) {
|
|
32
33
|
const index = typeof indexArg === 'number' ? coerceToSnippet(indexArg) : indexArg;
|
|
34
|
+
const knownIndex = asComptime(index);
|
|
33
35
|
// array
|
|
34
36
|
if (isWgslArray(target.dataType) || isDisarray(target.dataType)) {
|
|
35
37
|
const elementType = target.dataType.elementType;
|
|
36
|
-
if (target.value instanceof ArrayExpression &&
|
|
37
|
-
return target.value.elements[
|
|
38
|
+
if (target.value instanceof ArrayExpression && knownIndex) {
|
|
39
|
+
return target.value.elements[knownIndex.value];
|
|
38
40
|
}
|
|
39
41
|
const origin = deriveIndexAccessOrigin(target.origin, index.origin);
|
|
40
|
-
|
|
42
|
+
const knownTarget = knownIndex && asComptime(target);
|
|
43
|
+
return snip(knownTarget && knownIndex
|
|
41
44
|
? // oxlint-disable-next-line typescript/no-explicit-any -- it's fine, it's there
|
|
42
|
-
|
|
45
|
+
knownTarget.value[knownIndex.value]
|
|
43
46
|
: stitch `${target}[${index}]`, elementType,
|
|
44
47
|
/* origin */ origin, target.possibleSideEffects || index.possibleSideEffects);
|
|
45
48
|
}
|
|
46
49
|
// vector
|
|
47
50
|
if (isVec(target.dataType)) {
|
|
48
|
-
|
|
51
|
+
const knownTarget = knownIndex && asComptime(target);
|
|
52
|
+
return snip(knownTarget && knownIndex
|
|
49
53
|
? // oxlint-disable-next-line typescript/no-explicit-any -- it's fine, it's there
|
|
50
|
-
|
|
54
|
+
knownTarget.value[knownIndex.value]
|
|
51
55
|
: stitch `${target}[${index}]`, target.dataType.primitive, deriveIndexAccessOrigin(target.origin, index.origin), target.possibleSideEffects || index.possibleSideEffects);
|
|
52
56
|
}
|
|
53
57
|
if (isPtr(target.dataType)) {
|
|
@@ -64,16 +68,15 @@ export function accessIndex(target, indexArg) {
|
|
|
64
68
|
if (target.dataType.type in indexableTypeToResult) {
|
|
65
69
|
throw new Error("The only way of accessing matrix elements in TypeGPU functions is through the 'columns' property.");
|
|
66
70
|
}
|
|
67
|
-
|
|
71
|
+
const knownTarget = knownIndex && asComptime(target);
|
|
72
|
+
if (knownTarget && knownIndex) {
|
|
68
73
|
// No idea what the type is, so we act on the snippet's value and try to guess
|
|
69
74
|
return coerceToSnippet(
|
|
70
75
|
// oxlint-disable-next-line typescript/no-explicit-any -- we're inspecting the value, and it could be any value
|
|
71
|
-
|
|
76
|
+
knownTarget.value[knownIndex.value]);
|
|
72
77
|
}
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
typeof index.value === 'string') {
|
|
76
|
-
return accessProp(target, index.value);
|
|
78
|
+
if (typeof knownIndex?.value === 'string') {
|
|
79
|
+
return accessProp(target, knownIndex.value);
|
|
77
80
|
}
|
|
78
81
|
return undefined;
|
|
79
82
|
}
|
package/tgsl/accessProp.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { stitch } from "../core/resolve/stitch.js";
|
|
2
2
|
import { AutoStruct } from "../data/autoStruct.js";
|
|
3
3
|
import { EntryInputRouter } from "../core/function/entryInputRouter.js";
|
|
4
|
-
import { isUnstruct,
|
|
4
|
+
import { isUnstruct, UnknownData } from "../data/dataTypes.js";
|
|
5
|
+
import { MatrixColumnsAccess } from "../data/matrixColumnsAccess.js";
|
|
5
6
|
import { bool, f16, f32, i32, u32 } from "../data/numeric.js";
|
|
6
7
|
import { derefSnippet } from "../data/ref.js";
|
|
7
8
|
import { isSnippet, snip } from "../data/snippet.js";
|
|
8
9
|
import { vec2b, vec2f, vec2h, vec2i, vec2u, vec3b, vec3f, vec3h, vec3i, vec3u, vec4b, vec4f, vec4h, vec4i, vec4u, } from "../data/vector.js";
|
|
9
10
|
import { isMat, isPtr, isVec, isWgslArray, isWgslStruct, } from "../data/wgslTypes.js";
|
|
10
|
-
import {
|
|
11
|
+
import { asComptime } from "../types.js";
|
|
11
12
|
import { coerceToSnippet, numericLiteralToSnippet } from "./generationHelpers.js";
|
|
12
13
|
import { InfixDispatch, infixOperators } from "./infixDispatch.js";
|
|
13
14
|
import { accessStructProp } from "./accessStructProp.js";
|
|
@@ -128,9 +129,10 @@ export function accessProp(target, propName) {
|
|
|
128
129
|
if (!swizzleType) {
|
|
129
130
|
return undefined;
|
|
130
131
|
}
|
|
131
|
-
|
|
132
|
+
const knownTarget = asComptime(target);
|
|
133
|
+
return snip(knownTarget
|
|
132
134
|
? // oxlint-disable-next-line typescript/no-explicit-any -- it's fine, the prop is there
|
|
133
|
-
|
|
135
|
+
knownTarget.value[propName]
|
|
134
136
|
: stitch `${target}.${propName}`, swizzleType,
|
|
135
137
|
// Swizzling creates new vectors (unless they're on the lhs of an assignment, but that's not yet supported in WGSL)
|
|
136
138
|
/* origin */ propLength === 1
|
|
@@ -139,9 +141,10 @@ export function accessProp(target, propName) {
|
|
|
139
141
|
? 'constant'
|
|
140
142
|
: 'runtime', target.possibleSideEffects);
|
|
141
143
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
const knownTarget = asComptime(target);
|
|
145
|
+
if (knownTarget) {
|
|
146
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
147
|
+
const prop = knownTarget.value[propName];
|
|
145
148
|
if (isNamable(prop) && getName(prop) === undefined) {
|
|
146
149
|
setName(prop, propName);
|
|
147
150
|
}
|
package/tgsl/conversion.js
CHANGED
|
@@ -10,6 +10,7 @@ import { safeStringify } from "../shared/stringify.js";
|
|
|
10
10
|
import { assertExhaustive } from "../shared/utilityTypes.js";
|
|
11
11
|
import { logger } from "../tgpuLogger.js";
|
|
12
12
|
import { accessStructProp } from "./accessStructProp.js";
|
|
13
|
+
import { stringifySnippet } from "./stringifySnippet.js";
|
|
13
14
|
const INFINITE_RANK = {
|
|
14
15
|
rank: Number.POSITIVE_INFINITY,
|
|
15
16
|
action: 'none',
|
|
@@ -254,7 +255,7 @@ export function convertToCommonType(ctx, values, restrictTo, verbose = true) {
|
|
|
254
255
|
}
|
|
255
256
|
if (verbose && conversion.hasImplicitConversions) {
|
|
256
257
|
logger.warn('implicit-conversion', `Implicit conversions from [\n${values
|
|
257
|
-
.map((v) => ` ${
|
|
258
|
+
.map((v) => ` ${stringifySnippet(v)}: ${safeStringify(v.dataType)}`)
|
|
258
259
|
.join(',\n')}\n] to ${conversion.targetType.type} are supported, but not recommended.
|
|
259
260
|
Consider using explicit conversions instead.`);
|
|
260
261
|
}
|
|
@@ -281,7 +282,7 @@ export function tryConvertSnippet(ctx, snippet, targetDataTypes, verbose = true)
|
|
|
281
282
|
if (converted) {
|
|
282
283
|
return converted[0];
|
|
283
284
|
}
|
|
284
|
-
throw new WgslTypeError(`Cannot convert
|
|
285
|
+
throw new WgslTypeError(`Cannot convert '${stringifySnippet(snippet)}' of type '${String(dataType)}' to any of the target types: [${targets.map((t) => t.type).join(', ')}]`);
|
|
285
286
|
}
|
|
286
287
|
export function convertStructValues(ctx, structType, values) {
|
|
287
288
|
return Object.entries(structType.propTypes).map(([key, targetType]) => {
|
package/tgsl/forOfUtils.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { UnknownData } from "../data/dataTypes.js";
|
|
2
2
|
import { isAddressableOrigin, isStoredInMemory, snip } from "../data/snippet.js";
|
|
3
|
-
import { stitch } from "../core/resolve/stitch.js";
|
|
4
3
|
import * as wgsl from "../data/wgslTypes.js";
|
|
5
4
|
import { i32, u32 } from "../data/numeric.js";
|
|
6
5
|
import { invariant, WgslTypeError } from "../errors.js";
|
|
@@ -9,6 +8,7 @@ import { accessIndex } from "./accessIndex.js";
|
|
|
9
8
|
import { createPtrFromOrigin, implicitFrom } from "../data/ptr.js";
|
|
10
9
|
import { $gpuCallable } from "../shared/symbols.js";
|
|
11
10
|
import { ArrayExpression, concretize } from "./generationHelpers.js";
|
|
11
|
+
import { stringifySnippet } from "./stringifySnippet.js";
|
|
12
12
|
import { isTgpuRange } from "../std/range.js";
|
|
13
13
|
export function getLoopVarKind(elementSnippet) {
|
|
14
14
|
// If it's ephemeral, it's a value that cannot change. If it's a reference, we take
|
|
@@ -28,7 +28,7 @@ export function getElementSnippet(iterableSnippet, index) {
|
|
|
28
28
|
export function getElementType(elementSnippet, iterableSnippet) {
|
|
29
29
|
let elementType = elementSnippet.dataType;
|
|
30
30
|
if (elementType === UnknownData) {
|
|
31
|
-
throw new WgslTypeError(
|
|
31
|
+
throw new WgslTypeError(`The elements in iterable '${stringifySnippet(iterableSnippet)}' are of unknown type`);
|
|
32
32
|
}
|
|
33
33
|
if (wgsl.isNaturallyEphemeral(elementSnippet.dataType) ||
|
|
34
34
|
!isAddressableOrigin(elementSnippet.origin)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ResolvedSnippet, Snippet } from '../data/snippet.ts';
|
|
2
2
|
import { type AnyWgslData, type BaseData, type F32, type I32, type WgslArray } from '../data/wgslTypes.ts';
|
|
3
|
-
import { type ResolutionCtx, type SelfResolvable } from '../types.ts';
|
|
4
|
-
import { $internal, $resolve } from '../shared/symbols.ts';
|
|
3
|
+
import { type ComptimeValue, type ResolutionCtx, type SelfResolvable, type WithComptimeValue } from '../types.ts';
|
|
4
|
+
import { $comptimeValueOf, $internal, $resolve } from '../shared/symbols.ts';
|
|
5
5
|
export declare function numericLiteralToSnippet(value: number): Snippet;
|
|
6
6
|
export declare function concretize<T extends BaseData>(type: T): T | F32 | I32;
|
|
7
7
|
export declare function concretizeSnippet(snippet: Snippet): Snippet;
|
|
@@ -12,11 +12,12 @@ export declare function coerceToSnippet(value: unknown): Snippet;
|
|
|
12
12
|
* Defers resolution. Stores array elements as snippets so the
|
|
13
13
|
* generator can access them when needed.
|
|
14
14
|
*/
|
|
15
|
-
export declare class ArrayExpression implements SelfResolvable {
|
|
15
|
+
export declare class ArrayExpression implements SelfResolvable, WithComptimeValue {
|
|
16
16
|
readonly [$internal] = true;
|
|
17
17
|
readonly type: WgslArray<AnyWgslData>;
|
|
18
18
|
readonly elements: Snippet[];
|
|
19
19
|
constructor(type: WgslArray<AnyWgslData>, elements: Snippet[]);
|
|
20
20
|
toString(): string;
|
|
21
|
+
[$comptimeValueOf](): ComptimeValue;
|
|
21
22
|
[$resolve](ctx: ResolutionCtx): ResolvedSnippet;
|
|
22
23
|
}
|
|
@@ -3,10 +3,11 @@ import { abstractFloat, abstractInt, bool, f32, i32 } from "../data/numeric.js";
|
|
|
3
3
|
import { isRef } from "../data/ref.js";
|
|
4
4
|
import { isStoredInMemory, isSnippet, snip, withDataType } from "../data/snippet.js";
|
|
5
5
|
import { isMatInstance, isNaturallyEphemeral, isVecInstance, WORKAROUND_getSchema, } from "../data/wgslTypes.js";
|
|
6
|
-
import { getOwnSnippet } from "../types.js";
|
|
6
|
+
import { asComptime, getOwnSnippet, } from "../types.js";
|
|
7
7
|
import { WgslTypeError } from "../errors.js";
|
|
8
|
-
import { $internal, $resolve } from "../shared/symbols.js";
|
|
8
|
+
import { $comptimeValueOf, $internal, $resolve } from "../shared/symbols.js";
|
|
9
9
|
import { logger } from "../tgpuLogger.js";
|
|
10
|
+
import { stringifySnippet } from "./stringifySnippet.js";
|
|
10
11
|
export function numericLiteralToSnippet(value) {
|
|
11
12
|
if (value >= 2 ** 63 || value < -(2 ** 63)) {
|
|
12
13
|
return snip(value, abstractFloat, /* origin */ 'constant', /* possibleSideEffects */ false);
|
|
@@ -78,11 +79,23 @@ export class ArrayExpression {
|
|
|
78
79
|
toString() {
|
|
79
80
|
return 'ArrayExpression';
|
|
80
81
|
}
|
|
82
|
+
[$comptimeValueOf]() {
|
|
83
|
+
// The array is known at comptime only if every element is known at comptime
|
|
84
|
+
const values = [];
|
|
85
|
+
for (const elem of this.elements) {
|
|
86
|
+
const known = asComptime(elem);
|
|
87
|
+
if (!known) {
|
|
88
|
+
return { comptime: false };
|
|
89
|
+
}
|
|
90
|
+
values.push(known.value);
|
|
91
|
+
}
|
|
92
|
+
return { comptime: true, value: values };
|
|
93
|
+
}
|
|
81
94
|
[$resolve](ctx) {
|
|
82
95
|
for (const elem of this.elements) {
|
|
83
96
|
// We check if there are no references among the elements
|
|
84
97
|
if (isStoredInMemory(elem) && !isNaturallyEphemeral(elem.dataType)) {
|
|
85
|
-
const snippetStr =
|
|
98
|
+
const snippetStr = stringifySnippet(elem);
|
|
86
99
|
const snippetType = ctx.resolve(concretize(elem.dataType)).value;
|
|
87
100
|
throw new WgslTypeError(`'${snippetStr}' reference cannot be used in an array constructor.\n-----\nTry '${snippetType}(${snippetStr})' or 'arrayOf(${snippetType}, count)([...])' to copy the value instead.\n-----`);
|
|
88
101
|
}
|
package/tgsl/infixDispatch.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { MatBase } from '../data/matrix.ts';
|
|
|
2
2
|
import { type Snippet } from '../data/snippet.ts';
|
|
3
3
|
import type { VecBase } from '../data/vectorImpl.ts';
|
|
4
4
|
import type { AnyMatInstance, AnyNumericVecInstance } from '../data/wgslTypes.ts';
|
|
5
|
+
import { $comptimeValueOf } from '../shared/symbols.ts';
|
|
6
|
+
import { type ComptimeValue, type WithComptimeValue } from '../types.ts';
|
|
5
7
|
export declare const infixOperators: {
|
|
6
8
|
readonly add: import("../types.ts").DualFn<{
|
|
7
9
|
(lhs: number, rhs: number): number;
|
|
@@ -56,10 +58,11 @@ export type InfixOperator = (typeof infixOperators)[InfixOperatorName];
|
|
|
56
58
|
* d.vec2u(1).mul(2) // lhs is a snippet
|
|
57
59
|
* }
|
|
58
60
|
*/
|
|
59
|
-
export declare class InfixDispatch {
|
|
61
|
+
export declare class InfixDispatch implements WithComptimeValue {
|
|
60
62
|
readonly lhs: Snippet | Numeric;
|
|
61
63
|
readonly operator: InfixOperator;
|
|
62
64
|
constructor(lhs: Snippet | Numeric, operator: InfixOperator);
|
|
65
|
+
[$comptimeValueOf](): ComptimeValue;
|
|
63
66
|
}
|
|
64
67
|
export declare function isInfixDispatch(o: unknown): o is InfixDispatch;
|
|
65
68
|
/**
|
package/tgsl/infixDispatch.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {} from "../data/snippet.js";
|
|
1
|
+
import { isSnippet } from "../data/snippet.js";
|
|
2
2
|
import { inCodegenMode } from "../execMode.js";
|
|
3
|
+
import { $comptimeValueOf } from "../shared/symbols.js";
|
|
4
|
+
import { asComptime } from "../types.js";
|
|
3
5
|
import { add, bitShiftLeft, bitShiftRight, div, mod, mul, sub } from "../std/operators.js";
|
|
4
6
|
export const infixOperators = {
|
|
5
7
|
add,
|
|
@@ -28,6 +30,16 @@ export class InfixDispatch {
|
|
|
28
30
|
this.lhs = lhs;
|
|
29
31
|
this.operator = operator;
|
|
30
32
|
}
|
|
33
|
+
[$comptimeValueOf]() {
|
|
34
|
+
const known = isSnippet(this.lhs) ? asComptime(this.lhs) : { value: this.lhs };
|
|
35
|
+
if (!known) {
|
|
36
|
+
return { comptime: false };
|
|
37
|
+
}
|
|
38
|
+
// Same as accessing e.g. `.mul` on a vector in JS, but bound to `lhs`
|
|
39
|
+
const lhs = known.value;
|
|
40
|
+
const operator = this.operator;
|
|
41
|
+
return { comptime: true, value: (rhs) => operator(lhs, rhs) };
|
|
42
|
+
}
|
|
31
43
|
}
|
|
32
44
|
export function isInfixDispatch(o) {
|
|
33
45
|
return o instanceof InfixDispatch;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Snippet } from '../data/snippet.ts';
|
|
2
|
-
import type
|
|
2
|
+
import { type SimulationState } from '../types.ts';
|
|
3
3
|
import type { makeResolvable } from './makeResolvable.ts';
|
|
4
4
|
/**
|
|
5
5
|
* WARNING: This is an API that touches a lot of internals, and is not stable
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { $gpuValueOf, $internal, $ownSnippet, $resolve } from "../shared/symbols.js";
|
|
1
|
+
import { $comptimeValueOf, $gpuValueOf, $internal, $ownSnippet, $resolve, } from "../shared/symbols.js";
|
|
2
2
|
import { valueProxyHandler } from "../core/valueProxyUtils.js";
|
|
3
|
+
import { runtimeOnly } from "../types.js";
|
|
3
4
|
import { getExecMode } from "../execMode.js";
|
|
4
5
|
import { assertExhaustive } from "../shared/utilityTypes.js";
|
|
5
6
|
/**
|
|
@@ -30,6 +31,7 @@ export function makeDereferenceable(value, options) {
|
|
|
30
31
|
}
|
|
31
32
|
return options.codegenMode.getBaseSnippet.apply(resource, [this]);
|
|
32
33
|
},
|
|
34
|
+
[$comptimeValueOf]: runtimeOnly,
|
|
33
35
|
[$resolve]: (ctx) => ctx.resolve(resource),
|
|
34
36
|
toString: () => `${resource.toString()}.$`,
|
|
35
37
|
}, valueProxyHandler);
|
package/tgsl/shellless.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { createShelllessImpl } from "../core/function/shelllessImpl.js";
|
|
2
2
|
import { UnknownData } from "../data/dataTypes.js";
|
|
3
|
-
import { RefOperator } from "../data/ref.js";
|
|
4
3
|
import { isPtr, isWgslArray, isWgslStruct } from "../data/wgslTypes.js";
|
|
5
|
-
import { WgslTypeError } from "../errors.js";
|
|
6
4
|
import { getFunctionMetadata, getName } from "../shared/meta.js";
|
|
7
5
|
import { concretize } from "./generationHelpers.js";
|
|
6
|
+
import { stringifySnippet } from "./stringifySnippet.js";
|
|
8
7
|
function shallowEqualSchemas(a, b) {
|
|
9
8
|
if (a.type !== b.type)
|
|
10
9
|
return false;
|
|
@@ -34,14 +33,11 @@ export class ShelllessRepository {
|
|
|
34
33
|
throw new Error(`Cannot resolve '${getName(fn)}' directly, because it expects arguments. Either call it from another function, or wrap it in a shell`);
|
|
35
34
|
}
|
|
36
35
|
const argTypes = (argSnippets ?? []).map((s, index) => {
|
|
37
|
-
if (s.value instanceof RefOperator) {
|
|
38
|
-
if (s.dataType === UnknownData) {
|
|
39
|
-
throw new WgslTypeError(`d.ref() created with primitive types must be stored in a variable before use`);
|
|
40
|
-
}
|
|
41
|
-
return s.dataType;
|
|
42
|
-
}
|
|
43
36
|
if (s.dataType === UnknownData) {
|
|
44
|
-
|
|
37
|
+
const snippetStr = stringifySnippet(s);
|
|
38
|
+
const valueStr = String(s.value);
|
|
39
|
+
const description = snippetStr === valueStr ? `'${snippetStr}'` : `'${snippetStr}' (${valueStr})`;
|
|
40
|
+
throw new Error(`Passed illegal value ${description} as the #${index} argument to ${getName(fn) ?? '<unnamed>'}(...)\n` +
|
|
45
41
|
`Shellless functions can only accept arguments representing WGSL resources: constructible WGSL types, d.refs, samplers or texture views.\n` +
|
|
46
42
|
`Remember, that arguments such as samplers, texture views, accessors, slots etc. should be dereferenced via '.$' first.`);
|
|
47
43
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type * as tinyest from 'tinyest';
|
|
2
|
+
import type { Snippet } from '../data/snippet.ts';
|
|
3
|
+
export declare function setSourceNode(snippet: Snippet, node: tinyest.Expression): Snippet;
|
|
4
|
+
export declare function getSourceNode(snippet: Snippet): tinyest.Expression | undefined;
|
|
5
|
+
/**
|
|
6
|
+
* Describes a snippet in a human-readable way, meant to be used in error messages.
|
|
7
|
+
* Prefers the JS expression that produced the snippet, falling back to its value.
|
|
8
|
+
*/
|
|
9
|
+
export declare function stringifySnippet(snippet: Snippet): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { stringifyNode } from "../shared/tseynit.js";
|
|
2
|
+
/**
|
|
3
|
+
* The JS expression that first produced a given snippet.
|
|
4
|
+
* Snippets can be shared (e.g. every reference to a variable returns the same snippet),
|
|
5
|
+
* so only the first, most specific node is remembered.
|
|
6
|
+
*/
|
|
7
|
+
const sourceNodes = new WeakMap();
|
|
8
|
+
export function setSourceNode(snippet, node) {
|
|
9
|
+
if (!sourceNodes.has(snippet)) {
|
|
10
|
+
sourceNodes.set(snippet, node);
|
|
11
|
+
}
|
|
12
|
+
return snippet;
|
|
13
|
+
}
|
|
14
|
+
export function getSourceNode(snippet) {
|
|
15
|
+
return sourceNodes.get(snippet);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Describes a snippet in a human-readable way, meant to be used in error messages.
|
|
19
|
+
* Prefers the JS expression that produced the snippet, falling back to its value.
|
|
20
|
+
*/
|
|
21
|
+
export function stringifySnippet(snippet) {
|
|
22
|
+
const node = getSourceNode(snippet);
|
|
23
|
+
return node !== undefined ? stringifyNode(node) : String(snippet.value);
|
|
24
|
+
}
|
package/tgsl/wgslGenerator.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export declare class WgslGenerator implements ShaderGenerator {
|
|
|
27
27
|
*/
|
|
28
28
|
protected _typedExpression(expression: tinyest.Expression, expectedType: wgsl.BaseData | wgsl.BaseData[]): Snippet;
|
|
29
29
|
protected _expression(expression: tinyest.Expression): Snippet;
|
|
30
|
+
private _expressionImpl;
|
|
30
31
|
declareGlobalConst(options: ConstantDefinitionOptions): ResolvedSnippet;
|
|
31
32
|
declareGlobalVar(options: VariableDefinitionOptions): ResolvedSnippet;
|
|
32
33
|
functionDefinition(options: FunctionDefinitionOptions): string;
|