Vulkan 缓冲区内存管理——我们什么时候需要暂存缓冲区?

Vulkan buffer memory management - When do we need staging buffers?

我读了很多关于 Vulkan 内存管理的文章,他们都推荐使用暂存缓冲区来传输到 GPU。 但是我们已经可以创建设备本地和主机可见、主机一致的内存。它可以从 GPU 读取,也可以从 CPU.

写入

这是我认为合理的做法 - 创建一个绑定到设备本地、主机可见且一致的内存的大缓冲区。现在对于所有动态缓冲区,我们只是继续使用此缓冲区中的内存并将缓冲区绑定到该偏移量。

但在大多数示例中,他们创建一个主机可见缓冲区和一个gpu 可见缓冲区并使用copyBuffer 操作进行传输。与仅使用 cpu 和 gpu 都可以访问的一个缓冲区相比,这有什么优势?我只是在谈论缓冲区,而不是纹理。

Create one big buffer bound to a memory which is device local, host visible and coherent.

并不是所有的设备都会有这样的内存堆。所以如果你想便携,你需要考虑到这一点。

如果您 want/have 用来放置缓冲区的内存对主机不可见,那么除了使用暂存缓冲区别无选择。

正如 ratchet freak 所说,设备不需要具有设备本地和主机可见的内存类型。尽管大多数都这样做,但大小可能有限。也许过去几年情况发生了变化,但过去 PCI-E 和 BIOS 限制意味着 256 MB 或 512 MB 是您可以获得的最大容量。最后,CPU 通过 PCI-E 写入的带宽将低于 CPU 自己的内存。因此,即使使用暂存缓冲区使用两倍的总带宽,如果它可以在传输队列上异步完成,它也会最大限度地减少 CPU 和图形管道在该传输上花费的时间。因此,使用暂存缓冲区是否是一个净赢将取决于特定的 CPU 和 GPU 组合,以及您的应用程序在做什么。

但是,在移动设备或集成 GPU 等 SOC 上,使用暂存缓冲区应该很少成功。移动 GPU 不应限制设备本地 + 主机可见的堆大小。查看 vulkan.gpuinfo.org 上的几个 Windows 集成 GPU,看起来现代 Intel 集成 GPU 也没有这样的限制,但 AMD 集成 GPU 仍然有(我只看了一些随机样本,YMMV ).

所有这些使得很难给出明确的"always do X"建议。就个人而言,我通常会这样做:

  • 如果我只想要一个适用于任何地方的代码路径并且不担心性能或内存占用,请使用暂存缓冲区。对于离散 GPU,这可能是一个不错的选择,但对于 integrated/SOC GPU 来说不是最佳选择。
  • 否则,将暂存缓冲区保留为后备路径,但在有足够大可用时使用共享 device-local/host-visible 池。
  • 当我开始尝试获得最后一点性能时,当我有数据显示它是净赢时,然后调整上面的内容以更喜欢带有异步传输的暂存缓冲区,以便在离散 GPU 上进行某些类型的上传。