diff --git a/idd/LGIdd/CIndirectDeviceContext.cpp b/idd/LGIdd/CIndirectDeviceContext.cpp index 7e0dc0ae..de4b68c8 100644 --- a/idd/LGIdd/CIndirectDeviceContext.cpp +++ b/idd/LGIdd/CIndirectDeviceContext.cpp @@ -635,6 +635,39 @@ void CIndirectDeviceContext::ReplugMonitor() m_finishInitQueued.store(1); } +void CIndirectDeviceContext::ReloadSettings() +{ + bool modesLoaded = false; + + AcquireSRWLockExclusive(&m_modeReloadLock); + + CSettings::DisplayMode extraMode; + if (g_settings.GetExtraMode(extraMode)) + { + const unsigned refresh = g_settings.GetDefaultRefresh(); + if (extraMode.refresh != refresh) + { + extraMode.refresh = refresh; + if (!g_settings.SetExtraMode(extraMode)) + { + ReleaseSRWLockExclusive(&m_modeReloadLock); + return; + } + } + } + + modesLoaded = PopulateDefaultModes(); + ReleaseSRWLockExclusive(&m_modeReloadLock); + + if (!modesLoaded) + { + DEBUG_ERROR("Failed to reload the display mode list"); + return; + } + + ReplugMonitor(); +} + void CIndirectDeviceContext::OnMonitorDestroyed(IDDCX_MONITOR monitor) { AcquireSRWLockExclusive(&m_stateLock); @@ -936,19 +969,23 @@ void CIndirectDeviceContext::SetResolution(uint32_t width, uint32_t height) mode.refresh = g_settings.GetDefaultRefresh(); mode.preferred = true; - AcquireSRWLockExclusive(&m_stateLock); - m_setMode = mode; - m_doSetMode = true; - ReleaseSRWLockExclusive(&m_stateLock); + bool modesLoaded = false; + AcquireSRWLockExclusive(&m_modeReloadLock); + if (g_settings.SetExtraMode(mode)) + modesLoaded = PopulateDefaultModes(); + ReleaseSRWLockExclusive(&m_modeReloadLock); - g_settings.SetExtraMode(mode); - - if (!PopulateDefaultModes()) + if (!modesLoaded) { DEBUG_ERROR("Failed to rebuild the display mode list"); return; } + AcquireSRWLockExclusive(&m_stateLock); + m_setMode = mode; + m_doSetMode = true; + ReleaseSRWLockExclusive(&m_stateLock); + // IddCxMonitorUpdateModes[2] does not invalidate Windows' cached mode list, // so the only reliable way to apply a new mode is to depart and re-arrive the // monitor, forcing Windows to rebuild the topology from the new mode list. diff --git a/idd/LGIdd/CIndirectDeviceContext.h b/idd/LGIdd/CIndirectDeviceContext.h index 358ba8dd..9dbaae1b 100644 --- a/idd/LGIdd/CIndirectDeviceContext.h +++ b/idd/LGIdd/CIndirectDeviceContext.h @@ -215,6 +215,11 @@ private: // Never held across an IddCx API call - snapshot then call. mutable SRWLOCK m_modeLock = SRWLOCK_INIT; + // Serializes registry-backed mode changes with rebuilding m_displayModes. + // Reload requests arrive on the pipe thread while dynamic resolution + // requests arrive on the LGMP timer thread. + SRWLOCK m_modeReloadLock = SRWLOCK_INIT; + CSettings::DisplayModes m_displayModes; CEdid m_edid; @@ -238,6 +243,7 @@ public: void InitAdapter(); void FinishAdapterInit(UINT connectorIndex); void FinishInit(UINT connectorIndex); + void ReloadSettings(); void ReplugMonitor(); void OnMonitorDestroyed(IDDCX_MONITOR monitor); diff --git a/idd/LGIdd/CPipeServer.cpp b/idd/LGIdd/CPipeServer.cpp index 24fab90b..cee504aa 100644 --- a/idd/LGIdd/CPipeServer.cpp +++ b/idd/LGIdd/CPipeServer.cpp @@ -262,7 +262,7 @@ void CPipeServer::HandleReloadSettings() AcquireSRWLockShared(&m_deviceContextLock); if (m_deviceContext) - m_deviceContext->ReplugMonitor(); + m_deviceContext->ReloadSettings(); ReleaseSRWLockShared(&m_deviceContextLock); } diff --git a/idd/LGIdd/CSettings.cpp b/idd/LGIdd/CSettings.cpp index ae3bd03c..4bab5d8c 100644 --- a/idd/LGIdd/CSettings.cpp +++ b/idd/LGIdd/CSettings.cpp @@ -76,7 +76,7 @@ CSettings::DisplayModes CSettings::LoadModes() return displayModes; } -void CSettings::SetExtraMode(const DisplayMode& mode) +bool CSettings::SetExtraMode(const DisplayMode& mode) { WCHAR buf[64]; _snwprintf_s(buf, _countof(buf), _TRUNCATE, L"%ux%u@%u%s", @@ -94,15 +94,24 @@ void CSettings::SetExtraMode(const DisplayMode& mode) if (ec != ERROR_SUCCESS) { - DEBUG_INFO("Failed to write key"); - return; + DEBUG_ERROR_HR(ec, "Failed to open settings key for ExtraMode"); + return false; } const WCHAR* valueName = L"ExtraMode"; const DWORD cb = (DWORD)((wcslen(buf) + 1) * sizeof(WCHAR)); - RegSetValueExW(hKey, valueName, 0, REG_SZ, (const BYTE*)buf, cb); + ec = RegSetValueExW(hKey, valueName, 0, REG_SZ, + (const BYTE*)buf, cb); RegCloseKey(hKey); + + if (ec != ERROR_SUCCESS) + { + DEBUG_ERROR_HR(ec, "Failed to write ExtraMode"); + return false; + } + + return true; } std::wstring CSettings::ReadStringValue(const wchar_t* name, const wchar_t* defaultValue) diff --git a/idd/LGIdd/CSettings.h b/idd/LGIdd/CSettings.h index f31a763e..7b932557 100644 --- a/idd/LGIdd/CSettings.h +++ b/idd/LGIdd/CSettings.h @@ -39,7 +39,7 @@ class CSettings CSettings(); DisplayModes LoadModes(); - void SetExtraMode(const DisplayMode & mode); + bool SetExtraMode(const DisplayMode & mode); bool GetExtraMode(DisplayMode & mode); unsigned GetDefaultRefresh() const;