Files
WebGPU-FFT-Ocean-Demo/framework/WGSLReflection.js

144 lines
3.5 KiB
JavaScript
Raw Normal View History

2025-12-31 14:22:45 +01:00
export class WGSLReflection {
constructor(wgslSource) {
this.src = wgslSource;
this.structs = {};
this.bindings = [];
this.parseStructs();
this.parseBindings();
}
//
// ------------------------------------------------------------
// STRUCT PARSING
// ------------------------------------------------------------
//
parseStructs() {
const structRegex =
/struct\s+(\w+)\s*\{([^}]+)\}/g;
let match;
while ((match = structRegex.exec(this.src))) {
const structName = match[1];
const body = match[2].trim();
const fields = this.parseStructFields(body);
const size = fields.reduce((sum, f) => sum + f.size, 0);
this.structs[structName] = {
name: structName,
fields,
size
};
}
}
parseStructFields(body) {
const lines = body.split("\n");
const fields = [];
for (let line of lines) {
line = line.trim();
if (!line) continue;
const m = line.match(/(\w+)\s*:\s*([^;]+);/);
if (!m) continue;
const fieldName = m[1];
const wgslType = m[2].trim();
const size = this.computeTypeSize(wgslType);
fields.push({ fieldName, wgslType, size });
}
return fields;
}
//
// ------------------------------------------------------------
// BINDING PARSING
// ------------------------------------------------------------
//
parseBindings() {
const varRegex =
/@group\((\d+)\)\s*@binding\((\d+)\)\s*var<([^>]+)>\s+(\w+)\s*:\s*([^;]+);/g;
let match;
while ((match = varRegex.exec(this.src))) {
const group = parseInt(match[1]);
const binding = parseInt(match[2]);
const type = match[3].trim();
const varName = match[4].trim();
const varType = match[5].trim();
const size = this.computeTypeSize(varType);
this.bindings.push({
group,
binding,
type,
varName,
varType,
size
});
}
}
//
// ------------------------------------------------------------
// TYPE SIZE COMPUTATION (Simplified)
// ------------------------------------------------------------
//
computeTypeSize(wgslType) {
// scalar
if (wgslType === "f32" || wgslType === "u32" || wgslType === "i32") {
return 4;
}
// array<f32, N>
const arrMatch = wgslType.match(/array<(\w+),\s*(\d+)>/);
if (arrMatch) {
const elementType = arrMatch[1];
const count = parseInt(arrMatch[2]);
return this.computeTypeSize(elementType) * count;
}
// array<f32> runtime-sized → minimal
const runtimeArr = wgslType.match(/array<(\w+)>/);
if (runtimeArr) {
return 4;
}
// struct
if (this.structs[wgslType]) {
return this.structs[wgslType].size;
}
return 4;
}
//
// ------------------------------------------------------------
// SUMMARY OUTPUT
// ------------------------------------------------------------
//
reflect() {
return {
structs: this.structs,
bindings: this.bindings
};
}
}