From 14eb469005fd0270d95133e3c83f9e4c5d1f405d Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 9 May 2023 12:24:54 +0200 Subject: [PATCH] [dxgi] Be more robust against monitor enumeration issues. If there are monitors on the system that are not associated with any adapter, enumerate all monitors for all adatpers. May solve some issues if device filter options are used on multi-GPU systems. --- src/dxgi/dxgi_adapter.cpp | 6 +++- src/dxgi/dxgi_factory.cpp | 58 ++++++++++++++++++++++++++++++++++----- src/dxgi/dxgi_factory.h | 5 ++++ 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/dxgi/dxgi_adapter.cpp b/src/dxgi/dxgi_adapter.cpp index 1094e43b4ce..854a7373024 100644 --- a/src/dxgi/dxgi_adapter.cpp +++ b/src/dxgi/dxgi_adapter.cpp @@ -162,7 +162,7 @@ namespace dxvk { auto linkedAdapter = m_adapter->linkedIGPUAdapter(); - /* If either LUID is not valid enumerate all monitors. */ + // If either LUID is not valid, enumerate all monitors. if (numLUIDs && linkedAdapter != nullptr) { const auto& deviceId = linkedAdapter->devicePropertiesExt().vk11; @@ -172,6 +172,10 @@ namespace dxvk { numLUIDs = 0; } + // Enumerate all monitors if the robustness fallback is active. + if (m_factory->UseMonitorFallback()) + numLUIDs = 0; + HMONITOR monitor = wsi::enumMonitors(adapterLUIDs.data(), numLUIDs, Output); if (monitor == nullptr) diff --git a/src/dxgi/dxgi_factory.cpp b/src/dxgi/dxgi_factory.cpp index 3e218ecb4de..314a30b047b 100644 --- a/src/dxgi/dxgi_factory.cpp +++ b/src/dxgi/dxgi_factory.cpp @@ -1,3 +1,5 @@ +#include + #include "dxgi_factory.h" #include "dxgi_surface.h" #include "dxgi_swapchain.h" @@ -48,13 +50,55 @@ namespace dxvk { DxgiFactory::DxgiFactory(UINT Flags) - : m_instance (g_dxvkInstance.acquire()), - m_interop (this), - m_options (m_instance->config()), - m_monitorInfo (this, m_options), - m_flags (Flags) { - for (uint32_t i = 0; m_instance->enumAdapters(i) != nullptr; i++) - m_instance->enumAdapters(i)->logAdapterInfo(); + : m_instance (g_dxvkInstance.acquire()), + m_interop (this), + m_options (m_instance->config()), + m_monitorInfo (this, m_options), + m_flags (Flags), + m_monitorFallback (false) { + // Be robust against situations where some monitors are not + // associated with any adapter. This can happen if device + // filter options are used. + std::vector monitors; + + for (uint32_t i = 0; ; i++) { + HMONITOR hmon = wsi::enumMonitors(i); + + if (!hmon) + break; + + monitors.push_back(hmon); + } + + for (uint32_t i = 0; m_instance->enumAdapters(i) != nullptr; i++) { + auto adapter = m_instance->enumAdapters(i); + adapter->logAdapterInfo(); + + // Remove all monitors that are associated + // with the current adapter from the list. + const auto& vk11 = adapter->devicePropertiesExt().vk11; + + if (vk11.deviceLUIDValid) { + auto luid = reinterpret_cast(&vk11.deviceLUID); + + for (uint32_t j = 0; ; j++) { + HMONITOR hmon = wsi::enumMonitors(&luid, 1, j); + + if (!hmon) + break; + + auto entry = std::find(monitors.begin(), monitors.end(), hmon); + + if (entry != monitors.end()) + monitors.erase(entry); + } + } + } + + // If any monitors are left on the list, enable the + // fallback to always enumerate all monitors. + if ((m_monitorFallback = !monitors.empty())) + Logger::warn("DXGI: Found monitors not associated with any adapter, using fallback"); } diff --git a/src/dxgi/dxgi_factory.h b/src/dxgi/dxgi_factory.h index 72af2f3c080..5c65bf49db2 100644 --- a/src/dxgi/dxgi_factory.h +++ b/src/dxgi/dxgi_factory.h @@ -158,6 +158,10 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE UnregisterAdaptersChangedEvent( DWORD Cookie); + BOOL UseMonitorFallback() const { + return m_monitorFallback; + } + Rc GetDXVKInstance() const { return m_instance; } @@ -177,6 +181,7 @@ namespace dxvk { DxgiOptions m_options; DxgiMonitorInfo m_monitorInfo; UINT m_flags; + BOOL m_monitorFallback; HWND m_associatedWindow = nullptr;