@luma.gl/shadertools 9.3.0-alpha.8 → 9.3.0
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 +1020 -191
- package/dist/dist.min.js +440 -145
- package/dist/index.cjs +915 -173
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/color/normalize-byte-colors.d.ts +23 -0
- package/dist/lib/color/normalize-byte-colors.d.ts.map +1 -0
- package/dist/lib/color/normalize-byte-colors.js +42 -0
- package/dist/lib/color/normalize-byte-colors.js.map +1 -0
- package/dist/lib/glsl-utils/shader-utils.js +4 -4
- package/dist/lib/glsl-utils/shader-utils.js.map +1 -1
- package/dist/lib/shader-assembly/assemble-shaders.d.ts.map +1 -1
- package/dist/lib/shader-assembly/assemble-shaders.js +102 -49
- package/dist/lib/shader-assembly/assemble-shaders.js.map +1 -1
- package/dist/lib/shader-assembly/wgsl-binding-debug.d.ts.map +1 -1
- package/dist/lib/shader-assembly/wgsl-binding-debug.js +7 -3
- package/dist/lib/shader-assembly/wgsl-binding-debug.js.map +1 -1
- 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 +4 -4
- package/dist/lib/shader-generator/glsl/generate-glsl.js.map +1 -1
- package/dist/lib/shader-module/shader-module-uniform-layout.d.ts +69 -0
- package/dist/lib/shader-module/shader-module-uniform-layout.d.ts.map +1 -1
- package/dist/lib/shader-module/shader-module-uniform-layout.js +145 -4
- package/dist/lib/shader-module/shader-module-uniform-layout.js.map +1 -1
- package/dist/modules/color/float-colors.d.ts +26 -0
- package/dist/modules/color/float-colors.d.ts.map +1 -0
- package/dist/modules/color/float-colors.js +82 -0
- package/dist/modules/color/float-colors.js.map +1 -0
- package/dist/modules/engine/picking/picking.d.ts +8 -8
- package/dist/modules/engine/picking/picking.d.ts.map +1 -1
- package/dist/modules/engine/picking/picking.js +13 -15
- 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 +2 -2
- package/dist/modules/engine/skin/skin.d.ts.map +1 -1
- package/dist/modules/engine/skin/skin.js +1 -1
- 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 +6 -3
- package/dist/modules/lighting/gouraud-material/gouraud-material.js.map +1 -1
- package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.d.ts +2 -2
- package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.d.ts.map +1 -1
- package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.js +2 -2
- 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 +1 -1
- package/dist/modules/lighting/lights/lighting.d.ts +4 -2
- package/dist/modules/lighting/lights/lighting.d.ts.map +1 -1
- package/dist/modules/lighting/lights/lighting.js +17 -11
- package/dist/modules/lighting/lights/lighting.js.map +1 -1
- package/dist/modules/lighting/no-material/dirlight.d.ts +3 -3
- package/dist/modules/lighting/no-material/dirlight.d.ts.map +1 -1
- package/dist/modules/lighting/no-material/dirlight.js +2 -2
- 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 +138 -35
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.js.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js +139 -35
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material.d.ts +74 -6
- package/dist/modules/lighting/pbr-material/pbr-material.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material.js +70 -2
- package/dist/modules/lighting/pbr-material/pbr-material.js.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-projection.js +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 +6 -3
- 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 +2 -2
- 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 +1 -1
- package/package.json +2 -2
- package/src/index.ts +17 -1
- package/src/lib/color/normalize-byte-colors.ts +57 -0
- package/src/lib/glsl-utils/shader-utils.ts +4 -4
- package/src/lib/shader-assembly/assemble-shaders.ts +197 -69
- package/src/lib/shader-assembly/wgsl-binding-debug.ts +14 -3
- package/src/lib/shader-assembly/wgsl-binding-scan.ts +228 -0
- package/src/lib/shader-generator/glsl/generate-glsl.ts +4 -4
- package/src/lib/shader-module/shader-module-uniform-layout.ts +236 -10
- package/src/modules/color/float-colors.ts +99 -0
- package/src/modules/engine/picking/picking.ts +17 -19
- package/src/modules/engine/project/project.ts +1 -1
- package/src/modules/engine/skin/skin.ts +1 -1
- package/src/modules/lighting/gouraud-material/gouraud-material.ts +10 -3
- package/src/modules/lighting/lambert-material/lambert-shaders-glsl.ts +2 -2
- package/src/modules/lighting/lights/lighting-glsl.ts +1 -1
- package/src/modules/lighting/lights/lighting.ts +20 -11
- package/src/modules/lighting/no-material/dirlight.ts +2 -2
- package/src/modules/lighting/pbr-material/pbr-material-glsl.ts +138 -35
- package/src/modules/lighting/pbr-material/pbr-material-wgsl.ts +139 -35
- package/src/modules/lighting/pbr-material/pbr-material.ts +110 -3
- package/src/modules/lighting/pbr-material/pbr-projection.ts +1 -1
- package/src/modules/lighting/pbr-material/pbr-scene.ts +91 -0
- package/src/modules/lighting/phong-material/phong-material.ts +10 -3
- package/src/modules/lighting/phong-material/phong-shaders-glsl.ts +2 -2
- package/src/modules/math/fp64/fp64-arithmetic-glsl.ts +1 -1
|
@@ -8,23 +8,28 @@ 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 {
|
|
11
|
+
import {
|
|
12
|
+
validateShaderModuleUniformLayout,
|
|
13
|
+
warnIfGLSLUniformBlocksAreNotStd140
|
|
14
|
+
} from '../shader-module/shader-module-uniform-layout';
|
|
12
15
|
import type {ShaderInjection} from './shader-injections';
|
|
13
16
|
import type {ShaderModule} from '../shader-module/shader-module';
|
|
14
17
|
import {ShaderHook, normalizeShaderHooks, getShaderHooks} from './shader-hooks';
|
|
15
18
|
import {assert} from '../utils/assert';
|
|
16
19
|
import {getShaderInfo} from '../glsl-utils/get-shader-info';
|
|
17
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';
|
|
18
31
|
|
|
19
32
|
const INJECT_SHADER_DECLARATIONS = `\n\n${DECLARATION_INJECT_MARKER}\n`;
|
|
20
|
-
const MODULE_WGSL_BINDING_DECLARATION_REGEXES = [
|
|
21
|
-
/@binding\(\s*(auto|\d+)\s*\)\s*@group\(\s*(\d+)\s*\)\s*(var(?:<[^>]+>)?\s+([A-Za-z_][A-Za-z0-9_]*))/g,
|
|
22
|
-
/@group\(\s*(\d+)\s*\)\s*@binding\(\s*(auto|\d+)\s*\)\s*(var(?:<[^>]+>)?\s+([A-Za-z_][A-Za-z0-9_]*))/g
|
|
23
|
-
] as const;
|
|
24
|
-
const WGSL_BINDING_DECLARATION_REGEXES = [
|
|
25
|
-
/@binding\(\s*(\d+)\s*\)\s*@group\(\s*(\d+)\s*\)\s*(var(?:<[^>]+>)?\s+([A-Za-z_][A-Za-z0-9_]*))/g,
|
|
26
|
-
/@group\(\s*(\d+)\s*\)\s*@binding\(\s*(\d+)\s*\)\s*(var(?:<[^>]+>)?\s+([A-Za-z_][A-Za-z0-9_]*))/g
|
|
27
|
-
] as const;
|
|
28
33
|
const RESERVED_APPLICATION_GROUP_0_BINDING_LIMIT = 100;
|
|
29
34
|
|
|
30
35
|
/**
|
|
@@ -249,7 +254,10 @@ export function assembleShaderWGSL(
|
|
|
249
254
|
|
|
250
255
|
// TODO - hack until shadertool modules support WebGPU
|
|
251
256
|
const modulesToInject = modules;
|
|
252
|
-
const
|
|
257
|
+
const applicationRelocation = relocateWGSLApplicationBindings(coreSource);
|
|
258
|
+
const usedBindingsByGroup = getUsedBindingsByGroupFromApplicationWGSL(
|
|
259
|
+
applicationRelocation.source
|
|
260
|
+
);
|
|
253
261
|
const reservedBindingKeysByGroup = reserveRegisteredModuleBindings(
|
|
254
262
|
modulesToInject,
|
|
255
263
|
options._bindingRegistry,
|
|
@@ -299,7 +307,7 @@ export function assembleShaderWGSL(
|
|
|
299
307
|
assembledSource += formatWGSLBindingAssignmentComments(bindingAssignments);
|
|
300
308
|
|
|
301
309
|
// Add the version directive and actual source of this shader
|
|
302
|
-
assembledSource +=
|
|
310
|
+
assembledSource += applicationRelocation.source;
|
|
303
311
|
|
|
304
312
|
// Apply any requested shader injections
|
|
305
313
|
assembledSource = injectShader(assembledSource, stage, mainInjections);
|
|
@@ -460,6 +468,10 @@ ${getApplicationDefines(allDefines)}
|
|
|
460
468
|
assembledSource = transpileGLSLShader(assembledSource, stage);
|
|
461
469
|
}
|
|
462
470
|
|
|
471
|
+
if (language === 'glsl') {
|
|
472
|
+
warnIfGLSLUniformBlocksAreNotStd140(assembledSource, stage, log);
|
|
473
|
+
}
|
|
474
|
+
|
|
463
475
|
return assembledSource.trim();
|
|
464
476
|
}
|
|
465
477
|
|
|
@@ -568,13 +580,16 @@ type WGSLBindingAssignment = {
|
|
|
568
580
|
location: number;
|
|
569
581
|
};
|
|
570
582
|
|
|
583
|
+
type WGSLApplicationRelocationState = {
|
|
584
|
+
sawSupportedBindingDeclaration: boolean;
|
|
585
|
+
};
|
|
586
|
+
|
|
571
587
|
type WGSLRelocationState = {
|
|
572
588
|
sawSupportedBindingDeclaration: boolean;
|
|
573
589
|
nextHintedBindingLocation: number | null;
|
|
574
590
|
};
|
|
575
591
|
|
|
576
592
|
type WGSLRelocationParams = {
|
|
577
|
-
isBindingFirst: boolean;
|
|
578
593
|
module: ShaderModule;
|
|
579
594
|
context: BindingRelocationContext;
|
|
580
595
|
bindingAssignments: WGSLBindingAssignment[];
|
|
@@ -584,82 +599,115 @@ type WGSLRelocationParams = {
|
|
|
584
599
|
function getUsedBindingsByGroupFromApplicationWGSL(source: string): Map<number, Set<number>> {
|
|
585
600
|
const usedBindingsByGroup = new Map<number, Set<number>>();
|
|
586
601
|
|
|
587
|
-
for (const
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
`application binding "${name}"`
|
|
602
|
-
);
|
|
603
|
-
}
|
|
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
|
+
);
|
|
604
616
|
}
|
|
605
617
|
|
|
606
618
|
return usedBindingsByGroup;
|
|
607
619
|
}
|
|
608
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
|
+
|
|
609
666
|
function relocateWGSLModuleBindings(
|
|
610
667
|
moduleSource: string,
|
|
611
668
|
module: ShaderModule,
|
|
612
669
|
context: BindingRelocationContext
|
|
613
670
|
): {source: string; bindingAssignments: WGSLBindingAssignment[]} {
|
|
614
671
|
const bindingAssignments: WGSLBindingAssignment[] = [];
|
|
672
|
+
const declarationMatches = getWGSLBindingDeclarationMatches(
|
|
673
|
+
moduleSource,
|
|
674
|
+
MODULE_WGSL_BINDING_DECLARATION_REGEXES
|
|
675
|
+
);
|
|
615
676
|
const relocationState: WGSLRelocationState = {
|
|
616
|
-
sawSupportedBindingDeclaration:
|
|
677
|
+
sawSupportedBindingDeclaration: declarationMatches.length > 0,
|
|
617
678
|
nextHintedBindingLocation:
|
|
618
679
|
typeof module.firstBindingSlot === 'number' ? module.firstBindingSlot : null
|
|
619
680
|
};
|
|
620
681
|
|
|
621
|
-
|
|
682
|
+
const relocatedSource = replaceWGSLBindingDeclarationMatches(
|
|
622
683
|
moduleSource,
|
|
623
|
-
MODULE_WGSL_BINDING_DECLARATION_REGEXES
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
684
|
+
MODULE_WGSL_BINDING_DECLARATION_REGEXES,
|
|
685
|
+
declarationMatch =>
|
|
686
|
+
relocateWGSLModuleBindingMatch(declarationMatch, {
|
|
687
|
+
module,
|
|
688
|
+
context,
|
|
689
|
+
bindingAssignments,
|
|
690
|
+
relocationState
|
|
691
|
+
})
|
|
630
692
|
);
|
|
631
693
|
|
|
632
|
-
if (moduleSource
|
|
694
|
+
if (hasWGSLAutoBinding(moduleSource) && !relocationState.sawSupportedBindingDeclaration) {
|
|
633
695
|
throw new Error(
|
|
634
696
|
`Unsupported @binding(auto) declaration form in module "${module.name}". ` +
|
|
635
|
-
'Use "@group(N)
|
|
697
|
+
'Use adjacent "@group(N)" and "@binding(auto)" decorators followed by a bindable "var" declaration.'
|
|
636
698
|
);
|
|
637
699
|
}
|
|
638
700
|
|
|
639
701
|
return {source: relocatedSource, bindingAssignments};
|
|
640
702
|
}
|
|
641
703
|
|
|
642
|
-
function relocateWGSLModuleBindingsWithRegex(
|
|
643
|
-
source: string,
|
|
644
|
-
regex: RegExp,
|
|
645
|
-
params: WGSLRelocationParams
|
|
646
|
-
): string {
|
|
647
|
-
return source.replace(regex, (...replaceArguments) =>
|
|
648
|
-
relocateWGSLModuleBindingMatch(replaceArguments, params)
|
|
649
|
-
);
|
|
650
|
-
}
|
|
651
|
-
|
|
652
704
|
function relocateWGSLModuleBindingMatch(
|
|
653
|
-
|
|
705
|
+
declarationMatch: WGSLBindingDeclarationMatch,
|
|
654
706
|
params: WGSLRelocationParams
|
|
655
707
|
): string {
|
|
656
|
-
const {
|
|
657
|
-
relocationState.sawSupportedBindingDeclaration = true;
|
|
708
|
+
const {module, context, bindingAssignments, relocationState} = params;
|
|
658
709
|
|
|
659
|
-
const match
|
|
660
|
-
const bindingToken = replaceArguments[isBindingFirst ? 1 : 2] as string;
|
|
661
|
-
const groupToken = replaceArguments[isBindingFirst ? 2 : 1] as string;
|
|
662
|
-
const name = replaceArguments[4] as string;
|
|
710
|
+
const {match, bindingToken, groupToken, name} = declarationMatch;
|
|
663
711
|
const group = Number(groupToken);
|
|
664
712
|
|
|
665
713
|
if (bindingToken === 'auto') {
|
|
@@ -709,6 +757,30 @@ function relocateWGSLModuleBindingMatch(
|
|
|
709
757
|
return match;
|
|
710
758
|
}
|
|
711
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
|
+
|
|
712
784
|
function reserveRegisteredModuleBindings(
|
|
713
785
|
modules: ShaderModule[],
|
|
714
786
|
bindingRegistry: Map<string, number> | undefined,
|
|
@@ -775,16 +847,14 @@ function getModuleWGSLBindingDeclarations(module: ShaderModule): {name: string;
|
|
|
775
847
|
const declarations: {name: string; group: number}[] = [];
|
|
776
848
|
const moduleSource = module.source || '';
|
|
777
849
|
|
|
778
|
-
for (const
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
});
|
|
787
|
-
}
|
|
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
|
+
});
|
|
788
858
|
}
|
|
789
859
|
|
|
790
860
|
return declarations;
|
|
@@ -850,10 +920,45 @@ function allocateAutoBindingLocation(
|
|
|
850
920
|
return nextBinding;
|
|
851
921
|
}
|
|
852
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
|
+
|
|
853
937
|
function assertNoUnresolvedAutoBindings(source: string): void {
|
|
854
|
-
|
|
855
|
-
|
|
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
|
+
);
|
|
856
957
|
}
|
|
958
|
+
|
|
959
|
+
throw new Error(
|
|
960
|
+
`Unresolved @binding(auto) remained in assembled WGSL source near "${formatWGSLSourceSnippet(unresolvedBinding.match)}".`
|
|
961
|
+
);
|
|
857
962
|
}
|
|
858
963
|
|
|
859
964
|
function formatWGSLBindingAssignmentComments(bindingAssignments: WGSLBindingAssignment[]): string {
|
|
@@ -873,6 +978,29 @@ function getBindingRegistryKey(group: number, moduleName: string, bindingName: s
|
|
|
873
978
|
return `${group}:${moduleName}:${bindingName}`;
|
|
874
979
|
}
|
|
875
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
|
+
|
|
876
1004
|
/*
|
|
877
1005
|
function getHookFunctions(
|
|
878
1006
|
hookFunctions: Record<string, HookFunction>,
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
+
import {WGSL_BINDABLE_VARIABLE_PATTERN, maskWGSLComments} from './wgsl-binding-scan';
|
|
6
|
+
|
|
5
7
|
type ShaderBindingAssignment = {
|
|
6
8
|
moduleName: string;
|
|
7
9
|
name: string;
|
|
@@ -10,8 +12,14 @@ type ShaderBindingAssignment = {
|
|
|
10
12
|
};
|
|
11
13
|
|
|
12
14
|
const WGSL_BINDING_DEBUG_REGEXES = [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
new RegExp(
|
|
16
|
+
`@binding\\(\\s*(\\d+)\\s*\\)\\s*@group\\(\\s*(\\d+)\\s*\\)\\s*${WGSL_BINDABLE_VARIABLE_PATTERN}\\s*:\\s*([^;]+);`,
|
|
17
|
+
'g'
|
|
18
|
+
),
|
|
19
|
+
new RegExp(
|
|
20
|
+
`@group\\(\\s*(\\d+)\\s*\\)\\s*@binding\\(\\s*(\\d+)\\s*\\)\\s*${WGSL_BINDABLE_VARIABLE_PATTERN}\\s*:\\s*([^;]+);`,
|
|
21
|
+
'g'
|
|
22
|
+
)
|
|
15
23
|
] as const;
|
|
16
24
|
|
|
17
25
|
/** One debug row describing a WGSL binding in the assembled shader source. */
|
|
@@ -54,6 +62,7 @@ export function getShaderBindingDebugRowsFromWGSL(
|
|
|
54
62
|
source: string,
|
|
55
63
|
bindingAssignments: ShaderBindingAssignment[] = []
|
|
56
64
|
): ShaderBindingDebugRow[] {
|
|
65
|
+
const maskedSource = maskWGSLComments(source);
|
|
57
66
|
const assignmentMap = new Map<string, string>();
|
|
58
67
|
for (const bindingAssignment of bindingAssignments) {
|
|
59
68
|
assignmentMap.set(
|
|
@@ -70,7 +79,8 @@ export function getShaderBindingDebugRowsFromWGSL(
|
|
|
70
79
|
for (const regex of WGSL_BINDING_DEBUG_REGEXES) {
|
|
71
80
|
regex.lastIndex = 0;
|
|
72
81
|
let match: RegExpExecArray | null;
|
|
73
|
-
|
|
82
|
+
match = regex.exec(maskedSource);
|
|
83
|
+
while (match) {
|
|
74
84
|
const isBindingFirst = regex === WGSL_BINDING_DEBUG_REGEXES[0];
|
|
75
85
|
const binding = Number(match[isBindingFirst ? 1 : 2]);
|
|
76
86
|
const group = Number(match[isBindingFirst ? 2 : 1]);
|
|
@@ -90,6 +100,7 @@ export function getShaderBindingDebugRowsFromWGSL(
|
|
|
90
100
|
resourceType
|
|
91
101
|
})
|
|
92
102
|
);
|
|
103
|
+
match = regex.exec(maskedSource);
|
|
93
104
|
}
|
|
94
105
|
}
|
|
95
106
|
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
export const WGSL_BINDABLE_VARIABLE_PATTERN =
|
|
6
|
+
'(?:var<\\s*(uniform|storage(?:\\s*,\\s*[A-Za-z_][A-Za-z0-9_]*)?)\\s*>|var)\\s+([A-Za-z_][A-Za-z0-9_]*)';
|
|
7
|
+
const WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN = '\\s*';
|
|
8
|
+
|
|
9
|
+
export const MODULE_WGSL_BINDING_DECLARATION_REGEXES = [
|
|
10
|
+
new RegExp(
|
|
11
|
+
`@binding\\(\\s*(auto|\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}@group\\(\\s*(\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}${WGSL_BINDABLE_VARIABLE_PATTERN}`,
|
|
12
|
+
'g'
|
|
13
|
+
),
|
|
14
|
+
new RegExp(
|
|
15
|
+
`@group\\(\\s*(\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}@binding\\(\\s*(auto|\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}${WGSL_BINDABLE_VARIABLE_PATTERN}`,
|
|
16
|
+
'g'
|
|
17
|
+
)
|
|
18
|
+
] as const;
|
|
19
|
+
|
|
20
|
+
export const WGSL_BINDING_DECLARATION_REGEXES = [
|
|
21
|
+
new RegExp(
|
|
22
|
+
`@binding\\(\\s*(auto|\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}@group\\(\\s*(\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}${WGSL_BINDABLE_VARIABLE_PATTERN}`,
|
|
23
|
+
'g'
|
|
24
|
+
),
|
|
25
|
+
new RegExp(
|
|
26
|
+
`@group\\(\\s*(\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}@binding\\(\\s*(auto|\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}${WGSL_BINDABLE_VARIABLE_PATTERN}`,
|
|
27
|
+
'g'
|
|
28
|
+
)
|
|
29
|
+
] as const;
|
|
30
|
+
|
|
31
|
+
export const WGSL_EXPLICIT_BINDING_DECLARATION_REGEXES = [
|
|
32
|
+
new RegExp(
|
|
33
|
+
`@binding\\(\\s*(\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}@group\\(\\s*(\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}${WGSL_BINDABLE_VARIABLE_PATTERN}`,
|
|
34
|
+
'g'
|
|
35
|
+
),
|
|
36
|
+
new RegExp(
|
|
37
|
+
`@group\\(\\s*(\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}@binding\\(\\s*(\\d+)\\s*\\)${WGSL_BINDING_DECLARATION_SEPARATOR_PATTERN}${WGSL_BINDABLE_VARIABLE_PATTERN}`,
|
|
38
|
+
'g'
|
|
39
|
+
)
|
|
40
|
+
] as const;
|
|
41
|
+
|
|
42
|
+
const WGSL_AUTO_BINDING_DECLARATION_REGEXES = [
|
|
43
|
+
new RegExp(
|
|
44
|
+
`@binding\\(\\s*(auto)\\s*\\)\\s*@group\\(\\s*(\\d+)\\s*\\)\\s*${WGSL_BINDABLE_VARIABLE_PATTERN}`,
|
|
45
|
+
'g'
|
|
46
|
+
),
|
|
47
|
+
new RegExp(
|
|
48
|
+
`@group\\(\\s*(\\d+)\\s*\\)\\s*@binding\\(\\s*(auto)\\s*\\)\\s*${WGSL_BINDABLE_VARIABLE_PATTERN}`,
|
|
49
|
+
'g'
|
|
50
|
+
),
|
|
51
|
+
new RegExp(
|
|
52
|
+
`@binding\\(\\s*(auto)\\s*\\)\\s*@group\\(\\s*(\\d+)\\s*\\)(?:[\\s\\n\\r]*@[A-Za-z_][^\\n\\r]*)*[\\s\\n\\r]*${WGSL_BINDABLE_VARIABLE_PATTERN}`,
|
|
53
|
+
'g'
|
|
54
|
+
),
|
|
55
|
+
new RegExp(
|
|
56
|
+
`@group\\(\\s*(\\d+)\\s*\\)\\s*@binding\\(\\s*(auto)\\s*\\)(?:[\\s\\n\\r]*@[A-Za-z_][^\\n\\r]*)*[\\s\\n\\r]*${WGSL_BINDABLE_VARIABLE_PATTERN}`,
|
|
57
|
+
'g'
|
|
58
|
+
)
|
|
59
|
+
] as const;
|
|
60
|
+
|
|
61
|
+
export type WGSLBindingDeclarationMatch = {
|
|
62
|
+
match: string;
|
|
63
|
+
index: number;
|
|
64
|
+
length: number;
|
|
65
|
+
bindingToken: string;
|
|
66
|
+
groupToken: string;
|
|
67
|
+
accessDeclaration?: string;
|
|
68
|
+
name: string;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export function maskWGSLComments(source: string): string {
|
|
72
|
+
const maskedCharacters = source.split('');
|
|
73
|
+
let index = 0;
|
|
74
|
+
let blockCommentDepth = 0;
|
|
75
|
+
let inLineComment = false;
|
|
76
|
+
let inString = false;
|
|
77
|
+
let isEscaped = false;
|
|
78
|
+
|
|
79
|
+
while (index < source.length) {
|
|
80
|
+
const character = source[index];
|
|
81
|
+
const nextCharacter = source[index + 1];
|
|
82
|
+
|
|
83
|
+
if (inString) {
|
|
84
|
+
if (isEscaped) {
|
|
85
|
+
isEscaped = false;
|
|
86
|
+
} else if (character === '\\') {
|
|
87
|
+
isEscaped = true;
|
|
88
|
+
} else if (character === '"') {
|
|
89
|
+
inString = false;
|
|
90
|
+
}
|
|
91
|
+
index++;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (inLineComment) {
|
|
96
|
+
if (character === '\n' || character === '\r') {
|
|
97
|
+
inLineComment = false;
|
|
98
|
+
} else {
|
|
99
|
+
maskedCharacters[index] = ' ';
|
|
100
|
+
}
|
|
101
|
+
index++;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (blockCommentDepth > 0) {
|
|
106
|
+
if (character === '/' && nextCharacter === '*') {
|
|
107
|
+
maskedCharacters[index] = ' ';
|
|
108
|
+
maskedCharacters[index + 1] = ' ';
|
|
109
|
+
blockCommentDepth++;
|
|
110
|
+
index += 2;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (character === '*' && nextCharacter === '/') {
|
|
115
|
+
maskedCharacters[index] = ' ';
|
|
116
|
+
maskedCharacters[index + 1] = ' ';
|
|
117
|
+
blockCommentDepth--;
|
|
118
|
+
index += 2;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (character !== '\n' && character !== '\r') {
|
|
123
|
+
maskedCharacters[index] = ' ';
|
|
124
|
+
}
|
|
125
|
+
index++;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (character === '"') {
|
|
130
|
+
inString = true;
|
|
131
|
+
index++;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (character === '/' && nextCharacter === '/') {
|
|
136
|
+
maskedCharacters[index] = ' ';
|
|
137
|
+
maskedCharacters[index + 1] = ' ';
|
|
138
|
+
inLineComment = true;
|
|
139
|
+
index += 2;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (character === '/' && nextCharacter === '*') {
|
|
144
|
+
maskedCharacters[index] = ' ';
|
|
145
|
+
maskedCharacters[index + 1] = ' ';
|
|
146
|
+
blockCommentDepth = 1;
|
|
147
|
+
index += 2;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
index++;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return maskedCharacters.join('');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function getWGSLBindingDeclarationMatches(
|
|
158
|
+
source: string,
|
|
159
|
+
regexes: readonly RegExp[]
|
|
160
|
+
): WGSLBindingDeclarationMatch[] {
|
|
161
|
+
const maskedSource = maskWGSLComments(source);
|
|
162
|
+
const matches: WGSLBindingDeclarationMatch[] = [];
|
|
163
|
+
|
|
164
|
+
for (const regex of regexes) {
|
|
165
|
+
regex.lastIndex = 0;
|
|
166
|
+
let match: RegExpExecArray | null;
|
|
167
|
+
match = regex.exec(maskedSource);
|
|
168
|
+
while (match) {
|
|
169
|
+
const isBindingFirst = regex === regexes[0];
|
|
170
|
+
const index = match.index;
|
|
171
|
+
const length = match[0].length;
|
|
172
|
+
matches.push({
|
|
173
|
+
match: source.slice(index, index + length),
|
|
174
|
+
index,
|
|
175
|
+
length,
|
|
176
|
+
bindingToken: match[isBindingFirst ? 1 : 2],
|
|
177
|
+
groupToken: match[isBindingFirst ? 2 : 1],
|
|
178
|
+
accessDeclaration: match[3]?.trim(),
|
|
179
|
+
name: match[4]
|
|
180
|
+
});
|
|
181
|
+
match = regex.exec(maskedSource);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return matches.sort((left, right) => left.index - right.index);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function replaceWGSLBindingDeclarationMatches(
|
|
189
|
+
source: string,
|
|
190
|
+
regexes: readonly RegExp[],
|
|
191
|
+
replacer: (match: WGSLBindingDeclarationMatch) => string
|
|
192
|
+
): string {
|
|
193
|
+
const matches = getWGSLBindingDeclarationMatches(source, regexes);
|
|
194
|
+
if (!matches.length) {
|
|
195
|
+
return source;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let relocatedSource = '';
|
|
199
|
+
let lastIndex = 0;
|
|
200
|
+
|
|
201
|
+
for (const match of matches) {
|
|
202
|
+
relocatedSource += source.slice(lastIndex, match.index);
|
|
203
|
+
relocatedSource += replacer(match);
|
|
204
|
+
lastIndex = match.index + match.length;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
relocatedSource += source.slice(lastIndex);
|
|
208
|
+
return relocatedSource;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function hasWGSLAutoBinding(source: string): boolean {
|
|
212
|
+
return /@binding\(\s*auto\s*\)/.test(maskWGSLComments(source));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function getFirstWGSLAutoBindingDeclarationMatch(
|
|
216
|
+
source: string,
|
|
217
|
+
regexes: readonly RegExp[]
|
|
218
|
+
): WGSLBindingDeclarationMatch | undefined {
|
|
219
|
+
const autoBindingRegexes =
|
|
220
|
+
regexes === MODULE_WGSL_BINDING_DECLARATION_REGEXES ||
|
|
221
|
+
regexes === WGSL_BINDING_DECLARATION_REGEXES
|
|
222
|
+
? WGSL_AUTO_BINDING_DECLARATION_REGEXES
|
|
223
|
+
: regexes;
|
|
224
|
+
|
|
225
|
+
return getWGSLBindingDeclarationMatches(source, autoBindingRegexes).find(
|
|
226
|
+
declarationMatch => declarationMatch.bindingToken === 'auto'
|
|
227
|
+
);
|
|
228
|
+
}
|
|
@@ -21,11 +21,11 @@ function generateGLSLUniformDeclarations(
|
|
|
21
21
|
): string {
|
|
22
22
|
const glsl: string[] = [];
|
|
23
23
|
|
|
24
|
-
// => uniform UniformBlockName {
|
|
24
|
+
// => layout(std140) uniform UniformBlockName {
|
|
25
25
|
switch (options.uniforms) {
|
|
26
26
|
case 'scoped-interface-blocks':
|
|
27
27
|
case 'unscoped-interface-blocks':
|
|
28
|
-
glsl.push(`uniform ${capitalize(module.name)} {`);
|
|
28
|
+
glsl.push(`layout(std140) uniform ${capitalize(module.name)} {`);
|
|
29
29
|
break;
|
|
30
30
|
case 'uniforms':
|
|
31
31
|
// ignore
|
|
@@ -41,11 +41,11 @@ function generateGLSLUniformDeclarations(
|
|
|
41
41
|
const glslUniformType = getGLSLUniformType(uniformFormat as UniformFormat);
|
|
42
42
|
switch (options.uniforms) {
|
|
43
43
|
case 'scoped-interface-blocks':
|
|
44
|
-
// => uniform UniformBlockName {
|
|
44
|
+
// => layout(std140) uniform UniformBlockName {
|
|
45
45
|
glsl.push(` ${glslUniformType} ${uniformName};`);
|
|
46
46
|
break;
|
|
47
47
|
case 'unscoped-interface-blocks':
|
|
48
|
-
// => uniform UniformBlockName {
|
|
48
|
+
// => layout(std140) uniform UniformBlockName {
|
|
49
49
|
glsl.push(` ${glslUniformType} ${module.name}_${uniformName};`);
|
|
50
50
|
break;
|
|
51
51
|
case 'uniforms':
|