From 741f0140ee6e626a09a02aa2bbb4f2acbc249026 Mon Sep 17 00:00:00 2001 From: IgorAlexey Date: Wed, 18 Mar 2026 21:35:47 -0300 Subject: [PATCH 1/4] Vulkan: do not replace hardware GPU with software renderer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When no discrete GPU is present, SelectPhysicalDevice iterates all physical devices and keeps overwriting SelectedPhysicalDevice without breaking, because the break only fires for VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU. On Linux with Mesa, a CPU-type software renderer (llvmpipe) is always enumerated alongside the real hardware device. On a system with only an integrated GPU the loop would iterate past the iGPU, land on llvmpipe as the last entry, and silently return it as the selected device—making the application run entirely on software rendering with no warning. Fix this by skipping CPU-type devices when a hardware device has already been selected. A CPU-type device is still accepted as a last resort when no hardware GPU is found at all, so the fallback behavior is preserved. Tested on an Intel Core Ultra 7 258V (Lunar Lake, Arc 130V/140V iGPU) running Fedora 43 with Mesa 25.3.6. --- .../GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp index c3a52ed5a8..f9bf4759ae 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp @@ -717,6 +717,13 @@ VkPhysicalDevice Instance::SelectPhysicalDevice(uint32_t AdapterId) const noexce if (IsGraphicsAndComputeQueueSupported(Device)) { + // Don't replace a hardware device with a software renderer (e.g. llvmpipe). + // On systems without a discrete GPU the loop would otherwise overwrite an + // integrated GPU with the last CPU-type device in the list. + if (SelectedPhysicalDevice != VK_NULL_HANDLE && + DeviceProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) + continue; + SelectedPhysicalDevice = Device; if (DeviceProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) break; From 327341303d67f884bb6c5d22e8dc0ac45c5beda8 Mon Sep 17 00:00:00 2001 From: IgorAlexey Date: Thu, 19 Mar 2026 16:12:27 -0300 Subject: [PATCH 2/4] Vulkan: pick best device by type, require gfx+compute queue --- .../src/VulkanUtilities/Instance.cpp | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp index f9bf4759ae..27fd6d1a72 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp @@ -706,16 +706,32 @@ VkPhysicalDevice Instance::SelectPhysicalDevice(uint32_t AdapterId) const noexce SelectedPhysicalDevice = m_PhysicalDevices[AdapterId]; } - // Select a device that exposes a queue family that supports both compute and graphics operations. - // Prefer discrete GPU. + // Select a device that exposes a queue family that supports both compute and graphics operations + // DISCRETE > INTEGRATED > everything else. if (SelectedPhysicalDevice == VK_NULL_HANDLE) { + // Returns a priority value for the device type (higher is better). + const auto GetDeviceTypePriority = [](VkPhysicalDeviceType Type) -> int { + switch (Type) + { + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return 3; + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return 2; + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return 1; + default: return 0; + } + }; + + int BestPriority = -1; for (VkPhysicalDevice Device : m_PhysicalDevices) { + if (!IsGraphicsAndComputeQueueSupported(Device)) + continue; + VkPhysicalDeviceProperties DeviceProps; vkGetPhysicalDeviceProperties(Device, &DeviceProps); - if (IsGraphicsAndComputeQueueSupported(Device)) + const int Priority = GetDeviceTypePriority(DeviceProps.deviceType); + if (Priority > BestPriority) { // Don't replace a hardware device with a software renderer (e.g. llvmpipe). // On systems without a discrete GPU the loop would otherwise overwrite an @@ -725,8 +741,7 @@ VkPhysicalDevice Instance::SelectPhysicalDevice(uint32_t AdapterId) const noexce continue; SelectedPhysicalDevice = Device; - if (DeviceProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - break; + BestPriority = Priority; } } } From 6828bdda8fe6f733d9fa5a8b31aed79ba7d3c7a9 Mon Sep 17 00:00:00 2001 From: IgorAlexey Date: Fri, 20 Mar 2026 20:32:14 -0300 Subject: [PATCH 3/4] Clang-format --- .../GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp index 27fd6d1a72..069506cc6a 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp @@ -714,10 +714,10 @@ VkPhysicalDevice Instance::SelectPhysicalDevice(uint32_t AdapterId) const noexce const auto GetDeviceTypePriority = [](VkPhysicalDeviceType Type) -> int { switch (Type) { - case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return 3; + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return 3; case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return 2; - case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return 1; - default: return 0; + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return 1; + default: return 0; } }; From 436a9958baafb91eb88f464bf27bc19a90d4d68a Mon Sep 17 00:00:00 2001 From: IgorAlexey Date: Mon, 23 Mar 2026 00:30:46 -0300 Subject: [PATCH 4/4] Remove condition --- .../GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp index 069506cc6a..56cef9a30e 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/Instance.cpp @@ -733,13 +733,6 @@ VkPhysicalDevice Instance::SelectPhysicalDevice(uint32_t AdapterId) const noexce const int Priority = GetDeviceTypePriority(DeviceProps.deviceType); if (Priority > BestPriority) { - // Don't replace a hardware device with a software renderer (e.g. llvmpipe). - // On systems without a discrete GPU the loop would otherwise overwrite an - // integrated GPU with the last CPU-type device in the list. - if (SelectedPhysicalDevice != VK_NULL_HANDLE && - DeviceProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) - continue; - SelectedPhysicalDevice = Device; BestPriority = Priority; }