@luma.gl/shadertools
Version:
Shader module system for luma.gl
93 lines • 2.99 kB
JavaScript
// luma.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { log } from '@luma.gl/core';
import { WgslReflect } from 'wgsl_reflect';
/**
* Parse a ShaderLayout from WGSL shader source code.
* @param source WGSL source code (can contain both @vertex and @fragment entry points)
* @returns
*/
export function getShaderLayoutFromWGSL(source) {
const shaderLayout = { attributes: [], bindings: [] };
let parsedWGSL;
try {
parsedWGSL = parseWGSL(source);
}
catch (error) {
log.error(error.message)();
return shaderLayout;
}
for (const uniform of parsedWGSL.uniforms) {
const members = [];
for (const attribute of uniform.type?.members || []) {
members.push({
name: attribute.name,
type: getType(attribute.type)
});
}
shaderLayout.bindings.push({
type: 'uniform',
name: uniform.name,
group: uniform.group,
location: uniform.binding,
// @ts-expect-error TODO - unused for now but needs fixing
members
});
}
for (const texture of parsedWGSL.textures) {
shaderLayout.bindings.push({
type: 'texture',
name: texture.name,
group: texture.group,
location: texture.binding
});
}
for (const sampler of parsedWGSL.samplers) {
shaderLayout.bindings.push({
type: 'sampler',
name: sampler.name,
group: sampler.group,
location: sampler.binding
});
}
const vertex = parsedWGSL.entry.vertex[0]; // "main"
// Vertex shader inputs
const attributeCount = vertex?.inputs.length || 0; // inputs to "main"
for (let i = 0; i < attributeCount; i++) {
const wgslAttribute = vertex.inputs[i];
// locationType can be "builtin"
if (wgslAttribute.locationType === 'location') {
const type = getType(wgslAttribute.type);
shaderLayout.attributes.push({
name: wgslAttribute.name,
location: Number(wgslAttribute.location),
type
});
}
}
return shaderLayout;
}
/** Get a valid shader attribute type string from a wgsl-reflect type */
function getType(type) {
return type.format ? `${type.name}<${type.format.name}>` : type.name;
}
function parseWGSL(source) {
try {
return new WgslReflect(source);
}
catch (error) {
if (error instanceof Error) {
throw error;
}
let message = 'WGSL parse error';
if (typeof error === 'object' && error?.message) {
message += `: ${error.message} `;
}
if (typeof error === 'object' && error?.token) {
message += error.token.line || '';
}
throw new Error(message, { cause: error });
}
}
//# sourceMappingURL=get-shader-layout-wgsl.js.map