[idd] helper: preserve mode apply transaction

This commit is contained in:
Geoffrey McRae
2026-08-17 13:21:08 +10:00
parent cec1a16cfc
commit 571a58b716
2 changed files with 18 additions and 72 deletions

View File

@@ -196,58 +196,12 @@ namespace
return lgIndex != SIZE_MAX; return lgIndex != SIZE_MAX;
} }
bool GetLGDisplayState(DisplayState& state)
{
DISPLAY_DEVICE device = {};
device.cb = sizeof(device);
for (DWORD i = 0; EnumDisplayDevices(NULL, i, &device, 0); ++i)
{
if ((device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) &&
!(device.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) &&
IsLGDisplay(device))
{
state = {};
state.device = device;
state.mode.dmSize = sizeof(state.mode);
state.isLG = true;
return EnumDisplaySettingsEx(device.DeviceName, ENUM_CURRENT_SETTINGS,
&state.mode, 0) != FALSE;
}
device = {};
device.cb = sizeof(device);
}
return false;
}
uint32_t DisplayModeRefresh(const LGPipeMsg& msg) uint32_t DisplayModeRefresh(const LGPipeMsg& msg)
{ {
return (msg.displayMode.refresh100uHz + LG_REFRESH_RATE_SCALE / 2) / return (msg.displayMode.refresh100uHz + LG_REFRESH_RATE_SCALE / 2) /
LG_REFRESH_RATE_SCALE; LG_REFRESH_RATE_SCALE;
} }
bool FindDisplayMode(const DisplayState& display, const LGPipeMsg& msg,
DEVMODE& mode)
{
const uint32_t refresh = DisplayModeRefresh(msg);
for (DWORD i = 0; ; ++i)
{
DEVMODE candidate = {};
candidate.dmSize = sizeof(candidate);
if (!EnumDisplaySettingsEx(display.device.DeviceName, i, &candidate, 0))
return false;
if (candidate.dmPelsWidth == msg.displayMode.width &&
candidate.dmPelsHeight == msg.displayMode.height &&
candidate.dmDisplayFrequency == refresh)
{
mode = candidate;
return true;
}
}
}
bool HasActiveDisplay(bool lg) bool HasActiveDisplay(bool lg)
{ {
DISPLAY_DEVICE device = {}; DISPLAY_DEVICE device = {};
@@ -613,38 +567,28 @@ bool CPipeClient::ApplyDisplayMode(const LGPipeMsg& msg, LONG& result)
{ {
CSRWExclusiveLock lock(m_displayLock); CSRWExclusiveLock lock(m_displayLock);
DisplayState display = {}; std::vector<DisplayState> displays;
if (!GetLGDisplayState(display)) size_t lgIndex;
if (!GetDisplayStates(displays, lgIndex))
{ {
result = DISP_CHANGE_FAILED; result = DISP_CHANGE_FAILED;
return false; return false;
} }
DEVMODE mode = {}; // Preserve the original mode-application transaction: Windows accepts the
if (!FindDisplayMode(display, msg, mode)) // requested values before EnumDisplaySettingsEx necessarily lists the new
{ // mode after a monitor replug.
result = DISP_CHANGE_BADMODE; DEVMODE mode = displays[lgIndex].mode;
return false; mode.dmPelsWidth = msg.displayMode.width;
} mode.dmPelsHeight = msg.displayMode.height;
mode.dmDisplayFrequency = DisplayModeRefresh(msg);
mode.dmFields = mode.dmFields =
DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
result = ChangeDisplaySettingsEx(display.device.DeviceName, result = ChangeDisplaySettingsEx(displays[lgIndex].device.DeviceName,
&mode, NULL, CDS_UPDATEREGISTRY, NULL); &mode, NULL, CDS_UPDATEREGISTRY, NULL);
return result == DISP_CHANGE_SUCCESSFUL; return result == DISP_CHANGE_SUCCESSFUL;
} }
bool CPipeClient::VerifyDisplayMode(const LGPipeMsg& msg)
{
CSRWExclusiveLock lock(m_displayLock);
DisplayState display = {};
return GetLGDisplayState(display) &&
display.mode.dmPelsWidth == msg.displayMode.width &&
display.mode.dmPelsHeight == msg.displayMode.height &&
display.mode.dmDisplayFrequency == DisplayModeRefresh(msg);
}
void CPipeClient::DisplayModeThread() void CPipeClient::DisplayModeThread()
{ {
const HANDLE handles[] = { m_displayModeStop, m_displayModeWake }; const HANDLE handles[] = { m_displayModeStop, m_displayModeWake };
@@ -683,7 +627,10 @@ void CPipeClient::DisplayModeThread()
LONG result = DISP_CHANGE_FAILED; LONG result = DISP_CHANGE_FAILED;
if (ApplyDisplayMode(msg, result)) if (ApplyDisplayMode(msg, result))
{ {
if (EnsureOnlyDisplay() && VerifyDisplayMode(msg)) // A requested resolution replug is also a topology transition. Keep
// the original apply-then-enforce ordering so LG remains the only
// active (and therefore primary) display on this path.
if (EnsureOnlyDisplay())
{ {
CSRWExclusiveLock lock(m_displayModeLock); CSRWExclusiveLock lock(m_displayModeLock);
if (serial == m_displayModeSerial) if (serial == m_displayModeSerial)
@@ -1225,9 +1172,9 @@ void CPipeClient::HandleSetCursorPos(const LGPipeMsg& msg)
void CPipeClient::HandleSetDisplayMode(const LGPipeMsg& msg) void CPipeClient::HandleSetDisplayMode(const LGPipeMsg& msg)
{ {
// The IDD reaches swap-chain readiness before Win32 has necessarily // The IDD reaches swap-chain readiness while the replugged monitor can
// enumerated the replugged monitor's complete mode list. Latch the latest // still be settling. Latch the latest request and retry the original
// request and let the worker apply it once that list is ready. // apply-then-enforce transaction outside the pipe callback.
{ {
CSRWExclusiveLock lock(m_displayModeLock); CSRWExclusiveLock lock(m_displayModeLock);
m_displayMode = msg; m_displayMode = msg;

View File

@@ -64,7 +64,6 @@ private:
bool StartDisplayModeThread(); bool StartDisplayModeThread();
void StopDisplayModeThread(); void StopDisplayModeThread();
bool ApplyDisplayMode(const LGPipeMsg& msg, LONG& result); bool ApplyDisplayMode(const LGPipeMsg& msg, LONG& result);
bool VerifyDisplayMode(const LGPipeMsg& msg);
bool EnsureOnlyDisplayLocked(); bool EnsureOnlyDisplayLocked();
uint32_t RestoreSavedTopologyLocked() const; uint32_t RestoreSavedTopologyLocked() const;