Rether / docs
engine/apis/vulkan/Vulkan physical device
gardenChoosing the GPU that can do the job

Vulkan physical device

updated 2026.08.29created 2026.08.29~2 min

The concept

Once the Vulkan instance is initialized, we are able to enumerate all the physical devices (GPUs) on the computer. This allows us to choose the one that has the specific features required for our engine.

// cpp
std::vector<vk::raii::PhysicalDevice> devices =
    d_instance.enumeratePhysicalDevices();

Now that we have handles to all physical devices on the machine, we iterate through them and check three requirements: the Vulkan version, the device extensions, and the Vulkan queue families it offers.

Vulkan version

First, we check that the device supports our target Vulkan API version (1.3 in this case). This is critical because Vulkan 1.3 introduces dynamic rendering as a core feature, which simplifies our rendering pipeline significantly.

// cpp
const auto devIter =
    std::ranges::find_if(devices, [&](auto const& device) {
        // Check if the device supports the Vulkan 1.3 API version
        if (device.getProperties().apiVersion < VK_API_VERSION_1_3) {
            return false;
        }
    });

Device extensions

Next, we check for device extensions. Unlike the instance-level Vulkan extensions, these are specific to the GPU. Even though the instance handles the Vulkan surface creation, the physical device needs specific extensions to interact with that surface and manage memory.

// cpp
const std::vector deviceExtensions = {
    vk::KHRSwapchainExtensionName,
    vk::KHRSpirv14ExtensionName,
#if defined(__APPLE__)
    // Required for MoltenVK (Metal translation) on macOS
    "VK_KHR_portability_subset",
#endif
};

bool checkDeviceExtensions(const vk::PhysicalDevice        device,
                           const std::vector<const char*>& requiredExtensions)
{
    const auto availableExtensions =
        device.enumerateDeviceExtensionProperties();
    std::set<std::string> required(requiredExtensions.begin(),
                                   requiredExtensions.end());

    for (const auto& extension : availableExtensions) {
        required.erase(extension.extensionName);
    }
    return required.empty();
}

The important ones:

  • VK_KHR_swapchain: the most important. It allows the GPU to present rendered images to the screen (via the OS windowing system). Without it, we can render images but never display them.
  • VK_KHR_portability_subset: strictly for macOS (MoltenVK). It handles non-conformant behavior where Metal (Apple's API) does not perfectly match the Vulkan spec.

Queue families

Finally, the device must offer a queue family that supports both graphics and presentation on our surface — the details live in Vulkan queue families. A device that passes all three checks is the one we keep; the next step is to create its Vulkan logical device.

Keyboard

search this vault⌘K / /
step the sidebarjk
open selected↵
switch browse mode123
switch vaultgv
toggle themet
close / clearesc
this help?
esc to close