From 6bb5c039cd4368ebade11b8387f6753e2f429e90 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Thu, 6 Aug 2026 12:27:09 +1000 Subject: [PATCH] [idd] capture: keep preparing during publication Do not freeze the spare retained candidate while a frame is copied to IVSHMEM. Allow newer source frames to replace that candidate and retain any frame prepared after the published sequence for the next deadline. Take the pipeline lock before selecting the publication candidate so its transport copy is submitted before any newly admitted preparation. --- idd/LGIdd/CSwapChainProcessor.cpp | 40 +++++++++++++++++-------------- idd/LGIdd/CSwapChainProcessor.h | 1 - 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/idd/LGIdd/CSwapChainProcessor.cpp b/idd/LGIdd/CSwapChainProcessor.cpp index fb675c80..4cca454a 100644 --- a/idd/LGIdd/CSwapChainProcessor.cpp +++ b/idd/LGIdd/CSwapChainProcessor.cpp @@ -950,13 +950,20 @@ int CSwapChainProcessor::AcquireCandidate(bool exclusiveSample) uint64_t oldest = UINT64_MAX; bool superseded = false; bool idle = true; + bool publishing = false; AcquireSRWLockExclusive(&m_candidateLock); for (unsigned i = 0; i < ARRAYSIZE(m_candidates); ++i) + { if (m_candidates[i].state != CANDIDATE_FREE) + { idle = false; + if (m_candidates[i].state == CANDIDATE_PUBLISHING) + publishing = true; + } else if (selected < 0) selected = static_cast(i); + } // Effect timing samples must not queue behind work which can later be // superseded, otherwise that discarded work contaminates the sample. @@ -968,7 +975,11 @@ int CSwapChainProcessor::AcquireCandidate(bool exclusiveSample) if (candidate.state == CANDIDATE_READY) ++readyCount; - if (!exclusiveSample && selected < 0 && readyCount > 1) + // Preserve one completed fallback unless another candidate is already + // publishing. In that case its peer must remain available for new source + // frames instead of being frozen for the duration of the transport copy. + if (!exclusiveSample && selected < 0 && + readyCount > (publishing ? 0U : 1U)) for (unsigned i = 0; i < ARRAYSIZE(m_candidates); ++i) if (m_candidates[i].state == CANDIDATE_READY && m_candidates[i].sequence < oldest) @@ -1094,6 +1105,10 @@ bool CSwapChainProcessor::PublishNewestCandidate( const CFrameScheduler::Schedule& schedule, bool periodic, uint64_t publishStart) { + // Once a deadline is due, submit transport work before allowing another + // preparation to enqueue on the same physical copy queue. + CSRWExclusiveLock pipelineLock(&m_pipelineLock); + int selectedCandidate = -1; uint64_t newestSequence = 0; @@ -1108,11 +1123,8 @@ bool CSwapChainProcessor::PublishNewestCandidate( } if (selectedCandidate >= 0) - for (unsigned i = 0; i < ARRAYSIZE(m_candidates); ++i) - if (static_cast(i) == selectedCandidate) - m_candidates[i].state = CANDIDATE_PUBLISHING; - else if (m_candidates[i].state == CANDIDATE_READY) - m_candidates[i].state = CANDIDATE_HELD; + m_candidates[static_cast(selectedCandidate)].state = + CANDIDATE_PUBLISHING; ReleaseSRWLockExclusive(&m_candidateLock); if (selectedCandidate < 0) @@ -1125,14 +1137,10 @@ bool CSwapChainProcessor::PublishNewestCandidate( AcquireSRWLockExclusive(&m_candidateLock); if (m_candidates[candidateIndex].state == CANDIDATE_PUBLISHING) m_candidates[candidateIndex].state = CANDIDATE_READY; - for (FrameCandidate& candidate : m_candidates) - if (candidate.state == CANDIDATE_HELD) - candidate.state = CANDIDATE_READY; ReleaseSRWLockExclusive(&m_candidateLock); SignalCandidateState(); }; - CSRWExclusiveLock pipelineLock(&m_pipelineLock); AcquireSRWLockShared(&m_candidateLock); const bool candidateValid = m_candidates[candidateIndex].state == CANDIDATE_PUBLISHING && @@ -1290,11 +1298,6 @@ bool CSwapChainProcessor::PublishNewestCandidate( } 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; } @@ -1304,10 +1307,11 @@ bool CSwapChainProcessor::PublishNewestCandidate( unsigned superseded = 0; AcquireSRWLockExclusive(&m_candidateLock); - for (FrameCandidate& held : m_candidates) - if (held.state == CANDIDATE_HELD) + for (FrameCandidate& ready : m_candidates) + if (ready.state == CANDIDATE_READY && + ready.sequence < candidateSequence) { - held.state = CANDIDATE_FREE; + ready.state = CANDIDATE_FREE; ++superseded; } ReleaseSRWLockExclusive(&m_candidateLock); diff --git a/idd/LGIdd/CSwapChainProcessor.h b/idd/LGIdd/CSwapChainProcessor.h index 0f1fe64a..4ddec21c 100644 --- a/idd/LGIdd/CSwapChainProcessor.h +++ b/idd/LGIdd/CSwapChainProcessor.h @@ -62,7 +62,6 @@ private: CANDIDATE_PREPARING, CANDIDATE_READY, CANDIDATE_PUBLISHING, - CANDIDATE_HELD, }; struct FrameCandidate