Signatur
Beschreibung
Mit setPipeline() legst du fest, welche GPURenderPipeline (Shader, Vertex-Layout, Primitiv-Topologie, Blending, Tiefen-/Stencil-Zustand) für die folgenden draw()-, drawIndexed()-, drawIndirect()- und drawIndexedIndirect()-Aufrufe innerhalb eines Render-Bündels gilt. Ohne gesetzte Pipeline sind Zeichenbefehle ungültig.
Ein GPURenderBundleEncoder zeichnet eine Befehlsfolge einmal auf. Mit finish() wird daraus ein GPURenderBundle, das du in beliebig vielen Render-Passes über GPURenderPassEncoder.executeBundles() erneut abspielen kannst. Das spart CPU-Aufwand, wenn sich statische Szenenteile wie Gelände, Umgebung oder UI-Hintergrund Frame für Frame nicht ändern.
Du kannst setPipeline() innerhalb eines Bündels mehrmals aufrufen, um zwischen Pipelines zu wechseln. Bind-Groups und Vertex-Puffer bleiben dabei gesetzt, müssen aber zum Layout der neuen Pipeline passen. Die Pipeline muss mit dem Bündel kompatibel sein. Die colorFormats, das depthStencilFormat und der sampleCount aus createRenderBundleEncoder() müssen also zu den fragment.targets, zum depthStencil.format und zu multisample.count der Pipeline passen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $pipeline Pflicht | GPURenderPipeline | Die Render-Pipeline für die nachfolgenden Zeichenbefehle. Erzeugt mit GPUDevice.createRenderPipeline() oder createRenderPipelineAsync(), und zwar auf demselben GPUDevice wie der Encoder. |
Rückgabewert
Beispiele
Einfaches Render-Bündel mit einem Dreieck
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const format = navigator.gpu.getPreferredCanvasFormat();
const module = device.createShaderModule({
code: `
@vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
var p = array(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 }] },
});
// colorFormats muss zu fragment.targets passen
const bundleEncoder = device.createRenderBundleEncoder({ colorFormats: [format] });
bundleEncoder.setPipeline(pipeline);
bundleEncoder.draw(3);
const bundle = bundleEncoder.finish();
console.log(bundle instanceof GPURenderBundle);
Bündel in jedem Frame wiederverwenden
// Voraussetzung: device, format, bundle aus dem vorigen Beispiel
const canvas = document.querySelector('canvas');
const context = canvas.getContext('webgpu');
context.configure({ device, format });
const frame = () => {
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.executeBundles([bundle]); // Pipeline + draw kommen aus dem Bündel
pass.end();
device.queue.submit([encoder.finish()]);
requestAnimationFrame(frame);
};
requestAnimationFrame(frame);
Mehrere Pipelines in einem Bündel
// opaquePipeline und transparentPipeline: gleiche colorFormats/depthStencil-Formate
const be = device.createRenderBundleEncoder({
colorFormats: [format],
depthStencilFormat: 'depth24plus',
});
be.setPipeline(opaquePipeline);
be.setBindGroup(0, sceneBindGroup);
be.setVertexBuffer(0, terrainVertices);
be.draw(terrainVertexCount);
be.setPipeline(transparentPipeline); // Wechsel innerhalb des Bündels
be.setVertexBuffer(0, waterVertices);
be.draw(waterVertexCount);
const staticScene = be.finish({ label: 'statische Szene' });
// Wichtig · Fallstricke
- Validierungsfehler statt Exception: Eine inkompatible Pipeline (falsches Farbformat, abweichendes
depthStencilFormatoder anderersampleCount) wirft keinen JavaScript-Fehler. Stattdessen macht sie den Encoder ungültig. Der Fehler zeigt sich erst beifinish()bzw. überdevice.pushErrorScope('validation')oder das Ereignisuncapturederror. - Hat die Pipeline ein
depthStencilmitdepthWriteEnabled: true, darf das Bündel nicht mitdepthReadOnly: trueerzeugt worden sein. Dasselbe gilt für Stencil-Schreibzugriffe undstencilReadOnly. - Render-Bündel erben keinen Zustand aus dem Render-Pass. Pipeline, Bind-Groups und Puffer müssen im Bündel selbst gesetzt werden. Umgekehrt ist der Zustand des Passes nach
executeBundles()zurückgesetzt, und du musstsetPipeline()dort erneut aufrufen. - Dynamische Zustände wie
setViewport(),setScissorRect()odersetBlendConstant()gibt es im Bündel-Encoder nicht. Sie werden am Render-Pass gesetzt. - Nach
finish()ist der Encoder verbraucht. Weitere Aufrufe vonsetPipeline()erzeugen einen Validierungsfehler. - Kompatibilität: WebGPU läuft nur in sicheren Kontexten und ist noch nicht überall verfügbar. Prüfe vorher mit
if (!navigator.gpu)und sieh eine Ausweichlösung vor, etwa WebGL.