@luma.gl/shaders 10.0.0-alpha.6 → 10.0.0-alpha.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/dist/dist.dev.js +236 -141
- package/dist/dist.min.js +130 -125
- package/dist/glsl.cjs.map +1 -1
- package/dist/index.cjs.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/glsl-shader-assembler.cjs +1 -1
- package/dist/lib/glsl-shader-assembler.js +1 -1
- package/dist/lib/glsl-shader-assembler.js.map +1 -1
- package/dist/lib/preprocessor/preprocessor.cjs +21 -0
- package/dist/lib/preprocessor/preprocessor.js +21 -0
- package/dist/lib/preprocessor/preprocessor.js.map +1 -1
- package/dist/lib/shader-assembly/assemble-glsl-shaders.cjs +12 -20
- package/dist/lib/shader-assembly/assemble-glsl-shaders.d.ts +3 -2
- package/dist/lib/shader-assembly/assemble-glsl-shaders.d.ts.map +1 -1
- package/dist/lib/shader-assembly/assemble-glsl-shaders.js +13 -21
- package/dist/lib/shader-assembly/assemble-glsl-shaders.js.map +1 -1
- package/dist/lib/shader-assembly/assemble-wgsl-shaders.cjs +7 -7
- package/dist/lib/shader-assembly/assemble-wgsl-shaders.js +8 -8
- package/dist/lib/shader-assembly/assemble-wgsl-shaders.js.map +1 -1
- package/dist/lib/shader-assembly/shader-assembly-types.d.ts +11 -7
- package/dist/lib/shader-assembly/shader-assembly-types.d.ts.map +1 -1
- package/dist/lib/shader-assembly/shader-hooks.cjs +23 -4
- package/dist/lib/shader-assembly/shader-hooks.d.ts +1 -1
- package/dist/lib/shader-assembly/shader-hooks.d.ts.map +1 -1
- package/dist/lib/shader-assembly/shader-hooks.js +27 -4
- package/dist/lib/shader-assembly/shader-hooks.js.map +1 -1
- package/dist/lib/shader-assembly/shader-injections.d.ts +2 -0
- package/dist/lib/shader-assembly/shader-injections.d.ts.map +1 -1
- package/dist/lib/shader-assembly/shader-injections.js.map +1 -1
- package/dist/lib/shader-assembly/shader-plugin-varyings.cjs +39 -22
- package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts +5 -5
- package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts.map +1 -1
- package/dist/lib/shader-assembly/shader-plugin-varyings.js +45 -19
- package/dist/lib/shader-assembly/shader-plugin-varyings.js.map +1 -1
- package/dist/lib/shader-generator/glsl/generate-glsl.d.ts +1 -1
- package/dist/lib/shader-generator/glsl/generate-glsl.d.ts.map +1 -1
- package/dist/lib/shader-generator/wgsl/generate-wgsl.d.ts +1 -1
- package/dist/lib/shader-generator/wgsl/generate-wgsl.d.ts.map +1 -1
- package/dist/lib/shader-plugin.cjs +94 -34
- package/dist/lib/shader-plugin.d.ts +55 -37
- package/dist/lib/shader-plugin.d.ts.map +1 -1
- package/dist/lib/shader-plugin.js +103 -35
- package/dist/lib/shader-plugin.js.map +1 -1
- package/dist/lib/wgsl-shader-assembler.cjs +1 -1
- package/dist/lib/wgsl-shader-assembler.js +1 -1
- package/dist/lib/wgsl-shader-assembler.js.map +1 -1
- package/dist/modules/engine/clip/clip.cjs +20 -30
- package/dist/modules/engine/clip/clip.d.ts.map +1 -1
- package/dist/modules/engine/clip/clip.js +21 -31
- package/dist/modules/engine/clip/clip.js.map +1 -1
- package/dist/modules/engine/filter/filter.cjs +10 -18
- package/dist/modules/engine/filter/filter.d.ts.map +1 -1
- package/dist/modules/engine/filter/filter.js +10 -18
- package/dist/modules/engine/filter/filter.js.map +1 -1
- package/dist/modules/lighting/lights/lighting.d.ts +1 -1
- package/dist/modules/lighting/lights/lighting.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.cjs +2 -2
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.js +2 -2
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.cjs +2 -2
- 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 +2 -2
- package/dist/modules/lighting/pbr-material/pbr-material.d.ts +2 -2
- package/dist/modules/math/fp64/fp64.cjs +1 -1
- package/dist/modules/math/fp64/fp64.d.ts +1 -1
- package/dist/modules/math/fp64/fp64.d.ts.map +1 -1
- package/dist/modules/math/fp64/fp64.js +1 -1
- package/dist/modules/math/fp64/fp64.js.map +1 -1
- package/dist/types/texture-formats.d.ts +1 -1
- package/dist/types/texture-formats.d.ts.map +1 -1
- package/dist/types.cjs +27 -16
- package/dist/types.d.ts +7 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -7
- package/dist/types.js.map +1 -1
- package/dist/wgsl.cjs +20 -4
- package/dist/wgsl.cjs.map +1 -1
- package/dist/wgsl.d.ts +1 -1
- package/dist/wgsl.d.ts.map +1 -1
- package/dist/wgsl.js +1 -1
- package/dist/wgsl.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +5 -4
- package/src/lib/glsl-shader-assembler.ts +1 -1
- package/src/lib/preprocessor/preprocessor.ts +25 -0
- package/src/lib/shader-assembly/assemble-glsl-shaders.ts +19 -23
- package/src/lib/shader-assembly/assemble-wgsl-shaders.ts +9 -9
- package/src/lib/shader-assembly/shader-assembly-types.ts +11 -7
- package/src/lib/shader-assembly/shader-hooks.ts +33 -4
- package/src/lib/shader-assembly/shader-injections.ts +2 -0
- package/src/lib/shader-assembly/shader-plugin-varyings.ts +58 -27
- package/src/lib/shader-generator/glsl/generate-glsl.ts +1 -1
- package/src/lib/shader-generator/wgsl/generate-wgsl.ts +1 -1
- package/src/lib/shader-module/shader-module-dependencies.ts +1 -1
- package/src/lib/shader-plugin.ts +154 -77
- package/src/lib/wgsl-shader-assembler.ts +1 -1
- package/src/modules/engine/clip/clip.ts +21 -31
- package/src/modules/engine/filter/filter.ts +10 -18
- package/src/modules/lighting/lights/lighting.ts +1 -1
- package/src/modules/lighting/pbr-material/pbr-material-glsl.ts +2 -2
- package/src/modules/lighting/pbr-material/pbr-material-wgsl.ts +2 -2
- package/src/modules/math/fp64/fp64.ts +1 -1
- package/src/types/texture-formats.ts +2 -0
- package/src/types.ts +75 -7
- package/src/wgsl.ts +12 -1
package/src/index.ts
CHANGED
|
@@ -20,13 +20,14 @@ export {
|
|
|
20
20
|
export type {ShaderModule} from './lib/shader-module/shader-module';
|
|
21
21
|
export type {
|
|
22
22
|
ResolvedShaderPlugins,
|
|
23
|
-
|
|
23
|
+
ResolvedShaderPluginInterStageVariable,
|
|
24
24
|
ShaderPlugin,
|
|
25
|
+
ShaderPluginHook,
|
|
26
|
+
ShaderPluginTarget,
|
|
25
27
|
ShaderPluginInjection,
|
|
26
28
|
ShaderPluginInjectionTarget,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
ShaderPluginVariant
|
|
29
|
+
ShaderPluginInterStageVariable,
|
|
30
|
+
ShaderPluginInterStageVariableInterpolation
|
|
30
31
|
} from './lib/shader-plugin';
|
|
31
32
|
export type {
|
|
32
33
|
ShaderPass,
|
|
@@ -23,7 +23,7 @@ export class GLSLShaderAssembler extends ShaderAssembler {
|
|
|
23
23
|
modules: ShaderModule[];
|
|
24
24
|
} {
|
|
25
25
|
const modules = this._getModuleList(props.modules); // Combine with default modules
|
|
26
|
-
const hookFunctions = this._hookFunctions
|
|
26
|
+
const hookFunctions = [...this._hookFunctions, ...(props.hookFunctions || [])];
|
|
27
27
|
const vertex = this._transpileShader(props, modules, props.vs, 'vertex');
|
|
28
28
|
const fragment = this._transpileShader(props, modules, props.fs, 'fragment');
|
|
29
29
|
const assembled = assembleGLSLShaderPair({
|
|
@@ -104,6 +104,31 @@ function evaluateIfExpression(
|
|
|
104
104
|
return false;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
const operandPattern = '(?:[A-Za-z_][A-Za-z0-9_]*|[+-]?\\d+(?:\\.\\d+)?)';
|
|
108
|
+
const comparison = trimmedExpression.match(
|
|
109
|
+
new RegExp(`^(${operandPattern})\\s*(==|!=|<=|>=|<|>)\\s*(${operandPattern})$`)
|
|
110
|
+
);
|
|
111
|
+
if (comparison) {
|
|
112
|
+
const resolveOperand = (operand: string) =>
|
|
113
|
+
/^[A-Za-z_]/.test(operand) ? Number(defines[operand] ?? 0) : Number(operand);
|
|
114
|
+
const left = resolveOperand(comparison[1]);
|
|
115
|
+
const right = resolveOperand(comparison[3]);
|
|
116
|
+
switch (comparison[2]) {
|
|
117
|
+
case '==':
|
|
118
|
+
return left === right;
|
|
119
|
+
case '!=':
|
|
120
|
+
return left !== right;
|
|
121
|
+
case '<=':
|
|
122
|
+
return left <= right;
|
|
123
|
+
case '>=':
|
|
124
|
+
return left >= right;
|
|
125
|
+
case '<':
|
|
126
|
+
return left < right;
|
|
127
|
+
case '>':
|
|
128
|
+
return left > right;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
107
132
|
const negatedDefineMatch = trimmedExpression.match(new RegExp(`^!\\s*${DEFINE_NAME_PATTERN}$`));
|
|
108
133
|
if (negatedDefineMatch) {
|
|
109
134
|
return !Boolean(defines[negatedDefineMatch[1]]);
|
|
@@ -24,12 +24,12 @@ import {
|
|
|
24
24
|
} from './shader-hooks';
|
|
25
25
|
import {type ShaderInjection, injectShader} from './shader-injections';
|
|
26
26
|
import {type AttributeShaderType} from '../../types';
|
|
27
|
-
import {type
|
|
27
|
+
import {type ResolvedShaderPluginInterStageVariable} from '../shader-plugin';
|
|
28
28
|
import {assert} from '../utils/assert';
|
|
29
29
|
import {getShaderInfo} from '../glsl-utils/get-shader-info';
|
|
30
30
|
import {getPlatformShaderDefines} from './platform-defines';
|
|
31
31
|
import {getShaderPluginVertexInputDeclarationsGLSL} from './shader-plugin-vertex-inputs';
|
|
32
|
-
import {
|
|
32
|
+
import {assembleShaderPluginInterStageVariablesGLSL} from './shader-plugin-varyings';
|
|
33
33
|
import {transpileGLSLShader} from '../shader-transpiler/transpile-glsl-shader';
|
|
34
34
|
import {warnIfGLSLUniformBlocksAreNotStd140} from '../shader-module/shader-module-uniform-layout';
|
|
35
35
|
|
|
@@ -94,10 +94,11 @@ export function assembleShaderGLSL(
|
|
|
94
94
|
modules: ShaderModule[];
|
|
95
95
|
defines?: Record<string, boolean | number>;
|
|
96
96
|
hookFunctions?: readonly (ShaderHook | string)[];
|
|
97
|
+
pluginHooks?: readonly ShaderHook[];
|
|
97
98
|
inject?: Record<string, string | ShaderInjection>;
|
|
98
99
|
pluginInjections?: Record<string, ShaderInjection[]>;
|
|
99
100
|
pluginVertexInputs?: Record<string, AttributeShaderType>;
|
|
100
|
-
|
|
101
|
+
pluginInterStageVariables?: Record<string, ResolvedShaderPluginInterStageVariable>;
|
|
101
102
|
prologue?: boolean;
|
|
102
103
|
log?: ShaderAssemblyLog;
|
|
103
104
|
}
|
|
@@ -112,7 +113,7 @@ export function assembleShaderGLSL(
|
|
|
112
113
|
inject = {},
|
|
113
114
|
pluginInjections = {},
|
|
114
115
|
pluginVertexInputs = {},
|
|
115
|
-
|
|
116
|
+
pluginInterStageVariables = {},
|
|
116
117
|
prologue = true,
|
|
117
118
|
log
|
|
118
119
|
} = options;
|
|
@@ -163,7 +164,7 @@ ${getApplicationDefines(allDefines)}
|
|
|
163
164
|
break;
|
|
164
165
|
}
|
|
165
166
|
|
|
166
|
-
const hookFunctionMap = normalizeShaderHooks(hookFunctions);
|
|
167
|
+
const hookFunctionMap = normalizeShaderHooks(hookFunctions, options.pluginHooks, 'glsl');
|
|
167
168
|
|
|
168
169
|
// Add source of dependent modules in resolved order
|
|
169
170
|
const hookInjections: Record<string, ShaderInjection[]> = {};
|
|
@@ -181,36 +182,31 @@ ${getApplicationDefines(allDefines)}
|
|
|
181
182
|
const name = match[3];
|
|
182
183
|
if (hash) {
|
|
183
184
|
if (name === 'decl') {
|
|
184
|
-
declInjections[key] = [injection];
|
|
185
|
+
declInjections[key] = [...(declInjections[key] || []), injection];
|
|
185
186
|
} else {
|
|
186
|
-
mainInjections[key] = [injection];
|
|
187
|
+
mainInjections[key] = [...(mainInjections[key] || []), injection];
|
|
187
188
|
}
|
|
188
189
|
} else {
|
|
189
|
-
hookInjections[key] = [injection];
|
|
190
|
+
hookInjections[key] = [...(hookInjections[key] || []), injection];
|
|
190
191
|
}
|
|
191
192
|
} else {
|
|
192
193
|
// Regex injection
|
|
193
|
-
mainInjections[key] = [injection];
|
|
194
|
+
mainInjections[key] = [...(mainInjections[key] || []), injection];
|
|
194
195
|
}
|
|
195
196
|
}
|
|
197
|
+
// Module helpers may access plugin inputs and varyings. GLSL requires these
|
|
198
|
+
// interface declarations before the helpers, unlike ordinary #decl injections.
|
|
196
199
|
if (stage === 'vertex') {
|
|
197
200
|
const declarations = getShaderPluginVertexInputDeclarationsGLSL(coreSource, pluginVertexInputs);
|
|
198
|
-
if (declarations) {
|
|
199
|
-
declInjections['vs:#decl'] = declInjections['vs:#decl'] || [];
|
|
200
|
-
declInjections['vs:#decl'].push({
|
|
201
|
-
injection: declarations,
|
|
202
|
-
order: Number.MIN_SAFE_INTEGER
|
|
203
|
-
});
|
|
204
|
-
}
|
|
201
|
+
if (declarations) assembledSource += `${declarations}\n`;
|
|
205
202
|
}
|
|
206
|
-
const pluginVaryingAssembly =
|
|
203
|
+
const pluginVaryingAssembly = assembleShaderPluginInterStageVariablesGLSL(
|
|
204
|
+
coreSource,
|
|
205
|
+
stage,
|
|
206
|
+
pluginInterStageVariables
|
|
207
|
+
);
|
|
207
208
|
if (pluginVaryingAssembly.declarations) {
|
|
208
|
-
|
|
209
|
-
declInjections[declarationTarget] = declInjections[declarationTarget] || [];
|
|
210
|
-
declInjections[declarationTarget].push({
|
|
211
|
-
injection: pluginVaryingAssembly.declarations,
|
|
212
|
-
order: Number.MIN_SAFE_INTEGER
|
|
213
|
-
});
|
|
209
|
+
assembledSource += `${pluginVaryingAssembly.declarations}\n`;
|
|
214
210
|
}
|
|
215
211
|
if (pluginVaryingAssembly.initialization) {
|
|
216
212
|
mainInjections['vs:#main-start'] = mainInjections['vs:#main-start'] || [];
|
|
@@ -26,7 +26,7 @@ import {PlatformInfo} from './platform-info';
|
|
|
26
26
|
import {assert} from '../utils/assert';
|
|
27
27
|
import {preprocess} from '../preprocessor/preprocessor';
|
|
28
28
|
import {assembleShaderPluginVertexInputsWGSL} from './shader-plugin-vertex-inputs';
|
|
29
|
-
import {
|
|
29
|
+
import {assembleShaderPluginInterStageVariablesWGSL} from './shader-plugin-varyings';
|
|
30
30
|
import {
|
|
31
31
|
normalizeShaderHooks,
|
|
32
32
|
validateShaderHookInjections,
|
|
@@ -113,7 +113,7 @@ export function assembleShaderWGSL(
|
|
|
113
113
|
inject = {},
|
|
114
114
|
pluginInjections = {},
|
|
115
115
|
pluginVertexInputs = {},
|
|
116
|
-
|
|
116
|
+
pluginInterStageVariables = {},
|
|
117
117
|
vertexEntryPoint = 'vertexMain',
|
|
118
118
|
fragmentEntryPoint = 'fragmentMain',
|
|
119
119
|
log
|
|
@@ -130,11 +130,11 @@ export function assembleShaderWGSL(
|
|
|
130
130
|
vertexEntryPoint,
|
|
131
131
|
pluginVertexInputs
|
|
132
132
|
);
|
|
133
|
-
const pluginVaryingAssembly =
|
|
133
|
+
const pluginVaryingAssembly = assembleShaderPluginInterStageVariablesWGSL(
|
|
134
134
|
pluginVertexInputAssembly.source,
|
|
135
135
|
vertexEntryPoint,
|
|
136
136
|
fragmentEntryPoint,
|
|
137
|
-
|
|
137
|
+
pluginInterStageVariables
|
|
138
138
|
);
|
|
139
139
|
const coreSource = pluginVaryingAssembly.source;
|
|
140
140
|
|
|
@@ -159,7 +159,7 @@ export function assembleShaderWGSL(
|
|
|
159
159
|
// `
|
|
160
160
|
// `;
|
|
161
161
|
|
|
162
|
-
const hookFunctionMap = normalizeShaderHooks(hookFunctions);
|
|
162
|
+
const hookFunctionMap = normalizeShaderHooks(hookFunctions, options.pluginHooks, 'wgsl');
|
|
163
163
|
|
|
164
164
|
// Add source of dependent modules in resolved order
|
|
165
165
|
const hookInjections: Record<string, ShaderInjection[]> = {};
|
|
@@ -177,16 +177,16 @@ export function assembleShaderWGSL(
|
|
|
177
177
|
const name = match[3];
|
|
178
178
|
if (hash) {
|
|
179
179
|
if (name === 'decl') {
|
|
180
|
-
declInjections[key] = [injection];
|
|
180
|
+
declInjections[key] = [...(declInjections[key] || []), injection];
|
|
181
181
|
} else {
|
|
182
|
-
mainInjections[key] = [injection];
|
|
182
|
+
mainInjections[key] = [...(mainInjections[key] || []), injection];
|
|
183
183
|
}
|
|
184
184
|
} else {
|
|
185
|
-
hookInjections[key] = [injection];
|
|
185
|
+
hookInjections[key] = [...(hookInjections[key] || []), injection];
|
|
186
186
|
}
|
|
187
187
|
} else {
|
|
188
188
|
// Regex injection
|
|
189
|
-
mainInjections[key] = [injection];
|
|
189
|
+
mainInjections[key] = [...(mainInjections[key] || []), injection];
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
appendGeneratedVertexInputInjections(
|
|
@@ -7,7 +7,7 @@ import {type ShaderModule} from '../shader-module/shader-module';
|
|
|
7
7
|
import {type ShaderHook} from './shader-hooks';
|
|
8
8
|
import {type ShaderInjection} from './shader-injections';
|
|
9
9
|
import {type AttributeShaderType} from '../../types';
|
|
10
|
-
import {type
|
|
10
|
+
import {type ResolvedShaderPluginInterStageVariable} from '../shader-plugin';
|
|
11
11
|
|
|
12
12
|
export type ShaderAssemblyLog = {
|
|
13
13
|
deprecated?: (...args: unknown[]) => () => unknown;
|
|
@@ -44,16 +44,18 @@ export type AssembleShaderOptions = {
|
|
|
44
44
|
defines?: Record<string, boolean | number>;
|
|
45
45
|
/** GLSL only: Overrides to be injected. In WGSL these are supplied during Pipeline creation time */
|
|
46
46
|
constants?: Record<string, number>;
|
|
47
|
-
/**
|
|
47
|
+
/** Per-call hooks, appended after registered assembler hooks; matching names override for this call. */
|
|
48
48
|
hookFunctions?: readonly (ShaderHook | string)[];
|
|
49
|
+
/** Hook declarations contributed by resolved plugins. */
|
|
50
|
+
pluginHooks?: readonly ShaderHook[];
|
|
49
51
|
/** Code injections */
|
|
50
52
|
inject?: Record<string, string | ShaderInjection>;
|
|
51
53
|
/** Ordered code injections contributed by ShaderPlugin descriptors. */
|
|
52
54
|
pluginInjections?: Record<string, ShaderInjection[]>;
|
|
53
55
|
/** Vertex inputs contributed by ShaderPlugin descriptors. */
|
|
54
56
|
pluginVertexInputs?: Record<string, AttributeShaderType>;
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
+
/** Inter-stage variables contributed by ShaderPlugin descriptors. */
|
|
58
|
+
pluginInterStageVariables?: Record<string, ResolvedShaderPluginInterStageVariable>;
|
|
57
59
|
/** WGSL vertex entry point selected by the render pipeline. */
|
|
58
60
|
vertexEntryPoint?: string;
|
|
59
61
|
/** Whether WGSL interface scanning should include vertex attributes. */
|
|
@@ -78,16 +80,18 @@ export type AssembleStageOptions = {
|
|
|
78
80
|
defines?: Record<string, boolean | number>;
|
|
79
81
|
/** GLSL only: Overrides to be injected. In WGSL these are supplied during Pipeline creation time */
|
|
80
82
|
constants?: Record<string, number>;
|
|
81
|
-
/**
|
|
83
|
+
/** Per-call hooks, appended after registered assembler hooks; matching names override for this call. */
|
|
82
84
|
hookFunctions?: readonly (ShaderHook | string)[];
|
|
85
|
+
/** Hook declarations contributed by resolved plugins. */
|
|
86
|
+
pluginHooks?: readonly ShaderHook[];
|
|
83
87
|
/** Code injections */
|
|
84
88
|
inject?: Record<string, string | ShaderInjection>;
|
|
85
89
|
/** Ordered code injections contributed by ShaderPlugin descriptors. */
|
|
86
90
|
pluginInjections?: Record<string, ShaderInjection[]>;
|
|
87
91
|
/** Vertex inputs contributed by ShaderPlugin descriptors. */
|
|
88
92
|
pluginVertexInputs?: Record<string, AttributeShaderType>;
|
|
89
|
-
/**
|
|
90
|
-
|
|
93
|
+
/** Inter-stage variables contributed by ShaderPlugin descriptors. */
|
|
94
|
+
pluginInterStageVariables?: Record<string, ResolvedShaderPluginInterStageVariable>;
|
|
91
95
|
/** WGSL vertex entry point selected by the render pipeline. */
|
|
92
96
|
vertexEntryPoint?: string;
|
|
93
97
|
/** WGSL fragment entry point selected by the render pipeline. */
|
|
@@ -71,14 +71,38 @@ export function getShaderHooks(
|
|
|
71
71
|
* A later declaration of the same stage-prefixed hook name replaces an earlier one.
|
|
72
72
|
*/
|
|
73
73
|
export function normalizeShaderHooks(
|
|
74
|
-
hookFunctions: readonly (ShaderHook | string)[]
|
|
74
|
+
hookFunctions: readonly (ShaderHook | string)[],
|
|
75
|
+
pluginHooks: readonly ShaderHook[] = [],
|
|
76
|
+
language?: 'glsl' | 'wgsl'
|
|
75
77
|
): ShaderHookRegistry {
|
|
76
78
|
const result: ShaderHookRegistry = {vertex: {}, fragment: {}};
|
|
77
79
|
|
|
78
80
|
for (const hookFunction of hookFunctions) {
|
|
79
|
-
|
|
81
|
+
const text = typeof hookFunction === 'string' ? hookFunction : hookFunction.hook;
|
|
82
|
+
const qualified = /^(glsl|wgsl):([\s\S]+)$/.exec(text);
|
|
83
|
+
if (qualified && qualified[1] !== language) continue;
|
|
84
|
+
addShaderHookToRegistry(
|
|
85
|
+
result,
|
|
86
|
+
qualified
|
|
87
|
+
? typeof hookFunction === 'string'
|
|
88
|
+
? qualified[2]
|
|
89
|
+
: {...hookFunction, hook: qualified[2]}
|
|
90
|
+
: hookFunction
|
|
91
|
+
);
|
|
80
92
|
}
|
|
81
93
|
|
|
94
|
+
for (const hook of pluginHooks) {
|
|
95
|
+
const normalized = normalizeShaderHooks([hook]);
|
|
96
|
+
for (const stage of ['vertex', 'fragment'] as const) {
|
|
97
|
+
for (const [name, declaration] of Object.entries(normalized[stage])) {
|
|
98
|
+
const existing = result[stage][name];
|
|
99
|
+
if (existing && existing.signature !== declaration.signature) {
|
|
100
|
+
throw new Error(`Conflicting ShaderPlugin hook ${name}`);
|
|
101
|
+
}
|
|
102
|
+
result[stage][name] = existing || declaration;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
82
106
|
return result;
|
|
83
107
|
}
|
|
84
108
|
|
|
@@ -106,7 +130,12 @@ export function validateShaderHookInjections(
|
|
|
106
130
|
|
|
107
131
|
if (!isShaderHookRegistered(registry, hookName)) {
|
|
108
132
|
// The injection targets a hook that was not declared for this stage.
|
|
109
|
-
|
|
133
|
+
const pluginNames = [
|
|
134
|
+
...new Set(hookInjections[hookName].map(injection => injection.pluginName).filter(Boolean))
|
|
135
|
+
];
|
|
136
|
+
throw new Error(
|
|
137
|
+
`Unknown shader hook ${hookName}${pluginNames.length ? ` (plugins: ${pluginNames.join(', ')})` : ''}`
|
|
138
|
+
);
|
|
110
139
|
}
|
|
111
140
|
}
|
|
112
141
|
}
|
|
@@ -120,7 +149,7 @@ function addShaderHookToRegistry(
|
|
|
120
149
|
const stageSeparatorIndex = hook.indexOf(':');
|
|
121
150
|
const shaderStage = hook.slice(0, stageSeparatorIndex);
|
|
122
151
|
const signature = hook.slice(stageSeparatorIndex + 1);
|
|
123
|
-
const name = hook.
|
|
152
|
+
const name = hook.split('(')[0].trim();
|
|
124
153
|
const normalizedHook: Required<ShaderHook> = {
|
|
125
154
|
hook: name,
|
|
126
155
|
signature,
|
|
@@ -21,6 +21,8 @@ export const DECLARATION_INJECT_MARKER = '__LUMA_INJECT_DECLARATIONS__';
|
|
|
21
21
|
*
|
|
22
22
|
*/
|
|
23
23
|
export type ShaderInjection = {
|
|
24
|
+
/** Plugin responsible for this injection, when supplied by a ShaderPlugin. */
|
|
25
|
+
pluginName?: string;
|
|
24
26
|
injection: string;
|
|
25
27
|
order: number;
|
|
26
28
|
};
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import {shaderTypeDecoder} from '../../types';
|
|
6
|
-
import type {
|
|
6
|
+
import type {ResolvedShaderPluginInterStageVariable} from '../shader-plugin';
|
|
7
7
|
import {getGLSLAttributeType} from './shader-plugin-vertex-inputs';
|
|
8
|
+
import {maskWGSLComments} from './wgsl-binding-scan';
|
|
8
9
|
|
|
9
|
-
export type
|
|
10
|
+
export type ShaderPluginInterStageVariableAssembly = {
|
|
10
11
|
source: string;
|
|
11
12
|
declarations: string;
|
|
12
13
|
vertexInitialization: string;
|
|
@@ -14,14 +15,14 @@ export type ShaderPluginVaryingAssembly = {
|
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
/** Generate one stage of the GLSL interface contributed by shader plugins. */
|
|
17
|
-
export function
|
|
18
|
+
export function assembleShaderPluginInterStageVariablesGLSL(
|
|
18
19
|
source: string,
|
|
19
20
|
stage: 'vertex' | 'fragment',
|
|
20
|
-
|
|
21
|
+
interStageVariables: Record<string, ResolvedShaderPluginInterStageVariable>
|
|
21
22
|
): {declarations: string; initialization: string} {
|
|
22
23
|
const declarations: string[] = [];
|
|
23
24
|
const initialization: string[] = [];
|
|
24
|
-
for (const [name, varying] of Object.entries(
|
|
25
|
+
for (const [name, varying] of Object.entries(interStageVariables)) {
|
|
25
26
|
assertGLSLVaryingIsNew(source, name);
|
|
26
27
|
const qualifier = varying.interpolation === 'flat' ? 'flat ' : '';
|
|
27
28
|
const direction = stage === 'vertex' ? 'out' : 'in';
|
|
@@ -33,14 +34,14 @@ export function assembleShaderPluginVaryingsGLSL(
|
|
|
33
34
|
return {declarations: declarations.join('\n'), initialization: initialization.join('\n')};
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
/** Add plugin
|
|
37
|
-
export function
|
|
37
|
+
/** Add plugin interStageVariables to selected WGSL vertex and fragment entry points. */
|
|
38
|
+
export function assembleShaderPluginInterStageVariablesWGSL(
|
|
38
39
|
source: string,
|
|
39
40
|
vertexEntryPoint: string,
|
|
40
41
|
fragmentEntryPoint: string,
|
|
41
|
-
|
|
42
|
-
):
|
|
43
|
-
const entries = Object.entries(
|
|
42
|
+
interStageVariables: Record<string, ResolvedShaderPluginInterStageVariable>
|
|
43
|
+
): ShaderPluginInterStageVariableAssembly {
|
|
44
|
+
const entries = Object.entries(interStageVariables);
|
|
44
45
|
if (entries.length === 0) {
|
|
45
46
|
return {
|
|
46
47
|
source,
|
|
@@ -56,19 +57,23 @@ export function assembleShaderPluginVaryingsWGSL(
|
|
|
56
57
|
let fragmentFunction = getWGSLFunctionRange(transformedSource, fragmentEntryPoint, 'fragment');
|
|
57
58
|
const fragmentInput = getWGSLFragmentStructInput(transformedSource, fragmentFunction);
|
|
58
59
|
const vertexOutputStruct = getWGSLStructRange(transformedSource, vertexOutputType);
|
|
59
|
-
const fragmentInputStruct =
|
|
60
|
+
const fragmentInputStruct = fragmentInput
|
|
61
|
+
? getWGSLStructRange(transformedSource, fragmentInput.type)
|
|
62
|
+
: null;
|
|
60
63
|
|
|
61
64
|
const interfaceNames = new Set([
|
|
62
65
|
...getWGSLDeclaredNames(vertexFunction.parameters),
|
|
63
66
|
...getWGSLDeclaredNames(vertexOutputStruct.body),
|
|
64
67
|
...getWGSLDeclaredNames(fragmentFunction.parameters),
|
|
65
|
-
...getWGSLDeclaredNames(fragmentInputStruct
|
|
68
|
+
...getWGSLDeclaredNames(fragmentInputStruct?.body || '')
|
|
66
69
|
]);
|
|
67
70
|
const usedLocations = new Set([
|
|
68
71
|
...getWGSLLocations(vertexOutputStruct.body),
|
|
69
|
-
...getWGSLLocations(fragmentInputStruct
|
|
72
|
+
...getWGSLLocations(fragmentInputStruct?.body || ''),
|
|
73
|
+
...getWGSLLocations(fragmentFunction.parameters)
|
|
70
74
|
]);
|
|
71
75
|
const fields: string[] = [];
|
|
76
|
+
const fragmentParameters: string[] = [];
|
|
72
77
|
const declarations: string[] = [];
|
|
73
78
|
const vertexInitialization: string[] = [];
|
|
74
79
|
const fragmentInitialization: string[] = [];
|
|
@@ -85,7 +90,20 @@ export function assembleShaderPluginVaryingsWGSL(
|
|
|
85
90
|
fields.push(` @location(${location})${interpolation} ${name}: ${varying.type},`);
|
|
86
91
|
declarations.push(`var<private> ${name}: ${varying.type};`);
|
|
87
92
|
vertexInitialization.push(`${name} = ${getWGSLZeroValue(varying.type)};`);
|
|
88
|
-
|
|
93
|
+
if (fragmentInput) {
|
|
94
|
+
fragmentInitialization.push(`${name} = ${fragmentInput.name}.${name};`);
|
|
95
|
+
} else {
|
|
96
|
+
const parameterName = `_luma_${name}`;
|
|
97
|
+
if (interfaceNames.has(parameterName)) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`ShaderPlugin varying "${name}" conflicts with a generated fragment parameter`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
fragmentParameters.push(
|
|
103
|
+
`@location(${location})${interpolation} ${parameterName}: ${varying.type}`
|
|
104
|
+
);
|
|
105
|
+
fragmentInitialization.push(`${name} = ${parameterName};`);
|
|
106
|
+
}
|
|
89
107
|
}
|
|
90
108
|
|
|
91
109
|
assertWGSLStructConstructorsAreLocal(
|
|
@@ -108,7 +126,7 @@ export function assembleShaderPluginVaryingsWGSL(
|
|
|
108
126
|
);
|
|
109
127
|
|
|
110
128
|
const structNames =
|
|
111
|
-
vertexOutputType === fragmentInput.type
|
|
129
|
+
!fragmentInput || vertexOutputType === fragmentInput.type
|
|
112
130
|
? [vertexOutputType]
|
|
113
131
|
: [vertexOutputType, fragmentInput.type];
|
|
114
132
|
const structInsertions = structNames
|
|
@@ -122,9 +140,20 @@ export function assembleShaderPluginVaryingsWGSL(
|
|
|
122
140
|
}
|
|
123
141
|
|
|
124
142
|
fragmentFunction = getWGSLFunctionRange(transformedSource, fragmentEntryPoint, 'fragment');
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
143
|
+
if (fragmentParameters.length) {
|
|
144
|
+
let parameters = fragmentFunction.parameters;
|
|
145
|
+
const parameterTokens = maskWGSLComments(parameters).trimEnd();
|
|
146
|
+
if (parameterTokens.trim() && !parameterTokens.endsWith(',')) {
|
|
147
|
+
const insertionIndex = parameterTokens.length;
|
|
148
|
+
parameters = `${parameters.slice(0, insertionIndex)},${parameters.slice(insertionIndex)}`;
|
|
149
|
+
}
|
|
150
|
+
transformedSource =
|
|
151
|
+
transformedSource.slice(0, fragmentFunction.openParenthesis + 1) +
|
|
152
|
+
parameters +
|
|
153
|
+
'\n ' +
|
|
154
|
+
fragmentParameters.join(',\n ') +
|
|
155
|
+
'\n' +
|
|
156
|
+
transformedSource.slice(fragmentFunction.closeParenthesis);
|
|
128
157
|
}
|
|
129
158
|
|
|
130
159
|
return {
|
|
@@ -157,7 +186,9 @@ function getWGSLFunctionRange(
|
|
|
157
186
|
const functionPattern = new RegExp(`\\bfn\\s+${escapeRegExp(entryPoint)}\\s*\\(`, 'g');
|
|
158
187
|
const match = functionPattern.exec(source);
|
|
159
188
|
if (!match) {
|
|
160
|
-
throw new Error(
|
|
189
|
+
throw new Error(
|
|
190
|
+
`ShaderPlugin interStageVariables require WGSL ${stage} entry point "${entryPoint}"`
|
|
191
|
+
);
|
|
161
192
|
}
|
|
162
193
|
const openParenthesis = source.indexOf('(', match.index);
|
|
163
194
|
const closeParenthesis = findMatchingDelimiter(source, openParenthesis, '(', ')');
|
|
@@ -180,7 +211,7 @@ function getWGSLNamedReturnType(source: string, functionRange: WGSLFunctionRange
|
|
|
180
211
|
const match = /->\s*([A-Za-z_][\w]*)\s*$/.exec(resultSource.trim());
|
|
181
212
|
if (!match || getWGSLStructRangeOrNull(source, match[1]) === null) {
|
|
182
213
|
throw new Error(
|
|
183
|
-
'ShaderPlugin
|
|
214
|
+
'ShaderPlugin interStageVariables require the WGSL vertex entry point to return a named struct'
|
|
184
215
|
);
|
|
185
216
|
}
|
|
186
217
|
return match[1];
|
|
@@ -189,9 +220,9 @@ function getWGSLNamedReturnType(source: string, functionRange: WGSLFunctionRange
|
|
|
189
220
|
function getWGSLFragmentStructInput(
|
|
190
221
|
source: string,
|
|
191
222
|
functionRange: WGSLFunctionRange
|
|
192
|
-
): {name: string; type: string} {
|
|
223
|
+
): {name: string; type: string} | null {
|
|
193
224
|
const candidates: {name: string; type: string}[] = [];
|
|
194
|
-
for (const parameter of splitTopLevel(functionRange.parameters, ',')) {
|
|
225
|
+
for (const parameter of splitTopLevel(maskWGSLComments(functionRange.parameters), ',')) {
|
|
195
226
|
const match =
|
|
196
227
|
/(?:@[A-Za-z_][\w]*(?:\([^)]*\))?\s*)*([A-Za-z_][\w]*)\s*:\s*([A-Za-z_][\w]*)\s*$/.exec(
|
|
197
228
|
parameter.trim()
|
|
@@ -200,12 +231,12 @@ function getWGSLFragmentStructInput(
|
|
|
200
231
|
candidates.push({name: match[1], type: match[2]});
|
|
201
232
|
}
|
|
202
233
|
}
|
|
203
|
-
if (candidates.length
|
|
234
|
+
if (candidates.length > 1) {
|
|
204
235
|
throw new Error(
|
|
205
|
-
`ShaderPlugin
|
|
236
|
+
`ShaderPlugin interStageVariables require exactly one named WGSL fragment input struct; found ${candidates.length}`
|
|
206
237
|
);
|
|
207
238
|
}
|
|
208
|
-
return candidates[0];
|
|
239
|
+
return candidates[0] || null;
|
|
209
240
|
}
|
|
210
241
|
|
|
211
242
|
function getWGSLStructRange(source: string, structName: string): WGSLStructRange {
|
|
@@ -440,13 +471,13 @@ function getFirstUnusedLocation(usedLocations: Set<number>): number {
|
|
|
440
471
|
return location;
|
|
441
472
|
}
|
|
442
473
|
|
|
443
|
-
function getGLSLZeroValue(type:
|
|
474
|
+
function getGLSLZeroValue(type: ResolvedShaderPluginInterStageVariable['type']): string {
|
|
444
475
|
const {primitiveType, components} = shaderTypeDecoder.getAttributeShaderTypeInfo(type);
|
|
445
476
|
const scalar = primitiveType === 'u32' ? '0u' : primitiveType === 'i32' ? '0' : '0.0';
|
|
446
477
|
return components === 1 ? scalar : `${getGLSLAttributeType(type)}(${scalar})`;
|
|
447
478
|
}
|
|
448
479
|
|
|
449
|
-
function getWGSLZeroValue(type:
|
|
480
|
+
function getWGSLZeroValue(type: ResolvedShaderPluginInterStageVariable['type']): string {
|
|
450
481
|
const {primitiveType, components} = shaderTypeDecoder.getAttributeShaderTypeInfo(type);
|
|
451
482
|
const scalar = `${primitiveType}(0)`;
|
|
452
483
|
return components === 1 ? scalar : `${type}(${scalar})`;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import {UniformFormat} from '../../../types';
|
|
6
|
-
import {ShaderModule} from '
|
|
6
|
+
import {ShaderModule} from '../../shader-module/shader-module';
|
|
7
7
|
import {capitalize} from '../utils/capitalize';
|
|
8
8
|
|
|
9
9
|
export type GLSLGenerationOptions = {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import {ShaderModule} from '
|
|
5
|
+
import {ShaderModule} from '../../shader-module/shader-module';
|
|
6
6
|
import {capitalize} from '../utils/capitalize';
|
|
7
7
|
|
|
8
8
|
export type WGSLGenerationOptions = {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import {ShaderModule, initializeShaderModules} from './shader-module';
|
|
6
6
|
import {assert} from '../utils/assert';
|
|
7
7
|
|
|
8
|
-
// import type {ShaderModule} from '
|
|
8
|
+
// import type {ShaderModule} from './shader-module';
|
|
9
9
|
|
|
10
10
|
type AbstractModule = {
|
|
11
11
|
name: string;
|