Memory Budget extended features
The source for this sample can be found in the Khronos Vulkan samples github repository. |
This sample demonstrates how to incorporate the Vulkan memory budget extension.
Memory budget extension helps users to sample the memory budget consumption on each heap from the physical device
, and is able to tell the property flag
for each heap.
Which is a proper debug tool to visualize the memory consumption in run-time.
Memory budget extension
In order to enable usage of memory budget extension features, an instance extension and a device extension were introduced in the constructor of the MemoryBudget
class, where:
add_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
add_device_extension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
Memory properties related structure instances were defined and initialized in the header of the MemoryBudget
class, listed as follows:
VkPhysicalDeviceMemoryBudgetPropertiesEXT physical_device_memory_budget_properties{};
VkPhysicalDeviceMemoryProperties2 device_memory_properties{};
Where, the sType
and pNext
variables were defined inside the initialize_device_memory_properties()
function, such that:
void MemoryBudget::initialize_device_memory_properties()
{
// Initialize physical device memory budget properties structures variables
physical_device_memory_budget_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
physical_device_memory_budget_properties.pNext = nullptr;
// Initialize physical device memory properties structure variables
device_memory_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
device_memory_properties.pNext = &physical_device_memory_budget_properties;
}
The sType
of device_memory_properties
is defined as VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2
, and its pNext
chained in a pointer of the structure instance physical_device_memory_budget_properties
.
Where, the sType
of physical_device_memory_budget_properties
is defined as VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT
and its pNext
is defined as a nullptr
.
Each of the mentioned extension structure instances were defined in the header and initialized in function initialize_device_memory_properties()
.
UI Overlay: Memory properties
In application’s UI overlay, total memory usage and total memory budget will be displayed.
In addition, by pressing down the arrow next to the “Memory Heap Details” tab, it expands a list of all memory usages and budgets from the heap count.
Where all memory properties were converted and displayed in proper units (e.g.,kilobytes
, megabytes
, etc.,).
Where:
void MemoryBudget::on_update_ui_overlay(vkb::Drawer &drawer)
{
converted_memory = update_converted_memory(device_memory_total_usage);
drawer.text("Total Memory Usage: %.2f %s", converted_memory.data, converted_memory.units.c_str());
converted_memory = update_converted_memory(device_memory_total_budget);
drawer.text("Total Memory Budget: %.2f %s", converted_memory.data, converted_memory.units.c_str());
if (drawer.header("Memory Heap Details"))
{
for (int i = 0; i < static_cast<int>(device_memory_heap_count); i++)
{
std::string header = "Memory Heap Index: " + std::to_string(i);
if (drawer.header(header.c_str()))
{
converted_memory = update_converted_memory(physical_device_memory_budget_properties.heapUsage[i]);
drawer.text("Usage: %.2f %s", converted_memory.data, converted_memory.units.c_str());
converted_memory = update_converted_memory(physical_device_memory_budget_properties.heapBudget[i]);
drawer.text("Budget: %.2f %s", converted_memory.data, converted_memory.units.c_str());
drawer.text("Heap Flag: %s", read_memoryHeap_flags(device_memory_properties.memoryProperties.memoryHeaps[i].flags).c_str());
}
}
}
}
The function update_device_memory_properties()
measures and updates all memory properties related variables, by calling the vkGetPhysicalDeviceMemoryProperties2()
and evaluating the device_memory_total_usage
and device_memory_total_budget
, where:
void MemoryBudget::update_device_memory_properties()
{
vkGetPhysicalDeviceMemoryProperties2(get_device().get_gpu().get_handle(), &device_memory_properties);
device_memory_heap_count = device_memory_properties.memoryProperties.memoryHeapCount;
device_memory_total_usage = 0;
device_memory_total_budget = 0;
for (uint32_t i = 0; i < device_memory_heap_count; i++)
{
device_memory_total_usage += physical_device_memory_budget_properties.heapUsage[i];
device_memory_total_budget += physical_device_memory_budget_properties.heapBudget[i];
}
}
And the function update_device_memory_properties()
is assigned to the prepare_instance_data()
.
Which, in this sample it will only need to be called once after everything was ready in the prepare_instance_data()
, and before it returns true
.