对于渲染到
<canvas>
,似乎 navigator.getPreferredCanvasFormat()
是获得有效格式的唯一方法。
根据 文档,它将始终返回
rgba8unorm
或 bgra8unorm
,这两种 f32
类型。如果我尝试将格式设置为除这些之外的任何格式,例如到 rgba8uint
,我在渲染时得到 GPUCanvasContext.getCurrentTexture: Canvas not configured
。
但是文档暗示其他格式是可能的,通过陈述
如果您在配置画布时不使用首选格式 上下文,您可能会产生额外的开销,例如额外的纹理 副本,具体取决于平台。
即使最后的渲染步骤无论如何都发生在 GPU 上,似乎效率很低。必须使用每通道 4B = 4x4 字节浮点数 = 每像素 16B,而不是每通道 1 字节(每像素 4B)。浪费?
如果我可以降低带宽成本,我很乐意接受纹理转换。
我在这里遗漏了什么吗?这可能吗?
您可以渲染到您自己实例化的非画布纹理。
const nonScreenTexture = device.createTexture({});
这些纹理不适合直接绘制到屏幕上。
如果您使用 TypeScript 类型 (@webgpu/types) 并查看
GPUTextureFormat
格式列表,您将看到有很多很多选项。如果您使用扩展,对于某些有损压缩游戏行业格式,还有更多扩展。
canvas
目前支持的两种格式是rgba8unorm
和bgra8unorm
。这些是将发送到 Vulkan/DirectX/Metal 后端的 SDR 格式,与操作系统需要绘制的其他内容进行合成,并放在屏幕上。一种格式 (rgba) 常见于手持设备。另一种格式 (bgra) 常见于台式机/笔记本电脑。如果您为正确的设备提供正确的格式,则不会产生额外的副本。如果您给它的格式错误,它会将其交换为正确的格式。 ...即使它支持更多格式,当您提交它时,WebGPU 将其提交给 Vulkan/DX/Metal,它会复制它并将其转换为其中一种格式。
这里没有节省空间,因为如果你谈论的是画布纹理的格式,它不是你可以触摸或控制的东西。浏览器内部结构和计算机的图形驱动程序会这样做。为了支持空间节省,您将谈论您自己的 Chrome 构建,使用自定义 Dawn / ANGLE 分叉,以节省 DX/Vulkan SDR 绘制调用上的位...
但他们正在努力为 WebGPU 添加广色域和 HDR 支持(他们已经在 2D 画布和 CSS 中实现了)。我面前的这台显示器是 12bpp、HDR、98% DCI-P3 和一大块 BT2020,误差很低。为了使 WebGPU 能够像支持桌面 GPU 的应用程序一样执行(而不仅仅是窄色域 SDR),它需要每像素处理“更多”位,而不是更少。你最终会得到像 DXGI_FORMAT_R11G11B10
这样的东西,它可能仍然是 32 位,但显然,根本没有以同样的方式分解。