Start · Sprachen · JavaScript · Referenz · GPUCompilationMessage

GPUCompilationMessage

Schnittstelle

Stellt eine einzelne Info-, Warn- oder Fehlermeldung dar, die der WebGPU-Shader-Compiler beim Übersetzen eines <code>GPUShaderModule</code> erzeugt.

seit JavaScript WebGPU – Chrome/Edge 113+, Safari 26+, Firefox 141 Kategorie: webapi

Signatur

interface GPUCompilationMessage

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

Typ
GPUCompilationMessage
Beschreibung
Kein Konstruktor. Instanzen stecken im Array 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}`);
}
[error] Zeile 5:1 – expected ';' for return statement

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));
}
ERROR: return statement type must match its function return type ... 1 | fn f() -> f32 { return 1u; } | ^^^^^^^^^ Betroffen: return 1u

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);
}
Pipeline bereit GPURenderPipeline {...} (oder die formatierte Fehlerliste)

// Wichtig · Fallstricke

  • Kein Konstruktor: new GPUCompilationMessage() wirft einen TypeError. Instanzen liefert nur getCompilationInfo().
  • Meldungen ohne Position: Bezieht sich eine Meldung auf keine bestimmte Quelltextstelle, sind lineNum, linePos, offset und length alle 0. Prüfe das, bevor du die Werte als Index verwendest (lineNum - 1 ergäbe sonst -1).
  • Zählweise: lineNum und linePos beginnen bei 1, offset beginnt 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 message hä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 über type.
  • 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. im uncapturederror-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 textContent ein und nicht per innerHTML. Sie können Teile des Shader-Quelltexts enthalten, und der kann aus Nutzereingaben stammen.