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; }
+};