mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-07-21 06:42:02 +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();
|
g_settings.LoadModes();
|
||||||
|
|
||||||
// Build the new mode list and EDID into locals first so we only hold the
|
// Build the new mode list into a local first so we only hold the lock for
|
||||||
// lock for the swap. IddCx readers may be iterating the live containers on
|
// the swap. IddCx readers may be iterating the live container on another
|
||||||
// another thread; a clear()/push_back() under them would reallocate the
|
// thread; a clear()/push_back() under them would reallocate the backing
|
||||||
// backing store and crash. std::move makes the publish a pointer swap.
|
// store and crash. std::move makes the publish a pointer swap.
|
||||||
CSettings::DisplayModes newModes;
|
CSettings::DisplayModes newModes;
|
||||||
newModes.reserve(g_settings.GetDisplayModes().size());
|
newModes.reserve(g_settings.GetDisplayModes().size());
|
||||||
for (auto& dm : g_settings.GetDisplayModes())
|
for (auto& dm : g_settings.GetDisplayModes())
|
||||||
newModes.push_back(dm);
|
newModes.push_back(dm);
|
||||||
|
|
||||||
CEdid newEdid;
|
|
||||||
newEdid.Build(newModes);
|
|
||||||
|
|
||||||
AcquireSRWLockExclusive(&m_modeLock);
|
AcquireSRWLockExclusive(&m_modeLock);
|
||||||
m_displayModes = std::move(newModes);
|
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);
|
ReleaseSRWLockExclusive(&m_modeLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,6 +188,7 @@ void CIndirectDeviceContext::InitAdapter()
|
|||||||
|
|
||||||
QueryIddCxCapabilities();
|
QueryIddCxCapabilities();
|
||||||
PopulateDefaultModes();
|
PopulateDefaultModes();
|
||||||
|
InitializeEdid();
|
||||||
|
|
||||||
IDDCX_ADAPTER_CAPS caps = {};
|
IDDCX_ADAPTER_CAPS caps = {};
|
||||||
caps.Size = sizeof(caps);
|
caps.Size = sizeof(caps);
|
||||||
@@ -292,10 +297,8 @@ void CIndirectDeviceContext::FinishInit(UINT connectorIndex)
|
|||||||
WDF_OBJECT_ATTRIBUTES attr;
|
WDF_OBJECT_ATTRIBUTES attr;
|
||||||
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, CIndirectMonitorContextWrapper);
|
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, CIndirectMonitorContextWrapper);
|
||||||
|
|
||||||
// Take a private copy of the EDID so a concurrent PopulateDefaultModes on
|
// Take a private copy of the immutable EDID. The copy lives for the duration
|
||||||
// the timer thread cannot reallocate the buffer out from under
|
// of the synchronous create call below.
|
||||||
// IddCxMonitorCreate. The copy lives for the duration of the synchronous
|
|
||||||
// create call below.
|
|
||||||
std::vector<BYTE> edid;
|
std::vector<BYTE> edid;
|
||||||
AcquireSRWLockShared(&m_modeLock);
|
AcquireSRWLockShared(&m_modeLock);
|
||||||
edid.assign(m_edid.Data(), m_edid.Data() + m_edid.Size());
|
edid.assign(m_edid.Data(), m_edid.Data() + m_edid.Size());
|
||||||
|
|||||||
@@ -140,11 +140,12 @@ private:
|
|||||||
void DeInitLGMP();
|
void DeInitLGMP();
|
||||||
void LGMPTimer();
|
void LGMPTimer();
|
||||||
void ResendCursor() const;
|
void ResendCursor() const;
|
||||||
|
void InitializeEdid();
|
||||||
|
|
||||||
// Guards m_displayModes and m_edid. The mode list is rebuilt on the LGMP
|
// Guards m_displayModes and m_edid. The mode list is rebuilt on the LGMP
|
||||||
// timer thread (SetResolution) while IddCx concurrently enumerates it on its
|
// timer thread (SetResolution) while IddCx concurrently enumerates it on its
|
||||||
// own callback threads (ParseMonitorDescription / MonitorQueryTargetModes /
|
// own callback threads. The EDID is initialized once and remains immutable.
|
||||||
// FinishInit). Never held across an IddCx API call - snapshot then call.
|
// Never held across an IddCx API call - snapshot then call.
|
||||||
mutable SRWLOCK m_modeLock = SRWLOCK_INIT;
|
mutable SRWLOCK m_modeLock = SRWLOCK_INIT;
|
||||||
|
|
||||||
CSettings::DisplayModes m_displayModes;
|
CSettings::DisplayModes m_displayModes;
|
||||||
|
|||||||
Reference in New Issue
Block a user