Buffers

haiku provides a buffer handle hk_buffer_t and associated utility functions in haiku/graphics.h allowing to store and transfer data between CPU and GPU :

Warning

doxygenstruct: Cannot find class “hk_buffer_t” in doxygen xml output for project “haiku” from directory: /builds/haiku/haiku/build/docs//xml

Before creation, user must define how it will be used. To do so, we exposed enum flag bits using hk_buffer_usage_flag_bits_e:

enum hk_buffer_usage_flag_bits_e

Values:

enumerator HK_BUFFER_USAGE_NONE

Invalid flag for completness/default.

enumerator HK_BUFFER_USAGE_TRANSFER_SRC_BIT

Hint that buffer will be later used as a tranfer source.

enumerator HK_BUFFER_USAGE_TRANSFER_DST_BIT

Hint that buffer will be later used as a tranfer destination.

enumerator HK_BUFFER_USAGE_UNIFORM_BUFFER_BIT

Hint that buffer will be later used as a uniform buffer (UBO).

enumerator HK_BUFFER_USAGE_STORAGE_BUFFER_BIT

Hint that buffer will be later used as a storage buffer (SSBO).

enumerator HK_BUFFER_USAGE_INDEX_BUFFER_BIT

Hint that buffer will be later used as an index buffer.

enumerator HK_BUFFER_USAGE_VERTEX_BUFFER_BIT

Hint that buffer will be later used as a vertex buffer (VBO).

enumerator HK_BUFFER_USAGE_INDIRECT_BUFFER_BIT

Hint that buffer will be later used as an indirect buffer.

the next point to consider is the type of memory to be used by the buffer. Buffers can be used to transfer data from the CPU to the GPU and vice versa, or to store data only on the GPU. These these choices are decided by hk_memory_type_e enumeration:

enum hk_memory_type_e

GPU memory type enum. Hint the memory lifecycle of objects (buffers/images).

Values:

enumerator HK_MEMORY_TYPE_NONE

Invalid flag for completness/default.

enumerator HK_MEMORY_TYPE_CPU_ONLY

Host-only memory type. Example: CPU mapped staging buffers.

enumerator HK_MEMORY_TYPE_GPU_ONLY

Device-only memory type. Example: GPU-only buffers.

enumerator HK_MEMORY_TYPE_CPU_TO_GPU

Host-to-GPU memory type. Example: CPU/GPU mapped staging buffers.

enumerator HK_MEMORY_TYPE_GPU_TO_CPU

Device-to-GPU buffers. Example: mapped GPU buffers

enumerator HK_MEMORY_TYPE_COUNT

Do not use. Internal usage only.

Once these two uses have been defined, we can build a buffer by calling the hkgfx_buffer_create function, which takes a hk_gfx_buffer_desc description structure as parameter :

struct hk_gfx_buffer_desc

Graphics buffer configuration data structure.

Public Members

char label[HK_MAX_LABEL_SIZE]

Optional label/name. Useful when debugging.

size_t bytesize

The byte size of the buffer object.

void *dataptr

Raw pointer to data with byte size. Required specific memory type:

  • HK_MEMORY_TYPE_CPU_ONLY

  • HK_MEMORY_TYPE_CPU_TO_GPU

uint32_t usage_flags

Combination of hk_buffer_usage_flag_bits_e flag bits to hint the usage of the buffer. Usual examples:

  • Staging buffer: HK_BUFFER_USAGE_TRANSFER_SRC_BIT

  • Uniform buffer: HK_BUFFER_USAGE_TRANSFER_DST_BIT | HK_BUFFER_USAGE_UNIFORM_BUFFER_BIT

  • Vertex buffer : HK_BUFFER_USAGE_VERTEX_BUFFER_BIT

hk_memory_type_e memory_type

Suggets the lifecycle of the buffer object.

  • HK_MEMORY_TYPE_CPU_ONLY Host-only memory type

  • HK_MEMORY_TYPE_GPU_ONLY Device-only memory type

  • HK_MEMORY_TYPE_CPU_TO_GPU Host-to-Device memory type

  • HK_MEMORY_TYPE_GPU_TO_CPU Device-to-Host memory type

Here’s an example of how it’s typically used:

// Creating a staging buffer (moving data from CPU to GPU)
// with HK_MEMORY_TYPE_CPU_ONLY and HK_MEMORY_TYPE_CPU_TO_GPU you can use the dataptr member
hk_buffer_t buffer_staging = hkgfx_buffer_create(device, &(hk_gfx_buffer_desc){
    .usage_flags = HK_BUFFER_USAGE_TRANSFER_SRC_BIT,
    .memory_type = HK_MEMORY_TYPE_CPU_ONLY,
    .bytesize    = array_size * sizeof(/* ... */),
    .dataptr     = array
});

