Signatur
Beschreibung
Mit setPipeline() bindest du eine zuvor mit GPUDevice.createRenderPipeline() oder createRenderPipelineAsync() erstellte Render-Pipeline an den aktuellen Render-Pass. Die Pipeline legt fest, welche Vertex- und Fragment-Shader laufen, wie die Vertex-Puffer aufgebaut sind, welcher Primitivtyp gilt (z. B. triangle-list), wie überblendet wird und wie Tiefe und Stencil ausgewertet werden.
Der Aufruf wirkt auf alle folgenden Zeichenbefehle, bis im selben Pass erneut setPipeline() aufgerufen wird. Innerhalb eines Passes darfst du beliebig oft wechseln, etwa erst undurchsichtige Objekte mit einer Pipeline zeichnen und danach durchsichtige mit einer anderen Blend-Einstellung.
Gebundene Ressourcen wie Bind Groups (setBindGroup()) und Vertex-/Index-Puffer (setVertexBuffer(), setIndexBuffer()) bleiben beim Pipeline-Wechsel erhalten. Sie müssen aber zum Layout der neuen Pipeline passen. Die Pipeline muss außerdem mit den Anhängen des Passes kompatibel sein: Farbformate, Tiefen-/Stencil-Format und sampleCount müssen zum GPURenderPassDescriptor passen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $pipeline Pflicht | GPURenderPipeline | Die Render-Pipeline, die für alle folgenden Zeichenbefehle dieses Passes gelten soll. Sie muss vom selben GPUDevice stammen wie der Encoder. |
Rückgabewert
GPUQueue.submit() ausgeführt.Beispiele
Einfaches Dreieck zeichnen
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const canvas = document.querySelector('canvas');
const context = canvas.getContext('webgpu');
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device, format });
const module = device.createShaderModule({
code: `
@vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
var p = array<vec2f, 3>(vec2f(0.0, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5));
return vec4f(p[i], 0.0, 1.0);
}
@fragment fn fs() -> @location(0) vec4f {
return vec4f(1.0, 0.4, 0.0, 1.0);
}`
});
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: { module, entryPoint: 'vs' },
fragment: { module, entryPoint: 'fs', targets: [{ format }] },
primitive: { topology: 'triangle-list' }
});
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
clearValue: { r: 0, g: 0, b: 0, a: 1 },
loadOp: 'clear',
storeOp: 'store'
}]
});
pass.setPipeline(pipeline); // Pipeline vor draw() setzen
pass.draw(3);
pass.end();
device.queue.submit([encoder.finish()]);
Pipeline innerhalb eines Passes wechseln (undurchsichtig/transparent)
// opaquePipeline und blendPipeline wurden mit gleichem Layout erstellt
const renderScene = (pass, { opaquePipeline, blendPipeline, bindGroup, meshes }) => {
pass.setBindGroup(0, bindGroup); // bleibt über den Pipeline-Wechsel erhalten
pass.setPipeline(opaquePipeline);
for (const mesh of meshes.filter((m) => !m.transparent)) {
pass.setVertexBuffer(0, mesh.vertexBuffer);
pass.draw(mesh.vertexCount);
}
pass.setPipeline(blendPipeline);
for (const mesh of meshes.filter((m) => m.transparent)) {
pass.setVertexBuffer(0, mesh.vertexBuffer);
pass.draw(mesh.vertexCount);
}
};
Validierungsfehler abfangen
device.pushErrorScope('validation');
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass(passDescriptor);
pass.setPipeline(pipeline); // z. B. falsches Farbformat im Vergleich zum Anhang
pass.draw(3);
pass.end();
device.queue.submit([encoder.finish()]);
const error = await device.popErrorScope();
if (error) console.error('WebGPU-Fehler:', error.message);
// Wichtig · Fallstricke
- Keine Exception: Ungültige Aufrufe werfen keinen Fehler. Stattdessen wird der Encoder ungültig, und der Fehler zeigt sich erst bei
finish()/submit()als Validierungsfehler. MitpushErrorScope()bzw. dem Eventuncapturederrorkannst du solche Fehler sichtbar machen. - Ohne vorheriges
setPipeline()ist jederdraw()-Aufruf ungültig. - Die Pipeline muss zu den Anhängen des Passes passen: Farbformate,
depthStencil.formatundmultisample.count. Ist beidepthReadOnly/stencilReadOnlyder Tiefen- bzw. Stencil-Anhang schreibgeschützt, darf die Pipeline dort nicht schreiben. - Bei
layout: 'auto'sind die Bind-Group-Layouts an genau diese Pipeline gebunden. Bind Groups lassen sich dann nicht zwischen Pipelines teilen. Für häufige Wechsel solltest du ein explizitesGPUPipelineLayoutverwenden. - Leistung: Ein Pipeline-Wechsel ist vergleichsweise teuer. Sortiere Zeichenaufrufe deshalb nach Pipeline, um unnötige Wechsel zu vermeiden.
- Kompatibilität: WebGPU steht nur in sicheren Kontexten (HTTPS) zur Verfügung. Die Unterstützung wird noch ausgebaut: Chromium ab 113, Safari ab 26, Firefox zunächst unter Windows. Prüfe vorher, ob
navigator.gpuvorhanden ist. - Die gleiche Methode gibt es auch bei
GPURenderBundleEncoder. Bei Compute-Passes heißt das GegenstückGPUComputePassEncoder.setPipeline()und erwartet eineGPUComputePipeline.