diff --git a/idd/LGIdd/CIndirectDeviceContext.cpp b/idd/LGIdd/CIndirectDeviceContext.cpp index 3cb5f8ab..7a241500 100644 --- a/idd/LGIdd/CIndirectDeviceContext.cpp +++ b/idd/LGIdd/CIndirectDeviceContext.cpp @@ -820,7 +820,7 @@ bool CIndirectDeviceContext::SetupLGMP(size_t alignSize) void CIndirectDeviceContext::DeInitLGMP() { - m_hasFrame = false; + InterlockedExchange(&m_publishedFrameIndex, -1); // The retry timer callback dereferences this context, so make sure it is // stopped and drained before we tear anything down. Wait for any in-flight @@ -910,8 +910,10 @@ void CIndirectDeviceContext::LGMPTimer() if (lgmpHostQueueNewSubs(m_frameQueue) && m_monitor) { - if (m_hasFrame) - lgmpHostQueuePost(m_frameQueue, 0, m_frameMemory[m_frameIndex]); + const LONG frameIndex = + InterlockedCompareExchange(&m_publishedFrameIndex, 0, 0); + if (frameIndex >= 0) + lgmpHostQueuePost(m_frameQueue, 0, m_frameMemory[frameIndex]); } if (lgmpHostQueueNewSubs(m_pointerQueue)) @@ -1047,15 +1049,33 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame FrameBuffer* fb = m_frameBuffer[m_frameIndex]; fb->wp = 0; - lgmpHostQueuePost(m_frameQueue, 0, m_frameMemory[m_frameIndex]); - result.frameIndex = m_frameIndex; result.mem = fb->data; - m_hasFrame = true; return result; } +bool CIndirectDeviceContext::PublishFrameBuffer(unsigned frameIndex) +{ + if (!m_frameQueue || frameIndex >= LGMP_Q_FRAME_LEN) + return false; + + /* Make resends select this submitted frame before posting it. This prevents + * a new subscriber racing publication from receiving the previous frame + * after the new one. */ + InterlockedExchange(&m_publishedFrameIndex, (LONG)frameIndex); + + const LGMP_STATUS status = + lgmpHostQueuePost(m_frameQueue, 0, m_frameMemory[frameIndex]); + if (status != LGMP_OK) + { + DEBUG_ERROR("Failed to publish frame: %s", lgmpStatusString(status)); + return false; + } + + return true; +} + void CIndirectDeviceContext::WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos) const { FrameBuffer * fb = m_frameBuffer[frameIndex]; diff --git a/idd/LGIdd/CIndirectDeviceContext.h b/idd/LGIdd/CIndirectDeviceContext.h index 602fb1ae..60a7a7bd 100644 --- a/idd/LGIdd/CIndirectDeviceContext.h +++ b/idd/LGIdd/CIndirectDeviceContext.h @@ -91,11 +91,12 @@ private: bool m_cursorVisible = false; int m_cursorX = 0, m_cursorY = 0; - size_t m_alignSize = 0; - size_t m_maxFrameSize = 0; - int m_frameIndex = 0; - uint32_t m_formatVer = 0; - uint32_t m_frameSerial = 0; + size_t m_alignSize = 0; + size_t m_maxFrameSize = 0; + int m_frameIndex = 0; + volatile LONG m_publishedFrameIndex = -1; + uint32_t m_formatVer = 0; + uint32_t m_frameSerial = 0; PLGMPMemory m_frameMemory[LGMP_Q_FRAME_LEN] = {}; KVMFRFrame * m_frame [LGMP_Q_FRAME_LEN] = {}; FrameBuffer * m_frameBuffer[LGMP_Q_FRAME_LEN] = {}; @@ -105,8 +106,6 @@ private: unsigned m_pitch = 0; DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN; FrameType m_frameType = FRAME_TYPE_INVALID; - bool m_hasFrame = false; - UINT m_iddCxVersion = 0; bool m_canProcessFP16 = false; @@ -211,6 +210,7 @@ public: }; PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch, const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat, const RECT * dirtyRects, unsigned nbDirtyRects); + bool PublishFrameBuffer(unsigned frameIndex); void WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos) const; void FinalizeFrameBuffer(unsigned frameIndex) const; diff --git a/idd/LGIdd/CSwapChainProcessor.cpp b/idd/LGIdd/CSwapChainProcessor.cpp index e69e9817..3090d4dc 100644 --- a/idd/LGIdd/CSwapChainProcessor.cpp +++ b/idd/LGIdd/CSwapChainProcessor.cpp @@ -224,7 +224,8 @@ bool CSwapChainProcessor::SwapChainThreadCore() if (frameNumber != lastFrameNumber) { lastFrameNumber = frameNumber; - SwapChainNewFrame(surface, dirtyRectCount, colorSpace, sdrWhiteLevel); + if (!SwapChainNewFrame(surface, dirtyRectCount, colorSpace, sdrWhiteLevel)) + DEBUG_WARN("Failed to submit frame"); // report that all GPU processing for this frame has been queued hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain); @@ -582,9 +583,10 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr acquiredBuffer memcpy(m_dirtyRects, currentDirtyRects, nbDirtyRects * sizeof(*m_dirtyRects)); m_nbDirtyRects = nbDirtyRects; - copyQueue->Execute(); + if (!copyQueue->Execute()) + return false; - return true; + return m_devContext->PublishFrameBuffer(buffer.frameIndex); } DWORD CALLBACK CSwapChainProcessor::_CursorThread(LPVOID arg)