From 0e353895fdd1a811209e02221cfd293b4b824ea7 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Fri, 21 Feb 2020 01:06:55 +0000 Subject: [PATCH] [d3d9] Enumerate adapters by display WPF expects us to return an adapter for every display attached otherwise it decides to device reset every frame. Closes #1459 --- src/d3d9/d3d9_adapter.cpp | 14 +++++++------ src/d3d9/d3d9_adapter.h | 4 +++- src/d3d9/d3d9_interface.cpp | 42 ++++++++++++++++++++++++++++++++++--- src/d3d9/d3d9_options.cpp | 1 + src/d3d9/d3d9_options.h | 3 +++ 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/d3d9/d3d9_adapter.cpp b/src/d3d9/d3d9_adapter.cpp index 8e75febe6..7c5e60b63 100644 --- a/src/d3d9/d3d9_adapter.cpp +++ b/src/d3d9/d3d9_adapter.cpp @@ -32,10 +32,12 @@ namespace dxvk { D3D9Adapter::D3D9Adapter( D3D9InterfaceEx* pParent, Rc Adapter, - UINT Ordinal) + UINT Ordinal, + UINT DisplayIndex) : m_parent (pParent) , m_adapter (Adapter) , m_ordinal (Ordinal) + , m_displayIndex (DisplayIndex) , m_modeCacheFormat (D3D9Format::Unknown) , m_d3d9Formats (Adapter, m_parent->GetOptions()) { m_adapter->logAdapterInfo(); @@ -52,11 +54,11 @@ namespace dxvk { const auto& props = m_adapter->deviceProperties(); - ::MONITORINFOEXA monInfo; - monInfo.cbSize = sizeof(monInfo); + DISPLAY_DEVICEA device = { }; + device.cb = sizeof(device); - if (!::GetMonitorInfoA(GetDefaultMonitor(), reinterpret_cast(&monInfo))) { - Logger::err("D3D9Adapter::GetAdapterIdentifier: Failed to query monitor info"); + if (!::EnumDisplayDevicesA(nullptr, m_displayIndex, &device, 0)) { + Logger::err("D3D9Adapter::GetAdapterIdentifier: Failed to query display info"); return D3DERR_INVALIDCALL; } @@ -68,7 +70,7 @@ namespace dxvk { const char* driver = GetDriverDLL(DxvkGpuVendor(vendorId)); std::strncpy(pIdentifier->Description, desc, countof(pIdentifier->Description)); - std::strncpy(pIdentifier->DeviceName, monInfo.szDevice, countof(pIdentifier->DeviceName)); // The GDI device name. Not the actual device name. + std::strncpy(pIdentifier->DeviceName, device.DeviceName, countof(pIdentifier->DeviceName)); // The GDI device name. Not the actual device name. std::strncpy(pIdentifier->Driver, driver, countof(pIdentifier->Driver)); // This is the driver's dll. pIdentifier->DeviceIdentifier = guid; diff --git a/src/d3d9/d3d9_adapter.h b/src/d3d9/d3d9_adapter.h index 991287aec..1ac169d26 100644 --- a/src/d3d9/d3d9_adapter.h +++ b/src/d3d9/d3d9_adapter.h @@ -18,7 +18,8 @@ namespace dxvk { D3D9Adapter( D3D9InterfaceEx* pParent, Rc Adapter, - UINT Ordinal); + UINT Ordinal, + UINT DisplayIndex); HRESULT GetAdapterIdentifier( DWORD Flags, @@ -101,6 +102,7 @@ namespace dxvk { Rc m_adapter; UINT m_ordinal; + UINT m_displayIndex; std::vector m_modes; D3D9Format m_modeCacheFormat; diff --git a/src/d3d9/d3d9_interface.cpp b/src/d3d9/d3d9_interface.cpp index 204d9f727..43f14e896 100644 --- a/src/d3d9/d3d9_interface.cpp +++ b/src/d3d9/d3d9_interface.cpp @@ -12,9 +12,45 @@ namespace dxvk { : m_instance ( new DxvkInstance() ) , m_extended ( bExtended ) , m_d3d9Options ( nullptr, m_instance->config() ) { - m_adapters.reserve(m_instance->adapterCount()); - for (uint32_t i = 0; i < m_instance->adapterCount(); i++) - m_adapters.emplace_back(this, m_instance->enumAdapters(i), i); + // D3D9 doesn't enumerate adapters like physical adapters... + // only as connected displays. + + // Let's create some "adapters" for the amount of displays we have. + // We'll go through and match up displays -> our adapters in order. + // If we run out of adapters, then we'll just make repeats of the first one. + // We can't match up by names on Linux/Wine as they don't match at all + // like on Windows, so this is our best option. + if (m_d3d9Options.enumerateByDisplays) { + DISPLAY_DEVICEA device = { }; + device.cb = sizeof(device); + + uint32_t adapterOrdinal = 0; + uint32_t i = 0; + while (::EnumDisplayDevicesA(nullptr, i++, &device, 0)) { + // If we aren't attached, skip over. + if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) + continue; + + // If we are a mirror, skip over this device. + if (device.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) + continue; + + Rc adapter = adapterOrdinal >= m_instance->adapterCount() + ? m_instance->enumAdapters(0) + : m_instance->enumAdapters(adapterOrdinal); + + if (adapter != nullptr) + m_adapters.emplace_back(this, adapter, adapterOrdinal++, i - 1); + } + } + else + { + const uint32_t adapterCount = m_instance->adapterCount(); + m_adapters.reserve(adapterCount); + + for (uint32_t i = 0; i < adapterCount; i++) + m_adapters.emplace_back(this, m_instance->enumAdapters(i), i, 0); + } if (m_d3d9Options.dpiAware) { Logger::info("Process set as DPI aware"); diff --git a/src/d3d9/d3d9_options.cpp b/src/d3d9/d3d9_options.cpp index 1ed1aaff8..f4a5ee78a 100644 --- a/src/d3d9/d3d9_options.cpp +++ b/src/d3d9/d3d9_options.cpp @@ -67,6 +67,7 @@ namespace dxvk { this->forceAspectRatio = config.getOption("d3d9.forceAspectRatio", ""); this->allowDoNotWait = config.getOption ("d3d9.allowDoNotWait", true); this->allowDiscard = config.getOption ("d3d9.allowDiscard", true); + this->enumerateByDisplays = config.getOption ("d3d9.enumerateByDisplays", true); // If we are not Nvidia, enable general hazards. this->generalHazards = adapter == nullptr || !adapter->matchesDriver(DxvkGpuVendor::Nvidia, VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR, 0, 0); diff --git a/src/d3d9/d3d9_options.h b/src/d3d9/d3d9_options.h index 582898b71..385e4fda8 100644 --- a/src/d3d9/d3d9_options.h +++ b/src/d3d9/d3d9_options.h @@ -125,6 +125,9 @@ namespace dxvk { /// Allow D3DLOCK_DISCARD bool allowDiscard; + + /// Enumerate adapters by displays + bool enumerateByDisplays; }; } \ No newline at end of file