Code that acquires instance-level extensions can be divided into two stages. First we get the total number of available extensions as follows:
uint32_t extensions_count = 0;
VkResult result = VK_SUCCESS;
result = vkEnumerateInstanceExtensionProperties( nullptr, &extensions_count, nullptr );
if( (result != VK_SUCCESS) ||
(extensions_count == 0) ) {
std::cout << "Could not get the number of Instance extensions." << std::endl;
return false;
}
When called with the last parameter set to nullptr, the vkEnumerateInstanceExtensionProperties() function stores the number of available extensions in the variable pointed to in the second parameter. This way, we know how many extensions are on a given platform and how much space we need to be able to store parameters for all of them.
When we are ready to acquire extensions' properties, we can call the same function once again. This time the last parameter should point to the prepared space (an array of VkExtensionProperties elements, or a vector, in our case) in which these properties will be stored:
available_extensions.resize( extensions_count );
result = vkEnumerateInstanceExtensionProperties( nullptr, &extensions_count, &available_extensions[0] );
if( (result != VK_SUCCESS) ||
(extensions_count == 0) ) {
std::cout << "Could not enumerate Instance extensions." << std::endl;
return false;
}
return true;
The pattern of calling the same function twice is common in Vulkan. There are multiple functions, which store the number of elements returned in the query when their last argument is set to nullptr. When their last element points to an appropriate variable, they return the data itself.
Now that we have the list, we can look through it and check whether the extensions we would like to enable are available on a given platform.