Vulkan 中动态统一缓冲区的缓冲区内存分配
Buffer memory allocation for Dynamic uniform buffer in Vulkan
我想把这个问题分成三个部分:-
什么是概念limits.minUniformBufferOffsetAlignment为什么我们需要使用它来获得我们需要的对齐并从中导出缓冲区的偏移量它? Vulkan 不能自动区分不同的数据类型及其各自的对齐方式吗?
在 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 计算是如何工作的
这个 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));
1.: 缓冲区大小需要是它的倍数。而且您需要知道您实际上在该缓冲区的哪个部分存储了一些东西,而在哪些地方没有存储。如果您的数据不完全适合您的缓冲区,则它需要更大的倍数。
2.: 你的计算不对。整数算术。结果只有 256.
3.: 无需复制实际上不包含您的数据的缓冲区部分。允许部分复制,只是缓冲区本身更大。
最低 UBO 对齐是对您的限制。也就是说,它告诉您每个 UBO 的开始必须是该对齐的某个倍数。它告诉您必须将数据放在内存中的什么位置,以便系统使用该数据。
这不是 Vulkan 可以自动让您做的事情。 Vulkan 是一个明确的 API:您生活在 它的 限制之内,反之亦然。请注意,OpenGL has the same restriction on UBO data.
这段代码很糟糕,但它是偶然的。 (sizeof(glm::mat4) / uboAlignment)
的结果是 zero,因为整数相除总是会得到 integers。由于标准要求 minUniformBufferOffsetAlignment
不小于 256,因此将 64 除以该值将 总是 产生零,向下舍入。而 0 * uboAlignment
仍然是零。
所以代码剩下的唯一部分是 ((sizeof(glm::mat4) % uboAlignment) > 0 ? uboAlignment : 0)
64 % 256 是 192,即 > 0,所以结果是 uboAlignment
.
所以它有效,但只是偶然。他还不如直接用了minUniformBufferOffsetAlignment
首先,内存映射是一个非常重量级的操作。您永远不应该仅仅为了设置矩阵而映射内存,然后立即取消映射。如果你打算通过映射修改内存,你应该保持映射直到你准备好删除它。这不会抑制性能,阻止您按照允许的使用方法或其他任何方式使用该内存。
其次,正如规范明确概述的那样,如果您创建一个可以用作统一缓冲区的 VkBuffer
,您指定的偏移量必须遵守 minUniformBufferOffsetAlignment
。同样,当使用这样的缓冲区作为 UBO 资源时,您提供的偏移量 必须 也必须与 minUniformBufferOffsetAlignment
对齐,无论偏移量是动态的还是静态的。
我想把这个问题分成三个部分:-
什么是概念limits.minUniformBufferOffsetAlignment为什么我们需要使用它来获得我们需要的对齐并从中导出缓冲区的偏移量它? Vulkan 不能自动区分不同的数据类型及其各自的对齐方式吗?
在 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 计算是如何工作的
这个 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));
1.: 缓冲区大小需要是它的倍数。而且您需要知道您实际上在该缓冲区的哪个部分存储了一些东西,而在哪些地方没有存储。如果您的数据不完全适合您的缓冲区,则它需要更大的倍数。
2.: 你的计算不对。整数算术。结果只有 256.
3.: 无需复制实际上不包含您的数据的缓冲区部分。允许部分复制,只是缓冲区本身更大。
最低 UBO 对齐是对您的限制。也就是说,它告诉您每个 UBO 的开始必须是该对齐的某个倍数。它告诉您必须将数据放在内存中的什么位置,以便系统使用该数据。
这不是 Vulkan 可以自动让您做的事情。 Vulkan 是一个明确的 API:您生活在 它的 限制之内,反之亦然。请注意,OpenGL has the same restriction on UBO data.
这段代码很糟糕,但它是偶然的。
(sizeof(glm::mat4) / uboAlignment)
的结果是 zero,因为整数相除总是会得到 integers。由于标准要求minUniformBufferOffsetAlignment
不小于 256,因此将 64 除以该值将 总是 产生零,向下舍入。而0 * uboAlignment
仍然是零。所以代码剩下的唯一部分是
((sizeof(glm::mat4) % uboAlignment) > 0 ? uboAlignment : 0)
64 % 256 是 192,即 > 0,所以结果是uboAlignment
.所以它有效,但只是偶然。他还不如直接用了
minUniformBufferOffsetAlignment
首先,内存映射是一个非常重量级的操作。您永远不应该仅仅为了设置矩阵而映射内存,然后立即取消映射。如果你打算通过映射修改内存,你应该保持映射直到你准备好删除它。这不会抑制性能,阻止您按照允许的使用方法或其他任何方式使用该内存。
其次,正如规范明确概述的那样,如果您创建一个可以用作统一缓冲区的
VkBuffer
,您指定的偏移量必须遵守minUniformBufferOffsetAlignment
。同样,当使用这样的缓冲区作为 UBO 资源时,您提供的偏移量 必须 也必须与minUniformBufferOffsetAlignment
对齐,无论偏移量是动态的还是静态的。