CommandEncoder
命令录制器:把多个通道、拷贝与查询按顺序写进一条命令流,
finish() 得到不可变的命令缓冲。
设备还提供一个默认编码器 device.commandEncoder,device.beginRenderPass 等便捷方法用的就是它。
方法
| 方法 | 返回 | 说明 |
|---|---|---|
beginRenderPass(props?) | RenderPass | 在本编码器上开始渲染通道 |
beginComputePass(props?) | ComputePass | 在本编码器上开始计算通道 |
copyBufferToBuffer(options) | void | 缓冲区之间的区域拷贝 |
copyBufferToTexture(options) | void | 缓冲区内容写入纹理 |
copyTextureToBuffer(options) | void | 纹理内容读入缓冲区 |
copyTextureToTexture(options) | void | 纹理之间的区域拷贝 |
resolveQuerySet() | void | 把查询结果解析到缓冲区 |
finish() | CommandBuffer | 结束录制并锁死编码器 |
pushDebugGroup(label) / popDebugGroup() | void | 命令流分组标记 |
insertDebugMarker(label) | void | 单点标记,便于在调试工具里定位 |
显式录制
const encoder = device.createCommandEncoder({ id: 'frame' });
/* 第一趟:离屏渲染 */
const offscreen = encoder.beginRenderPass({
framebuffer: fbo,
clearColor: [0, 0, 0, 1]
});
offscreen.setPipeline(offscreenPipeline);
offscreen.setVertexArray(quadArray);
offscreen.draw({ vertexCount: 6 });
offscreen.end();
/* 第二趟:画到画布 */
const screen = encoder.beginRenderPass({
clearColor: [0.04, 0.06, 0.09, 1]
});
screen.setPipeline(postPipeline);
screen.setVertexArray(quadArray);
screen.setBindings({ uScene: colorTexture });
screen.draw({ vertexCount: 6 });
screen.end();
const commandBuffer = encoder.finish();
device.submit(commandBuffer);
通道属于创建它的编码器,调用 end() 只是结束通道,
不会单独产生可提交对象。真正的提交点在 finish() 之后的 device.submit。
拷贝命令的位置
拷贝不必包在通道里:它们直接记录到编码器,与通道按记录顺序执行。 需要「先渲染到纹理,再拷到缓冲区回读」时,两件事放在同一个编码器里, 顺序由调用先后保证。
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
framebuffer: fbo,
clearColor: [0.1, 0.2, 0.3, 1]
});
pass.end();
encoder.copyTextureToBuffer(copyOptions);
device.submit(encoder.finish());
const pixels = await readbackBuffer.readAsync();
跨编码器的命令没有顺序保证。先写的渲染、后写的拷贝如果分属两个编码器, 必须分成两次提交,或在第二次提交前等待第一次完成。
录制完成后不可复用
finish() 会锁死编码器,之后再调用任何记录方法都会失败。
每帧新建一个编码器,不要跨帧缓存。
命令缓冲继承编码器的 id 与 userData,便于调试定位。
WebGL 的执行差异
WebGL 后端没有真正的延迟执行,通道状态与清除在记录时就地生效, 拷贝命令推迟到提交时回放。代码结构可以保持与 WebGPU 相同, 但不要指望在 WebGL 上通过「先记录、后修改资源」来得到快照语义。
计算通道在 WebGL 上不可用。 在 WebGL 后端创建计算通道会抛错。需要同一份代码跑两种后端时, 把计算能力隔离成可选模块,而不是在启动时无条件创建。
经纬志(2026)。《CommandEncoder》。https://www.jingweizhi.com/lumagl/api/command-encoder.html(访问日期 2026-11-03)。