From da5af3d4785c5f6050f4662210443bfc7d9e1c9e Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Thu, 1 Oct 2026 10:18:15 +1000 Subject: [PATCH] [idd] network: recover video after display reconfiguration Reset reusable D3D12 command queues before rebuilding the encoder. Treat a committed frame graph as recovery from transient device loss. --- idd/LGIdd/d3d/CD3D12CommandQueue.cpp | 27 ++++++++++++++++- idd/LGIdd/transport/network/CNetworkVideo.cpp | 30 +++++++++---------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/idd/LGIdd/d3d/CD3D12CommandQueue.cpp b/idd/LGIdd/d3d/CD3D12CommandQueue.cpp index 251541de..f3fdf9a4 100644 --- a/idd/LGIdd/d3d/CD3D12CommandQueue.cpp +++ b/idd/LGIdd/d3d/CD3D12CommandQueue.cpp @@ -141,7 +141,29 @@ void CD3D12CommandSlot::DeInit() m_cmdList.Reset(); m_gfxList.Reset(); m_allocator.Reset(); - m_queue = nullptr; + + for (UINT i = 0; i < MAX_FENCE_WAITS; ++i) + { + m_fenceWaits[i].fence.Reset(); + m_fenceWaits[i].value = 0; + } + + m_queue = nullptr; + m_name = nullptr; + m_needsReset = false; + m_fenceTarget = 0; + m_fenceWaitCount = 0; + m_completionCallback = nullptr; + m_completionParams[0] = nullptr; + m_completionParams[1] = nullptr; + m_completionResult = true; + m_queryBase = 0; + m_timingActive = false; + m_timestampFrequency = 0; + m_calibrationGPU = 0; + m_calibrationCPU = 0; + Atomic::Store(m_submitted, false, std::memory_order_release); + Atomic::Store(m_state, STATE_FREE, std::memory_order_release); } bool CD3D12CommandSlot::Acquire() @@ -505,6 +527,9 @@ void CD3D12CommandQueue::DeInit() m_queue.Reset(); m_timingSupported = false; m_qpcFrequency = 0; + m_fenceValue = 0; + m_name = nullptr; + Atomic::Store(m_failed, false, std::memory_order_release); } CD3D12CommandSlot * CD3D12CommandQueue::Try(UINT slotIndex) diff --git a/idd/LGIdd/transport/network/CNetworkVideo.cpp b/idd/LGIdd/transport/network/CNetworkVideo.cpp index 62b77a53..0380dcd9 100644 --- a/idd/LGIdd/transport/network/CNetworkVideo.cpp +++ b/idd/LGIdd/transport/network/CNetworkVideo.cpp @@ -1607,6 +1607,15 @@ struct CNetworkVideo::Impl LG_NET_VIDEO_STATUS_WIRE_SIZE); } + void FailNL(uint32_t detail) + { + m_failed = true; + m_frames.clear(); + for (PeerState& peer : m_peers) + if (peer.subscribed) + QueueStatusNL(peer, LG_NET_VIDEO_STATE_ERROR, detail); + } + void DropPeerFramesNL(PeerState& peer) { // Finish a frame once any of its fragments have been accepted. Replacing @@ -1934,7 +1943,7 @@ struct CNetworkVideo::Impl { CSRWExclusiveLock lock(m_lock); if (m_encoder.Busy() || m_frames.empty() || !m_started || - m_stopped || !m_active || !HasSubscribersNL()) + m_stopped || m_failed || !m_active || !HasSubscribersNL()) return false; pending = std::move(m_frames.front()); m_frames.pop_front(); @@ -1952,10 +1961,7 @@ struct CNetworkVideo::Impl return true; CSRWExclusiveLock lock(m_lock); - m_failed = true; - for (PeerState& peer : m_peers) - if (peer.subscribed) - QueueStatusNL(peer, LG_NET_VIDEO_STATE_ERROR, 3); + FailNL(3); return false; } @@ -2368,21 +2374,14 @@ void CNetworkVideo::Process(uint64_t nowMs) else { CSRWExclusiveLock lock(m_impl->m_lock); - m_impl->m_failed = true; - for (Impl::PeerState& peer : m_impl->m_peers) - if (peer.subscribed) - m_impl->QueueStatusNL( - peer, LG_NET_VIDEO_STATE_ERROR, 4); + m_impl->FailNL(4); } } else if (state == D12SyncState::FAILED) { m_impl->m_encoder.Reset(); CSRWExclusiveLock lock(m_impl->m_lock); - m_impl->m_failed = true; - for (Impl::PeerState& peer : m_impl->m_peers) - if (peer.subscribed) - m_impl->QueueStatusNL(peer, LG_NET_VIDEO_STATE_ERROR, 5); + m_impl->FailNL(5); } } @@ -2432,7 +2431,7 @@ CfgResult CNetworkVideo::Probe(const FrameCfg& cfg) const if (!m_impl) return CfgResult::FAILED; CSRWSharedLock lock(m_impl->m_lock); - if (m_impl->m_stopped || m_impl->m_failed) + if (m_impl->m_stopped) return CfgResult::FAILED; if (!Frame::Valid(cfg.mode) || !cfg.width || !cfg.height || cfg.width > MAX_WIDTH || cfg.height > MAX_HEIGHT || @@ -2475,6 +2474,7 @@ void CNetworkVideo::Commit() m_impl->m_pendingCfg = {}; m_impl->m_active = true; m_impl->m_pending = false; + m_impl->m_failed = false; m_impl->m_changing = false; m_impl->m_configEpoch = Next64(m_impl->m_configEpoch); m_impl->m_frames.clear();