GPURenderBundleEncoder
注意:此功能在 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() 相似。
实例属性
实例方法
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 示例中,许多类似的操作同时在许多不同的对象上进行。命令包使用以下函数进行编码:
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 中。
const renderBundleEncoder = device.createRenderBundleEncoder({
colorFormats: [presentationFormat],
});
recordRenderPass(renderBundleEncoder);
const renderBundle = renderBundleEncoder.finish();
然后使用 GPURenderPassEncoder.executeBundles() 在多个渲染通道中重用该工作以提高性能。请参阅示例代码列表以获取完整上下文。
// …
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 |
浏览器兼容性
加载中…