diff --git a/idd/LGIdd/Device.cpp b/idd/LGIdd/Device.cpp index beb0a5ef..0fe9b230 100644 --- a/idd/LGIdd/Device.cpp +++ b/idd/LGIdd/Device.cpp @@ -36,7 +36,7 @@ #include "display/IddCxCompat.h" #include "display/device/CDeviceContext.h" #include "display/monitor/Context.h" -#include "transport/CLGMPControl.h" +#include "transport/IControlTransport.h" #include "transport/CPipeServer.h" #include "config/CSettings.h" @@ -193,7 +193,7 @@ NTSTATUS LGIddMonitorSetGammaRamp(IDDCX_MONITOR monitor, const IDARG_IN_SET_GAMM { auto * wrapper = WdfObjectGet_CMonitorContextWrapper(monitor); auto * ctx = wrapper->context->GetDeviceContext(); - auto & control = ctx->GetLGMPControl(); + auto & control = ctx->GetTransport().Control(); if (ctx->IsSoftwareMode()) { diff --git a/idd/LGIdd/LGIdd.vcxproj b/idd/LGIdd/LGIdd.vcxproj index 572607a5..dbec06b7 100644 --- a/idd/LGIdd/LGIdd.vcxproj +++ b/idd/LGIdd/LGIdd.vcxproj @@ -36,7 +36,6 @@ - @@ -53,11 +52,14 @@ - - - - + + + + + + + @@ -75,10 +77,8 @@ - - @@ -94,12 +94,20 @@ - - - - + + + + + + + + + + + + diff --git a/idd/LGIdd/LGIdd.vcxproj.filters b/idd/LGIdd/LGIdd.vcxproj.filters index 621f6037..e9fe9002 100644 --- a/idd/LGIdd/LGIdd.vcxproj.filters +++ b/idd/LGIdd/LGIdd.vcxproj.filters @@ -29,6 +29,9 @@ {22FDF1F6-0A8C-4B96-9E74-53D74733CC0A} + + {530EE339-4AD6-4AE7-9A74-09420E73D04B} + {82810F1C-E51C-4DBD-86B2-1CDE8C16A2A9} @@ -91,18 +94,12 @@ Capture - - Capture - Capture Capture - - Capture - Capture @@ -148,24 +145,48 @@ Post-processing\Effects - - Transport - - - Transport - - - Transport - - + Transport Transport + + Transport + Transport + + Transport + + + Transport + + + Transport + + + Transport + + + Transport + + + Transport\LGMP + + + Transport\LGMP + + + Transport\LGMP + + + Transport\LGMP + + + Transport\LGMP + Configuration @@ -213,9 +234,6 @@ Capture - - Capture - Capture @@ -264,21 +282,30 @@ Post-processing\Effects - - Transport - - - Transport - - - Transport - - + Transport Transport + + Transport + + + Transport\LGMP + + + Transport\LGMP + + + Transport\LGMP + + + Transport\LGMP + + + Transport\LGMP + Configuration diff --git a/idd/LGIdd/capture/CFrameBufferPool.cpp b/idd/LGIdd/capture/CFrameBufferPool.cpp index 7157d1df..b5318656 100644 --- a/idd/LGIdd/capture/CFrameBufferPool.cpp +++ b/idd/LGIdd/capture/CFrameBufferPool.cpp @@ -19,11 +19,12 @@ */ #include "capture/CFrameBufferPool.h" +#include "transport/IFrameTransport.h" #include void CFrameBufferPool::Init( - CFrameTransport * transport, CD3D12Device * dx12) + IFrameTransport * transport, CD3D12Device * dx12) { m_transport = transport; m_dx12 = dx12; @@ -43,8 +44,9 @@ CFrameBufferResource * CFrameBufferPool::Get( return nullptr; CFrameBufferResource * fbr = &m_buffers[buffer.frameIndex]; - if (!fbr->Init(m_transport, m_dx12, buffer.frameIndex, buffer.mem, - minSize, textureDesc)) + if (!fbr->Init(m_dx12, buffer.frameIndex, buffer.mem, + buffer.heapOffset, minSize, m_transport->GetMaxFrameSize(), + textureDesc)) return nullptr; return fbr; diff --git a/idd/LGIdd/capture/CFrameBufferPool.h b/idd/LGIdd/capture/CFrameBufferPool.h index 50062db0..c34a333c 100644 --- a/idd/LGIdd/capture/CFrameBufferPool.h +++ b/idd/LGIdd/capture/CFrameBufferPool.h @@ -21,22 +21,22 @@ #pragma once #include "capture/CFrameBufferResource.h" -#include "capture/FrameBufferTypes.h" -#include "common/KVMFR.h" +#include "transport/FrameBufferTypes.h" +#include "transport/TransportTypes.h" struct CD3D12Device; -class CFrameTransport; +class IFrameTransport; class CFrameBufferPool { private: - CFrameTransport * m_transport = nullptr; + IFrameTransport * m_transport = nullptr; CD3D12Device * m_dx12 = nullptr; - CFrameBufferResource m_buffers[LGMP_Q_FRAME_BUFFER_LEN]; + CFrameBufferResource m_buffers[TRANSPORT_FRAME_BUFFER_COUNT]; public: - void Init(CFrameTransport * transport, CD3D12Device * dx12); + void Init(IFrameTransport * transport, CD3D12Device * dx12); void Reset(); CFrameBufferResource * Get(const PreparedFrameBuffer& buffer, diff --git a/idd/LGIdd/capture/CFrameBufferResource.cpp b/idd/LGIdd/capture/CFrameBufferResource.cpp index ca7cb350..f27585af 100644 --- a/idd/LGIdd/capture/CFrameBufferResource.cpp +++ b/idd/LGIdd/capture/CFrameBufferResource.cpp @@ -21,21 +21,19 @@ #include "capture/CFrameBufferResource.h" #include "capture/CFrameProcessorUtil.h" #include "d3d/CD3D12Device.h" -#include "transport/CFrameTransport.h" -#include "transport/CIVSHMEM.h" #include "CDebug.h" #include -bool CFrameBufferResource::Init(CFrameTransport * transport, - CD3D12Device * dx12, unsigned frameIndex, uint8_t * base, size_t size, - const D3D12_RESOURCE_DESC * textureDesc) +bool CFrameBufferResource::Init(CD3D12Device * dx12, + unsigned frameIndex, uint8_t * base, uint64_t heapOffset, size_t size, + size_t maxFrameSize, const D3D12_RESOURCE_DESC * textureDesc) { m_frameIndex = frameIndex; - if (size > transport->GetMaxFrameSize()) + if (size > maxFrameSize) { - DEBUG_ERROR("Frame size of %llu is too large to fit in shared ram", + DEBUG_ERROR("Frame size of %llu is too large for transport memory", (unsigned long long)size); return false; } @@ -47,7 +45,7 @@ bool CFrameBufferResource::Init(CFrameTransport * transport, D3D12_RESOURCE_DESC desc = {}; if (textureDesc) { - if (indirect || !dx12->CanUseIVSHMEMTexture()) + if (indirect || !dx12->CanUseDirectTexture()) return false; desc = *textureDesc; if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D || @@ -130,20 +128,19 @@ bool CFrameBufferResource::Init(CFrameTransport * transport, } else { - const UINT64 heapOffset = - (uintptr_t)base - - (uintptr_t)transport->GetIVSHMEM().GetMem(); const D3D12_RESOURCE_ALLOCATION_INFO allocation = dx12->GetDevice()->GetResourceAllocationInfo(0, 1, &desc); allocationSize = allocation.SizeInBytes; - const D3D12_HEAP_DESC heapDesc = dx12->GetHeap()->GetDesc(); + const D3D12_HEAP_DESC heapDesc = + dx12->GetTransportHeap()->GetDesc(); if (!allocation.Alignment || heapOffset % allocation.Alignment || - allocation.SizeInBytes > transport->GetMaxFrameSize() || + allocation.SizeInBytes > maxFrameSize || heapOffset > heapDesc.SizeInBytes || allocation.SizeInBytes > heapDesc.SizeInBytes - heapOffset) { - DEBUG_ERROR("IVSHMEM resource does not fit its framebuffer allocation"); + DEBUG_ERROR( + "Transport resource does not fit its framebuffer allocation"); return false; } @@ -156,20 +153,20 @@ bool CFrameBufferResource::Init(CFrameTransport * transport, if (FAILED(hr) || !(support.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D)) { - DEBUG_ERROR("IVSHMEM texture format is unsupported"); + DEBUG_ERROR("Transport texture format is unsupported"); return false; } - DEBUG_TRACE("Creating IVSHMEM texture for %p", base); - resName = L"IVSHMEM Texture"; + DEBUG_TRACE("Creating transport texture for %p", base); + resName = L"Transport Texture"; } else { - DEBUG_TRACE("Creating IVSHMEM buffer for %p", base); - resName = L"IVSHMEM"; + DEBUG_TRACE("Creating transport buffer for %p", base); + resName = L"Transport Buffer"; } hr = dx12->GetDevice()->CreatePlacedResource( - dx12->GetHeap().Get(), + dx12->GetTransportHeap().Get(), heapOffset, &desc, D3D12_RESOURCE_STATE_COMMON, diff --git a/idd/LGIdd/capture/CFrameBufferResource.h b/idd/LGIdd/capture/CFrameBufferResource.h index 0ae0e1a8..1cf27bb3 100644 --- a/idd/LGIdd/capture/CFrameBufferResource.h +++ b/idd/LGIdd/capture/CFrameBufferResource.h @@ -27,11 +27,10 @@ #include #include -#include "capture/CFrameScheduler.h" +#include "transport/CFrameScheduler.h" #include "d3d/CInteropResource.h" struct CD3D12Device; -class CFrameTransport; using namespace Microsoft::WRL; @@ -70,8 +69,8 @@ class CFrameBufferResource void * m_map = nullptr; public: - bool Init(CFrameTransport * transport, CD3D12Device * dx12, - unsigned frameIndex, uint8_t * base, size_t size, + bool Init(CD3D12Device * dx12, unsigned frameIndex, uint8_t * base, + uint64_t heapOffset, size_t size, size_t maxFrameSize, const D3D12_RESOURCE_DESC * textureDesc = nullptr); void Reset(); diff --git a/idd/LGIdd/capture/CFrameProcessor.cpp b/idd/LGIdd/capture/CFrameProcessor.cpp index 52407b00..ac4a34b4 100644 --- a/idd/LGIdd/capture/CFrameProcessor.cpp +++ b/idd/LGIdd/capture/CFrameProcessor.cpp @@ -27,9 +27,9 @@ #include #include -CFrameProcessor::CFrameProcessor(CFrameTransport * transport, +CFrameProcessor::CFrameProcessor(IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], + CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], SRWLOCK * pipelineLock, HANDLE terminateEvent) : m_transport(transport), m_dx12(std::move(dx12)), @@ -154,9 +154,9 @@ void CFrameProcessor::GetPreviousDamage( } std::unique_ptr CreateFrameProcessor( - bool software, CFrameTransport * transport, + bool software, IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], + CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], SRWLOCK * pipelineLock, HANDLE terminateEvent) { std::unique_ptr processor; diff --git a/idd/LGIdd/capture/CFrameProcessor.h b/idd/LGIdd/capture/CFrameProcessor.h index 951f29f7..46e92960 100644 --- a/idd/LGIdd/capture/CFrameProcessor.h +++ b/idd/LGIdd/capture/CFrameProcessor.h @@ -24,13 +24,15 @@ #include "capture/CFrameBufferPool.h" #include "d3d/CInteropResource.h" #include "postprocess/CPostProcessor.h" +#include "transport/CFrameScheduler.h" +#include "transport/TransportTypes.h" #include #include using namespace Microsoft::WRL; -class CFrameTransport; +class IFrameTransport; struct FrameSubmission { @@ -46,7 +48,7 @@ struct FrameSubmission class CFrameProcessor { protected: - CFrameTransport * m_transport; + IFrameTransport * m_transport; std::shared_ptr m_dx12; CPostProcessor * m_postProcessors; SRWLOCK * m_pipelineLock; @@ -72,9 +74,9 @@ protected: virtual void SetFullDamageLocked(); public: - CFrameProcessor(CFrameTransport * transport, + CFrameProcessor(IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], + CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], SRWLOCK * pipelineLock, HANDLE terminateEvent); virtual ~CFrameProcessor() = default; @@ -94,7 +96,7 @@ public: }; std::unique_ptr CreateFrameProcessor( - bool software, CFrameTransport * transport, + bool software, IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], + CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], SRWLOCK * pipelineLock, HANDLE terminateEvent); diff --git a/idd/LGIdd/capture/CHardwareFrameProcessor.cpp b/idd/LGIdd/capture/CHardwareFrameProcessor.cpp index 7ac4b4a8..a94512ad 100644 --- a/idd/LGIdd/capture/CHardwareFrameProcessor.cpp +++ b/idd/LGIdd/capture/CHardwareFrameProcessor.cpp @@ -20,7 +20,7 @@ #include "capture/CHardwareFrameProcessor.h" #include "capture/CFrameProcessorUtil.h" -#include "transport/CFrameTransport.h" +#include "transport/IFrameTransport.h" #include "util/CSRWLock.h" #include "CDebug.h" @@ -29,7 +29,7 @@ using namespace Microsoft::WRL; -static_assert(LGMP_Q_FRAME_LEN == 2, +static_assert(TRANSPORT_FRAME_QUEUE_LENGTH == 2, "IDD candidate pipeline assumes two slots"); class CPublishPending @@ -71,8 +71,8 @@ public: }; CHardwareFrameProcessor::CHardwareFrameProcessor( - CFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], + IFrameTransport * transport, std::shared_ptr dx12, + CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], SRWLOCK * pipelineLock, HANDLE terminateEvent) : CFrameProcessor(transport, std::move(dx12), postProcessors, pipelineLock, terminateEvent) diff --git a/idd/LGIdd/capture/CHardwareFrameProcessor.h b/idd/LGIdd/capture/CHardwareFrameProcessor.h index b25116b3..6136f828 100644 --- a/idd/LGIdd/capture/CHardwareFrameProcessor.h +++ b/idd/LGIdd/capture/CHardwareFrameProcessor.h @@ -65,8 +65,8 @@ private: bool active = false; }; - FrameCandidate m_candidates[LGMP_Q_FRAME_LEN]; - CandidateDamageTail m_candidateDamageTail[LGMP_Q_FRAME_LEN]; + FrameCandidate m_candidates[TRANSPORT_FRAME_QUEUE_LENGTH]; + CandidateDamageTail m_candidateDamageTail[TRANSPORT_FRAME_QUEUE_LENGTH]; mutable SRWLOCK m_candidateLock = SRWLOCK_INIT; SRWLOCK m_copySubmitLock = SRWLOCK_INIT; uint64_t m_candidateSequence = 0; @@ -89,9 +89,9 @@ private: void SetFullDamageLocked() override; public: - CHardwareFrameProcessor(CFrameTransport * transport, + CHardwareFrameProcessor(IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], + CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], SRWLOCK * pipelineLock, HANDLE terminateEvent); bool IsValid() const override; diff --git a/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp b/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp index c2806792..fba9b60d 100644 --- a/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp +++ b/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp @@ -20,21 +20,21 @@ #include "capture/CSoftwareFrameProcessor.h" #include "capture/CFrameProcessorUtil.h" -#include "capture/FrameBufferTypes.h" -#include "transport/CFrameTransport.h" +#include "transport/TransportTypes.h" +#include "transport/IFrameTransport.h" #include "util/CSRWLock.h" #include "CDebug.h" #include CSoftwareFrameProcessor::CSoftwareFrameProcessor( - CFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], + IFrameTransport * transport, std::shared_ptr dx12, + CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], SRWLOCK * pipelineLock, HANDLE terminateEvent) : CFrameProcessor(transport, std::move(dx12), postProcessors, pipelineLock, terminateEvent), m_directTexture( - !m_dx12->IsIndirectCopy() && m_dx12->CanUseIVSHMEMTexture()) + !m_dx12->IsIndirectCopy() && m_dx12->CanUseDirectTexture()) { } @@ -152,18 +152,18 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission) else { m_directTexture = false; - DEBUG_WARN("IVSHMEM texture layout does not fit the framebuffer"); + DEBUG_WARN("Transport texture layout does not fit the framebuffer"); } } else if (m_directTexture) { m_directTexture = false; - DEBUG_WARN("Post-processor output cannot use an IVSHMEM texture"); + DEBUG_WARN("Post-processor output cannot use a transport texture"); } if (!pitch || !frameSize || frameSize > m_transport->GetMaxFrameSize()) { - DEBUG_ERROR("Software frame does not fit in shared memory"); + DEBUG_ERROR("Software frame does not fit in transport memory"); SetFullDamage(); return false; } @@ -190,7 +190,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission) deliverySchedule.deliveryDeadlineSerial = 0; deliverySchedule.phaseEligible = false; - m_transport->ProcessFrameQueue(); + m_transport->ProcessDeliveries(); if (!m_transport->FrameBufferAvailable( deliverySchedule, submission.noImageUpdate)) { @@ -258,7 +258,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission) RestorePendingDamage( currentDirtyRects, nbDirtyRects, hasDamage); DEBUG_ERROR_HR(deviceStatus, - "D3D12 device removed while creating an IVSHMEM texture"); + "D3D12 device removed while creating a transport texture"); SetFullDamage(); return false; } @@ -266,7 +266,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission) m_directTexture = false; textureDescPtr = nullptr; DEBUG_WARN( - "IVSHMEM textures unavailable; using a direct buffer copy"); + "Transport textures unavailable; using a direct buffer copy"); } } diff --git a/idd/LGIdd/capture/CSoftwareFrameProcessor.h b/idd/LGIdd/capture/CSoftwareFrameProcessor.h index b0dea032..59d53e76 100644 --- a/idd/LGIdd/capture/CSoftwareFrameProcessor.h +++ b/idd/LGIdd/capture/CSoftwareFrameProcessor.h @@ -31,9 +31,9 @@ private: CD3D12CommandSlot * slot, bool result, void * param1, void * param2); public: - CSoftwareFrameProcessor(CFrameTransport * transport, + CSoftwareFrameProcessor(IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], + CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], SRWLOCK * pipelineLock, HANDLE terminateEvent); bool Submit(const FrameSubmission& submission) override; diff --git a/idd/LGIdd/capture/CSwapChainCursor.cpp b/idd/LGIdd/capture/CSwapChainCursor.cpp index a0872df9..67194e49 100644 --- a/idd/LGIdd/capture/CSwapChainCursor.cpp +++ b/idd/LGIdd/capture/CSwapChainCursor.cpp @@ -22,7 +22,7 @@ #include "display/IddCxCompat.h" #include "display/device/CDeviceContext.h" -#include "transport/CLGMPControl.h" +#include "transport/IControlTransport.h" #include "CDebug.h" diff --git a/idd/LGIdd/capture/CSwapChainProcessor.cpp b/idd/LGIdd/capture/CSwapChainProcessor.cpp index 191c88d4..e559fd10 100644 --- a/idd/LGIdd/capture/CSwapChainProcessor.cpp +++ b/idd/LGIdd/capture/CSwapChainProcessor.cpp @@ -24,8 +24,8 @@ #include "display/device/CDeviceContext.h" #include "display/monitor/Context.h" #include "platform/CPlatformInfo.h" -#include "transport/CFrameTransport.h" -#include "transport/CLGMPControl.h" +#include "transport/IFrameTransport.h" +#include "transport/IControlTransport.h" #include "util/CSRWLock.h" #include @@ -49,8 +49,8 @@ CSwapChainProcessor::CSwapChainProcessor(CMonitorContext * monitorContext, m_assignmentGeneration(assignmentGeneration), m_monitor(monitor), m_devContext(devContext), - m_transport(devContext->GetFrameTransport()), - m_control(devContext->GetLGMPControl()), + m_transport(devContext->GetTransport().Frames()), + m_control(devContext->GetTransport().Control()), m_hSwapChain(hSwapChain), m_renderAdapter(renderAdapter), m_dx11Device(dx11Device), @@ -99,7 +99,8 @@ bool CSwapChainProcessor::InitializePipeline() UINT64 alignSize = CPlatformInfo::GetPageSize(); auto dx12Device = std::make_shared(m_renderAdapter); const CD3D12Device::InitResult result = dx12Device->Init( - m_transport.GetIVSHMEM(), alignSize, !m_dx11Device->IsSoftware()); + m_devContext->GetTransport().GetDirectMemory(), alignSize, + !m_dx11Device->IsSoftware()); if (result == CD3D12Device::RETRY) { const HRESULT deviceStatus = @@ -115,9 +116,9 @@ bool CSwapChainProcessor::InitializePipeline() if (result == CD3D12Device::FAILURE) return false; - if (!m_devContext->SetupLGMP(alignSize)) + if (!m_devContext->SetupTransport(alignSize)) { - DEBUG_ERROR("SetupLGMP failed"); + DEBUG_ERROR("Transport setup failed"); return false; } @@ -333,7 +334,7 @@ void CSwapChainProcessor::SwapChainThreadCore() // Only the buffer2 acquisition path (IddCx 1.10+) reports it; on the legacy // path HDR is not available, so default to SDR. DXGI_COLOR_SPACE_TYPE colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; - UINT sdrWhiteLevel = KVMFR_SDR_WHITE_LEVEL_DEFAULT; + UINT sdrWhiteLevel = LG_SDR_WHITE_LEVEL_DEFAULT; const uint64_t captureStart = CFrameScheduler::Nanotime(); #ifdef HAS_IDDCX_110 diff --git a/idd/LGIdd/capture/CSwapChainProcessor.h b/idd/LGIdd/capture/CSwapChainProcessor.h index 450927de..75d52400 100644 --- a/idd/LGIdd/capture/CSwapChainProcessor.h +++ b/idd/LGIdd/capture/CSwapChainProcessor.h @@ -25,7 +25,7 @@ #include "display/IddCxCompat.h" #include "d3d/CInteropResourcePool.h" #include "capture/CFrameProcessor.h" -#include "common/KVMFR.h" +#include "postprocess/D12FrameFormat.h" #include "postprocess/CPostProcessor.h" #include @@ -37,8 +37,8 @@ using namespace Microsoft::WRL; class CMonitorContext; class CDeviceContext; -class CFrameTransport; -class CLGMPControl; +class IFrameTransport; +class IControlTransport; class CSwapChainProcessor { @@ -47,8 +47,8 @@ private: UINT64 m_assignmentGeneration; IDDCX_MONITOR m_monitor; CDeviceContext * m_devContext; - CFrameTransport & m_transport; - CLGMPControl & m_control; + IFrameTransport & m_transport; + IControlTransport & m_control; IDDCX_SWAPCHAIN m_hSwapChain; LUID m_renderAdapter; std::shared_ptr m_dx11Device; @@ -56,7 +56,7 @@ private: HANDLE m_newFrameEvent; CInteropResourcePool m_resPool; - CPostProcessor m_postProcessors[LGMP_Q_FRAME_LEN]; + CPostProcessor m_postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH]; std::unique_ptr m_frameProcessor; // Reconfiguration is exclusive while per-candidate recording is shared. SRWLOCK m_pipelineLock = SRWLOCK_INIT; @@ -68,7 +68,7 @@ private: Wrappers::Event m_cursorDataEvent; BYTE* m_shapeBuffer; DWORD m_lastShapeId = 0; - std::atomic m_sdrWhiteLevel { KVMFR_SDR_WHITE_LEVEL_DEFAULT }; + std::atomic m_sdrWhiteLevel { LG_SDR_WHITE_LEVEL_DEFAULT }; #ifdef HAS_IDDCX_110 // The per-frame metadata stream can select the monitor default, provide a diff --git a/idd/LGIdd/capture/CSwapChainPublisher.cpp b/idd/LGIdd/capture/CSwapChainPublisher.cpp index b972bf91..66739fd6 100644 --- a/idd/LGIdd/capture/CSwapChainPublisher.cpp +++ b/idd/LGIdd/capture/CSwapChainPublisher.cpp @@ -20,7 +20,7 @@ #include "capture/CSwapChainProcessor.h" -#include "transport/CFrameTransport.h" +#include "transport/IFrameTransport.h" #include #include "CDebug.h" @@ -83,7 +83,7 @@ void CSwapChainProcessor::PublisherThread() const bool ready = m_frameProcessor->HasReadyFrame(); if (!ready) { - m_transport.ProcessFrameQueue(); + m_transport.ProcessDeliveries(); if (m_frameProcessor->HasReadyFrame()) continue; @@ -123,12 +123,12 @@ void CSwapChainProcessor::PublisherThread() } uint64_t replayTarget; - if (m_transport.GetSharedFrameTarget(current, replayTarget)) + if (m_transport.GetPendingDeliveryTarget(current, replayTarget)) { bool retry = false; if (replayTarget <= current) { - if (m_transport.ReplaySharedFrame(current, retry)) + if (m_transport.RetryPendingDelivery(current, retry)) continue; current = CFrameScheduler::Nanotime(); @@ -205,15 +205,15 @@ void CSwapChainProcessor::PublisherThread() uint64_t current = CFrameScheduler::Nanotime(); uint64_t replayTarget; - if (m_transport.GetSharedFrameTarget(current, replayTarget) && + if (m_transport.GetPendingDeliveryTarget(current, replayTarget) && replayTarget < target) { if (replayTarget <= current) { - m_transport.ProcessFrameQueue(); + m_transport.ProcessDeliveries(); current = CFrameScheduler::Nanotime(); bool retry = false; - if (m_transport.ReplaySharedFrame(current, retry)) + if (m_transport.RetryPendingDelivery(current, retry)) continue; current = CFrameScheduler::Nanotime(); @@ -251,7 +251,7 @@ void CSwapChainProcessor::PublisherThread() } const uint64_t publishStart = CFrameScheduler::Nanotime(); - m_transport.ProcessFrameQueue(); + m_transport.ProcessDeliveries(); if (!m_transport.FrameBufferAvailable(schedule) || !m_frameProcessor->Publish(schedule, periodic, publishStart)) { diff --git a/idd/LGIdd/d3d/CD3D12Device.cpp b/idd/LGIdd/d3d/CD3D12Device.cpp index 434bc1ac..fcc4704d 100644 --- a/idd/LGIdd/d3d/CD3D12Device.cpp +++ b/idd/LGIdd/d3d/CD3D12Device.cpp @@ -21,7 +21,7 @@ #include "d3d/CD3D12Device.h" #include "CDebug.h" -bool CD3D12Device::m_indirectCopy = false; +bool CD3D12Device::s_directHeapFailed = false; CD3D12Device::CD3D12Device(LUID adapterLuid) : m_adapterLuid(adapterLuid), @@ -60,12 +60,14 @@ static void CALLBACK _D3D12DebugCallback( description); } -CD3D12Device::InitResult CD3D12Device::Init(CIVSHMEM &ivshmem, - UINT64 &alignSize, bool enableCompute) +CD3D12Device::InitResult CD3D12Device::Init( + const DirectFrameBufferMemory& directMemory, + UINT64& alignSize, bool enableCompute) { HRESULT hr; m_computeEnabled = enableCompute; + m_indirectCopy = !directMemory || s_directHeapFailed; hr = CreateDXGIFactory2(m_debug ? DXGI_CREATE_FACTORY_DEBUG : 0, IID_PPV_ARGS(&m_factory)); if (FAILED(hr)) @@ -105,34 +107,37 @@ CD3D12Device::InitResult CD3D12Device::Init(CIVSHMEM &ivshmem, if (!m_indirectCopy) { - hr = m_device->OpenExistingHeapFromAddress(ivshmem.GetMem(), IID_PPV_ARGS(&m_ivshmemHeap)); + hr = m_device->OpenExistingHeapFromAddress( + directMemory.address, IID_PPV_ARGS(&m_transportHeap)); if (FAILED(hr)) { - DEBUG_ERROR_HR(hr, "Failed to open IVSHMEM as a D3D12Heap"); - m_indirectCopy = true; + DEBUG_ERROR_HR(hr, + "Failed to open transport memory as a D3D12 heap"); + s_directHeapFailed = true; return InitResult::RETRY; } - m_ivshmemHeap->SetName(L"IVSHMEM"); + m_transportHeap->SetName(L"Transport Memory"); - D3D12_HEAP_DESC heapDesc = m_ivshmemHeap->GetDesc(); + D3D12_HEAP_DESC heapDesc = m_transportHeap->GetDesc(); alignSize = heapDesc.Alignment; - m_ivshmemTextureSupported = + m_directTextureSupported = (heapDesc.Flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER) && !(heapDesc.Flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES); // test that the heap is usable if (!HeapTest()) { - DEBUG_WARN("Unable to create resources in the IVSHMEM heap, falling back to indirect copy"); + DEBUG_WARN("Unable to create resources in transport memory, " + "falling back to indirect copy"); // failure often results in the device being removed and we need to completely reinit when this occurs - m_indirectCopy = true; + s_directHeapFailed = true; return InitResult::RETRY; } - DEBUG_INFO("Using IVSHMEM as a D3D12Heap"); - if (!m_ivshmemTextureSupported) - DEBUG_WARN("IVSHMEM heap does not support placed textures"); + DEBUG_INFO("Using transport memory as a D3D12 heap"); + if (!m_directTextureSupported) + DEBUG_WARN("Transport memory does not support placed textures"); } if (!m_copyQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COPY, @@ -182,7 +187,7 @@ bool CD3D12Device::HeapTest() ComPtr resource; hr = m_device->CreatePlacedResource( - m_ivshmemHeap.Get(), + m_transportHeap.Get(), 0, &desc, D3D12_RESOURCE_STATE_COPY_DEST, @@ -190,7 +195,8 @@ bool CD3D12Device::HeapTest() IID_PPV_ARGS(&resource)); if (FAILED(hr)) { - DEBUG_ERROR_HR(hr, "Failed to create the ivshmem ID3D12Resource"); + DEBUG_ERROR_HR(hr, + "Failed to create the transport-memory ID3D12Resource"); return false; } resource->SetName(L"HeapTest"); diff --git a/idd/LGIdd/d3d/CD3D12Device.h b/idd/LGIdd/d3d/CD3D12Device.h index d5bb27fe..0cc635d6 100644 --- a/idd/LGIdd/d3d/CD3D12Device.h +++ b/idd/LGIdd/d3d/CD3D12Device.h @@ -26,8 +26,8 @@ #include #include -#include "transport/CIVSHMEM.h" #include "d3d/CD3D12CommandQueue.h" +#include "transport/TransportTypes.h" using namespace Microsoft::WRL; @@ -37,8 +37,9 @@ struct CD3D12Device LUID m_adapterLuid; bool m_debug; - // static as this needs to persist if set - static bool m_indirectCopy; + // A failed direct heap can remove the device. Preserve the fallback for + // the replacement device so initialization does not retry forever. + static bool s_directHeapFailed; ComPtr m_dxDebug; ComPtr m_infoQueue; @@ -47,12 +48,13 @@ struct CD3D12Device ComPtr m_factory; ComPtr m_adapter; ComPtr m_device; - ComPtr m_ivshmemHeap; + ComPtr m_transportHeap; CD3D12CommandQueue m_copyQueue; CD3D12CommandQueue m_computeQueue; - bool m_computeEnabled = false; - bool m_ivshmemTextureSupported = false; + bool m_computeEnabled = false; + bool m_indirectCopy = true; + bool m_directTextureSupported = false; bool HeapTest(); @@ -67,8 +69,8 @@ struct CD3D12Device SUCCESS }; - InitResult Init(CIVSHMEM &ivshmem, UINT64 &alignSize, - bool enableCompute); + InitResult Init(const DirectFrameBufferMemory& directMemory, + UINT64& alignSize, bool enableCompute); void DeInit(); // Wait for all command queues to finish in-flight GPU work and run their @@ -77,9 +79,9 @@ struct CD3D12Device void WaitForIdle(); ComPtr GetDevice() { return m_device; } - ComPtr GetHeap() { return m_ivshmemHeap; } - bool IsIndirectCopy() { return m_indirectCopy; } - bool CanUseIVSHMEMTexture() { return m_ivshmemTextureSupported; } + ComPtr GetTransportHeap() { return m_transportHeap; } + bool IsIndirectCopy() const { return m_indirectCopy; } + bool CanUseDirectTexture() const { return m_directTextureSupported; } CD3D12CommandSlot * GetCopySlot (); CD3D12CommandSlot * GetCopySlot (unsigned frameIndex); diff --git a/idd/LGIdd/display/CDisplayConfiguration.cpp b/idd/LGIdd/display/CDisplayConfiguration.cpp index 728b5edb..3be72330 100644 --- a/idd/LGIdd/display/CDisplayConfiguration.cpp +++ b/idd/LGIdd/display/CDisplayConfiguration.cpp @@ -21,7 +21,6 @@ #include "display/CDisplayConfiguration.h" #include "CDebug.h" -#include "common/LGMPConfig.h" #include "util/CSRWLock.h" #include @@ -59,12 +58,12 @@ bool CDisplayConfiguration::CalculateFrameSize( bool CDisplayConfiguration::GetResolutionMemoryRequirements( uint32_t width, uint32_t height, UINT64 alignment, - const FrameMemoryLimits& limits, UINT64& frameSize, UINT64& sharedSize) + const FrameMemoryLimits& limits, UINT64& frameSize, UINT64& requiredSize) { - frameSize = 0; - sharedSize = 0; + frameSize = 0; + requiredSize = 0; - if (!alignment || !limits.frameMemoryOffset || + if (!alignment || !limits.frameMemoryOffset || !limits.bufferCount || !CalculateFrameSize(width, height, frameSize)) return false; @@ -76,12 +75,12 @@ bool CDisplayConfiguration::GetResolutionMemoryRequirements( if (!AlignUp(limits.frameMemoryOffset, alignment, frameMemoryStart)) return false; - sharedSize = frameMemoryStart + - frameAllocationSize * LGMP_Q_FRAME_BUFFER_LEN; + requiredSize = frameMemoryStart + + frameAllocationSize * limits.bufferCount; return true; } -uint32_t CDisplayConfiguration::RecommendedIVSHMEMSizeMiB( +uint32_t CDisplayConfiguration::RecommendedMemorySizeMiB( UINT64 requiredSize) { UINT64 sizeMiB = requiredSize / 1048576; @@ -135,10 +134,10 @@ bool CDisplayConfiguration::LoadModes(const FrameMemoryLimits& limits) for (const auto& configuredMode : configuredModes) { UINT64 frameSize; - UINT64 requiredIVSHMEMSize; + UINT64 requiredMemorySize; if (!GetResolutionMemoryRequirements(configuredMode.width, configuredMode.height, alignment, limits, frameSize, - requiredIVSHMEMSize)) + requiredMemorySize)) { DEBUG_WARN("Filtering invalid %s mode %ux%u@%.3f", configuredMode.extraMode ? "extra" : "configured", @@ -147,15 +146,15 @@ bool CDisplayConfiguration::LoadModes(const FrameMemoryLimits& limits) continue; } - if (requiredIVSHMEMSize > limits.sharedSize) + if (requiredMemorySize > limits.capacity) { DEBUG_WARN( - "Filtering %s mode %ux%u@%.3f: requires %llu bytes of IVSHMEM, only %llu bytes are available", + "Filtering %s mode %ux%u@%.3f: requires %llu bytes of transport memory, only %llu bytes are available", configuredMode.extraMode ? "extra" : "configured", configuredMode.width, configuredMode.height, configuredMode.refreshMilliHz / 1000.0, - (unsigned long long)requiredIVSHMEMSize, - (unsigned long long)limits.sharedSize); + (unsigned long long)requiredMemorySize, + (unsigned long long)limits.capacity); continue; } @@ -170,7 +169,7 @@ bool CDisplayConfiguration::LoadModes(const FrameMemoryLimits& limits) if (newModes.empty()) { - DEBUG_ERROR("No configured display modes fit in IVSHMEM"); + DEBUG_ERROR("No configured display modes fit in transport memory"); return false; } @@ -225,20 +224,20 @@ CDisplayConfiguration::SetResolution( ResolutionResult result; UINT64 frameSize; - UINT64 requiredIVSHMEMSize; + UINT64 requiredMemorySize; if (!GetResolutionMemoryRequirements(width, height, limits.alignment, - limits, frameSize, requiredIVSHMEMSize)) + limits, frameSize, requiredMemorySize)) { DEBUG_WARN("Ignoring invalid resolution request: %ux%u", width, height); return result; } - if (requiredIVSHMEMSize > limits.sharedSize) + if (requiredMemorySize > limits.capacity) { result.status = ResolutionStatus::TOO_LARGE; - result.requiredMiB = RecommendedIVSHMEMSizeMiB(requiredIVSHMEMSize); + result.requiredMiB = RecommendedMemorySizeMiB(requiredMemorySize); DEBUG_WARN( - "Refusing resolution %ux%u: frame requires %llu bytes, only %llu bytes are available; IVSHMEM must be at least %u MiB", + "Refusing resolution %ux%u: frame requires %llu bytes, only %llu bytes are available; transport memory must be at least %u MiB", width, height, (unsigned long long)frameSize, (unsigned long long)limits.maxFrameSize, diff --git a/idd/LGIdd/display/CDisplayConfiguration.h b/idd/LGIdd/display/CDisplayConfiguration.h index 8b073b31..68b3f2e2 100644 --- a/idd/LGIdd/display/CDisplayConfiguration.h +++ b/idd/LGIdd/display/CDisplayConfiguration.h @@ -74,8 +74,8 @@ private: UINT64& frameSize); static bool GetResolutionMemoryRequirements(uint32_t width, uint32_t height, UINT64 alignment, const FrameMemoryLimits& limits, - UINT64& frameSize, UINT64& sharedSize); - static uint32_t RecommendedIVSHMEMSizeMiB(UINT64 requiredSize); + UINT64& frameSize, UINT64& requiredSize); + static uint32_t RecommendedMemorySizeMiB(UINT64 requiredSize); public: explicit CDisplayConfiguration(CSettings& settings); diff --git a/idd/LGIdd/display/CMonitorManager.h b/idd/LGIdd/display/CMonitorManager.h index d34bee63..87008cf8 100644 --- a/idd/LGIdd/display/CMonitorManager.h +++ b/idd/LGIdd/display/CMonitorManager.h @@ -57,7 +57,7 @@ private: IDDCX_MONITOR m_monitor = nullptr; // Guards the monitor/replug/swap-chain state. These values are touched by - // IddCx callback threads, the swap-chain thread, and the LGMP timer. + // IddCx callback threads, the swap-chain thread, and the transport timer. SRWLOCK m_lock = SRWLOCK_INIT; bool m_replugMonitor = false; diff --git a/idd/LGIdd/display/device/CDeviceContext.cpp b/idd/LGIdd/display/device/CDeviceContext.cpp index 543dca0d..8192d46f 100644 --- a/idd/LGIdd/display/device/CDeviceContext.cpp +++ b/idd/LGIdd/display/device/CDeviceContext.cpp @@ -22,6 +22,8 @@ #include "display/IddCxCompat.h" #include "transport/CPipeServer.h" +#include "transport/IFrameTransport.h" +#include "transport/TransportFactory.h" #include "CDebug.h" #include @@ -33,8 +35,7 @@ static const UINT IDDCX_VERSION_1_10 = 0x1A00; CDeviceContext::CDeviceContext(WDFDEVICE wdfDevice) : m_wdfDevice(wdfDevice), - m_lgmpControl(m_lgmpHost), - m_frameTransport(m_lgmpHost, m_ivshmem), + m_transport(CreateTransport()), m_displayConfiguration(g_settings) { } @@ -49,10 +50,10 @@ CDeviceContext::~CDeviceContext() m_initTimer = nullptr; } - if (m_lgmpTimer) + if (m_transportTimer) { - WdfTimerStop(m_lgmpTimer, TRUE); - m_lgmpTimer = nullptr; + WdfTimerStop(m_transportTimer, TRUE); + m_transportTimer = nullptr; } } @@ -156,19 +157,32 @@ void CDeviceContext::InitAdapter() return; } - // At boot the IVSHMEM PCI device may not have enumerated yet. Rather than + // At boot the selected transport may not be available yet. Rather than // silently abandoning the adapter (leaving the device loaded but with no - // monitor), retry from a timer until the shared memory becomes available. - if (!m_ivshmemOpened) + // monitor), retry from a timer until it can be opened. + if (!m_transportOpened) { - if (!m_ivshmem.Init() || !m_ivshmem.Open()) + if (!m_transport) { - DEBUG_WARN("IVSHMEM not available yet, scheduling init retry"); - ScheduleInitRetry(); + DEBUG_ERROR("Failed to create the frame transport"); m_initInProgress.store(0); return; } - m_ivshmemOpened = true; + + const ITransport::OpenResult result = m_transport->Open(); + if (result != ITransport::OpenResult::SUCCESS) + { + if (result == ITransport::OpenResult::RETRY) + { + DEBUG_WARN("Frame transport not available yet, scheduling init retry"); + ScheduleInitRetry(); + } + else + DEBUG_ERROR("Failed to open the frame transport"); + m_initInProgress.store(0); + return; + } + m_transportOpened = true; } // Select the render adapter before advertising capabilities. If no hardware @@ -234,14 +248,14 @@ void CDeviceContext::InitAdapter() DEBUG_INFO("No hardware render adapter available; using SDR software mode"); QueryIddCxCapabilities(); - DEBUG_TRACE("Initializing LGMP metadata"); - if (!InitializeLGMP()) + DEBUG_TRACE("Initializing frame transport metadata"); + if (!InitializeTransport()) { m_initInProgress.store(0); return; } DEBUG_TRACE("Loading configured display modes"); - if (!m_displayConfiguration.Load(m_frameTransport.GetMemoryLimits())) + if (!m_displayConfiguration.Load(m_transport->GetMemoryLimits())) { m_initInProgress.store(0); return; @@ -374,7 +388,7 @@ void CDeviceContext::ReplugMonitor() void CDeviceContext::ReloadSettings() { if (!m_displayConfiguration.ReloadSettings( - m_frameTransport.GetMemoryLimits())) + m_transport->GetMemoryLimits())) return; ReplugMonitor(); @@ -417,7 +431,7 @@ void CDeviceContext::SetResolution(uint32_t width, uint32_t height) { const CDisplayConfiguration::ResolutionResult result = m_displayConfiguration.SetResolution( - width, height, m_frameTransport.GetMemoryLimits()); + width, height, m_transport->GetMemoryLimits()); switch (result.status) { @@ -437,33 +451,21 @@ void CDeviceContext::SetResolution(uint32_t width, uint32_t height) } } -// LGMP transport +// Frame transport -bool CDeviceContext::InitializeLGMP() +bool CDeviceContext::InitializeTransport() { - if (m_lgmpHost.IsInitialized()) - return true; - - if (!m_lgmpHost.Initialize(m_ivshmem)) - return false; - - // Preserve the shared-memory layout: frame queues precede the pointer queue - // and its retained cursor and color-transform allocations. - if (!m_frameTransport.Initialize() || !m_lgmpControl.Initialize()) - return false; - - m_frameTransport.SealMemoryLayout(); - return true; + return m_transport && m_transport->Initialize(); } -bool CDeviceContext::SetupLGMP(size_t alignSize) +bool CDeviceContext::SetupTransport(size_t alignSize) { // Frame buffers cannot be allocated until the GPU-specific alignment is // known. The swap-chain path may call this again after setup completed. - if (m_frameTransport.GetMaxFrameSize()) + if (m_transport->Frames().GetMaxFrameSize()) return true; - if (!InitializeLGMP() || !m_frameTransport.Setup(alignSize)) + if (!InitializeTransport() || !m_transport->Setup(alignSize)) return false; WDF_TIMER_CONFIG config; @@ -472,7 +474,7 @@ bool CDeviceContext::SetupLGMP(size_t alignSize) { WDFOBJECT parent = WdfTimerGetParentObject(timer); auto wrapper = WdfObjectGet_CDeviceContextWrapper(parent); - wrapper->context->LGMPTimer(); + wrapper->context->TransportTimer(); }, 10); config.AutomaticSerialization = FALSE; @@ -487,18 +489,18 @@ bool CDeviceContext::SetupLGMP(size_t alignSize) attribs.ExecutionLevel = WdfExecutionLevelDispatch; NTSTATUS status = WdfTimerCreate( - &config, &attribs, &m_lgmpTimer); + &config, &attribs, &m_transportTimer); if (!NT_SUCCESS(status)) { DEBUG_ERROR_HR(status, "Timer creation failed"); return false; } - WdfTimerStart(m_lgmpTimer, WDF_REL_TIMEOUT_IN_MS(10)); + WdfTimerStart(m_transportTimer, WDF_REL_TIMEOUT_IN_MS(10)); return true; } -void CDeviceContext::LGMPTimer() +void CDeviceContext::TransportTimer() { // Monitor work is deferred off IddCx callback threads. switch (m_monitorManager.TakeDeferredAction()) @@ -515,74 +517,15 @@ void CDeviceContext::LGMPTimer() break; } - const LGMP_STATUS processStatus = m_lgmpHost.Process(); - if (processStatus != LGMP_OK) - { - if (processStatus == LGMP_ERR_CORRUPTED) - { - DEBUG_WARN( - "LGMP reported the shared memory has been corrupted, attempting to recover\n"); - // TODO: reinitialize LGMP. - return; - } - - DEBUG_ERROR("lgmpHostProcess Failed: %s", - lgmpStatusString(processStatus)); - // TODO: shut down LGMP. - return; - } - - const uint64_t now = CFrameScheduler::Nanotime(); - - // Take the frame subscriber snapshot before processing scheduling messages, - // then publish both updates together just as the original timer did. - const CFrameTransport::SubscriberSnapshot subscribers = - m_frameTransport.SnapshotSubscribers(); - - uint8_t data[LGMP_MSGS_SIZE]; - size_t size; - uint32_t sourceClientID; - LGMP_STATUS status; - while ((status = m_lgmpControl.ReadDataWithSource( - data, &size, &sourceClientID)) == LGMP_OK) - { - KVMFRMessage * msg = reinterpret_cast(data); - switch (msg->type) - { - case KVMFR_MESSAGE_SETCURSORPOS: - { - KVMFRSetCursorPos * position = - reinterpret_cast(msg); - g_pipe.SetCursorPos(position->x, position->y); - break; - } - - case KVMFR_MESSAGE_WINDOWSIZE: - { - KVMFRWindowSize * window = - reinterpret_cast(msg); - SetResolution(window->w, window->h); - break; - } - - case KVMFR_MESSAGE_FRAME_SCHEDULE: - { - const KVMFRFrameSchedule * schedule = - reinterpret_cast(msg); - const bool valid = size == sizeof(*schedule) && - m_frameTransport.UpdateSchedule( - sourceClientID, *schedule, now); - if (!valid) - DEBUG_WARN("Ignoring invalid KVMFR frame schedule"); - break; - } - } - - m_lgmpControl.AckData(); - } - - m_frameTransport.FinalizeSubscribers(subscribers, now); - - if (m_lgmpControl.HasNewSubscribers()) - m_lgmpControl.ResendState(); + m_transport->Process(*this); +} + +void CDeviceContext::OnSetCursorPos(int32_t x, int32_t y) +{ + g_pipe.SetCursorPos(x, y); +} + +void CDeviceContext::OnSetResolution(uint32_t width, uint32_t height) +{ + SetResolution(width, height); } diff --git a/idd/LGIdd/display/device/CDeviceContext.h b/idd/LGIdd/display/device/CDeviceContext.h index fe4aa792..eadef141 100644 --- a/idd/LGIdd/display/device/CDeviceContext.h +++ b/idd/LGIdd/display/device/CDeviceContext.h @@ -25,17 +25,15 @@ #include #include +#include #include #include #include "display/CDisplayConfiguration.h" #include "display/CMonitorManager.h" -#include "transport/CFrameTransport.h" -#include "transport/CIVSHMEM.h" -#include "transport/CLGMPControl.h" -#include "transport/CLGMPHost.h" +#include "transport/ITransport.h" -class CDeviceContext +class CDeviceContext : private ITransportEvents { private: WDFDEVICE m_wdfDevice; @@ -43,20 +41,17 @@ private: LUID m_preferredRenderAdapter = {}; bool m_havePreferredRenderAdapter = false; - // At boot IVSHMEM may not have enumerated yet. The retry timer and atomic - // gate keep adapter creation single-threaded until it becomes available. - WDFTIMER m_initTimer = nullptr; - bool m_ivshmemOpened = false; - std::atomic m_initInProgress = 0; + // At boot the selected transport may not be available yet. The retry timer + // and atomic gate keep adapter creation single-threaded until it is ready. + WDFTIMER m_initTimer = nullptr; + bool m_transportOpened = false; + std::atomic m_initInProgress = 0; - CIVSHMEM m_ivshmem; - CLGMPHost m_lgmpHost; - CLGMPControl m_lgmpControl; - CFrameTransport m_frameTransport; - CDisplayConfiguration m_displayConfiguration; - CMonitorManager m_monitorManager; + std::unique_ptr m_transport; + CDisplayConfiguration m_displayConfiguration; + CMonitorManager m_monitorManager; - WDFTIMER m_lgmpTimer = nullptr; + WDFTIMER m_transportTimer = nullptr; UINT m_iddCxVersion = 0; bool m_hasIddCx110DDIs = false; @@ -68,8 +63,10 @@ private: void ScheduleInitRetry(); void StopInitRetry(); - bool InitializeLGMP(); - void LGMPTimer(); + bool InitializeTransport(); + void TransportTimer(); + void OnSetCursorPos(int32_t x, int32_t y) override; + void OnSetResolution(uint32_t width, uint32_t height) override; void SetResolution(uint32_t width, uint32_t height); public: @@ -79,7 +76,7 @@ public: CDeviceContext(const CDeviceContext&) = delete; CDeviceContext& operator=(const CDeviceContext&) = delete; - bool SetupLGMP(size_t alignSize); + bool SetupTransport(size_t alignSize); void InitAdapter(); void FinishAdapterInit(UINT connectorIndex); @@ -96,14 +93,9 @@ public: bool CanProcessFP16 () const { return m_canProcessFP16; } bool IsSoftwareMode () const { return m_softwareMode; } - CFrameTransport& GetFrameTransport() + ITransport& GetTransport() { - return m_frameTransport; - } - - CLGMPControl& GetLGMPControl() - { - return m_lgmpControl; + return *m_transport; } CDisplayConfiguration& GetDisplayConfiguration() diff --git a/idd/LGIdd/display/monitor/Context.cpp b/idd/LGIdd/display/monitor/Context.cpp index 9455c4f7..416b2fe2 100644 --- a/idd/LGIdd/display/monitor/Context.cpp +++ b/idd/LGIdd/display/monitor/Context.cpp @@ -53,7 +53,7 @@ NTSTATUS CMonitorContext::AssignSwapChain( // Build the D3D11 device into a local so the member is never observed // half-constructed. The worker binds it before performing the expensive - // D3D12, LGMP and post-processing initialization. + // D3D12, transport and post-processing initialization. auto dx11Device = std::make_shared(renderAdapter); const HRESULT initStatus = dx11Device->Init(); if (FAILED(initStatus)) diff --git a/idd/LGIdd/postprocess/effect/CRGB24Effect.cpp b/idd/LGIdd/postprocess/effect/CRGB24Effect.cpp index 570dbd44..6c5bff94 100644 --- a/idd/LGIdd/postprocess/effect/CRGB24Effect.cpp +++ b/idd/LGIdd/postprocess/effect/CRGB24Effect.cpp @@ -22,7 +22,7 @@ #include "CDebug.h" #include "config/CSettings.h" -#include "common/LGMPConfig.h" +#include "transport/TransportTypes.h" #include #include @@ -61,7 +61,7 @@ struct CRGB24Effect::State std::shared_ptr colorTransform; }; - static const unsigned WarmupCount = LGMP_Q_FRAME_LEN; + static const unsigned WarmupCount = TRANSPORT_FRAME_QUEUE_LENGTH; static const unsigned SampleCount = 64; static const unsigned TrimCount = SampleCount / 8; diff --git a/idd/LGIdd/capture/CFrameScheduler.cpp b/idd/LGIdd/transport/CFrameScheduler.cpp similarity index 97% rename from idd/LGIdd/capture/CFrameScheduler.cpp rename to idd/LGIdd/transport/CFrameScheduler.cpp index e9ab4f89..c13aa54c 100644 --- a/idd/LGIdd/capture/CFrameScheduler.cpp +++ b/idd/LGIdd/transport/CFrameScheduler.cpp @@ -18,7 +18,7 @@ * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "capture/CFrameScheduler.h" +#include "transport/CFrameScheduler.h" #include "CDebug.h" @@ -288,10 +288,10 @@ void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs, { AcquireSRWLockExclusive(&m_lock); - uint32_t oldClientIDs [LGMP_MAX_CLIENTS] = {}; - bool wasSubscribed [LGMP_MAX_CLIENTS] = {}; - bool wasOwnerCapable[LGMP_MAX_CLIENTS] = {}; - unsigned clientIndex = 0; + uint32_t oldClientIDs [TRANSPORT_MAX_CLIENTS] = {}; + bool wasSubscribed [TRANSPORT_MAX_CLIENTS] = {}; + bool wasOwnerCapable[TRANSPORT_MAX_CLIENTS] = {}; + unsigned clientIndex = 0; for (const Client& client : m_clients) { oldClientIDs[clientIndex] = client.clientID; @@ -349,19 +349,19 @@ void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs, } bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID, - const KVMFRFrameSchedule& schedule, uint64_t now) + const FrameScheduleUpdate& schedule, uint64_t now) { - static const KVMFRFrameScheduleFlags validFlags = - KVMFR_FRAME_SCHEDULE_ACTIVE | - KVMFR_FRAME_SCHEDULE_RELEASE | - KVMFR_FRAME_SCHEDULE_RESET | - KVMFR_FRAME_SCHEDULE_IMMEDIATE; + static const uint32_t validFlags = + FRAME_SCHEDULE_ACTIVE | + FRAME_SCHEDULE_RELEASE | + FRAME_SCHEDULE_RESET | + FRAME_SCHEDULE_IMMEDIATE; if (!sourceClientID || schedule.clientID != sourceClientID || schedule.flags & ~validFlags) return false; - if (schedule.flags & KVMFR_FRAME_SCHEDULE_RELEASE) + if (schedule.flags & FRAME_SCHEDULE_RELEASE) { AcquireSRWLockExclusive(&m_lock); Client * client = FindClient(schedule.clientID); @@ -381,7 +381,7 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID, return true; } - if (!(schedule.flags & KVMFR_FRAME_SCHEDULE_ACTIVE) || + if (!(schedule.flags & FRAME_SCHEDULE_ACTIVE) || schedule.period < MIN_SCHEDULE_PERIOD_NS || schedule.period > MAX_PERIOD_NS || schedule.targetSlack >= schedule.period || @@ -400,7 +400,7 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID, } const bool explicitReset = - (schedule.flags & KVMFR_FRAME_SCHEDULE_RESET) != 0; + (schedule.flags & FRAME_SCHEDULE_RESET) != 0; const bool reset = client->generation != schedule.generation || explicitReset; bool wake = reset || !client->active || @@ -417,7 +417,7 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID, client->targetSlack = schedule.targetSlack; client->expiry = now + static_cast(schedule.lease) * 1000000; client->active = true; - if (schedule.flags & KVMFR_FRAME_SCHEDULE_IMMEDIATE) + if (schedule.flags & FRAME_SCHEDULE_IMMEDIATE) { client->immediate = true; wake = true; @@ -425,7 +425,7 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID, wake |= ElectOwner(now, explicitReset ? schedule.clientID : 0); if (m_scheduling && client->clientID == m_schedule.clientID && client->generation == m_schedule.generation && - (schedule.flags & KVMFR_FRAME_SCHEDULE_IMMEDIATE)) + (schedule.flags & FRAME_SCHEDULE_IMMEDIATE)) { ++m_forceRequestTicket; ++m_republishRequestTicket; @@ -439,7 +439,7 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID, } bool CFrameScheduler::ApplyFeedback(Client& client, - const KVMFRFrameSchedule& schedule) + const FrameScheduleUpdate& schedule) { if (!m_scheduling || client.clientID != m_schedule.clientID || schedule.generation != m_schedule.generation || diff --git a/idd/LGIdd/capture/CFrameScheduler.h b/idd/LGIdd/transport/CFrameScheduler.h similarity index 91% rename from idd/LGIdd/capture/CFrameScheduler.h rename to idd/LGIdd/transport/CFrameScheduler.h index b3cde9c6..ef90392b 100644 --- a/idd/LGIdd/capture/CFrameScheduler.h +++ b/idd/LGIdd/transport/CFrameScheduler.h @@ -23,11 +23,7 @@ #include #include -extern "C" { - #include -} - -#include "common/KVMFR.h" +#include "transport/TransportTypes.h" class CFrameScheduler { @@ -79,15 +75,15 @@ private: bool accepted; }; - static const unsigned PUBLICATION_HISTORY_SIZE = 128; + static const unsigned PUBLICATION_HISTORY_SIZE = 128; static const unsigned WORK_TIMING_HISTORY_SIZE = 32; mutable SRWLOCK m_lock = SRWLOCK_INIT; HANDLE m_wakeEvent = nullptr; - Client m_clients[LGMP_MAX_CLIENTS] = {}; - Schedule m_schedule = {}; - bool m_scheduling = false; - uint32_t m_epoch = 0; + Client m_clients[TRANSPORT_MAX_CLIENTS] = {}; + Schedule m_schedule = {}; + bool m_scheduling = false; + uint32_t m_epoch = 0; // A result acknowledges only the request tickets captured by its attempt. uint64_t m_forceRequestTicket = 0; @@ -122,7 +118,7 @@ private: Publication * FindPublication(const Schedule& schedule, uint32_t frameSerial); bool ElectOwner(uint64_t now, uint32_t resetClientID = 0); - bool ApplyFeedback(Client& client, const KVMFRFrameSchedule& schedule); + bool ApplyFeedback(Client& client, const FrameScheduleUpdate& schedule); void AdvanceCurrentDeadline(); void AdvanceDeadlineSerial(uint64_t count); void AdvanceDeadline(uint64_t now); @@ -139,7 +135,7 @@ public: void UpdateSubscribers(const uint32_t * clientIDs, unsigned count, const uint32_t * ownerClientIDs, unsigned ownerCount, uint64_t now); bool UpdateSchedule(uint32_t sourceClientID, - const KVMFRFrameSchedule& schedule, uint64_t now); + const FrameScheduleUpdate& schedule, uint64_t now); bool GetSchedule(Schedule& schedule) const; HANDLE GetWakeEvent() const { return m_wakeEvent; } void ObserveFrame(uint64_t now); diff --git a/idd/LGIdd/capture/FrameBufferTypes.h b/idd/LGIdd/transport/FrameBufferTypes.h similarity index 81% rename from idd/LGIdd/capture/FrameBufferTypes.h rename to idd/LGIdd/transport/FrameBufferTypes.h index c607d098..c8dcfd71 100644 --- a/idd/LGIdd/capture/FrameBufferTypes.h +++ b/idd/LGIdd/transport/FrameBufferTypes.h @@ -22,19 +22,10 @@ #include -// FrameBuffer overlays LGMP shared memory and has a variable-length payload. -#pragma warning(push) -#pragma warning(disable: 4200) -struct FrameBuffer -{ - volatile uint32_t wp; - uint8_t data[0]; -}; -#pragma warning(pop) - struct PreparedFrameBuffer { unsigned frameIndex; uint8_t * mem; + uint64_t heapOffset; bool fullCopy; }; diff --git a/idd/LGIdd/transport/FrameMemoryLimits.h b/idd/LGIdd/transport/FrameMemoryLimits.h index dbe0b7bc..9e7ac6f6 100644 --- a/idd/LGIdd/transport/FrameMemoryLimits.h +++ b/idd/LGIdd/transport/FrameMemoryLimits.h @@ -24,8 +24,9 @@ struct FrameMemoryLimits { - uint64_t sharedSize = 0; + uint64_t capacity = 0; uint64_t frameMemoryOffset = 0; uint64_t alignment = 0; uint64_t maxFrameSize = 0; + unsigned bufferCount = 0; }; diff --git a/idd/LGIdd/transport/IControlTransport.h b/idd/LGIdd/transport/IControlTransport.h new file mode 100644 index 00000000..7c67f8af --- /dev/null +++ b/idd/LGIdd/transport/IControlTransport.h @@ -0,0 +1,42 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma once + +#include "postprocess/D12FrameFormat.h" + +#include +#include +#include + +#include + +class IControlTransport +{ +public: + virtual ~IControlTransport() = default; + + virtual void SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info, + const BYTE * data, UINT sdrWhiteLevel) = 0; + virtual void SetColorTransform( + std::shared_ptr transform) = 0; + virtual std::shared_ptr + GetColorTransform() const = 0; +}; diff --git a/idd/LGIdd/transport/IFrameTransport.h b/idd/LGIdd/transport/IFrameTransport.h new file mode 100644 index 00000000..982e555b --- /dev/null +++ b/idd/LGIdd/transport/IFrameTransport.h @@ -0,0 +1,87 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma once + +#include "postprocess/D12FrameFormat.h" +#include "transport/CFrameScheduler.h" +#include "transport/FrameBufferTypes.h" +#include "transport/TransportTypes.h" + +#include +#include +#include + +class IFrameTransport +{ +public: + virtual ~IFrameTransport() = default; + + virtual size_t GetMaxFrameSize() const = 0; + + virtual bool FrameBufferAvailable( + const CFrameScheduler::Schedule& schedule, + bool allowReadyReplacement = true) = 0; + virtual bool HasPublishedFrame() const = 0; + virtual void ProcessDeliveries() = 0; + virtual bool GetPendingDeliveryTarget( + uint64_t now, uint64_t& target) = 0; + virtual bool RetryPendingDelivery(uint64_t now, bool& retry) = 0; + virtual PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch, + const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat, + const RECT * dirtyRects, unsigned nbDirtyRects, + const CFrameScheduler::Schedule& schedule, + bool allowReadyReplacement = true) = 0; + virtual bool PublishFrameBuffer(unsigned frameIndex, + const CFrameScheduler::Schedule& schedule, + bool& deliveredToOwner) = 0; + virtual bool RepublishFrameBuffer( + const CFrameScheduler::Schedule& schedule) = 0; + virtual bool TryFrameSubmitted(unsigned frameIndex, + const CFrameScheduler::Schedule& schedule) = 0; + virtual void CommitFrameBuffer(unsigned frameIndex, + const CFrameScheduler::Schedule& schedule, bool periodic, + bool deliveredToOwner) = 0; + virtual void AbortFrameBuffer(unsigned frameIndex) = 0; + virtual void FailFrameBuffer(unsigned frameIndex) = 0; + virtual void CompleteFrameBuffer( + unsigned frameIndex, bool succeeded) = 0; + virtual void SetFrameTiming(unsigned frameIndex, uint64_t captureTime, + uint64_t postProcessTime, uint64_t copyTime, uint64_t readyTime, + uint64_t holdTime, const CFrameScheduler::Schedule& schedule, + uint64_t completedAt) = 0; + virtual void WriteFrameBuffer(unsigned frameIndex, void * src, + size_t offset, size_t len, bool setWritePos) const = 0; + virtual void WriteFrameBufferRows(unsigned frameIndex, void * src, + size_t offset, size_t rowBytes, size_t pitch, + unsigned rows) const = 0; + virtual void FinalizeFrameBuffer(unsigned frameIndex) const = 0; + + virtual void ObserveFrame(uint64_t now) = 0; + virtual void ForceFrame() = 0; + virtual bool GetPublishTarget(uint64_t now, uint64_t& target, + CFrameScheduler::Schedule& schedule, bool& periodic, + bool& republish) = 0; + virtual void FrameMissed(const CFrameScheduler::Schedule& schedule, + uint64_t now, bool periodic) = 0; + virtual void FrameSuperseded() = 0; + virtual HANDLE GetFrameScheduleEvent() const = 0; + virtual void TryRecordFrameTiming(uint64_t duration) = 0; +}; diff --git a/idd/LGIdd/transport/ITransport.h b/idd/LGIdd/transport/ITransport.h new file mode 100644 index 00000000..7f2a7138 --- /dev/null +++ b/idd/LGIdd/transport/ITransport.h @@ -0,0 +1,63 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma once + +#include "transport/FrameMemoryLimits.h" +#include "transport/TransportTypes.h" + +#include +#include + +class IControlTransport; +class IFrameTransport; + +class ITransportEvents +{ +public: + virtual ~ITransportEvents() = default; + + virtual void OnSetCursorPos(int32_t x, int32_t y) = 0; + virtual void OnSetResolution(uint32_t width, uint32_t height) = 0; +}; + +class ITransport +{ +public: + enum class OpenResult + { + SUCCESS, + RETRY, + FAILURE, + }; + + virtual ~ITransport() = default; + + virtual OpenResult Open() = 0; + virtual bool Initialize() = 0; + virtual bool Setup(size_t alignment) = 0; + virtual void Process(ITransportEvents& events) = 0; + + virtual FrameMemoryLimits GetMemoryLimits() const = 0; + virtual DirectFrameBufferMemory GetDirectMemory() const = 0; + + virtual IFrameTransport& Frames() = 0; + virtual IControlTransport& Control() = 0; +}; diff --git a/idd/LGIdd/transport/TransportFactory.cpp b/idd/LGIdd/transport/TransportFactory.cpp new file mode 100644 index 00000000..ec671ef6 --- /dev/null +++ b/idd/LGIdd/transport/TransportFactory.cpp @@ -0,0 +1,30 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "transport/TransportFactory.h" + +#include "transport/lgmp/CLGMPTransport.h" + +#include + +std::unique_ptr CreateTransport() +{ + return std::unique_ptr(new (std::nothrow) CLGMPTransport()); +} diff --git a/idd/LGIdd/transport/TransportFactory.h b/idd/LGIdd/transport/TransportFactory.h new file mode 100644 index 00000000..b11671e9 --- /dev/null +++ b/idd/LGIdd/transport/TransportFactory.h @@ -0,0 +1,27 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma once + +#include "transport/ITransport.h" + +#include + +std::unique_ptr CreateTransport(); diff --git a/idd/LGIdd/transport/TransportTypes.h b/idd/LGIdd/transport/TransportTypes.h new file mode 100644 index 00000000..4a535af5 --- /dev/null +++ b/idd/LGIdd/transport/TransportTypes.h @@ -0,0 +1,64 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma once + +#include +#include + +enum : unsigned +{ + TRANSPORT_FRAME_QUEUE_LENGTH = 2, + TRANSPORT_FRAME_BUFFER_COUNT = 3, + TRANSPORT_MAX_CLIENTS = 8, +}; + +enum : uint32_t +{ + FRAME_SCHEDULE_ACTIVE = 0x1, + FRAME_SCHEDULE_RELEASE = 0x2, + FRAME_SCHEDULE_RESET = 0x4, + FRAME_SCHEDULE_IMMEDIATE = 0x8, +}; + +struct FrameScheduleUpdate +{ + uint32_t clientID; + uint32_t generation; + uint32_t flags; + uint64_t period; + uint64_t targetSlack; + int64_t phaseError; + uint32_t feedbackFrameSerial; + uint32_t feedbackScheduleEpoch; + uint32_t feedbackDeadlineSerial; + uint32_t lease; +}; + +struct DirectFrameBufferMemory +{ + void * address = nullptr; + size_t size = 0; + + explicit operator bool() const + { + return address && size; + } +}; diff --git a/idd/LGIdd/transport/CIVSHMEM.cpp b/idd/LGIdd/transport/lgmp/CIVSHMEM.cpp similarity index 99% rename from idd/LGIdd/transport/CIVSHMEM.cpp rename to idd/LGIdd/transport/lgmp/CIVSHMEM.cpp index a9de4fd1..9a68491e 100644 --- a/idd/LGIdd/transport/CIVSHMEM.cpp +++ b/idd/LGIdd/transport/lgmp/CIVSHMEM.cpp @@ -18,7 +18,7 @@ * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "transport/CIVSHMEM.h" +#include "transport/lgmp/CIVSHMEM.h" #include #include diff --git a/idd/LGIdd/transport/CIVSHMEM.h b/idd/LGIdd/transport/lgmp/CIVSHMEM.h similarity index 96% rename from idd/LGIdd/transport/CIVSHMEM.h rename to idd/LGIdd/transport/lgmp/CIVSHMEM.h index b9781548..b79bcd79 100644 --- a/idd/LGIdd/transport/CIVSHMEM.h +++ b/idd/LGIdd/transport/lgmp/CIVSHMEM.h @@ -47,5 +47,5 @@ public: void Close(); size_t GetSize() const { return m_size; } - void * GetMem () { return m_mem; } + void * GetMem () const { return m_mem; } }; diff --git a/idd/LGIdd/transport/CLGMPControl.cpp b/idd/LGIdd/transport/lgmp/CLGMPControl.cpp similarity index 99% rename from idd/LGIdd/transport/CLGMPControl.cpp rename to idd/LGIdd/transport/lgmp/CLGMPControl.cpp index 01a9f148..5a43d57f 100644 --- a/idd/LGIdd/transport/CLGMPControl.cpp +++ b/idd/LGIdd/transport/lgmp/CLGMPControl.cpp @@ -18,7 +18,7 @@ * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "transport/CLGMPControl.h" +#include "transport/lgmp/CLGMPControl.h" #include "CDebug.h" diff --git a/idd/LGIdd/transport/CLGMPControl.h b/idd/LGIdd/transport/lgmp/CLGMPControl.h similarity index 85% rename from idd/LGIdd/transport/CLGMPControl.h rename to idd/LGIdd/transport/lgmp/CLGMPControl.h index 10e28729..c4d773af 100644 --- a/idd/LGIdd/transport/CLGMPControl.h +++ b/idd/LGIdd/transport/lgmp/CLGMPControl.h @@ -20,8 +20,8 @@ #pragma once -#include "transport/CLGMPHost.h" -#include "postprocess/D12FrameFormat.h" +#include "transport/lgmp/CLGMPHost.h" +#include "transport/IControlTransport.h" #include "common/KVMFR.h" @@ -31,9 +31,13 @@ #include -class CLGMPControl +class CLGMPTransport; + +class CLGMPControl final : public IControlTransport { private: + friend class CLGMPTransport; + static constexpr int POINTER_SHAPE_BUFFERS = 3; static constexpr int COLOR_TRANSFORM_BUFFERS = 3; @@ -56,27 +60,26 @@ private: void SendColorTransform(); void ResendCursor(); - -public: - explicit CLGMPControl(CLGMPHost& host) : - m_host(host) {} - ~CLGMPControl(); - - CLGMPControl(const CLGMPControl&) = delete; - CLGMPControl& operator=(const CLGMPControl&) = delete; - bool Initialize(); void DeInit(); - LGMP_STATUS ReadDataWithSource(void * data, size_t * size, uint32_t * sourceClientID); LGMP_STATUS AckData(); bool HasNewSubscribers(); + void ResendState(); + +public: + explicit CLGMPControl(CLGMPHost& host) : + m_host(host) {} + ~CLGMPControl() override; + + CLGMPControl(const CLGMPControl&) = delete; + CLGMPControl& operator=(const CLGMPControl&) = delete; void SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info, const BYTE * data, - UINT sdrWhiteLevel); + UINT sdrWhiteLevel) override; void SetColorTransform( - std::shared_ptr transform); - std::shared_ptr GetColorTransform() const; - void ResendState(); + std::shared_ptr transform) override; + std::shared_ptr + GetColorTransform() const override; }; diff --git a/idd/LGIdd/transport/CFrameTransport.cpp b/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.cpp similarity index 91% rename from idd/LGIdd/transport/CFrameTransport.cpp rename to idd/LGIdd/transport/lgmp/CLGMPFrameTransport.cpp index b65a671c..e20103f9 100644 --- a/idd/LGIdd/transport/CFrameTransport.cpp +++ b/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.cpp @@ -18,14 +18,30 @@ * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "transport/CFrameTransport.h" +#include "transport/lgmp/CLGMPFrameTransport.h" -#include "transport/CIVSHMEM.h" -#include "transport/CLGMPHost.h" +#include "transport/lgmp/CIVSHMEM.h" +#include "transport/lgmp/CLGMPHost.h" #include "CDebug.h" #include +#pragma warning(push) +#pragma warning(disable: 4200) +struct LGMPBuffer +{ + volatile uint32_t wp; + uint8_t data[0]; +}; +#pragma warning(pop) + +static_assert(TRANSPORT_FRAME_QUEUE_LENGTH == LGMP_Q_FRAME_LEN, + "The capture pipeline must match the LGMP frame queue"); +static_assert(TRANSPORT_FRAME_BUFFER_COUNT == LGMP_Q_FRAME_BUFFER_LEN, + "The capture buffer pool must match the LGMP frame buffers"); +static_assert(TRANSPORT_MAX_CLIENTS == LGMP_MAX_CLIENTS, + "The scheduler must support every LGMP client"); + static const struct LGMPQueueConfig FRAME_QUEUE_CONFIG = { LGMP_Q_FRAME, // queueID @@ -49,19 +65,19 @@ static bool FrameScheduleMatches( a.epoch == b.epoch; } -CFrameTransport::CFrameTransport( +CLGMPFrameTransport::CLGMPFrameTransport( CLGMPHost& host, CIVSHMEM& ivshmem) : m_host(host), m_ivshmem(ivshmem) { } -CFrameTransport::~CFrameTransport() +CLGMPFrameTransport::~CLGMPFrameTransport() { DeInit(); } -bool CFrameTransport::Initialize() +bool CLGMPFrameTransport::Initialize() { if (m_frameQueue) { @@ -100,13 +116,13 @@ bool CFrameTransport::Initialize() return true; } -void CFrameTransport::SealMemoryLayout() +void CLGMPFrameTransport::SealMemoryLayout() { m_frameMemoryOffset = m_ivshmem.GetSize() - m_host.Available(); } -bool CFrameTransport::Setup(size_t alignSize) +bool CLGMPFrameTransport::Setup(size_t alignSize) { // This may get called multiple times as frame buffers cannot be allocated // until the GPU-specific alignment is known. @@ -116,7 +132,7 @@ bool CFrameTransport::Setup(size_t alignSize) m_alignSize = alignSize; if (!m_alignSize || (m_alignSize & (m_alignSize - 1)) || - m_alignSize < sizeof(KVMFRFrame) + sizeof(FrameBuffer)) + m_alignSize < sizeof(KVMFRFrame) + sizeof(LGMPBuffer)) { DEBUG_ERROR("Invalid frame buffer alignment: %llu", (unsigned long long)m_alignSize); @@ -147,7 +163,7 @@ bool CFrameTransport::Setup(size_t alignSize) return false; } - // The KVMFR frame header and FrameBuffer write position occupy the first + // The KVMFR frame header and frame-buffer write position occupy the first // alignment unit. Only the bytes after it are usable for pixel data. const size_t maxFrameSize = frameAllocationSize - m_alignSize; DEBUG_INFO("Max Frame Data Size: %u MiB", @@ -173,9 +189,9 @@ bool CFrameTransport::Setup(size_t alignSize) * Put the framebuffer on the border of the next page, this is to allow * for aligned DMA transfers by the receiver. */ - const size_t alignOffset = alignSize - sizeof(FrameBuffer); + const size_t alignOffset = alignSize - sizeof(LGMPBuffer); m_frame[i]->offset = (uint32_t)alignOffset; - m_frameBuffer[i] = reinterpret_cast( + m_frameBuffer[i] = reinterpret_cast( reinterpret_cast(m_frame[i]) + alignOffset); m_frameInFlight[i].store(false, std::memory_order_release); m_frameCompleted[i] = false; @@ -196,7 +212,7 @@ bool CFrameTransport::Setup(size_t alignSize) return true; } -void CFrameTransport::DeInit() +void CLGMPFrameTransport::DeInit() { m_frameScheduler.Reset(); @@ -226,18 +242,19 @@ void CFrameTransport::DeInit() memset(m_frameOwnerQueue, 0, sizeof(m_frameOwnerQueue)); } -FrameMemoryLimits CFrameTransport::GetMemoryLimits() const +FrameMemoryLimits CLGMPFrameTransport::GetMemoryLimits() const { FrameMemoryLimits limits; - limits.sharedSize = m_ivshmem.GetSize(); + limits.capacity = m_ivshmem.GetSize(); limits.frameMemoryOffset = m_frameMemoryOffset; limits.alignment = m_alignSize; limits.maxFrameSize = m_maxFrameSize; + limits.bufferCount = LGMP_Q_FRAME_BUFFER_LEN; return limits; } -CFrameTransport::SubscriberSnapshot -CFrameTransport::SnapshotSubscribers() const +CLGMPFrameTransport::SubscriberSnapshot +CLGMPFrameTransport::SnapshotSubscribers() const { SubscriberSnapshot snapshot; snapshot.status = lgmpHostGetClientIDs( @@ -276,7 +293,7 @@ CFrameTransport::SnapshotSubscribers() const return snapshot; } -void CFrameTransport::FinalizeSubscribers( +void CLGMPFrameTransport::FinalizeSubscribers( const SubscriberSnapshot& snapshot, uint64_t now) { if (snapshot.status == LGMP_OK) @@ -303,14 +320,14 @@ void CFrameTransport::FinalizeSubscribers( ProcessFrameDeliveries(); } -bool CFrameTransport::UpdateSchedule(uint32_t sourceClientID, - const KVMFRFrameSchedule& schedule, uint64_t now) +bool CLGMPFrameTransport::UpdateSchedule(uint32_t sourceClientID, + const FrameScheduleUpdate& schedule, uint64_t now) { return m_frameScheduler.UpdateSchedule(sourceClientID, schedule, now); } -CFrameTransport::SharedFramePostResult -CFrameTransport::PostSharedFrame(unsigned frameIndex, +CLGMPFrameTransport::SharedFramePostResult +CLGMPFrameTransport::PostSharedFrame(unsigned frameIndex, uint32_t excludeClientID, uint64_t now) { if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN || @@ -391,7 +408,7 @@ CFrameTransport::PostSharedFrame(unsigned frameIndex, return SHARED_FRAME_POSTED; } -bool CFrameTransport::PostSharedOwnerFrame(unsigned frameIndex, +bool CLGMPFrameTransport::PostSharedOwnerFrame(unsigned frameIndex, const CFrameScheduler::Schedule& schedule) { if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN || !schedule.clientID || @@ -419,7 +436,7 @@ bool CFrameTransport::PostSharedOwnerFrame(unsigned frameIndex, return true; } -void CFrameTransport::ProcessFrameDeliveries() +void CLGMPFrameTransport::ProcessFrameDeliveries() { if (!m_frameQueue) return; @@ -471,7 +488,7 @@ void CFrameTransport::ProcessFrameDeliveries() m_frameScheduler.NotifyPublisher(); } -int CFrameTransport::FindAvailableOwnerQueue( +int CLGMPFrameTransport::FindAvailableOwnerQueue( unsigned preferredIndex) const { for (unsigned i = 0; i < LGMP_Q_FRAME_LEN; ++i) @@ -487,7 +504,7 @@ int CFrameTransport::FindAvailableOwnerQueue( return -1; } -unsigned CFrameTransport::CountOwnerDeliveries( +unsigned CLGMPFrameTransport::CountOwnerDeliveries( uint32_t clientID) const { unsigned count = 0; @@ -503,7 +520,7 @@ unsigned CFrameTransport::CountOwnerDeliveries( return count; } -bool CFrameTransport::HasMatchingOwnerDelivery( +bool CLGMPFrameTransport::HasMatchingOwnerDelivery( uint32_t clientID, unsigned frameIndex, uint64_t token) const { for (const OwnerDelivery& delivery : m_ownerDelivery) @@ -526,7 +543,7 @@ bool CFrameTransport::HasMatchingOwnerDelivery( return false; } -bool CFrameTransport::FrameBufferReferenced( +bool CLGMPFrameTransport::FrameBufferReferenced( unsigned frameIndex) const { if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN) @@ -548,7 +565,7 @@ bool CFrameTransport::FrameBufferReferenced( return false; } -int CFrameTransport::FindAvailableFrameBuffer( +int CLGMPFrameTransport::FindAvailableFrameBuffer( bool allowReady) const { const LONG readyFrameIndex = @@ -582,7 +599,7 @@ int CFrameTransport::FindAvailableFrameBuffer( return static_cast(readyFrameIndex); } -int CFrameTransport::FindNewestCompletedFrame( +int CLGMPFrameTransport::FindNewestCompletedFrame( unsigned excludeFrameIndex) const { int newestFrame = -1; @@ -605,7 +622,7 @@ int CFrameTransport::FindNewestCompletedFrame( return newestFrame; } -bool CFrameTransport::FrameBufferAvailable( +bool CLGMPFrameTransport::FrameBufferAvailable( const CFrameScheduler::Schedule& schedule, bool allowReadyReplacement) { @@ -642,7 +659,7 @@ bool CFrameTransport::FrameBufferAvailable( return available; } -void CFrameTransport::ProcessFrameQueue() +void CLGMPFrameTransport::ProcessDeliveries() { if (!m_host.IsInitialized()) return; @@ -656,7 +673,7 @@ void CFrameTransport::ProcessFrameQueue() ProcessFrameDeliveries(); } -bool CFrameTransport::GetSharedFrameTarget(uint64_t now, +bool CLGMPFrameTransport::GetPendingDeliveryTarget(uint64_t now, uint64_t& target) { if (!m_frameQueue) @@ -686,7 +703,7 @@ bool CFrameTransport::GetSharedFrameTarget(uint64_t now, return result; } -bool CFrameTransport::ReplaySharedFrame(uint64_t now, bool& retry) +bool CLGMPFrameTransport::RetryPendingDelivery(uint64_t now, bool& retry) { retry = false; if (!m_frameQueue) @@ -710,7 +727,7 @@ bool CFrameTransport::ReplaySharedFrame(uint64_t now, bool& retry) return result == SHARED_FRAME_POSTED; } -PreparedFrameBuffer CFrameTransport::PrepareFrameBuffer( +PreparedFrameBuffer CLGMPFrameTransport::PrepareFrameBuffer( unsigned pitch, const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat, const RECT * dirtyRects, unsigned nbDirtyRects, const CFrameScheduler::Schedule& schedule, @@ -903,16 +920,18 @@ PreparedFrameBuffer CFrameTransport::PrepareFrameBuffer( } } - FrameBuffer * fb = m_frameBuffer[frameIndex]; + LGMPBuffer * fb = m_frameBuffer[frameIndex]; fb->wp = 0; result.frameIndex = frameIndex; result.mem = fb->data; + result.heapOffset = reinterpret_cast(fb->data) - + reinterpret_cast(m_ivshmem.GetMem()); result.fullCopy = fullCopy; return result; } -bool CFrameTransport::PublishFrameBuffer(unsigned frameIndex, +bool CLGMPFrameTransport::PublishFrameBuffer(unsigned frameIndex, const CFrameScheduler::Schedule& schedule, bool& deliveredToOwner) { deliveredToOwner = false; @@ -1017,7 +1036,7 @@ bool CFrameTransport::PublishFrameBuffer(unsigned frameIndex, return true; } -bool CFrameTransport::RepublishFrameBuffer( +bool CLGMPFrameTransport::RepublishFrameBuffer( const CFrameScheduler::Schedule& schedule) { if (!schedule.clientID) @@ -1118,7 +1137,7 @@ bool CFrameTransport::RepublishFrameBuffer( return true; } -void CFrameTransport::CommitFrameBuffer(unsigned frameIndex, +void CLGMPFrameTransport::CommitFrameBuffer(unsigned frameIndex, const CFrameScheduler::Schedule& schedule, bool periodic, bool deliveredToOwner) { @@ -1133,7 +1152,7 @@ void CFrameTransport::CommitFrameBuffer(unsigned frameIndex, m_frameScheduler.FrameRetained(schedule, now, periodic); } -bool CFrameTransport::TryFrameSubmitted(unsigned frameIndex, +bool CLGMPFrameTransport::TryFrameSubmitted(unsigned frameIndex, const CFrameScheduler::Schedule& schedule) { if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN) @@ -1143,17 +1162,17 @@ bool CFrameTransport::TryFrameSubmitted(unsigned frameIndex, schedule, m_frame[frameIndex]->frameSerial); } -void CFrameTransport::ObserveFrame(uint64_t now) +void CLGMPFrameTransport::ObserveFrame(uint64_t now) { m_frameScheduler.ObserveFrame(now); } -void CFrameTransport::ForceFrame() +void CLGMPFrameTransport::ForceFrame() { m_frameScheduler.ForceFrame(); } -bool CFrameTransport::GetPublishTarget(uint64_t now, +bool CLGMPFrameTransport::GetPublishTarget(uint64_t now, uint64_t& target, CFrameScheduler::Schedule& schedule, bool& periodic, bool& republish) { @@ -1161,23 +1180,23 @@ bool CFrameTransport::GetPublishTarget(uint64_t now, now, target, schedule, periodic, republish); } -void CFrameTransport::FrameMissed( +void CLGMPFrameTransport::FrameMissed( const CFrameScheduler::Schedule& schedule, uint64_t now, bool periodic) { m_frameScheduler.FrameMissed(schedule, now, periodic); } -void CFrameTransport::FrameSuperseded() +void CLGMPFrameTransport::FrameSuperseded() { m_frameScheduler.FrameSuperseded(); } -void CFrameTransport::TryRecordFrameTiming(uint64_t duration) +void CLGMPFrameTransport::TryRecordFrameTiming(uint64_t duration) { m_frameScheduler.TryRecordFrameTiming(duration); } -void CFrameTransport::AbortFrameBuffer(unsigned frameIndex) +void CLGMPFrameTransport::AbortFrameBuffer(unsigned frameIndex) { if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN) return; @@ -1193,7 +1212,7 @@ void CFrameTransport::AbortFrameBuffer(unsigned frameIndex) ReleaseSRWLockExclusive(&m_framePublishLock); } -void CFrameTransport::FailFrameBuffer(unsigned frameIndex) +void CLGMPFrameTransport::FailFrameBuffer(unsigned frameIndex) { if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN) return; @@ -1204,7 +1223,7 @@ void CFrameTransport::FailFrameBuffer(unsigned frameIndex) CompleteFrameBuffer(frameIndex, false); } -void CFrameTransport::CompleteFrameBuffer( +void CLGMPFrameTransport::CompleteFrameBuffer( unsigned frameIndex, bool succeeded) { if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN) @@ -1232,7 +1251,7 @@ void CFrameTransport::CompleteFrameBuffer( ReleaseSRWLockExclusive(&m_framePublishLock); } -void CFrameTransport::SetFrameTiming(unsigned frameIndex, +void CLGMPFrameTransport::SetFrameTiming(unsigned frameIndex, uint64_t captureTime, uint64_t postProcessTime, uint64_t copyTime, uint64_t readyTime, uint64_t holdTime, const CFrameScheduler::Schedule& schedule, uint64_t completedAt) @@ -1257,10 +1276,10 @@ void CFrameTransport::SetFrameTiming(unsigned frameIndex, InterlockedExchange((volatile LONG *)&frame->timingValid, 1); } -void CFrameTransport::WriteFrameBuffer(unsigned frameIndex, void * src, +void CLGMPFrameTransport::WriteFrameBuffer(unsigned frameIndex, void * src, size_t offset, size_t len, bool setWritePos) const { - FrameBuffer * fb = m_frameBuffer[frameIndex]; + LGMPBuffer * fb = m_frameBuffer[frameIndex]; memcpy( reinterpret_cast( @@ -1273,11 +1292,11 @@ void CFrameTransport::WriteFrameBuffer(unsigned frameIndex, void * src, fb->wp = (uint32_t)(offset + len); } -void CFrameTransport::WriteFrameBufferRows(unsigned frameIndex, +void CLGMPFrameTransport::WriteFrameBufferRows(unsigned frameIndex, void * src, size_t offset, size_t rowBytes, size_t pitch, unsigned rows) const { - FrameBuffer * fb = m_frameBuffer[frameIndex]; + LGMPBuffer * fb = m_frameBuffer[frameIndex]; uint8_t * dst = fb->data + offset; uint8_t * source = static_cast(src) + offset; for (unsigned row = 0; row < rows; ++row) @@ -1288,9 +1307,9 @@ void CFrameTransport::WriteFrameBufferRows(unsigned frameIndex, } } -void CFrameTransport::FinalizeFrameBuffer(unsigned frameIndex) const +void CLGMPFrameTransport::FinalizeFrameBuffer(unsigned frameIndex) const { const KVMFRFrame * frame = m_frame[frameIndex]; - FrameBuffer * fb = m_frameBuffer[frameIndex]; + LGMPBuffer * fb = m_frameBuffer[frameIndex]; fb->wp = frame->dataHeight * frame->pitch; } diff --git a/idd/LGIdd/transport/CFrameTransport.h b/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.h similarity index 75% rename from idd/LGIdd/transport/CFrameTransport.h rename to idd/LGIdd/transport/lgmp/CLGMPFrameTransport.h index 00132ae4..45c77d19 100644 --- a/idd/LGIdd/transport/CFrameTransport.h +++ b/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.h @@ -28,18 +28,21 @@ extern "C" { #include "lgmp/host.h" } -#include "capture/CFrameScheduler.h" -#include "capture/FrameBufferTypes.h" #include "common/KVMFR.h" -#include "postprocess/D12FrameFormat.h" +#include "transport/CFrameScheduler.h" #include "transport/FrameMemoryLimits.h" +#include "transport/IFrameTransport.h" class CIVSHMEM; class CLGMPHost; +class CLGMPTransport; +struct LGMPBuffer; -class CFrameTransport +class CLGMPFrameTransport final : public IFrameTransport { -public: +private: + friend class CLGMPTransport; + struct SubscriberSnapshot { uint32_t clientIDs [LGMP_MAX_CLIENTS] = {}; @@ -103,7 +106,7 @@ private: uint32_t m_frameSerial = 0; PLGMPMemory m_frameMemory[LGMP_Q_FRAME_BUFFER_LEN] = {}; KVMFRFrame * m_frame [LGMP_Q_FRAME_BUFFER_LEN] = {}; - FrameBuffer * m_frameBuffer[LGMP_Q_FRAME_BUFFER_LEN] = {}; + LGMPBuffer * m_frameBuffer[LGMP_Q_FRAME_BUFFER_LEN] = {}; unsigned m_width = 0; unsigned m_height = 0; @@ -136,74 +139,77 @@ private: uint32_t excludeClientID, uint64_t now); bool PostSharedOwnerFrame(unsigned frameIndex, const CFrameScheduler::Schedule& schedule); - -public: - CFrameTransport(CLGMPHost& host, CIVSHMEM& ivshmem); - ~CFrameTransport(); - - CFrameTransport(const CFrameTransport&) = delete; - CFrameTransport& operator=(const CFrameTransport&) = delete; - + CLGMPFrameTransport(CLGMPHost& host, CIVSHMEM& ivshmem); bool Initialize(); void SealMemoryLayout(); bool Setup(size_t alignSize); void DeInit(); - FrameMemoryLimits GetMemoryLimits() const; - size_t GetMaxFrameSize() const { return m_maxFrameSize; } - CIVSHMEM& GetIVSHMEM() { return m_ivshmem; } - SubscriberSnapshot SnapshotSubscribers() const; void FinalizeSubscribers( const SubscriberSnapshot& snapshot, uint64_t now); bool UpdateSchedule(uint32_t sourceClientID, - const KVMFRFrameSchedule& schedule, uint64_t now); + const FrameScheduleUpdate& schedule, uint64_t now); + +public: + ~CLGMPFrameTransport() override; + + CLGMPFrameTransport(const CLGMPFrameTransport&) = delete; + CLGMPFrameTransport& operator=(const CLGMPFrameTransport&) = delete; + + size_t GetMaxFrameSize() const override { return m_maxFrameSize; } bool FrameBufferAvailable(const CFrameScheduler::Schedule& schedule, - bool allowReadyReplacement = true); - bool HasPublishedFrame() const + bool allowReadyReplacement = true) override; + bool HasPublishedFrame() const override { return m_readyFrameIndex.load(std::memory_order_acquire) >= 0; } - void ProcessFrameQueue(); - bool GetSharedFrameTarget(uint64_t now, uint64_t& target); - bool ReplaySharedFrame(uint64_t now, bool& retry); + void ProcessDeliveries() override; + bool GetPendingDeliveryTarget( + uint64_t now, uint64_t& target) override; + bool RetryPendingDelivery(uint64_t now, bool& retry) override; PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch, const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat, const RECT * dirtyRects, unsigned nbDirtyRects, const CFrameScheduler::Schedule& schedule, - bool allowReadyReplacement = true); + bool allowReadyReplacement = true) override; bool PublishFrameBuffer(unsigned frameIndex, - const CFrameScheduler::Schedule& schedule, bool& deliveredToOwner); - bool RepublishFrameBuffer(const CFrameScheduler::Schedule& schedule); + const CFrameScheduler::Schedule& schedule, + bool& deliveredToOwner) override; + bool RepublishFrameBuffer( + const CFrameScheduler::Schedule& schedule) override; bool TryFrameSubmitted(unsigned frameIndex, - const CFrameScheduler::Schedule& schedule); + const CFrameScheduler::Schedule& schedule) override; void CommitFrameBuffer(unsigned frameIndex, const CFrameScheduler::Schedule& schedule, bool periodic, - bool deliveredToOwner); - void AbortFrameBuffer(unsigned frameIndex); - void FailFrameBuffer(unsigned frameIndex); - void CompleteFrameBuffer(unsigned frameIndex, bool succeeded); + bool deliveredToOwner) override; + void AbortFrameBuffer(unsigned frameIndex) override; + void FailFrameBuffer(unsigned frameIndex) override; + void CompleteFrameBuffer( + unsigned frameIndex, bool succeeded) override; void SetFrameTiming(unsigned frameIndex, uint64_t captureTime, uint64_t postProcessTime, uint64_t copyTime, uint64_t readyTime, uint64_t holdTime, const CFrameScheduler::Schedule& schedule, - uint64_t completedAt); + uint64_t completedAt) override; void WriteFrameBuffer(unsigned frameIndex, void * src, size_t offset, - size_t len, bool setWritePos) const; + size_t len, bool setWritePos) const override; void WriteFrameBufferRows(unsigned frameIndex, void * src, - size_t offset, size_t rowBytes, size_t pitch, unsigned rows) const; - void FinalizeFrameBuffer(unsigned frameIndex) const; + size_t offset, size_t rowBytes, size_t pitch, + unsigned rows) const override; + void FinalizeFrameBuffer(unsigned frameIndex) const override; - void ObserveFrame(uint64_t now); - void ForceFrame(); + void ObserveFrame(uint64_t now) override; + void ForceFrame() override; bool GetPublishTarget(uint64_t now, uint64_t& target, - CFrameScheduler::Schedule& schedule, bool& periodic, bool& republish); + CFrameScheduler::Schedule& schedule, bool& periodic, + bool& republish) override; void FrameMissed(const CFrameScheduler::Schedule& schedule, - uint64_t now, bool periodic); - void FrameSuperseded(); - HANDLE GetFrameScheduleEvent() const + uint64_t now, bool periodic) override; + void FrameSuperseded() override; + HANDLE GetFrameScheduleEvent() const override { return m_frameScheduler.GetWakeEvent(); } - void TryRecordFrameTiming(uint64_t duration); + void TryRecordFrameTiming(uint64_t duration) override; }; diff --git a/idd/LGIdd/transport/CLGMPHost.cpp b/idd/LGIdd/transport/lgmp/CLGMPHost.cpp similarity index 98% rename from idd/LGIdd/transport/CLGMPHost.cpp rename to idd/LGIdd/transport/lgmp/CLGMPHost.cpp index 1c437400..8419fe3e 100644 --- a/idd/LGIdd/transport/CLGMPHost.cpp +++ b/idd/LGIdd/transport/lgmp/CLGMPHost.cpp @@ -18,9 +18,9 @@ * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "transport/CLGMPHost.h" +#include "transport/lgmp/CLGMPHost.h" -#include "transport/CIVSHMEM.h" +#include "transport/lgmp/CIVSHMEM.h" #include "platform/CPlatformInfo.h" #include "CDebug.h" #include "VersionInfo.h" diff --git a/idd/LGIdd/transport/CLGMPHost.h b/idd/LGIdd/transport/lgmp/CLGMPHost.h similarity index 100% rename from idd/LGIdd/transport/CLGMPHost.h rename to idd/LGIdd/transport/lgmp/CLGMPHost.h diff --git a/idd/LGIdd/transport/lgmp/CLGMPTransport.cpp b/idd/LGIdd/transport/lgmp/CLGMPTransport.cpp new file mode 100644 index 00000000..a407e068 --- /dev/null +++ b/idd/LGIdd/transport/lgmp/CLGMPTransport.cpp @@ -0,0 +1,183 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "transport/lgmp/CLGMPTransport.h" + +#include "CDebug.h" +#include "common/KVMFR.h" + +static bool TranslateFrameScheduleFlags( + uint32_t source, uint32_t& destination) +{ + static const uint32_t validFlags = + KVMFR_FRAME_SCHEDULE_ACTIVE | + KVMFR_FRAME_SCHEDULE_RELEASE | + KVMFR_FRAME_SCHEDULE_RESET | + KVMFR_FRAME_SCHEDULE_IMMEDIATE; + + if (source & ~validFlags) + return false; + + destination = 0; + if (source & KVMFR_FRAME_SCHEDULE_ACTIVE) + destination |= FRAME_SCHEDULE_ACTIVE; + if (source & KVMFR_FRAME_SCHEDULE_RELEASE) + destination |= FRAME_SCHEDULE_RELEASE; + if (source & KVMFR_FRAME_SCHEDULE_RESET) + destination |= FRAME_SCHEDULE_RESET; + if (source & KVMFR_FRAME_SCHEDULE_IMMEDIATE) + destination |= FRAME_SCHEDULE_IMMEDIATE; + return true; +} + +CLGMPTransport::CLGMPTransport() : + m_control(m_host), + m_frames(m_host, m_ivshmem) +{ +} + +ITransport::OpenResult CLGMPTransport::Open() +{ + if (m_ivshmem.GetMem()) + return OpenResult::SUCCESS; + + if (!m_ivshmem.Init() || !m_ivshmem.Open()) + return OpenResult::RETRY; + + return OpenResult::SUCCESS; +} + +bool CLGMPTransport::Initialize() +{ + if (!m_host.Initialize(m_ivshmem)) + return false; + + // Preserve the shared-memory layout: frame queues precede the pointer queue + // and its retained cursor and color-transform allocations. + if (!m_frames.Initialize() || !m_control.Initialize()) + return false; + + m_frames.SealMemoryLayout(); + return true; +} + +bool CLGMPTransport::Setup(size_t alignment) +{ + return m_frames.Setup(alignment); +} + +void CLGMPTransport::Process(ITransportEvents& events) +{ + const LGMP_STATUS processStatus = m_host.Process(); + if (processStatus != LGMP_OK) + { + if (processStatus == LGMP_ERR_CORRUPTED) + { + DEBUG_WARN( + "LGMP reported the shared memory has been corrupted, attempting to recover\n"); + // TODO: reinitialize LGMP. + return; + } + + DEBUG_ERROR("lgmpHostProcess Failed: %s", + lgmpStatusString(processStatus)); + // TODO: shut down LGMP. + return; + } + + const uint64_t now = CFrameScheduler::Nanotime(); + + // Take the frame subscriber snapshot before processing scheduling messages, + // then publish both updates together just as the original timer did. + const CLGMPFrameTransport::SubscriberSnapshot subscribers = + m_frames.SnapshotSubscribers(); + + uint8_t data[LGMP_MSGS_SIZE]; + size_t size; + uint32_t sourceClientID; + LGMP_STATUS status; + while ((status = m_control.ReadDataWithSource( + data, &size, &sourceClientID)) == LGMP_OK) + { + KVMFRMessage * msg = reinterpret_cast(data); + switch (msg->type) + { + case KVMFR_MESSAGE_SETCURSORPOS: + { + KVMFRSetCursorPos * position = + reinterpret_cast(msg); + events.OnSetCursorPos(position->x, position->y); + break; + } + + case KVMFR_MESSAGE_WINDOWSIZE: + { + KVMFRWindowSize * window = + reinterpret_cast(msg); + events.OnSetResolution(window->w, window->h); + break; + } + + case KVMFR_MESSAGE_FRAME_SCHEDULE: + { + const KVMFRFrameSchedule * schedule = + reinterpret_cast(msg); + uint32_t translatedFlags = 0; + bool valid = size == sizeof(*schedule) && + TranslateFrameScheduleFlags(schedule->flags, translatedFlags); + if (valid) + { + FrameScheduleUpdate update = {}; + update.clientID = schedule->clientID; + update.generation = schedule->generation; + update.flags = translatedFlags; + update.period = schedule->period; + update.targetSlack = schedule->targetSlack; + update.phaseError = schedule->phaseError; + update.feedbackFrameSerial = schedule->feedbackFrameSerial; + update.feedbackScheduleEpoch = schedule->feedbackScheduleEpoch; + update.feedbackDeadlineSerial = schedule->feedbackDeadlineSerial; + update.lease = schedule->lease; + valid = m_frames.UpdateSchedule(sourceClientID, update, now); + } + if (!valid) + DEBUG_WARN("Ignoring invalid KVMFR frame schedule"); + break; + } + } + + m_control.AckData(); + } + + m_frames.FinalizeSubscribers(subscribers, now); + + if (m_control.HasNewSubscribers()) + m_control.ResendState(); +} + +FrameMemoryLimits CLGMPTransport::GetMemoryLimits() const +{ + return m_frames.GetMemoryLimits(); +} + +DirectFrameBufferMemory CLGMPTransport::GetDirectMemory() const +{ + return {m_ivshmem.GetMem(), m_ivshmem.GetSize()}; +} diff --git a/idd/LGIdd/transport/lgmp/CLGMPTransport.h b/idd/LGIdd/transport/lgmp/CLGMPTransport.h new file mode 100644 index 00000000..12cbacfc --- /dev/null +++ b/idd/LGIdd/transport/lgmp/CLGMPTransport.h @@ -0,0 +1,56 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma once + +#include "transport/ITransport.h" +#include "transport/lgmp/CIVSHMEM.h" +#include "transport/lgmp/CLGMPControl.h" +#include "transport/lgmp/CLGMPFrameTransport.h" +#include "transport/lgmp/CLGMPHost.h" + +class CLGMPTransport final : public ITransport +{ +private: + // Keep this declaration order. Destruction must release frame and control + // allocations before the LGMP host and its IVSHMEM mapping are destroyed. + CIVSHMEM m_ivshmem; + CLGMPHost m_host; + CLGMPControl m_control; + CLGMPFrameTransport m_frames; + +public: + CLGMPTransport(); + ~CLGMPTransport() override = default; + + CLGMPTransport(const CLGMPTransport&) = delete; + CLGMPTransport& operator=(const CLGMPTransport&) = delete; + + OpenResult Open() override; + bool Initialize() override; + bool Setup(size_t alignment) override; + void Process(ITransportEvents& events) override; + + FrameMemoryLimits GetMemoryLimits() const override; + DirectFrameBufferMemory GetDirectMemory() const override; + + IFrameTransport& Frames() override { return m_frames; } + IControlTransport& Control() override { return m_control; } +};