lwjglgamedev / vulkanbook

Online book which introduces the main concepts required to write graphics games or any other applications using Vulkan in Java by using the LWJGL library.
MIT License
260 stars 13 forks source link

Improved physical device selection #37

Closed Cleptomania closed 1 year ago

Cleptomania commented 2 years ago

Currently in (I believe) every chapter of the book from the point at which physical devices are introduced onwards uses a hard set device name in the eng.properties file to select a device. A better approach could be to find the first available device with the required features(like the KHR swapchain extension and a graphics queue family for example).

To expand on that, could even have it score devices based on extra features, such as prioritize a discrete over integrated GPU, etc. This technique shows a quick implementation in the C vulkan-tutorial here.

A rough idea of what this might look like in this project might be something like below. This is definitely open to further thoughts and development but I've tested the implementation and it works at least. I would think if this were to be included it would make sense to include from the physical devices initial implementation onwards

Create a new method rateDeviceSuitability in PhysicalDevice:

private static int rateDeviceSuitability(PhysicalDevice device) {
    VkPhysicalDeviceProperties properties = device.getVkPhysicalDeviceProperties();
    VkPhysicalDeviceFeatures features = device.getVkPhysicalDeviceFeatures();

    // Device must support a swap chain and graphics queue
    if (!device.hasGraphicsQueueFamily() || !device.hasKHRSwapChainExtension()) {
        return 0;
    }

    int score = 1;

    // Discrete GPUs are always better
    if (properties.deviceType() == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
        score += 1000;
    }

    return score;
}

Then update the createPhysicalDevice function to work something like this:

Map<Integer, PhysicalDevice> devices = new HashMap<>();
for (int i = 0; i < numDevices; i++) {
    VkPhysicalDevice vkPhysicalDevice = new VkPhysicalDevice(pPhysicalDevices.get(i), instance.getVkInstance());
    PhysicalDevice physicalDevice = new PhysicalDevice(vkPhysicalDevice);
    rating = rateDeviceSuitability(physicalDevice);
    if (rating > 0) {
        devices.put(rating, physicalDevice);
    }
}

SortedSet<Integer> keys = new TreeSet<>(devices.keySet()).descendingSet();
selectedPhysicalDevice = devicees.remove(keys.first());

for (PhysicalDevice physicalDevice : devices.values()) {
    physicalDevice.cleanup();
}
lwjglgamedev commented 2 years ago

Many thanks for the suggestion.

Actually, the code iterates over available phsysical devices and checks if they support swap chain and graphics queue. With all of these candidates, we try to select the one that is on the properties file. It is explained that you may want to add additional heuristics, such as the approach tou propose, to select the most performant device. In any case, I would prefer not to add more code and complicate first chapters.