// Creating an uniform buffer (receiving data from CPU)
// with HK_MEMORY_TYPE_GPU_ONLY and HK_MEMORY_TYPE_GPU_TO_CPU dataptr is not used
// you'll need to perform a transfer operation.
hk_buffer_t buffer_ubo = hkgfx_buffer_create(device, &(hk_gfx_buffer_desc){
    .usage_flags = HK_BUFFER_USAGE_TRANSFER_DST_BIT | HK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
    .memory_type = HK_MEMORY_TYPE_GPU_ONLY,
    .bytesize    = ubo_size * sizeof(/* ... */)
});

Here’s the full API reference for the hkgfx_buffer_create and the respective hkgfx_buffer_destroy functions:

hk_buffer_t hkgfx_buffer_create(hk_device_t *device, const hk_gfx_buffer_desc *desc)

Creates a gpu buffer object.

void hkgfx_buffer_destroy(hk_device_t *device, hk_buffer_t buffer)

Destroys a gpu buffer object.

Usually GPU buffers allows to map memory in order to easily access data through a pointer. We provide hkgfx_buffer_memory_map and hkgfx_buffer_memory_unmap :

void hkgfx_buffer_memory_map(hk_device_t *device, hk_buffer_t buf, void **mapped_pointer)

Maps a gpu buffer object to host.

void hkgfx_buffer_memory_unmap(hk_device_t *device, hk_buffer_t buf)

Unmaps a gpu buffer object to host.

A simpler variant is available for persitently mapped buffer (with memory type HK_MEMORY_TYPE_CPU_ONLY, HK_MEMORY_TYPE_CPU_TO_GPU or HK_MEMORY_TYPE_GPU_TO_CPU):

hk_buffer_t buffer_result = hkgfx_buffer_create(device, &(hk_gfx_buffer_desc){
    .usage_flags = HK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
    .memory_type = HK_MEMORY_TYPE_GPU_TO_CPU,
    .bytesize    = buffer_bytesize
});

/* [...] */
void* bufdata = hkgfx_buffer_map(buffer_result);

Here’s the API reference for the hkgfx_buffer_map function:

void *hkgfx_buffer_map(hk_buffer_t buffer)

Retrieves a pointer to a persistant gpu buffer object to host.

Another needed feature, is the ability to reset the buffer content (e.g. atomic counters, etc.):

void hkgfx_buffer_reset(hk_device_t *device, hk_buffer_t buf, const hk_gfx_buffer_desc *desc)

Resets a previously created gpu buffer object.

How to transition between buffer states

enum hk_buffer_state_e

Buffer state enumeration.

Values:

enumerator HK_BUFFER_STATE_DEFAULT

Default buffer state.

enumerator HK_BUFFER_STATE_UNDEFINED

Undefined state. Used as an initial state for a buffer.

enumerator HK_BUFFER_STATE_INDEX

Index buffer state. The buffer will be used as an index buffer.

enumerator HK_BUFFER_STATE_VERTEX

Vertex buffer state. The buffer will be used as a vertex buffer.

enumerator HK_BUFFER_STATE_UNIFORM

Uniform buffer state. The buffer will be used a an uniform buffer.

enumerator HK_BUFFER_STATE_INDIRECT

Indirect buffer state. The buffer will be used a an indirect command buffer.

enumerator HK_BUFFER_STATE_SHADER_ACCESS

Unordered access state. The buffer will be read and written by a shader.

enumerator HK_BUFFER_STATE_SHADER_READ

Read-only access state. The buffer will be read by a shader.

enumerator HK_BUFFER_STATE_SHADER_WRITE

Write-only access state. The buffer will be modified by a shader.

enumerator HK_BUFFER_STATE_TRANSFER_SRC

Transfer source state. The buffer will be the source of a transfer command.

enumerator HK_BUFFER_STATE_TRANSFER_DST

Transfer destination state. The buffer will be the destination of a transfer command.

enumerator HK_BUFFER_STATE_COUNT

Do not use. Internal usage only.

struct hk_gfx_barrier_buffer_params

Buffer barrier description.

Public Members

hk_buffer_t buffer

Buffer to transition between states

hk_buffer_state_e prev_state

Previous/Current state flag

hk_buffer_state_e next_state

Next state flag

void hkgfx_context_buffer_barrier(hk_context_t ctx, const hk_gfx_barrier_buffer_params *params)

Apply a buffer memory barrier command.