Vulkan Memory Allocator
Memory mapping

Persistently mapped memory

If you need to map memory on host, it may happen that two allocations are assigned to the same VkDeviceMemory block, so if you map them both at the same time, it will cause error because mapping single memory block multiple times is illegal in Vulkan.

TODO update this...

It is safer, more convenient and more efficient to use special feature designed for that: persistently mapped memory. Allocations made with VMA_ALLOCATION_CREATE_MAPPED_BIT flag set in VmaAllocationCreateInfo::flags are returned from device memory blocks that stay mapped all the time, so you can just access CPU pointer to it. VmaAllocationInfo::pMappedData pointer is already offseted to the beginning of particular allocation. Example:

VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufCreateInfo.size = 1024;
bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
VkBuffer buf;
VmaAllocation alloc;
vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo);
// Buffer is immediately mapped. You can access its memory.
memcpy(allocInfo.pMappedData, myData, 1024);

Memory in Vulkan doesn't need to be unmapped before using it e.g. for transfers, but if you are not sure whether it's HOST_COHERENT (here is surely is because it's created with VMA_MEMORY_USAGE_CPU_ONLY), you should check it. If it's not, you should call vkInvalidateMappedMemoryRanges() before reading and vkFlushMappedMemoryRanges() after writing to mapped memory on CPU. Example:

VkMemoryPropertyFlags memFlags;
vmaGetMemoryTypeProperties(allocator, allocInfo.memoryType, &memFlags);
if((memFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
{
VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };
memRange.memory = allocInfo.deviceMemory;
memRange.offset = allocInfo.offset;
memRange.size = allocInfo.size;
vkFlushMappedMemoryRanges(device, 1, &memRange);
}

Note on performance

There is a situation that you should be careful about. It happens only if all of following conditions are met:

  1. You use AMD GPU.
  2. You use the memory type that is both DEVICE_LOCAL and HOST_VISIBLE (used when you specify VMA_MEMORY_USAGE_CPU_TO_GPU).
  3. Operating system is Windows 7 or 8.x (Windows 10 is not affected because it uses WDDM2).

Then whenever a VkDeviceMemory block allocated from this memory type is mapped for the time of any call to vkQueueSubmit() or vkQueuePresentKHR(), this block is migrated by WDDM to system RAM, which degrades performance. It doesn't matter if that particular memory block is actually used by the command buffer being submitted.

To avoid this problem, either make sure to unmap all allocations made from this memory type before your Submit and Present, or use VMA_MEMORY_USAGE_GPU_ONLY and transfer from a staging buffer in VMA_MEMORY_USAGE_CPU_ONLY, which can safely stay mapped all the time.