diff --git a/doc/idd_configuration.rst b/doc/idd_configuration.rst index ec78fa9d..f3ec787b 100644 --- a/doc/idd_configuration.rst +++ b/doc/idd_configuration.rst @@ -71,6 +71,13 @@ Force full direct frame copies disabled unless you encounter corruption. Changing it requests a driver reload. +Force indirect copy + Disables direct D3D12 access to the shared transport heap and instead + copies each frame through a CPU-mapped readback resource. Enable this only + to work around a GPU driver that corrupts direct transport writes: it adds + a CPU copy and significantly reduces throughput. It takes precedence over + the direct-copy preference and requests a driver reload when changed. + Unlike mode-list edits, preference checkboxes are saved when clicked. Software processing diff --git a/idd/LGIdd/config/CSettings.h b/idd/LGIdd/config/CSettings.h index b4b967e6..d2b7dc92 100644 --- a/idd/LGIdd/config/CSettings.h +++ b/idd/LGIdd/config/CSettings.h @@ -101,6 +101,11 @@ class CSettings return ReadBoolValue(L"ForceFullDirectCopy"); } + static bool ShouldForceIndirectCopy() + { + return ReadBoolValue(L"ForceIndirectCopy"); + } + private: static const wchar_t * RegistryKey() { diff --git a/idd/LGIdd/d3d/CD3D12Device.cpp b/idd/LGIdd/d3d/CD3D12Device.cpp index 42595201..94d86a1f 100644 --- a/idd/LGIdd/d3d/CD3D12Device.cpp +++ b/idd/LGIdd/d3d/CD3D12Device.cpp @@ -19,6 +19,7 @@ */ #include "d3d/CD3D12Device.h" +#include "config/CSettings.h" #include "CDebug.h" bool CD3D12Device::s_directHeapFailed = false; @@ -66,8 +67,12 @@ CD3D12Device::InitResult CD3D12Device::Init( { HRESULT hr; + const bool forceIndirectCopy = CSettings::ShouldForceIndirectCopy(); m_computeEnabled = enableCompute; - m_indirectCopy = !directMemory || s_directHeapFailed; + m_indirectCopy = !directMemory || s_directHeapFailed || forceIndirectCopy; + + if (forceIndirectCopy) + DEBUG_INFO("Forcing indirect transport copies"); hr = CreateDXGIFactory2(m_debug ? DXGI_CREATE_FACTORY_DEBUG : 0, IID_PPV_ARGS(&m_factory)); if (FAILED(hr)) diff --git a/idd/LGIddHelper/CConfigWindow.cpp b/idd/LGIddHelper/CConfigWindow.cpp index c91ad183..5a51b22f 100644 --- a/idd/LGIddHelper/CConfigWindow.cpp +++ b/idd/LGIddHelper/CConfigWindow.cpp @@ -55,6 +55,7 @@ CConfigWindow::CConfigWindow() : m_scale(1) m_noGPU = m_settings.getNoGPU(); m_exclusive = m_settings.getExclusiveMonitor(); m_forceFullDirectCopy = m_settings.getForceFullDirectCopy(); + m_forceIndirectCopy = m_settings.getForceIndirectCopy(); } if (!CreateWindowEx(0, MAKEINTATOM(s_atom), L"Looking Glass IDD Configuration", @@ -96,6 +97,7 @@ void CConfigWindow::updateFont() *m_defRefreshLabel, *m_defRefresh, *m_defRefreshHz, *m_modeSave, *m_modeRevert, *m_prefGroup, *m_prefNoGPU, *m_prefExclusive, *m_prefForceFullDirectCopy, + *m_prefForceIndirectCopy, })) SendMessage(child, WM_SETFONT, (WPARAM)m_font.Get(), 1); } @@ -191,6 +193,8 @@ LRESULT CConfigWindow::onCreate() m_prefExclusive.reset(new CCheckbox(L"Make LG the only monitor", 0, m_hwnd)); m_prefForceFullDirectCopy.reset(new CCheckbox( L"Force full direct frame copies", 0, m_hwnd)); + m_prefForceIndirectCopy.reset(new CCheckbox( + L"Force indirect copy", 0, m_hwnd)); if (m_noGPU) m_prefNoGPU->setChecked(*m_noGPU); @@ -201,6 +205,9 @@ LRESULT CConfigWindow::onCreate() if (m_forceFullDirectCopy) m_prefForceFullDirectCopy->setChecked(*m_forceFullDirectCopy); + if (m_forceIndirectCopy) + m_prefForceIndirectCopy->setChecked(*m_forceIndirectCopy); + LONG width, height; getMinimumSize(width, height); SetWindowPos(m_hwnd, NULL, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER); @@ -240,10 +247,11 @@ LRESULT CConfigWindow::onResize(DWORD width, DWORD height) pos.pinBottomLeft(*m_modeSave, 20, 20, 132, 24); pos.pinBottomLeft(*m_modeRevert, 154, 20, 50, 24); - pos.pinTopLeft(*m_prefGroup, 224, 40, 200, 92); + pos.pinTopLeft(*m_prefGroup, 224, 40, 200, 112); pos.pinTopLeft(*m_prefNoGPU, 236, 64, 176, 20); pos.pinTopLeft(*m_prefExclusive, 236, 84, 176, 20); pos.pinTopLeft(*m_prefForceFullDirectCopy, 236, 104, 188, 20); + pos.pinTopLeft(*m_prefForceIndirectCopy, 236, 124, 188, 20); return 0; } @@ -368,6 +376,22 @@ LRESULT CConfigWindow::onCommand(WORD id, WORD code, HWND hwnd) m_prefForceFullDirectCopy->setChecked(value); sendSettingChange(); } + else if (m_prefForceIndirectCopy && + hwnd == *m_prefForceIndirectCopy && code == BN_CLICKED && + m_forceIndirectCopy) + { + const bool value = !*m_forceIndirectCopy; + const LSTATUS result = m_settings.setForceIndirectCopy(value); + if (result != ERROR_SUCCESS) + { + DEBUG_ERROR_HR(result, "Failed to save ForceIndirectCopy"); + return 0; + } + + *m_forceIndirectCopy = value; + m_prefForceIndirectCopy->setChecked(value); + sendSettingChange(); + } else if (m_modeSave && hwnd == *m_modeSave && code == BN_CLICKED) { bool updated = false; diff --git a/idd/LGIddHelper/CConfigWindow.h b/idd/LGIddHelper/CConfigWindow.h index 87d7cd57..f4b50cec 100644 --- a/idd/LGIddHelper/CConfigWindow.h +++ b/idd/LGIddHelper/CConfigWindow.h @@ -65,6 +65,7 @@ class CConfigWindow : public CWindow std::unique_ptr m_prefNoGPU; std::unique_ptr m_prefExclusive; std::unique_ptr m_prefForceFullDirectCopy; + std::unique_ptr m_prefForceIndirectCopy; std::function m_onDestroy; std::function m_onSettingChange; @@ -77,6 +78,7 @@ class CConfigWindow : public CWindow std::optional m_noGPU; std::optional m_exclusive; std::optional m_forceFullDirectCopy; + std::optional m_forceIndirectCopy; void getMinimumSize(LONG &width, LONG &height); void updateFont(); diff --git a/idd/LGIddHelper/CRegistrySettings.cpp b/idd/LGIddHelper/CRegistrySettings.cpp index 016d2752..54f7c4ed 100644 --- a/idd/LGIddHelper/CRegistrySettings.cpp +++ b/idd/LGIddHelper/CRegistrySettings.cpp @@ -290,3 +290,28 @@ LSTATUS CRegistrySettings::setForceFullDirectCopy(bool forceFullCopy) return RegSetValueEx(hKey, L"ForceFullDirectCopy", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD)); } + +std::optional CRegistrySettings::getForceIndirectCopy() +{ + DWORD result, cbData = sizeof result; + + LSTATUS status = RegGetValue(hKey, nullptr, L"ForceIndirectCopy", + RRF_RT_REG_DWORD, nullptr, &result, &cbData); + switch (status) + { + case ERROR_SUCCESS: + return !!result; + case ERROR_FILE_NOT_FOUND: + return false; + default: + DEBUG_ERROR_HR(status, "RegGetValue(ForceIndirectCopy)"); + return {}; + } +} + +LSTATUS CRegistrySettings::setForceIndirectCopy(bool forceIndirectCopy) +{ + DWORD dwValue = forceIndirectCopy; + return RegSetValueEx(hKey, L"ForceIndirectCopy", 0, REG_DWORD, + (LPBYTE)&dwValue, sizeof(DWORD)); +} diff --git a/idd/LGIddHelper/CRegistrySettings.h b/idd/LGIddHelper/CRegistrySettings.h index e4d44f22..b66d5b1b 100644 --- a/idd/LGIddHelper/CRegistrySettings.h +++ b/idd/LGIddHelper/CRegistrySettings.h @@ -59,4 +59,7 @@ public: std::optional getForceFullDirectCopy(); LSTATUS setForceFullDirectCopy(bool forceFullCopy); + + std::optional getForceIndirectCopy(); + LSTATUS setForceIndirectCopy(bool forceIndirectCopy); };