[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_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,14 +946,6 @@ void CSwapChainProcessor::AccumulateFrameDamage(
int CSwapChainProcessor::AcquireCandidate(bool exclusiveSample)
{
HANDLE waitHandles[] =
{
m_candidateAvailableEvent.Get(),
m_terminateEvent.Get(),
};
for (;;)
{
int selected = -1;
uint64_t oldest = UINT64_MAX;
bool superseded = false;
@@ -968,9 +956,7 @@ int CSwapChainProcessor::AcquireCandidate(bool exclusiveSample)
if (m_candidates[i].state != CANDIDATE_FREE)
idle = false;
else if (selected < 0)
{
selected = static_cast<int>(i);
}
// Effect timing samples must not queue behind work which can later be
// superseded, otherwise that discarded work contaminates the sample.
@@ -1001,22 +987,9 @@ int CSwapChainProcessor::AcquireCandidate(bool exclusiveSample)
}
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;
}
}
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(

View File

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