这似乎是一个简单的Vulkan API问题,但是在搜索Internet之后,我真的找不到答案。 我注意到有一个Vulkan函数:
void vkCmdUpdateBuffer(
VkCommandBuffer commandBuffer,
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
const void* pData);
乍一看,我认为它可以用来记录命令缓冲区,因为它的名称中带有前缀vkCmd
,但是文档说
vkCmdUpdateBuffer仅在渲染过程之外被允许。出于同步屏障的目的,此命令被视为“传输”操作。
因此,我开始认为这是一个便利功能,它包装缓冲区数据传输操作,例如使用memcpy()
将数据从主机复制到设备。
然后我的问题是:为什么没有使用vkCmdUpdateBuffer()
而不是通过memcpy()
手动处理数据的单个Vulkan示例/教程(我已经搜索了所有示例)。我理解错了吗?
答案 0 :(得分:5)
所有vkCmd*
函数都将命令生成到命令缓冲区中。这也不例外。这是一个传输命令,和大多数传输命令一样,您不必在渲染过程中执行它们。但是有很多命令缓冲区生成的命令在渲染过程中不起作用。
通常,Vulkan内存传输操作仅在设备内存之间发生。主机将某些内容放入设备内存的典型机制是写入映射的指针。但是根据定义,这要求目标内存是可映射的。因此,如果您想将某些内容写入不可映射的内存,则必须将其复制到可映射的内存,然后通过vkCmdCopy*
函数在可映射的内存与不可映射的内存之间进行传输操作。
如果您一次完成一堆传输,那就很好了。您可以将一堆东西复制到映射的内存中,然后提交包含所有复制操作的批处理,以将数据复制到适当的位置。
但是有时候,您只是在更新一小部分设备内存。如果它不是可映射的,那么要做很多工作就是将几千字节的数据发送到GPU。在这种情况下,vkCmdUpdateBuffer
可能是更好的选择,因为它可以“直接”从CPU内存复制到任何设备内存。
我之所以说“直接”,是因为这显然不是它在做什么。除了在命令缓冲区内执行操作外,它实际上执行的操作与执行操作相同。您将已将CPU数据复制到GPU可映射的内存中,然后创建了一个命令,将从该可映射的内存复制到不可映射的内存中。
vkCmdUpdateBuffer
的作用完全相同。它将数据从您给它的指针/大小中复制到可映射的内存中(由命令缓冲区本身提供。这就是为什么它的上限为64KB)的原因。该复制会立即发生,就像您执行memcpy
一样,因此,当此函数返回时,您可以使用给它的指针进行任何操作。然后,它将在命令缓冲区中创建一条命令,该命令将从命令缓冲区中的可映射内存复制到目标内存位置。
The documentation for this function明确给出有关将其用于较大传输的警告。也就是说,它告诉您不要这样做。这是用于快速,小型一次性修改不可映射的内存。没什么。
这是教程之所以不谈论它的原因之一:这是一种非常特殊的功能,许多新手用户都会尝试使用,因为它比显式代码更容易。但是在大多数情况下,他们不应该使用它。