【问题标题】:Buffer memory allocation for Dynamic uniform buffer in VulkanVulkan 中动态统一缓冲区的缓冲区内存分配
【发布时间】:2017-10-06 18:10:12
【问题描述】:

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

  1. limits.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);
    

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

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

    VkBufferCreateInfo bufferInfo = {};
    bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    bufferInfo.size = size;
    

    和内存映射类似

    void * data;
    vkMapMemory(device, uniformStagingBufferMemory, 0, sizeof(matrix), 0, &data);
    memcpy(data, &matrix, sizeof(matrix));
    vkUnmapMemory(device, uniformStagingBufferMemory);
    copyBuffer(uniformStagingBuffer, uniformBuffer, sizeof(matrix));
    

【问题讨论】:

    标签: c++ game-engine game-physics vulkan


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

      这不是 Vulkan 可以自动让您做的事情。 Vulkan 是一个明确的 API:您生活在 限制内,反之亦然。注意 OpenGL has the same restriction on UBO data.

    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 对齐,无论偏移量是动态的还是静态的。

    【讨论】:

    • 在我的场景中,我有一个 mat4 向量(每个有 64 个字节),它具有许多模型矩阵的统一缓冲区数据,从技术上讲,机器知道向量内每个元素的偏移量是 64 个字节它是倍数,但我告诉 vulkan 为向量内的每个统一数据偏移 256 个字节,这将如何工作?
    • 2 中的代码没有损坏,它完全按照它应该做的。天花板sizeof(glm::mat4)uboAlignment 的下一个倍数。无论uboAlignment 的值(甚至可能小于 64!),或glm::mat4 的大小。
    • @Ext3h: "甚至可能小于 64" 它不能小于 64; Vulkan 规范要求它至少为 256。此外,这样做是一种非常迟钝的方法,因为如果这是您想要的,您可以直接使用 std::max(uboAlignment, sizeof(glm::mat4))
    • @NicolBolas 对,不知道 256 是保证的最小值。然而,std::max 的使用也是完全错误的。如果sizeof(glm::mat4) > uboAlignment && sizeof(glm::mat4) % uboAlignment != 0,缓冲区大小将不再是uboAlignment 的倍数。原始代码是正确的,并且是一种确保正确结果的干净方法。
    • 万一其他人感到困惑,这只是一个糟糕的变量名问题。 “dynamicAlignment”实际上应该是存储统一缓冲区对象所需的大小,以便满足 UBO 之间的对齐要求。换句话说,它只是 UBO 的大小,四舍五入到最接近的最小对齐要求的倍数。这几乎不是“对齐”;正如@NicolBolas 提到的,它是一个大小。知道了这一点,所呈现的代码并没有被破坏。作为记录,Sascha 的示例已更改为使用按位算术,但它在语义上是等价的。
    【解决方案2】:

    1.:缓冲区大小需要是它的倍数。你需要知道你在缓冲区的哪个部分实际存储了一些东西,而你没有在哪里存储。如果您的数据不完全适合您的缓冲区,则它需要以倍数变大。

    2.:您的计算已关闭。整数运算。结果只有 256。

    3.: 无需复制缓冲区中实际上不包含您的数据的部分。允许部分复制,只是缓冲区本身更大。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-23
      • 2021-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-07
      • 2017-12-09
      相关资源
      最近更新 更多