Enumerating available physical devices
Almost all the work in Vulkan is performed on logical devices: we create resources on them, manage their memory, record command buffers created from them, and submit commands for processing to their queues. In our application, logical devices represent physical devices for which a set of features and extensions were enabled. To create a logical device, we need to select one of the physical devices available on a given hardware platform. How do we know how many and what physical devices are available on a given computer? We need to enumerate them.
How to do it...
- Take the handle of a created Vulkan Instance. Provide it through a variable of type
VkInstance
namedinstance
. - Prepare a variable of type
uint32_t
nameddevices_count
. - Call
vkEnumeratePhysicalDevices( instance, &devices_count, nullptr )
. In the first parameter, provide a handle of the Vulkan Instance; in second, provide a pointer to thedevices_count
variable, and leave the third parameter set tonullptr
right now.
- If a function call is successful, the
devices_count
variable will contain the total number of available physical devices. - Prepare storage for the list of physical devices. The best solution is to use a variable of type
std::vector
with elements of typeVkPhysicalDevice
. Call itavailable_devices
. - Resize the vector to be able to hold at least the
devices_count
elements. - Call
vkEnumeratePhysicalDevices( instance, &devices_count, &available_devices[0] )
. Again, the first parameter should be set to the handle of a Vulkan Instance object, the second parameter should still point to theextensions_count
variable, and the third parameter must point to an array of at leastdevices_count
elements of typeVkPhysicalDevice
. Here, in the third parameter, provide an address of the first element of anavailable_devices
vector. - If the function returns successfully, the
available_devices
vector will contain a list of all physical devices installed on a given hardware platform that supports a Vulkan API.
How it works...
Enumerating the available physical devices operation is divided into two stages: First, we check how many physical devices are available on any given hardware. This is done by calling the vkEnumeratePhysicalDevices()
function with the last parameter set to nullptr
, as follows:
uint32_t devices_count = 0; VkResult result = VK_SUCCESS; result = vkEnumeratePhysicalDevices( instance, &devices_count, nullptr ); if( (result != VK_SUCCESS) || (devices_count == 0) ) { std::cout << "Could not get the number of available physical devices." << std::endl; return false; }
This way, we know how many devices are supporting Vulkan and how much storage we need to prepare for their handles. When we are ready and have prepared enough space, we can go to the second stage and get the actual handles of physical devices. This is done with the call of the same vkEnumeratePhysicalDevices()
function, but this time, the last parameter must point to an array of VkPhysicalDevice
elements:
available_devices.resize( devices_count ); result = vkEnumeratePhysicalDevices( instance, &devices_count, &available_devices[0] ); if( (result != VK_SUCCESS) || (devices_count == 0) ) { std::cout << "Could not enumerate physical devices." << std::endl; return false; } return true;
When the call is successful, the prepared storage is filled with the handles of physical devices installed on any computer on which our application is executed.
Now that we have the list of devices, we can look through it and check the properties of each device, check operations we can perform on it, and see what extensions are supported by it.
See also
The following recipes in this chapter:
- Loading instance-level functions
- Checking available device extensions
- Checking available queue families and their properties
- Creating a logical device