Vulkan 中动态统一缓冲区的缓冲区内存分配

Bul*_*Bul 2 c++ game-engine game-physics vulkan

我想把这个问题分成 3 部分:-

  1. limit.minUniformBufferOffsetAlignment的概念是什么,为什么我们需要使用它来获取我们所需的对齐方式并从中导出缓冲区的偏移量?Vulkan 不能自动区分不同的数据类型和它们各自的对齐方式吗?

  2. 在 Sascha Willems 示例中,他计算了一个 4X4 矩阵的动态对齐,如下所示

    size_t uboAlignment = vulkanDevice->properties.limits.minUniformBufferOffsetAlignment
    dynamicAlignment = (sizeof(glm::mat4) / uboAlignment) * uboAlignment + ((sizeof(glm::mat4) % uboAlignment) > 0 ? uboAlignment : 0);
    
    Run Code Online (Sandbox Code Playgroud)

    一个 4X4 矩阵是 64 字节,允许的最小对齐大小是 256 字节,但据我所知,他的 dynamicAlignment 计算结果为 (64+256 = 320 //我认为这在 vulkan 中是不允许的) 我不太明白这个dynamicAlignment 是如何实现的计算工作

  3. 这个 dynamicAlignment 变量如何反映到

    VkBufferCreateInfo bufferInfo = {};
    bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    bufferInfo.size = size;
    
    Run Code Online (Sandbox Code Playgroud)

    和内存映射之类的

    void * data;
    vkMapMemory(device, uniformStagingBufferMemory, 0, sizeof(matrix), 0, &data);
    memcpy(data, &matrix, sizeof(matrix));
    vkUnmapMemory(device, uniformStagingBufferMemory);
    copyBuffer(uniformStagingBuffer, uniformBuffer, sizeof(matrix));
    
    Run Code Online (Sandbox Code Playgroud)

Nic*_*las 8

  1. 最低 UBO 对齐是对您的限制。也就是说,它告诉您每个 UBO 的开始必须是该对齐的某个倍数。它告诉您必须将数据放在内存中的哪个位置,以便系统使用该数据。

    这不是 Vulkan 可以自动让您做的事情。Vulkan 是一个明确的 API:您生活在它的限制中,反之亦然。请注意,OpenGL对 UBO 数据具有相同的限制

  2. 这段代码很糟糕,但它是偶然工作的。结果(sizeof(glm::mat4) / uboAlignment),因为整数的除法总是会导致整数。由于minUniformBufferOffsetAlignment标准要求不小于 256,因此 64 除以该值将始终产生零,向下取整。而且0 * uboAlignment还是零。

    所以剩下的代码的唯一部分是((sizeof(glm::mat4) % uboAlignment) > 0 ? uboAlignment : 0)64 % 256 是 192,也就是 > 0,所以结果是uboAlignment.

    所以它有效,但只是偶然。他还不如minUniformBufferOffsetAlignment直接用。

  3. 首先,内存映射是一个非常重量级的操作。您永远不应该仅仅为了设置矩阵而映射内存,然后立即取消映射。如果您打算通过映射修改内存,您应该保持映射直到您准备删除它。这不会抑制性能,阻止您按照允许的使用方法或其他任何方式使用该内存。

    其次,正如规范中明确概述的那样,如果您创建VkBuffer可用作统一缓冲区的 ,则您指定的偏移量必须遵守minUniformBufferOffsetAlignment。同样,当使用这样的缓冲区作为 UBO 资源时,您提供的偏移量也必须对齐minUniformBufferOffsetAlignment,无论偏移量是动态的还是静态的。

  • 如果其他人感到困惑,这只是一个糟糕的变量名问题。“dynamicAlignment”实际上应该是存储统一缓冲区对象所需的大小,以便满足 UBO 之间的对齐要求。换句话说,它只是 UBO 的大小四舍五入到最小对齐要求的最接近倍数。这很难说是一种“结盟”;正如@NicolBolas 提到的,它是一个尺寸。知道了这一点,所提供的代码就不会被破坏。根据记录,Sascha 的示例已更改为使用按位算术,但它在语义上是等效的。 (2认同)