vkEnumeratePhysicalDevices() not finding all GPUs

Viewed 1774

My system has the following specs:

GPUs:

  • AMD Radeon(TM) Graphics
  • NVIDIA GeForce RTX 2060 with Max-Q Design

CPU:

  • AMD Ryzen 9 4900HS with Radeon Graphics

When I run vkEnumeratePhysicalDevices() it only returns 1 device, my integrated graphics (AMD Radeon(TM) Graphics). But I figured out that I can force it to use my discrete graphics card if I use the graphics settings in Windows settings (Settings > System > Display > Graphics Settings, then browse to find the build .exe for the Vulkan project and set options to High Performance). However, when I run the Vulkan project now, it still only shows 1 gpu on the system, just it switched to only showing the RTX 2060.

This is obviously not something that one could expect a player of a game to do who has no experience with code (if I was to ever finish a game with Vulkan). I've reasoned that this might be happening because I'm on a laptop, so I tried disabling all power saving settings but nothing changed.

So I'm wondering if there is a way to find all GPUs on the system outside of Vulkan and have the physical device be set out of that list, since Vulkan seems to be unable to find all GPUs at once?

Edit: I figured out that I can get it to see the dedicated GPU if I turn off the integrated GPU in Device Manager, then turn it back on.

Also I am getting the error: validation layer: setupLoaderTrampPhysDevs: Failed during dispatch call of 'vkEnumeratePhysicalDevices' to lower layers or loader to get count.

Edit 2: I call vkEnumeratePhysicalDevices() like so:

    void pickPhysicalDevice() {
        uint32_t deviceCount = 0;
        vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
        std::vector<VkPhysicalDevice> devices1(deviceCount);
        
        vkEnumeratePhysicalDevices(instance, &deviceCount, devices1.data());
        if (deviceCount == 0) {
            throw std::runtime_error("Failed to find GPUs with Vulkan support.");
        }

        std::vector<VkPhysicalDevice> devices(deviceCount);
        vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());

        std::cout << "Physical Devices(" << deviceCount << "):\n";

        for (const auto& device : devices) {
            //get the device properties
            VkPhysicalDeviceProperties props;
            vkGetPhysicalDeviceProperties(device, &props);
            //print the device and whether it is suitable or not
            std::cout << props.deviceName << " -- " <<  (isDeviceSuitable(device) && props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ? "suitable GPU" : "unsuitable GPU") << std::endl;

            if (isDeviceSuitable(device) && props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
                std::cout << "Device ^ accepted" << std::endl;
                physicalDevice = device;
                break;
            }
        }

        if (physicalDevice == VK_NULL_HANDLE) {
            throw std::runtime_error("Failed to find a suitable GPU.");
        }


    }

My base Vulkan code is modeled off of this website: https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_families

1 Answers

After much reading of basically every forum on the internet that consists of the function name vkEnumeratePhysicalDevices(), and after the week long bounty on this question still remained unanswered, I've found the answer. It lies within the interop between AMD and Nvidia drivers, at least for my laptop (ROG Zephyrus G14). The forum in which the answer was hiding was here: https://github.com/KhronosGroup/Vulkan-Loader/issues/552

From what I understood from what they were saying over there on GitHub, what is happening as @pdaniel-nv describes, is the validation layers VK_LAYER_AMD_swichable_graphics and VK_LAYER_NV_optimus both want to pick High Performance GPUs, but they only want to filter for AMD or Nvidia GPUs respectively. (VK_LAYER_AMD_swichable_graphics wants to use AMD dedicated GPUs and VK_LAYER_NV_optimus wants to use Nvidia dedicated GPUs) So what happens is both drivers from AMD and Nvidia filter out each others GPUs when these layers are used so the list of available GPUs ends up with nothing.

So basically the solution is to disable one or both of those layers through Vulkan Configurator, or better yet in your code. The only downside is that the developer now has to write custom code to determine which GPU is optimal for their program—which honestly is no big deal in my opinion.

Related