GS/Vulkan: Simplify GPU selection

Hopefully stops a crash on broken drivers.
This commit is contained in:
Stenzek 2023-04-29 22:15:26 +10:00 committed by refractionpcsx2
parent 388da2058b
commit b3697579c0
3 changed files with 43 additions and 58 deletions

View File

@ -26,6 +26,8 @@
#include <array> #include <array>
#include <cstring> #include <cstring>
#include "fmt/format.h"
#ifdef _WIN32 #ifdef _WIN32
#include "common/RedtapeWindows.h" #include "common/RedtapeWindows.h"
#else #else
@ -192,83 +194,60 @@ namespace Vulkan
Context::GPUList Context::EnumerateGPUs(VkInstance instance) Context::GPUList Context::EnumerateGPUs(VkInstance instance)
{ {
GPUList gpus;
u32 gpu_count = 0; u32 gpu_count = 0;
VkResult res = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr); VkResult res = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr);
if ((res != VK_SUCCESS && res != VK_INCOMPLETE) || gpu_count == 0) if ((res != VK_SUCCESS && res != VK_INCOMPLETE) || gpu_count == 0)
{ {
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices (1) failed: "); LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices (1) failed: ");
return {}; return gpus;
} }
GPUList gpus; std::vector<VkPhysicalDevice> physical_devices(gpu_count);
gpus.resize(gpu_count); res = vkEnumeratePhysicalDevices(instance, &gpu_count, physical_devices.data());
res = vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.data());
if (res == VK_INCOMPLETE) if (res == VK_INCOMPLETE)
{ {
Console.Warning("First vkEnumeratePhysicalDevices() call returned %zu devices, but second returned %u", gpus.size(), gpu_count); Console.Warning("First vkEnumeratePhysicalDevices() call returned %zu devices, but second returned %u",
physical_devices.size(), gpu_count);
} }
else if (res != VK_SUCCESS) else if (res != VK_SUCCESS)
{ {
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices (2) failed: "); LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices (2) failed: ");
return {};
}
// Maybe we lost a GPU?
if (gpu_count < gpus.size())
gpus.resize(gpu_count);
return gpus; return gpus;
} }
Context::GPUNameList Context::EnumerateGPUNames(VkInstance instance) // Maybe we lost a GPU?
{ if (gpu_count < physical_devices.size())
u32 gpu_count = 0; physical_devices.resize(gpu_count);
VkResult res = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr);
if (res != VK_SUCCESS || gpu_count == 0)
{
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices failed: ");
return {};
}
GPUList gpus; gpus.reserve(physical_devices.size());
gpus.resize(gpu_count); for (VkPhysicalDevice device : physical_devices)
res = vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.data());
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices failed: ");
return {};
}
GPUNameList gpu_names;
gpu_names.reserve(gpu_count);
for (u32 i = 0; i < gpu_count; i++)
{ {
VkPhysicalDeviceProperties props = {}; VkPhysicalDeviceProperties props = {};
vkGetPhysicalDeviceProperties(gpus[i], &props); vkGetPhysicalDeviceProperties(device, &props);
std::string gpu_name(props.deviceName); std::string gpu_name = props.deviceName;
// handle duplicate adapter names // handle duplicate adapter names
if (std::any_of(gpu_names.begin(), gpu_names.end(), if (std::any_of(gpus.begin(), gpus.end(),
[&gpu_name](const std::string& other) { return (gpu_name == other); })) [&gpu_name](const auto& other) { return (gpu_name == other.second); }))
{ {
std::string original_adapter_name = std::move(gpu_name); std::string original_adapter_name = std::move(gpu_name);
u32 current_extra = 2; u32 current_extra = 2;
do do
{ {
gpu_name = StringUtil::StdStringFromFormat("%s (%u)", original_adapter_name.c_str(), current_extra); gpu_name = fmt::format("{} ({})", original_adapter_name, current_extra);
current_extra++; current_extra++;
} while (std::any_of(gpu_names.begin(), gpu_names.end(), } while (std::any_of(gpus.begin(), gpus.end(),
[&gpu_name](const std::string& other) { return (gpu_name == other); })); [&gpu_name](const auto& other) { return (gpu_name == other.second); }));
} }
gpu_names.push_back(std::move(gpu_name)); gpus.emplace_back(device, std::move(gpu_name));
} }
return gpu_names; return gpus;
} }
bool Context::Create(VkInstance instance, VkSurfaceKHR surface, VkPhysicalDevice physical_device, bool Context::Create(VkInstance instance, VkSurfaceKHR surface, VkPhysicalDevice physical_device,

View File

@ -66,10 +66,8 @@ namespace Vulkan
const WindowInfo& wi, bool enable_debug_utils, bool enable_validation_layer); const WindowInfo& wi, bool enable_debug_utils, bool enable_validation_layer);
// Returns a list of Vulkan-compatible GPUs. // Returns a list of Vulkan-compatible GPUs.
using GPUList = std::vector<VkPhysicalDevice>; using GPUList = std::vector<std::pair<VkPhysicalDevice, std::string>>;
using GPUNameList = std::vector<std::string>;
static GPUList EnumerateGPUs(VkInstance instance); static GPUList EnumerateGPUs(VkInstance instance);
static GPUNameList EnumerateGPUNames(VkInstance instance);
// Creates a new context and sets it up as global. // Creates a new context and sets it up as global.
static bool Create(VkInstance instance, VkSurfaceKHR surface, VkPhysicalDevice physical_device, static bool Create(VkInstance instance, VkSurfaceKHR surface, VkPhysicalDevice physical_device,

View File

@ -86,6 +86,15 @@ GSDeviceVK::~GSDeviceVK()
pxAssert(!g_vulkan_context); pxAssert(!g_vulkan_context);
} }
static void GPUListToAdapterNames(std::vector<std::string>* dest, VkInstance instance)
{
Vulkan::Context::GPUList gpus = Vulkan::Context::EnumerateGPUs(instance);
dest->clear();
dest->reserve(gpus.size());
for (auto& [gpu, name] : gpus)
dest->push_back(std::move(name));
}
void GSDeviceVK::GetAdaptersAndFullscreenModes( void GSDeviceVK::GetAdaptersAndFullscreenModes(
std::vector<std::string>* adapters, std::vector<std::string>* fullscreen_modes) std::vector<std::string>* adapters, std::vector<std::string>* fullscreen_modes)
{ {
@ -94,7 +103,7 @@ void GSDeviceVK::GetAdaptersAndFullscreenModes(
if (g_vulkan_context) if (g_vulkan_context)
{ {
if (adapters) if (adapters)
*adapters = Vulkan::Context::EnumerateGPUNames(g_vulkan_context->GetVulkanInstance()); GPUListToAdapterNames(adapters, g_vulkan_context->GetVulkanInstance());
if (fullscreen_modes) if (fullscreen_modes)
{ {
@ -111,7 +120,7 @@ void GSDeviceVK::GetAdaptersAndFullscreenModes(
if (instance != VK_NULL_HANDLE) if (instance != VK_NULL_HANDLE)
{ {
if (Vulkan::LoadVulkanInstanceFunctions(instance)) if (Vulkan::LoadVulkanInstanceFunctions(instance))
*adapters = Vulkan::Context::EnumerateGPUNames(instance); GPUListToAdapterNames(adapters, instance);
vkDestroyInstance(instance, nullptr); vkDestroyInstance(instance, nullptr);
} }
@ -606,26 +615,25 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
} }
u32 gpu_index = 0; u32 gpu_index = 0;
Vulkan::Context::GPUNameList gpu_names = Vulkan::Context::EnumerateGPUNames(instance);
if (!GSConfig.Adapter.empty()) if (!GSConfig.Adapter.empty())
{ {
for (; gpu_index < static_cast<u32>(gpu_names.size()); gpu_index++) for (; gpu_index < static_cast<u32>(gpus.size()); gpu_index++)
{ {
Console.WriteLn(fmt::format("GPU {}: {}", gpu_index, gpu_names[gpu_index])); Console.WriteLn(fmt::format("GPU {}: {}", gpu_index, gpus[gpu_index].second));
if (gpu_names[gpu_index] == GSConfig.Adapter) if (gpus[gpu_index].second == GSConfig.Adapter)
break; break;
} }
if (gpu_index == static_cast<u32>(gpu_names.size())) if (gpu_index == static_cast<u32>(gpus.size()))
{ {
Console.Warning( Console.Warning(
fmt::format("Requested GPU '{}' not found, using first ({})", GSConfig.Adapter, gpu_names[0])); fmt::format("Requested GPU '{}' not found, using first ({})", GSConfig.Adapter, gpus[0].second));
gpu_index = 0; gpu_index = 0;
} }
} }
else else
{ {
Console.WriteLn("No GPU requested, using first (%s)", gpu_names[0].c_str()); Console.WriteLn(fmt::format("No GPU requested, using first ({})", gpus[0].second));
} }
VkSurfaceKHR surface = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE;
@ -635,12 +643,12 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
}; };
if (m_window_info.type != WindowInfo::Type::Surfaceless) if (m_window_info.type != WindowInfo::Type::Surfaceless)
{ {
surface = Vulkan::SwapChain::CreateVulkanSurface(instance, gpus[gpu_index], &m_window_info); surface = Vulkan::SwapChain::CreateVulkanSurface(instance, gpus[gpu_index].first, &m_window_info);
if (surface == VK_NULL_HANDLE) if (surface == VK_NULL_HANDLE)
return false; return false;
} }
if (!Vulkan::Context::Create(instance, surface, gpus[gpu_index], !GSConfig.DisableThreadedPresentation, if (!Vulkan::Context::Create(instance, surface, gpus[gpu_index].first, !GSConfig.DisableThreadedPresentation,
enable_debug_utils, enable_validation_layer)) enable_debug_utils, enable_validation_layer))
{ {
Console.Error("Failed to create Vulkan context"); Console.Error("Failed to create Vulkan context");