Signatur
Beschreibung
GPUShaderModule ist ein Container für Shader-Code in der Sprache WGSL (WebGPU Shading Language). Ein Modul wird nicht direkt über einen Konstruktor erzeugt, sondern über GPUDevice.createShaderModule({ code }). Der Browser prüft und übersetzt den WGSL-Code dabei in das native Format der Grafikschnittstelle (Vulkan, Metal oder Direct3D 12).
Ein Modul kann mehrere Einstiegspunkte enthalten, z. B. eine mit @vertex, eine mit @fragment und eine mit @compute markierte Funktion. Bei GPUDevice.createRenderPipeline() oder createComputePipeline() verweist man dann über module und entryPoint auf die passende Funktion. So lässt sich ein Modul in mehreren Pipelines wiederverwenden.
Die Schnittstelle hat nur wenige Mitglieder:
label(Eigenschaft): ein frei wählbarer Name, der in Fehlermeldungen und Debugging-Werkzeugen angezeigt wird.getCompilationInfo()(Methode): gibt einPromise<GPUCompilationInfo>zurück. Dessen Arraymessagesenthält Fehler, Warnungen und Hinweise des Compilers, jeweils mit Zeile, Spalte und Text.
createShaderModule() wirft keine Ausnahme, wenn der Code fehlerhaft ist. Das Modul wird dann als ungültig markiert, und der Fehler zeigt sich erst später. Deshalb sollte man während der Entwicklung getCompilationInfo() auswerten oder mit pushErrorScope('validation') arbeiten.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $descriptor.code Pflicht | string | WGSL-Quelltext des Moduls (Übergabe an GPUDevice.createShaderModule()). |
|
| $descriptor.label | string | "" | Optionaler Name für Fehlermeldungen und Debugging-Werkzeuge. Man kann ihn später über module.label lesen und ändern. |
| $descriptor.compilationHints | Array<{ entryPoint: string, layout?: GPUPipelineLayout | "auto" }> | [] | Optionale Hinweise auf Einstiegspunkte und Pipeline-Layouts. Der Browser kann damit früher kompilieren. |
| $descriptor.sourceMap | object | Optionale Source Map für die Fehlersuche. Wird in der Praxis kaum unterstützt. |
Rückgabewert
GPUDevice.createShaderModule() gibt ein GPUShaderModule zurück. Das Modul kann auch ungültig sein; dann hilft getCompilationInfo() bei der Fehlersuche.Beispiele
Shader-Modul erzeugen und Compiler-Meldungen prüfen
const adapter = await navigator.gpu?.requestAdapter();
if (!adapter) throw new Error('WebGPU wird nicht unterstützt');
const device = await adapter.requestDevice();
const module = device.createShaderModule({
label: 'Dreieck-Shader',
code: /* wgsl */ `
@vertex
fn vs_main(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
var pos = array<vec2f, 3>(
vec2f(0.0, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5)
);
return vec4f(pos[i], 0.0, 1.0);
}
@fragment
fn fs_main() -> @location(0) vec4f {
return vec4f(1.0, 0.4, 0.0, 1.0);
}
`
});
const info = await module.getCompilationInfo();
console.log(module.label, '–', info.messages.length, 'Meldungen');
Modul in einer Render-Pipeline verwenden
const canvas = document.querySelector('canvas');
const context = canvas.getContext('webgpu');
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device, format });
// module aus dem vorherigen Beispiel: ein Modul, zwei Einstiegspunkte
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: { module, entryPoint: 'vs_main' },
fragment: { module, entryPoint: 'fs_main', targets: [{ format }] },
primitive: { topology: 'triangle-list' }
});
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
clearValue: { r: 0, g: 0, b: 0, a: 1 },
loadOp: 'clear',
storeOp: 'store'
}]
});
pass.setPipeline(pipeline);
pass.draw(3);
pass.end();
device.queue.submit([encoder.finish()]);
WGSL-Fehler mit Zeilenangabe ausgeben
const broken = device.createShaderModule({
label: 'Kaputter Compute-Shader',
code: `
@compute @workgroup_size(64)
fn main() {
let x: f32 = 1; // Fehler: kein automatisches Umwandeln von i32 nach f32
}
`
});
const { messages } = await broken.getCompilationInfo();
for (const m of messages) {
console.log(`[${m.type}] Zeile ${m.lineNum}:${m.linePos} – ${m.message}`);
}
Validierungsfehler über einen Error-Scope abfangen
device.pushErrorScope('validation');
const mod = device.createShaderModule({ code: 'fn oops( {' });
const error = await device.popErrorScope();
if (error) {
console.error('Shader ungültig:', error.message);
}
// Wichtig · Fallstricke
- Kein Konstruktor:
new GPUShaderModule()wirft einenTypeError. Module werden immer überGPUDevice.createShaderModule()erzeugt. - Stille Fehler: Fehlerhafter WGSL-Code löst beim Erzeugen keine Ausnahme aus. Der Fehler zeigt sich erst als Validierungsfehler, z. B. beim Erstellen der Pipeline. Deshalb während der Entwicklung immer
getCompilationInfo()oderpushErrorScope()nutzen. - Nur WGSL: GLSL und SPIR-V werden nicht direkt angenommen. Dafür braucht man einen Übersetzer wie naga oder tint.
- Zeilennummern:
lineNumundlinePosbeginnen bei 1. Die Positionen zählen UTF-16-Codeeinheiten, das ist bei Unicode-Kommentaren zu beachten. - Performance: Das Kompilieren kann teuer sein. Module sollten daher einmal erzeugt und wiederverwendet werden, nicht in jedem Frame. Für asynchrones Erstellen von Pipelines gibt es
createRenderPipelineAsync(). - Kompatibilität: WebGPU steht nur in sicheren Kontexten (HTTPS) zur Verfügung. Unterstützt wird es in Chrome/Edge ab 113, in Safari ab 26 und in Firefox ab 141 (zunächst unter Windows). Vorher unbedingt
navigator.gpuprüfen. Auch in Web Workern ist die API verfügbar. - Sicherheit: Die GPU führt Shader-Code aus. Deshalb niemals ungeprüften WGSL-Code von Nutzern ausführen, weil das zu Denial-of-Service durch Endlosschleifen oder Geräteverlust führen kann (
device.lost).