Start · Sprachen · JavaScript · Referenz · GPURenderPassEncoder.executeBundles()

GPURenderPassEncoder.executeBundles()

Methode

Führt die in einem oder mehreren <code>GPURenderBundle</code>-Objekten vorab aufgezeichneten Zeichenbefehle innerhalb des aktuellen Render-Passes aus.

seit JavaScript WebGPU – Chrome/Edge 113+, Firefox 141+ (Windows), Kategorie: webapi

Signatur

GPURenderPassEncoder.prototype.executeBundles(bundles)

Beschreibung

executeBundles() spielt Befehle ab, die vorher mit einem GPURenderBundleEncoder aufgezeichnet und per finish() zu einem GPURenderBundle abgeschlossen wurden. Ein solches Bundle enthält typischerweise setPipeline(), setBindGroup(), setVertexBuffer(), setIndexBuffer() und draw*()-Aufrufe. Die Bundles werden in der übergebenen Reihenfolge ausgeführt.

Render-Bundles sind dafür gedacht, die CPU-Last in JavaScript zu senken: Statt in jedem Frame hunderte Zeichenbefehle neu zu kodieren und zu validieren, zeichnet man sie einmal auf und verwendet sie in beliebig vielen Frames und Render-Passes wieder. Das lohnt sich vor allem bei statischen oder selten veränderten Szenenteilen (Umgebung, Gelände, UI-Hintergründe). Dynamische Daten lassen sich trotzdem ändern, indem man den Inhalt der referenzierten Buffer (z. B. Uniforms) per queue.writeBuffer() aktualisiert.

Wichtig: Nach dem Aufruf wird der Zustand des Render-Pass-Encoders zurückgesetzt – gesetzte Pipeline, Bind-Groups, Vertex- und Index-Buffer gelten danach nicht mehr. Wer im selben Pass weitere normale Zeichenbefehle absetzen will, muss diese Zustände neu setzen. Viewport, Scissor-Rechteck, Blend-Konstante und Stencil-Referenz werden dagegen nicht im Bundle gespeichert, sondern vom Render-Pass übernommen.

Parameter

Name Typ Default Beschreibung
$bundles Pflicht Iterable<GPURenderBundle> Ein Array (oder anderes Iterable) von GPURenderBundle-Objekten, deren aufgezeichnete Befehle in dieser Reihenfolge ausgeführt werden. Ein leeres Array ist erlaubt und setzt lediglich den Encoder-Zustand zurück.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Validierungsfehler werden nicht geworfen, sondern machen den Encoder ungültig und erscheinen später als GPU-Fehler (z. B. über device.pushErrorScope() oder das uncapturederror-Event).

Beispiele

Render-Bundle einmal aufzeichnen, jeden Frame ausführen

// Voraussetzung: device, context, pipeline und vertexBuffer existieren bereits
const format = navigator.gpu.getPreferredCanvasFormat();

// 1. Bundle einmalig aufzeichnen
const bundleEncoder = device.createRenderBundleEncoder({
  colorFormats: [format] // muss zum Render-Pass passen
});
bundleEncoder.setPipeline(pipeline);
bundleEncoder.setVertexBuffer(0, vertexBuffer);
bundleEncoder.draw(3);
const triangleBundle = bundleEncoder.finish({ label: 'Dreieck-Bundle' });

// 2. In jedem Frame nur noch abspielen
const frame = () => {
  const encoder = device.createCommandEncoder();
  const pass = encoder.beginRenderPass({
    colorAttachments: [{
      view: context.getCurrentTexture().createView(),
      clearValue: { r: 0.1, g: 0.1, b: 0.1, a: 1 },
      loadOp: 'clear',
      storeOp: 'store'
    }]
  });
  pass.executeBundles([triangleBundle]);
  pass.end();
  device.queue.submit([encoder.finish()]);
  requestAnimationFrame(frame);
};
requestAnimationFrame(frame);

Statische Szene per Bundle, dynamische Objekte direkt zeichnen

// staticBundles: Array von GPURenderBundle für Gelände, Gebäude usw.
const renderScene = (pass, staticBundles, player) => {
  // Viewport gilt auch für die Bundles
  pass.setViewport(0, 0, canvas.width, canvas.height, 0, 1);

  // Statische Objekte in einem Rutsch
  pass.executeBundles(staticBundles);

  // ACHTUNG: Zustand wurde zurückgesetzt – alles neu setzen!
  pass.setPipeline(player.pipeline);
  pass.setBindGroup(0, player.bindGroup);
  pass.setVertexBuffer(0, player.vertexBuffer);
  pass.setIndexBuffer(player.indexBuffer, 'uint16');
  pass.drawIndexed(player.indexCount);
};

Formatfehler im Bundle abfangen

device.pushErrorScope('validation');

const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass(renderPassDescriptor);
// Bundle wurde mit colorFormats ['rgba8unorm'] erstellt,
// der Pass rendert aber in 'bgra8unorm' → ungültig
pass.executeBundles([mismatchedBundle]);
pass.end();
device.queue.submit([encoder.finish()]);

const error = await device.popErrorScope();
if (error) {
  console.warn('Bundle passt nicht zum Pass:', error.message);
}
Bundle passt nicht zum Pass: ... (browserabhängige Fehlermeldung)

// Wichtig · Fallstricke

  • Zustand wird zurückgesetzt: Nach executeBundles() sind Pipeline, Bind-Groups sowie Vertex- und Index-Buffer des Passes nicht mehr gesetzt. Folgende draw()-Aufrufe ohne erneutes setPipeline() sind ungültig.
  • Kompatibilität der Attachments: colorFormats, depthStencilFormat und sampleCount des Bundles müssen exakt zum Render-Pass passen. Wurde das Bundle ohne depthReadOnly/stencilReadOnly erstellt, darf der Pass das jeweilige Aspekt nicht schreibgeschützt nutzen.
  • Bundles erben keinen Zustand vom Pass (außer Viewport, Scissor, Blend-Konstante und Stencil-Referenz) und hinterlassen keinen – jedes Bundle muss seine Pipeline und Bind-Groups selbst setzen.
  • Referenzierte Buffer dürfen beim Ausführen nicht zerstört sein; ihr Inhalt kann aber zwischen Frames verändert werden.
  • Fehler werden asynchron über das WebGPU-Fehlermodell gemeldet, nicht als JavaScript-Ausnahme.
  • Kompatibilität: WebGPU ist nur in sicheren Kontexten (HTTPS) verfügbar und noch nicht in allen Browsern bzw. Plattformen aktiviert – vorher navigator.gpu prüfen.