mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 16:51:31 +00:00
[idd] capture: retire published pending damage
Track damage received after each retained candidate snapshot. When a candidate is submitted successfully, replace the global pending set with its trailing damage instead of requiring the source generation to remain unchanged. This lets published full-frame damage retire while preserving newer partial or full updates.
This commit is contained in:
@@ -798,12 +798,48 @@ static FrameType GetFrameType(DXGI_FORMAT format)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AccumulatePendingDamage(
|
||||||
|
RECT pendingDirtyRects[], unsigned * nbPendingDirtyRects,
|
||||||
|
bool * hasPendingDamage, const RECT dirtyRects[], unsigned nbDirtyRects)
|
||||||
|
{
|
||||||
|
if (nbDirtyRects > LG_MAX_DIRTY_RECTS)
|
||||||
|
nbDirtyRects = 0;
|
||||||
|
|
||||||
|
if (!*hasPendingDamage)
|
||||||
|
{
|
||||||
|
*hasPendingDamage = true;
|
||||||
|
*nbPendingDirtyRects = nbDirtyRects;
|
||||||
|
if (nbDirtyRects)
|
||||||
|
memcpy(pendingDirtyRects, dirtyRects,
|
||||||
|
nbDirtyRects * sizeof(*pendingDirtyRects));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero dirty rectangles represents full-frame damage. Once an accumulated
|
||||||
|
// set is full, no later rectangles can narrow that same set again.
|
||||||
|
if (*nbPendingDirtyRects == 0 || nbDirtyRects == 0 ||
|
||||||
|
*nbPendingDirtyRects + nbDirtyRects > LG_MAX_DIRTY_RECTS)
|
||||||
|
{
|
||||||
|
*nbPendingDirtyRects = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pendingDirtyRects + *nbPendingDirtyRects, dirtyRects,
|
||||||
|
nbDirtyRects * sizeof(*pendingDirtyRects));
|
||||||
|
*nbPendingDirtyRects += nbDirtyRects;
|
||||||
|
}
|
||||||
|
|
||||||
void CSwapChainProcessor::SetFullPendingDamage()
|
void CSwapChainProcessor::SetFullPendingDamage()
|
||||||
{
|
{
|
||||||
AcquireSRWLockExclusive(&m_damageLock);
|
AcquireSRWLockExclusive(&m_damageLock);
|
||||||
m_hasPendingDamage = true;
|
m_hasPendingDamage = true;
|
||||||
m_nbPendingDirtyRects = 0;
|
m_nbPendingDirtyRects = 0;
|
||||||
++m_damageGeneration;
|
for (CandidateDamageTail& tail : m_candidateDamageTail)
|
||||||
|
if (tail.active)
|
||||||
|
{
|
||||||
|
tail.hasDamage = true;
|
||||||
|
tail.nbDirtyRects = 0;
|
||||||
|
}
|
||||||
ReleaseSRWLockExclusive(&m_damageLock);
|
ReleaseSRWLockExclusive(&m_damageLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,40 +847,14 @@ void CSwapChainProcessor::AccumulateFrameDamage(
|
|||||||
const RECT * dirtyRects, unsigned nbDirtyRects)
|
const RECT * dirtyRects, unsigned nbDirtyRects)
|
||||||
{
|
{
|
||||||
AcquireSRWLockExclusive(&m_damageLock);
|
AcquireSRWLockExclusive(&m_damageLock);
|
||||||
++m_damageGeneration;
|
AccumulatePendingDamage(
|
||||||
if (nbDirtyRects > LG_MAX_DIRTY_RECTS)
|
m_pendingDirtyRects, &m_nbPendingDirtyRects, &m_hasPendingDamage,
|
||||||
nbDirtyRects = 0;
|
dirtyRects, nbDirtyRects);
|
||||||
|
for (CandidateDamageTail& tail : m_candidateDamageTail)
|
||||||
if (!m_hasPendingDamage)
|
if (tail.active)
|
||||||
{
|
AccumulatePendingDamage(
|
||||||
m_hasPendingDamage = true;
|
tail.dirtyRects, &tail.nbDirtyRects, &tail.hasDamage,
|
||||||
m_nbPendingDirtyRects = nbDirtyRects;
|
dirtyRects, nbDirtyRects);
|
||||||
if (nbDirtyRects)
|
|
||||||
memcpy(m_pendingDirtyRects, dirtyRects,
|
|
||||||
nbDirtyRects * sizeof(*m_pendingDirtyRects));
|
|
||||||
ReleaseSRWLockExclusive(&m_damageLock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zero dirty rectangles represents full-frame damage. Once any skipped
|
|
||||||
// frame requires a full update, no later rectangles can narrow it again.
|
|
||||||
if (m_nbPendingDirtyRects == 0 || nbDirtyRects == 0)
|
|
||||||
{
|
|
||||||
m_nbPendingDirtyRects = 0;
|
|
||||||
ReleaseSRWLockExclusive(&m_damageLock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_nbPendingDirtyRects + nbDirtyRects > LG_MAX_DIRTY_RECTS)
|
|
||||||
{
|
|
||||||
m_nbPendingDirtyRects = 0;
|
|
||||||
ReleaseSRWLockExclusive(&m_damageLock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(m_pendingDirtyRects + m_nbPendingDirtyRects, dirtyRects,
|
|
||||||
nbDirtyRects * sizeof(*m_pendingDirtyRects));
|
|
||||||
m_nbPendingDirtyRects += nbDirtyRects;
|
|
||||||
ReleaseSRWLockExclusive(&m_damageLock);
|
ReleaseSRWLockExclusive(&m_damageLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -994,6 +1004,11 @@ void CSwapChainProcessor::ResetCandidates()
|
|||||||
for (FrameCandidate& candidate : m_candidates)
|
for (FrameCandidate& candidate : m_candidates)
|
||||||
candidate = {};
|
candidate = {};
|
||||||
ReleaseSRWLockExclusive(&m_candidateLock);
|
ReleaseSRWLockExclusive(&m_candidateLock);
|
||||||
|
|
||||||
|
AcquireSRWLockExclusive(&m_damageLock);
|
||||||
|
for (CandidateDamageTail& tail : m_candidateDamageTail)
|
||||||
|
tail = {};
|
||||||
|
ReleaseSRWLockExclusive(&m_damageLock);
|
||||||
SignalCandidateState();
|
SignalCandidateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1059,6 +1074,7 @@ bool CSwapChainProcessor::PublishNewestCandidate(
|
|||||||
|
|
||||||
FrameCandidate& candidate = m_candidates[candidateIndex];
|
FrameCandidate& candidate = m_candidates[candidateIndex];
|
||||||
CPostProcessor& postProcessor = m_postProcessors[candidateIndex];
|
CPostProcessor& postProcessor = m_postProcessors[candidateIndex];
|
||||||
|
const uint64_t candidateSequence = candidate.sequence;
|
||||||
|
|
||||||
auto buffer = m_devContext->PrepareFrameBuffer(
|
auto buffer = m_devContext->PrepareFrameBuffer(
|
||||||
candidate.pitch,
|
candidate.pitch,
|
||||||
@@ -1194,10 +1210,16 @@ bool CSwapChainProcessor::PublishNewestCandidate(
|
|||||||
memcpy(m_dirtyRects, candidate.dirtyRects,
|
memcpy(m_dirtyRects, candidate.dirtyRects,
|
||||||
candidate.nbDirtyRects * sizeof(*m_dirtyRects));
|
candidate.nbDirtyRects * sizeof(*m_dirtyRects));
|
||||||
m_nbDirtyRects = candidate.nbDirtyRects;
|
m_nbDirtyRects = candidate.nbDirtyRects;
|
||||||
if (candidate.damageGeneration == m_damageGeneration)
|
CandidateDamageTail& tail = m_candidateDamageTail[candidateIndex];
|
||||||
|
if (tail.active && tail.ownerSequence == candidateSequence)
|
||||||
{
|
{
|
||||||
m_hasPendingDamage = false;
|
m_hasPendingDamage = tail.hasDamage;
|
||||||
m_nbPendingDirtyRects = 0;
|
m_nbPendingDirtyRects = tail.nbDirtyRects;
|
||||||
|
if (tail.hasDamage && tail.nbDirtyRects)
|
||||||
|
memcpy(m_pendingDirtyRects, tail.dirtyRects,
|
||||||
|
tail.nbDirtyRects * sizeof(*m_pendingDirtyRects));
|
||||||
|
tail.ownerSequence = 0;
|
||||||
|
tail.active = false;
|
||||||
}
|
}
|
||||||
ReleaseSRWLockExclusive(&m_damageLock);
|
ReleaseSRWLockExclusive(&m_damageLock);
|
||||||
|
|
||||||
@@ -1545,6 +1567,7 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
|||||||
}
|
}
|
||||||
const unsigned candidateIndex =
|
const unsigned candidateIndex =
|
||||||
static_cast<unsigned>(selectedCandidate);
|
static_cast<unsigned>(selectedCandidate);
|
||||||
|
FrameCandidate& candidate = m_candidates[candidateIndex];
|
||||||
|
|
||||||
CSRWExclusiveLock pipelineLock(&m_pipelineLock);
|
CSRWExclusiveLock pipelineLock(&m_pipelineLock);
|
||||||
CPostProcessor& postProcessor = m_postProcessors[candidateIndex];
|
CPostProcessor& postProcessor = m_postProcessors[candidateIndex];
|
||||||
@@ -1552,17 +1575,20 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
|||||||
|
|
||||||
RECT currentDirtyRects[LG_MAX_DIRTY_RECTS] = {};
|
RECT currentDirtyRects[LG_MAX_DIRTY_RECTS] = {};
|
||||||
unsigned nbDirtyRects = 0;
|
unsigned nbDirtyRects = 0;
|
||||||
uint64_t damageGeneration = 0;
|
AcquireSRWLockExclusive(&m_damageLock);
|
||||||
AcquireSRWLockShared(&m_damageLock);
|
|
||||||
if (m_hasPendingDamage)
|
if (m_hasPendingDamage)
|
||||||
{
|
{
|
||||||
nbDirtyRects = m_nbPendingDirtyRects;
|
nbDirtyRects = m_nbPendingDirtyRects;
|
||||||
if (nbDirtyRects)
|
if (nbDirtyRects)
|
||||||
memcpy(currentDirtyRects, m_pendingDirtyRects,
|
memcpy(currentDirtyRects, m_pendingDirtyRects,
|
||||||
nbDirtyRects * sizeof(*currentDirtyRects));
|
nbDirtyRects * sizeof(*currentDirtyRects));
|
||||||
damageGeneration = m_damageGeneration;
|
|
||||||
}
|
}
|
||||||
ReleaseSRWLockShared(&m_damageLock);
|
CandidateDamageTail& tail = m_candidateDamageTail[candidateIndex];
|
||||||
|
tail.ownerSequence = candidate.sequence;
|
||||||
|
tail.nbDirtyRects = 0;
|
||||||
|
tail.hasDamage = false;
|
||||||
|
tail.active = true;
|
||||||
|
ReleaseSRWLockExclusive(&m_damageLock);
|
||||||
|
|
||||||
CD3D12CommandSlot * copySlot =
|
CD3D12CommandSlot * copySlot =
|
||||||
m_dx12Device->GetCopySlot(candidateIndex);
|
m_dx12Device->GetCopySlot(candidateIndex);
|
||||||
@@ -1651,13 +1677,11 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameCandidate& candidate = m_candidates[candidateIndex];
|
|
||||||
candidate.srcFormat = srcFormat;
|
candidate.srcFormat = srcFormat;
|
||||||
candidate.dstFormat = dstFormat;
|
candidate.dstFormat = dstFormat;
|
||||||
candidate.nbDirtyRects = nbDirtyRects;
|
candidate.nbDirtyRects = nbDirtyRects;
|
||||||
candidate.pitch = postProcessor.GetOutputPitch();
|
candidate.pitch = postProcessor.GetOutputPitch();
|
||||||
candidate.frameSize = postProcessor.GetOutputSize();
|
candidate.frameSize = postProcessor.GetOutputSize();
|
||||||
candidate.damageGeneration = damageGeneration;
|
|
||||||
candidate.captureTime = captureTime;
|
candidate.captureTime = captureTime;
|
||||||
candidate.postProcessStart = postProcessStart;
|
candidate.postProcessStart = postProcessStart;
|
||||||
candidate.prepareCopyStart = CFrameScheduler::Nanotime();
|
candidate.prepareCopyStart = CFrameScheduler::Nanotime();
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ private:
|
|||||||
unsigned pitch = 0;
|
unsigned pitch = 0;
|
||||||
size_t frameSize = 0;
|
size_t frameSize = 0;
|
||||||
uint64_t sequence = 0;
|
uint64_t sequence = 0;
|
||||||
uint64_t damageGeneration = 0;
|
|
||||||
uint64_t captureTime = 0;
|
uint64_t captureTime = 0;
|
||||||
uint64_t postProcessStart = 0;
|
uint64_t postProcessStart = 0;
|
||||||
uint64_t prepareCopyStart = 0;
|
uint64_t prepareCopyStart = 0;
|
||||||
@@ -87,12 +86,22 @@ private:
|
|||||||
bool prepareTimingValid = false;
|
bool prepareTimingValid = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CandidateDamageTail
|
||||||
|
{
|
||||||
|
uint64_t ownerSequence = 0;
|
||||||
|
RECT dirtyRects[LG_MAX_DIRTY_RECTS] = {};
|
||||||
|
unsigned nbDirtyRects = 0;
|
||||||
|
bool hasDamage = false;
|
||||||
|
bool active = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// An active tail records only damage received after its candidate snapshot.
|
||||||
FrameCandidate m_candidates[LGMP_Q_FRAME_LEN];
|
FrameCandidate m_candidates[LGMP_Q_FRAME_LEN];
|
||||||
|
CandidateDamageTail m_candidateDamageTail[LGMP_Q_FRAME_LEN];
|
||||||
SRWLOCK m_candidateLock = SRWLOCK_INIT;
|
SRWLOCK m_candidateLock = SRWLOCK_INIT;
|
||||||
SRWLOCK m_damageLock = SRWLOCK_INIT;
|
SRWLOCK m_damageLock = SRWLOCK_INIT;
|
||||||
SRWLOCK m_pipelineLock = SRWLOCK_INIT;
|
SRWLOCK m_pipelineLock = SRWLOCK_INIT;
|
||||||
uint64_t m_candidateSequence = 0;
|
uint64_t m_candidateSequence = 0;
|
||||||
uint64_t m_damageGeneration = 0;
|
|
||||||
|
|
||||||
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_thread[3];
|
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_thread[3];
|
||||||
Wrappers::Event m_terminateEvent;
|
Wrappers::Event m_terminateEvent;
|
||||||
|
|||||||
Reference in New Issue
Block a user