Buffers and images#

CORE provides RAII wrappers for the two resource types used throughout its Vulkan examples: VulkanBuffer and VulkanImage.

Buffers#

Construct a buffer with its size, usage, and memory properties. Host-visible buffers can be populated through MapData():

core::vulkan::VulkanBuffer input(
    &context, byte_size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
        VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

input.MapData([&source](void* data) {
  memcpy(data, source.data(), source.size_bytes());
});

CopyToBuffer() supports staging uploads to device-local buffers.

const VkDeviceSize size = vertices.size() * sizeof(vertices[0]);

core::vulkan::VulkanBuffer staging(
    &context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
        VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

core::vulkan::VulkanBuffer device_buffer(
    &context, size,
    VK_BUFFER_USAGE_TRANSFER_DST_BIT |
        VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

staging.MapData([&vertices, size](void* data) {
  memcpy(data, vertices.data(), static_cast<size_t>(size));
});
staging.CopyToBuffer(device_buffer);

Important

CopyToBuffer() requires the source and destination to have exactly the same size. MapData() accepts only memory created with both HOST_VISIBLE and HOST_COHERENT; mapping device-local memory throws an exception.

Images#

VulkanImage creates the image, memory, and image view as one object. Its API supports layout transitions, depth layouts, mipmap generation, array layers, and multisampling.

Use VulkanBuffer::CopyToImage() to upload staged pixel data. Use VulkanSampler when the image will be read through a combined image sampler descriptor.

A basic texture upload follows three distinct operations:

core::vulkan::VulkanImage texture(
    &context, width, height, VK_FORMAT_R8G8B8A8_SRGB,
    VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
    VK_IMAGE_ASPECT_COLOR_BIT,
    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

texture.TransitionImageLayout(
    VK_IMAGE_LAYOUT_UNDEFINED,
    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
    VK_FORMAT_R8G8B8A8_SRGB);

staging.CopyToImage(texture, width, height);

texture.TransitionImageLayout(
    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
    VK_FORMAT_R8G8B8A8_SRGB);

core::vulkan::VulkanSampler sampler(&context);

Warning

TransitionImageLayout() currently supports a fixed set of color-image transitions. Unsupported old/new layout pairs throw std::invalid_argument. CopyToImage() expects the destination to already be in VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.

For mipmaps, create the image with TRANSFER_SRC, TRANSFER_DST, and SAMPLED usage flags, allocate all mip levels, upload level 0, and call GenerateMipmaps(). The selected format must support linear blitting.

Ownership#

Both resource wrappers are movable and release their Vulkan objects in their destructors. Avoid copying them, and keep their VulkanContext alive for their entire lifetime.