mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-07-20 14:22:00 +00:00
[idd] keep the generated EDID immutable
Generate the EDID once during adapter initialization and update only the live mode list when resolutions change. Changing the EDID during a monitor replug causes Windows to identify it as a different monitor, losing the existing display configuration. Reusing the original EDID preserves the monitor identity while still allowing dynamic modes to be advertised through IddCx.
This commit is contained in:
@@ -99,21 +99,25 @@ void CIndirectDeviceContext::PopulateDefaultModes()
|
||||
{
|
||||
g_settings.LoadModes();
|
||||
|
||||
// Build the new mode list and EDID into locals first so we only hold the
|
||||
// lock for the swap. IddCx readers may be iterating the live containers on
|
||||
// another thread; a clear()/push_back() under them would reallocate the
|
||||
// backing store and crash. std::move makes the publish a pointer swap.
|
||||
// Build the new mode list into a local first so we only hold the lock for
|
||||
// the swap. IddCx readers may be iterating the live container on another
|
||||
// thread; a clear()/push_back() under them would reallocate the backing
|
||||
// store and crash. std::move makes the publish a pointer swap.
|
||||
CSettings::DisplayModes newModes;
|
||||
newModes.reserve(g_settings.GetDisplayModes().size());
|
||||
for (auto& dm : g_settings.GetDisplayModes())
|
||||
newModes.push_back(dm);
|
||||
|
||||
CEdid newEdid;
|
||||
newEdid.Build(newModes);
|
||||
|
||||
AcquireSRWLockExclusive(&m_modeLock);
|
||||
m_displayModes = std::move(newModes);
|
||||
m_edid = std::move(newEdid);
|
||||
ReleaseSRWLockExclusive(&m_modeLock);
|
||||
}
|
||||
|
||||
void CIndirectDeviceContext::InitializeEdid()
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_modeLock);
|
||||
if (!m_edid.Size())
|
||||
m_edid.Build(m_displayModes);
|
||||
ReleaseSRWLockExclusive(&m_modeLock);
|
||||
}
|
||||
|
||||
@@ -184,6 +188,7 @@ void CIndirectDeviceContext::InitAdapter()
|
||||
|
||||
QueryIddCxCapabilities();
|
||||
PopulateDefaultModes();
|
||||
InitializeEdid();
|
||||
|
||||
IDDCX_ADAPTER_CAPS caps = {};
|
||||
caps.Size = sizeof(caps);
|
||||
@@ -292,10 +297,8 @@ void CIndirectDeviceContext::FinishInit(UINT connectorIndex)
|
||||
WDF_OBJECT_ATTRIBUTES attr;
|
||||
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, CIndirectMonitorContextWrapper);
|
||||
|
||||
// Take a private copy of the EDID so a concurrent PopulateDefaultModes on
|
||||
// the timer thread cannot reallocate the buffer out from under
|
||||
// IddCxMonitorCreate. The copy lives for the duration of the synchronous
|
||||
// create call below.
|
||||
// Take a private copy of the immutable EDID. The copy lives for the duration
|
||||
// of the synchronous create call below.
|
||||
std::vector<BYTE> edid;
|
||||
AcquireSRWLockShared(&m_modeLock);
|
||||
edid.assign(m_edid.Data(), m_edid.Data() + m_edid.Size());
|
||||
|
||||
@@ -140,11 +140,12 @@ private:
|
||||
void DeInitLGMP();
|
||||
void LGMPTimer();
|
||||
void ResendCursor() const;
|
||||
void InitializeEdid();
|
||||
|
||||
// Guards m_displayModes and m_edid. The mode list is rebuilt on the LGMP
|
||||
// timer thread (SetResolution) while IddCx concurrently enumerates it on its
|
||||
// own callback threads (ParseMonitorDescription / MonitorQueryTargetModes /
|
||||
// FinishInit). Never held across an IddCx API call - snapshot then call.
|
||||
// own callback threads. The EDID is initialized once and remains immutable.
|
||||
// Never held across an IddCx API call - snapshot then call.
|
||||
mutable SRWLOCK m_modeLock = SRWLOCK_INIT;
|
||||
|
||||
CSettings::DisplayModes m_displayModes;
|
||||
|
||||
Reference in New Issue
Block a user