GPURenderBundleEncoder

可用性有限

此特性不是基線特性,因為它在一些最廣泛使用的瀏覽器中不起作用。

安全上下文: 此功能僅在安全上下文(HTTPS)中可用,且支援此功能的瀏覽器數量有限。

注意:此功能在 Web Workers 中可用。

GPURenderBundleEncoder 介面是 WebGPU API 的一部分,用於預先錄製命令包。

命令包是透過呼叫 GPURenderBundleEncoder 的方法來編碼的;一旦所需的命令被編碼完成,它們就會透過 GPURenderBundleEncoder.finish() 方法錄製到一個 GPURenderBundle 物件例項中。然後,這些渲染包可以透過將 GPURenderBundle 物件傳遞給 GPURenderPassEncoder.executeBundles() 呼叫來在多個渲染通道中重複使用。

實際上,這就像一個部分的渲染通道 — GPURenderBundleEncoder 擁有與 GPURenderPassEncoder 相同的功能,只是它們不能開始和結束遮擋查詢,也不能設定裁剪矩形 (scissor rect)、視口 (viewport)、混合常量 (blend constant) 和模板參考值 (stencil reference)。GPURenderBundle 將繼承執行它的 GPURenderPassEncoder 的所有這些值。

注意: 在執行渲染包之前,當前設定的頂點緩衝區、索引緩衝區、繫結組和管線都會被清除,並在渲染包執行完畢後再次清除。

在 JavaScript 繪製呼叫開銷成為瓶頸的情況下,重用預先錄製的命令可以顯著提高應用程式的效能。在同一批物件將在多個檢視或幀中以相同方式繪製,而唯一不同之處在於正在使用的緩衝區內容(例如更新的矩陣統一變數)的情況下,渲染包最為有效。一個很好的例子是 VR 渲染。將渲染過程錄製為渲染包,然後為每個眼睛調整檢視矩陣並重放它,是為場景的兩次渲染髮出繪製呼叫的更有效方法。

GPURenderBundleEncoder 物件例項是透過 GPUDevice.createRenderBundleEncoder() 屬性建立的。

注意: GPURenderBundleEncoder 的方法在功能上與其在 GPURenderPassEncoder 上可用的相應方法是相同的,除了 GPURenderBundleEncoder.finish(),它的目的與 GPUCommandEncoder.finish() 相似。

例項屬性

label

一個字串,提供可用於識別物件的標籤,例如在 GPUError 訊息或控制檯警告中。

例項方法

draw()

根據 setVertexBuffer() 提供的頂點緩衝區繪製圖元。

drawIndexed()

根據 setVertexBuffer()setIndexBuffer() 提供的頂點和索引緩衝區繪製帶索引的圖元。

drawIndirect()

使用從 GPUBuffer 讀取的引數繪製圖元。

drawIndexedIndirect()

使用從 GPUBuffer 讀取的引數繪製帶索引的圖元。

finish()

完成當前渲染通道命令序列的錄製。

insertDebugMarker()

使用標籤在一系列已編碼命令中的特定點進行標記。

popDebugGroup()

結束一個除錯組,該除錯組由 pushDebugGroup() 呼叫開始。

pushDebugGroup()

開始一個除錯組,該除錯組帶有指定的標籤,並將包含所有後續編碼的命令,直到呼叫 popDebugGroup() 方法為止。

setBindGroup()

為指定的索引設定將用於後續渲染包命令的 GPUBindGroup

setIndexBuffer()

設定當前將為後續繪製命令提供索引資料的 GPUBuffer

setPipeline()

設定此渲染包使用的 GPURenderPipeline

setVertexBuffer()

設定或取消設定當前將為後續繪製命令提供頂點資料的 GPUBuffer

示例

在 WebGPU 示例 Animometer 示例中,許多類似的操作同時在許多不同的物件上進行。命令包使用以下函式進行編碼:

js
function recordRenderPass(
  passEncoder: GPURenderBundleEncoder | GPURenderPassEncoder
) {
  if (settings.dynamicOffsets) {
    passEncoder.setPipeline(dynamicPipeline);
  } else {
    passEncoder.setPipeline(pipeline);
  }
  passEncoder.setVertexBuffer(0, vertexBuffer);
  passEncoder.setBindGroup(0, timeBindGroup);
  const dynamicOffsets = [0];
  for (let i = 0; i < numTriangles; ++i) {
    if (settings.dynamicOffsets) {
      dynamicOffsets[0] = i * alignedUniformBytes;
      passEncoder.setBindGroup(1, dynamicBindGroup, dynamicOffsets);
    } else {
      passEncoder.setBindGroup(1, bindGroups[i]);
    }
    passEncoder.draw(3, 1, 0, 0);
  }
}

稍後,會建立一個 GPURenderBundleEncoder,呼叫該函式,然後使用 GPURenderBundleEncoder.finish() 將命令包錄製到 GPURenderBundle 中。

js
const renderBundleEncoder = device.createRenderBundleEncoder({
  colorFormats: [presentationFormat],
});
recordRenderPass(renderBundleEncoder);
const renderBundle = renderBundleEncoder.finish();

然後使用 GPURenderPassEncoder.executeBundles() 在多個渲染通道中重用該工作以提高效能。請參閱示例程式碼列表以獲取完整上下文。

js
// …

return function doDraw(timestamp) {
  if (startTime === undefined) {
    startTime = timestamp;
  }
  uniformTime[0] = (timestamp - startTime) / 1000;
  device.queue.writeBuffer(uniformBuffer, timeOffset, uniformTime.buffer);

  renderPassDescriptor.colorAttachments[0].view = context
    .getCurrentTexture()
    .createView();

  const commandEncoder = device.createCommandEncoder();
  const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);

  if (settings.renderBundles) {
    passEncoder.executeBundles([renderBundle]);
  } else {
    recordRenderPass(passEncoder);
  }

  passEncoder.end();
  device.queue.submit([commandEncoder.finish()]);
};

// …

規範

規範
WebGPU
# gpurenderbundle

瀏覽器相容性

另見