Signatur
Beschreibung
GPUCompilationMessage gehört zur WebGPU API. Jedes Objekt beschreibt eine Meldung des WGSL-Compilers: einen Syntaxfehler, eine Warnung (z. B. zu ungenutzten Variablen) oder einen reinen Hinweis. Du erzeugst solche Objekte nicht selbst. Du bekommst sie über GPUShaderModule.getCompilationInfo(). Die Methode liefert ein Promise<GPUCompilationInfo>, dessen Eigenschaft messages ein Array von GPUCompilationMessage-Objekten enthält.
Alle Eigenschaften sind schreibgeschützt:
message(string): lesbarer Meldungstext des Compilers.type("error" | "warning" | "info"): Schweregrad der Meldung.lineNum(number): Zeilennummer im Shader-Quelltext, beginnend bei 1.linePos(number): Position innerhalb der Zeile in UTF-16-Codeeinheiten, beginnend bei 1.offset(number): Versatz vom Anfang des Quelltexts in UTF-16-Codeeinheiten, beginnend bei 0.length(number): Länge des betroffenen Quelltextabschnitts in UTF-16-Codeeinheiten.
Du brauchst das Interface vor allem beim Entwickeln und Debuggen von Shadern. Damit kannst du Compilerfehler mit genauer Position ausgeben, fehlerhafte Stellen in einem Editor markieren oder vor dem Erstellen einer Render- bzw. Compute-Pipeline prüfen, ob der Shader überhaupt gültig ist. Da offset und length in UTF-16-Codeeinheiten angegeben sind, passen sie direkt zu String.prototype.slice() auf dem ursprünglichen WGSL-String.
Rückgabewert
GPUCompilationInfo.messages, das GPUShaderModule.getCompilationInfo() liefert.Beispiele
Compilermeldungen eines Shader-Moduls ausgeben
const adapter = await navigator.gpu?.requestAdapter();
if (!adapter) throw new Error('WebGPU wird nicht unterstützt');
const device = await adapter.requestDevice();
// Absichtlich fehlerhafter Shader: das Semikolon fehlt
const code = `
@vertex
fn main() -> @builtin(position) vec4f {
return vec4f(0.0, 0.0, 0.0, 1.0)
}`;
const module = device.createShaderModule({ code });
const info = await module.getCompilationInfo();
for (const msg of info.messages) {
console.log(`[${msg.type}] Zeile ${msg.lineNum}:${msg.linePos} – ${msg.message}`);
}
Fehlerstelle im Quelltext markieren
const formatMessage = (source, msg) => {
const lines = source.split('\n');
const line = lines[msg.lineNum - 1] ?? '';
// Unterstreichung ab linePos (1-basiert), mindestens ein Zeichen breit
const marker = ' '.repeat(Math.max(msg.linePos - 1, 0)) + '^'.repeat(Math.max(msg.length, 1));
return `${msg.type.toUpperCase()}: ${msg.message}\n${msg.lineNum} | ${line}\n${' '.repeat(String(msg.lineNum).length)} | ${marker}`;
};
const code = 'fn f() -> f32 { return 1u; }';
const module = device.createShaderModule({ code });
const { messages } = await module.getCompilationInfo();
messages.forEach((m) => console.log(formatMessage(code, m)));
// Betroffenen Ausschnitt direkt über offset/length holen
if (messages[0]) {
const { offset, length } = messages[0];
console.log('Betroffen:', code.slice(offset, offset + length));
}
Pipeline nur bei fehlerfreiem Shader erzeugen
const compileShader = async (device, code, label) => {
const module = device.createShaderModule({ code, label });
const { messages } = await module.getCompilationInfo();
const errors = messages.filter((m) => m.type === 'error');
const warnings = messages.filter((m) => m.type === 'warning');
warnings.forEach((w) => console.warn(`${label}:${w.lineNum}:${w.linePos} ${w.message}`));
if (errors.length > 0) {
const text = errors.map((e) => `${label}:${e.lineNum}:${e.linePos} ${e.message}`).join('\n');
throw new Error(`Shader-Kompilierung fehlgeschlagen:\n${text}`);
}
return module;
};
try {
const module = await compileShader(device, wgslSource, 'dreieck.wgsl');
const pipeline = await device.createRenderPipelineAsync({
layout: 'auto',
vertex: { module, entryPoint: 'vs' },
fragment: { module, entryPoint: 'fs', targets: [{ format: navigator.gpu.getPreferredCanvasFormat() }] },
});
console.log('Pipeline bereit', pipeline);
} catch (err) {
console.error(err.message);
}
// Wichtig · Fallstricke
- Kein Konstruktor:
new GPUCompilationMessage()wirft einenTypeError. Instanzen liefert nurgetCompilationInfo(). - Meldungen ohne Position: Bezieht sich eine Meldung auf keine bestimmte Quelltextstelle, sind
lineNum,linePos,offsetundlengthalle0. Prüfe das, bevor du die Werte als Index verwendest (lineNum - 1ergäbe sonst-1). - Zählweise:
lineNumundlinePosbeginnen bei 1,offsetbeginnt bei 0. Alle Positionsangaben zählen in UTF-16-Codeeinheiten, nicht in Bytes oder Unicode-Codepunkten. Das ist bei Emojis oder anderen Nicht-BMP-Zeichen in Kommentaren wichtig. - Meldungstext nicht stabil: Der Inhalt von
messagehängt von der Implementierung ab (Tint in Chromium, Naga in Firefox, WebKit-eigener Compiler) und kann sich zwischen Browserversionen ändern. Werte ihn nicht per String-Vergleich aus, sondern nur übertype. - Fehler werden nicht geworfen:
createShaderModule()wirft bei ungültigem WGSL keinen Fehler. Das Modul gilt dann als ungültig, und der Fehler landet zusätzlich im Fehler-Scope bzw. imuncapturederror-Event des Geräts. Ohne ausdrückliche Prüfung scheitert erst die spätere Erstellung der Pipeline. - Browser-Kompatibilität: WebGPU gibt es nur in sicheren Kontexten und noch nicht überall (Chrome/Edge 113+, Safari 26+, Firefox ab 141 zunächst unter Windows). Prüfe die Unterstützung vorher mit
navigator.gpu. - Sicherheit: Wenn du Meldungen in einer Oberfläche anzeigst, setze sie per
textContentein und nicht perinnerHTML. Sie können Teile des Shader-Quelltexts enthalten, und der kann aus Nutzereingaben stammen.