Signatur
Beschreibung
Die schreibgeschützte Eigenschaft offset einer GPUCompilationMessage gibt an, wo im Quelltext eines Shader-Moduls die gemeldete Stelle liegt. Das kann ein einzelner Punkt sein oder der Anfang eines Abschnitts. Gezählt wird ab dem Anfang des Strings, der als code an GPUDevice.createShaderModule() übergeben wurde. Die Zählung beginnt bei 0 und erfolgt in UTF-16-Codeeinheiten, also genauso wie String-Indizes in JavaScript.
Zusammen mit length beschreibt offset genau den betroffenen Abschnitt. Mit code.slice(msg.offset, msg.offset + msg.length) holen Sie ihn direkt aus dem Quelltext. Das eignet sich gut, um Fehlerstellen in einem Shader-Editor zu markieren, zum Beispiel mit Wellenlinien, oder um eigene Fehlermeldungen mit Codeausschnitt zu bauen.
Die Meldungen erhalten Sie über GPUShaderModule.getCompilationInfo(). Das Promise liefert eine GPUCompilationInfo, deren Array messages die einzelnen GPUCompilationMessage-Objekte enthält. Jede Meldung hat einen type ("error", "warning" oder "info"), einen Text und die Positionsangaben offset, length, lineNum und linePos.
Rückgabewert
0 (und length ebenfalls 0).Beispiele
Compiler-Meldungen mit Position ausgeben
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const code = `@fragment
fn main() -> @location(0) vec4f {
return vec4f(1.0, 0.0, 0.0);
}`;
const module = device.createShaderModule({ code });
const info = await module.getCompilationInfo();
for (const msg of info.messages) {
console.log(`${msg.type} bei Offset ${msg.offset} (Länge ${msg.length}): ${msg.message}`);
}
Fehlerhaften Abschnitt aus dem Quelltext holen
const showErrors = async (device, code) => {
const module = device.createShaderModule({ code });
const { messages } = await module.getCompilationInfo();
return messages
.filter((m) => m.type === 'error')
.map((m) => ({
text: m.message,
snippet: code.slice(m.offset, m.offset + m.length),
line: m.lineNum,
column: m.linePos
}));
};
const errors = await showErrors(device, 'fn f() -> i32 { return 1.5; }');
console.table(errors);
Fehlerstelle im Editor markieren (HTML-Ausgabe)
const escape = (s) => s.replace(/[&<>]/g, (c) => ({ '&': '&', '<': '<', '>': '>' })[c]);
const highlight = (code, msg) => {
const start = msg.offset;
const end = start + Math.max(msg.length, 1); // bei Länge 0 mindestens ein Zeichen markieren
return escape(code.slice(0, start)) +
'<mark>' + escape(code.slice(start, end)) + '</mark>' +
escape(code.slice(end));
};
const { messages } = await module.getCompilationInfo();
if (messages.length > 0) {
document.querySelector('#editor').innerHTML = highlight(code, messages[0]);
}
// Wichtig · Fallstricke
- UTF-16 statt Bytes oder Zeichen:
offsetzählt UTF-16-Codeeinheiten. Bei Emojis oder anderen Zeichen außerhalb der BMP (in Kommentaren) stimmt der Wert deshalb nicht mit der Anzahl sichtbarer Zeichen überein. FürString.prototype.slice()passt er aber genau. - Unterschiedliche Zählbasis:
offsetbeginnt bei 0,lineNumundlinePosbeginnen bei 1. Nicht vermischen. - Kein Positionsbezug: Bei allgemeinen Meldungen sind
offsetundlengthbeide0. Prüfen Sie deshalb auchlengthoderlineNum, bevor Sie eine Stelle markieren. - Browserabhängig: Ob Warnungen oder Infos erscheinen, der Meldungstext und die genaue Länge des Abschnitts hängen von der Implementierung ab. Die Werte eignen sich zur Anzeige, nicht für feste Tests.
- Sicherheit: Wenn Sie Codeausschnitte per
innerHTMLeinfügen, müssen Sie Quelltext und Meldungstext vorher maskieren (siehe Beispiel 3), sonst droht XSS. - Kompatibilität: WebGPU gibt es nur in sicheren Kontexten und noch nicht in allen Browsern. Prüfen Sie vorher mit
if (!navigator.gpu), ob die API vorhanden ist.