一个主机可见缓冲区而不是多个——我应该考虑一些对齐吗?

One host-visible buffer instead of multiple - should I consider some alignment?

假设我有 280 字节的数据。如果我要创建一个缓冲区,那么根据 VkMemoryRequirements 分配的大小应该是 512 字节,对齐 512 - 很清楚。但是我需要 一个主机可见的 大缓冲区,它可以容纳 3 个这样的数据(根据 nvidia 的说法,这比 3 个缓冲区要好)。我不清楚 - 我应该指定 VkBufferCreateInfo::size 等于 280 * 3 还是 512 * 3?如果我让它等于 512 * 3,那是对 space 的浪费。如果我使它等于 280 * 3,那么在映射内存时是否会出现问题?规范提到映射范围应该是 VkPhysicalDeviceLimits::nonCoherentAtomSize 的倍数,但仅适用于在没有 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT 的情况下分配的内存,这不是我的情况。主机一致性内存是否保证字节粒度内存更新?

当您将缓冲区绑定到内存时,memoryOffset 需要是 VkMemoryRequirements 中返回的对齐值的倍数。所以你应该有三个 VkBuffers,每个 280 字节,但是你将把它们绑定为:

// stride = 512 in your example: 512 rounded up to a multiple of 512.
// would still be true if memoryRequirements.size was just 280.
// if 512 < memoryRequirements.size <= 1024, stride would be 1024, etc.
VkDeviceSize stride = round_up(memoryRequirement.size, memoryRequirement.alignment);

vkBindBufferMemory(device, buffer0, memory, 0 * stride);
vkBindBufferMemory(device, buffer1, memory, 1 * stride);
vkBindBufferMemory(device, buffer2, memory, 2 * stride);

因此 VkDeviceMemory 的大小需要 3*memoryRequirements.size,或者在您的示例中为 1536 字节。

nonCoherentAtomSize 独立于所有这些。它本质上是缓存行或内存事务大小。对于非相干内存,如果你在 "non coherent atom" 中写入一个字节,CPU 仍然必须将整个原子写入内存,这意味着你会破坏从GPU。使用一致性内存,CPU 和 GPU 协作,以便它们可以各自写入相邻字节而不会覆盖彼此的数据。但是,如果您使用的是非相干内存,并且想写入您的 VkBuffers 之一,而 GPU 可能正在写入同一 VkDeviceMemory 中的另一个 VkBuffer,您可能想要确保两个 VkBuffers 在缓冲区的同一 nonCoherentAtomSize 块内不重叠。

如果您想创建一个可以容纳 3 * 280 字节数据的缓冲区,那么您需要创建一个可以容纳 3 * 280 字节数据的缓冲区(您需要将此值指定为缓冲区创建期间的大小)。但是它需要多少内存(内存对象应该有多大),这取决于驱动程序。您需要创建一个大小等于 3 * 280 的缓冲区,然后您需要检查它的内存要求,然后分配必要的内存对象(或从更大的内存对象进行子分配)并将此内存绑定到缓冲区。

至于对齐 - 如果您想将单个内存对象的部分绑定到多个资源(缓冲区或图像),这很重要。在您的示例中,您可以创建 3 个可以容纳 280 字节数据的缓冲区。但是(如 vkGetBufferMemoryRequirements() 函数所示)每个这样的缓冲区需要 512 字节的内存对齐到 512 字节。因此,为了 3 个单独的缓冲区,您需要 3 个单独的内存对象,每个大小为 512 字节,或者一个大小为 1536 字节的内存对象。然后,从偏移量 0 开始的内存范围可以绑定到第一个缓冲区,从偏移量 512 到第二个缓冲区,从偏移量 1024 到第三个缓冲区。但是尽管你将 512 字节的内存绑定到你的缓冲区,但不要忘记你的缓冲区仍然只能容纳 280 字节的内存。

在此示例中,大小和对齐方式相同(均为 512)。想象一下这样一种情况,你的大小为 380 字节的缓冲区需要 386 字节的内存对齐到 512。这种情况不会改变任何东西 - 你的第一个缓冲区绑定到偏移量 0(这个偏移量总是满足所有对齐要求),第二个到偏移量 512 和第三个缓冲区到偏移量 1024。一般来说,对齐意味着绑定到资源的内存范围的开始必须是给定对齐值的倍数(从内存对象的开头算起)。

在你的情况下,一个大缓冲区可能更好(就浪费的内存而言 space):3 * 280 等于 840 以及所需内存大小和大小之间的相对差异您的缓冲区可能会更小。