Start · Sprachen · JavaScript · Referenz · GPUDevice.createComputePipeline()

GPUDevice.createComputePipeline()

Methode

Erstellt synchron eine <code>GPUComputePipeline</code>, die einen Compute-Shader kapselt und in einem <code>GPUComputePassEncoder</code> ausgeführt werden kann.

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

Signatur

GPUDevice.prototype.createComputePipeline(descriptor)

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:
  • layout (GPUPipelineLayout | "auto", Pflicht): explizites Pipeline-Layout oder "auto" für ein Layout, das aus dem Shader abgeleitet wird.
  • compute (Objekt, Pflicht):
    • module (GPUShaderModule): Shader-Modul mit dem WGSL-Code.
    • entryPoint (string, optional): Name der @compute-Funktion. Darf fehlen, wenn das Modul genau einen Compute-Einstiegspunkt hat.
    • constants (Record<string, number>, optional): Werte für override-Konstanten im WGSL-Code, z. B. die Workgroup-Größe.
  • label (string, optional): Name für Debugging und Fehlermeldungen.

Rückgabewert

Typ
GPUComputePipeline
Beschreibung
Die neue Compute-Pipeline. Bei einem Validierungsfehler kommt trotzdem ein Objekt zurück, das aber ungültig ist. Der Fehler wird dann asynchron gemeldet, zum Beispiel über 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);
Verdoppeln-Pipeline

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

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');
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. Deshalb pushErrorScope('validation')/popErrorScope() verwenden oder den Rückgabewert von shaderModule.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 explizites GPUPipelineLayout mit createPipelineLayout() 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) und maxComputeWorkgroupSizeX/Y/Z.
  • Kompatibilität: WebGPU gibt es nur in sicheren Kontexten und noch nicht in allen Browsern bzw. auf allen Plattformen. Vorher navigator.gpu prüfen. In Firefox und Safari ist die Unterstützung neuer und vom Betriebssystem abhängig.