关于调用 vkCmdBindVertexBuffers() 时顶点缓冲区数据的内存对齐偏移倍数的问题

Question regarding the memory alignment offset multiple for Vertex buffer data when calling vkCmdBindVertexBuffers()

我正在为我的游戏框架创建一个基于 Vulkan 的渲染器后端。目前,我正在加载一个包含大约 10,000 个独特三角形(未索引 - 所有单独的三角形)的网格,其中每个顶点都有一个位置值、RGB 值、没有法线也没有纹理坐标。这相当于每个三角形 72 个字节,即。 1 * xyz 浮点数 + 1 * RGB 浮点数 = 每个顶点 6 个浮点数。 6 * 3 个顶点 = 每个三角形 18 个浮点数。 18 * 4 = 每个三角形 72 个字节。顶点数据存储在设置了 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT 标志的 GPU 本地缓冲区中。

我目前还对所有网格使用相同的垂直和碎片着色器,并为 CPU 计算的 MVP 矩阵使用推送常量。

如果我使用 72 的倍数作为 vkCmdBindVertexBuffers() 中的偏移参数,那么我的网格会分解,因为缓冲区中的第一个三角形永远不会被绘制。我逐帧将偏移量增加了 72,这样就可以在没有段错误或错误的情况下溶解网格。 LunarG 标准验证已启用,没有报告验证错误,(我的代码中有很多错误检查和日志记录)。

顺便说一句,如果我不使用 72 的倍数,那么我会得到一些非常有趣的渲染,但不会崩溃!我还在 renderdoc 中的一台六年前的机器上获得了 650fps 的帧速率 运行。

这是绑定顶点缓冲区的代码...

vkCmdBindVertexBuffers, (cmd[swapindex], 0, 1, vertexBuffers, offsets)

现在,这在我的 PC 上运行良好并不意味着它是正确的。我感到困惑的一件事是 Vulkan 规范中关于内存对齐要求的区域,特别是在 VkPhysicalDeviceLimits 中。

VkPhysicalDeviceLimits:minTexelBufferOffsetAlignment中有几个,minUniformBufferOffsetAlignment & minStorageBufferOffsetAlignment。

规范说: 对齐成员满足与 VkBuffer 的使用相关的缓冲区描述符偏移对齐要求:

如果用法包括 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT 或 VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,对齐方式必须是 VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment 的整数倍。

如果包含用法 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,对齐方式必须是 VkPhysicalDeviceLimits::minUniformBufferOffsetAlignment 的整数倍。

如果包含用法 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,对齐方式必须是 VkPhysicalDeviceLimits::minStorageBufferOffsetAlignment 的整数倍。

我正在使用 vkCreateBuffer() 使用 bufferCreateInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT(以及 VK_BUFFER_USAGE_TRANSFER_DST_BIT、VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)在设备本地内存中创建顶点缓冲区。

问题... 由于我没有使用 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT、VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT、VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT 或 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT 创建缓冲区,这是否意味着当我调用时偏移参数没有内存对齐要求vkCmdBindVertexBuffers(cmd, 0, 1, vertexBuffer, 偏移量)?

我问的原因是我想在设置了 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT 标志的单个 vkCreateBuffer() 分配缓冲区中存储多个网格。然后我可以为我需要绘制的每个唯一网格偏移到这个 'super vertex buffer',而无需分配多个顶点缓冲区。我知道分配顶点缓冲区的限制通常是 4096 (VkPhysicalDeviceLimits::maxMemoryAllocationCount) 但我宁愿使用一个 'super buffer' 来提高性能,而不是分配多个顶点缓冲区。

这有意义吗?

更新: 我更改了我的代码以在 vkCmdBindVertexBuffers() 中不使用偏移量,而是在 vkCmdDraw() 中使用 firstVertex 参数作为网格模型偏移量,从而产生了更高且更稳定的 FPS。

我在规范中没有看到任何对齐要求,但我认为这可能是一个疏忽。您可以尝试四舍五入到 16 的倍数;任何实际对齐要求都不太可能大于此。因此,如果您的第一个网格是 5 个三角形,则需要 5*72 个字节,而第二个网格将从偏移量 round_up(5*72, 16)=368 开始。如果这不起作用,您可能在其他地方遇到了错误。

虽然不使用 vkCmdBindVertexBuffers 的偏移量,但您可以只绑定一次完整的顶点缓冲区,并为每次绘制使用 firstVertex 参数来指示缓冲区中网格所在的索引开始。