Signatur
Beschreibung
createComputePipeline() legt eine Compute-Pipeline an. Sie besteht aus einem Compute-Shader-Einstiegspunkt aus einem GPUShaderModule und einem Pipeline-Layout, das festlegt, welche Ressourcen (Buffer, Texturen, Sampler) der Shader über Bind Groups bekommt. Compute-Pipelines braucht man für allgemeine Berechnungen auf der GPU (GPGPU): Bildfilter, Partikelsimulationen, Physik, Matrixrechnungen oder Inferenz von ML-Modellen.
Die Pipeline wird mit passEncoder.setPipeline(pipeline) in einem Compute-Pass gesetzt. Danach bindet man mit setBindGroup() Ressourcen und startet die Arbeit mit dispatchWorkgroups(). Für das Layout kann man ein explizites GPUPipelineLayout übergeben oder "auto" nutzen. Dann leitet WebGPU das Layout aus dem Shader ab, und man holt sich die Bind-Group-Layouts mit pipeline.getBindGroupLayout(index).
Die Methode arbeitet synchron. Das Kompilieren kann aber den GPU-Prozess aufhalten. Die asynchrone Variante createComputePipelineAsync() gibt ein Promise zurück, das erst erfüllt wird, wenn die Pipeline fertig ist. Sie ist deshalb für große Shader oder beim Laden der Anwendung meist die bessere Wahl.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $descriptor Pflicht | GPUComputePipelineDescriptor | Konfigurationsobjekt mit folgenden Eigenschaften:
|
Rückgabewert
popErrorScope() oder das Ereignis uncapturederror.Beispiele
Einfache Pipeline mit layout: "auto"
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: 'Verdoppeln',
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;
}
}
`,
});
const pipeline = device.createComputePipeline({
label: 'Verdoppeln-Pipeline',
layout: 'auto',
compute: { module, entryPoint: 'main' },
});
console.log(pipeline.label);
Pipeline ausführen und Ergebnis zurücklesen
// setzt device und pipeline aus dem vorigen Beispiel voraus
const input = new Float32Array([1, 2, 3, 4]);
const storage = device.createBuffer({
size: input.byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(storage, 0, input);
const readback = device.createBuffer({
size: input.byteLength,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
});
const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{ binding: 0, resource: { buffer: storage } }],
});
const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(Math.ceil(input.length / 64));
pass.end();
encoder.copyBufferToBuffer(storage, 0, readback, 0, input.byteLength);
device.queue.submit([encoder.finish()]);
await readback.mapAsync(GPUMapMode.READ);
console.log(Array.from(new Float32Array(readback.getMappedRange())));
readback.unmap();
Override-Konstanten und Fehlerbehandlung
const module = device.createShaderModule({
code: `
override WG_SIZE: u32 = 64;
@group(0) @binding(0) var<storage, read_write> data: array<u32>;
@compute @workgroup_size(WG_SIZE)
fn main(@builtin(global_invocation_id) id: vec3u) {
if (id.x < arrayLength(&data)) { data[id.x] = id.x; }
}
`,
});
device.pushErrorScope('validation');
const pipeline = device.createComputePipeline({
label: 'Index-Pipeline',
layout: 'auto',
compute: { module, entryPoint: 'main', constants: { WG_SIZE: 128 } },
});
const error = await device.popErrorScope();
console.log(error ? `Fehler: ${error.message}` : 'Pipeline gültig');
// Wichtig · Fallstricke
- Keine Exception bei Fehlern: Ein falscher
entryPoint, Fehler im Shader oder ein Layout, das nicht zum Shader passt, werfen keine Exception. Man bekommt ein ungültiges Pipeline-Objekt, und der Fehler erscheint erst später. DeshalbpushErrorScope('validation')/popErrorScope()verwenden oder den Rückgabewert vonshaderModule.getCompilationInfo()prüfen. - Blockierende Kompilierung: Bei großen Shadern kann der synchrone Aufruf das Rendern spürbar ausbremsen. Besser
createComputePipelineAsync()nehmen. Dort wird ein Validierungsfehler als abgelehntes Promise gemeldet (GPUPipelineError). layout: \"auto\": Ein automatisch erzeugtes Bind-Group-Layout gehört genau zu einer Pipeline und lässt sich nicht mit anderen Pipelines teilen. Wenn mehrere Pipelines dieselben Bind Groups nutzen sollen, ein explizitesGPUPipelineLayoutmitcreatePipelineLayout()anlegen. Außerdem lässt\"auto\"Bindungen weg, die der Shader-Einstiegspunkt gar nicht nutzt.- Limits: Die Workgroup-Größe darf die Geräte-Limits nicht überschreiten. Maßgeblich sind
maxComputeInvocationsPerWorkgroup(meist 256) undmaxComputeWorkgroupSizeX/Y/Z. - Kompatibilität: WebGPU gibt es nur in sicheren Kontexten und noch nicht in allen Browsern bzw. auf allen Plattformen. Vorher
navigator.gpuprüfen. In Firefox und Safari ist die Unterstützung neuer und vom Betriebssystem abhängig.