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 <cstring>
#include "fmt/format.h"
#ifdef _WIN32
#include "common/RedtapeWindows.h"
#else
@ -192,83 +194,60 @@ namespace Vulkan
Context::GPUList Context::EnumerateGPUs(VkInstance instance)
{
GPUList gpus;
u32 gpu_count = 0;
VkResult res = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr);
if ((res != VK_SUCCESS && res != VK_INCOMPLETE) || gpu_count == 0)
{
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices (1) failed: ");
return {};
return gpus;
}
GPUList gpus;
gpus.resize(gpu_count);
res = vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.data());
std::vector<VkPhysicalDevice> physical_devices(gpu_count);
res = vkEnumeratePhysicalDevices(instance, &gpu_count, physical_devices.data());
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)
{
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices (2) failed: ");
return {};
return gpus;
}
// Maybe we lost a GPU?
if (gpu_count < gpus.size())
gpus.resize(gpu_count);
if (gpu_count < physical_devices.size())
physical_devices.resize(gpu_count);
return gpus;
}
Context::GPUNameList Context::EnumerateGPUNames(VkInstance instance)
{
u32 gpu_count = 0;
VkResult res = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr);
if (res != VK_SUCCESS || gpu_count == 0)
{
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices failed: ");
return {};
}
GPUList gpus;
gpus.resize(gpu_count);
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++)
gpus.reserve(physical_devices.size());
for (VkPhysicalDevice device : physical_devices)
{
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
if (std::any_of(gpu_names.begin(), gpu_names.end(),
[&gpu_name](const std::string& other) { return (gpu_name == other); }))
if (std::any_of(gpus.begin(), gpus.end(),
[&gpu_name](const auto& other) { return (gpu_name == other.second); }))
{
std::string original_adapter_name = std::move(gpu_name);
u32 current_extra = 2;
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++;
} while (std::any_of(gpu_names.begin(), gpu_names.end(),
[&gpu_name](const std::string& other) { return (gpu_name == other); }));
} while (std::any_of(gpus.begin(), gpus.end(),
[&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,

View File

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

View File

@ -86,6 +86,15 @@ GSDeviceVK::~GSDeviceVK()
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(
std::vector<std::string>* adapters, std::vector<std::string>* fullscreen_modes)
{
@ -94,7 +103,7 @@ void GSDeviceVK::GetAdaptersAndFullscreenModes(
if (g_vulkan_context)
{
if (adapters)
*adapters = Vulkan::Context::EnumerateGPUNames(g_vulkan_context->GetVulkanInstance());
GPUListToAdapterNames(adapters, g_vulkan_context->GetVulkanInstance());
if (fullscreen_modes)
{
@ -111,7 +120,7 @@ void GSDeviceVK::GetAdaptersAndFullscreenModes(
if (instance != VK_NULL_HANDLE)
{
if (Vulkan::LoadVulkanInstanceFunctions(instance))
*adapters = Vulkan::Context::EnumerateGPUNames(instance);
GPUListToAdapterNames(adapters, instance);
vkDestroyInstance(instance, nullptr);
}
@ -606,26 +615,25 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
}
u32 gpu_index = 0;
Vulkan::Context::GPUNameList gpu_names = Vulkan::Context::EnumerateGPUNames(instance);
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]));
if (gpu_names[gpu_index] == GSConfig.Adapter)
Console.WriteLn(fmt::format("GPU {}: {}", gpu_index, gpus[gpu_index].second));
if (gpus[gpu_index].second == GSConfig.Adapter)
break;
}
if (gpu_index == static_cast<u32>(gpu_names.size()))
if (gpu_index == static_cast<u32>(gpus.size()))
{
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;
}
}
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;
@ -635,12 +643,12 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
};
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)
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))
{
Console.Error("Failed to create Vulkan context");