[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.
This commit is contained in:
Geoffrey McRae
2026-08-06 11:38:10 +10:00
parent 4c1722feac
commit 3e6c9197f1
2 changed files with 37 additions and 66 deletions

View File

@@ -34,7 +34,6 @@
static const uint32_t HDR_PQ_MIN_LUMINANCE = 50; static const uint32_t HDR_PQ_MIN_LUMINANCE = 50;
static const uint32_t HDR_PQ_MAX_LUMINANCE = 10000; static const uint32_t HDR_PQ_MAX_LUMINANCE = 10000;
static const uint64_t PUBLISH_RETRY_NS = 1000000ULL; static const uint64_t PUBLISH_RETRY_NS = 1000000ULL;
static const DWORD CANDIDATE_WAIT_MS = 2;
static_assert(LGMP_Q_FRAME_LEN == 2, static_assert(LGMP_Q_FRAME_LEN == 2,
"IDD candidate pipeline assumes two slots"); "IDD candidate pipeline assumes two slots");
@@ -91,8 +90,6 @@ CSwapChainProcessor::CSwapChainProcessor(CIndirectMonitorContext * monitorContex
// once set or only one thread would ever observe termination. // once set or only one thread would ever observe termination.
m_terminateEvent.Attach(CreateEvent(nullptr, TRUE, FALSE, nullptr)); m_terminateEvent.Attach(CreateEvent(nullptr, TRUE, FALSE, nullptr));
m_candidateEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr)); m_candidateEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr));
m_candidateAvailableEvent.Attach(
CreateEvent(nullptr, FALSE, FALSE, nullptr));
m_publishTimer.Attach(CreateWaitableTimerExW(nullptr, nullptr, m_publishTimer.Attach(CreateWaitableTimerExW(nullptr, nullptr,
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS)); CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS));
if (!m_publishTimer.Get()) if (!m_publishTimer.Get())
@@ -105,8 +102,7 @@ CSwapChainProcessor::CSwapChainProcessor(CIndirectMonitorContext * monitorContex
bool CSwapChainProcessor::Start() bool CSwapChainProcessor::Start()
{ {
if (!m_terminateEvent.Get() || !m_candidateEvent.Get() || if (!m_terminateEvent.Get() || !m_candidateEvent.Get() ||
!m_candidateAvailableEvent.Get() || !m_publishTimer.Get() || !m_publishTimer.Get() || !m_cursorDataEvent.Get() || !m_shapeBuffer)
!m_cursorDataEvent.Get() || !m_shapeBuffer)
{ {
DEBUG_ERROR("Failed to initialize swap chain worker resources"); DEBUG_ERROR("Failed to initialize swap chain worker resources");
return false; return false;
@@ -949,14 +945,6 @@ void CSwapChainProcessor::AccumulateFrameDamage(
} }
int CSwapChainProcessor::AcquireCandidate(bool exclusiveSample) int CSwapChainProcessor::AcquireCandidate(bool exclusiveSample)
{
HANDLE waitHandles[] =
{
m_candidateAvailableEvent.Get(),
m_terminateEvent.Get(),
};
for (;;)
{ {
int selected = -1; int selected = -1;
uint64_t oldest = UINT64_MAX; uint64_t oldest = UINT64_MAX;
@@ -968,9 +956,7 @@ int CSwapChainProcessor::AcquireCandidate(bool exclusiveSample)
if (m_candidates[i].state != CANDIDATE_FREE) if (m_candidates[i].state != CANDIDATE_FREE)
idle = false; idle = false;
else if (selected < 0) else if (selected < 0)
{
selected = static_cast<int>(i); selected = static_cast<int>(i);
}
// Effect timing samples must not queue behind work which can later be // Effect timing samples must not queue behind work which can later be
// superseded, otherwise that discarded work contaminates the sample. // superseded, otherwise that discarded work contaminates the sample.
@@ -1001,24 +987,11 @@ int CSwapChainProcessor::AcquireCandidate(bool exclusiveSample)
} }
ReleaseSRWLockExclusive(&m_candidateLock); ReleaseSRWLockExclusive(&m_candidateLock);
if (selected >= 0)
{
if (superseded) if (superseded)
m_devContext->FrameSuperseded(); m_devContext->FrameSuperseded();
return selected; 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;
}
}
void CSwapChainProcessor::ReleaseCandidate(unsigned candidateIndex) void CSwapChainProcessor::ReleaseCandidate(unsigned candidateIndex)
{ {
if (candidateIndex >= ARRAYSIZE(m_candidates)) if (candidateIndex >= ARRAYSIZE(m_candidates))
@@ -1115,7 +1088,6 @@ void CSwapChainProcessor::ResetCandidates()
void CSwapChainProcessor::SignalCandidateState() void CSwapChainProcessor::SignalCandidateState()
{ {
SetEvent(m_candidateEvent.Get()); SetEvent(m_candidateEvent.Get());
SetEvent(m_candidateAvailableEvent.Get());
} }
bool CSwapChainProcessor::PublishNewestCandidate( bool CSwapChainProcessor::PublishNewestCandidate(

View File

@@ -108,7 +108,6 @@ private:
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_thread[3]; Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_thread[3];
Wrappers::Event m_terminateEvent; Wrappers::Event m_terminateEvent;
Wrappers::Event m_candidateEvent; Wrappers::Event m_candidateEvent;
Wrappers::Event m_candidateAvailableEvent;
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_publishTimer; Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_publishTimer;
Wrappers::Event m_cursorDataEvent; Wrappers::Event m_cursorDataEvent;