Upload a texture to the GPU

In order to use textures and render targets, haiku provides hk_image_t and associated utility functions in haiku/graphics.h.

In this tutorial, we will define a texture as a CPU ressource that you’ll want to use/sample later inside a shader on the GPU. We’ll imagine that you had previously loaded a .jpg or .png file from disc to CPU using any image library (like stb_image.h).

Here’s the full course of actions:

  • Create the CPU buffer containing the texture pixels

  • Create the GPU image that will be used inside as your texture

  • Transfer pixels from the CPU buffer to the GPU image.

Create the buffer

// You previously loaded a rgba8 texture
// with the following variables:
// - texture_width  : int;
// - texture_height : int;
// - pixels: unsigned char* ;

hk_buffer_t my_pixelbuf = hkgfx_buffer_create(device, &(hk_gfx_buffer_desc){
    .usage_flags = HK_BUFFER_USAGE_TRANSFER_SRC_BIT,
    .memory_type = HK_MEMORY_TYPE_CPU_ONLY,
    .bytesize    = texture_width*texture_height*4*sizeof(uint8_t),
    .dataptr     = texdata
});

// You can now free(pixels);

Create the image

hk_image_t my_texture = hkgfx_image_create(device, &(hk_gfx_image_desc){
    .type = HK_IMAGE_TYPE_2D,
    .extent = {.width = texture_width, .height = texture_height},
    .levels = 1,
    .usage_flags  = HK_IMAGE_USAGE_TRANSFER_DST_BIT | HK_IMAGE_USAGE_SAMPLED_BIT,
    .memory_type  = HK_MEMORY_TYPE_GPU_ONLY
});

Upload pixels to the GPU

hk_context_t ctx = hkgfx_context_create(device);

hkgfx_context_begin(ctx);
{
    // First we transfer the texture content to the image
    hkgfx_context_image_barrier(ctx, &(hk_gfx_barrier_image_params){
        .image       = my_texture,
        .prev_state  = HK_IMAGE_STATE_UNDEFINED,
        .next_state  = HK_IMAGE_STATE_TRANSFER_DST
    });

    hkgfx_context_copy_buffer_to_image(ctx, my_pixelbuf, my_texture, &(hk_gfx_cmd_image_buffer_copy_params){
        .aspect = HK_IMAGE_ASPECT_COLOR_BIT,
        .region = {
            .extent = {.width = texture_width, .height = texture_height, .depth = 1},
            .layer_count = 1,
        }
    });
}
hkgfx_context_end(ctx);
hkgfx_device_submit(device, &(hk_gfx_submit_params){.context = ctx});
hkgfx_device_wait(device);

// after that, your texture is uploaded the GPU.
// You can cleanup my_pixelbuf using hkgfx_buffer_destroy(device, my_pixelbuf);