我想将这个问题分成三部分: -
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变量如何反映到
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));
答案 0 :(得分:3)
最小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
对齐,无论偏移是动态的还是静态的。
答案 1 :(得分:1)
1:缓冲区大小需要是其倍数。而且你需要知道你在缓冲区的哪个部分实际存储了某些东西以及你没有做过什么。如果您的数据不完全适合您的缓冲区,则需要更大倍数。
2:您的计算已关闭。整数算术。结果只有256个。
3:无需复制实际上不包含数据的缓冲区部分。允许部分副本,只是缓冲区本身更大。