From c6c90d4cbcdd77e4a2b799ebcc6c0a0cb020136c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 9 Nov 2017 12:21:20 +0100 Subject: [PATCH] Improve Vulkan device selection mechanism to prefer discrete GPUs --- Common/Vulkan/VulkanContext.cpp | 51 +++++++++++++++++++++++++++------ Common/Vulkan/VulkanContext.h | 12 ++++++-- android/jni/app-android.cpp | 10 ++++++- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 6c1ce1eb5c..ae695251a1 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -120,6 +120,11 @@ VkResult VulkanContext::CreateInstance(const char *app_name, int app_ver, uint32 } VulkanLoadInstanceFunctions(instance_); + if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) { + WLOG("CheckLayers for instance failed"); + // init_error_ = "Failed to validate instance layers"; + // return; + } uint32_t gpu_count = 1; res = vkEnumeratePhysicalDevices(instance_, &gpu_count, nullptr); @@ -141,11 +146,6 @@ VkResult VulkanContext::CreateInstance(const char *app_name, int app_ver, uint32 return res; } - if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) { - WLOG("CheckLayers failed"); - // init_error_ = "Failed to validate instance layers"; - // return; - } return VK_SUCCESS; } @@ -333,14 +333,47 @@ bool VulkanContext::CheckLayers(const std::vector &layer_props, return true; } +int VulkanContext::GetBestPhysicalDevice() { + // Rules: Prefer discrete over embedded. + // Prefer nVidia over Intel. + + int maxScore = -1; + int best = -1; + + for (size_t i = 0; i < physical_devices_.size(); i++) { + int score = 0; + VkPhysicalDeviceProperties props; + vkGetPhysicalDeviceProperties(physical_devices_[i], &props); + switch (props.deviceType) { + case VK_PHYSICAL_DEVICE_TYPE_CPU: + score += 1; + break; + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: + score += 20; + break; + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: + score += 10; + break; + } + if (props.vendorID == VULKAN_VENDOR_AMD) { + score += 5; + } else if (props.vendorID == VULKAN_VENDOR_NVIDIA) { + score += 5; + } + if (score > maxScore) { + best = i; + maxScore = score; + } + } + return best; +} + void VulkanContext::ChooseDevice(int physical_device) { physical_device_ = physical_device; GetDeviceLayerProperties(); if (!CheckLayers(device_layer_properties_, device_layer_names_)) { - WLOG("CheckLayers failed (2)"); - // init_error_ = "Failed to validate device layers"; - // return; + WLOG("CheckLayers for device %d failed", physical_device); } vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, nullptr); @@ -913,4 +946,4 @@ const char *VulkanResultToString(VkResult res) { default: return "VK_ERROR_...(unknown)"; } -} \ No newline at end of file +} diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 8c40442197..bf48a1460e 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -43,6 +43,15 @@ enum { VULKAN_FLAG_PRESENT_FIFO_RELAXED = 8, }; +enum { + VULKAN_VENDOR_NVIDIA = 0x000010de, + VULKAN_VENDOR_INTEL = 0x00008086, // Haha! + VULKAN_VENDOR_AMD = 0x00001002, + VULKAN_VENDOR_ARM = 0x000013B5, // Mali + VULKAN_VENDOR_QUALCOMM = 0x00005143, + VULKAN_VENDOR_IMGTEC = 0x00001010, // PowerVR +}; + struct VulkanPhysicalDeviceInfo { VkFormat preferredDepthStencilFormat; }; @@ -203,8 +212,7 @@ public: VkResult CreateInstance(const char *app_name, int app_ver, uint32_t flags); - // TODO: Actually do some checks? - int GetBestPhysicalDevice() const { return 0; } + int GetBestPhysicalDevice(); void ChooseDevice(int physical_device); bool EnableDeviceExtension(const char *extension); VkResult CreateDevice(); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 19a133502f..2d16e1b0e7 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -290,7 +290,15 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX, return false; } - g_Vulkan->ChooseDevice(g_Vulkan->GetBestPhysicalDevice()); + int physicalDevice = g_Vulkan->GetBestPhysicalDevice(); + if (physicalDevice < 0) { + ELOG("No usable Vulkan device found."); + delete g_Vulkan; + g_Vulkan = nullptr; + return false; + } + + g_Vulkan->ChooseDevice(physicalDevice); // Here we can enable device extensions if we like. ILOG("Creating vulkan device");