From f04775823d79820fd9039d3bec8dfed562d7121f Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Thu, 6 Aug 2026 12:17:26 +1000 Subject: [PATCH] [idd] capture: retire damage before copy submission Retire candidate damage before submitting its publication copy. A fast completion callback can otherwise release and reuse the candidate while the publisher is still reading its fields and damage tail. --- idd/LGIdd/CSwapChainProcessor.cpp | 50 +++++++++++++++++-------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/idd/LGIdd/CSwapChainProcessor.cpp b/idd/LGIdd/CSwapChainProcessor.cpp index cab09002..fb675c80 100644 --- a/idd/LGIdd/CSwapChainProcessor.cpp +++ b/idd/LGIdd/CSwapChainProcessor.cpp @@ -1254,29 +1254,8 @@ bool CSwapChainProcessor::PublishNewestCandidate( return false; } - if (!copySlot->Execute()) - { - AcquireSRWLockShared(&m_candidateLock); - const bool callbackPending = - candidate.state == CANDIDATE_PUBLISHING; - ReleaseSRWLockShared(&m_candidateLock); - if (callbackPending && !copySlot->HasSubmittedWork()) - { - m_devContext->FailFrameBuffer(buffer.frameIndex); - SetFullPendingDamage(); - ReleaseCandidate(candidateIndex); - } - m_devContext->ForceFrame(); - - AcquireSRWLockExclusive(&m_candidateLock); - for (FrameCandidate& held : m_candidates) - if (held.state == CANDIDATE_HELD) - held.state = CANDIDATE_READY; - ReleaseSRWLockExclusive(&m_candidateLock); - SignalCandidateState(); - return false; - } - + // Retire the candidate damage before submission. The completion callback + // may run before Execute returns and make this candidate reusable. AcquireSRWLockExclusive(&m_damageLock); if (candidate.nbDirtyRects) memcpy(m_dirtyRects, candidate.dirtyRects, @@ -1295,6 +1274,31 @@ bool CSwapChainProcessor::PublishNewestCandidate( } ReleaseSRWLockExclusive(&m_damageLock); + if (!copySlot->Execute()) + { + // The logical damage state was advanced before submission. Force a full + // repair whether submission failed or its callback reported the failure. + SetFullPendingDamage(); + AcquireSRWLockShared(&m_candidateLock); + const bool callbackPending = + candidate.state == CANDIDATE_PUBLISHING; + ReleaseSRWLockShared(&m_candidateLock); + if (callbackPending && !copySlot->HasSubmittedWork()) + { + m_devContext->FailFrameBuffer(buffer.frameIndex); + ReleaseCandidate(candidateIndex); + } + m_devContext->ForceFrame(); + + AcquireSRWLockExclusive(&m_candidateLock); + for (FrameCandidate& held : m_candidates) + if (held.state == CANDIDATE_HELD) + held.state = CANDIDATE_READY; + ReleaseSRWLockExclusive(&m_candidateLock); + SignalCandidateState(); + return false; + } + m_devContext->CommitFrameBuffer( buffer.frameIndex, schedule, periodic);