Signatur
Beschreibung
Mit setPipeline() wählt man innerhalb eines Compute-Durchlaufs (GPUComputePassEncoder) die GPUComputePipeline aus. Sie legt fest, welcher Compute-Shader (WGSL-Modul plus Einstiegspunkt) und welches Pipeline-Layout für die folgenden dispatchWorkgroups()- bzw. dispatchWorkgroupsIndirect()-Aufrufe gelten.
Die typische Reihenfolge in einem Compute-Durchlauf ist: commandEncoder.beginComputePass() → setPipeline() → setBindGroup() → dispatchWorkgroups() → end(). Innerhalb eines Durchlaufs kann setPipeline() mehrmals aufgerufen werden, um mehrere Shader nacheinander auszuführen, z. B. für mehrstufige Berechnungen wie Prefix-Summen oder Bildfilter-Ketten.
Die Methode zeichnet einen Befehl nur auf, sie führt nichts sofort aus. Ausgeführt wird erst, wenn der fertige GPUCommandBuffer über device.queue.submit() abgeschickt wird. Fehler werden nicht als Ausnahme geworfen. Sie machen den Encoder ungültig und erscheinen spätestens bei finish() als Validierungsfehler.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $pipeline Pflicht | GPUComputePipeline | Die Compute-Pipeline, die für die folgenden Dispatch-Befehle verwendet werden soll. Sie muss mit demselben GPUDevice erzeugt worden sein wie der Encoder, z. B. über device.createComputePipeline() oder device.createComputePipelineAsync(). |
Rückgabewert
Beispiele
Zahlen in einem Buffer auf der GPU verdoppeln
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({
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({
layout: 'auto',
compute: { module, entryPoint: 'main' }
});
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); // Pipeline festlegen
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();
Mehrere Pipelines nacheinander in einem Durchlauf
// Annahme: device, blurPipeline, sharpenPipeline und die passenden
// Bind Groups wurden bereits erstellt (Bildgröße 512×512, Workgroup 8×8)
const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass({ label: 'Filterkette' });
pass.setPipeline(blurPipeline);
pass.setBindGroup(0, blurBindGroup);
pass.dispatchWorkgroups(512 / 8, 512 / 8);
// Pipeline wechseln: Bind Groups müssen zum neuen Layout passen
pass.setPipeline(sharpenPipeline);
pass.setBindGroup(0, sharpenBindGroup);
pass.dispatchWorkgroups(512 / 8, 512 / 8);
pass.end();
device.queue.submit([encoder.finish()]);
Pipeline asynchron erzeugen und Validierungsfehler abfangen
const pipeline = await device.createComputePipelineAsync({
layout: 'auto',
compute: { module, entryPoint: 'main' }
});
device.pushErrorScope('validation');
const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.dispatchWorkgroups(1); // Bind Group fehlt absichtlich
pass.end();
const commandBuffer = encoder.finish();
const error = await device.popErrorScope();
if (error) {
console.warn('Validierungsfehler:', error.message);
} else {
device.queue.submit([commandBuffer]);
}
// Wichtig · Fallstricke
- Ohne Pipeline kein Dispatch: Wenn
dispatchWorkgroups()aufgerufen wird, bevor eine Pipeline gesetzt wurde, ist das ein Validierungsfehler. Auch Bind Groups, die fehlen oder nicht zum Pipeline-Layout passen, führen zu einem Fehler. - Keine Ausnahmen: Fehler werden nicht synchron geworfen. Sie machen den Encoder ungültig und erscheinen als
GPUValidationError, zum Beispiel überpushErrorScope()/popErrorScope()oder das Eventuncapturederror. - Gleiches Gerät: Pipeline und Encoder müssen von demselben
GPUDevicestammen. layout: 'auto': Automatisch erzeugte Bind-Group-Layouts gelten nur für genau die Pipeline, aus der sie mitgetBindGroupLayout()geholt wurden. Wer Bind Groups für mehrere Pipelines wiederverwenden will, braucht ein explizitesGPUPipelineLayout.- Nur Compute-Pipelines: Für Render-Durchläufe gibt es die eigene Methode
GPURenderPassEncoder.setPipeline(), die eineGPURenderPipelineerwartet. - Leistung: Häufige Pipeline-Wechsel kosten Zeit. Wenn möglich, Dispatches mit derselben Pipeline gruppieren.
- Kompatibilität: WebGPU gibt es nur in sicheren Kontexten (HTTPS). Die Unterstützung hängt von Browser und Plattform ab. Vorher mit
navigator.gpuprüfen und aufnullals Rückgabewert vonrequestAdapter()reagieren.