gpu: Move device ranking to a standalone function.

This allows us to treat Dozen as an "other" driver, rather than blacklisting it outright.
This commit is contained in:
Ethan Lee
2025-11-06 20:57:26 -05:00
parent 0cc2b026e7
commit 799c6aa629

View File

@@ -81,22 +81,6 @@ typedef struct VulkanExtensions
// Conversions // Conversions
static const Uint8 DEVICE_PRIORITY_HIGHPERFORMANCE[] = {
0, // VK_PHYSICAL_DEVICE_TYPE_OTHER
3, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
4, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU
1 // VK_PHYSICAL_DEVICE_TYPE_CPU
};
static const Uint8 DEVICE_PRIORITY_LOWPOWER[] = {
0, // VK_PHYSICAL_DEVICE_TYPE_OTHER
4, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
3, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU
1 // VK_PHYSICAL_DEVICE_TYPE_CPU
};
static VkPresentModeKHR SDLToVK_PresentMode[] = { static VkPresentModeKHR SDLToVK_PresentMode[] = {
VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_KHR,
VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR,
@@ -11307,35 +11291,62 @@ static Uint8 VULKAN_INTERNAL_CreateInstance(VulkanRenderer *renderer)
return 1; return 1;
} }
static Uint8 VULKAN_INTERNAL_IsDeviceSuitable( static bool VULKAN_INTERNAL_GetDeviceRank(
VulkanRenderer *renderer, VulkanRenderer *renderer,
VkPhysicalDevice physicalDevice, VkPhysicalDevice physicalDevice,
VulkanExtensions *physicalDeviceExtensions, VulkanExtensions *physicalDeviceExtensions,
Uint32 *queueFamilyIndex,
Uint64 *deviceRank) Uint64 *deviceRank)
{ {
Uint32 queueFamilyCount, queueFamilyRank, queueFamilyBest; static const Uint8 DEVICE_PRIORITY_HIGHPERFORMANCE[] = {
VkQueueFamilyProperties *queueProps; 0, // VK_PHYSICAL_DEVICE_TYPE_OTHER
bool supportsPresent; 3, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
VkPhysicalDeviceProperties deviceProperties; 4, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
VkPhysicalDeviceFeatures deviceFeatures; 2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU
VkPhysicalDeviceMemoryProperties deviceMemory; 1 // VK_PHYSICAL_DEVICE_TYPE_CPU
Uint32 i; };
static const Uint8 DEVICE_PRIORITY_LOWPOWER[] = {
0, // VK_PHYSICAL_DEVICE_TYPE_OTHER
4, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
3, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU
1 // VK_PHYSICAL_DEVICE_TYPE_CPU
};
const Uint8 *devicePriority = renderer->preferLowPower ? DEVICE_PRIORITY_LOWPOWER : DEVICE_PRIORITY_HIGHPERFORMANCE; const Uint8 *devicePriority = renderer->preferLowPower ? DEVICE_PRIORITY_LOWPOWER : DEVICE_PRIORITY_HIGHPERFORMANCE;
/* Get the device rank before doing any checks, in case one fails. VkPhysicalDeviceType deviceType;
* Note: If no dedicated device exists, one that supports our features if (physicalDeviceExtensions->MSFT_layered_driver) {
* would be fine VkPhysicalDeviceProperties2KHR physicalDeviceProperties;
*/ VkPhysicalDeviceLayeredDriverPropertiesMSFT physicalDeviceLayeredDriverProperties;
renderer->vkGetPhysicalDeviceProperties(
physicalDevice, physicalDeviceProperties.sType =
&deviceProperties); VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
physicalDeviceProperties.pNext = &physicalDeviceLayeredDriverProperties;
physicalDeviceLayeredDriverProperties.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT;
physicalDeviceLayeredDriverProperties.pNext = NULL;
renderer->vkGetPhysicalDeviceProperties2KHR(
physicalDevice,
&physicalDeviceProperties);
if (physicalDeviceLayeredDriverProperties.underlyingAPI != VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT) {
deviceType = VK_PHYSICAL_DEVICE_TYPE_OTHER;
} else {
deviceType = physicalDeviceProperties.properties.deviceType;
}
} else {
VkPhysicalDeviceProperties physicalDeviceProperties;
renderer->vkGetPhysicalDeviceProperties(
physicalDevice,
&physicalDeviceProperties);
deviceType = physicalDeviceProperties.deviceType;
}
/* Apply a large bias on the devicePriority so that we always respect the order in the priority arrays. /* Apply a large bias on the devicePriority so that we always respect the order in the priority arrays.
* We also rank by e.g. VRAM which should have less influence than the device type. * We also rank by e.g. VRAM which should have less influence than the device type.
*/ */
Uint64 devicePriorityValue = devicePriority[deviceProperties.deviceType] * 1000000; Uint64 devicePriorityValue = devicePriority[deviceType] * 1000000;
if (*deviceRank < devicePriorityValue) { if (*deviceRank < devicePriorityValue) {
/* This device outranks the best device we've found so far! /* This device outranks the best device we've found so far!
@@ -11349,9 +11360,50 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
* run a query and reset the rank to avoid overwrites * run a query and reset the rank to avoid overwrites
*/ */
*deviceRank = 0; *deviceRank = 0;
return 0; return false;
} }
/* If we prefer high performance, sum up all device local memory (rounded to megabytes)
* to deviceRank. In the niche case of someone having multiple dedicated GPUs in the same
* system, this theoretically picks the most powerful one (or at least the one with the
* most memory!)
*
* We do this *after* discarding all non suitable devices, which means if this computer
* has multiple dedicated GPUs that all meet our criteria, *and* the user asked for high
* performance, then we always pick the GPU with more VRAM.
*/
if (!renderer->preferLowPower) {
Uint32 i;
Uint64 videoMemory = 0;
VkPhysicalDeviceMemoryProperties deviceMemory;
renderer->vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemory);
for (i = 0; i < deviceMemory.memoryHeapCount; i++) {
VkMemoryHeap heap = deviceMemory.memoryHeaps[i];
if (heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
videoMemory += heap.size;
}
}
// Round it to megabytes (as per the vulkan spec videoMemory is in bytes)
Uint64 videoMemoryRounded = videoMemory / 1024 / 1024;
*deviceRank += videoMemoryRounded;
}
return true;
}
static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
VulkanRenderer *renderer,
VkPhysicalDevice physicalDevice,
VulkanExtensions *physicalDeviceExtensions,
Uint32 *queueFamilyIndex,
Uint64 *deviceRank)
{
Uint32 queueFamilyCount, queueFamilyRank, queueFamilyBest;
VkQueueFamilyProperties *queueProps;
bool supportsPresent;
VkPhysicalDeviceFeatures deviceFeatures;
Uint32 i;
renderer->vkGetPhysicalDeviceFeatures( renderer->vkGetPhysicalDeviceFeatures(
physicalDevice, physicalDevice,
&deviceFeatures); &deviceFeatures);
@@ -11373,26 +11425,13 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
return 0; return 0;
} }
// Ignore Dozen, for now // Device rank depends on extension support, do NOT move this block any higher!
if (renderer->supports.MSFT_layered_driver) { if (!VULKAN_INTERNAL_GetDeviceRank(
VkPhysicalDeviceProperties2KHR physicalDeviceProperties; renderer,
VkPhysicalDeviceLayeredDriverPropertiesMSFT physicalDeviceLayeredDriverProperties; physicalDevice,
physicalDeviceExtensions,
physicalDeviceProperties.sType = deviceRank)) {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; return 0;
physicalDeviceProperties.pNext = &physicalDeviceLayeredDriverProperties;
physicalDeviceLayeredDriverProperties.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT;
physicalDeviceLayeredDriverProperties.pNext = NULL;
renderer->vkGetPhysicalDeviceProperties2KHR(
renderer->physicalDevice,
&physicalDeviceProperties);
if (physicalDeviceLayeredDriverProperties.underlyingAPI != VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT) {
return 0;
}
} }
renderer->vkGetPhysicalDeviceQueueFamilyProperties( renderer->vkGetPhysicalDeviceQueueFamilyProperties(
@@ -11469,30 +11508,6 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
return 0; return 0;
} }
/* If we prefer high performance, sum up all device local memory (rounded to megabytes)
* to deviceRank. In the niche case of someone having multiple dedicated GPUs in the same
* system, this theoretically picks the most powerful one (or at least the one with the
* most memory!)
*
* We do this *after* discarding all non suitable devices, which means if this computer
* has multiple dedicated GPUs that all meet our criteria, *and* the user asked for high
* performance, then we always pick the GPU with more VRAM.
*/
if (!renderer->preferLowPower) {
renderer->vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemory);
Uint64 videoMemory = 0;
for (i = 0; i < deviceMemory.memoryHeapCount; i++) {
VkMemoryHeap heap = deviceMemory.memoryHeaps[i];
if (heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
videoMemory += heap.size;
}
}
// Round it to megabytes (as per the vulkan spec videoMemory is in bytes)
Uint64 videoMemoryRounded = videoMemory / 1024 / 1024;
*deviceRank += videoMemoryRounded;
}
// FIXME: Need better structure for checking vs storing swapchain support details // FIXME: Need better structure for checking vs storing swapchain support details
return 1; return 1;
} }