mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
[idd] capture: replay only completed frames
Track the newest submitted and completed frame independently. Only retain or replay a frame after its copy callback succeeds. Keep the prior completed frame when a newer copy fails, and compare publication sequences so out-of-order callbacks cannot move backward.
This commit is contained in:
@@ -1187,7 +1187,8 @@ bool CIndirectDeviceContext::SetupLGMP(size_t alignSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_maxFrameSize = maxFrameSize;
|
m_maxFrameSize = maxFrameSize;
|
||||||
m_publishedFrameIndex.store(-1, std::memory_order_release);
|
m_submittedFrameIndex.store(-1, std::memory_order_release);
|
||||||
|
m_readyFrameIndex.store(-1, std::memory_order_release);
|
||||||
m_framePublishSequence = 0;
|
m_framePublishSequence = 0;
|
||||||
memset(m_frameLastPublishSequence, 0,
|
memset(m_frameLastPublishSequence, 0,
|
||||||
sizeof(m_frameLastPublishSequence));
|
sizeof(m_frameLastPublishSequence));
|
||||||
@@ -1241,7 +1242,8 @@ void CIndirectDeviceContext::DeInitLGMP()
|
|||||||
if (m_lgmp == nullptr)
|
if (m_lgmp == nullptr)
|
||||||
{
|
{
|
||||||
m_frameScheduler.Reset();
|
m_frameScheduler.Reset();
|
||||||
m_publishedFrameIndex.store(-1, std::memory_order_release);
|
m_submittedFrameIndex.store(-1, std::memory_order_release);
|
||||||
|
m_readyFrameIndex.store(-1, std::memory_order_release);
|
||||||
m_framePublishSequence = 0;
|
m_framePublishSequence = 0;
|
||||||
memset(m_frameLastPublishSequence, 0,
|
memset(m_frameLastPublishSequence, 0,
|
||||||
sizeof(m_frameLastPublishSequence));
|
sizeof(m_frameLastPublishSequence));
|
||||||
@@ -1261,7 +1263,8 @@ void CIndirectDeviceContext::DeInitLGMP()
|
|||||||
m_frameScheduler.Reset();
|
m_frameScheduler.Reset();
|
||||||
|
|
||||||
AcquireSRWLockExclusive(&m_framePublishLock);
|
AcquireSRWLockExclusive(&m_framePublishLock);
|
||||||
m_publishedFrameIndex.store(-1, std::memory_order_release);
|
m_submittedFrameIndex.store(-1, std::memory_order_release);
|
||||||
|
m_readyFrameIndex.store(-1, std::memory_order_release);
|
||||||
m_framePublishSequence = 0;
|
m_framePublishSequence = 0;
|
||||||
memset(m_frameLastPublishSequence, 0,
|
memset(m_frameLastPublishSequence, 0,
|
||||||
sizeof(m_frameLastPublishSequence));
|
sizeof(m_frameLastPublishSequence));
|
||||||
@@ -1633,15 +1636,15 @@ bool CIndirectDeviceContext::HasMatchingOwnerDelivery(
|
|||||||
|
|
||||||
int CIndirectDeviceContext::FindAvailableFrameBuffer() const
|
int CIndirectDeviceContext::FindAvailableFrameBuffer() const
|
||||||
{
|
{
|
||||||
const LONG publishedFrameIndex =
|
const LONG readyFrameIndex =
|
||||||
m_publishedFrameIndex.load(std::memory_order_acquire);
|
m_readyFrameIndex.load(std::memory_order_acquire);
|
||||||
int available = -1;
|
int available = -1;
|
||||||
uint64_t newestPublish = 0;
|
uint64_t newestPublish = 0;
|
||||||
for (unsigned frameIndex = 0;
|
for (unsigned frameIndex = 0;
|
||||||
frameIndex < LGMP_Q_FRAME_BUFFER_LEN;
|
frameIndex < LGMP_Q_FRAME_BUFFER_LEN;
|
||||||
++frameIndex)
|
++frameIndex)
|
||||||
{
|
{
|
||||||
if (static_cast<LONG>(frameIndex) == publishedFrameIndex ||
|
if (static_cast<LONG>(frameIndex) == readyFrameIndex ||
|
||||||
m_frameInFlight[frameIndex].load(std::memory_order_acquire) ||
|
m_frameInFlight[frameIndex].load(std::memory_order_acquire) ||
|
||||||
m_frameDelivery[frameIndex].ownerQueueMask ||
|
m_frameDelivery[frameIndex].ownerQueueMask ||
|
||||||
m_frameDelivery[frameIndex].sharedPending ||
|
m_frameDelivery[frameIndex].sharedPending ||
|
||||||
@@ -1722,7 +1725,7 @@ bool CIndirectDeviceContext::GetSharedFrameTarget(uint64_t now,
|
|||||||
|
|
||||||
AcquireSRWLockShared(&m_framePublishLock);
|
AcquireSRWLockShared(&m_framePublishLock);
|
||||||
const LONG frameIndex =
|
const LONG frameIndex =
|
||||||
m_publishedFrameIndex.load(std::memory_order_acquire);
|
m_readyFrameIndex.load(std::memory_order_acquire);
|
||||||
if (frameIndex < 0 ||
|
if (frameIndex < 0 ||
|
||||||
m_frameInFlight[frameIndex].load(std::memory_order_acquire) ||
|
m_frameInFlight[frameIndex].load(std::memory_order_acquire) ||
|
||||||
lgmpHostQueuePending(m_frameQueue) != 0)
|
lgmpHostQueuePending(m_frameQueue) != 0)
|
||||||
@@ -1752,7 +1755,7 @@ bool CIndirectDeviceContext::ReplaySharedFrame(uint64_t now, bool& retry)
|
|||||||
|
|
||||||
AcquireSRWLockExclusive(&m_framePublishLock);
|
AcquireSRWLockExclusive(&m_framePublishLock);
|
||||||
const LONG frameIndex =
|
const LONG frameIndex =
|
||||||
m_publishedFrameIndex.load(std::memory_order_acquire);
|
m_readyFrameIndex.load(std::memory_order_acquire);
|
||||||
if (frameIndex < 0 ||
|
if (frameIndex < 0 ||
|
||||||
m_frameInFlight[frameIndex].load(std::memory_order_acquire) ||
|
m_frameInFlight[frameIndex].load(std::memory_order_acquire) ||
|
||||||
lgmpHostQueuePending(m_frameQueue) != 0)
|
lgmpHostQueuePending(m_frameQueue) != 0)
|
||||||
@@ -1992,7 +1995,7 @@ bool CIndirectDeviceContext::PublishFrameBuffer(unsigned frameIndex,
|
|||||||
if (published)
|
if (published)
|
||||||
{
|
{
|
||||||
m_frameLastPublishSequence[frameIndex] = ++m_framePublishSequence;
|
m_frameLastPublishSequence[frameIndex] = ++m_framePublishSequence;
|
||||||
m_publishedFrameIndex.store(
|
m_submittedFrameIndex.store(
|
||||||
static_cast<LONG>(frameIndex), std::memory_order_release);
|
static_cast<LONG>(frameIndex), std::memory_order_release);
|
||||||
}
|
}
|
||||||
ReleaseSRWLockExclusive(&m_framePublishLock);
|
ReleaseSRWLockExclusive(&m_framePublishLock);
|
||||||
@@ -2024,7 +2027,7 @@ bool CIndirectDeviceContext::RepublishFrameBuffer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const LONG frameIndex =
|
const LONG frameIndex =
|
||||||
m_publishedFrameIndex.load(std::memory_order_acquire);
|
m_readyFrameIndex.load(std::memory_order_acquire);
|
||||||
if (frameIndex < 0 ||
|
if (frameIndex < 0 ||
|
||||||
m_frameInFlight[frameIndex].load(std::memory_order_acquire))
|
m_frameInFlight[frameIndex].load(std::memory_order_acquire))
|
||||||
{
|
{
|
||||||
@@ -2150,13 +2153,31 @@ void CIndirectDeviceContext::FailFrameBuffer(unsigned frameIndex)
|
|||||||
|
|
||||||
InterlockedExchange((volatile LONG *)&m_frame[frameIndex]->timingValid, 0);
|
InterlockedExchange((volatile LONG *)&m_frame[frameIndex]->timingValid, 0);
|
||||||
FinalizeFrameBuffer(frameIndex);
|
FinalizeFrameBuffer(frameIndex);
|
||||||
CompleteFrameBuffer(frameIndex);
|
CompleteFrameBuffer(frameIndex, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndirectDeviceContext::CompleteFrameBuffer(unsigned frameIndex)
|
void CIndirectDeviceContext::CompleteFrameBuffer(
|
||||||
|
unsigned frameIndex, bool succeeded)
|
||||||
{
|
{
|
||||||
if (frameIndex < LGMP_Q_FRAME_BUFFER_LEN)
|
if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN)
|
||||||
m_frameInFlight[frameIndex].store(false, std::memory_order_release);
|
return;
|
||||||
|
|
||||||
|
AcquireSRWLockExclusive(&m_framePublishLock);
|
||||||
|
if (succeeded)
|
||||||
|
{
|
||||||
|
// Completion callbacks may run out of order. Never replace a newer ready
|
||||||
|
// frame with an older submission.
|
||||||
|
const uint64_t sequence = m_frameLastPublishSequence[frameIndex];
|
||||||
|
const LONG readyFrameIndex =
|
||||||
|
m_readyFrameIndex.load(std::memory_order_acquire);
|
||||||
|
if (sequence &&
|
||||||
|
(readyFrameIndex < 0 ||
|
||||||
|
sequence > m_frameLastPublishSequence[readyFrameIndex]))
|
||||||
|
m_readyFrameIndex.store(
|
||||||
|
static_cast<LONG>(frameIndex), std::memory_order_release);
|
||||||
|
}
|
||||||
|
m_frameInFlight[frameIndex].store(false, std::memory_order_release);
|
||||||
|
ReleaseSRWLockExclusive(&m_framePublishLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndirectDeviceContext::SetFrameTiming(unsigned frameIndex,
|
void CIndirectDeviceContext::SetFrameTiming(unsigned frameIndex,
|
||||||
|
|||||||
@@ -110,7 +110,10 @@ private:
|
|||||||
size_t m_alignSize = 0;
|
size_t m_alignSize = 0;
|
||||||
size_t m_frameMemoryOffset = 0;
|
size_t m_frameMemoryOffset = 0;
|
||||||
size_t m_maxFrameSize = 0;
|
size_t m_maxFrameSize = 0;
|
||||||
std::atomic<LONG> m_publishedFrameIndex = -1;
|
// LGMP publication precedes copy completion, so only the ready index is safe
|
||||||
|
// to retain and replay.
|
||||||
|
std::atomic<LONG> m_submittedFrameIndex = -1;
|
||||||
|
std::atomic<LONG> m_readyFrameIndex = -1;
|
||||||
std::atomic<bool> m_frameInFlight[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
std::atomic<bool> m_frameInFlight[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
||||||
SRWLOCK m_framePublishLock = SRWLOCK_INIT;
|
SRWLOCK m_framePublishLock = SRWLOCK_INIT;
|
||||||
uint64_t m_framePublishSequence = 0;
|
uint64_t m_framePublishSequence = 0;
|
||||||
@@ -270,7 +273,7 @@ public:
|
|||||||
bool FrameBufferAvailable(const CFrameScheduler::Schedule& schedule);
|
bool FrameBufferAvailable(const CFrameScheduler::Schedule& schedule);
|
||||||
bool HasPublishedFrame() const
|
bool HasPublishedFrame() const
|
||||||
{
|
{
|
||||||
return m_publishedFrameIndex.load(std::memory_order_acquire) >= 0;
|
return m_readyFrameIndex.load(std::memory_order_acquire) >= 0;
|
||||||
}
|
}
|
||||||
void ProcessFrameQueue();
|
void ProcessFrameQueue();
|
||||||
bool GetSharedFrameTarget(uint64_t now, uint64_t& target);
|
bool GetSharedFrameTarget(uint64_t now, uint64_t& target);
|
||||||
@@ -283,7 +286,7 @@ public:
|
|||||||
const CFrameScheduler::Schedule& schedule, bool periodic);
|
const CFrameScheduler::Schedule& schedule, bool periodic);
|
||||||
void AbortFrameBuffer(unsigned frameIndex);
|
void AbortFrameBuffer(unsigned frameIndex);
|
||||||
void FailFrameBuffer(unsigned frameIndex);
|
void FailFrameBuffer(unsigned frameIndex);
|
||||||
void CompleteFrameBuffer(unsigned frameIndex);
|
void CompleteFrameBuffer(unsigned frameIndex, bool succeeded);
|
||||||
void SetFrameTiming(unsigned frameIndex, uint64_t captureTime,
|
void SetFrameTiming(unsigned frameIndex, uint64_t captureTime,
|
||||||
uint64_t postProcessTime, uint64_t copyTime, uint64_t readyTime);
|
uint64_t postProcessTime, uint64_t copyTime, uint64_t readyTime);
|
||||||
void WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos) const;
|
void WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos) const;
|
||||||
|
|||||||
@@ -744,7 +744,7 @@ void CSwapChainProcessor::CompletionFunction(
|
|||||||
sc->m_devContext->RecordFrameTiming(readyEnd - publishStart);
|
sc->m_devContext->RecordFrameTiming(readyEnd - publishStart);
|
||||||
sc->m_devContext->SetFrameTiming(fbRes->GetFrameIndex(),
|
sc->m_devContext->SetFrameTiming(fbRes->GetFrameIndex(),
|
||||||
fbRes->GetCaptureTime(), postProcessTime, copyTime, readyTime);
|
fbRes->GetCaptureTime(), postProcessTime, copyTime, readyTime);
|
||||||
sc->m_devContext->CompleteFrameBuffer(fbRes->GetFrameIndex());
|
sc->m_devContext->CompleteFrameBuffer(fbRes->GetFrameIndex(), true);
|
||||||
sc->ReleaseCandidate(candidateIndex);
|
sc->ReleaseCandidate(candidateIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user