[idd] don't rebuild the monitor from inside the old monitor's context
Some checks are pending
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / module (push) Waiting to run
build / host-linux (push) Waiting to run
build / host-windows-cross (push) Waiting to run
build / host-windows-native (push) Waiting to run
build / idd (push) Waiting to run
build / obs (clang) (push) Waiting to run
build / obs (gcc) (push) Waiting to run
build / docs (push) Waiting to run

This commit is contained in:
Geoffrey McRae
2026-07-16 16:13:24 +10:00
parent fbf564f2e1
commit b97a0b79f1
2 changed files with 20 additions and 1 deletions

View File

@@ -390,8 +390,13 @@ void CIndirectDeviceContext::OnUnassignedSwapChain()
m_replugMonitor = false; m_replugMonitor = false;
ReleaseSRWLockExclusive(&m_stateLock); ReleaseSRWLockExclusive(&m_stateLock);
// Do NOT rebuild the monitor from inside this callback. Creating and arriving
// a new monitor here re-enters IddCx while the old monitor's swap-chain
// teardown is still unwinding on this thread, which leaves the new swap
// chain's surfaces lost/abandoned (DXGI_ERROR_ACCESS_LOST). Defer to the LGMP
// timer, matching how the departure is scheduled.
if (replug) if (replug)
FinishInit(0); InterlockedExchange(&m_finishInitQueued, 1);
} }
void CIndirectDeviceContext::OnSwapChainLost() void CIndirectDeviceContext::OnSwapChainLost()
@@ -913,6 +918,14 @@ void CIndirectDeviceContext::LGMPTimer()
return; return;
} }
// Rebuild the monitor deferred from the IddCx unassign callback, off that
// callback's thread and after its swap-chain teardown has fully unwound.
if (InterlockedExchange(&m_finishInitQueued, 0))
{
FinishInit(0);
return;
}
LGMP_STATUS status; LGMP_STATUS status;
if ((status = lgmpHostProcess(m_lgmp)) != LGMP_OK) if ((status = lgmpHostProcess(m_lgmp)) != LGMP_OK)
{ {

View File

@@ -155,6 +155,12 @@ private:
bool m_doSetMode = false; bool m_doSetMode = false;
volatile LONG m_replugMonitorQueued = 0; volatile LONG m_replugMonitorQueued = 0;
volatile LONG m_recoverModeUpdateSwapChain = 0; volatile LONG m_recoverModeUpdateSwapChain = 0;
// Set from the IddCx unassign callback to defer the monitor rebuild
// (FinishInit) onto the LGMP timer. Creating/arriving a new monitor from
// inside the old monitor's unassign callback re-enters IddCx while its
// swap-chain teardown is still unwinding, which leaves the new swap-chain
// surfaces in a lost/abandoned state.
volatile LONG m_finishInitQueued = 0;
public: public:
CIndirectDeviceContext(_In_ WDFDEVICE wdfDevice) : CIndirectDeviceContext(_In_ WDFDEVICE wdfDevice) :