typegpu 0.12.5 → 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/index.d.ts +1 -0
- package/common/index.js +1 -0
- package/common/writeChannels.d.ts +31 -0
- package/common/writeChannels.js +32 -0
- package/common/writeSoA.js +16 -0
- package/core/buffer/buffer.js +47 -11
- package/core/commandEncoder/attachments.js +5 -2
- package/core/commandEncoder/computePass.d.ts +13 -0
- package/core/commandEncoder/computePass.js +5 -2
- package/core/commandEncoder/renderPass.d.ts +18 -4
- package/core/commandEncoder/renderPass.js +6 -2
- package/core/declare/tgpuDeclare.d.ts +11 -0
- package/core/declare/tgpuDeclare.js +1 -1
- 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/immediate/immediateVar.d.ts +52 -0
- package/core/immediate/immediateVar.js +149 -0
- package/core/pipeline/computePipeline.d.ts +17 -0
- package/core/pipeline/computePipeline.js +23 -9
- 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/drawState.d.ts +8 -4
- package/core/pipeline/drawState.js +41 -51
- package/core/pipeline/priors.js +1 -0
- package/core/pipeline/renderPipeline.d.ts +22 -4
- package/core/pipeline/renderPipeline.js +25 -13
- package/core/resolve/namespace.js +2 -2
- package/core/root/init.js +3 -0
- package/core/root/rootTypes.d.ts +17 -2
- package/core/slot/accessor.d.ts +1 -1
- package/core/slot/accessor.js +72 -5
- package/core/slot/slotTypes.d.ts +2 -1
- package/core/texture/texture.d.ts +20 -14
- package/core/texture/texture.js +78 -69
- package/core/texture/textureUtils.d.ts +3 -6
- package/core/texture/textureUtils.js +142 -165
- package/core/texture/textureWrite.d.ts +61 -0
- package/core/texture/textureWrite.js +59 -0
- package/data/autoStruct.d.ts +1 -1
- package/data/autoStruct.js +8 -4
- package/data/dataIO.d.ts +2 -2
- 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 +11 -5
- package/data/snippet.js +9 -4
- package/data/wgslTypes.d.ts +4 -1
- package/errors.d.ts +7 -0
- package/errors.js +15 -0
- package/indexNamedExports.d.ts +5 -2
- package/indexNamedExports.js +2 -1
- package/internal.d.ts +2 -1
- package/internal.js +1 -1
- package/nameUtils.d.ts +7 -0
- package/nameUtils.js +60 -0
- package/package.json +2 -2
- package/resolutionCtx.d.ts +5 -0
- package/resolutionCtx.js +11 -0
- package/serial/restore.d.ts +3 -1
- package/serial/restore.js +2 -0
- package/shared/meta.js +1 -1
- package/shared/symbols.js +1 -1
- package/shared/tseynit.d.ts +1 -0
- package/shared/tseynit.js +80 -44
- package/std/atomic.d.ts +13 -0
- package/std/atomic.js +63 -29
- package/std/boolean.js +9 -10
- package/std/derivative.js +14 -9
- package/std/index.d.ts +4 -4
- package/std/index.js +5 -5
- package/std/numeric.d.ts +5 -1
- package/std/numeric.js +3 -3
- package/std/operators.js +9 -4
- package/std/packing.d.ts +61 -1
- package/std/packing.js +214 -25
- package/std/subgroup.d.ts +4 -0
- package/std/subgroup.js +34 -0
- package/std/texture.d.ts +15 -2
- package/std/texture.js +48 -0
- package/tgpuUnstable.d.ts +1 -0
- package/tgpuUnstable.js +1 -0
- package/tgsl/accessIndex.js +19 -23
- package/tgsl/conversion.d.ts +2 -0
- package/tgsl/conversion.js +3 -0
- package/tgsl/forOfUtils.js +6 -6
- package/tgsl/generationHelpers.js +2 -2
- package/tgsl/shaderGenerator.d.ts +1 -1
- package/tgsl/wgslGenerator.d.ts +5 -0
- package/tgsl/wgslGenerator.js +288 -58
- package/types.d.ts +9 -1
- package/types.js +5 -0
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typegpu",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.7",
|
|
4
4
|
"description": "A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compute",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"tsover-runtime": "^0.0.7",
|
|
52
52
|
"typed-binary": "^4.3.3",
|
|
53
|
-
"tinyest": "~0.3.
|
|
53
|
+
"tinyest": "~0.3.4"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
56
|
"node": ">=12.20.0"
|
package/resolutionCtx.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TgpuImmediateVar } from './core/immediate/immediateVar.ts';
|
|
1
2
|
import type { Namespace } from './core/resolve/namespace.ts';
|
|
2
3
|
import type { Configurable, ExperimentalTgpuRoot } from './core/root/rootTypes.ts';
|
|
3
4
|
import { type Eventual, type SlotValuePair, type TgpuLazy, type TgpuSlot } from './core/slot/slotTypes.ts';
|
|
@@ -84,6 +85,8 @@ export declare class ResolutionCtxImpl implements ResolutionCtx {
|
|
|
84
85
|
readonly enableExtensions: WgslEnableExtension[] | undefined;
|
|
85
86
|
expectedType: BaseData | undefined;
|
|
86
87
|
constructor(opts: ResolutionCtxImplOptions);
|
|
88
|
+
registerImmediate(immediate: TgpuImmediateVar): void;
|
|
89
|
+
get usedImmediate(): TgpuImmediateVar | undefined;
|
|
87
90
|
isIdentifierBanned(name: string): boolean;
|
|
88
91
|
isIdentifierTaken(name: string, scope: 'global' | 'block'): boolean;
|
|
89
92
|
makeUniqueIdentifier(primer: string | undefined, scope: 'global' | 'block'): string;
|
|
@@ -158,6 +161,7 @@ export interface ResolvedDeclaration {
|
|
|
158
161
|
* @param usedBindGroupLayouts - List of used `tgpu.bindGroupLayout`s.
|
|
159
162
|
* @param catchall - Automatically constructed bind group for buffer usages and buffer bindings, preceded by its index.
|
|
160
163
|
* @param logResources - Buffers and information about used console.logs needed to decode the raw data.
|
|
164
|
+
* @param usedImmediate - The immediate variable used by the shader, if any.
|
|
161
165
|
*/
|
|
162
166
|
export interface ResolutionResult {
|
|
163
167
|
code: string;
|
|
@@ -165,6 +169,7 @@ export interface ResolutionResult {
|
|
|
165
169
|
usedBindGroupLayouts: TgpuBindGroupLayout[];
|
|
166
170
|
catchall: [number, TgpuBindGroup] | undefined;
|
|
167
171
|
logResources: LogResources | undefined;
|
|
172
|
+
usedImmediate: TgpuImmediateVar | undefined;
|
|
168
173
|
}
|
|
169
174
|
export declare function resolve(item: Wgsl, options: ResolutionCtxImplOptions): ResolutionResult;
|
|
170
175
|
export {};
|
package/resolutionCtx.js
CHANGED
|
@@ -334,6 +334,7 @@ export class ResolutionCtxImpl {
|
|
|
334
334
|
// --
|
|
335
335
|
enableExtensions;
|
|
336
336
|
expectedType;
|
|
337
|
+
#usedImmediate;
|
|
337
338
|
/**
|
|
338
339
|
* A counter used to generate unique identifiers for globally-scoped definitions in the 'random' strategy.
|
|
339
340
|
*/
|
|
@@ -345,6 +346,15 @@ export class ResolutionCtxImpl {
|
|
|
345
346
|
this.gen = opts.shaderGenerator ?? new WgslGenerator();
|
|
346
347
|
this.gen.initGenerator(this);
|
|
347
348
|
}
|
|
349
|
+
registerImmediate(immediate) {
|
|
350
|
+
if (this.#usedImmediate !== undefined && this.#usedImmediate !== immediate) {
|
|
351
|
+
throw new Error(`Cannot use both immediate variables '${getName(this.#usedImmediate) ?? '<unnamed>'}' and '${getName(immediate) ?? '<unnamed>'}' in a single shader. At most one immediate variable is allowed per resolution.`);
|
|
352
|
+
}
|
|
353
|
+
this.#usedImmediate = immediate;
|
|
354
|
+
}
|
|
355
|
+
get usedImmediate() {
|
|
356
|
+
return this.#usedImmediate;
|
|
357
|
+
}
|
|
348
358
|
isIdentifierBanned(name) {
|
|
349
359
|
return bannedTokens.has(name);
|
|
350
360
|
}
|
|
@@ -924,5 +934,6 @@ export function resolve(item, options) {
|
|
|
924
934
|
usedBindGroupLayouts,
|
|
925
935
|
catchall,
|
|
926
936
|
logResources: ctx.logResources,
|
|
937
|
+
usedImmediate: ctx.usedImmediate,
|
|
927
938
|
};
|
|
928
939
|
}
|
package/serial/restore.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type TgpuBuffer, type TgpuBufferSoul } from '../core/buffer/buffer.ts';
|
|
|
2
2
|
import type { BaseData } from '../data/wgslTypes.ts';
|
|
3
3
|
import { TgpuBufferBindingImpl, type TgpuBufferBindingSoul } from '../core/buffer/bufferBinding.ts';
|
|
4
4
|
import { type TgpuConstSoul } from '../core/constant/tgpuConstant.ts';
|
|
5
|
+
import { type ImmediateData, type TgpuImmediateVarSoul } from '../core/immediate/immediateVar.ts';
|
|
5
6
|
import { type TgpuComputePipelineSoul } from '../core/pipeline/computePipeline.ts';
|
|
6
7
|
import { type TgpuRenderPipelineSoul } from '../core/pipeline/renderPipeline.ts';
|
|
7
8
|
import type { TgpuQuerySetSoul } from '../core/querySet/querySet.ts';
|
|
@@ -17,7 +18,7 @@ import { type TgpuBindGroupLayoutSoul, type TgpuBindGroupSoul } from '../tgpuBin
|
|
|
17
18
|
import type { TgpuSoul } from '../shared/soul.ts';
|
|
18
19
|
import type { RestoreContext } from './types.ts';
|
|
19
20
|
/** Every soul that can cross a device boundary, discriminated by `type` */
|
|
20
|
-
export type TgpuResourceSoul = TgpuBufferSoul | TgpuBufferBindingSoul | TgpuTextureSoul | TgpuSamplerSoul | TgpuQuerySetSoul | TgpuBindGroupLayoutSoul | TgpuBindGroupSoul | TgpuVertexLayoutSoul | TgpuConstSoul | TgpuSlotSoul | TgpuAccessorSoul | TgpuComputePipelineSoul | TgpuRenderPipelineSoul | TgpuGuardedComputePipelineSoul | TgpuRootSoul;
|
|
21
|
+
export type TgpuResourceSoul = TgpuBufferSoul | TgpuBufferBindingSoul | TgpuTextureSoul | TgpuSamplerSoul | TgpuQuerySetSoul | TgpuBindGroupLayoutSoul | TgpuBindGroupSoul | TgpuVertexLayoutSoul | TgpuConstSoul | TgpuImmediateVarSoul | TgpuSlotSoul | TgpuAccessorSoul | TgpuComputePipelineSoul | TgpuRenderPipelineSoul | TgpuGuardedComputePipelineSoul | TgpuRootSoul;
|
|
21
22
|
type Restorer<TSoul extends TgpuSoul> = (soul: TSoul, ctx: RestoreContext) => unknown;
|
|
22
23
|
declare function restoreBufferBinding(soul: TgpuBufferBindingSoul): TgpuBufferBindingImpl<"uniform" | "mutable" | "readonly", BaseData>;
|
|
23
24
|
/**
|
|
@@ -37,6 +38,7 @@ export declare const soulRestorers: {
|
|
|
37
38
|
'bind-group': Restorer<TgpuBindGroupSoul>;
|
|
38
39
|
'vertex-layout': (soul: TgpuVertexLayoutSoul) => import("../indexNamedExports.ts").TgpuVertexLayout<import("../data/wgslTypes.ts").WgslArray<AnyWgslData>> | import("../indexNamedExports.ts").TgpuVertexLayout<import("../data/dataTypes.ts").Disarray<AnyData>>;
|
|
39
40
|
const: (soul: TgpuConstSoul) => import("../indexNamedExports.ts").TgpuConst<AnyData>;
|
|
41
|
+
'immediate-var': (soul: TgpuImmediateVarSoul<ImmediateData>) => import("../indexNamedExports.ts").TgpuImmediateVar<ImmediateData>;
|
|
40
42
|
slot: (soul: TgpuSlotSoul) => import("../indexNamedExports.ts").TgpuSlot<unknown>;
|
|
41
43
|
accessor: (soul: TgpuAccessorSoul) => import("../indexNamedExports.ts").TgpuAccessor<AnyData>;
|
|
42
44
|
'mutable-accessor': (soul: TgpuAccessorSoul) => TgpuMutableAccessor<AnyData>;
|
package/serial/restore.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { INTERNAL_applyBufferUsages, } from "../core/buffer/buffer.js";
|
|
2
2
|
import { TgpuBufferBindingImpl } from "../core/buffer/bufferBinding.js";
|
|
3
3
|
import { constant } from "../core/constant/tgpuConstant.js";
|
|
4
|
+
import { immediateVar, } from "../core/immediate/immediateVar.js";
|
|
4
5
|
import { INTERNAL_restoreComputePipeline, } from "../core/pipeline/computePipeline.js";
|
|
5
6
|
import { INTERNAL_restoreRenderPipeline, } from "../core/pipeline/renderPipeline.js";
|
|
6
7
|
import { INTERNAL_restoreGuardedComputePipeline, INTERNAL_restoreRoot } from "../core/root/init.js";
|
|
@@ -57,6 +58,7 @@ export const soulRestorers = {
|
|
|
57
58
|
throw new Error('TypeGPU vertex layout payload could not be reconstructed.');
|
|
58
59
|
},
|
|
59
60
|
const: (soul) => constant(soul.dataType, soul.value),
|
|
61
|
+
'immediate-var': (soul) => immediateVar(soul.dataType, soul.defaultValue),
|
|
60
62
|
slot: (soul) => slot(soul.defaultValue),
|
|
61
63
|
accessor: (soul) => accessor(soul.schema, soul.defaultValue),
|
|
62
64
|
'mutable-accessor': (soul) => mutableAccessor(soul.schema, soul.defaultValue),
|
package/shared/meta.js
CHANGED
package/shared/symbols.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = "0.12.
|
|
1
|
+
const version = "0.12.7";
|
|
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`);
|
package/shared/tseynit.d.ts
CHANGED
package/shared/tseynit.js
CHANGED
|
@@ -2,77 +2,106 @@ 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 = `${indent}let ${stringifyExpression(node[1])}`;
|
|
31
32
|
if (node[2] !== undefined) {
|
|
32
|
-
return `${
|
|
33
|
+
return `${decl} = ${stringifyExpression(node[2])};`;
|
|
33
34
|
}
|
|
34
|
-
return `${
|
|
35
|
+
return `${decl};`;
|
|
35
36
|
}
|
|
36
37
|
if (node[0] === NODE.const) {
|
|
38
|
+
const decl = `${indent}const ${stringifyExpression(node[1])}`;
|
|
37
39
|
if (node[2] !== undefined) {
|
|
38
|
-
return `${
|
|
40
|
+
return `${decl} = ${stringifyExpression(node[2])};`;
|
|
39
41
|
}
|
|
40
|
-
return `${
|
|
42
|
+
return `${decl};`;
|
|
41
43
|
}
|
|
42
44
|
if (node[0] === NODE.for) {
|
|
43
45
|
const init = node[1] ? stringifyStatement(node[1], '') : ';';
|
|
44
|
-
const cond = node[2] ? stringifyExpression(node[2]
|
|
46
|
+
const cond = node[2] ? stringifyExpression(node[2]) : '';
|
|
45
47
|
const update = node[3] ? stringifyStatement(node[3], '') : '';
|
|
46
|
-
const body = stringifyStatement(node[4],
|
|
47
|
-
return `${
|
|
48
|
+
const body = stringifyStatement(node[4], indent);
|
|
49
|
+
return `${indent}for (${init} ${cond}; ${update.slice(0, -1) /* trim the ';' */}) ${body}`;
|
|
48
50
|
}
|
|
49
51
|
if (node[0] === NODE.while) {
|
|
50
|
-
const cond = stringifyExpression(node[1]
|
|
51
|
-
const body = stringifyStatement(node[2],
|
|
52
|
-
return `${
|
|
52
|
+
const cond = stringifyExpression(node[1]);
|
|
53
|
+
const body = stringifyStatement(node[2], indent);
|
|
54
|
+
return `${indent}while (${cond}) ${body}`;
|
|
53
55
|
}
|
|
54
56
|
if (node[0] === NODE.continue) {
|
|
55
|
-
return `${
|
|
57
|
+
return `${indent}continue;`;
|
|
56
58
|
}
|
|
57
59
|
if (node[0] === NODE.break) {
|
|
58
|
-
return `${
|
|
60
|
+
return `${indent}break;`;
|
|
59
61
|
}
|
|
60
62
|
if (node[0] === NODE.forOf) {
|
|
61
63
|
const leftKind = node[1][0] === NODE.const ? 'const' : 'let';
|
|
62
|
-
const leftName = node[1][1];
|
|
63
|
-
const right = stringifyExpression(node[2]
|
|
64
|
-
const body = stringifyStatement(node[3],
|
|
65
|
-
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
|
+
}
|
|
69
|
+
if (node[0] === NODE.switch) {
|
|
70
|
+
const discriminant = stringifyExpression(node[1]);
|
|
71
|
+
const cases = node[2].map((c) => {
|
|
72
|
+
const test = c[0] === null ? 'default' : `case ${stringifyExpression(c[0])}`;
|
|
73
|
+
if (c[1].length === 0) {
|
|
74
|
+
return `${test}:`;
|
|
75
|
+
}
|
|
76
|
+
const consequents = c[1].map((s) => stringifyStatement(s, indent + ' '));
|
|
77
|
+
return `${test}:\n${consequents.join('\n')}`;
|
|
78
|
+
});
|
|
79
|
+
return `${indent}switch (${discriminant}) {\n${cases.map((c) => `${indent + ' '}${c}`).join('\n')}\n${indent}}`;
|
|
66
80
|
}
|
|
67
81
|
assertExhaustive(node);
|
|
68
82
|
}
|
|
69
|
-
|
|
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
|
+
}
|
|
87
|
+
export function stringifyObjectProperty([key, value, computed]) {
|
|
88
|
+
const keyStr = computed ? `[${stringifyExpression(key)}]` : stringifyObjectPropertyKey(key);
|
|
89
|
+
const valueStr = stringifyExpression(value);
|
|
90
|
+
return `${keyStr}: ${valueStr}`;
|
|
91
|
+
}
|
|
92
|
+
function stringifyExpression(node) {
|
|
70
93
|
if (typeof node === 'string') {
|
|
71
94
|
return node;
|
|
72
95
|
}
|
|
73
96
|
if (typeof node === 'boolean') {
|
|
74
97
|
return `${node}`;
|
|
75
98
|
}
|
|
99
|
+
if (node[0] === NODE.identifier) {
|
|
100
|
+
return node[1];
|
|
101
|
+
}
|
|
102
|
+
if (node[0] === NODE.booleanLiteral) {
|
|
103
|
+
return `${node[1]}`;
|
|
104
|
+
}
|
|
76
105
|
if (node[0] === NODE.numericLiteral) {
|
|
77
106
|
return node[1];
|
|
78
107
|
}
|
|
@@ -80,49 +109,52 @@ function stringifyExpression(node, ident) {
|
|
|
80
109
|
return JSON.stringify(node[1]);
|
|
81
110
|
}
|
|
82
111
|
if (node[0] === NODE.arrayExpr) {
|
|
83
|
-
const elements = node[1].map((n) => stringifyExpression(n
|
|
112
|
+
const elements = node[1].map((n) => stringifyExpression(n));
|
|
84
113
|
return `[${elements.join(', ')}]`;
|
|
85
114
|
}
|
|
86
115
|
if (node[0] === NODE.binaryExpr) {
|
|
87
|
-
return `${wrapIfComplex(node[1]
|
|
116
|
+
return `${wrapIfComplex(node[1])} ${node[2]} ${wrapIfComplex(node[3])}`;
|
|
88
117
|
}
|
|
89
118
|
if (node[0] === NODE.assignmentExpr) {
|
|
90
|
-
return `${stringifyExpression(node[1]
|
|
119
|
+
return `${stringifyExpression(node[1])} ${node[2]} ${stringifyExpression(node[3])}`;
|
|
91
120
|
}
|
|
92
121
|
if (node[0] === NODE.logicalExpr) {
|
|
93
|
-
return `${wrapIfComplex(node[1]
|
|
122
|
+
return `${wrapIfComplex(node[1])} ${node[2]} ${wrapIfComplex(node[3])}`;
|
|
94
123
|
}
|
|
95
124
|
if (node[0] === NODE.unaryExpr) {
|
|
96
125
|
// Unary word operators like void, instanceof and delete require a space
|
|
97
126
|
const sep = node[1].length > 1 ? ' ' : '';
|
|
98
|
-
return `${node[1]}${sep}${wrapIfComplex(node[2]
|
|
127
|
+
return `${node[1]}${sep}${wrapIfComplex(node[2])}`;
|
|
99
128
|
}
|
|
100
129
|
if (node[0] === NODE.call) {
|
|
101
|
-
const callee = wrapIfComplex(node[1]
|
|
102
|
-
const args = node[2].map((n) => stringifyExpression(n
|
|
130
|
+
const callee = wrapIfComplex(node[1]);
|
|
131
|
+
const args = node[2].map((n) => stringifyExpression(n)).join(', ');
|
|
103
132
|
return `${callee}(${args})`;
|
|
104
133
|
}
|
|
105
134
|
if (node[0] === NODE.memberAccess) {
|
|
106
135
|
if (Array.isArray(node[1]) && node[1][0] === NODE.numericLiteral) {
|
|
107
|
-
return `(${stringifyExpression(node[1]
|
|
136
|
+
return `(${stringifyExpression(node[1])}).${stringifyExpression(node[2])}`;
|
|
108
137
|
}
|
|
109
|
-
return `${wrapIfComplex(node[1]
|
|
138
|
+
return `${wrapIfComplex(node[1])}.${stringifyExpression(node[2])}`;
|
|
110
139
|
}
|
|
111
140
|
if (node[0] === NODE.indexAccess) {
|
|
112
|
-
return `${wrapIfComplex(node[1]
|
|
141
|
+
return `${wrapIfComplex(node[1])}[${stringifyExpression(node[2])}]`;
|
|
113
142
|
}
|
|
114
143
|
if (node[0] === NODE.preUpdate) {
|
|
115
|
-
return `${node[1]}${wrapIfComplex(node[2]
|
|
144
|
+
return `${node[1]}${wrapIfComplex(node[2])}`;
|
|
116
145
|
}
|
|
117
146
|
if (node[0] === NODE.postUpdate) {
|
|
118
|
-
return `${wrapIfComplex(node[2]
|
|
147
|
+
return `${wrapIfComplex(node[2])}${node[1]}`;
|
|
119
148
|
}
|
|
120
149
|
if (node[0] === NODE.objectExpr) {
|
|
121
|
-
|
|
150
|
+
if (Array.isArray(node[1])) {
|
|
151
|
+
return `{ ${node[1].map(stringifyObjectProperty).join(', ')} }`;
|
|
152
|
+
}
|
|
153
|
+
const entries = Object.entries(node[1]).map(([key, val]) => `${stringifyObjectPropertyKey(key)}: ${stringifyExpression(val)}`);
|
|
122
154
|
return `{ ${entries.join(', ')} }`;
|
|
123
155
|
}
|
|
124
156
|
if (node[0] === NODE.conditionalExpr) {
|
|
125
|
-
return `${wrapIfComplex(node[1]
|
|
157
|
+
return `${wrapIfComplex(node[1])} ? ${wrapIfComplex(node[2])} : ${wrapIfComplex(node[3])}`;
|
|
126
158
|
}
|
|
127
159
|
if (node[0] === NODE.nullLiteral) {
|
|
128
160
|
return 'null';
|
|
@@ -135,6 +167,8 @@ function assertExhaustive(value) {
|
|
|
135
167
|
function isExpression(node) {
|
|
136
168
|
if (typeof node === 'string' ||
|
|
137
169
|
typeof node === 'boolean' ||
|
|
170
|
+
node[0] === NODE.identifier ||
|
|
171
|
+
node[0] === NODE.booleanLiteral ||
|
|
138
172
|
node[0] === NODE.numericLiteral ||
|
|
139
173
|
node[0] === NODE.stringLiteral ||
|
|
140
174
|
node[0] === NODE.arrayExpr ||
|
|
@@ -163,12 +197,14 @@ const SIMPLE_NODES = [
|
|
|
163
197
|
NODE.arrayExpr, // [] make things not ambiguous
|
|
164
198
|
NODE.stringLiteral,
|
|
165
199
|
NODE.numericLiteral,
|
|
200
|
+
NODE.identifier,
|
|
201
|
+
NODE.booleanLiteral,
|
|
166
202
|
];
|
|
167
203
|
/**
|
|
168
204
|
* Stringifies expression, and wraps it in parentheses if they cannot be trivially omitted
|
|
169
205
|
*/
|
|
170
|
-
function wrapIfComplex(node
|
|
171
|
-
const s = stringifyExpression(node
|
|
206
|
+
function wrapIfComplex(node) {
|
|
207
|
+
const s = stringifyExpression(node);
|
|
172
208
|
if (typeof node === 'string' || typeof node === 'boolean') {
|
|
173
209
|
return s;
|
|
174
210
|
}
|
package/std/atomic.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { type _ref as ref } from '../data/ref.ts';
|
|
1
2
|
import { type atomicI32, type atomicU32 } from '../data/wgslTypes.ts';
|
|
2
3
|
type AnyAtomic = atomicI32 | atomicU32;
|
|
3
4
|
export declare const workgroupBarrier: import("../types.ts").DualFn<(...args: never[]) => unknown>;
|
|
4
5
|
export declare const storageBarrier: import("../types.ts").DualFn<(...args: never[]) => unknown>;
|
|
5
6
|
export declare const textureBarrier: import("../types.ts").DualFn<(...args: never[]) => unknown>;
|
|
7
|
+
interface WorkgroupUniformLoad {
|
|
8
|
+
<T extends AnyAtomic>(value: T | ref<T>): number;
|
|
9
|
+
<T>(value: ref<T>): T;
|
|
10
|
+
<T>(value: T): T;
|
|
11
|
+
}
|
|
12
|
+
export declare const workgroupUniformLoad: import("../types.ts").DualFn<WorkgroupUniformLoad>;
|
|
6
13
|
export declare const atomicLoad: import("../types.ts").DualFn<(<T extends AnyAtomic>(a: T) => number)>;
|
|
7
14
|
export declare const atomicStore: import("../types.ts").DualFn<(<T extends AnyAtomic>(a: T, value: number) => void)>;
|
|
8
15
|
export declare const atomicAdd: import("../types.ts").DualFn<(<T extends AnyAtomic>(a: T, value: number) => number)>;
|
|
@@ -12,4 +19,10 @@ export declare const atomicMin: import("../types.ts").DualFn<(<T extends AnyAtom
|
|
|
12
19
|
export declare const atomicAnd: import("../types.ts").DualFn<(<T extends AnyAtomic>(a: T, value: number) => number)>;
|
|
13
20
|
export declare const atomicOr: import("../types.ts").DualFn<(<T extends AnyAtomic>(a: T, value: number) => number)>;
|
|
14
21
|
export declare const atomicXor: import("../types.ts").DualFn<(<T extends AnyAtomic>(a: T, value: number) => number)>;
|
|
22
|
+
export declare const atomicExchange: import("../types.ts").DualFn<(<T extends AnyAtomic>(a: T, value: number) => number)>;
|
|
23
|
+
type AtomicCompareExchangeResult = {
|
|
24
|
+
old_value: number;
|
|
25
|
+
exchanged: boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare const atomicCompareExchangeWeak: import("../types.ts").DualFn<(<T extends AnyAtomic>(a: T, compare: number, value: number) => AtomicCompareExchangeResult)>;
|
|
15
28
|
export {};
|
package/std/atomic.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { dualImpl } from "../core/function/dualImpl.js";
|
|
2
2
|
import { stitch } from "../core/resolve/stitch.js";
|
|
3
|
-
import {
|
|
3
|
+
import { unptr } from "../data/dataTypes.js";
|
|
4
|
+
import { bool, i32, u32 } from "../data/numeric.js";
|
|
5
|
+
import { derefSnippet } from "../data/ref.js";
|
|
6
|
+
import { abstruct } from "../data/struct.js";
|
|
4
7
|
import { isAtomic, Void, } from "../data/wgslTypes.js";
|
|
5
8
|
import { safeStringify } from "../shared/stringify.js";
|
|
6
9
|
export const workgroupBarrier = dualImpl({
|
|
@@ -24,33 +27,40 @@ export const textureBarrier = dualImpl({
|
|
|
24
27
|
codegenImpl: () => 'textureBarrier()',
|
|
25
28
|
sideEffects: true,
|
|
26
29
|
});
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
export const workgroupUniformLoad = dualImpl({
|
|
31
|
+
name: 'workgroupUniformLoad',
|
|
32
|
+
normalImpl: 'workgroupUniformLoad is not supported outside of CODEGEN mode.',
|
|
33
|
+
signature: (value) => {
|
|
34
|
+
const inner = unptr(value);
|
|
35
|
+
return {
|
|
36
|
+
argTypes: [value],
|
|
37
|
+
returnType: isAtomic(inner) ? inner.inner : inner,
|
|
38
|
+
};
|
|
36
39
|
},
|
|
37
|
-
codegenImpl: (_ctx, [
|
|
40
|
+
codegenImpl: (_ctx, [value]) => stitch `workgroupUniformLoad(&${derefSnippet(value)})`,
|
|
38
41
|
sideEffects: true,
|
|
39
42
|
});
|
|
40
|
-
const
|
|
41
|
-
|
|
43
|
+
const atomicNormalError = 'Atomic operations are not supported outside of CODEGEN mode.';
|
|
44
|
+
const unwrapAtomic = (a) => {
|
|
45
|
+
const inner = unptr(a);
|
|
46
|
+
if (!isAtomic(inner)) {
|
|
42
47
|
throw new Error(`Invalid atomic type: ${safeStringify(a)}`);
|
|
43
48
|
}
|
|
44
|
-
return
|
|
45
|
-
argTypes: [a, a.inner.type === 'u32' ? u32 : i32],
|
|
46
|
-
returnType: Void,
|
|
47
|
-
};
|
|
49
|
+
return inner;
|
|
48
50
|
};
|
|
51
|
+
export const atomicLoad = dualImpl({
|
|
52
|
+
name: 'atomicLoad',
|
|
53
|
+
normalImpl: atomicNormalError,
|
|
54
|
+
signature: (a) => ({ argTypes: [a], returnType: unwrapAtomic(a).inner }),
|
|
55
|
+
codegenImpl: (_ctx, [a]) => stitch `atomicLoad(&${derefSnippet(a)})`,
|
|
56
|
+
sideEffects: true,
|
|
57
|
+
});
|
|
58
|
+
const atomicActionSignature = (a) => ({
|
|
59
|
+
argTypes: [a, unwrapAtomic(a).inner.type === 'u32' ? u32 : i32],
|
|
60
|
+
returnType: Void,
|
|
61
|
+
});
|
|
49
62
|
const atomicOpSignature = (a) => {
|
|
50
|
-
|
|
51
|
-
throw new Error(`Invalid atomic type: ${safeStringify(a)}`);
|
|
52
|
-
}
|
|
53
|
-
const paramType = a.inner.type === 'u32' ? u32 : i32;
|
|
63
|
+
const paramType = unwrapAtomic(a).inner.type === 'u32' ? u32 : i32;
|
|
54
64
|
return {
|
|
55
65
|
argTypes: [a, paramType],
|
|
56
66
|
returnType: paramType,
|
|
@@ -60,55 +70,79 @@ export const atomicStore = dualImpl({
|
|
|
60
70
|
name: 'atomicStore',
|
|
61
71
|
normalImpl: atomicNormalError,
|
|
62
72
|
signature: atomicActionSignature,
|
|
63
|
-
codegenImpl: (_ctx, [a, value]) => stitch `atomicStore(&${a}, ${value})`,
|
|
73
|
+
codegenImpl: (_ctx, [a, value]) => stitch `atomicStore(&${derefSnippet(a)}, ${value})`,
|
|
64
74
|
sideEffects: true,
|
|
65
75
|
});
|
|
66
76
|
export const atomicAdd = dualImpl({
|
|
67
77
|
name: 'atomicAdd',
|
|
68
78
|
normalImpl: atomicNormalError,
|
|
69
79
|
signature: atomicOpSignature,
|
|
70
|
-
codegenImpl: (_ctx, [a, value]) => stitch `atomicAdd(&${a}, ${value})`,
|
|
80
|
+
codegenImpl: (_ctx, [a, value]) => stitch `atomicAdd(&${derefSnippet(a)}, ${value})`,
|
|
71
81
|
sideEffects: true,
|
|
72
82
|
});
|
|
73
83
|
export const atomicSub = dualImpl({
|
|
74
84
|
name: 'atomicSub',
|
|
75
85
|
normalImpl: atomicNormalError,
|
|
76
86
|
signature: atomicOpSignature,
|
|
77
|
-
codegenImpl: (_ctx, [a, value]) => stitch `atomicSub(&${a}, ${value})`,
|
|
87
|
+
codegenImpl: (_ctx, [a, value]) => stitch `atomicSub(&${derefSnippet(a)}, ${value})`,
|
|
78
88
|
sideEffects: true,
|
|
79
89
|
});
|
|
80
90
|
export const atomicMax = dualImpl({
|
|
81
91
|
name: 'atomicMax',
|
|
82
92
|
normalImpl: atomicNormalError,
|
|
83
93
|
signature: atomicOpSignature,
|
|
84
|
-
codegenImpl: (_ctx, [a, value]) => stitch `atomicMax(&${a}, ${value})`,
|
|
94
|
+
codegenImpl: (_ctx, [a, value]) => stitch `atomicMax(&${derefSnippet(a)}, ${value})`,
|
|
85
95
|
sideEffects: true,
|
|
86
96
|
});
|
|
87
97
|
export const atomicMin = dualImpl({
|
|
88
98
|
name: 'atomicMin',
|
|
89
99
|
normalImpl: atomicNormalError,
|
|
90
100
|
signature: atomicOpSignature,
|
|
91
|
-
codegenImpl: (_ctx, [a, value]) => stitch `atomicMin(&${a}, ${value})`,
|
|
101
|
+
codegenImpl: (_ctx, [a, value]) => stitch `atomicMin(&${derefSnippet(a)}, ${value})`,
|
|
92
102
|
sideEffects: true,
|
|
93
103
|
});
|
|
94
104
|
export const atomicAnd = dualImpl({
|
|
95
105
|
name: 'atomicAnd',
|
|
96
106
|
normalImpl: atomicNormalError,
|
|
97
107
|
signature: atomicOpSignature,
|
|
98
|
-
codegenImpl: (_ctx, [a, value]) => stitch `atomicAnd(&${a}, ${value})`,
|
|
108
|
+
codegenImpl: (_ctx, [a, value]) => stitch `atomicAnd(&${derefSnippet(a)}, ${value})`,
|
|
99
109
|
sideEffects: true,
|
|
100
110
|
});
|
|
101
111
|
export const atomicOr = dualImpl({
|
|
102
112
|
name: 'atomicOr',
|
|
103
113
|
normalImpl: atomicNormalError,
|
|
104
114
|
signature: atomicOpSignature,
|
|
105
|
-
codegenImpl: (_ctx, [a, value]) => stitch `atomicOr(&${a}, ${value})`,
|
|
115
|
+
codegenImpl: (_ctx, [a, value]) => stitch `atomicOr(&${derefSnippet(a)}, ${value})`,
|
|
106
116
|
sideEffects: true,
|
|
107
117
|
});
|
|
108
118
|
export const atomicXor = dualImpl({
|
|
109
119
|
name: 'atomicXor',
|
|
110
120
|
normalImpl: atomicNormalError,
|
|
111
121
|
signature: atomicOpSignature,
|
|
112
|
-
codegenImpl: (_ctx, [a, value]) => stitch `atomicXor(&${a}, ${value})`,
|
|
122
|
+
codegenImpl: (_ctx, [a, value]) => stitch `atomicXor(&${derefSnippet(a)}, ${value})`,
|
|
123
|
+
sideEffects: true,
|
|
124
|
+
});
|
|
125
|
+
export const atomicExchange = dualImpl({
|
|
126
|
+
name: 'atomicExchange',
|
|
127
|
+
normalImpl: atomicNormalError,
|
|
128
|
+
signature: atomicOpSignature,
|
|
129
|
+
codegenImpl: (_ctx, [a, value]) => stitch `atomicExchange(&${derefSnippet(a)}, ${value})`,
|
|
130
|
+
sideEffects: true,
|
|
131
|
+
});
|
|
132
|
+
const AtomicCompareExchangeResults = {
|
|
133
|
+
i32: abstruct({ old_value: i32, exchanged: bool }),
|
|
134
|
+
u32: abstruct({ old_value: u32, exchanged: bool }),
|
|
135
|
+
};
|
|
136
|
+
export const atomicCompareExchangeWeak = dualImpl({
|
|
137
|
+
name: 'atomicCompareExchangeWeak',
|
|
138
|
+
normalImpl: atomicNormalError,
|
|
139
|
+
signature: (a) => {
|
|
140
|
+
const inner = unwrapAtomic(a).inner.type === 'u32' ? u32 : i32;
|
|
141
|
+
return {
|
|
142
|
+
argTypes: [a, inner, inner],
|
|
143
|
+
returnType: AtomicCompareExchangeResults[inner.type],
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
codegenImpl: (_ctx, [a, compare, value]) => stitch `atomicCompareExchangeWeak(&${derefSnippet(a)}, ${compare}, ${value})`,
|
|
113
147
|
sideEffects: true,
|
|
114
148
|
});
|