From 3e6c9197f198c4ac5dee84e0e53a70816761c0fc Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Thu, 6 Aug 2026 11:38:10 +1000 Subject: [PATCH] [idd] capture: never wait on superseded frames Drop an acquired frame immediately when both retained candidate slots are unavailable. Waiting for up to 2 ms held the IddCx surface and backpressured sources whose frame period was shorter than the wait. --- idd/LGIdd/CSwapChainProcessor.cpp | 102 +++++++++++------------------- idd/LGIdd/CSwapChainProcessor.h | 1 - 2 files changed, 37 insertions(+), 66 deletions(-) diff --git a/idd/LGIdd/CSwapChainProcessor.cpp b/idd/LGIdd/CSwapChainProcessor.cpp index 94ebb634..6415337a 100644 --- a/idd/LGIdd/CSwapChainProcessor.cpp +++ b/idd/LGIdd/CSwapChainProcessor.cpp @@ -34,7 +34,6 @@ static const uint32_t HDR_PQ_MIN_LUMINANCE = 50; static const uint32_t HDR_PQ_MAX_LUMINANCE = 10000; static const uint64_t PUBLISH_RETRY_NS = 1000000ULL; -static const DWORD CANDIDATE_WAIT_MS = 2; static_assert(LGMP_Q_FRAME_LEN == 2, "IDD candidate pipeline assumes two slots"); @@ -91,8 +90,6 @@ CSwapChainProcessor::CSwapChainProcessor(CIndirectMonitorContext * monitorContex // once set or only one thread would ever observe termination. m_terminateEvent.Attach(CreateEvent(nullptr, TRUE, FALSE, nullptr)); m_candidateEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr)); - m_candidateAvailableEvent.Attach( - CreateEvent(nullptr, FALSE, FALSE, nullptr)); m_publishTimer.Attach(CreateWaitableTimerExW(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS)); if (!m_publishTimer.Get()) @@ -105,8 +102,7 @@ CSwapChainProcessor::CSwapChainProcessor(CIndirectMonitorContext * monitorContex bool CSwapChainProcessor::Start() { if (!m_terminateEvent.Get() || !m_candidateEvent.Get() || - !m_candidateAvailableEvent.Get() || !m_publishTimer.Get() || - !m_cursorDataEvent.Get() || !m_shapeBuffer) + !m_publishTimer.Get() || !m_cursorDataEvent.Get() || !m_shapeBuffer) { DEBUG_ERROR("Failed to initialize swap chain worker resources"); return false; @@ -950,73 +946,50 @@ void CSwapChainProcessor::AccumulateFrameDamage( int CSwapChainProcessor::AcquireCandidate(bool exclusiveSample) { - HANDLE waitHandles[] = - { - m_candidateAvailableEvent.Get(), - m_terminateEvent.Get(), - }; + int selected = -1; + uint64_t oldest = UINT64_MAX; + bool superseded = false; + bool idle = true; - for (;;) - { - int selected = -1; - uint64_t oldest = UINT64_MAX; - bool superseded = false; - bool idle = true; + AcquireSRWLockExclusive(&m_candidateLock); + for (unsigned i = 0; i < ARRAYSIZE(m_candidates); ++i) + if (m_candidates[i].state != CANDIDATE_FREE) + idle = false; + else if (selected < 0) + selected = static_cast(i); - AcquireSRWLockExclusive(&m_candidateLock); + // Effect timing samples must not queue behind work which can later be + // superseded, otherwise that discarded work contaminates the sample. + if (exclusiveSample && !idle) + selected = -1; + + unsigned readyCount = 0; + for (const FrameCandidate& candidate : m_candidates) + if (candidate.state == CANDIDATE_READY) + ++readyCount; + + if (!exclusiveSample && selected < 0 && readyCount > 1) for (unsigned i = 0; i < ARRAYSIZE(m_candidates); ++i) - if (m_candidates[i].state != CANDIDATE_FREE) - idle = false; - else if (selected < 0) + if (m_candidates[i].state == CANDIDATE_READY && + m_candidates[i].sequence < oldest) { selected = static_cast(i); + oldest = m_candidates[i].sequence; } - // Effect timing samples must not queue behind work which can later be - // superseded, otherwise that discarded work contaminates the sample. - if (exclusiveSample && !idle) - selected = -1; - - unsigned readyCount = 0; - for (const FrameCandidate& candidate : m_candidates) - if (candidate.state == CANDIDATE_READY) - ++readyCount; - - if (!exclusiveSample && selected < 0 && readyCount > 1) - for (unsigned i = 0; i < ARRAYSIZE(m_candidates); ++i) - if (m_candidates[i].state == CANDIDATE_READY && - m_candidates[i].sequence < oldest) - { - selected = static_cast(i); - oldest = m_candidates[i].sequence; - } - - if (selected >= 0) - { - FrameCandidate& candidate = - m_candidates[static_cast(selected)]; - superseded = candidate.state == CANDIDATE_READY; - candidate.state = CANDIDATE_PREPARING; - candidate.sequence = ++m_candidateSequence; - } - ReleaseSRWLockExclusive(&m_candidateLock); - - if (selected >= 0) - { - if (superseded) - m_devContext->FrameSuperseded(); - return selected; - } - - const DWORD result = WaitForMultipleObjects( - ARRAYSIZE(waitHandles), waitHandles, FALSE, CANDIDATE_WAIT_MS); - if (result == WAIT_OBJECT_0 + 1) - return -1; - if (result == WAIT_TIMEOUT) - return -1; - if (result != WAIT_OBJECT_0) - return -1; + if (selected >= 0) + { + FrameCandidate& candidate = + m_candidates[static_cast(selected)]; + superseded = candidate.state == CANDIDATE_READY; + candidate.state = CANDIDATE_PREPARING; + candidate.sequence = ++m_candidateSequence; } + ReleaseSRWLockExclusive(&m_candidateLock); + + if (superseded) + m_devContext->FrameSuperseded(); + return selected; } void CSwapChainProcessor::ReleaseCandidate(unsigned candidateIndex) @@ -1115,7 +1088,6 @@ void CSwapChainProcessor::ResetCandidates() void CSwapChainProcessor::SignalCandidateState() { SetEvent(m_candidateEvent.Get()); - SetEvent(m_candidateAvailableEvent.Get()); } bool CSwapChainProcessor::PublishNewestCandidate( diff --git a/idd/LGIdd/CSwapChainProcessor.h b/idd/LGIdd/CSwapChainProcessor.h index 4aae4445..0f1fe64a 100644 --- a/idd/LGIdd/CSwapChainProcessor.h +++ b/idd/LGIdd/CSwapChainProcessor.h @@ -108,7 +108,6 @@ private: Wrappers::HandleT m_thread[3]; Wrappers::Event m_terminateEvent; Wrappers::Event m_candidateEvent; - Wrappers::Event m_candidateAvailableEvent; Wrappers::HandleT m_publishTimer; Wrappers::Event m_cursorDataEvent;