Creating buffers
A buffer in Vulkan is simply a contiguous block of memory that holds some data. The data can be vertex, index, uniform, and more. A buffer object is just metadata and does not directly contain data. The memory associated with a buffer is allocated after a buffer has been created.
Table 2.1 summarizes the most important usage types of buffers and their access type:
Buffer Type |
Access Type |
Uses |
Vertex or Index |
Read-only |
|
Uniform |
Read-only |
Uniform data storage |
Storage |
Read/write |
Generic data storage |
Uniform texel |
Read/write |
Data is interpreted as texels |
Storage texel |
Read/write |
Data is interpreted as texels |
Table 2.1 – Buffer types
Creating buffers is easy, but it helps to know what types of buffers exist and what their requirements are before setting out to create them. In this chapter, we will provide a template for creating buffers.
Getting ready
In the repository, Vulkan buffers are managed by the VulkanCore::Buffer
class, which provides functions to create and upload data to the device, as well as a utility function to use a staging buffer to upload data to device-only heaps.
How to do it…
Creating a buffer using VMA is simple:
- All you need are buffer creation flags ( –a value of
0
for the flags is correct for most cases), the size of the buffer in bytes, its usage (this is how you define how the buffer will be used), and assign those values to an instance of theVkBufferCreateInfo
structure:VkDeviceSize size; // The requested size of the buffer VmaAllocator allocator; // valid VMA Allocator VkUsageBufferFlags use; // Transfer src/dst/uniform/SSBO VkBuffer buffer; // The created buffer VkBufferCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = {}, .size = size, .usage = use, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = {}, .pQueueFamilyIndices = {}, };
You will also need a set of VmaAllocationCreateFlagBits values:
const VmaAllocationCreateFlagBits allocCreateInfo = { VMA_ALLOCATION_CREATE_MAPPED_BIT, VMA_MEMORY_USAGE_CPU_ONLY, };
- Then, call
vmaCreateBuffer
to obtain the buffer handle and its allocation:VmaAllocation allocation; // Needs to live until the // buffer is destroyed VK_CHECK(vmaCreateBuffer(allocator, &createInfo, &allocCreateInfo, &buffer, &allocation, nullptr));
- The next step is optional but useful for debugging and optimization:
VmaAllocationInfo allocationInfo; vmaGetAllocationInfo(allocator, allocation, &allocationInfo);
Some creation flags affect how the buffer can be used, so you might need to make adjustments to the preceding code depending on how you intend to use the buffers you create in your application.