typegpu 0.12.6 → 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/common/writeSoA.js +16 -0
- package/core/buffer/buffer.js +47 -11
- package/core/commandEncoder/attachments.js +5 -2
- package/core/function/autoIO.js +5 -3
- 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 +17 -2
- package/core/function/ioSchema.js +74 -27
- package/core/function/tgpuFn.d.ts +11 -1
- package/core/function/tgpuFn.js +9 -2
- package/core/function/tgpuFragmentFn.d.ts +1 -1
- package/core/function/tgpuFragmentFn.js +2 -1
- package/core/function/tgpuVertexFn.js +2 -1
- package/core/pipeline/connectAttachmentToShader.d.ts +2 -2
- package/core/pipeline/connectAttachmentToShader.js +16 -21
- package/core/pipeline/connectTargetsToShader.d.ts +5 -1
- package/core/pipeline/connectTargetsToShader.js +23 -18
- package/core/pipeline/renderPipeline.d.ts +9 -6
- package/core/pipeline/renderPipeline.js +22 -22
- package/core/pipeline/timeable.js +15 -2
- package/core/resolve/namespace.js +2 -2
- package/core/root/configurableImpl.js +1 -2
- package/core/root/rootTypes.d.ts +6 -2
- package/core/slot/accessor.d.ts +1 -1
- package/core/slot/accessor.js +72 -5
- 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 +12 -5
- 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/autoStruct.d.ts +1 -1
- package/data/autoStruct.js +8 -4
- 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/deepEqual.js +19 -9
- package/data/matrix.js +10 -3
- package/data/matrixColumnsAccess.d.ts +8 -0
- package/data/matrixColumnsAccess.js +15 -0
- package/data/offsetUtils.js +181 -102
- package/data/partialIO.d.ts +8 -1
- package/data/partialIO.js +36 -19
- package/data/ref.d.ts +12 -5
- package/data/ref.js +51 -24
- package/data/snippet.d.ts +13 -4
- package/data/snippet.js +17 -4
- package/data/struct.js +3 -0
- package/data/wgslTypes.d.ts +6 -3
- package/internal.d.ts +1 -0
- package/nameUtils.d.ts +7 -0
- package/nameUtils.js +60 -0
- 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/shared/tseynit.js +54 -50
- package/std/boolean.js +9 -10
- package/std/numeric.js +1 -4
- package/std/operators.js +9 -4
- package/std/packing.js +10 -10
- package/std/texture.d.ts +2 -2
- package/tgpuLogger.d.ts +1 -1
- package/tgpuLogger.js +0 -2
- package/tgsl/accessIndex.js +37 -38
- package/tgsl/accessProp.js +10 -7
- package/tgsl/conversion.js +3 -2
- package/tgsl/forOfUtils.js +8 -8
- package/tgsl/generationHelpers.d.ts +4 -3
- package/tgsl/generationHelpers.js +18 -5
- 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 +180 -86
- package/types.d.ts +23 -2
- package/types.js +30 -5
package/data/snippet.d.ts
CHANGED
|
@@ -7,25 +7,26 @@ export type Origin = 'uniform' | 'readonly' | 'mutable' | 'workgroup' | 'private
|
|
|
7
7
|
*/
|
|
8
8
|
export declare function fallthroughCopyOrigin(origin: Origin): Origin;
|
|
9
9
|
/**
|
|
10
|
-
* Whether a snippet
|
|
10
|
+
* Whether a snippet refers to a value already stored in memory.
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* ```ts
|
|
14
14
|
* function foo(a: number) {
|
|
15
|
+
* 'use gpu';
|
|
15
16
|
* const color = d.vec3f(1, 2, 3);
|
|
16
17
|
* return color * a;
|
|
17
18
|
* }
|
|
18
19
|
*
|
|
19
|
-
* //
|
|
20
|
+
* // Stored in memory:
|
|
20
21
|
* // - color
|
|
21
22
|
* // - a
|
|
22
23
|
* //
|
|
23
|
-
* //
|
|
24
|
+
* // Ephemeral values:
|
|
24
25
|
* // - d.vec3f(1, 2, 3)
|
|
25
26
|
* // - color * a
|
|
26
27
|
* ```
|
|
27
28
|
*/
|
|
28
|
-
export declare function
|
|
29
|
+
export declare function isStoredInMemory(snippet: Snippet): boolean;
|
|
29
30
|
export declare const originToPtrParams: {
|
|
30
31
|
readonly uniform: {
|
|
31
32
|
readonly space: "uniform";
|
|
@@ -61,6 +62,14 @@ export declare const originToPtrParams: {
|
|
|
61
62
|
};
|
|
62
63
|
};
|
|
63
64
|
export type OriginToPtrParams = typeof originToPtrParams;
|
|
65
|
+
/**
|
|
66
|
+
* Whether values of this origin can have their address taken.
|
|
67
|
+
*/
|
|
68
|
+
export declare function isAddressableOrigin(origin: Origin): origin is keyof OriginToPtrParams;
|
|
69
|
+
/**
|
|
70
|
+
* Whether values of this origin can be mutated.
|
|
71
|
+
*/
|
|
72
|
+
export declare function isMutableOrigin(origin: Origin): boolean;
|
|
64
73
|
export interface Snippet {
|
|
65
74
|
readonly value: unknown;
|
|
66
75
|
/**
|
package/data/snippet.js
CHANGED
|
@@ -16,25 +16,26 @@ export function fallthroughCopyOrigin(origin) {
|
|
|
16
16
|
return 'runtime';
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* Whether a snippet
|
|
19
|
+
* Whether a snippet refers to a value already stored in memory.
|
|
20
20
|
*
|
|
21
21
|
* @example
|
|
22
22
|
* ```ts
|
|
23
23
|
* function foo(a: number) {
|
|
24
|
+
* 'use gpu';
|
|
24
25
|
* const color = d.vec3f(1, 2, 3);
|
|
25
26
|
* return color * a;
|
|
26
27
|
* }
|
|
27
28
|
*
|
|
28
|
-
* //
|
|
29
|
+
* // Stored in memory:
|
|
29
30
|
* // - color
|
|
30
31
|
* // - a
|
|
31
32
|
* //
|
|
32
|
-
* //
|
|
33
|
+
* // Ephemeral values:
|
|
33
34
|
* // - d.vec3f(1, 2, 3)
|
|
34
35
|
* // - color * a
|
|
35
36
|
* ```
|
|
36
37
|
*/
|
|
37
|
-
export function
|
|
38
|
+
export function isStoredInMemory(snippet) {
|
|
38
39
|
return !(snippet.origin === 'runtime' || snippet.origin === 'constant');
|
|
39
40
|
}
|
|
40
41
|
export const originToPtrParams = {
|
|
@@ -48,6 +49,18 @@ export const originToPtrParams = {
|
|
|
48
49
|
// Local declarations are also in the `function` address space
|
|
49
50
|
'local-def': { space: 'function', access: 'read-write' },
|
|
50
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* Whether values of this origin can have their address taken.
|
|
54
|
+
*/
|
|
55
|
+
export function isAddressableOrigin(origin) {
|
|
56
|
+
return origin in originToPtrParams;
|
|
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
|
+
}
|
|
51
64
|
class SnippetImpl {
|
|
52
65
|
value;
|
|
53
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,11 +704,12 @@ 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;
|
|
711
711
|
(...columns: [v2f, v2f]): m2x2f;
|
|
712
|
+
(other: m2x2f): m2x2f;
|
|
712
713
|
(): m2x2f;
|
|
713
714
|
identity(): m2x2f;
|
|
714
715
|
}
|
|
@@ -719,11 +720,12 @@ export interface Mat3x3f extends BaseData {
|
|
|
719
720
|
readonly type: 'mat3x3f';
|
|
720
721
|
readonly primitive: F32;
|
|
721
722
|
readonly [$repr]: m3x3f;
|
|
722
|
-
readonly [$inRepr]: m3x3f | readonly number
|
|
723
|
+
readonly [$inRepr]: m3x3f | readonly [number, number, number, number, number, number, number, number, number] | Float32Array;
|
|
723
724
|
readonly [$validStorageSchema]: true;
|
|
724
725
|
readonly [$validUniformSchema]: true;
|
|
725
726
|
(...elements: [number, number, number, number, number, number, number, number, number]): m3x3f;
|
|
726
727
|
(...columns: [v3f, v3f, v3f]): m3x3f;
|
|
728
|
+
(other: m3x3f): m3x3f;
|
|
727
729
|
(): m3x3f;
|
|
728
730
|
identity(): m3x3f;
|
|
729
731
|
}
|
|
@@ -734,11 +736,12 @@ export interface Mat4x4f extends BaseData {
|
|
|
734
736
|
readonly type: 'mat4x4f';
|
|
735
737
|
readonly primitive: F32;
|
|
736
738
|
readonly [$repr]: m4x4f;
|
|
737
|
-
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;
|
|
738
740
|
readonly [$validStorageSchema]: true;
|
|
739
741
|
readonly [$validUniformSchema]: true;
|
|
740
742
|
(...elements: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]): m4x4f;
|
|
741
743
|
(...columns: [v4f, v4f, v4f, v4f]): m4x4f;
|
|
744
|
+
(other: m4x4f): m4x4f;
|
|
742
745
|
(): m4x4f;
|
|
743
746
|
identity(): m4x4f;
|
|
744
747
|
translation(vec: v3f): m4x4f;
|
package/internal.d.ts
CHANGED
|
@@ -13,4 +13,5 @@ export type { RestoreContext } from './serial/types.ts';
|
|
|
13
13
|
export { deserializeDataSchema, serializeDataSchema, type SerializedDataSchema, } from './serial/schema.ts';
|
|
14
14
|
export type { ResolutionCtx, FunctionArgument } from './types.ts';
|
|
15
15
|
export type { Snippet, ResolvedSnippet, Origin } from './data/snippet.ts';
|
|
16
|
+
export type { AutoStruct } from './data/autoStruct.ts';
|
|
16
17
|
export type { ShaderGenerator, ResolvedStatement, BinaryOperator, ShaderGeneratorClass, FunctionDefinitionOptions, ConstantDefinitionOptions, VariableDefinitionOptions, } from './tgsl/shaderGenerator.ts';
|
package/nameUtils.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
export declare const bannedTokens: Set<string>;
|
|
2
|
+
/**
|
|
3
|
+
* Predeclared enumerants that appear as template parameters, e.g. `var<storage, read_write>` or
|
|
4
|
+
* `texture_storage_2d<rgba8unorm, write>`. A module-scope or local declaration with one of these names
|
|
5
|
+
* would shadow the enumerant, so a template using it would refer to the declaration instead.
|
|
6
|
+
* Unlike `bannedTokens`, these remain valid as struct member names, which never shadow anything.
|
|
7
|
+
*/
|
|
8
|
+
export declare const templateEnumerants: Set<string>;
|
|
2
9
|
export declare const builtins: Set<string>;
|
|
3
10
|
/**
|
|
4
11
|
* Sanitizes the primer so that it is compliant with WGSL guidelines.
|
package/nameUtils.js
CHANGED
|
@@ -178,6 +178,66 @@ export const bannedTokens = new Set([
|
|
|
178
178
|
'uniform',
|
|
179
179
|
'storage',
|
|
180
180
|
]);
|
|
181
|
+
/**
|
|
182
|
+
* Predeclared enumerants that appear as template parameters, e.g. `var<storage, read_write>` or
|
|
183
|
+
* `texture_storage_2d<rgba8unorm, write>`. A module-scope or local declaration with one of these names
|
|
184
|
+
* would shadow the enumerant, so a template using it would refer to the declaration instead.
|
|
185
|
+
* Unlike `bannedTokens`, these remain valid as struct member names, which never shadow anything.
|
|
186
|
+
*/
|
|
187
|
+
export const templateEnumerants = new Set([
|
|
188
|
+
// address spaces
|
|
189
|
+
'function',
|
|
190
|
+
'private',
|
|
191
|
+
'workgroup',
|
|
192
|
+
'uniform',
|
|
193
|
+
'storage',
|
|
194
|
+
'immediate',
|
|
195
|
+
// access modes
|
|
196
|
+
'read',
|
|
197
|
+
'write',
|
|
198
|
+
'read_write',
|
|
199
|
+
// texel formats
|
|
200
|
+
'rgba8unorm',
|
|
201
|
+
'rgba8snorm',
|
|
202
|
+
'rgba8uint',
|
|
203
|
+
'rgba8sint',
|
|
204
|
+
'rgba16unorm',
|
|
205
|
+
'rgba16snorm',
|
|
206
|
+
'rgba16uint',
|
|
207
|
+
'rgba16sint',
|
|
208
|
+
'rgba16float',
|
|
209
|
+
'rg8unorm',
|
|
210
|
+
'rg8snorm',
|
|
211
|
+
'rg8uint',
|
|
212
|
+
'rg8sint',
|
|
213
|
+
'rg16unorm',
|
|
214
|
+
'rg16snorm',
|
|
215
|
+
'rg16uint',
|
|
216
|
+
'rg16sint',
|
|
217
|
+
'rg16float',
|
|
218
|
+
'r8unorm',
|
|
219
|
+
'r8snorm',
|
|
220
|
+
'r8uint',
|
|
221
|
+
'r8sint',
|
|
222
|
+
'r16unorm',
|
|
223
|
+
'r16snorm',
|
|
224
|
+
'r16uint',
|
|
225
|
+
'r16sint',
|
|
226
|
+
'r16float',
|
|
227
|
+
'r32uint',
|
|
228
|
+
'r32sint',
|
|
229
|
+
'r32float',
|
|
230
|
+
'rg32uint',
|
|
231
|
+
'rg32sint',
|
|
232
|
+
'rg32float',
|
|
233
|
+
'rgba32uint',
|
|
234
|
+
'rgba32sint',
|
|
235
|
+
'rgba32float',
|
|
236
|
+
'bgra8unorm',
|
|
237
|
+
'rgb10a2unorm',
|
|
238
|
+
'rgb10a2uint',
|
|
239
|
+
'rg11b10ufloat',
|
|
240
|
+
]);
|
|
181
241
|
export const builtins = new Set([
|
|
182
242
|
// constructors
|
|
183
243
|
'array',
|
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/shared/tseynit.js
CHANGED
|
@@ -2,90 +2,94 @@ import * as tinyest from 'tinyest';
|
|
|
2
2
|
const { NodeTypeCatalog: NODE } = tinyest;
|
|
3
3
|
export function stringifyNode(node) {
|
|
4
4
|
if (isExpression(node)) {
|
|
5
|
-
return stringifyExpression(node
|
|
5
|
+
return stringifyExpression(node);
|
|
6
6
|
}
|
|
7
7
|
return stringifyStatement(node, '');
|
|
8
8
|
}
|
|
9
|
-
function stringifyStatement(node,
|
|
9
|
+
function stringifyStatement(node, indent) {
|
|
10
10
|
if (isExpression(node)) {
|
|
11
|
-
return `${
|
|
11
|
+
return `${indent}${stringifyExpression(node)};`;
|
|
12
12
|
}
|
|
13
13
|
if (node[0] === NODE.block) {
|
|
14
|
-
const statements = node[1].map((n) => stringifyStatement(n,
|
|
15
|
-
return `{\n${statements.join('\n')}\n${
|
|
14
|
+
const statements = node[1].map((n) => stringifyStatement(n, indent + ' '));
|
|
15
|
+
return `{\n${statements.join('\n')}\n${indent}}`;
|
|
16
16
|
}
|
|
17
17
|
if (node[0] === NODE.return) {
|
|
18
|
-
const expr = node[1] === undefined ? '' : ` ${stringifyExpression(node[1]
|
|
19
|
-
return `${
|
|
18
|
+
const expr = node[1] === undefined ? '' : ` ${stringifyExpression(node[1])}`;
|
|
19
|
+
return `${indent}return${expr};`;
|
|
20
20
|
}
|
|
21
21
|
if (node[0] === NODE.if) {
|
|
22
|
-
const cond = stringifyExpression(node[1]
|
|
23
|
-
const then = stringifyStatement(node[2],
|
|
24
|
-
const base = `${
|
|
22
|
+
const cond = stringifyExpression(node[1]);
|
|
23
|
+
const then = stringifyStatement(node[2], indent);
|
|
24
|
+
const base = `${indent}if (${cond}) ${then}`;
|
|
25
25
|
if (node[3] !== undefined) {
|
|
26
|
-
return `${base} else ${stringifyStatement(node[3],
|
|
26
|
+
return `${base} else ${stringifyStatement(node[3], indent)}`;
|
|
27
27
|
}
|
|
28
28
|
return base;
|
|
29
29
|
}
|
|
30
30
|
if (node[0] === NODE.let) {
|
|
31
|
-
const decl = `${
|
|
31
|
+
const decl = `${indent}let ${stringifyExpression(node[1])}`;
|
|
32
32
|
if (node[2] !== undefined) {
|
|
33
|
-
return `${decl} = ${stringifyExpression(node[2]
|
|
33
|
+
return `${decl} = ${stringifyExpression(node[2])};`;
|
|
34
34
|
}
|
|
35
35
|
return `${decl};`;
|
|
36
36
|
}
|
|
37
37
|
if (node[0] === NODE.const) {
|
|
38
|
-
const decl = `${
|
|
38
|
+
const decl = `${indent}const ${stringifyExpression(node[1])}`;
|
|
39
39
|
if (node[2] !== undefined) {
|
|
40
|
-
return `${decl} = ${stringifyExpression(node[2]
|
|
40
|
+
return `${decl} = ${stringifyExpression(node[2])};`;
|
|
41
41
|
}
|
|
42
42
|
return `${decl};`;
|
|
43
43
|
}
|
|
44
44
|
if (node[0] === NODE.for) {
|
|
45
45
|
const init = node[1] ? stringifyStatement(node[1], '') : ';';
|
|
46
|
-
const cond = node[2] ? stringifyExpression(node[2]
|
|
46
|
+
const cond = node[2] ? stringifyExpression(node[2]) : '';
|
|
47
47
|
const update = node[3] ? stringifyStatement(node[3], '') : '';
|
|
48
|
-
const body = stringifyStatement(node[4],
|
|
49
|
-
return `${
|
|
48
|
+
const body = stringifyStatement(node[4], indent);
|
|
49
|
+
return `${indent}for (${init} ${cond}; ${update.slice(0, -1) /* trim the ';' */}) ${body}`;
|
|
50
50
|
}
|
|
51
51
|
if (node[0] === NODE.while) {
|
|
52
|
-
const cond = stringifyExpression(node[1]
|
|
53
|
-
const body = stringifyStatement(node[2],
|
|
54
|
-
return `${
|
|
52
|
+
const cond = stringifyExpression(node[1]);
|
|
53
|
+
const body = stringifyStatement(node[2], indent);
|
|
54
|
+
return `${indent}while (${cond}) ${body}`;
|
|
55
55
|
}
|
|
56
56
|
if (node[0] === NODE.continue) {
|
|
57
|
-
return `${
|
|
57
|
+
return `${indent}continue;`;
|
|
58
58
|
}
|
|
59
59
|
if (node[0] === NODE.break) {
|
|
60
|
-
return `${
|
|
60
|
+
return `${indent}break;`;
|
|
61
61
|
}
|
|
62
62
|
if (node[0] === NODE.forOf) {
|
|
63
63
|
const leftKind = node[1][0] === NODE.const ? 'const' : 'let';
|
|
64
|
-
const leftName = stringifyExpression(node[1][1]
|
|
65
|
-
const right = stringifyExpression(node[2]
|
|
66
|
-
const body = stringifyStatement(node[3],
|
|
67
|
-
return `${
|
|
64
|
+
const leftName = stringifyExpression(node[1][1]);
|
|
65
|
+
const right = stringifyExpression(node[2]);
|
|
66
|
+
const body = stringifyStatement(node[3], indent);
|
|
67
|
+
return `${indent}for (${leftKind} ${leftName} of ${right}) ${body}`;
|
|
68
68
|
}
|
|
69
69
|
if (node[0] === NODE.switch) {
|
|
70
|
-
const discriminant = stringifyExpression(node[1]
|
|
70
|
+
const discriminant = stringifyExpression(node[1]);
|
|
71
71
|
const cases = node[2].map((c) => {
|
|
72
|
-
const test = c[0] === null ? 'default' : `case ${stringifyExpression(c[0]
|
|
72
|
+
const test = c[0] === null ? 'default' : `case ${stringifyExpression(c[0])}`;
|
|
73
73
|
if (c[1].length === 0) {
|
|
74
74
|
return `${test}:`;
|
|
75
75
|
}
|
|
76
|
-
const consequents = c[1].map((s) => stringifyStatement(s,
|
|
76
|
+
const consequents = c[1].map((s) => stringifyStatement(s, indent + ' '));
|
|
77
77
|
return `${test}:\n${consequents.join('\n')}`;
|
|
78
78
|
});
|
|
79
|
-
return `${
|
|
79
|
+
return `${indent}switch (${discriminant}) {\n${cases.map((c) => `${indent + ' '}${c}`).join('\n')}\n${indent}}`;
|
|
80
80
|
}
|
|
81
81
|
assertExhaustive(node);
|
|
82
82
|
}
|
|
83
|
+
const JS_IDENTIFIER = /^[$_\p{ID_Start}][$_\u{200c}\u{200d}\p{ID_Continue}]*$/u;
|
|
84
|
+
function stringifyObjectPropertyKey(key) {
|
|
85
|
+
return JS_IDENTIFIER.test(key) ? key : JSON.stringify(key);
|
|
86
|
+
}
|
|
83
87
|
export function stringifyObjectProperty([key, value, computed]) {
|
|
84
|
-
const keyStr = computed ? `[${stringifyExpression(key
|
|
85
|
-
const valueStr = stringifyExpression(value
|
|
88
|
+
const keyStr = computed ? `[${stringifyExpression(key)}]` : stringifyObjectPropertyKey(key);
|
|
89
|
+
const valueStr = stringifyExpression(value);
|
|
86
90
|
return `${keyStr}: ${valueStr}`;
|
|
87
91
|
}
|
|
88
|
-
function stringifyExpression(node
|
|
92
|
+
function stringifyExpression(node) {
|
|
89
93
|
if (typeof node === 'string') {
|
|
90
94
|
return node;
|
|
91
95
|
}
|
|
@@ -105,52 +109,52 @@ function stringifyExpression(node, ident) {
|
|
|
105
109
|
return JSON.stringify(node[1]);
|
|
106
110
|
}
|
|
107
111
|
if (node[0] === NODE.arrayExpr) {
|
|
108
|
-
const elements = node[1].map((n) => stringifyExpression(n
|
|
112
|
+
const elements = node[1].map((n) => stringifyExpression(n));
|
|
109
113
|
return `[${elements.join(', ')}]`;
|
|
110
114
|
}
|
|
111
115
|
if (node[0] === NODE.binaryExpr) {
|
|
112
|
-
return `${wrapIfComplex(node[1]
|
|
116
|
+
return `${wrapIfComplex(node[1])} ${node[2]} ${wrapIfComplex(node[3])}`;
|
|
113
117
|
}
|
|
114
118
|
if (node[0] === NODE.assignmentExpr) {
|
|
115
|
-
return `${stringifyExpression(node[1]
|
|
119
|
+
return `${stringifyExpression(node[1])} ${node[2]} ${stringifyExpression(node[3])}`;
|
|
116
120
|
}
|
|
117
121
|
if (node[0] === NODE.logicalExpr) {
|
|
118
|
-
return `${wrapIfComplex(node[1]
|
|
122
|
+
return `${wrapIfComplex(node[1])} ${node[2]} ${wrapIfComplex(node[3])}`;
|
|
119
123
|
}
|
|
120
124
|
if (node[0] === NODE.unaryExpr) {
|
|
121
125
|
// Unary word operators like void, instanceof and delete require a space
|
|
122
126
|
const sep = node[1].length > 1 ? ' ' : '';
|
|
123
|
-
return `${node[1]}${sep}${wrapIfComplex(node[2]
|
|
127
|
+
return `${node[1]}${sep}${wrapIfComplex(node[2])}`;
|
|
124
128
|
}
|
|
125
129
|
if (node[0] === NODE.call) {
|
|
126
|
-
const callee = wrapIfComplex(node[1]
|
|
127
|
-
const args = node[2].map((n) => stringifyExpression(n
|
|
130
|
+
const callee = wrapIfComplex(node[1]);
|
|
131
|
+
const args = node[2].map((n) => stringifyExpression(n)).join(', ');
|
|
128
132
|
return `${callee}(${args})`;
|
|
129
133
|
}
|
|
130
134
|
if (node[0] === NODE.memberAccess) {
|
|
131
135
|
if (Array.isArray(node[1]) && node[1][0] === NODE.numericLiteral) {
|
|
132
|
-
return `(${stringifyExpression(node[1]
|
|
136
|
+
return `(${stringifyExpression(node[1])}).${stringifyExpression(node[2])}`;
|
|
133
137
|
}
|
|
134
|
-
return `${wrapIfComplex(node[1]
|
|
138
|
+
return `${wrapIfComplex(node[1])}.${stringifyExpression(node[2])}`;
|
|
135
139
|
}
|
|
136
140
|
if (node[0] === NODE.indexAccess) {
|
|
137
|
-
return `${wrapIfComplex(node[1]
|
|
141
|
+
return `${wrapIfComplex(node[1])}[${stringifyExpression(node[2])}]`;
|
|
138
142
|
}
|
|
139
143
|
if (node[0] === NODE.preUpdate) {
|
|
140
|
-
return `${node[1]}${wrapIfComplex(node[2]
|
|
144
|
+
return `${node[1]}${wrapIfComplex(node[2])}`;
|
|
141
145
|
}
|
|
142
146
|
if (node[0] === NODE.postUpdate) {
|
|
143
|
-
return `${wrapIfComplex(node[2]
|
|
147
|
+
return `${wrapIfComplex(node[2])}${node[1]}`;
|
|
144
148
|
}
|
|
145
149
|
if (node[0] === NODE.objectExpr) {
|
|
146
150
|
if (Array.isArray(node[1])) {
|
|
147
151
|
return `{ ${node[1].map(stringifyObjectProperty).join(', ')} }`;
|
|
148
152
|
}
|
|
149
|
-
const entries = Object.entries(node[1]).map(([key, val]) => `${key}: ${stringifyExpression(val
|
|
153
|
+
const entries = Object.entries(node[1]).map(([key, val]) => `${stringifyObjectPropertyKey(key)}: ${stringifyExpression(val)}`);
|
|
150
154
|
return `{ ${entries.join(', ')} }`;
|
|
151
155
|
}
|
|
152
156
|
if (node[0] === NODE.conditionalExpr) {
|
|
153
|
-
return `${wrapIfComplex(node[1]
|
|
157
|
+
return `${wrapIfComplex(node[1])} ? ${wrapIfComplex(node[2])} : ${wrapIfComplex(node[3])}`;
|
|
154
158
|
}
|
|
155
159
|
if (node[0] === NODE.nullLiteral) {
|
|
156
160
|
return 'null';
|
|
@@ -199,8 +203,8 @@ const SIMPLE_NODES = [
|
|
|
199
203
|
/**
|
|
200
204
|
* Stringifies expression, and wraps it in parentheses if they cannot be trivially omitted
|
|
201
205
|
*/
|
|
202
|
-
function wrapIfComplex(node
|
|
203
|
-
const s = stringifyExpression(node
|
|
206
|
+
function wrapIfComplex(node) {
|
|
207
|
+
const s = stringifyExpression(node);
|
|
204
208
|
if (typeof node === 'string' || typeof node === 'boolean') {
|
|
205
209
|
return s;
|
|
206
210
|
}
|
package/std/boolean.js
CHANGED
|
@@ -9,6 +9,7 @@ import { isBool, isVecBool, isVecInstance, } from "../data/wgslTypes.js";
|
|
|
9
9
|
import { SignatureNotSupportedError, WgslTypeError } from "../errors.js";
|
|
10
10
|
import { unify } from "../tgsl/conversion.js";
|
|
11
11
|
import { cpuCopy } from "./copy.js";
|
|
12
|
+
import { coerceToSnippet } from "../tgsl/generationHelpers.js";
|
|
12
13
|
function correspondingBooleanVectorSchema(dataType) {
|
|
13
14
|
if (dataType.type.includes('2')) {
|
|
14
15
|
return vec2b;
|
|
@@ -30,7 +31,7 @@ export const allEq = dualImpl({
|
|
|
30
31
|
name: 'allEq',
|
|
31
32
|
signature: (...argTypes) => ({ argTypes, returnType: bool }),
|
|
32
33
|
normalImpl: (lhs, rhs) => cpuAll(cpuEq(lhs, rhs)),
|
|
33
|
-
codegenImpl: (
|
|
34
|
+
codegenImpl: (ctx, [lhs, rhs]) => stitch `all(${ctx.gen.emitBinaryOp(lhs, '==', rhs)})`,
|
|
34
35
|
sideEffects: false,
|
|
35
36
|
});
|
|
36
37
|
const cpuEq = (lhs, rhs) => {
|
|
@@ -54,7 +55,7 @@ export const eq = dualImpl({
|
|
|
54
55
|
returnType: correspondingBooleanVectorSchema(argTypes[0]),
|
|
55
56
|
}),
|
|
56
57
|
normalImpl: cpuEq,
|
|
57
|
-
codegenImpl: (
|
|
58
|
+
codegenImpl: (ctx, [lhs, rhs]) => ctx.gen.emitBinaryOp(lhs, '==', rhs),
|
|
58
59
|
sideEffects: false,
|
|
59
60
|
});
|
|
60
61
|
/**
|
|
@@ -72,7 +73,7 @@ export const ne = dualImpl({
|
|
|
72
73
|
returnType: correspondingBooleanVectorSchema(argTypes[0]),
|
|
73
74
|
}),
|
|
74
75
|
normalImpl: (lhs, rhs) => cpuNot(cpuEq(lhs, rhs)),
|
|
75
|
-
codegenImpl: (
|
|
76
|
+
codegenImpl: (ctx, [lhs, rhs]) => ctx.gen.emitBinaryOp(lhs, '!=', rhs),
|
|
76
77
|
sideEffects: false,
|
|
77
78
|
});
|
|
78
79
|
const cpuLt = (lhs, rhs) => {
|
|
@@ -95,7 +96,7 @@ export const lt = dualImpl({
|
|
|
95
96
|
returnType: correspondingBooleanVectorSchema(argTypes[0]),
|
|
96
97
|
}),
|
|
97
98
|
normalImpl: cpuLt,
|
|
98
|
-
codegenImpl: (
|
|
99
|
+
codegenImpl: (ctx, [lhs, rhs]) => ctx.gen.emitBinaryOp(lhs, '<', rhs),
|
|
99
100
|
sideEffects: false,
|
|
100
101
|
});
|
|
101
102
|
/**
|
|
@@ -113,7 +114,7 @@ export const le = dualImpl({
|
|
|
113
114
|
returnType: correspondingBooleanVectorSchema(argTypes[0]),
|
|
114
115
|
}),
|
|
115
116
|
normalImpl: (lhs, rhs) => cpuOr(cpuLt(lhs, rhs), cpuEq(lhs, rhs)),
|
|
116
|
-
codegenImpl: (
|
|
117
|
+
codegenImpl: (ctx, [lhs, rhs]) => ctx.gen.emitBinaryOp(lhs, '<=', rhs),
|
|
117
118
|
sideEffects: false,
|
|
118
119
|
});
|
|
119
120
|
/**
|
|
@@ -131,7 +132,7 @@ export const gt = dualImpl({
|
|
|
131
132
|
returnType: correspondingBooleanVectorSchema(argTypes[0]),
|
|
132
133
|
}),
|
|
133
134
|
normalImpl: (lhs, rhs) => cpuAnd(cpuNot(cpuLt(lhs, rhs)), cpuNot(cpuEq(lhs, rhs))),
|
|
134
|
-
codegenImpl: (
|
|
135
|
+
codegenImpl: (ctx, [lhs, rhs]) => ctx.gen.emitBinaryOp(lhs, '>', rhs),
|
|
135
136
|
sideEffects: false,
|
|
136
137
|
});
|
|
137
138
|
/**
|
|
@@ -149,7 +150,7 @@ export const ge = dualImpl({
|
|
|
149
150
|
returnType: correspondingBooleanVectorSchema(argTypes[0]),
|
|
150
151
|
}),
|
|
151
152
|
normalImpl: (lhs, rhs) => cpuNot(cpuLt(lhs, rhs)),
|
|
152
|
-
codegenImpl: (
|
|
153
|
+
codegenImpl: (ctx, [lhs, rhs]) => ctx.gen.emitBinaryOp(lhs, '>=', rhs),
|
|
153
154
|
sideEffects: false,
|
|
154
155
|
});
|
|
155
156
|
function cpuNot(value) {
|
|
@@ -274,9 +275,7 @@ export const isCloseTo = dualImpl({
|
|
|
274
275
|
return stitch `(abs(f32(${lhs}) - f32(${rhs})) <= ${precision})`;
|
|
275
276
|
}
|
|
276
277
|
if (!isSnippetNumeric(lhs) && !isSnippetNumeric(rhs)) {
|
|
277
|
-
|
|
278
|
-
// (a-a)+prec creates a vector of a.length elements, all equal to prec
|
|
279
|
-
return stitch `all(abs(${lhs} - ${rhs}) <= (${lhs} - ${lhs}) + ${precision})`;
|
|
278
|
+
return stitch `all(abs(${lhs} - ${rhs}) <= ${_ctx.gen.typeInstantiation(lhs.dataType, [coerceToSnippet(precision)])})`;
|
|
280
279
|
}
|
|
281
280
|
return 'false';
|
|
282
281
|
},
|
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/operators.js
CHANGED
|
@@ -160,10 +160,15 @@ function cpuNeg(value) {
|
|
|
160
160
|
}
|
|
161
161
|
export const neg = dualImpl({
|
|
162
162
|
name: 'neg',
|
|
163
|
-
signature: (arg) =>
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
163
|
+
signature: (arg) => {
|
|
164
|
+
if (getPrimitive(arg) === u32) {
|
|
165
|
+
throw new WgslTypeError(`Unsupported signature. Unary operator - cannot be applied to argument of kind '${arg.type}'.`);
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
argTypes: [arg],
|
|
169
|
+
returnType: arg,
|
|
170
|
+
};
|
|
171
|
+
},
|
|
167
172
|
normalImpl: cpuNeg,
|
|
168
173
|
codegenImpl: (_ctx, [arg]) => stitch `-(${arg})`,
|
|
169
174
|
sideEffects: false,
|