In graphics programming we deal with different kinds of resources. Their specific types and names depend on graphics API. For example, in Direct3D 9 we have vertex buffers, index buffers, constant buffers, textures etc. OpenGL equivalent of constant buffer is uniform buffer object (UBO).
Vulkan has only two types of resources: buffers and images. This may be the only thing that is simpler in Vulkan than in other APIs :) When creating such resource, we specify usage flags that define how do we intend to use it. For example,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT means that a buffer may be used as vertex buffer.
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT means that an image may be used as color attachment (which is Vulkan name for “render target”).
Such flags may be combined together, so a single buffer can contain data to be used as vertex buffer, index buffer, and uniform buffer. I’m not 100% sure if this is guaranteed by the specification (theoretically some drivers could return disjoint sets of
VkMemoryRequirements::memoryTypeBits for different usage flags), but I think that every real implementation allows that. It means we cannot clearly classify buffers and images into categories. Despite that, I decided to develop a human-friendly classification of Vulkan resources into several categories, starting from most “special”, and ending with most “common/generic” ones. I propose following algorithm:
For buffers: // Buffer is used as source of data for fixed-function stage of graphics pipeline. // It’s indirect, vertex, or index buffer. if ((usage & (VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT)) != 0) return class0; // Buffer is accessed by shaders for load/store/atomic. // Aka “UAV” else if ((usage & (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) != 0) return class1; // Buffer is accessed by shaders for reading uniform data. // Aka “constant buffer” else if ((usage & (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT)) != 0) return class2; // Any other type of buffer. // Notice that VK_BUFFER_USAGE_TRANSFER_SRC_BIT and VK_BUFFER_USAGE_TRANSFER_DST_BIT // flags are intentionally ignored. else return class3; For images: // Image is used as depth/stencil “texture/surface”. if ((usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) return class0; // Image is used as other type of attachment. // Aka “render target” else if ((usage & (VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) != 0) return class1; // Image is accessed by shaders for sampling. // Aka “texture” else if ((usage & VK_IMAGE_USAGE_SAMPLED_BIT) != 0) return class2; // Any other type of image. // Notice that VK_IMAGE_USAGE_TRANSFER_SRC_BIT and VK_IMAGE_USAGE_TRANSFER_DST_BIT // flags are intentionally ignored. else return class3;
I needed this because I wanted to introduce better coloring to VMA Dump Vis. Vulkan Memory Allocator (VMA) is a C++ library that simplifies GPU memory management in Vulkan applications. VMA Dump Vis is a Python script that can visualize JSON dump from this library on a picture. As I updated the library to remember usage flags of created resources, I wanted to use them to show more information on the picture. To do this, I defined following color scheme:
Example visualization of Vulkan memory in some game:
This color scheme is carefully designed. I based it on following principles:
VK_IMAGE_TILING_OPTIMALshould be used wherever possible, so those with
VK_IMAGE_TILING_LINEARare just marked with green. Images of unknown tiling have color between cyan and green.
You can already visualize your Vulkan memory with all these colors if you grab Vulkan Memory Allocator from development branch. I think that this classification of GPU resources and accompanying color scheme could also be useful for other graphics APIs.