diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 313df095d..6a519f34d 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -31,6 +31,7 @@ void Settings::Load(SettingsInterface& si) gpu_renderer = ParseRendererName(si.GetStringValue("GPU", "Renderer", GetRendererName(DEFAULT_GPU_RENDERER)).c_str()) .value_or(DEFAULT_GPU_RENDERER); + gpu_adapter = si.GetStringValue("GPU", "Adapter", ""); gpu_resolution_scale = static_cast(si.GetIntValue("GPU", "ResolutionScale", 1)); gpu_use_debug_device = si.GetBoolValue("GPU", "UseDebugDevice", false); gpu_true_color = si.GetBoolValue("GPU", "TrueColor", true); @@ -128,6 +129,7 @@ void Settings::Save(SettingsInterface& si) const si.SetStringValue("CPU", "ExecutionMode", GetCPUExecutionModeName(cpu_execution_mode)); si.SetStringValue("GPU", "Renderer", GetRendererName(gpu_renderer)); + si.SetStringValue("GPU", "Adapter", gpu_adapter.c_str()); si.SetIntValue("GPU", "ResolutionScale", static_cast(gpu_resolution_scale)); si.SetBoolValue("GPU", "UseDebugDevice", gpu_use_debug_device); si.SetBoolValue("GPU", "TrueColor", gpu_true_color); diff --git a/src/core/settings.h b/src/core/settings.h index f719c6f2a..6821d18a8 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -48,6 +48,7 @@ struct Settings bool load_memory_cards_from_save_states = false; GPURenderer gpu_renderer = GPURenderer::Software; + std::string gpu_adapter; u32 gpu_resolution_scale = 1; bool gpu_use_debug_device = false; bool gpu_true_color = true; diff --git a/src/duckstation-qt/d3d11hostdisplay.cpp b/src/duckstation-qt/d3d11hostdisplay.cpp index 73325c640..fc7c324fa 100644 --- a/src/duckstation-qt/d3d11hostdisplay.cpp +++ b/src/duckstation-qt/d3d11hostdisplay.cpp @@ -59,11 +59,14 @@ bool D3D11HostDisplay::hasDeviceContext() const return m_interface.HasContext(); } -bool D3D11HostDisplay::createDeviceContext(bool debug_device) +bool D3D11HostDisplay::createDeviceContext(const QString& adapter_name, bool debug_device) { std::optional wi = getWindowInfo(); - if (!wi || !m_interface.CreateContextAndSwapChain(wi.value(), shouldUseFlipModelSwapChain(), debug_device)) + if (!wi || !m_interface.CreateContextAndSwapChain(wi.value(), adapter_name.toStdString(), + shouldUseFlipModelSwapChain(), debug_device)) + { return false; + } m_window_width = static_cast(m_interface.GetSwapChainWidth()); m_window_height = static_cast(m_interface.GetSwapChainHeight()); diff --git a/src/duckstation-qt/d3d11hostdisplay.h b/src/duckstation-qt/d3d11hostdisplay.h index 0c86538da..22abf6e7f 100644 --- a/src/duckstation-qt/d3d11hostdisplay.h +++ b/src/duckstation-qt/d3d11hostdisplay.h @@ -15,7 +15,7 @@ public: ~D3D11HostDisplay(); bool hasDeviceContext() const override; - bool createDeviceContext(bool debug_device) override; + bool createDeviceContext(const QString& adapter_name, bool debug_device) override; bool initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device) override; bool activateDeviceContext() override; void deactivateDeviceContext() override; diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index 4d208127a..7aa1f2368 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -1,9 +1,9 @@ #include "mainwindow.h" +#include "aboutdialog.h" #include "common/assert.h" #include "core/game_list.h" #include "core/settings.h" #include "core/system.h" -#include "aboutdialog.h" #include "gamelistsettingswidget.h" #include "gamelistwidget.h" #include "gamepropertiesdialog.h" @@ -69,7 +69,8 @@ bool MainWindow::confirmMessage(const QString& message) return (result == QMessageBox::Yes); } -void MainWindow::createDisplay(QThread* worker_thread, bool use_debug_device, bool fullscreen, bool render_to_main) +void MainWindow::createDisplay(QThread* worker_thread, const QString& adapter_name, bool use_debug_device, + bool fullscreen, bool render_to_main) { Assert(!m_host_display && !m_display_widget); Assert(!fullscreen || !render_to_main); @@ -97,7 +98,7 @@ void MainWindow::createDisplay(QThread* worker_thread, bool use_debug_device, bo // we need the surface visible.. this might be able to be replaced with something else QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - if (!m_host_display->createDeviceContext(use_debug_device)) + if (!m_host_display->createDeviceContext(adapter_name, use_debug_device)) { reportError(tr("Failed to create host display device context.")); return; diff --git a/src/duckstation-qt/mainwindow.h b/src/duckstation-qt/mainwindow.h index 2a1f76bb3..df4ce7fa7 100644 --- a/src/duckstation-qt/mainwindow.h +++ b/src/duckstation-qt/mainwindow.h @@ -29,7 +29,8 @@ private Q_SLOTS: void reportError(const QString& message); void reportMessage(const QString& message); bool confirmMessage(const QString& message); - void createDisplay(QThread* worker_thread, bool use_debug_device, bool fullscreen, bool render_to_main); + void createDisplay(QThread* worker_thread, const QString& adapter_name, bool use_debug_device, bool fullscreen, + bool render_to_main); void updateDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main); void destroyDisplay(); void focusDisplayWidget(); diff --git a/src/duckstation-qt/openglhostdisplay.cpp b/src/duckstation-qt/openglhostdisplay.cpp index c6234e7c6..849a2632d 100644 --- a/src/duckstation-qt/openglhostdisplay.cpp +++ b/src/duckstation-qt/openglhostdisplay.cpp @@ -188,7 +188,7 @@ bool OpenGLHostDisplay::hasDeviceContext() const return static_cast(m_gl_context); } -bool OpenGLHostDisplay::createDeviceContext(bool debug_device) +bool OpenGLHostDisplay::createDeviceContext(const QString& adapter_name, bool debug_device) { m_window_width = m_widget->scaledWindowWidth(); m_window_height = m_widget->scaledWindowHeight(); diff --git a/src/duckstation-qt/openglhostdisplay.h b/src/duckstation-qt/openglhostdisplay.h index 9342ae9f4..120701bb3 100644 --- a/src/duckstation-qt/openglhostdisplay.h +++ b/src/duckstation-qt/openglhostdisplay.h @@ -26,7 +26,7 @@ public: ~OpenGLHostDisplay(); bool hasDeviceContext() const override; - bool createDeviceContext(bool debug_device) override; + bool createDeviceContext(const QString& adapter_name, bool debug_device) override; bool initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device) override; bool activateDeviceContext() override; void deactivateDeviceContext() override; diff --git a/src/duckstation-qt/qthostdisplay.cpp b/src/duckstation-qt/qthostdisplay.cpp index d7d0df492..056aa48ef 100644 --- a/src/duckstation-qt/qthostdisplay.cpp +++ b/src/duckstation-qt/qthostdisplay.cpp @@ -42,7 +42,7 @@ bool QtHostDisplay::hasDeviceContext() const return false; } -bool QtHostDisplay::createDeviceContext(bool debug_device) +bool QtHostDisplay::createDeviceContext(const QString& adapter_name, bool debug_device) { return false; } diff --git a/src/duckstation-qt/qthostdisplay.h b/src/duckstation-qt/qthostdisplay.h index dbf337406..7ea7b29cf 100644 --- a/src/duckstation-qt/qthostdisplay.h +++ b/src/duckstation-qt/qthostdisplay.h @@ -5,6 +5,7 @@ #include #include +class QString; class QThread; class QWidget; @@ -24,7 +25,7 @@ public: virtual void destroyWidget(); virtual bool hasDeviceContext() const; - virtual bool createDeviceContext(bool debug_device); + virtual bool createDeviceContext(const QString& adapter_name, bool debug_device); virtual bool initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device); virtual bool activateDeviceContext(); virtual void deactivateDeviceContext(); diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp index 5f56492ae..0afaa5269 100644 --- a/src/duckstation-qt/qthostinterface.cpp +++ b/src/duckstation-qt/qthostinterface.cpp @@ -316,8 +316,8 @@ bool QtHostInterface::AcquireHostDisplay() Assert(!m_display); m_is_rendering_to_main = getSettingValue("Main/RenderToMainWindow", true).toBool(); - emit createDisplayRequested(m_worker_thread, m_settings.gpu_use_debug_device, m_is_fullscreen, - m_is_rendering_to_main); + emit createDisplayRequested(m_worker_thread, QString::fromStdString(m_settings.gpu_adapter), + m_settings.gpu_use_debug_device, m_is_fullscreen, m_is_rendering_to_main); Assert(m_display); if (!getHostDisplay()->hasDeviceContext()) diff --git a/src/duckstation-qt/qthostinterface.h b/src/duckstation-qt/qthostinterface.h index 97993e803..783f2fe7d 100644 --- a/src/duckstation-qt/qthostinterface.h +++ b/src/duckstation-qt/qthostinterface.h @@ -96,7 +96,8 @@ Q_SIGNALS: void emulationPaused(bool paused); void stateSaved(const QString& game_code, bool global, qint32 slot); void gameListRefreshed(); - void createDisplayRequested(QThread* worker_thread, bool use_debug_device, bool fullscreen, bool render_to_main); + void createDisplayRequested(QThread* worker_thread, const QString& adapter_name, bool use_debug_device, + bool fullscreen, bool render_to_main); void updateDisplayRequested(QThread* worker_thread, bool fullscreen, bool render_to_main); void focusDisplayWidgetRequested(); void destroyDisplayRequested(); diff --git a/src/duckstation-qt/vulkanhostdisplay.cpp b/src/duckstation-qt/vulkanhostdisplay.cpp index ba86e0a1f..9cb6a5453 100644 --- a/src/duckstation-qt/vulkanhostdisplay.cpp +++ b/src/duckstation-qt/vulkanhostdisplay.cpp @@ -52,10 +52,10 @@ bool VulkanHostDisplay::hasDeviceContext() const return m_vulkan_display.HasContext(); } -bool VulkanHostDisplay::createDeviceContext(bool debug_device) +bool VulkanHostDisplay::createDeviceContext(const QString& adapter_name, bool debug_device) { std::optional wi = getWindowInfo(); - if (!wi || !m_vulkan_display.CreateContextAndSwapChain(wi.value(), debug_device)) + if (!wi || !m_vulkan_display.CreateContextAndSwapChain(wi.value(), adapter_name.toStdString(), debug_device)) return false; m_window_width = static_cast(m_vulkan_display.GetSwapChainWidth()); diff --git a/src/duckstation-qt/vulkanhostdisplay.h b/src/duckstation-qt/vulkanhostdisplay.h index dcd496cab..aee7cf99d 100644 --- a/src/duckstation-qt/vulkanhostdisplay.h +++ b/src/duckstation-qt/vulkanhostdisplay.h @@ -15,7 +15,7 @@ public: ~VulkanHostDisplay(); bool hasDeviceContext() const override; - bool createDeviceContext(bool debug_device) override; + bool createDeviceContext(const QString& adapter_name, bool debug_device) override; bool initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device) override; bool activateDeviceContext() override; void deactivateDeviceContext() override; diff --git a/src/duckstation-sdl/sdl_d3d11_host_display.cpp b/src/duckstation-sdl/sdl_d3d11_host_display.cpp index d93fc1bd5..e1e7cdafb 100644 --- a/src/duckstation-sdl/sdl_d3d11_host_display.cpp +++ b/src/duckstation-sdl/sdl_d3d11_host_display.cpp @@ -18,10 +18,10 @@ SDLD3D11HostDisplay::~SDLD3D11HostDisplay() SDL_DestroyWindow(m_window); } -std::unique_ptr SDLD3D11HostDisplay::Create(SDL_Window* window, bool debug_device) +std::unique_ptr SDLD3D11HostDisplay::Create(SDL_Window* window, std::string_view adapter_name, bool debug_device) { std::unique_ptr display = std::make_unique(window); - if (!display->Initialize(debug_device)) + if (!display->Initialize(adapter_name, debug_device)) return {}; return display; @@ -74,13 +74,13 @@ void SDLD3D11HostDisplay::SetVSync(bool enabled) m_interface.SetVSync(enabled); } -bool SDLD3D11HostDisplay::Initialize(bool debug_device) +bool SDLD3D11HostDisplay::Initialize(std::string_view adapter_name, bool debug_device) { std::optional wi = SDLUtil::GetWindowInfoForSDLWindow(m_window); if (!wi.has_value()) return false; - if (!m_interface.CreateContextAndSwapChain(wi.value(), true, debug_device)) + if (!m_interface.CreateContextAndSwapChain(wi.value(), adapter_name, true, debug_device)) return false; if (!m_interface.CreateResources()) diff --git a/src/duckstation-sdl/sdl_d3d11_host_display.h b/src/duckstation-sdl/sdl_d3d11_host_display.h index 3a3dbdca7..b172b2da7 100644 --- a/src/duckstation-sdl/sdl_d3d11_host_display.h +++ b/src/duckstation-sdl/sdl_d3d11_host_display.h @@ -12,7 +12,7 @@ public: SDLD3D11HostDisplay(SDL_Window* window); ~SDLD3D11HostDisplay(); - static std::unique_ptr Create(SDL_Window* window, bool debug_device); + static std::unique_ptr Create(SDL_Window* window, std::string_view adapter_name, bool debug_device); RenderAPI GetRenderAPI() const override; void* GetRenderDevice() const override; @@ -35,5 +35,5 @@ private: FrontendCommon::D3D11HostDisplay m_interface; - bool Initialize(bool debug_device); + bool Initialize(std::string_view adapter_name, bool debug_device); }; diff --git a/src/duckstation-sdl/sdl_host_interface.cpp b/src/duckstation-sdl/sdl_host_interface.cpp index 2ef59337e..3bf16d93b 100644 --- a/src/duckstation-sdl/sdl_host_interface.cpp +++ b/src/duckstation-sdl/sdl_host_interface.cpp @@ -129,27 +129,27 @@ void SDLHostInterface::DestroySDLWindow() bool SDLHostInterface::CreateDisplay() { - const bool debug_device = m_settings.gpu_use_debug_device; const std::string shader_cache_directory(GetShaderCacheDirectory()); std::unique_ptr display; switch (m_settings.gpu_renderer) { case GPURenderer::HardwareVulkan: - display = SDLVulkanHostDisplay::Create(m_window, shader_cache_directory, debug_device); + display = SDLVulkanHostDisplay::Create(m_window, m_settings.gpu_adapter, shader_cache_directory, + m_settings.gpu_use_debug_device); break; case GPURenderer::HardwareOpenGL: #ifndef WIN32 default: #endif - display = OpenGLHostDisplay::Create(m_window, debug_device); + display = OpenGLHostDisplay::Create(m_window, m_settings.gpu_use_debug_device); break; #ifdef WIN32 case GPURenderer::HardwareD3D11: default: - display = SDLD3D11HostDisplay::Create(m_window, debug_device); + display = SDLD3D11HostDisplay::Create(m_window, m_settings.gpu_adapter, m_settings.gpu_use_debug_device); break; #endif } diff --git a/src/duckstation-sdl/sdl_vulkan_host_display.cpp b/src/duckstation-sdl/sdl_vulkan_host_display.cpp index 075fa5f52..c7bfc67e3 100644 --- a/src/duckstation-sdl/sdl_vulkan_host_display.cpp +++ b/src/duckstation-sdl/sdl_vulkan_host_display.cpp @@ -27,11 +27,11 @@ SDLVulkanHostDisplay::~SDLVulkanHostDisplay() SDL_DestroyWindow(m_window); } -std::unique_ptr SDLVulkanHostDisplay::Create(SDL_Window* window, std::string_view shader_cache_directory, - bool debug_device) +std::unique_ptr SDLVulkanHostDisplay::Create(SDL_Window* window, std::string_view adapter_name, + std::string_view shader_cache_directory, bool debug_device) { std::unique_ptr display = std::make_unique(window); - if (!display->Initialize(shader_cache_directory, debug_device)) + if (!display->Initialize(adapter_name, shader_cache_directory, debug_device)) return nullptr; return display; @@ -84,7 +84,8 @@ void SDLVulkanHostDisplay::SetVSync(bool enabled) m_display.SetVSync(enabled); } -bool SDLVulkanHostDisplay::Initialize(std::string_view shader_cache_directory, bool debug_device) +bool SDLVulkanHostDisplay::Initialize(std::string_view adapter_name, std::string_view shader_cache_directory, + bool debug_device) { std::optional wi = SDLUtil::GetWindowInfoForSDLWindow(m_window); if (!wi.has_value()) @@ -93,7 +94,7 @@ bool SDLVulkanHostDisplay::Initialize(std::string_view shader_cache_directory, b return false; } - if (!m_display.CreateContextAndSwapChain(wi.value(), debug_device)) + if (!m_display.CreateContextAndSwapChain(wi.value(), adapter_name, debug_device)) return false; m_display.CreateShaderCache(shader_cache_directory, debug_device); diff --git a/src/duckstation-sdl/sdl_vulkan_host_display.h b/src/duckstation-sdl/sdl_vulkan_host_display.h index 76032e945..e9287c8d2 100644 --- a/src/duckstation-sdl/sdl_vulkan_host_display.h +++ b/src/duckstation-sdl/sdl_vulkan_host_display.h @@ -10,8 +10,8 @@ public: SDLVulkanHostDisplay(SDL_Window* window); ~SDLVulkanHostDisplay(); - static std::unique_ptr Create(SDL_Window* window, std::string_view shader_cache_directory, - bool debug_device); + static std::unique_ptr Create(SDL_Window* window, std::string_view adapter_name, + std::string_view shader_cache_directory, bool debug_device); RenderAPI GetRenderAPI() const override; void* GetRenderDevice() const override; @@ -33,7 +33,7 @@ public: void Render() override; private: - bool Initialize(std::string_view shader_cache_directory, bool debug_device); + bool Initialize(std::string_view adapter_name, std::string_view shader_cache_directory, bool debug_device); SDL_Window* m_window = nullptr; FrontendCommon::VulkanHostDisplay m_display; diff --git a/src/frontend-common/d3d11_host_display.cpp b/src/frontend-common/d3d11_host_display.cpp index ead55ab3b..72b1f2267 100644 --- a/src/frontend-common/d3d11_host_display.cpp +++ b/src/frontend-common/d3d11_host_display.cpp @@ -140,14 +140,55 @@ bool D3D11HostDisplay::HasContext() const return static_cast(m_device); } -bool D3D11HostDisplay::CreateContextAndSwapChain(const WindowInfo& wi, bool use_flip_model, bool debug_device) +bool D3D11HostDisplay::CreateContextAndSwapChain(const WindowInfo& wi, std::string_view adapter_name, + bool use_flip_model, bool debug_device) { UINT create_flags = 0; if (debug_device) create_flags |= D3D11_CREATE_DEVICE_DEBUG; - HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, create_flags, nullptr, 0, - D3D11_SDK_VERSION, m_device.GetAddressOf(), nullptr, m_context.GetAddressOf()); + ComPtr temp_dxgi_factory; + HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(temp_dxgi_factory.GetAddressOf())); + if (FAILED(hr)) + { + Log_ErrorPrintf("Failed to create DXGI factory: 0x%08X", hr); + return false; + } + + u32 adapter_index; + if (!adapter_name.empty()) + { + std::vector adapter_names = EnumerateAdapterNames(temp_dxgi_factory.Get()); + for (adapter_index = 0; adapter_index < static_cast(adapter_names.size()); adapter_index++) + { + if (adapter_name == adapter_names[adapter_index]) + break; + } + if (adapter_index == static_cast(adapter_names.size())) + { + Log_WarningPrintf("Could not find adapter '%s', using first (%s)", std::string(adapter_name).c_str(), + adapter_names[0].c_str()); + adapter_index = 0; + } + } + else + { + Log_InfoPrintf("No adapter selected, using first."); + adapter_index = 0; + } + + ComPtr dxgi_adapter; + hr = temp_dxgi_factory->EnumAdapters(adapter_index, dxgi_adapter.GetAddressOf()); + if (FAILED(hr)) + Log_WarningPrintf("Failed to enumerate adapter %u, using default", adapter_index); + + hr = D3D11CreateDevice(dxgi_adapter.Get(), dxgi_adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr, + create_flags, nullptr, 0, D3D11_SDK_VERSION, m_device.GetAddressOf(), nullptr, + m_context.GetAddressOf()); + + // we re-grab these later, see below + dxgi_adapter.Reset(); + temp_dxgi_factory.Reset(); if (FAILED(hr)) { @@ -168,7 +209,6 @@ bool D3D11HostDisplay::CreateContextAndSwapChain(const WindowInfo& wi, bool use_ // we need the specific factory for the device, otherwise MakeWindowAssociation() is flaky. ComPtr dxgi_device; - ComPtr dxgi_adapter; if (FAILED(m_device.As(&dxgi_device)) || FAILED(dxgi_device->GetParent(IID_PPV_ARGS(dxgi_adapter.GetAddressOf()))) || FAILED(dxgi_adapter->GetParent(IID_PPV_ARGS(m_dxgi_factory.GetAddressOf())))) { @@ -482,54 +522,56 @@ std::vector D3D11HostDisplay::EnumerateAdapterNames() { ComPtr dxgi_factory; HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(dxgi_factory.GetAddressOf())); - if (SUCCEEDED(hr)) - { - std::vector adapter_names; - ComPtr current_adapter; - while (SUCCEEDED( - dxgi_factory->EnumAdapters(static_cast(adapter_names.size()), current_adapter.ReleaseAndGetAddressOf()))) - { - DXGI_ADAPTER_DESC adapter_desc; - std::string adapter_name; - if (SUCCEEDED(current_adapter->GetDesc(&adapter_desc))) - { - char adapter_name_buffer[128]; - const int name_length = WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description, - static_cast(std::wcslen(adapter_desc.Description)), - adapter_name_buffer, countof(adapter_name_buffer), 0, nullptr); - if (name_length >= 0) - adapter_name.assign(adapter_name_buffer, static_cast(name_length)); - else - adapter_name.assign("(Unknown)"); - } - else - { - adapter_name.assign("(Unknown)"); - } + if (FAILED(hr)) + return {}; - // handle duplicate adapter names - if (std::any_of(adapter_names.begin(), adapter_names.end(), - [&adapter_name](const std::string& other) { return (adapter_name == other); })) - { - std::string original_adapter_name = std::move(adapter_name); - - u32 current_extra = 2; - do - { - adapter_name = StringUtil::StdStringFromFormat("%s (%u)", original_adapter_name.c_str(), current_extra); - current_extra++; - } while (std::any_of(adapter_names.begin(), adapter_names.end(), - [&adapter_name](const std::string& other) { return (adapter_name == other); })); - } - - adapter_names.push_back(std::move(adapter_name)); - } - - if (!adapter_names.empty()) - return adapter_names; - } - - return {"(Default)"}; + return EnumerateAdapterNames(dxgi_factory.Get()); } -} // namespace FrontendCommon \ No newline at end of file +std::vector D3D11HostDisplay::EnumerateAdapterNames(IDXGIFactory* dxgi_factory) +{ + std::vector adapter_names; + ComPtr current_adapter; + while (SUCCEEDED( + dxgi_factory->EnumAdapters(static_cast(adapter_names.size()), current_adapter.ReleaseAndGetAddressOf()))) + { + DXGI_ADAPTER_DESC adapter_desc; + std::string adapter_name; + if (SUCCEEDED(current_adapter->GetDesc(&adapter_desc))) + { + char adapter_name_buffer[128]; + const int name_length = WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description, + static_cast(std::wcslen(adapter_desc.Description)), + adapter_name_buffer, countof(adapter_name_buffer), 0, nullptr); + if (name_length >= 0) + adapter_name.assign(adapter_name_buffer, static_cast(name_length)); + else + adapter_name.assign("(Unknown)"); + } + else + { + adapter_name.assign("(Unknown)"); + } + + // handle duplicate adapter names + if (std::any_of(adapter_names.begin(), adapter_names.end(), + [&adapter_name](const std::string& other) { return (adapter_name == other); })) + { + std::string original_adapter_name = std::move(adapter_name); + + u32 current_extra = 2; + do + { + adapter_name = StringUtil::StdStringFromFormat("%s (%u)", original_adapter_name.c_str(), current_extra); + current_extra++; + } while (std::any_of(adapter_names.begin(), adapter_names.end(), + [&adapter_name](const std::string& other) { return (adapter_name == other); })); + } + + adapter_names.push_back(std::move(adapter_name)); + } + + return adapter_names; +} + +} // namespace FrontendCommon diff --git a/src/frontend-common/d3d11_host_display.h b/src/frontend-common/d3d11_host_display.h index 637340514..4617a6f2b 100644 --- a/src/frontend-common/d3d11_host_display.h +++ b/src/frontend-common/d3d11_host_display.h @@ -8,9 +8,10 @@ #include #include #include -#include -#include #include +#include +#include +#include namespace FrontendCommon { @@ -27,7 +28,8 @@ public: ALWAYS_INLINE void* GetRenderDevice() const { return m_device.Get(); } ALWAYS_INLINE void* GetRenderContext() const { return m_context.Get(); } - bool CreateContextAndSwapChain(const WindowInfo& wi, bool use_flip_model, bool debug_device); + bool CreateContextAndSwapChain(const WindowInfo& wi, std::string_view adapter_name, bool use_flip_model, + bool debug_device); bool HasContext() const; void DestroyContext(); @@ -67,6 +69,8 @@ public: private: static constexpr u32 DISPLAY_UNIFORM_BUFFER_SIZE = 16; + static std::vector EnumerateAdapterNames(IDXGIFactory* dxgi_factory); + bool CreateSwapChain(const WindowInfo& new_wi, bool use_flip_model); bool CreateSwapChainRTV(); diff --git a/src/frontend-common/vulkan_host_display.cpp b/src/frontend-common/vulkan_host_display.cpp index 2d5e14c7b..f6d2a88ab 100644 --- a/src/frontend-common/vulkan_host_display.cpp +++ b/src/frontend-common/vulkan_host_display.cpp @@ -192,9 +192,9 @@ void VulkanHostDisplay::SetVSync(bool enabled) m_swap_chain->SetVSync(enabled); } -bool VulkanHostDisplay::CreateContextAndSwapChain(const WindowInfo& wi, bool debug_device) +bool VulkanHostDisplay::CreateContextAndSwapChain(const WindowInfo& wi, std::string_view gpu_name, bool debug_device) { - if (!Vulkan::Context::Create({}, &wi, &m_swap_chain, debug_device, false)) + if (!Vulkan::Context::Create(gpu_name, &wi, &m_swap_chain, debug_device, false)) { Log_ErrorPrintf("Failed to create Vulkan context"); return false; diff --git a/src/frontend-common/vulkan_host_display.h b/src/frontend-common/vulkan_host_display.h index a17e2a2ec..2f1613d70 100644 --- a/src/frontend-common/vulkan_host_display.h +++ b/src/frontend-common/vulkan_host_display.h @@ -41,7 +41,7 @@ public: void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle); void EndRenderAndPresent(); - bool CreateContextAndSwapChain(const WindowInfo& wi, bool debug_device); + bool CreateContextAndSwapChain(const WindowInfo& wi, std::string_view gpu_name, bool debug_device); bool HasContext() const; void DestroyContext();