很少提到的Vulkan函数"vkCmdUpdateBuffer()",它用于什么?

Hon*_*ang 4 vulkan

这似乎是一个简单的Vulkan API问题,但我真的找不到搜索互联网后的答案.我注意到有一个Vulkan功能:

void vkCmdUpdateBuffer(
    VkCommandBuffer                             commandBuffer,
    VkBuffer                                    dstBuffer,
    VkDeviceSize                                dstOffset,
    VkDeviceSize                                dataSize,
    const void*                                 pData);
Run Code Online (Sandbox Code Playgroud)

乍一看,我认为它可用于记录命令缓冲区,因为它vkCmd的名称中有前缀,但文档说明了这一点

vkCmdUpdateBuffer仅允许在渲染过程之外.出于同步障碍的目的,此命令被视为"传输"操作.

所以我开始认为它是一个便利函数,它包含缓冲区数据传输操作,就像memcpy()用来将数据从主机复制到设备一样.

然后我的问题是:为什么没有一个Vulkan样本/教程(我已经搜索了所有这些)vkCmdUpdateBuffer()而不是手动处理数据memcpy().我明白了吗?

Nic*_*las 6

所有vkCmd*函数都将命令生成到命令缓冲区中.这个也不例外.它是一个传输命令,和大多数传输命令一样,你不能在渲染过程中完成它们.但是有很多命令缓冲区生成命令在渲染过程中不起作用.

通常,Vulkan内存传输操作仅发生在设备内存之间.主机将某些内容放入设备内存的典型机制是写入映射指针.但根据定义,这要求目标内存可以映射.因此,如果要将内容写入不可映射的内存,则必须将其复制到可映射内存,然后通过vkCmdCopy*函数在可映射内存和不可映射内存之间执行传输操作.

如果您同时进行一系列转移,那就没问题.您可以将一堆内容复制到映射内存中,然后提交包含所有复制操作的批处理,以将数据复制到适当的位置.

但有时候,你只是更新了一小块设备内存.如果它不可映射,那么只需要向GPU获取几千字节的数据就可以做很多工作.在这种情况下,vkCmdUpdateBuffer可能是更好的选择,因为它可以"直接"从CPU内存复制到任何设备内存.

我说"直接",因为这显然不是它正在做的事情.除了它在命令缓冲区中执行它之外,它确实做了你应该做的事情.您可以将CPU数据复制到GPU可映射内存中,然后创建一个命令,将该可映射内存复制到不可映射的内存中.

vkCmdUpdateBuffer做同样的事情.它将数据从您指定的指针/大小复制到可映射的内存中(由命令缓冲区本身提供.这就是它的上限为64KB的原因).这个副本会立即发生,就像你做的那样memcpy,所以当这个函数返回时,你可以用你给它的指针做任何你想做的事情.然后,它在命令缓冲区中创建一个命令,该命令从命令缓冲区中的可映射内存复制到目标内存位置.

此函数的文档明确提供有关将其用于更大传输的警告.也就是说,它告诉你不要这样做.这是为了快速,小巧,一次性更新不可映射的内存.而已.

这就是为什么教程不讨论它的一个原因:它是一个非常特殊的功能,许多新手用户会尝试使用它,因为它比显式代码更容易.但在大多数情况下,他们不应该使用它.