Start · Sprachen · JavaScript · Referenz · GPUComputePassEncoder.setPipeline()

GPUComputePassEncoder.setPipeline()

Methode

Legt die <code>GPUComputePipeline</code> fest, die bei nachfolgenden <code>dispatchWorkgroups()</code>-Aufrufen dieses Compute-Durchlaufs verwendet wird.

seit JavaScript WebGPU – Chrome/Edge 113+, Safari 26+, Firefox 141 Kategorie: webapi

Signatur

GPUComputePassEncoder.prototype.setPipeline(pipeline)

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

Typ
undefined
Beschreibung
Kein Rückgabewert. Der Befehl wird im Encoder aufgezeichnet.

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();
[2, 4, 6, 8]

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]);
}
Validierungsfehler: … (Meldung hängt vom Browser ab, z. B. fehlende Bind Group an Index 0)

// 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 über pushErrorScope()/popErrorScope() oder das Event uncapturederror.
  • Gleiches Gerät: Pipeline und Encoder müssen von demselben GPUDevice stammen.
  • layout: 'auto': Automatisch erzeugte Bind-Group-Layouts gelten nur für genau die Pipeline, aus der sie mit getBindGroupLayout() geholt wurden. Wer Bind Groups für mehrere Pipelines wiederverwenden will, braucht ein explizites GPUPipelineLayout.
  • Nur Compute-Pipelines: Für Render-Durchläufe gibt es die eigene Methode GPURenderPassEncoder.setPipeline(), die eine GPURenderPipeline erwartet.
  • 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.gpu prüfen und auf null als Rückgabewert von requestAdapter() reagieren.