Skip to content

Vulkan Storage Buffers in vulkan-cpp #7

@SpinnerX

Description

@SpinnerX

Storage buffers in Vulkan can store more data compared to both push constants and uniform buffers.

Different Uses to Storage Buffers Comparisons

These are the different resource sizes that can be sent to the shader

Push Constants

  • Only store 128 to 256 bytes
  • Very small and faster data transfer
  • Used if data is changed every draw call

Uniform Buffers

  • Stores 64kb (65,536 bytes)
  • Small to medium, read only data.
  • Used for data changed less like camera data.
  • Optimized for fast, cached reads by the shader

Storage Buffers

  • Stores 4 GB (up to full VRAM capacity)
  • Large read/write of resources
  • Used for bulky storage such as vertex data, large array of light sources, or even compute shader I/O.

API Design

The API design is going to look quite similar to vk::uniform_buffer, really. I would suspect the difference would be called vk::storage_buffer.

Code Example of API Usage

Setting up the storage buffer

vk::storage_buffer storage(m_device, m_arbitrary_large_light_sources);

storage.write(some_light_data); // write to the GPU

Setting up buffer_memory_barriers

Difference between .compute_write does the buffer memory barrier, whereas .write does not. Which sets up the buffer memory barrier with the set parameters with the buffer your doing the operation on.

vk::buffer_memory_barrier barrier_info = {
    .src_mask = vk::access::write,
    .dst_mask = vk::access::read,
    .src_index = VK_QUEUE_FAMILY_IGNORED,
    .dst_index = VK_QUEUE_FAMILY_IGNORED,
    .src_stage = vk::shader_stage::compute, // set in vkCmdPipelineBarrier
    .dst_stage = vk:shader_stage::vertex,     // set in vkCmdPipelineBarrier
};
storage.compute_write(barrier_info);

OR free-standing helpers for memory barriers

vk::buffer_memory_barrier barrier_info = {
    .src_mask = vk::access::write,
    .dst_mask = vk::access::read,
    .src_index = VK_QUEUE_FAMILY_IGNORED,
    .dst_index = VK_QUEUE_FAMILY_IGNORED,
    .src_stage = vk::shader_stage::compute, // set in vkCmdPipelineBarrier
    .dst_stage = vk:shader_stage::vertex,     // set in vkCmdPipelineBarrier
};
vk::buffer_memory_barrier(storage, barrier_info);

storage.write(some_light_data);

.write is equivalent to doing this below.

/*
Equivalent to doing
VkMappedMemoryRange memory_range = {
    .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
    .offset = 0,
    .size = VK_WHOLE_SIZE // can be typed in directly using that
};
vkFlushMappedMemoryRange(m_device, 1, &memory_range);
*/

.compute_write is equivalent to doing this raw Vulkan sample code

// Equivalent to doing:
VkBufferMemoryBarrier barrier = {
    .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
    .pNext = NULL,
    
    // The scope of the *previous* memory operations to wait on (Compute Shader Write)
    .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, 
    
    // The scope of the *upcoming* memory operations to make visible (Vertex Shader Read)
    .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, 
    
    // The queue families involved (often the same)
    .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 
    .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
    
    // The VkBuffer being synchronized
    .buffer = storageBuffer, 
    .offset = 0,
    .size   = VK_WHOLE_SIZE
};

// The first pipeline stage (Compute) must be completed before the second stage (Vertex) begins.
vkCmdPipelineBarrier(
    commandBuffer,
    VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,   // Wait for the Compute Write stage to finish
    VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,    // Block until the Vertex Read stage is ready
    0,                                      // Dependency flags
    0, NULL,                                // Memory barriers (none here)
    1, &barrier,                            // Buffer memory barriers
    0, NULL                                 // Image memory barriers (none here)
);

Last Few Notes

These are just some examples in comparisons to their equivalency. These may change when I begin working on getting the implementations to work as I continue learning more about descriptor indexing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions