typegpu 0.11.6 → 0.11.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/bin.mjs +57 -0
- package/builtin.d.ts +5 -1
- package/builtin.js +2 -0
- package/core/buffer/buffer.js +1 -1
- package/core/buffer/bufferUsage.js +18 -14
- package/core/constant/tgpuConstant.js +6 -6
- package/core/declare/tgpuDeclare.js +2 -2
- package/core/function/comptime.js +8 -3
- package/core/function/createCallableSchema.js +7 -5
- package/core/function/dualImpl.js +2 -2
- package/core/function/fnCore.js +12 -13
- package/core/function/tgpuComputeFn.js +1 -1
- package/core/function/tgpuFn.js +3 -2
- package/core/pipeline/computePipeline.js +3 -3
- package/core/pipeline/renderPipeline.js +3 -3
- package/core/rawCodeSnippet/tgpuRawCodeSnippet.d.ts +1 -1
- package/core/rawCodeSnippet/tgpuRawCodeSnippet.js +2 -2
- package/core/resolve/externals.d.ts +1 -1
- package/core/resolve/externals.js +24 -10
- package/core/resolve/tgpuResolve.d.ts +2 -2
- package/core/resolve/tgpuResolve.js +2 -2
- package/core/root/init.js +1 -1
- package/core/slot/accessor.js +1 -1
- package/core/texture/texture.js +8 -2
- package/core/variable/tgpuVariable.js +8 -6
- package/core/vertexLayout/vertexLayout.js +1 -1
- package/data/alignmentOf.js +1 -1
- package/data/attributes.d.ts +1 -1
- package/data/dataIO.js +1 -1
- package/data/dataTypes.d.ts +0 -1
- package/data/dataTypes.js +2 -12
- package/data/index.js +6 -23
- package/data/ref.js +20 -7
- package/data/snippet.d.ts +2 -1
- package/data/snippet.js +37 -10
- package/errors.d.ts +1 -4
- package/errors.js +1 -7
- package/index.d.ts +2 -2
- package/index.js +2 -2
- package/indexNamedExports.d.ts +1 -1
- package/package.js +1 -1
- package/package.json +5 -4
- package/resolutionCtx.js +9 -16
- package/shared/meta.d.ts +6 -15
- package/shared/meta.js +45 -38
- package/shared/normalizeMetadata.d.ts +32 -0
- package/shared/normalizeMetadata.js +41 -0
- package/std/atomic.js +1 -1
- package/std/boolean.js +36 -5
- package/std/environment.d.ts +48 -0
- package/std/environment.js +57 -0
- package/std/extensions.d.ts +2 -2
- package/std/extensions.js +2 -2
- package/std/index.d.ts +3 -2
- package/std/index.js +5 -2
- package/tgpuBindGroupLayout.js +1 -1
- package/tgsl/accessIndex.js +8 -14
- package/tgsl/accessProp.js +16 -29
- package/tgsl/consoleLog/serializers.js +1 -1
- package/tgsl/conversion.js +3 -3
- package/tgsl/forOfUtils.js +8 -5
- package/tgsl/generationHelpers.js +10 -11
- package/tgsl/infixDispatch.js +53 -0
- package/tgsl/shaderGenerator.d.ts +4 -1
- package/tgsl/shaderGenerator_members.d.ts +20 -2
- package/tgsl/shaderGenerator_members.js +5 -1
- package/tgsl/shellless.js +4 -4
- package/tgsl/wgslGenerator.d.ts +15 -11
- package/tgsl/wgslGenerator.js +173 -96
- package/types.d.ts +6 -4
- package/wgslExtensions.d.ts +3 -3
- package/wgslExtensions.js +3 -3
package/bin.mjs
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import pkg from './package.json' with { type: 'json' };
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Used to extract the version of `typegpu` that was used to
|
|
7
|
+
* trigger the CLI, which then allows us to download the latest
|
|
8
|
+
* version matching the major and minor of the `typegpu` package.
|
|
9
|
+
*/
|
|
10
|
+
const versionPattern = /^(\d+)\.(\d+)\.(\d+)/;
|
|
11
|
+
|
|
12
|
+
const result = versionPattern.exec(pkg.version);
|
|
13
|
+
const [_, major, minor] = result;
|
|
14
|
+
|
|
15
|
+
if (major === undefined || minor === undefined) {
|
|
16
|
+
throw new Error(`TypeGPU version doesn't match the expected major.minor.patch format`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Targeting the latest version with the same major and minor as `typegpu`
|
|
21
|
+
*/
|
|
22
|
+
const semver = `^${major}.${minor}.0`;
|
|
23
|
+
|
|
24
|
+
function asyncSpawn(...args) {
|
|
25
|
+
return new Promise((resolve, _reject) => {
|
|
26
|
+
const child = spawn(...args);
|
|
27
|
+
|
|
28
|
+
child.on('exit', (code, signal) => {
|
|
29
|
+
if (signal) {
|
|
30
|
+
process.kill(process.pid, signal);
|
|
31
|
+
process.exit(0);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
resolve(code);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
(async () => {
|
|
41
|
+
const code = await asyncSpawn('npx', [`@typegpu/cli@${semver}`, ...process.argv.slice(2)], {
|
|
42
|
+
stdio: ['inherit', 'inherit', 'ignore'],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (code !== 0) {
|
|
46
|
+
console.warn(
|
|
47
|
+
`Couldn't find @typegpu/cli version matching ${semver}, falling back to latest...`,
|
|
48
|
+
);
|
|
49
|
+
// Fallback to latest
|
|
50
|
+
const code = await asyncSpawn('npx', [`@typegpu/cli@latest`, ...process.argv.slice(2)], {
|
|
51
|
+
stdio: 'inherit',
|
|
52
|
+
});
|
|
53
|
+
process.exit(code ?? 0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
process.exit(code ?? 0);
|
|
57
|
+
})();
|
package/builtin.d.ts
CHANGED
|
@@ -13,7 +13,9 @@ type BuiltinSampleMask = Decorated<U32, [Builtin<'sample_mask'>]>;
|
|
|
13
13
|
type BuiltinLocalInvocationId = Decorated<Vec3u, [Builtin<'local_invocation_id'>]>;
|
|
14
14
|
type BuiltinLocalInvocationIndex = Decorated<U32, [Builtin<'local_invocation_index'>]>;
|
|
15
15
|
type BuiltinGlobalInvocationId = Decorated<Vec3u, [Builtin<'global_invocation_id'>]>;
|
|
16
|
+
type BuiltinGlobalInvocationIndex = Decorated<U32, [Builtin<'global_invocation_index'>]>;
|
|
16
17
|
type BuiltinWorkgroupId = Decorated<Vec3u, [Builtin<'workgroup_id'>]>;
|
|
18
|
+
type BuiltinWorkgroupIndex = Decorated<U32, [Builtin<'workgroup_index'>]>;
|
|
17
19
|
type BuiltinNumWorkgroups = Decorated<Vec3u, [Builtin<'num_workgroups'>]>;
|
|
18
20
|
type BuiltinSubgroupInvocationId = Decorated<U32, [Builtin<'subgroup_invocation_id'>]>;
|
|
19
21
|
type BuiltinSubgroupSize = Decorated<U32, [Builtin<'subgroup_size'>]>;
|
|
@@ -32,7 +34,9 @@ declare const builtin: {
|
|
|
32
34
|
readonly localInvocationId: BuiltinLocalInvocationId;
|
|
33
35
|
readonly localInvocationIndex: BuiltinLocalInvocationIndex;
|
|
34
36
|
readonly globalInvocationId: BuiltinGlobalInvocationId;
|
|
37
|
+
readonly globalInvocationIndex: BuiltinGlobalInvocationIndex;
|
|
35
38
|
readonly workgroupId: BuiltinWorkgroupId;
|
|
39
|
+
readonly workgroupIndex: BuiltinWorkgroupIndex;
|
|
36
40
|
readonly numWorkgroups: BuiltinNumWorkgroups;
|
|
37
41
|
readonly subgroupInvocationId: BuiltinSubgroupInvocationId;
|
|
38
42
|
readonly subgroupSize: BuiltinSubgroupSize;
|
|
@@ -40,7 +44,7 @@ declare const builtin: {
|
|
|
40
44
|
readonly numSubgroups: BuiltinNumSubgroups;
|
|
41
45
|
};
|
|
42
46
|
type AnyBuiltin = (typeof builtin)[keyof typeof builtin];
|
|
43
|
-
type AnyComputeBuiltin = BuiltinLocalInvocationId | BuiltinLocalInvocationIndex | BuiltinGlobalInvocationId | BuiltinWorkgroupId | BuiltinNumWorkgroups | BuiltinSubgroupInvocationId | BuiltinSubgroupSize | BuiltinSubgroupId | BuiltinNumSubgroups;
|
|
47
|
+
type AnyComputeBuiltin = BuiltinLocalInvocationId | BuiltinLocalInvocationIndex | BuiltinGlobalInvocationId | BuiltinGlobalInvocationIndex | BuiltinWorkgroupId | BuiltinWorkgroupIndex | BuiltinNumWorkgroups | BuiltinSubgroupInvocationId | BuiltinSubgroupSize | BuiltinSubgroupId | BuiltinNumSubgroups;
|
|
44
48
|
type AnyVertexInputBuiltin = BuiltinVertexIndex | BuiltinInstanceIndex;
|
|
45
49
|
type AnyVertexOutputBuiltin = BuiltinClipDistances | BuiltinPosition;
|
|
46
50
|
type AnyFragmentInputBuiltin = BuiltinPosition | BuiltinFrontFacing | BuiltinPrimitiveIndex | BuiltinSampleIndex | BuiltinSampleMask | BuiltinSubgroupInvocationId | BuiltinSubgroupSize;
|
package/builtin.js
CHANGED
|
@@ -25,7 +25,9 @@ const builtin = {
|
|
|
25
25
|
localInvocationId: defineBuiltin(vec3u, "local_invocation_id"),
|
|
26
26
|
localInvocationIndex: defineBuiltin(u32, "local_invocation_index"),
|
|
27
27
|
globalInvocationId: defineBuiltin(vec3u, "global_invocation_id"),
|
|
28
|
+
globalInvocationIndex: defineBuiltin(u32, "global_invocation_index"),
|
|
28
29
|
workgroupId: defineBuiltin(vec3u, "workgroup_id"),
|
|
30
|
+
workgroupIndex: defineBuiltin(u32, "workgroup_index"),
|
|
29
31
|
numWorkgroups: defineBuiltin(vec3u, "num_workgroups"),
|
|
30
32
|
subgroupInvocationId: defineBuiltin(u32, "subgroup_invocation_id"),
|
|
31
33
|
subgroupSize: defineBuiltin(u32, "subgroup_size"),
|
package/core/buffer/buffer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $internal } from "../../shared/symbols.js";
|
|
2
|
-
import { getName, setName } from "../../shared/meta.js";
|
|
3
2
|
import { isWgslData } from "../../data/wgslTypes.js";
|
|
3
|
+
import { getName, setName } from "../../shared/meta.js";
|
|
4
4
|
import { isGPUBuffer } from "../../types.js";
|
|
5
5
|
import { sizeOf } from "../../data/sizeOf.js";
|
|
6
6
|
import { getCompiledWriter } from "../../data/compiledIO.js";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { $getNameForward, $gpuValueOf, $internal, $ownSnippet, $resolve } from "../../shared/symbols.js";
|
|
2
2
|
import { getName, setName } from "../../shared/meta.js";
|
|
3
|
-
import { isNaturallyEphemeral } from "../../data/wgslTypes.js";
|
|
4
3
|
import { snip } from "../../data/snippet.js";
|
|
5
4
|
import { IllegalBufferAccessError } from "../../errors.js";
|
|
6
5
|
import { getExecMode, inCodegenMode, isInsideTgpuFn } from "../../execMode.js";
|
|
@@ -13,11 +12,6 @@ import { isUsableAsStorage } from "../../extension.js";
|
|
|
13
12
|
function isUsableAsUniform(buffer) {
|
|
14
13
|
return !!buffer.usableAsUniform;
|
|
15
14
|
}
|
|
16
|
-
const usageToVarTemplateMap = {
|
|
17
|
-
uniform: "uniform",
|
|
18
|
-
mutable: "storage, read_write",
|
|
19
|
-
readonly: "storage, read"
|
|
20
|
-
};
|
|
21
15
|
var TgpuFixedBufferImpl = class {
|
|
22
16
|
resourceType = "buffer-usage";
|
|
23
17
|
usage;
|
|
@@ -41,9 +35,14 @@ var TgpuFixedBufferImpl = class {
|
|
|
41
35
|
storage: dataType,
|
|
42
36
|
access: this.usage
|
|
43
37
|
}, this.buffer);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
return ctx.gen.declareGlobalVar({
|
|
39
|
+
group,
|
|
40
|
+
binding,
|
|
41
|
+
scope: this.usage,
|
|
42
|
+
id,
|
|
43
|
+
dataType,
|
|
44
|
+
init: void 0
|
|
45
|
+
});
|
|
47
46
|
}
|
|
48
47
|
toString() {
|
|
49
48
|
return `${this.usage}:${getName(this) ?? "<unnamed>"}`;
|
|
@@ -54,7 +53,7 @@ var TgpuFixedBufferImpl = class {
|
|
|
54
53
|
return new Proxy({
|
|
55
54
|
[$internal]: true,
|
|
56
55
|
get [$ownSnippet]() {
|
|
57
|
-
return snip(this, dataType,
|
|
56
|
+
return snip(this, dataType, usage);
|
|
58
57
|
},
|
|
59
58
|
[$resolve]: (ctx) => ctx.resolve(this),
|
|
60
59
|
toString: () => `${this.usage}:${getName(this) ?? "<unnamed>"}.$`
|
|
@@ -105,9 +104,14 @@ var TgpuLaidOutBufferImpl = class {
|
|
|
105
104
|
[$resolve](ctx) {
|
|
106
105
|
const id = ctx.makeUniqueIdentifier(getName(this), "global");
|
|
107
106
|
const group = ctx.allocateLayoutEntry(this.#membership.layout);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
return ctx.gen.declareGlobalVar({
|
|
108
|
+
group,
|
|
109
|
+
binding: this.#membership.idx,
|
|
110
|
+
scope: this.usage,
|
|
111
|
+
id,
|
|
112
|
+
dataType: this.dataType,
|
|
113
|
+
init: void 0
|
|
114
|
+
});
|
|
111
115
|
}
|
|
112
116
|
toString() {
|
|
113
117
|
return `${this.usage}:${getName(this) ?? "<unnamed>"}`;
|
|
@@ -118,7 +122,7 @@ var TgpuLaidOutBufferImpl = class {
|
|
|
118
122
|
return new Proxy({
|
|
119
123
|
[$internal]: true,
|
|
120
124
|
get [$ownSnippet]() {
|
|
121
|
-
return snip(this, schema,
|
|
125
|
+
return snip(this, schema, usage);
|
|
122
126
|
},
|
|
123
127
|
[$resolve]: (ctx) => ctx.resolve(this),
|
|
124
128
|
toString: () => `${this.usage}:${getName(this) ?? "<unnamed>"}.$`
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { $gpuValueOf, $internal, $ownSnippet, $resolve } from "../../shared/symbols.js";
|
|
2
2
|
import { getName, setName } from "../../shared/meta.js";
|
|
3
|
-
import { isNaturallyEphemeral } from "../../data/wgslTypes.js";
|
|
4
3
|
import { isData } from "../../data/dataTypes.js";
|
|
5
4
|
import { snip } from "../../data/snippet.js";
|
|
6
5
|
import { inCodegenMode } from "../../execMode.js";
|
|
@@ -38,10 +37,11 @@ var TgpuConstImpl = class {
|
|
|
38
37
|
}
|
|
39
38
|
[$resolve](ctx) {
|
|
40
39
|
const id = ctx.makeUniqueIdentifier(getName(this), "global");
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
return ctx.gen.declareGlobalConst({
|
|
41
|
+
id,
|
|
42
|
+
dataType: this.dataType,
|
|
43
|
+
init: snip(this.#value, this.dataType, "constant")
|
|
44
|
+
});
|
|
45
45
|
}
|
|
46
46
|
toString() {
|
|
47
47
|
return `const:${getName(this) ?? "<unnamed>"}`;
|
|
@@ -51,7 +51,7 @@ var TgpuConstImpl = class {
|
|
|
51
51
|
return new Proxy({
|
|
52
52
|
[$internal]: true,
|
|
53
53
|
get [$ownSnippet]() {
|
|
54
|
-
return snip(this, dataType,
|
|
54
|
+
return snip(this, dataType, "constant-immutable-def");
|
|
55
55
|
},
|
|
56
56
|
[$resolve]: (ctx) => ctx.resolve(this),
|
|
57
57
|
toString: () => `const:${getName(this) ?? "<unnamed>"}.$`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { $internal, $resolve } from "../../shared/symbols.js";
|
|
2
2
|
import { Void } from "../../data/wgslTypes.js";
|
|
3
3
|
import { snip } from "../../data/snippet.js";
|
|
4
|
-
import {
|
|
4
|
+
import { mergeExternals, replaceExternalsInWgsl } from "../resolve/externals.js";
|
|
5
5
|
|
|
6
6
|
//#region src/core/declare/tgpuDeclare.ts
|
|
7
7
|
/**
|
|
@@ -27,7 +27,7 @@ var TgpuDeclareImpl = class {
|
|
|
27
27
|
}
|
|
28
28
|
[$resolve](ctx) {
|
|
29
29
|
const externalMap = {};
|
|
30
|
-
for (const externals of this.#externalsToApply)
|
|
30
|
+
for (const externals of this.#externalsToApply) mergeExternals(externalMap, externals);
|
|
31
31
|
const replacedDeclaration = replaceExternalsInWgsl(ctx, externalMap, this.#declaration);
|
|
32
32
|
ctx.addDeclaration(replacedDeclaration);
|
|
33
33
|
return snip("", Void, "constant");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { $getNameForward, $gpuCallable, $internal } from "../../shared/symbols.js";
|
|
2
2
|
import { setName } from "../../shared/meta.js";
|
|
3
3
|
import { WgslTypeError } from "../../errors.js";
|
|
4
|
-
import { isKnownAtComptime } from "../../types.js";
|
|
4
|
+
import { NormalState, isKnownAtComptime } from "../../types.js";
|
|
5
5
|
import { coerceToSnippet } from "../../tgsl/generationHelpers.js";
|
|
6
6
|
|
|
7
7
|
//#region src/core/function/comptime.ts
|
|
@@ -35,9 +35,14 @@ function comptime(func) {
|
|
|
35
35
|
});
|
|
36
36
|
impl.toString = () => "comptime";
|
|
37
37
|
impl[$getNameForward] = func;
|
|
38
|
-
impl[$gpuCallable] = { call(
|
|
38
|
+
impl[$gpuCallable] = { call(ctx, args) {
|
|
39
39
|
if (!args.every((s) => isKnownAtComptime(s))) throw new WgslTypeError(`Called comptime function with runtime-known values: ${args.filter((s) => !isKnownAtComptime(s)).map((s) => `'${s.value}'`).join(", ")}`);
|
|
40
|
-
|
|
40
|
+
ctx.pushMode(new NormalState());
|
|
41
|
+
try {
|
|
42
|
+
return coerceToSnippet(func(...args.map((s) => s.value)));
|
|
43
|
+
} finally {
|
|
44
|
+
ctx.popMode();
|
|
45
|
+
}
|
|
41
46
|
} };
|
|
42
47
|
impl.$name = (label) => {
|
|
43
48
|
setName(func, label);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { $gpuCallable } from "../../shared/symbols.js";
|
|
2
|
-
import { setName } from "../../shared/meta.js";
|
|
3
2
|
import { isPtr } from "../../data/wgslTypes.js";
|
|
4
|
-
import {
|
|
3
|
+
import { setName } from "../../shared/meta.js";
|
|
4
|
+
import { noSideEffects, snip } from "../../data/snippet.js";
|
|
5
5
|
import { NormalState, isKnownAtComptime } from "../../types.js";
|
|
6
6
|
import { tryConvertSnippet } from "../../tgsl/conversion.js";
|
|
7
7
|
|
|
@@ -24,15 +24,17 @@ function callableSchema(options) {
|
|
|
24
24
|
if (!argType) throw new Error("Function called with invalid arguments");
|
|
25
25
|
return tryConvertSnippet(ctx, s, argType, false);
|
|
26
26
|
});
|
|
27
|
+
let result;
|
|
27
28
|
if (converted.every((s) => isKnownAtComptime(s))) {
|
|
28
29
|
ctx.pushMode(new NormalState());
|
|
29
30
|
try {
|
|
30
|
-
|
|
31
|
+
result = snip(options.normalImpl(...converted.map((s) => s.value)), options.schema(), "constant");
|
|
31
32
|
} finally {
|
|
32
33
|
ctx.popMode("normal");
|
|
33
34
|
}
|
|
34
|
-
}
|
|
35
|
-
|
|
35
|
+
} else result = options.codegenImpl(ctx, converted);
|
|
36
|
+
if (!args.some((a) => a.possibleSideEffects)) return noSideEffects(result);
|
|
37
|
+
return result;
|
|
36
38
|
}
|
|
37
39
|
};
|
|
38
40
|
return impl;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $gpuCallable } from "../../shared/symbols.js";
|
|
2
|
-
import { setName } from "../../shared/meta.js";
|
|
3
2
|
import { isPtr } from "../../data/wgslTypes.js";
|
|
3
|
+
import { setName } from "../../shared/meta.js";
|
|
4
4
|
import { snip } from "../../data/snippet.js";
|
|
5
5
|
import { NormalState, isKnownAtComptime } from "../../types.js";
|
|
6
6
|
import { tryConvertSnippet } from "../../tgsl/conversion.js";
|
|
@@ -18,7 +18,7 @@ function dualImpl(options) {
|
|
|
18
18
|
if (typeof options.normalImpl === "string") throw new MissingCpuImplError(options.normalImpl);
|
|
19
19
|
return options.normalImpl(...args);
|
|
20
20
|
});
|
|
21
|
-
setName(impl, options.name);
|
|
21
|
+
if (options.name) setName(impl, options.name);
|
|
22
22
|
impl.toString = () => options.name ?? "<unknown>";
|
|
23
23
|
impl[$gpuCallable] = {
|
|
24
24
|
get strictSignature() {
|
package/core/function/fnCore.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { $getNameForward } from "../../shared/symbols.js";
|
|
2
|
-
import { getMetaData, getName } from "../../shared/meta.js";
|
|
3
2
|
import { Void, isWgslData, isWgslStruct } from "../../data/wgslTypes.js";
|
|
3
|
+
import { getFunctionMetadata, getName } from "../../shared/meta.js";
|
|
4
4
|
import { undecorate } from "../../data/dataTypes.js";
|
|
5
5
|
import { snip } from "../../data/snippet.js";
|
|
6
|
-
import { MissingLinksError } from "../../errors.js";
|
|
7
6
|
import { getAttributesString } from "../../data/attributes.js";
|
|
8
7
|
import { validateIdentifier } from "../../nameUtils.js";
|
|
9
|
-
import {
|
|
8
|
+
import { mergeExternals, replaceExternalsInWgsl } from "../resolve/externals.js";
|
|
10
9
|
import { extractArgs } from "./extractArgs.js";
|
|
11
10
|
|
|
12
11
|
//#region src/core/function/fnCore.ts
|
|
@@ -29,7 +28,7 @@ function createFnCore(implementation, functionType, workgroupSize) {
|
|
|
29
28
|
if (functionType === "compute") attributes = `@compute @workgroup_size(${workgroupSize?.join(", ")}) `;
|
|
30
29
|
else if (functionType === "vertex") attributes = `@vertex `;
|
|
31
30
|
else if (functionType === "fragment") attributes = `@fragment `;
|
|
32
|
-
for (const externals of externalsToApply)
|
|
31
|
+
for (const externals of externalsToApply) mergeExternals(externalMap, externals);
|
|
33
32
|
const id = ctx.makeUniqueIdentifier(getName(this), "global");
|
|
34
33
|
if (typeof implementation === "string") {
|
|
35
34
|
if (!returnType) throw new Error("Explicit return type is required for string implementation");
|
|
@@ -38,7 +37,7 @@ function createFnCore(implementation, functionType, workgroupSize) {
|
|
|
38
37
|
const result = /* @__PURE__ */ validateIdentifier(arg.schemaKey);
|
|
39
38
|
if (!result.success) throw new Error(`Invalid argument name "${arg.schemaKey}"${result.error ? `: ${result.error}` : ""}`);
|
|
40
39
|
}
|
|
41
|
-
|
|
40
|
+
mergeExternals(externalMap, { in: Object.fromEntries(entryInput.positionalArgs.map((a) => [a.schemaKey, a.schemaKey])) });
|
|
42
41
|
}
|
|
43
42
|
const replacedImpl = replaceExternalsInWgsl(ctx, externalMap, implementation);
|
|
44
43
|
let header = "";
|
|
@@ -64,17 +63,17 @@ function createFnCore(implementation, functionType, workgroupSize) {
|
|
|
64
63
|
ctx.addDeclaration(`${attributes}fn ${id}${header}${body}`);
|
|
65
64
|
return snip(id, returnType, "runtime");
|
|
66
65
|
}
|
|
67
|
-
const pluginData =
|
|
68
|
-
const pluginExternals =
|
|
69
|
-
if (pluginExternals)
|
|
66
|
+
const pluginData = getFunctionMetadata(implementation);
|
|
67
|
+
const pluginExternals = pluginData?.externals();
|
|
68
|
+
if (pluginExternals) mergeExternals(externalMap, Object.fromEntries(Object.entries(pluginExternals).filter(([name]) => !(name in externalMap))));
|
|
70
69
|
const ast = pluginData?.ast;
|
|
71
70
|
if (!ast) throw new Error("Missing metadata for tgpu.fn function body (either missing 'use gpu' directive, or misconfigured `unplugin-typegpu`)");
|
|
72
|
-
const missingExternals = ast.externalNames.filter((name) => !(name in externalMap));
|
|
73
|
-
if (missingExternals.length > 0) throw new MissingLinksError(getName(this), missingExternals);
|
|
74
71
|
const maybeSecondArg = ast.params[1];
|
|
75
|
-
if (maybeSecondArg && maybeSecondArg.type === "i" && functionType !== "normal")
|
|
76
|
-
const { code, returnType: actualReturnType } = ctx.
|
|
72
|
+
if (maybeSecondArg && maybeSecondArg.type === "i" && functionType !== "normal") mergeExternals(externalMap, { [maybeSecondArg.name]: undecorate(returnType) });
|
|
73
|
+
const { code, returnType: actualReturnType } = ctx.resolveFunction({
|
|
77
74
|
functionType,
|
|
75
|
+
name: id,
|
|
76
|
+
workgroupSize,
|
|
78
77
|
argTypes,
|
|
79
78
|
entryInput,
|
|
80
79
|
params: ast.params,
|
|
@@ -82,7 +81,7 @@ function createFnCore(implementation, functionType, workgroupSize) {
|
|
|
82
81
|
body: ast.body,
|
|
83
82
|
externalMap
|
|
84
83
|
});
|
|
85
|
-
ctx.addDeclaration(
|
|
84
|
+
ctx.addDeclaration(code);
|
|
86
85
|
return snip(id, actualReturnType, "runtime");
|
|
87
86
|
}
|
|
88
87
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
|
|
2
|
-
import { getName, setName } from "../../shared/meta.js";
|
|
3
2
|
import { Void } from "../../data/wgslTypes.js";
|
|
3
|
+
import { getName, setName } from "../../shared/meta.js";
|
|
4
4
|
import { separateBuiltins } from "./ioSchema.js";
|
|
5
5
|
import { createFnCore } from "./fnCore.js";
|
|
6
6
|
import { stripTemplate } from "./templateUtils.js";
|
package/core/function/tgpuFn.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $getNameForward, $internal, $providing, $resolve, isMarkedInternal } from "../../shared/symbols.js";
|
|
2
|
-
import { getName, setName } from "../../shared/meta.js";
|
|
3
2
|
import { Void } from "../../data/wgslTypes.js";
|
|
3
|
+
import { getName, setName } from "../../shared/meta.js";
|
|
4
4
|
import { ExecutionError } from "../../errors.js";
|
|
5
5
|
import { isAccessor, isMutableAccessor } from "../slot/slotTypes.js";
|
|
6
6
|
import { provideInsideTgpuFn } from "../../execMode.js";
|
|
@@ -157,7 +157,8 @@ function createGenericFn(inner, pairs) {
|
|
|
157
157
|
return inner(...args);
|
|
158
158
|
};
|
|
159
159
|
const genericFn = Object.assign(call, fnBase);
|
|
160
|
-
|
|
160
|
+
const innerName = getName(inner);
|
|
161
|
+
if (innerName) setName(genericFn, innerName);
|
|
161
162
|
Object.defineProperty(genericFn, "toString", { value() {
|
|
162
163
|
const fnLabel = getName(genericFn) ?? "<unnamed>";
|
|
163
164
|
if (pairs.length > 0) return `fn*:${fnLabel}[${pairs.map(stringifyPair).join(", ")}]`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
|
|
2
|
-
import { PERF, getName, setName } from "../../shared/meta.js";
|
|
3
2
|
import { Void } from "../../data/wgslTypes.js";
|
|
3
|
+
import { PERF, getName, setName } from "../../shared/meta.js";
|
|
4
4
|
import { snip } from "../../data/snippet.js";
|
|
5
5
|
import { isGPUBuffer } from "../../types.js";
|
|
6
6
|
import { isBindGroup } from "../../tgpuBindGroupLayout.js";
|
|
@@ -9,7 +9,7 @@ import { isGPUCommandEncoder, isGPUComputePassEncoder } from "./typeGuards.js";
|
|
|
9
9
|
import { namespace } from "../resolve/namespace.js";
|
|
10
10
|
import { applyBindGroups } from "./applyPipelineState.js";
|
|
11
11
|
import { logDataFromGPU } from "../../tgsl/consoleLog/deserializers.js";
|
|
12
|
-
import {
|
|
12
|
+
import { wgslEnableExtensionToFeatureName, wgslEnableExtensions } from "../../wgslExtensions.js";
|
|
13
13
|
import { resolveIndirectOffset } from "./pipelineUtils.js";
|
|
14
14
|
import { createWithPerformanceCallback, createWithTimestampWrites, setupTimestampWrites, triggerPerformanceCallback } from "./timeable.js";
|
|
15
15
|
|
|
@@ -172,7 +172,7 @@ var ComputePipelineCore = class {
|
|
|
172
172
|
unwrap() {
|
|
173
173
|
if (this._memo === void 0) {
|
|
174
174
|
const device = this.root.device;
|
|
175
|
-
const enableExtensions =
|
|
175
|
+
const enableExtensions = wgslEnableExtensions.filter((extension) => this.root.enabledFeatures.has(wgslEnableExtensionToFeatureName[extension]));
|
|
176
176
|
let resolutionResult;
|
|
177
177
|
let resolveMeasure;
|
|
178
178
|
const ns = namespace({ names: this.root.nameRegistrySetting });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
|
|
2
|
-
import { PERF, getName, setName } from "../../shared/meta.js";
|
|
3
2
|
import { Void, isWgslData } from "../../data/wgslTypes.js";
|
|
3
|
+
import { PERF, getName, setName } from "../../shared/meta.js";
|
|
4
4
|
import { getCustomLocation } from "../../data/dataTypes.js";
|
|
5
5
|
import { snip } from "../../data/snippet.js";
|
|
6
6
|
import { isGPUBuffer } from "../../types.js";
|
|
@@ -15,7 +15,7 @@ import { isGPUCommandEncoder, isGPURenderBundleEncoder, isGPURenderPassEncoder }
|
|
|
15
15
|
import { namespace } from "../resolve/namespace.js";
|
|
16
16
|
import { applyBindGroups, applyVertexBuffers } from "./applyPipelineState.js";
|
|
17
17
|
import { logDataFromGPU } from "../../tgsl/consoleLog/deserializers.js";
|
|
18
|
-
import {
|
|
18
|
+
import { wgslEnableExtensionToFeatureName, wgslEnableExtensions } from "../../wgslExtensions.js";
|
|
19
19
|
import { resolveIndirectOffset } from "./pipelineUtils.js";
|
|
20
20
|
import { createWithPerformanceCallback, createWithTimestampWrites, setupTimestampWrites, triggerPerformanceCallback } from "./timeable.js";
|
|
21
21
|
import { AutoFragmentFn, AutoVertexFn } from "../function/autoIO.js";
|
|
@@ -378,7 +378,7 @@ var RenderPipelineCore = class {
|
|
|
378
378
|
if (this._memo !== void 0) return this._memo;
|
|
379
379
|
const { root, descriptor: tgpuDescriptor } = this.options;
|
|
380
380
|
const device = root.device;
|
|
381
|
-
const enableExtensions =
|
|
381
|
+
const enableExtensions = wgslEnableExtensions.filter((extension) => root.enabledFeatures.has(wgslEnableExtensionToFeatureName[extension]));
|
|
382
382
|
let resolutionResult;
|
|
383
383
|
let resolveMeasure;
|
|
384
384
|
const ns = namespace({ names: root.nameRegistrySetting });
|
|
@@ -16,7 +16,7 @@ interface TgpuRawCodeSnippet<TDataType extends BaseData> {
|
|
|
16
16
|
readonly [$gpuValueOf]: InferGPU<TDataType>;
|
|
17
17
|
$uses(dependencyMap: Record<string, unknown>): this;
|
|
18
18
|
}
|
|
19
|
-
type RawCodeSnippetOrigin = Exclude<Origin, 'function' | '
|
|
19
|
+
type RawCodeSnippetOrigin = Exclude<Origin, 'function' | 'local-def' | 'argument' | 'constant-immutable-def' | 'runtime-immutable-def'>;
|
|
20
20
|
/**
|
|
21
21
|
* An advanced API that creates a typed shader expression which
|
|
22
22
|
* can be injected into the final shader bundle upon use.
|
|
@@ -2,7 +2,7 @@ import { $gpuValueOf, $internal, $ownSnippet, $resolve } from "../../shared/symb
|
|
|
2
2
|
import { snip } from "../../data/snippet.js";
|
|
3
3
|
import { inCodegenMode } from "../../execMode.js";
|
|
4
4
|
import { valueProxyHandler } from "../valueProxyUtils.js";
|
|
5
|
-
import {
|
|
5
|
+
import { mergeExternals, replaceExternalsInWgsl } from "../resolve/externals.js";
|
|
6
6
|
|
|
7
7
|
//#region src/core/rawCodeSnippet/tgpuRawCodeSnippet.ts
|
|
8
8
|
/**
|
|
@@ -65,7 +65,7 @@ var TgpuRawCodeSnippetImpl = class {
|
|
|
65
65
|
}
|
|
66
66
|
[$resolve](ctx) {
|
|
67
67
|
const externalMap = {};
|
|
68
|
-
for (const externals of this.#externalsToApply)
|
|
68
|
+
for (const externals of this.#externalsToApply) mergeExternals(externalMap, externals);
|
|
69
69
|
return snip(replaceExternalsInWgsl(ctx, externalMap, this.#expression), this.dataType, this.origin);
|
|
70
70
|
}
|
|
71
71
|
toString() {
|
|
@@ -4,7 +4,7 @@ import "../../types.js";
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* A key-value mapping where keys represent identifiers within shader code,
|
|
7
|
-
* and values can be any type that can be resolved to a code string.
|
|
7
|
+
* and values can either be another ExternalMap, or be any type that can be resolved to a code string.
|
|
8
8
|
*/
|
|
9
9
|
type ExternalMap = Record<string, unknown>;
|
|
10
10
|
//#endregion
|
|
@@ -1,32 +1,46 @@
|
|
|
1
|
-
import { getName, hasTinyestMetadata, setName } from "../../shared/meta.js";
|
|
2
1
|
import { isWgslStruct } from "../../data/wgslTypes.js";
|
|
2
|
+
import { getName, hasTinyestMetadata, setName } from "../../shared/meta.js";
|
|
3
3
|
import { isLooseData } from "../../data/dataTypes.js";
|
|
4
4
|
import { isWgsl } from "../../types.js";
|
|
5
5
|
|
|
6
6
|
//#region src/core/resolve/externals.ts
|
|
7
|
+
function isResolvable(value) {
|
|
8
|
+
return isWgsl(value) || isLooseData(value) || hasTinyestMetadata(value);
|
|
9
|
+
}
|
|
7
10
|
/**
|
|
8
|
-
* Merges two external maps into one.
|
|
11
|
+
* Merges two external maps into one.
|
|
9
12
|
* If the external value is a namable object, it is given a name if it does not already have one.
|
|
10
13
|
* @param existing - The existing external map.
|
|
11
14
|
* @param newExternals - The new external map.
|
|
15
|
+
*
|
|
16
|
+
* NOTE:
|
|
17
|
+
* This function attempts to avoid accidental reference modification
|
|
18
|
+
* by performing a shallow copy before each modification,
|
|
19
|
+
* but it cannot avoid `existing` modification.
|
|
20
|
+
* Make sure that `existing` is created internally, instead of being passed in by users.
|
|
12
21
|
*/
|
|
13
|
-
function
|
|
22
|
+
function mergeExternals(existing, newExternals) {
|
|
14
23
|
for (const [key, value] of Object.entries(newExternals)) {
|
|
15
|
-
existing[key]
|
|
24
|
+
const existingValue = existing[key];
|
|
25
|
+
if (existingValue !== null && typeof existingValue === "object" && value !== null && typeof value === "object" && !isResolvable(existingValue) && !isResolvable(value)) {
|
|
26
|
+
const copiedValue = { ...existingValue };
|
|
27
|
+
mergeExternals(copiedValue, value);
|
|
28
|
+
existing[key] = copiedValue;
|
|
29
|
+
} else existing[key] = value;
|
|
16
30
|
if (value && (typeof value === "object" || typeof value === "function") && getName(value) === void 0) setName(value, key);
|
|
17
31
|
}
|
|
18
32
|
}
|
|
19
|
-
function addArgTypesToExternals(implementation, argTypes, applyExternals
|
|
33
|
+
function addArgTypesToExternals(implementation, argTypes, applyExternals) {
|
|
20
34
|
const argTypeNames = [...implementation.matchAll(/:\s*(?<arg>.*?)\s*[,)]/g)].map((found) => found ? found[1] : void 0);
|
|
21
|
-
applyExternals
|
|
35
|
+
applyExternals(Object.fromEntries(argTypes.flatMap((argType, i) => {
|
|
22
36
|
const argTypeName = argTypeNames ? argTypeNames[i] : void 0;
|
|
23
37
|
return isWgslStruct(argType) && argTypeName !== void 0 ? [[argTypeName, argType]] : [];
|
|
24
38
|
})));
|
|
25
39
|
}
|
|
26
|
-
function addReturnTypeToExternals(implementation, returnType, applyExternals
|
|
40
|
+
function addReturnTypeToExternals(implementation, returnType, applyExternals) {
|
|
27
41
|
const matched = implementation.match(/->\s(?<output>[\w\d_]+)\s{/);
|
|
28
42
|
const outputName = matched ? matched[1]?.trim() : void 0;
|
|
29
|
-
if (isWgslStruct(returnType) && outputName && !/\s/g.test(outputName)) applyExternals
|
|
43
|
+
if (isWgslStruct(returnType) && outputName && !/\s/g.test(outputName)) applyExternals({ [outputName]: returnType });
|
|
30
44
|
}
|
|
31
45
|
function identifierRegex(name) {
|
|
32
46
|
return new RegExp(`(?<![\\w\\$_.])${name.replaceAll(".", "\\.").replaceAll("$", "\\$")}(?![\\w\\$_])`, "g");
|
|
@@ -44,7 +58,7 @@ function replaceExternalsInWgsl(ctx, externalMap, wgsl) {
|
|
|
44
58
|
return Object.entries(externalMap).reduce((acc, [externalName, external]) => {
|
|
45
59
|
const externalRegex = identifierRegex(externalName);
|
|
46
60
|
if (wgsl && externalName !== "Out" && externalName !== "in" && !externalRegex.test(wgsl)) console.warn(`The external '${externalName}' wasn't used in the resolved template.`);
|
|
47
|
-
if (
|
|
61
|
+
if (isResolvable(external)) return acc.replaceAll(externalRegex, ctx.resolve(external).value);
|
|
48
62
|
if (external !== null && typeof external === "object") {
|
|
49
63
|
const foundProperties = [...wgsl.matchAll(new RegExp(`${externalName.replaceAll(".", "\\.").replaceAll("$", "\\$")}\\.(?<prop>.*?)(?![\\w\\$_])`, "g"))].map((found) => found[1]);
|
|
50
64
|
return [...new Set(foundProperties)].reduce((innerAcc, prop) => prop && prop in external ? replaceExternalsInWgsl(ctx, { [`${externalName}.${prop}`]: external[prop] }, innerAcc) : innerAcc, acc);
|
|
@@ -55,4 +69,4 @@ function replaceExternalsInWgsl(ctx, externalMap, wgsl) {
|
|
|
55
69
|
}
|
|
56
70
|
|
|
57
71
|
//#endregion
|
|
58
|
-
export { addArgTypesToExternals, addReturnTypeToExternals,
|
|
72
|
+
export { addArgTypesToExternals, addReturnTypeToExternals, mergeExternals, replaceExternalsInWgsl };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ShaderGenerator } from "../../tgsl/shaderGenerator.js";
|
|
2
2
|
import { Configurable } from "../root/rootTypes.js";
|
|
3
|
-
import {
|
|
3
|
+
import { WgslEnableExtension } from "../../wgslExtensions.js";
|
|
4
4
|
import { ResolvableObject, Wgsl } from "../../types.js";
|
|
5
5
|
import { Namespace } from "./namespace.js";
|
|
6
6
|
import { ResolutionResult } from "../../resolutionCtx.js";
|
|
@@ -27,7 +27,7 @@ interface TgpuResolveOptions {
|
|
|
27
27
|
/**
|
|
28
28
|
* List of WGSL shader extensions to enable.
|
|
29
29
|
*/
|
|
30
|
-
enableExtensions?:
|
|
30
|
+
enableExtensions?: WgslEnableExtension[] | undefined;
|
|
31
31
|
/**
|
|
32
32
|
* **NOTE: This is an unstable API and may change in the future.**
|
|
33
33
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { $internal, $resolve } from "../../shared/symbols.js";
|
|
2
2
|
import { Void } from "../../data/wgslTypes.js";
|
|
3
3
|
import { snip } from "../../data/snippet.js";
|
|
4
|
-
import {
|
|
4
|
+
import { mergeExternals, replaceExternalsInWgsl } from "./externals.js";
|
|
5
5
|
import { isBindGroupLayout } from "../../tgpuBindGroupLayout.js";
|
|
6
6
|
import { resolve } from "../../resolutionCtx.js";
|
|
7
7
|
import { isPipeline } from "../pipeline/typeGuards.js";
|
|
@@ -20,7 +20,7 @@ function resolveFromTemplate(options) {
|
|
|
20
20
|
const { template, externals, unstable_shaderGenerator: shaderGenerator, names = "strict", config, enableExtensions } = options;
|
|
21
21
|
if (!template) console.warn("Calling resolve with an empty template is deprecated and will soon return an empty string. Consider using the 'tgpu.resolve(resolvableArray, options)' API instead.");
|
|
22
22
|
const dependencies = {};
|
|
23
|
-
|
|
23
|
+
mergeExternals(dependencies, externals ?? {});
|
|
24
24
|
return resolve({
|
|
25
25
|
[$internal]: true,
|
|
26
26
|
[$resolve](ctx) {
|
package/core/root/init.js
CHANGED
|
@@ -12,6 +12,7 @@ import { clearTextureUtilsCache } from "../texture/textureUtils.js";
|
|
|
12
12
|
import { INTERNAL_createTexture, isTexture, isTextureView } from "../texture/texture.js";
|
|
13
13
|
import { TgpuBindGroupImpl, isBindGroup, isBindGroupLayout } from "../../tgpuBindGroupLayout.js";
|
|
14
14
|
import { ceil } from "../../std/numeric.js";
|
|
15
|
+
import { allEq } from "../../std/boolean.js";
|
|
15
16
|
import { isComputePipeline, isRenderPipeline } from "../pipeline/typeGuards.js";
|
|
16
17
|
import { builtin } from "../../builtin.js";
|
|
17
18
|
import { INTERNAL_createQuerySet, isQuerySet } from "../querySet/querySet.js";
|
|
@@ -22,7 +23,6 @@ import { applyBindGroups, applyVertexBuffers } from "../pipeline/applyPipelineSt
|
|
|
22
23
|
import { INTERNAL_createComputePipeline } from "../pipeline/computePipeline.js";
|
|
23
24
|
import { isVertexLayout } from "../vertexLayout/vertexLayout.js";
|
|
24
25
|
import { INTERNAL_createRenderPipeline } from "../pipeline/renderPipeline.js";
|
|
25
|
-
import { allEq } from "../../std/boolean.js";
|
|
26
26
|
|
|
27
27
|
//#region src/core/root/init.ts
|
|
28
28
|
/**
|
package/core/slot/accessor.js
CHANGED
|
@@ -51,7 +51,7 @@ var AccessorBase = class {
|
|
|
51
51
|
if (isTgpuFn(value) || hasTinyestMetadata(value)) return ctx.withResetIndentLevel(() => snip(`${ctx.resolve(value).value}()`, this.schema, "runtime"));
|
|
52
52
|
ctx.pushMode(new NormalState());
|
|
53
53
|
try {
|
|
54
|
-
return snip(schemaCallWrapper(this.schema, value), this.schema, "constant");
|
|
54
|
+
return snip(schemaCallWrapper(this.schema, value), this.schema, "constant", false);
|
|
55
55
|
} finally {
|
|
56
56
|
ctx.popMode("normal");
|
|
57
57
|
}
|