Signatur
Beschreibung
createShaderModule() ist die Methode, mit der Shader-Code an die GPU übergeben wird. Der Quelltext ist in der WebGPU Shading Language (WGSL) geschrieben und wird der Methode als String im Feld code übergeben. Zurück kommt ein GPUShaderModule, das eine oder mehrere Einstiegsfunktionen enthalten kann (markiert mit @vertex, @fragment oder @compute).
Das Modul allein führt noch nichts aus. Du referenzierst es später beim Erstellen einer Pipeline, etwa über createRenderPipeline() im Feld vertex.module bzw. fragment.module oder über createComputePipeline() im Feld compute.module. Zusätzlich gibst du dort den entryPoint an. Hat das Modul nur einen Einstiegspunkt der passenden Stufe, darfst du ihn weglassen.
Die Methode arbeitet synchron und wirft bei Syntaxfehlern keine Ausnahme. Stattdessen entsteht ein ungültiges Modul und es wird ein Validierungsfehler erzeugt, den du mit pushErrorScope()/popErrorScope() oder über das Event uncapturederror abfängst. Detaillierte Diagnosen mit Zeilen- und Spaltenangaben liefert GPUShaderModule.getCompilationInfo().
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $descriptor Pflicht | GPUShaderModuleDescriptor | Objekt, das das Shader-Modul beschreibt. Enthält die folgenden Felder. | |
| $descriptor.code Pflicht | string | Der WGSL-Quellcode des Moduls. | |
| $descriptor.label | string | "" | Name zur Fehlersuche. Er erscheint in Fehlermeldungen und in Entwicklerwerkzeugen. |
| $descriptor.compilationHints | Array<{entryPoint: string, layout?: GPUPipelineLayout | "auto"}> | [] | Optionale Hinweise, mit welchen Einstiegspunkten und Pipeline-Layouts das Modul später genutzt wird. Damit kann der Browser früher kompilieren. |
| $descriptor.sourceMap | object | Optionale Source Map (Format v3) für die Fehlersuche. Browser dürfen sie ignorieren. |
Rückgabewert
GPUShaderModule-Objekt. Bei Fehlern im WGSL-Code ist es ungültig und verursacht Validierungsfehler, sobald eine Pipeline es verwendet.Beispiele
Vertex- und Fragment-Shader für ein Dreieck
const adapter = await navigator.gpu?.requestAdapter();
if (!adapter) throw new Error('WebGPU wird nicht unterstützt');
const device = await adapter.requestDevice();
const shaderModule = 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 pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: { module: shaderModule, entryPoint: 'vs_main' },
fragment: {
module: shaderModule,
entryPoint: 'fs_main',
targets: [{ format: navigator.gpu.getPreferredCanvasFormat() }]
},
primitive: { topology: 'triangle-list' }
});
console.log(shaderModule.label);
Compute-Shader: Array-Werte verdoppeln
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const module = device.createShaderModule({
label: 'Verdoppler',
code: `
@group(0) @binding(0) var<storage, read_write> data: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3u) {
if (id.x < arrayLength(&data)) {
data[id.x] = data[id.x] * 2.0;
}
}
`
});
// entryPoint darf fehlen, weil es nur einen @compute-Einstiegspunkt gibt
const pipeline = device.createComputePipeline({
layout: 'auto',
compute: { module }
});
console.log(pipeline instanceof GPUComputePipeline);
Kompilierfehler mit getCompilationInfo() auswerten
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
device.pushErrorScope('validation');
const module = device.createShaderModule({
label: 'Fehlerhafter Shader',
code: `@fragment fn main() -> @location(0) vec4f { return vec4f(1.0) }` // Semikolon fehlt
});
const error = await device.popErrorScope();
if (error) console.warn('Validierungsfehler:', error.message);
const info = await module.getCompilationInfo();
for (const msg of info.messages) {
console.log(`${msg.type} in Zeile ${msg.lineNum}:${msg.linePos} – ${msg.message}`);
}
// Wichtig · Fallstricke
- Keine Ausnahme bei Fehlern: Fehlerhafter WGSL-Code bringt das Skript nicht zum Absturz. Er erzeugt nur einen Validierungsfehler, der ohne Error-Scope oder
uncapturederror-Handler lediglich in der Konsole erscheint. Wenn Pipelines unerklärlich ungültig sind, prüfegetCompilationInfo(). - Nur WGSL: Anders als bei WebGL gibt es kein GLSL und kein SPIR-V. Bestehende Shader musst du übersetzen, z. B. mit Tools wie naga oder Tint.
- Leistung: Die Kompilierung kann aufwendig sein. Erzeuge Module einmal und verwende sie wieder, statt sie in jedem Frame neu anzulegen. Für nicht blockierende Pipeline-Erstellung gibt es
createRenderPipelineAsync()bzw.createComputePipelineAsync(). - Sicherheit: Baue WGSL-Code nicht ungeprüft aus Benutzereingaben zusammen. Der Browser prüft zwar Speicherzugriffe, aber manipulierter Code kann trotzdem Denial-of-Service auslösen, z. B. durch Endlosschleifen, die zum Geräteverlust führen.
- Kompatibilität: WebGPU gibt es nur in sicheren Kontexten und noch nicht in allen Browsern bzw. auf allen Plattformen. Prüfe vorher
navigator.gpuund das Ergebnis vonrequestAdapter(). Das FeldcompilationHintswird nicht überall ausgewertet.