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

浏览器兼容性

另见