填充顶点缓冲

现在,我们可以开始将顶点数据复制到缓冲中。我们需要使用vkMapMemory函数将缓冲关联的内存映射到CPU可以访问的内存:

void* data;
vkMapMemory(device, vertexBufferMemory, 0, bufferInfo.size, 0, &data);

vkMapMemory函数允许我们通过给定的内存偏移值和内存大小访问特定的内存资源。这里我们使用的偏移值和内存大小分别时0和bufferInfo.size。还有一个特殊值VK_WHOLE_SIZE可以用来映射整个申请的内存。vkMapMemory函数的倒数第二个参数可以用来指定一个标记,但对于目前版本的Vulkan来说,这个参数还没有可以使用的标记,必须将其设置为0。最后一个参数用于返回内存映射后的地址。

void* data;
vkMapMemory(device, vertexBufferMemory, 0, bufferInfo.size, 0, &data);
memcpy(data, vertices.data(), (size_t) bufferInfo.size);
vkUnmapMemory(device, vertexBufferMemory);

现在可以使用memcpy将顶点数据复制到映射后的内存,然后调用vkUnmapMemory函数来结束内存映射。然而,驱动程序可能并不会立即复制数据到缓冲关联的内存中去,这是由于现代处理器都存在缓存这一设计,写入内存的数据并不一定在多个核心同时可见,有下面两种方法可以保证数据被立即复制到缓冲关联的内存中去:

  • 使用带有VK_MEMORY_PROPERTY_HOST_COHERENT_BIT属性的内存类型,保证内存可见的一致性

  • 写入数据到映射的内存后,调用vkFlushMappedMemoryRanges函数,读取映射的内存数据前调用vkInvalidateMappedMemoryRanges函数

在这里,我们使用第一种方法,它可以保证映射的内存的内容和缓冲关联的内存的内容一致。但使用这种方式,会比第二种方式些许降低性能表现。