@luma.gl/shadertools 9.2.6 → 9.3.0-alpha.11
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/dist/dist.dev.js +5388 -6438
- package/dist/dist.min.js +2264 -322
- package/dist/index.cjs +3601 -566
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/glsl-utils/shader-utils.js +4 -4
- package/dist/lib/glsl-utils/shader-utils.js.map +1 -1
- package/dist/lib/preprocessor/preprocessor.d.ts.map +1 -1
- package/dist/lib/preprocessor/preprocessor.js +35 -8
- package/dist/lib/preprocessor/preprocessor.js.map +1 -1
- package/dist/lib/shader-assembler.d.ts +10 -0
- package/dist/lib/shader-assembler.d.ts.map +1 -1
- package/dist/lib/shader-assembler.js +20 -3
- package/dist/lib/shader-assembler.js.map +1 -1
- package/dist/lib/shader-assembly/assemble-shaders.d.ts +23 -2
- package/dist/lib/shader-assembly/assemble-shaders.d.ts.map +1 -1
- package/dist/lib/shader-assembly/assemble-shaders.js +265 -12
- package/dist/lib/shader-assembly/assemble-shaders.js.map +1 -1
- package/dist/lib/shader-assembly/wgsl-binding-debug.d.ts +37 -0
- package/dist/lib/shader-assembly/wgsl-binding-debug.d.ts.map +1 -0
- package/dist/lib/shader-assembly/wgsl-binding-debug.js +144 -0
- package/dist/lib/shader-assembly/wgsl-binding-debug.js.map +1 -0
- package/dist/lib/shader-assembly/wgsl-binding-scan.d.ts +19 -0
- package/dist/lib/shader-assembly/wgsl-binding-scan.d.ts.map +1 -0
- package/dist/lib/shader-assembly/wgsl-binding-scan.js +151 -0
- package/dist/lib/shader-assembly/wgsl-binding-scan.js.map +1 -0
- package/dist/lib/shader-generator/glsl/generate-glsl.js +7 -4
- package/dist/lib/shader-generator/glsl/generate-glsl.js.map +1 -1
- package/dist/lib/shader-generator/wgsl/generate-wgsl.d.ts.map +1 -1
- package/dist/lib/shader-generator/wgsl/generate-wgsl.js +3 -0
- package/dist/lib/shader-generator/wgsl/generate-wgsl.js.map +1 -1
- package/dist/lib/shader-module/shader-module-uniform-layout.d.ts +91 -0
- package/dist/lib/shader-module/shader-module-uniform-layout.d.ts.map +1 -0
- package/dist/lib/shader-module/shader-module-uniform-layout.js +253 -0
- package/dist/lib/shader-module/shader-module-uniform-layout.js.map +1 -0
- package/dist/lib/shader-module/shader-module.d.ts +12 -6
- package/dist/lib/shader-module/shader-module.d.ts.map +1 -1
- package/dist/lib/shader-module/shader-module.js.map +1 -1
- package/dist/lib/utils/assert.d.ts.map +1 -1
- package/dist/lib/utils/assert.js +3 -1
- package/dist/lib/utils/assert.js.map +1 -1
- package/dist/lib/utils/uniform-types.d.ts +11 -7
- package/dist/lib/utils/uniform-types.d.ts.map +1 -1
- package/dist/modules/engine/picking/picking.d.ts +5 -2
- package/dist/modules/engine/picking/picking.d.ts.map +1 -1
- package/dist/modules/engine/picking/picking.js +5 -2
- package/dist/modules/engine/picking/picking.js.map +1 -1
- package/dist/modules/engine/project/project.d.ts +1 -1
- package/dist/modules/engine/project/project.js +1 -1
- package/dist/modules/engine/skin/skin.d.ts +30 -0
- package/dist/modules/engine/skin/skin.d.ts.map +1 -0
- package/dist/modules/engine/skin/skin.js +86 -0
- package/dist/modules/engine/skin/skin.js.map +1 -0
- package/dist/modules/lighting/gouraud-material/gouraud-material.d.ts +1 -0
- package/dist/modules/lighting/gouraud-material/gouraud-material.d.ts.map +1 -1
- package/dist/modules/lighting/gouraud-material/gouraud-material.js +3 -0
- package/dist/modules/lighting/gouraud-material/gouraud-material.js.map +1 -1
- package/dist/modules/lighting/ibl/ibl.d.ts +26 -0
- package/dist/modules/lighting/ibl/ibl.d.ts.map +1 -0
- package/dist/modules/lighting/ibl/ibl.js +33 -0
- package/dist/modules/lighting/ibl/ibl.js.map +1 -0
- package/dist/modules/lighting/lambert-material/lambert-material.d.ts +10 -0
- package/dist/modules/lighting/lambert-material/lambert-material.d.ts.map +1 -0
- package/dist/modules/lighting/lambert-material/lambert-material.js +33 -0
- package/dist/modules/lighting/lambert-material/lambert-material.js.map +1 -0
- package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.d.ts +3 -0
- package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.d.ts.map +1 -0
- package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.js +60 -0
- package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.js.map +1 -0
- package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.d.ts +2 -0
- package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.d.ts.map +1 -0
- package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.js +73 -0
- package/dist/modules/lighting/lambert-material/lambert-shaders-wgsl.js.map +1 -0
- package/dist/modules/lighting/lights/lighting-glsl.d.ts +1 -1
- package/dist/modules/lighting/lights/lighting-glsl.d.ts.map +1 -1
- package/dist/modules/lighting/lights/lighting-glsl.js +44 -38
- package/dist/modules/lighting/lights/lighting-glsl.js.map +1 -1
- package/dist/modules/lighting/lights/lighting-wgsl.d.ts +1 -1
- package/dist/modules/lighting/lights/lighting-wgsl.d.ts.map +1 -1
- package/dist/modules/lighting/lights/lighting-wgsl.js +46 -18
- package/dist/modules/lighting/lights/lighting-wgsl.js.map +1 -1
- package/dist/modules/lighting/lights/lighting.d.ts +104 -62
- package/dist/modules/lighting/lights/lighting.d.ts.map +1 -1
- package/dist/modules/lighting/lights/lighting.js +107 -68
- package/dist/modules/lighting/lights/lighting.js.map +1 -1
- package/dist/modules/lighting/no-material/dirlight.d.ts +8 -3
- package/dist/modules/lighting/no-material/dirlight.d.ts.map +1 -1
- package/dist/modules/lighting/no-material/dirlight.js +5 -3
- package/dist/modules/lighting/no-material/dirlight.js.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts +2 -2
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.js +694 -38
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.js.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts +2 -2
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js +956 -109
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material.d.ts +242 -43
- package/dist/modules/lighting/pbr-material/pbr-material.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material.js +178 -2
- package/dist/modules/lighting/pbr-material/pbr-material.js.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-projection.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-projection.js +14 -2
- package/dist/modules/lighting/pbr-material/pbr-projection.js.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-scene.d.ts +40 -0
- package/dist/modules/lighting/pbr-material/pbr-scene.d.ts.map +1 -0
- package/dist/modules/lighting/pbr-material/pbr-scene.js +67 -0
- package/dist/modules/lighting/pbr-material/pbr-scene.js.map +1 -0
- package/dist/modules/lighting/phong-material/phong-material.d.ts +1 -0
- package/dist/modules/lighting/phong-material/phong-material.d.ts.map +1 -1
- package/dist/modules/lighting/phong-material/phong-material.js +4 -0
- package/dist/modules/lighting/phong-material/phong-material.js.map +1 -1
- package/dist/modules/lighting/phong-material/phong-shaders-glsl.d.ts +2 -2
- package/dist/modules/lighting/phong-material/phong-shaders-glsl.d.ts.map +1 -1
- package/dist/modules/lighting/phong-material/phong-shaders-glsl.js +17 -6
- package/dist/modules/lighting/phong-material/phong-shaders-glsl.js.map +1 -1
- package/dist/modules/lighting/phong-material/phong-shaders-wgsl.d.ts +1 -40
- package/dist/modules/lighting/phong-material/phong-shaders-wgsl.d.ts.map +1 -1
- package/dist/modules/lighting/phong-material/phong-shaders-wgsl.js +71 -76
- package/dist/modules/lighting/phong-material/phong-shaders-wgsl.js.map +1 -1
- package/dist/modules/math/fp64/fp64-arithmetic-glsl.d.ts +1 -1
- package/dist/modules/math/fp64/fp64-arithmetic-glsl.d.ts.map +1 -1
- package/dist/modules/math/fp64/fp64-arithmetic-glsl.js +42 -11
- package/dist/modules/math/fp64/fp64-arithmetic-glsl.js.map +1 -1
- package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts +2 -0
- package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts.map +1 -0
- package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js +212 -0
- package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js.map +1 -0
- package/dist/modules/math/fp64/fp64.d.ts +1 -0
- package/dist/modules/math/fp64/fp64.d.ts.map +1 -1
- package/dist/modules/math/fp64/fp64.js +8 -2
- package/dist/modules/math/fp64/fp64.js.map +1 -1
- package/dist/modules/math/random/random.d.ts +1 -1
- package/dist/modules/math/random/random.d.ts.map +1 -1
- package/dist/modules/math/random/random.js +2 -3
- package/dist/modules/math/random/random.js.map +1 -1
- package/package.json +4 -5
- package/src/index.ts +37 -6
- package/src/lib/glsl-utils/shader-utils.ts +4 -4
- package/src/lib/preprocessor/preprocessor.ts +44 -8
- package/src/lib/shader-assembler.ts +25 -3
- package/src/lib/shader-assembly/assemble-shaders.ts +506 -13
- package/src/lib/shader-assembly/wgsl-binding-debug.ts +227 -0
- package/src/lib/shader-assembly/wgsl-binding-scan.ts +228 -0
- package/src/lib/shader-generator/glsl/generate-glsl.ts +11 -5
- package/src/lib/shader-generator/wgsl/generate-wgsl.ts +6 -0
- package/src/lib/shader-module/shader-module-uniform-layout.ts +420 -0
- package/src/lib/shader-module/shader-module.ts +17 -7
- package/src/lib/utils/assert.ts +3 -1
- package/src/lib/utils/uniform-types.ts +24 -9
- package/src/modules/engine/picking/picking.ts +5 -2
- package/src/modules/engine/project/project.ts +1 -1
- package/src/modules/engine/skin/skin.ts +114 -0
- package/src/modules/lighting/gouraud-material/gouraud-material.ts +4 -0
- package/src/modules/lighting/ibl/ibl.ts +44 -0
- package/src/modules/lighting/lambert-material/lambert-material.ts +42 -0
- package/src/modules/lighting/lambert-material/lambert-shaders-glsl.ts +61 -0
- package/src/modules/lighting/lambert-material/lambert-shaders-wgsl.ts +73 -0
- package/src/modules/lighting/lights/lighting-glsl.ts +44 -38
- package/src/modules/lighting/lights/lighting-wgsl.ts +46 -18
- package/src/modules/lighting/lights/lighting.ts +198 -99
- package/src/modules/lighting/no-material/dirlight.ts +5 -3
- package/src/modules/lighting/pbr-material/pbr-material-glsl.ts +694 -38
- package/src/modules/lighting/pbr-material/pbr-material-wgsl.ts +956 -109
- package/src/modules/lighting/pbr-material/pbr-material.ts +294 -7
- package/src/modules/lighting/pbr-material/pbr-projection.ts +15 -2
- package/src/modules/lighting/pbr-material/pbr-scene.ts +91 -0
- package/src/modules/lighting/phong-material/phong-material.ts +5 -0
- package/src/modules/lighting/phong-material/phong-shaders-glsl.ts +17 -6
- package/src/modules/lighting/phong-material/phong-shaders-wgsl.ts +71 -77
- package/src/modules/math/fp64/fp64-arithmetic-glsl.ts +42 -11
- package/src/modules/math/fp64/fp64-arithmetic-wgsl.ts +212 -0
- package/src/modules/math/fp64/fp64.ts +9 -3
- package/src/modules/math/random/random.ts +2 -3
- package/dist/lib/wgsl/get-shader-layout-wgsl.d.ts +0 -8
- package/dist/lib/wgsl/get-shader-layout-wgsl.d.ts.map +0 -1
- package/dist/lib/wgsl/get-shader-layout-wgsl.js +0 -95
- package/dist/lib/wgsl/get-shader-layout-wgsl.js.map +0 -1
- package/src/lib/wgsl/get-shader-layout-wgsl.ts +0 -105
|
@@ -8,13 +8,29 @@ import {getPlatformShaderDefines} from './platform-defines';
|
|
|
8
8
|
import {injectShader, DECLARATION_INJECT_MARKER} from './shader-injections';
|
|
9
9
|
import {transpileGLSLShader} from '../shader-transpiler/transpile-glsl-shader';
|
|
10
10
|
import {checkShaderModuleDeprecations} from '../shader-module/shader-module';
|
|
11
|
+
import {
|
|
12
|
+
validateShaderModuleUniformLayout,
|
|
13
|
+
warnIfGLSLUniformBlocksAreNotStd140
|
|
14
|
+
} from '../shader-module/shader-module-uniform-layout';
|
|
11
15
|
import type {ShaderInjection} from './shader-injections';
|
|
12
16
|
import type {ShaderModule} from '../shader-module/shader-module';
|
|
13
17
|
import {ShaderHook, normalizeShaderHooks, getShaderHooks} from './shader-hooks';
|
|
14
18
|
import {assert} from '../utils/assert';
|
|
15
19
|
import {getShaderInfo} from '../glsl-utils/get-shader-info';
|
|
20
|
+
import {getShaderBindingDebugRowsFromWGSL, type ShaderBindingDebugRow} from './wgsl-binding-debug';
|
|
21
|
+
import {
|
|
22
|
+
MODULE_WGSL_BINDING_DECLARATION_REGEXES,
|
|
23
|
+
WGSL_BINDING_DECLARATION_REGEXES,
|
|
24
|
+
WGSL_EXPLICIT_BINDING_DECLARATION_REGEXES,
|
|
25
|
+
getFirstWGSLAutoBindingDeclarationMatch,
|
|
26
|
+
getWGSLBindingDeclarationMatches,
|
|
27
|
+
hasWGSLAutoBinding,
|
|
28
|
+
replaceWGSLBindingDeclarationMatches,
|
|
29
|
+
type WGSLBindingDeclarationMatch
|
|
30
|
+
} from './wgsl-binding-scan';
|
|
16
31
|
|
|
17
32
|
const INJECT_SHADER_DECLARATIONS = `\n\n${DECLARATION_INJECT_MARKER}\n`;
|
|
33
|
+
const RESERVED_APPLICATION_GROUP_0_BINDING_LIMIT = 100;
|
|
18
34
|
|
|
19
35
|
/**
|
|
20
36
|
* Precision prologue to inject before functions are injected in shader
|
|
@@ -78,6 +94,8 @@ type AssembleStageOptions = {
|
|
|
78
94
|
prologue?: boolean;
|
|
79
95
|
/** logger object */
|
|
80
96
|
log?: any;
|
|
97
|
+
/** @internal Stable per-assembler WGSL binding assignments. */
|
|
98
|
+
_bindingRegistry?: Map<string, number>;
|
|
81
99
|
};
|
|
82
100
|
|
|
83
101
|
export type HookFunction = {hook: string; header: string; footer: string; signature?: string};
|
|
@@ -94,21 +112,28 @@ export function assembleWGSLShader(
|
|
|
94
112
|
options: AssembleShaderOptions & {
|
|
95
113
|
/** Single WGSL shader */
|
|
96
114
|
source: string;
|
|
115
|
+
/** @internal Stable per-assembler WGSL binding assignments. */
|
|
116
|
+
_bindingRegistry?: Map<string, number>;
|
|
97
117
|
}
|
|
98
118
|
): {
|
|
99
119
|
source: string;
|
|
100
120
|
getUniforms: GetUniformsFunc;
|
|
121
|
+
bindingAssignments: {moduleName: string; name: string; group: number; location: number}[];
|
|
122
|
+
bindingTable: ShaderBindingDebugRow[];
|
|
101
123
|
} {
|
|
102
124
|
const modules = getShaderModuleDependencies(options.modules || []);
|
|
125
|
+
const {source, bindingAssignments} = assembleShaderWGSL(options.platformInfo, {
|
|
126
|
+
...options,
|
|
127
|
+
source: options.source,
|
|
128
|
+
stage: 'vertex',
|
|
129
|
+
modules
|
|
130
|
+
});
|
|
103
131
|
|
|
104
132
|
return {
|
|
105
|
-
source
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
modules
|
|
110
|
-
}),
|
|
111
|
-
getUniforms: assembleGetUniforms(modules)
|
|
133
|
+
source,
|
|
134
|
+
getUniforms: assembleGetUniforms(modules),
|
|
135
|
+
bindingAssignments,
|
|
136
|
+
bindingTable: getShaderBindingDebugRowsFromWGSL(source, bindingAssignments)
|
|
112
137
|
};
|
|
113
138
|
}
|
|
114
139
|
|
|
@@ -155,7 +180,10 @@ export function assembleGLSLShaderPair(
|
|
|
155
180
|
* @param options
|
|
156
181
|
* @returns
|
|
157
182
|
*/
|
|
158
|
-
export function assembleShaderWGSL(
|
|
183
|
+
export function assembleShaderWGSL(
|
|
184
|
+
platformInfo: PlatformInfo,
|
|
185
|
+
options: AssembleStageOptions
|
|
186
|
+
): {source: string; bindingAssignments: WGSLBindingAssignment[]} {
|
|
159
187
|
const {
|
|
160
188
|
// id,
|
|
161
189
|
source,
|
|
@@ -226,12 +254,32 @@ export function assembleShaderWGSL(platformInfo: PlatformInfo, options: Assemble
|
|
|
226
254
|
|
|
227
255
|
// TODO - hack until shadertool modules support WebGPU
|
|
228
256
|
const modulesToInject = modules;
|
|
257
|
+
const applicationRelocation = relocateWGSLApplicationBindings(coreSource);
|
|
258
|
+
const usedBindingsByGroup = getUsedBindingsByGroupFromApplicationWGSL(
|
|
259
|
+
applicationRelocation.source
|
|
260
|
+
);
|
|
261
|
+
const reservedBindingKeysByGroup = reserveRegisteredModuleBindings(
|
|
262
|
+
modulesToInject,
|
|
263
|
+
options._bindingRegistry,
|
|
264
|
+
usedBindingsByGroup
|
|
265
|
+
);
|
|
266
|
+
const bindingAssignments: WGSLBindingAssignment[] = [];
|
|
229
267
|
|
|
230
268
|
for (const module of modulesToInject) {
|
|
231
269
|
if (log) {
|
|
232
270
|
checkShaderModuleDeprecations(module, coreSource, log);
|
|
233
271
|
}
|
|
234
|
-
const
|
|
272
|
+
const relocation = relocateWGSLModuleBindings(
|
|
273
|
+
getShaderModuleSource(module, 'wgsl', log),
|
|
274
|
+
module,
|
|
275
|
+
{
|
|
276
|
+
usedBindingsByGroup,
|
|
277
|
+
bindingRegistry: options._bindingRegistry,
|
|
278
|
+
reservedBindingKeysByGroup
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
bindingAssignments.push(...relocation.bindingAssignments);
|
|
282
|
+
const moduleSource = relocation.source;
|
|
235
283
|
// Add the module source, and a #define that declares it presence
|
|
236
284
|
assembledSource += moduleSource;
|
|
237
285
|
|
|
@@ -256,14 +304,17 @@ export function assembleShaderWGSL(platformInfo: PlatformInfo, options: Assemble
|
|
|
256
304
|
assembledSource = injectShader(assembledSource, stage, declInjections);
|
|
257
305
|
|
|
258
306
|
assembledSource += getShaderHooks(hookFunctionMap[stage], hookInjections);
|
|
307
|
+
assembledSource += formatWGSLBindingAssignmentComments(bindingAssignments);
|
|
259
308
|
|
|
260
309
|
// Add the version directive and actual source of this shader
|
|
261
|
-
assembledSource +=
|
|
310
|
+
assembledSource += applicationRelocation.source;
|
|
262
311
|
|
|
263
312
|
// Apply any requested shader injections
|
|
264
313
|
assembledSource = injectShader(assembledSource, stage, mainInjections);
|
|
265
314
|
|
|
266
|
-
|
|
315
|
+
assertNoUnresolvedAutoBindings(assembledSource);
|
|
316
|
+
|
|
317
|
+
return {source: assembledSource, bindingAssignments};
|
|
267
318
|
}
|
|
268
319
|
|
|
269
320
|
/**
|
|
@@ -379,7 +430,7 @@ ${getApplicationDefines(allDefines)}
|
|
|
379
430
|
if (log) {
|
|
380
431
|
checkShaderModuleDeprecations(module, coreSource, log);
|
|
381
432
|
}
|
|
382
|
-
const moduleSource = getShaderModuleSource(module, stage);
|
|
433
|
+
const moduleSource = getShaderModuleSource(module, stage, log);
|
|
383
434
|
// Add the module source, and a #define that declares it presence
|
|
384
435
|
assembledSource += moduleSource;
|
|
385
436
|
|
|
@@ -417,6 +468,10 @@ ${getApplicationDefines(allDefines)}
|
|
|
417
468
|
assembledSource = transpileGLSLShader(assembledSource, stage);
|
|
418
469
|
}
|
|
419
470
|
|
|
471
|
+
if (language === 'glsl') {
|
|
472
|
+
warnIfGLSLUniformBlocksAreNotStd140(assembledSource, stage, log);
|
|
473
|
+
}
|
|
474
|
+
|
|
420
475
|
return assembledSource.trim();
|
|
421
476
|
}
|
|
422
477
|
|
|
@@ -476,7 +531,8 @@ function getApplicationDefines(defines: Record<string, boolean> = {}): string {
|
|
|
476
531
|
/** Extracts the source code chunk for the specified shader type from the named shader module */
|
|
477
532
|
export function getShaderModuleSource(
|
|
478
533
|
module: ShaderModule,
|
|
479
|
-
stage: 'vertex' | 'fragment' | 'wgsl'
|
|
534
|
+
stage: 'vertex' | 'fragment' | 'wgsl',
|
|
535
|
+
log?: any
|
|
480
536
|
): string {
|
|
481
537
|
let moduleSource;
|
|
482
538
|
switch (stage) {
|
|
@@ -496,6 +552,9 @@ export function getShaderModuleSource(
|
|
|
496
552
|
if (!module.name) {
|
|
497
553
|
throw new Error('Shader module must have a name');
|
|
498
554
|
}
|
|
555
|
+
|
|
556
|
+
validateShaderModuleUniformLayout(module, stage, {log});
|
|
557
|
+
|
|
499
558
|
const moduleName = module.name.toUpperCase().replace(/[^0-9a-z]/gi, '_');
|
|
500
559
|
let source = `\
|
|
501
560
|
// ----- MODULE ${module.name} ---------------
|
|
@@ -508,6 +567,440 @@ export function getShaderModuleSource(
|
|
|
508
567
|
return source;
|
|
509
568
|
}
|
|
510
569
|
|
|
570
|
+
type BindingRelocationContext = {
|
|
571
|
+
usedBindingsByGroup: Map<number, Set<number>>;
|
|
572
|
+
bindingRegistry?: Map<string, number>;
|
|
573
|
+
reservedBindingKeysByGroup: Map<number, Map<number, string>>;
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
type WGSLBindingAssignment = {
|
|
577
|
+
moduleName: string;
|
|
578
|
+
name: string;
|
|
579
|
+
group: number;
|
|
580
|
+
location: number;
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
type WGSLApplicationRelocationState = {
|
|
584
|
+
sawSupportedBindingDeclaration: boolean;
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
type WGSLRelocationState = {
|
|
588
|
+
sawSupportedBindingDeclaration: boolean;
|
|
589
|
+
nextHintedBindingLocation: number | null;
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
type WGSLRelocationParams = {
|
|
593
|
+
module: ShaderModule;
|
|
594
|
+
context: BindingRelocationContext;
|
|
595
|
+
bindingAssignments: WGSLBindingAssignment[];
|
|
596
|
+
relocationState: WGSLRelocationState;
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
function getUsedBindingsByGroupFromApplicationWGSL(source: string): Map<number, Set<number>> {
|
|
600
|
+
const usedBindingsByGroup = new Map<number, Set<number>>();
|
|
601
|
+
|
|
602
|
+
for (const match of getWGSLBindingDeclarationMatches(
|
|
603
|
+
source,
|
|
604
|
+
WGSL_EXPLICIT_BINDING_DECLARATION_REGEXES
|
|
605
|
+
)) {
|
|
606
|
+
const location = Number(match.bindingToken);
|
|
607
|
+
const group = Number(match.groupToken);
|
|
608
|
+
|
|
609
|
+
validateApplicationWGSLBinding(group, location, match.name);
|
|
610
|
+
registerUsedBindingLocation(
|
|
611
|
+
usedBindingsByGroup,
|
|
612
|
+
group,
|
|
613
|
+
location,
|
|
614
|
+
`application binding "${match.name}"`
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
return usedBindingsByGroup;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function relocateWGSLApplicationBindings(source: string): {source: string} {
|
|
622
|
+
const declarationMatches = getWGSLBindingDeclarationMatches(
|
|
623
|
+
source,
|
|
624
|
+
WGSL_BINDING_DECLARATION_REGEXES
|
|
625
|
+
);
|
|
626
|
+
const usedBindingsByGroup = new Map<number, Set<number>>();
|
|
627
|
+
|
|
628
|
+
for (const declarationMatch of declarationMatches) {
|
|
629
|
+
if (declarationMatch.bindingToken === 'auto') {
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
const location = Number(declarationMatch.bindingToken);
|
|
634
|
+
const group = Number(declarationMatch.groupToken);
|
|
635
|
+
|
|
636
|
+
validateApplicationWGSLBinding(group, location, declarationMatch.name);
|
|
637
|
+
registerUsedBindingLocation(
|
|
638
|
+
usedBindingsByGroup,
|
|
639
|
+
group,
|
|
640
|
+
location,
|
|
641
|
+
`application binding "${declarationMatch.name}"`
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const relocationState: WGSLApplicationRelocationState = {
|
|
646
|
+
sawSupportedBindingDeclaration: declarationMatches.length > 0
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
const relocatedSource = replaceWGSLBindingDeclarationMatches(
|
|
650
|
+
source,
|
|
651
|
+
WGSL_BINDING_DECLARATION_REGEXES,
|
|
652
|
+
declarationMatch =>
|
|
653
|
+
relocateWGSLApplicationBindingMatch(declarationMatch, usedBindingsByGroup, relocationState)
|
|
654
|
+
);
|
|
655
|
+
|
|
656
|
+
if (hasWGSLAutoBinding(source) && !relocationState.sawSupportedBindingDeclaration) {
|
|
657
|
+
throw new Error(
|
|
658
|
+
'Unsupported @binding(auto) declaration form in application WGSL. ' +
|
|
659
|
+
'Use adjacent "@group(N)" and "@binding(auto)" decorators followed by a bindable "var" declaration.'
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
return {source: relocatedSource};
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function relocateWGSLModuleBindings(
|
|
667
|
+
moduleSource: string,
|
|
668
|
+
module: ShaderModule,
|
|
669
|
+
context: BindingRelocationContext
|
|
670
|
+
): {source: string; bindingAssignments: WGSLBindingAssignment[]} {
|
|
671
|
+
const bindingAssignments: WGSLBindingAssignment[] = [];
|
|
672
|
+
const declarationMatches = getWGSLBindingDeclarationMatches(
|
|
673
|
+
moduleSource,
|
|
674
|
+
MODULE_WGSL_BINDING_DECLARATION_REGEXES
|
|
675
|
+
);
|
|
676
|
+
const relocationState: WGSLRelocationState = {
|
|
677
|
+
sawSupportedBindingDeclaration: declarationMatches.length > 0,
|
|
678
|
+
nextHintedBindingLocation:
|
|
679
|
+
typeof module.firstBindingSlot === 'number' ? module.firstBindingSlot : null
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
const relocatedSource = replaceWGSLBindingDeclarationMatches(
|
|
683
|
+
moduleSource,
|
|
684
|
+
MODULE_WGSL_BINDING_DECLARATION_REGEXES,
|
|
685
|
+
declarationMatch =>
|
|
686
|
+
relocateWGSLModuleBindingMatch(declarationMatch, {
|
|
687
|
+
module,
|
|
688
|
+
context,
|
|
689
|
+
bindingAssignments,
|
|
690
|
+
relocationState
|
|
691
|
+
})
|
|
692
|
+
);
|
|
693
|
+
|
|
694
|
+
if (hasWGSLAutoBinding(moduleSource) && !relocationState.sawSupportedBindingDeclaration) {
|
|
695
|
+
throw new Error(
|
|
696
|
+
`Unsupported @binding(auto) declaration form in module "${module.name}". ` +
|
|
697
|
+
'Use adjacent "@group(N)" and "@binding(auto)" decorators followed by a bindable "var" declaration.'
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
return {source: relocatedSource, bindingAssignments};
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
function relocateWGSLModuleBindingMatch(
|
|
705
|
+
declarationMatch: WGSLBindingDeclarationMatch,
|
|
706
|
+
params: WGSLRelocationParams
|
|
707
|
+
): string {
|
|
708
|
+
const {module, context, bindingAssignments, relocationState} = params;
|
|
709
|
+
|
|
710
|
+
const {match, bindingToken, groupToken, name} = declarationMatch;
|
|
711
|
+
const group = Number(groupToken);
|
|
712
|
+
|
|
713
|
+
if (bindingToken === 'auto') {
|
|
714
|
+
const registryKey = getBindingRegistryKey(group, module.name, name);
|
|
715
|
+
const registryLocation = context.bindingRegistry?.get(registryKey);
|
|
716
|
+
const location =
|
|
717
|
+
registryLocation !== undefined
|
|
718
|
+
? registryLocation
|
|
719
|
+
: relocationState.nextHintedBindingLocation === null
|
|
720
|
+
? allocateAutoBindingLocation(group, context.usedBindingsByGroup)
|
|
721
|
+
: allocateAutoBindingLocation(
|
|
722
|
+
group,
|
|
723
|
+
context.usedBindingsByGroup,
|
|
724
|
+
relocationState.nextHintedBindingLocation
|
|
725
|
+
);
|
|
726
|
+
validateModuleWGSLBinding(module.name, group, location, name);
|
|
727
|
+
if (
|
|
728
|
+
registryLocation !== undefined &&
|
|
729
|
+
claimReservedBindingLocation(context.reservedBindingKeysByGroup, group, location, registryKey)
|
|
730
|
+
) {
|
|
731
|
+
bindingAssignments.push({moduleName: module.name, name, group, location});
|
|
732
|
+
return match.replace(/@binding\(\s*auto\s*\)/, `@binding(${location})`);
|
|
733
|
+
}
|
|
734
|
+
registerUsedBindingLocation(
|
|
735
|
+
context.usedBindingsByGroup,
|
|
736
|
+
group,
|
|
737
|
+
location,
|
|
738
|
+
`module "${module.name}" binding "${name}"`
|
|
739
|
+
);
|
|
740
|
+
context.bindingRegistry?.set(registryKey, location);
|
|
741
|
+
bindingAssignments.push({moduleName: module.name, name, group, location});
|
|
742
|
+
if (relocationState.nextHintedBindingLocation !== null && registryLocation === undefined) {
|
|
743
|
+
relocationState.nextHintedBindingLocation = location + 1;
|
|
744
|
+
}
|
|
745
|
+
return match.replace(/@binding\(\s*auto\s*\)/, `@binding(${location})`);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const location = Number(bindingToken);
|
|
749
|
+
validateModuleWGSLBinding(module.name, group, location, name);
|
|
750
|
+
registerUsedBindingLocation(
|
|
751
|
+
context.usedBindingsByGroup,
|
|
752
|
+
group,
|
|
753
|
+
location,
|
|
754
|
+
`module "${module.name}" binding "${name}"`
|
|
755
|
+
);
|
|
756
|
+
bindingAssignments.push({moduleName: module.name, name, group, location});
|
|
757
|
+
return match;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
function relocateWGSLApplicationBindingMatch(
|
|
761
|
+
declarationMatch: WGSLBindingDeclarationMatch,
|
|
762
|
+
usedBindingsByGroup: Map<number, Set<number>>,
|
|
763
|
+
relocationState: WGSLApplicationRelocationState
|
|
764
|
+
): string {
|
|
765
|
+
const {match, bindingToken, groupToken, name} = declarationMatch;
|
|
766
|
+
const group = Number(groupToken);
|
|
767
|
+
|
|
768
|
+
if (bindingToken === 'auto') {
|
|
769
|
+
const location = allocateApplicationAutoBindingLocation(group, usedBindingsByGroup);
|
|
770
|
+
validateApplicationWGSLBinding(group, location, name);
|
|
771
|
+
registerUsedBindingLocation(
|
|
772
|
+
usedBindingsByGroup,
|
|
773
|
+
group,
|
|
774
|
+
location,
|
|
775
|
+
`application binding "${name}"`
|
|
776
|
+
);
|
|
777
|
+
return match.replace(/@binding\(\s*auto\s*\)/, `@binding(${location})`);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
relocationState.sawSupportedBindingDeclaration = true;
|
|
781
|
+
return match;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
function reserveRegisteredModuleBindings(
|
|
785
|
+
modules: ShaderModule[],
|
|
786
|
+
bindingRegistry: Map<string, number> | undefined,
|
|
787
|
+
usedBindingsByGroup: Map<number, Set<number>>
|
|
788
|
+
): Map<number, Map<number, string>> {
|
|
789
|
+
const reservedBindingKeysByGroup = new Map<number, Map<number, string>>();
|
|
790
|
+
if (!bindingRegistry) {
|
|
791
|
+
return reservedBindingKeysByGroup;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
for (const module of modules) {
|
|
795
|
+
for (const binding of getModuleWGSLBindingDeclarations(module)) {
|
|
796
|
+
const registryKey = getBindingRegistryKey(binding.group, module.name, binding.name);
|
|
797
|
+
const location = bindingRegistry.get(registryKey);
|
|
798
|
+
if (location !== undefined) {
|
|
799
|
+
const reservedBindingKeys =
|
|
800
|
+
reservedBindingKeysByGroup.get(binding.group) || new Map<number, string>();
|
|
801
|
+
const existingReservation = reservedBindingKeys.get(location);
|
|
802
|
+
if (existingReservation && existingReservation !== registryKey) {
|
|
803
|
+
throw new Error(
|
|
804
|
+
`Duplicate WGSL binding reservation for modules "${existingReservation}" and "${registryKey}": group ${binding.group}, binding ${location}.`
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
registerUsedBindingLocation(
|
|
809
|
+
usedBindingsByGroup,
|
|
810
|
+
binding.group,
|
|
811
|
+
location,
|
|
812
|
+
`registered module binding "${registryKey}"`
|
|
813
|
+
);
|
|
814
|
+
reservedBindingKeys.set(location, registryKey);
|
|
815
|
+
reservedBindingKeysByGroup.set(binding.group, reservedBindingKeys);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
return reservedBindingKeysByGroup;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
function claimReservedBindingLocation(
|
|
824
|
+
reservedBindingKeysByGroup: Map<number, Map<number, string>>,
|
|
825
|
+
group: number,
|
|
826
|
+
location: number,
|
|
827
|
+
registryKey: string
|
|
828
|
+
): boolean {
|
|
829
|
+
const reservedBindingKeys = reservedBindingKeysByGroup.get(group);
|
|
830
|
+
if (!reservedBindingKeys) {
|
|
831
|
+
return false;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
const reservedKey = reservedBindingKeys.get(location);
|
|
835
|
+
if (!reservedKey) {
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
838
|
+
if (reservedKey !== registryKey) {
|
|
839
|
+
throw new Error(
|
|
840
|
+
`Registered module binding "${registryKey}" collided with "${reservedKey}": group ${group}, binding ${location}.`
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
return true;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function getModuleWGSLBindingDeclarations(module: ShaderModule): {name: string; group: number}[] {
|
|
847
|
+
const declarations: {name: string; group: number}[] = [];
|
|
848
|
+
const moduleSource = module.source || '';
|
|
849
|
+
|
|
850
|
+
for (const match of getWGSLBindingDeclarationMatches(
|
|
851
|
+
moduleSource,
|
|
852
|
+
MODULE_WGSL_BINDING_DECLARATION_REGEXES
|
|
853
|
+
)) {
|
|
854
|
+
declarations.push({
|
|
855
|
+
name: match.name,
|
|
856
|
+
group: Number(match.groupToken)
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
return declarations;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
function validateApplicationWGSLBinding(group: number, location: number, name: string): void {
|
|
864
|
+
if (group === 0 && location >= RESERVED_APPLICATION_GROUP_0_BINDING_LIMIT) {
|
|
865
|
+
throw new Error(
|
|
866
|
+
`Application binding "${name}" in group 0 uses reserved binding ${location}. ` +
|
|
867
|
+
`Application-owned explicit group-0 bindings must stay below ${RESERVED_APPLICATION_GROUP_0_BINDING_LIMIT}.`
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
function validateModuleWGSLBinding(
|
|
873
|
+
moduleName: string,
|
|
874
|
+
group: number,
|
|
875
|
+
location: number,
|
|
876
|
+
name: string
|
|
877
|
+
): void {
|
|
878
|
+
if (group === 0 && location < RESERVED_APPLICATION_GROUP_0_BINDING_LIMIT) {
|
|
879
|
+
throw new Error(
|
|
880
|
+
`Module "${moduleName}" binding "${name}" in group 0 uses reserved application binding ${location}. ` +
|
|
881
|
+
`Module-owned explicit group-0 bindings must be ${RESERVED_APPLICATION_GROUP_0_BINDING_LIMIT} or higher.`
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
function registerUsedBindingLocation(
|
|
887
|
+
usedBindingsByGroup: Map<number, Set<number>>,
|
|
888
|
+
group: number,
|
|
889
|
+
location: number,
|
|
890
|
+
label: string
|
|
891
|
+
): void {
|
|
892
|
+
const usedBindings = usedBindingsByGroup.get(group) || new Set<number>();
|
|
893
|
+
if (usedBindings.has(location)) {
|
|
894
|
+
throw new Error(
|
|
895
|
+
`Duplicate WGSL binding assignment for ${label}: group ${group}, binding ${location}.`
|
|
896
|
+
);
|
|
897
|
+
}
|
|
898
|
+
usedBindings.add(location);
|
|
899
|
+
usedBindingsByGroup.set(group, usedBindings);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
function allocateAutoBindingLocation(
|
|
903
|
+
group: number,
|
|
904
|
+
usedBindingsByGroup: Map<number, Set<number>>,
|
|
905
|
+
preferredBindingLocation?: number
|
|
906
|
+
): number {
|
|
907
|
+
const usedBindings = usedBindingsByGroup.get(group) || new Set<number>();
|
|
908
|
+
let nextBinding =
|
|
909
|
+
preferredBindingLocation ??
|
|
910
|
+
(group === 0
|
|
911
|
+
? RESERVED_APPLICATION_GROUP_0_BINDING_LIMIT
|
|
912
|
+
: usedBindings.size > 0
|
|
913
|
+
? Math.max(...usedBindings) + 1
|
|
914
|
+
: 0);
|
|
915
|
+
|
|
916
|
+
while (usedBindings.has(nextBinding)) {
|
|
917
|
+
nextBinding++;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
return nextBinding;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
function allocateApplicationAutoBindingLocation(
|
|
924
|
+
group: number,
|
|
925
|
+
usedBindingsByGroup: Map<number, Set<number>>
|
|
926
|
+
): number {
|
|
927
|
+
const usedBindings = usedBindingsByGroup.get(group) || new Set<number>();
|
|
928
|
+
let nextBinding = 0;
|
|
929
|
+
|
|
930
|
+
while (usedBindings.has(nextBinding)) {
|
|
931
|
+
nextBinding++;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
return nextBinding;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
function assertNoUnresolvedAutoBindings(source: string): void {
|
|
938
|
+
const unresolvedBinding = getFirstWGSLAutoBindingDeclarationMatch(
|
|
939
|
+
source,
|
|
940
|
+
MODULE_WGSL_BINDING_DECLARATION_REGEXES
|
|
941
|
+
);
|
|
942
|
+
if (!unresolvedBinding) {
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
const moduleName = getWGSLModuleNameAtIndex(source, unresolvedBinding.index);
|
|
947
|
+
if (moduleName) {
|
|
948
|
+
throw new Error(
|
|
949
|
+
`Unresolved @binding(auto) for module "${moduleName}" binding "${unresolvedBinding.name}" remained in assembled WGSL source.`
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
if (isInApplicationWGSLSection(source, unresolvedBinding.index)) {
|
|
954
|
+
throw new Error(
|
|
955
|
+
`Unresolved @binding(auto) for application binding "${unresolvedBinding.name}" remained in assembled WGSL source.`
|
|
956
|
+
);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
throw new Error(
|
|
960
|
+
`Unresolved @binding(auto) remained in assembled WGSL source near "${formatWGSLSourceSnippet(unresolvedBinding.match)}".`
|
|
961
|
+
);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
function formatWGSLBindingAssignmentComments(bindingAssignments: WGSLBindingAssignment[]): string {
|
|
965
|
+
if (bindingAssignments.length === 0) {
|
|
966
|
+
return '';
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
let source = '// ----- MODULE WGSL BINDING ASSIGNMENTS ---------------\n';
|
|
970
|
+
for (const bindingAssignment of bindingAssignments) {
|
|
971
|
+
source += `// ${bindingAssignment.moduleName}.${bindingAssignment.name} -> @group(${bindingAssignment.group}) @binding(${bindingAssignment.location})\n`;
|
|
972
|
+
}
|
|
973
|
+
source += '\n';
|
|
974
|
+
return source;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
function getBindingRegistryKey(group: number, moduleName: string, bindingName: string): string {
|
|
978
|
+
return `${group}:${moduleName}:${bindingName}`;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
function getWGSLModuleNameAtIndex(source: string, index: number): string | undefined {
|
|
982
|
+
const moduleHeaderRegex = /^\/\/ ----- MODULE ([^\n]+) ---------------$/gm;
|
|
983
|
+
let moduleName: string | undefined;
|
|
984
|
+
let match: RegExpExecArray | null;
|
|
985
|
+
|
|
986
|
+
match = moduleHeaderRegex.exec(source);
|
|
987
|
+
while (match && match.index <= index) {
|
|
988
|
+
moduleName = match[1];
|
|
989
|
+
match = moduleHeaderRegex.exec(source);
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
return moduleName;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
function isInApplicationWGSLSection(source: string, index: number): boolean {
|
|
996
|
+
const injectionMarkerIndex = source.indexOf(INJECT_SHADER_DECLARATIONS);
|
|
997
|
+
return injectionMarkerIndex >= 0 ? index > injectionMarkerIndex : true;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
function formatWGSLSourceSnippet(source: string): string {
|
|
1001
|
+
return source.replace(/\s+/g, ' ').trim();
|
|
1002
|
+
}
|
|
1003
|
+
|
|
511
1004
|
/*
|
|
512
1005
|
function getHookFunctions(
|
|
513
1006
|
hookFunctions: Record<string, HookFunction>,
|