我想把这个问题分成三个部分:-
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 变量如何反射(reflect)到
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));
最佳答案
最低 UBO 对齐是对您的限制。也就是说,它告诉您每个 UBO 的开始必须是该对齐的某个倍数。它告诉您必须将数据放在内存中的什么位置,以便系统使用该数据。
这不是 Vulkan 可以自动让您做的事情。 Vulkan 是一个明确的 API:您生活在它的限制之内,反之亦然。请注意,OpenGL has the same restriction on UBO data .
这段代码很糟糕,但它是偶然的。
(sizeof(glm::mat4)/uboAlignment)
的结果是零,因为整数除法总是得到整数。由于标准要求minUniformBufferOffsetAlignment
不小于 256,因此将 64 除以该值将总是产生零,向下舍入。而0 * uboAlignment
仍然是零。所以代码剩下的唯一部分是
((sizeof(glm::mat4) % uboAlignment) > 0 ? uboAlignment : 0)
64 % 256 是 192,也就是 > 0,所以结果是uboAlignment
。所以它有效,但只是偶然。他还不如直接使用
minUniformBufferOffsetAlignment
。首先,内存映射是非常的重量级操作。您永远不应该仅仅为了设置矩阵而映射内存,然后立即取消映射。如果你打算通过映射修改内存,你应该保持映射直到你准备好删除它。这不会抑制性能,不会阻止您按照允许的使用方法或其他任何方式使用该内存。
其次,正如规范明确概述的那样,如果您创建一个可用作统一缓冲区的
VkBuffer
,您指定的偏移量必须遵守minUniformBufferOffsetAlignment
。同样,当使用此类缓冲区作为 UBO 资源时,您提供的偏移量必须也与minUniformBufferOffsetAlignment
对齐,无论偏移量是动态的还是静态的。
关于c++ - Vulkan 中动态统一缓冲区的缓冲区内存分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46611623/