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.
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()
.
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
.