typegpu 0.12.6 → 0.12.7
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 +4 -2
- package/core/function/ioSchema.d.ts +7 -2
- package/core/function/ioSchema.js +41 -15
- 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 +5 -4
- package/core/pipeline/renderPipeline.js +10 -12
- package/core/resolve/namespace.js +2 -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/texture.js +8 -4
- package/data/autoStruct.d.ts +1 -1
- package/data/autoStruct.js +8 -4
- package/data/deepEqual.js +19 -9
- package/data/matrix.js +10 -3
- package/data/partialIO.d.ts +8 -1
- package/data/partialIO.js +36 -19
- package/data/ref.js +2 -2
- package/data/snippet.d.ts +6 -4
- package/data/snippet.js +8 -4
- package/data/wgslTypes.d.ts +3 -0
- package/internal.d.ts +1 -0
- package/nameUtils.d.ts +7 -0
- package/nameUtils.js +60 -0
- package/package.json +1 -1
- package/shared/meta.js +1 -1
- package/shared/symbols.js +1 -1
- package/shared/tseynit.js +54 -50
- package/std/boolean.js +9 -10
- package/std/operators.js +9 -4
- package/std/texture.d.ts +2 -2
- package/tgsl/accessIndex.js +19 -23
- package/tgsl/forOfUtils.js +6 -6
- package/tgsl/generationHelpers.js +2 -2
- package/tgsl/wgslGenerator.js +85 -23
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/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,
|
package/std/texture.d.ts
CHANGED
|
@@ -61,8 +61,8 @@ declare function textureStoreCpu<T extends textureStorage3d>(texture: T, coords:
|
|
|
61
61
|
export declare const textureStore: import("../types.ts").DualFn<typeof textureStoreCpu>;
|
|
62
62
|
declare function textureDimensionsCpu<T extends texture1d | textureStorage1d>(texture: T): number;
|
|
63
63
|
declare function textureDimensionsCpu<T extends texture1d>(texture: T, level: number): number;
|
|
64
|
-
declare function textureDimensionsCpu<T extends texture2d | texture2dArray | textureCube | textureCubeArray | textureStorage2d | textureStorage2dArray | textureExternal>(texture: T): v2u;
|
|
65
|
-
declare function textureDimensionsCpu<T extends texture2d | texture2dArray | textureCube | textureCubeArray>(texture: T, level: number): v2u;
|
|
64
|
+
declare function textureDimensionsCpu<T extends texture2d | texture2dArray | textureCube | textureCubeArray | textureMultisampled2d | textureDepth2d | textureDepth2dArray | textureDepthCube | textureDepthCubeArray | textureDepthMultisampled2d | textureStorage2d | textureStorage2dArray | textureExternal>(texture: T): v2u;
|
|
65
|
+
declare function textureDimensionsCpu<T extends texture2d | texture2dArray | textureCube | textureCubeArray | textureDepth2d | textureDepth2dArray | textureDepthCube | textureDepthCubeArray>(texture: T, level: number): v2u;
|
|
66
66
|
declare function textureDimensionsCpu<T extends texture3d | textureStorage3d>(texture: T): v3u;
|
|
67
67
|
declare function textureDimensionsCpu<T extends texture3d>(texture: T, level: number): v3u;
|
|
68
68
|
export declare const textureDimensions: import("../types.ts").DualFn<typeof textureDimensionsCpu>;
|
package/tgsl/accessIndex.js
CHANGED
|
@@ -12,33 +12,31 @@ const indexableTypeToResult = {
|
|
|
12
12
|
mat3x3f: vec3f,
|
|
13
13
|
mat4x4f: vec4f,
|
|
14
14
|
};
|
|
15
|
+
function deriveIndexAccessOrigin(targetOrigin, indexOrigin) {
|
|
16
|
+
if (targetOrigin === 'constant-immutable-def') {
|
|
17
|
+
// Constant refs stay const unless the index forces runtime materialization
|
|
18
|
+
return indexOrigin === 'constant' || indexOrigin === 'constant-immutable-def'
|
|
19
|
+
? 'constant-immutable-def'
|
|
20
|
+
: 'runtime-immutable-def';
|
|
21
|
+
}
|
|
22
|
+
if (targetOrigin === 'constant') {
|
|
23
|
+
// Ephemeral constants indexed with constants stay constant, otherwise they become runtime-known
|
|
24
|
+
return indexOrigin === 'constant' || indexOrigin === 'constant-immutable-def'
|
|
25
|
+
? 'constant'
|
|
26
|
+
: 'runtime';
|
|
27
|
+
}
|
|
28
|
+
// Fallthrough
|
|
29
|
+
return targetOrigin;
|
|
30
|
+
}
|
|
15
31
|
export function accessIndex(target, indexArg) {
|
|
16
32
|
const index = typeof indexArg === 'number' ? coerceToSnippet(indexArg) : indexArg;
|
|
17
33
|
// array
|
|
18
34
|
if (isWgslArray(target.dataType) || isDisarray(target.dataType)) {
|
|
19
35
|
const elementType = target.dataType.elementType;
|
|
20
|
-
let origin;
|
|
21
|
-
if (target.origin === 'constant-immutable-def') {
|
|
22
|
-
// Constant refs stay const unless the element/index forces runtime materialization
|
|
23
|
-
origin =
|
|
24
|
-
index.origin === 'constant' || index.origin === 'constant-immutable-def'
|
|
25
|
-
? 'constant-immutable-def'
|
|
26
|
-
: 'runtime-immutable-def';
|
|
27
|
-
}
|
|
28
|
-
else if (target.origin === 'constant') {
|
|
29
|
-
// Ephemeral constants indexed with constants stay constant, otherwise they become runtime-known
|
|
30
|
-
origin =
|
|
31
|
-
index.origin === 'constant' || index.origin === 'constant-immutable-def'
|
|
32
|
-
? 'constant'
|
|
33
|
-
: 'runtime';
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
// Fallthrough
|
|
37
|
-
origin = target.origin;
|
|
38
|
-
}
|
|
39
36
|
if (target.value instanceof ArrayExpression && isKnownAtComptime(index)) {
|
|
40
37
|
return target.value.elements[index.value];
|
|
41
38
|
}
|
|
39
|
+
const origin = deriveIndexAccessOrigin(target.origin, index.origin);
|
|
42
40
|
return snip(isKnownAtComptime(target) && isKnownAtComptime(index)
|
|
43
41
|
? // oxlint-disable-next-line typescript/no-explicit-any -- it's fine, it's there
|
|
44
42
|
target.value[index.value]
|
|
@@ -50,8 +48,7 @@ export function accessIndex(target, indexArg) {
|
|
|
50
48
|
return snip(isKnownAtComptime(target) && isKnownAtComptime(index)
|
|
51
49
|
? // oxlint-disable-next-line typescript/no-explicit-any -- it's fine, it's there
|
|
52
50
|
target.value[index.value]
|
|
53
|
-
: stitch `${target}[${index}]`, target.dataType.primitive,
|
|
54
|
-
/* origin */ target.origin, target.possibleSideEffects || index.possibleSideEffects);
|
|
51
|
+
: stitch `${target}[${index}]`, target.dataType.primitive, deriveIndexAccessOrigin(target.origin, index.origin), target.possibleSideEffects || index.possibleSideEffects);
|
|
55
52
|
}
|
|
56
53
|
if (isPtr(target.dataType)) {
|
|
57
54
|
// Sometimes values that are typed as pointers aren't instances of `d.ref`, so we
|
|
@@ -61,8 +58,7 @@ export function accessIndex(target, indexArg) {
|
|
|
61
58
|
// matrix.columns
|
|
62
59
|
if (target.value instanceof MatrixColumnsAccess) {
|
|
63
60
|
const propType = indexableTypeToResult[target.value.matrix.dataType.type];
|
|
64
|
-
return snip(stitch `${target.value.matrix}[${index}]`, propType,
|
|
65
|
-
/* origin */ target.origin, target.possibleSideEffects || index.possibleSideEffects);
|
|
61
|
+
return snip(stitch `${target.value.matrix}[${index}]`, propType, deriveIndexAccessOrigin(target.origin, index.origin), target.possibleSideEffects || index.possibleSideEffects);
|
|
66
62
|
}
|
|
67
63
|
// matrix
|
|
68
64
|
if (target.dataType.type in indexableTypeToResult) {
|
package/tgsl/forOfUtils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { UnknownData } from "../data/dataTypes.js";
|
|
2
|
-
import {
|
|
2
|
+
import { isAddressableOrigin, isStoredInMemory, snip } from "../data/snippet.js";
|
|
3
3
|
import { stitch } from "../core/resolve/stitch.js";
|
|
4
4
|
import * as wgsl from "../data/wgslTypes.js";
|
|
5
5
|
import { i32, u32 } from "../data/numeric.js";
|
|
@@ -31,10 +31,7 @@ export function getElementType(elementSnippet, iterableSnippet) {
|
|
|
31
31
|
throw new WgslTypeError(stitch `The elements in iterable ${iterableSnippet} are of unknown type`);
|
|
32
32
|
}
|
|
33
33
|
if (wgsl.isNaturallyEphemeral(elementSnippet.dataType) ||
|
|
34
|
-
elementSnippet.origin
|
|
35
|
-
elementSnippet.origin === 'constant' ||
|
|
36
|
-
elementSnippet.origin === 'constant-immutable-def' ||
|
|
37
|
-
elementSnippet.origin === 'runtime-immutable-def') {
|
|
34
|
+
!isAddressableOrigin(elementSnippet.origin)) {
|
|
38
35
|
return elementType;
|
|
39
36
|
}
|
|
40
37
|
if (!wgsl.isPtr(elementType)) {
|
|
@@ -56,7 +53,10 @@ export function getRangeSnippets(ctx, iterableSnippet, unroll = false) {
|
|
|
56
53
|
comparison: step < 0 ? '>' : '<',
|
|
57
54
|
};
|
|
58
55
|
}
|
|
59
|
-
if (
|
|
56
|
+
if (iterableSnippet.possibleSideEffects) {
|
|
57
|
+
throw new Error('`for ... of ...` loops do not support iterables with possible side effects. Store the iterable in a variable first.');
|
|
58
|
+
}
|
|
59
|
+
if (!unroll && !isStoredInMemory(iterableSnippet)) {
|
|
60
60
|
throw new Error(`\`for ... of ...\` loops only support std.range or iterables stored in variables.
|
|
61
61
|
-----
|
|
62
62
|
You can wrap iterable with \`tgpu.unroll(...)\`. If iterable is known at comptime, the loop will be unrolled.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { UnknownData } from "../data/dataTypes.js";
|
|
2
2
|
import { abstractFloat, abstractInt, bool, f32, i32 } from "../data/numeric.js";
|
|
3
3
|
import { isRef } from "../data/ref.js";
|
|
4
|
-
import {
|
|
4
|
+
import { isStoredInMemory, isSnippet, snip, withDataType } from "../data/snippet.js";
|
|
5
5
|
import { isMatInstance, isNaturallyEphemeral, isVecInstance, WORKAROUND_getSchema, } from "../data/wgslTypes.js";
|
|
6
6
|
import { getOwnSnippet } from "../types.js";
|
|
7
7
|
import { WgslTypeError } from "../errors.js";
|
|
@@ -81,7 +81,7 @@ export class ArrayExpression {
|
|
|
81
81
|
[$resolve](ctx) {
|
|
82
82
|
for (const elem of this.elements) {
|
|
83
83
|
// We check if there are no references among the elements
|
|
84
|
-
if (
|
|
84
|
+
if (isStoredInMemory(elem) && !isNaturallyEphemeral(elem.dataType)) {
|
|
85
85
|
const snippetStr = ctx.resolveSnippet(elem).value;
|
|
86
86
|
const snippetType = ctx.resolve(concretize(elem.dataType)).value;
|
|
87
87
|
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-----`);
|