Uploading data to buffers
Uploading data from the application to the GPU depends on the type of buffer. For host-visible buffers, it’s a direct copy using memcpy
. For device-local buffers, we need a staging buffer, which is a buffer that is visible both by the CPU and the GPU. In this recipe, we will demonstrate how to upload data from your application to the device-visible memory (into a buffer’s memory region on the device).
Getting ready
If you haven’t already, please refer to the Understanding Vulkan’s memory model recipe.
How to do it…
The upload process depends on the type of buffer:
- For host-visible memory, it’s enough to retrieve a pointer to the destination using
vmaMapMemory
and copy the data usingmemcpy
. The operation is synchronous, so the mapped pointer can be unmapped as soon asmemcpy
returns.It’s fine to map a host-visible buffer as soon as it is created and leave it mapped until its destruction. That is the recommended approach, as you don’t incur the overhead of mapping the memory every time it needs to be updated:
VmaAllocator allocator; // Valid VMA allocator VmaAllocation allocation; // Valid VMA allocation void *data; // Data to be uploaded size_t size; // Size of data in bytes void *map = nullptr; VK_CHECK(vmaMapMemory(allocator, allocation, &map)); memcpy(map, data, size); vmaUnmapMemory(allocator_, allocation_); VK_CHECK(vmaFlushAllocation(allocator_, allocation_, offset, size));
- Uploading data to a device-local memory needs to be (1) copied to a buffer that is visible from the host first (called a staging buffer) and then (2) copied from the staging buffer to the device-local memory using
vkCmdCopyBuffer
, as depicted in Figure 2.4. Note that this requires a command buffer:
Figure 2.4 – Staging buffers
- Once the data is residing on the device (on the host-visible buffer), copying it to the device-only buffer is simple:
VkDeviceSize srcOffset; VkDeviceSize dstOffset; VkDeviceSize size; VkCommandBuffer commandBuffer; // Valid Command Buffer VkBuffer stagingBuffer; // Valid host-visible buffer VkBuffer buffer; // Valid device-local buffer VkBufferCopy region(srcOffset, dstOffset, size); vkCmdCopyBuffer(commandBuffer, stagingBuffer, buffer, 1, ®ion);
Uploading data from your application to a buffer is accomplished either by a direct memcpy
operation or by means of a staging buffer. We showed how to perform both uploads in this recipe.