[idd] transport: abstract LGMP implementation

Introduce transport, frame, and control interfaces with an LGMP factory
backend.

Move LGMP and IVSHMEM implementation details under transport/lgmp and
expose direct frame-buffer memory through a neutral capability.
This commit is contained in:
Geoffrey McRae
2026-08-07 16:39:07 +10:00
parent 30a1383d5e
commit 6725133375
46 changed files with 1026 additions and 480 deletions

View File

@@ -36,7 +36,7 @@
#include "display/IddCxCompat.h" #include "display/IddCxCompat.h"
#include "display/device/CDeviceContext.h" #include "display/device/CDeviceContext.h"
#include "display/monitor/Context.h" #include "display/monitor/Context.h"
#include "transport/CLGMPControl.h" #include "transport/IControlTransport.h"
#include "transport/CPipeServer.h" #include "transport/CPipeServer.h"
#include "config/CSettings.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 * wrapper = WdfObjectGet_CMonitorContextWrapper(monitor);
auto * ctx = wrapper->context->GetDeviceContext(); auto * ctx = wrapper->context->GetDeviceContext();
auto & control = ctx->GetLGMPControl(); auto & control = ctx->GetTransport().Control();
if (ctx->IsSoftwareMode()) if (ctx->IsSoftwareMode())
{ {

View File

@@ -36,7 +36,6 @@
<ClCompile Include="capture\CFrameBufferResource.cpp" /> <ClCompile Include="capture\CFrameBufferResource.cpp" />
<ClCompile Include="capture\CFrameProcessor.cpp" /> <ClCompile Include="capture\CFrameProcessor.cpp" />
<ClCompile Include="capture\CFrameProcessorUtil.cpp" /> <ClCompile Include="capture\CFrameProcessorUtil.cpp" />
<ClCompile Include="capture\CFrameScheduler.cpp" />
<ClCompile Include="capture\CHardwareFrameProcessor.cpp" /> <ClCompile Include="capture\CHardwareFrameProcessor.cpp" />
<ClCompile Include="capture\CSoftwareFrameProcessor.cpp" /> <ClCompile Include="capture\CSoftwareFrameProcessor.cpp" />
<ClCompile Include="capture\CSwapChainCursor.cpp" /> <ClCompile Include="capture\CSwapChainCursor.cpp" />
@@ -53,11 +52,14 @@
<ClCompile Include="postprocess\effect\CDownsampleEffect.cpp" /> <ClCompile Include="postprocess\effect\CDownsampleEffect.cpp" />
<ClCompile Include="postprocess\effect\CHDR16to10Effect.cpp" /> <ClCompile Include="postprocess\effect\CHDR16to10Effect.cpp" />
<ClCompile Include="postprocess\effect\CRGB24Effect.cpp" /> <ClCompile Include="postprocess\effect\CRGB24Effect.cpp" />
<ClCompile Include="transport\CFrameTransport.cpp" /> <ClCompile Include="transport\CFrameScheduler.cpp" />
<ClCompile Include="transport\CIVSHMEM.cpp" />
<ClCompile Include="transport\CLGMPControl.cpp" />
<ClCompile Include="transport\CLGMPHost.cpp" />
<ClCompile Include="transport\CPipeServer.cpp" /> <ClCompile Include="transport\CPipeServer.cpp" />
<ClCompile Include="transport\TransportFactory.cpp" />
<ClCompile Include="transport\lgmp\CIVSHMEM.cpp" />
<ClCompile Include="transport\lgmp\CLGMPControl.cpp" />
<ClCompile Include="transport\lgmp\CLGMPFrameTransport.cpp" />
<ClCompile Include="transport\lgmp\CLGMPHost.cpp" />
<ClCompile Include="transport\lgmp\CLGMPTransport.cpp" />
<ClCompile Include="config\CSettings.cpp" /> <ClCompile Include="config\CSettings.cpp" />
<ClCompile Include="platform\CPlatformInfo.cpp" /> <ClCompile Include="platform\CPlatformInfo.cpp" />
</ItemGroup> </ItemGroup>
@@ -75,10 +77,8 @@
<ClInclude Include="display\monitor\Context.h" /> <ClInclude Include="display\monitor\Context.h" />
<ClInclude Include="capture\CFrameBufferPool.h" /> <ClInclude Include="capture\CFrameBufferPool.h" />
<ClInclude Include="capture\CFrameBufferResource.h" /> <ClInclude Include="capture\CFrameBufferResource.h" />
<ClInclude Include="capture\FrameBufferTypes.h" />
<ClInclude Include="capture\CFrameProcessor.h" /> <ClInclude Include="capture\CFrameProcessor.h" />
<ClInclude Include="capture\CFrameProcessorUtil.h" /> <ClInclude Include="capture\CFrameProcessorUtil.h" />
<ClInclude Include="capture\CFrameScheduler.h" />
<ClInclude Include="capture\CHardwareFrameProcessor.h" /> <ClInclude Include="capture\CHardwareFrameProcessor.h" />
<ClInclude Include="capture\CSoftwareFrameProcessor.h" /> <ClInclude Include="capture\CSoftwareFrameProcessor.h" />
<ClInclude Include="capture\CSwapChainProcessor.h" /> <ClInclude Include="capture\CSwapChainProcessor.h" />
@@ -94,12 +94,20 @@
<ClInclude Include="postprocess\effect\CDownsampleEffect.h" /> <ClInclude Include="postprocess\effect\CDownsampleEffect.h" />
<ClInclude Include="postprocess\effect\CHDR16to10Effect.h" /> <ClInclude Include="postprocess\effect\CHDR16to10Effect.h" />
<ClInclude Include="postprocess\effect\CRGB24Effect.h" /> <ClInclude Include="postprocess\effect\CRGB24Effect.h" />
<ClInclude Include="transport\CFrameTransport.h" /> <ClInclude Include="transport\CFrameScheduler.h" />
<ClInclude Include="transport\CIVSHMEM.h" />
<ClInclude Include="transport\CLGMPControl.h" />
<ClInclude Include="transport\CLGMPHost.h" />
<ClInclude Include="transport\CPipeServer.h" /> <ClInclude Include="transport\CPipeServer.h" />
<ClInclude Include="transport\FrameBufferTypes.h" />
<ClInclude Include="transport\FrameMemoryLimits.h" /> <ClInclude Include="transport\FrameMemoryLimits.h" />
<ClInclude Include="transport\IControlTransport.h" />
<ClInclude Include="transport\IFrameTransport.h" />
<ClInclude Include="transport\ITransport.h" />
<ClInclude Include="transport\TransportFactory.h" />
<ClInclude Include="transport\TransportTypes.h" />
<ClInclude Include="transport\lgmp\CIVSHMEM.h" />
<ClInclude Include="transport\lgmp\CLGMPControl.h" />
<ClInclude Include="transport\lgmp\CLGMPFrameTransport.h" />
<ClInclude Include="transport\lgmp\CLGMPHost.h" />
<ClInclude Include="transport\lgmp\CLGMPTransport.h" />
<ClInclude Include="config\CSettings.h" /> <ClInclude Include="config\CSettings.h" />
<ClInclude Include="platform\CPlatformInfo.h" /> <ClInclude Include="platform\CPlatformInfo.h" />
<ClInclude Include="util\CSRWLock.h" /> <ClInclude Include="util\CSRWLock.h" />

View File

@@ -29,6 +29,9 @@
<Filter Include="Transport"> <Filter Include="Transport">
<UniqueIdentifier>{22FDF1F6-0A8C-4B96-9E74-53D74733CC0A}</UniqueIdentifier> <UniqueIdentifier>{22FDF1F6-0A8C-4B96-9E74-53D74733CC0A}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Transport\LGMP">
<UniqueIdentifier>{530EE339-4AD6-4AE7-9A74-09420E73D04B}</UniqueIdentifier>
</Filter>
<Filter Include="Configuration"> <Filter Include="Configuration">
<UniqueIdentifier>{82810F1C-E51C-4DBD-86B2-1CDE8C16A2A9}</UniqueIdentifier> <UniqueIdentifier>{82810F1C-E51C-4DBD-86B2-1CDE8C16A2A9}</UniqueIdentifier>
</Filter> </Filter>
@@ -91,18 +94,12 @@
<ClInclude Include="capture\CFrameBufferResource.h"> <ClInclude Include="capture\CFrameBufferResource.h">
<Filter>Capture</Filter> <Filter>Capture</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="capture\FrameBufferTypes.h">
<Filter>Capture</Filter>
</ClInclude>
<ClInclude Include="capture\CFrameProcessor.h"> <ClInclude Include="capture\CFrameProcessor.h">
<Filter>Capture</Filter> <Filter>Capture</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="capture\CFrameProcessorUtil.h"> <ClInclude Include="capture\CFrameProcessorUtil.h">
<Filter>Capture</Filter> <Filter>Capture</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="capture\CFrameScheduler.h">
<Filter>Capture</Filter>
</ClInclude>
<ClInclude Include="capture\CHardwareFrameProcessor.h"> <ClInclude Include="capture\CHardwareFrameProcessor.h">
<Filter>Capture</Filter> <Filter>Capture</Filter>
</ClInclude> </ClInclude>
@@ -148,24 +145,48 @@
<ClInclude Include="postprocess\effect\CRGB24Effect.h"> <ClInclude Include="postprocess\effect\CRGB24Effect.h">
<Filter>Post-processing\Effects</Filter> <Filter>Post-processing\Effects</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="transport\CFrameTransport.h"> <ClInclude Include="transport\CFrameScheduler.h">
<Filter>Transport</Filter>
</ClInclude>
<ClInclude Include="transport\CIVSHMEM.h">
<Filter>Transport</Filter>
</ClInclude>
<ClInclude Include="transport\CLGMPControl.h">
<Filter>Transport</Filter>
</ClInclude>
<ClInclude Include="transport\CLGMPHost.h">
<Filter>Transport</Filter> <Filter>Transport</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="transport\CPipeServer.h"> <ClInclude Include="transport\CPipeServer.h">
<Filter>Transport</Filter> <Filter>Transport</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="transport\FrameBufferTypes.h">
<Filter>Transport</Filter>
</ClInclude>
<ClInclude Include="transport\FrameMemoryLimits.h"> <ClInclude Include="transport\FrameMemoryLimits.h">
<Filter>Transport</Filter> <Filter>Transport</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="transport\IControlTransport.h">
<Filter>Transport</Filter>
</ClInclude>
<ClInclude Include="transport\IFrameTransport.h">
<Filter>Transport</Filter>
</ClInclude>
<ClInclude Include="transport\ITransport.h">
<Filter>Transport</Filter>
</ClInclude>
<ClInclude Include="transport\TransportFactory.h">
<Filter>Transport</Filter>
</ClInclude>
<ClInclude Include="transport\TransportTypes.h">
<Filter>Transport</Filter>
</ClInclude>
<ClInclude Include="transport\lgmp\CIVSHMEM.h">
<Filter>Transport\LGMP</Filter>
</ClInclude>
<ClInclude Include="transport\lgmp\CLGMPControl.h">
<Filter>Transport\LGMP</Filter>
</ClInclude>
<ClInclude Include="transport\lgmp\CLGMPFrameTransport.h">
<Filter>Transport\LGMP</Filter>
</ClInclude>
<ClInclude Include="transport\lgmp\CLGMPHost.h">
<Filter>Transport\LGMP</Filter>
</ClInclude>
<ClInclude Include="transport\lgmp\CLGMPTransport.h">
<Filter>Transport\LGMP</Filter>
</ClInclude>
<ClInclude Include="config\CSettings.h"> <ClInclude Include="config\CSettings.h">
<Filter>Configuration</Filter> <Filter>Configuration</Filter>
</ClInclude> </ClInclude>
@@ -213,9 +234,6 @@
<ClCompile Include="capture\CFrameProcessorUtil.cpp"> <ClCompile Include="capture\CFrameProcessorUtil.cpp">
<Filter>Capture</Filter> <Filter>Capture</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="capture\CFrameScheduler.cpp">
<Filter>Capture</Filter>
</ClCompile>
<ClCompile Include="capture\CHardwareFrameProcessor.cpp"> <ClCompile Include="capture\CHardwareFrameProcessor.cpp">
<Filter>Capture</Filter> <Filter>Capture</Filter>
</ClCompile> </ClCompile>
@@ -264,21 +282,30 @@
<ClCompile Include="postprocess\effect\CRGB24Effect.cpp"> <ClCompile Include="postprocess\effect\CRGB24Effect.cpp">
<Filter>Post-processing\Effects</Filter> <Filter>Post-processing\Effects</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="transport\CFrameTransport.cpp"> <ClCompile Include="transport\CFrameScheduler.cpp">
<Filter>Transport</Filter>
</ClCompile>
<ClCompile Include="transport\CIVSHMEM.cpp">
<Filter>Transport</Filter>
</ClCompile>
<ClCompile Include="transport\CLGMPControl.cpp">
<Filter>Transport</Filter>
</ClCompile>
<ClCompile Include="transport\CLGMPHost.cpp">
<Filter>Transport</Filter> <Filter>Transport</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="transport\CPipeServer.cpp"> <ClCompile Include="transport\CPipeServer.cpp">
<Filter>Transport</Filter> <Filter>Transport</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="transport\TransportFactory.cpp">
<Filter>Transport</Filter>
</ClCompile>
<ClCompile Include="transport\lgmp\CIVSHMEM.cpp">
<Filter>Transport\LGMP</Filter>
</ClCompile>
<ClCompile Include="transport\lgmp\CLGMPControl.cpp">
<Filter>Transport\LGMP</Filter>
</ClCompile>
<ClCompile Include="transport\lgmp\CLGMPFrameTransport.cpp">
<Filter>Transport\LGMP</Filter>
</ClCompile>
<ClCompile Include="transport\lgmp\CLGMPHost.cpp">
<Filter>Transport\LGMP</Filter>
</ClCompile>
<ClCompile Include="transport\lgmp\CLGMPTransport.cpp">
<Filter>Transport\LGMP</Filter>
</ClCompile>
<ClCompile Include="config\CSettings.cpp"> <ClCompile Include="config\CSettings.cpp">
<Filter>Configuration</Filter> <Filter>Configuration</Filter>
</ClCompile> </ClCompile>

View File

@@ -19,11 +19,12 @@
*/ */
#include "capture/CFrameBufferPool.h" #include "capture/CFrameBufferPool.h"
#include "transport/IFrameTransport.h"
#include <stdint.h> #include <stdint.h>
void CFrameBufferPool::Init( void CFrameBufferPool::Init(
CFrameTransport * transport, CD3D12Device * dx12) IFrameTransport * transport, CD3D12Device * dx12)
{ {
m_transport = transport; m_transport = transport;
m_dx12 = dx12; m_dx12 = dx12;
@@ -43,8 +44,9 @@ CFrameBufferResource * CFrameBufferPool::Get(
return nullptr; return nullptr;
CFrameBufferResource * fbr = &m_buffers[buffer.frameIndex]; CFrameBufferResource * fbr = &m_buffers[buffer.frameIndex];
if (!fbr->Init(m_transport, m_dx12, buffer.frameIndex, buffer.mem, if (!fbr->Init(m_dx12, buffer.frameIndex, buffer.mem,
minSize, textureDesc)) buffer.heapOffset, minSize, m_transport->GetMaxFrameSize(),
textureDesc))
return nullptr; return nullptr;
return fbr; return fbr;

View File

@@ -21,22 +21,22 @@
#pragma once #pragma once
#include "capture/CFrameBufferResource.h" #include "capture/CFrameBufferResource.h"
#include "capture/FrameBufferTypes.h" #include "transport/FrameBufferTypes.h"
#include "common/KVMFR.h" #include "transport/TransportTypes.h"
struct CD3D12Device; struct CD3D12Device;
class CFrameTransport; class IFrameTransport;
class CFrameBufferPool class CFrameBufferPool
{ {
private: private:
CFrameTransport * m_transport = nullptr; IFrameTransport * m_transport = nullptr;
CD3D12Device * m_dx12 = nullptr; CD3D12Device * m_dx12 = nullptr;
CFrameBufferResource m_buffers[LGMP_Q_FRAME_BUFFER_LEN]; CFrameBufferResource m_buffers[TRANSPORT_FRAME_BUFFER_COUNT];
public: public:
void Init(CFrameTransport * transport, CD3D12Device * dx12); void Init(IFrameTransport * transport, CD3D12Device * dx12);
void Reset(); void Reset();
CFrameBufferResource * Get(const PreparedFrameBuffer& buffer, CFrameBufferResource * Get(const PreparedFrameBuffer& buffer,

View File

@@ -21,21 +21,19 @@
#include "capture/CFrameBufferResource.h" #include "capture/CFrameBufferResource.h"
#include "capture/CFrameProcessorUtil.h" #include "capture/CFrameProcessorUtil.h"
#include "d3d/CD3D12Device.h" #include "d3d/CD3D12Device.h"
#include "transport/CFrameTransport.h"
#include "transport/CIVSHMEM.h"
#include "CDebug.h" #include "CDebug.h"
#include <cstring> #include <cstring>
bool CFrameBufferResource::Init(CFrameTransport * transport, bool CFrameBufferResource::Init(CD3D12Device * dx12,
CD3D12Device * dx12, unsigned frameIndex, uint8_t * base, size_t size, unsigned frameIndex, uint8_t * base, uint64_t heapOffset, size_t size,
const D3D12_RESOURCE_DESC * textureDesc) size_t maxFrameSize, const D3D12_RESOURCE_DESC * textureDesc)
{ {
m_frameIndex = frameIndex; 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); (unsigned long long)size);
return false; return false;
} }
@@ -47,7 +45,7 @@ bool CFrameBufferResource::Init(CFrameTransport * transport,
D3D12_RESOURCE_DESC desc = {}; D3D12_RESOURCE_DESC desc = {};
if (textureDesc) if (textureDesc)
{ {
if (indirect || !dx12->CanUseIVSHMEMTexture()) if (indirect || !dx12->CanUseDirectTexture())
return false; return false;
desc = *textureDesc; desc = *textureDesc;
if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D || if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
@@ -130,20 +128,19 @@ bool CFrameBufferResource::Init(CFrameTransport * transport,
} }
else else
{ {
const UINT64 heapOffset =
(uintptr_t)base -
(uintptr_t)transport->GetIVSHMEM().GetMem();
const D3D12_RESOURCE_ALLOCATION_INFO allocation = const D3D12_RESOURCE_ALLOCATION_INFO allocation =
dx12->GetDevice()->GetResourceAllocationInfo(0, 1, &desc); dx12->GetDevice()->GetResourceAllocationInfo(0, 1, &desc);
allocationSize = allocation.SizeInBytes; allocationSize = allocation.SizeInBytes;
const D3D12_HEAP_DESC heapDesc = dx12->GetHeap()->GetDesc(); const D3D12_HEAP_DESC heapDesc =
dx12->GetTransportHeap()->GetDesc();
if (!allocation.Alignment || if (!allocation.Alignment ||
heapOffset % allocation.Alignment || heapOffset % allocation.Alignment ||
allocation.SizeInBytes > transport->GetMaxFrameSize() || allocation.SizeInBytes > maxFrameSize ||
heapOffset > heapDesc.SizeInBytes || heapOffset > heapDesc.SizeInBytes ||
allocation.SizeInBytes > heapDesc.SizeInBytes - heapOffset) 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; return false;
} }
@@ -156,20 +153,20 @@ bool CFrameBufferResource::Init(CFrameTransport * transport,
if (FAILED(hr) || if (FAILED(hr) ||
!(support.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D)) !(support.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D))
{ {
DEBUG_ERROR("IVSHMEM texture format is unsupported"); DEBUG_ERROR("Transport texture format is unsupported");
return false; return false;
} }
DEBUG_TRACE("Creating IVSHMEM texture for %p", base); DEBUG_TRACE("Creating transport texture for %p", base);
resName = L"IVSHMEM Texture"; resName = L"Transport Texture";
} }
else else
{ {
DEBUG_TRACE("Creating IVSHMEM buffer for %p", base); DEBUG_TRACE("Creating transport buffer for %p", base);
resName = L"IVSHMEM"; resName = L"Transport Buffer";
} }
hr = dx12->GetDevice()->CreatePlacedResource( hr = dx12->GetDevice()->CreatePlacedResource(
dx12->GetHeap().Get(), dx12->GetTransportHeap().Get(),
heapOffset, heapOffset,
&desc, &desc,
D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COMMON,

View File

@@ -27,11 +27,10 @@
#include <atomic> #include <atomic>
#include <stdint.h> #include <stdint.h>
#include "capture/CFrameScheduler.h" #include "transport/CFrameScheduler.h"
#include "d3d/CInteropResource.h" #include "d3d/CInteropResource.h"
struct CD3D12Device; struct CD3D12Device;
class CFrameTransport;
using namespace Microsoft::WRL; using namespace Microsoft::WRL;
@@ -70,8 +69,8 @@ class CFrameBufferResource
void * m_map = nullptr; void * m_map = nullptr;
public: public:
bool Init(CFrameTransport * transport, CD3D12Device * dx12, bool Init(CD3D12Device * dx12, unsigned frameIndex, uint8_t * base,
unsigned frameIndex, uint8_t * base, size_t size, uint64_t heapOffset, size_t size, size_t maxFrameSize,
const D3D12_RESOURCE_DESC * textureDesc = nullptr); const D3D12_RESOURCE_DESC * textureDesc = nullptr);
void Reset(); void Reset();

View File

@@ -27,9 +27,9 @@
#include <new> #include <new>
#include <utility> #include <utility>
CFrameProcessor::CFrameProcessor(CFrameTransport * transport, CFrameProcessor::CFrameProcessor(IFrameTransport * transport,
std::shared_ptr<CD3D12Device> dx12, std::shared_ptr<CD3D12Device> dx12,
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH],
SRWLOCK * pipelineLock, HANDLE terminateEvent) : SRWLOCK * pipelineLock, HANDLE terminateEvent) :
m_transport(transport), m_transport(transport),
m_dx12(std::move(dx12)), m_dx12(std::move(dx12)),
@@ -154,9 +154,9 @@ void CFrameProcessor::GetPreviousDamage(
} }
std::unique_ptr<CFrameProcessor> CreateFrameProcessor( std::unique_ptr<CFrameProcessor> CreateFrameProcessor(
bool software, CFrameTransport * transport, bool software, IFrameTransport * transport,
std::shared_ptr<CD3D12Device> dx12, std::shared_ptr<CD3D12Device> dx12,
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH],
SRWLOCK * pipelineLock, HANDLE terminateEvent) SRWLOCK * pipelineLock, HANDLE terminateEvent)
{ {
std::unique_ptr<CFrameProcessor> processor; std::unique_ptr<CFrameProcessor> processor;

View File

@@ -24,13 +24,15 @@
#include "capture/CFrameBufferPool.h" #include "capture/CFrameBufferPool.h"
#include "d3d/CInteropResource.h" #include "d3d/CInteropResource.h"
#include "postprocess/CPostProcessor.h" #include "postprocess/CPostProcessor.h"
#include "transport/CFrameScheduler.h"
#include "transport/TransportTypes.h"
#include <Windows.h> #include <Windows.h>
#include <memory> #include <memory>
using namespace Microsoft::WRL; using namespace Microsoft::WRL;
class CFrameTransport; class IFrameTransport;
struct FrameSubmission struct FrameSubmission
{ {
@@ -46,7 +48,7 @@ struct FrameSubmission
class CFrameProcessor class CFrameProcessor
{ {
protected: protected:
CFrameTransport * m_transport; IFrameTransport * m_transport;
std::shared_ptr<CD3D12Device> m_dx12; std::shared_ptr<CD3D12Device> m_dx12;
CPostProcessor * m_postProcessors; CPostProcessor * m_postProcessors;
SRWLOCK * m_pipelineLock; SRWLOCK * m_pipelineLock;
@@ -72,9 +74,9 @@ protected:
virtual void SetFullDamageLocked(); virtual void SetFullDamageLocked();
public: public:
CFrameProcessor(CFrameTransport * transport, CFrameProcessor(IFrameTransport * transport,
std::shared_ptr<CD3D12Device> dx12, std::shared_ptr<CD3D12Device> dx12,
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH],
SRWLOCK * pipelineLock, HANDLE terminateEvent); SRWLOCK * pipelineLock, HANDLE terminateEvent);
virtual ~CFrameProcessor() = default; virtual ~CFrameProcessor() = default;
@@ -94,7 +96,7 @@ public:
}; };
std::unique_ptr<CFrameProcessor> CreateFrameProcessor( std::unique_ptr<CFrameProcessor> CreateFrameProcessor(
bool software, CFrameTransport * transport, bool software, IFrameTransport * transport,
std::shared_ptr<CD3D12Device> dx12, std::shared_ptr<CD3D12Device> dx12,
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH],
SRWLOCK * pipelineLock, HANDLE terminateEvent); SRWLOCK * pipelineLock, HANDLE terminateEvent);

View File

@@ -20,7 +20,7 @@
#include "capture/CHardwareFrameProcessor.h" #include "capture/CHardwareFrameProcessor.h"
#include "capture/CFrameProcessorUtil.h" #include "capture/CFrameProcessorUtil.h"
#include "transport/CFrameTransport.h" #include "transport/IFrameTransport.h"
#include "util/CSRWLock.h" #include "util/CSRWLock.h"
#include "CDebug.h" #include "CDebug.h"
@@ -29,7 +29,7 @@
using namespace Microsoft::WRL; using namespace Microsoft::WRL;
static_assert(LGMP_Q_FRAME_LEN == 2, static_assert(TRANSPORT_FRAME_QUEUE_LENGTH == 2,
"IDD candidate pipeline assumes two slots"); "IDD candidate pipeline assumes two slots");
class CPublishPending class CPublishPending
@@ -71,8 +71,8 @@ public:
}; };
CHardwareFrameProcessor::CHardwareFrameProcessor( CHardwareFrameProcessor::CHardwareFrameProcessor(
CFrameTransport * transport, std::shared_ptr<CD3D12Device> dx12, IFrameTransport * transport, std::shared_ptr<CD3D12Device> dx12,
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH],
SRWLOCK * pipelineLock, HANDLE terminateEvent) : SRWLOCK * pipelineLock, HANDLE terminateEvent) :
CFrameProcessor(transport, std::move(dx12), postProcessors, CFrameProcessor(transport, std::move(dx12), postProcessors,
pipelineLock, terminateEvent) pipelineLock, terminateEvent)

View File

@@ -65,8 +65,8 @@ private:
bool active = false; bool active = false;
}; };
FrameCandidate m_candidates[LGMP_Q_FRAME_LEN]; FrameCandidate m_candidates[TRANSPORT_FRAME_QUEUE_LENGTH];
CandidateDamageTail m_candidateDamageTail[LGMP_Q_FRAME_LEN]; CandidateDamageTail m_candidateDamageTail[TRANSPORT_FRAME_QUEUE_LENGTH];
mutable SRWLOCK m_candidateLock = SRWLOCK_INIT; mutable SRWLOCK m_candidateLock = SRWLOCK_INIT;
SRWLOCK m_copySubmitLock = SRWLOCK_INIT; SRWLOCK m_copySubmitLock = SRWLOCK_INIT;
uint64_t m_candidateSequence = 0; uint64_t m_candidateSequence = 0;
@@ -89,9 +89,9 @@ private:
void SetFullDamageLocked() override; void SetFullDamageLocked() override;
public: public:
CHardwareFrameProcessor(CFrameTransport * transport, CHardwareFrameProcessor(IFrameTransport * transport,
std::shared_ptr<CD3D12Device> dx12, std::shared_ptr<CD3D12Device> dx12,
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH],
SRWLOCK * pipelineLock, HANDLE terminateEvent); SRWLOCK * pipelineLock, HANDLE terminateEvent);
bool IsValid() const override; bool IsValid() const override;

View File

@@ -20,21 +20,21 @@
#include "capture/CSoftwareFrameProcessor.h" #include "capture/CSoftwareFrameProcessor.h"
#include "capture/CFrameProcessorUtil.h" #include "capture/CFrameProcessorUtil.h"
#include "capture/FrameBufferTypes.h" #include "transport/TransportTypes.h"
#include "transport/CFrameTransport.h" #include "transport/IFrameTransport.h"
#include "util/CSRWLock.h" #include "util/CSRWLock.h"
#include "CDebug.h" #include "CDebug.h"
#include <utility> #include <utility>
CSoftwareFrameProcessor::CSoftwareFrameProcessor( CSoftwareFrameProcessor::CSoftwareFrameProcessor(
CFrameTransport * transport, std::shared_ptr<CD3D12Device> dx12, IFrameTransport * transport, std::shared_ptr<CD3D12Device> dx12,
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH],
SRWLOCK * pipelineLock, HANDLE terminateEvent) : SRWLOCK * pipelineLock, HANDLE terminateEvent) :
CFrameProcessor(transport, std::move(dx12), postProcessors, CFrameProcessor(transport, std::move(dx12), postProcessors,
pipelineLock, terminateEvent), pipelineLock, terminateEvent),
m_directTexture( 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 else
{ {
m_directTexture = false; 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) else if (m_directTexture)
{ {
m_directTexture = false; 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()) 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(); SetFullDamage();
return false; return false;
} }
@@ -190,7 +190,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
deliverySchedule.deliveryDeadlineSerial = 0; deliverySchedule.deliveryDeadlineSerial = 0;
deliverySchedule.phaseEligible = false; deliverySchedule.phaseEligible = false;
m_transport->ProcessFrameQueue(); m_transport->ProcessDeliveries();
if (!m_transport->FrameBufferAvailable( if (!m_transport->FrameBufferAvailable(
deliverySchedule, submission.noImageUpdate)) deliverySchedule, submission.noImageUpdate))
{ {
@@ -258,7 +258,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
RestorePendingDamage( RestorePendingDamage(
currentDirtyRects, nbDirtyRects, hasDamage); currentDirtyRects, nbDirtyRects, hasDamage);
DEBUG_ERROR_HR(deviceStatus, DEBUG_ERROR_HR(deviceStatus,
"D3D12 device removed while creating an IVSHMEM texture"); "D3D12 device removed while creating a transport texture");
SetFullDamage(); SetFullDamage();
return false; return false;
} }
@@ -266,7 +266,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
m_directTexture = false; m_directTexture = false;
textureDescPtr = nullptr; textureDescPtr = nullptr;
DEBUG_WARN( DEBUG_WARN(
"IVSHMEM textures unavailable; using a direct buffer copy"); "Transport textures unavailable; using a direct buffer copy");
} }
} }

View File

@@ -31,9 +31,9 @@ private:
CD3D12CommandSlot * slot, bool result, void * param1, void * param2); CD3D12CommandSlot * slot, bool result, void * param1, void * param2);
public: public:
CSoftwareFrameProcessor(CFrameTransport * transport, CSoftwareFrameProcessor(IFrameTransport * transport,
std::shared_ptr<CD3D12Device> dx12, std::shared_ptr<CD3D12Device> dx12,
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN], CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH],
SRWLOCK * pipelineLock, HANDLE terminateEvent); SRWLOCK * pipelineLock, HANDLE terminateEvent);
bool Submit(const FrameSubmission& submission) override; bool Submit(const FrameSubmission& submission) override;

View File

@@ -22,7 +22,7 @@
#include "display/IddCxCompat.h" #include "display/IddCxCompat.h"
#include "display/device/CDeviceContext.h" #include "display/device/CDeviceContext.h"
#include "transport/CLGMPControl.h" #include "transport/IControlTransport.h"
#include "CDebug.h" #include "CDebug.h"

View File

@@ -24,8 +24,8 @@
#include "display/device/CDeviceContext.h" #include "display/device/CDeviceContext.h"
#include "display/monitor/Context.h" #include "display/monitor/Context.h"
#include "platform/CPlatformInfo.h" #include "platform/CPlatformInfo.h"
#include "transport/CFrameTransport.h" #include "transport/IFrameTransport.h"
#include "transport/CLGMPControl.h" #include "transport/IControlTransport.h"
#include "util/CSRWLock.h" #include "util/CSRWLock.h"
#include <avrt.h> #include <avrt.h>
@@ -49,8 +49,8 @@ CSwapChainProcessor::CSwapChainProcessor(CMonitorContext * monitorContext,
m_assignmentGeneration(assignmentGeneration), m_assignmentGeneration(assignmentGeneration),
m_monitor(monitor), m_monitor(monitor),
m_devContext(devContext), m_devContext(devContext),
m_transport(devContext->GetFrameTransport()), m_transport(devContext->GetTransport().Frames()),
m_control(devContext->GetLGMPControl()), m_control(devContext->GetTransport().Control()),
m_hSwapChain(hSwapChain), m_hSwapChain(hSwapChain),
m_renderAdapter(renderAdapter), m_renderAdapter(renderAdapter),
m_dx11Device(dx11Device), m_dx11Device(dx11Device),
@@ -99,7 +99,8 @@ bool CSwapChainProcessor::InitializePipeline()
UINT64 alignSize = CPlatformInfo::GetPageSize(); UINT64 alignSize = CPlatformInfo::GetPageSize();
auto dx12Device = std::make_shared<CD3D12Device>(m_renderAdapter); auto dx12Device = std::make_shared<CD3D12Device>(m_renderAdapter);
const CD3D12Device::InitResult result = dx12Device->Init( 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) if (result == CD3D12Device::RETRY)
{ {
const HRESULT deviceStatus = const HRESULT deviceStatus =
@@ -115,9 +116,9 @@ bool CSwapChainProcessor::InitializePipeline()
if (result == CD3D12Device::FAILURE) if (result == CD3D12Device::FAILURE)
return false; return false;
if (!m_devContext->SetupLGMP(alignSize)) if (!m_devContext->SetupTransport(alignSize))
{ {
DEBUG_ERROR("SetupLGMP failed"); DEBUG_ERROR("Transport setup failed");
return false; return false;
} }
@@ -333,7 +334,7 @@ void CSwapChainProcessor::SwapChainThreadCore()
// Only the buffer2 acquisition path (IddCx 1.10+) reports it; on the legacy // Only the buffer2 acquisition path (IddCx 1.10+) reports it; on the legacy
// path HDR is not available, so default to SDR. // path HDR is not available, so default to SDR.
DXGI_COLOR_SPACE_TYPE colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; 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(); const uint64_t captureStart = CFrameScheduler::Nanotime();
#ifdef HAS_IDDCX_110 #ifdef HAS_IDDCX_110

View File

@@ -25,7 +25,7 @@
#include "display/IddCxCompat.h" #include "display/IddCxCompat.h"
#include "d3d/CInteropResourcePool.h" #include "d3d/CInteropResourcePool.h"
#include "capture/CFrameProcessor.h" #include "capture/CFrameProcessor.h"
#include "common/KVMFR.h" #include "postprocess/D12FrameFormat.h"
#include "postprocess/CPostProcessor.h" #include "postprocess/CPostProcessor.h"
#include <Windows.h> #include <Windows.h>
@@ -37,8 +37,8 @@ using namespace Microsoft::WRL;
class CMonitorContext; class CMonitorContext;
class CDeviceContext; class CDeviceContext;
class CFrameTransport; class IFrameTransport;
class CLGMPControl; class IControlTransport;
class CSwapChainProcessor class CSwapChainProcessor
{ {
@@ -47,8 +47,8 @@ private:
UINT64 m_assignmentGeneration; UINT64 m_assignmentGeneration;
IDDCX_MONITOR m_monitor; IDDCX_MONITOR m_monitor;
CDeviceContext * m_devContext; CDeviceContext * m_devContext;
CFrameTransport & m_transport; IFrameTransport & m_transport;
CLGMPControl & m_control; IControlTransport & m_control;
IDDCX_SWAPCHAIN m_hSwapChain; IDDCX_SWAPCHAIN m_hSwapChain;
LUID m_renderAdapter; LUID m_renderAdapter;
std::shared_ptr<CD3D11Device> m_dx11Device; std::shared_ptr<CD3D11Device> m_dx11Device;
@@ -56,7 +56,7 @@ private:
HANDLE m_newFrameEvent; HANDLE m_newFrameEvent;
CInteropResourcePool m_resPool; CInteropResourcePool m_resPool;
CPostProcessor m_postProcessors[LGMP_Q_FRAME_LEN]; CPostProcessor m_postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH];
std::unique_ptr<CFrameProcessor> m_frameProcessor; std::unique_ptr<CFrameProcessor> m_frameProcessor;
// Reconfiguration is exclusive while per-candidate recording is shared. // Reconfiguration is exclusive while per-candidate recording is shared.
SRWLOCK m_pipelineLock = SRWLOCK_INIT; SRWLOCK m_pipelineLock = SRWLOCK_INIT;
@@ -68,7 +68,7 @@ private:
Wrappers::Event m_cursorDataEvent; Wrappers::Event m_cursorDataEvent;
BYTE* m_shapeBuffer; BYTE* m_shapeBuffer;
DWORD m_lastShapeId = 0; DWORD m_lastShapeId = 0;
std::atomic<UINT> m_sdrWhiteLevel { KVMFR_SDR_WHITE_LEVEL_DEFAULT }; std::atomic<UINT> m_sdrWhiteLevel { LG_SDR_WHITE_LEVEL_DEFAULT };
#ifdef HAS_IDDCX_110 #ifdef HAS_IDDCX_110
// The per-frame metadata stream can select the monitor default, provide a // The per-frame metadata stream can select the monitor default, provide a

View File

@@ -20,7 +20,7 @@
#include "capture/CSwapChainProcessor.h" #include "capture/CSwapChainProcessor.h"
#include "transport/CFrameTransport.h" #include "transport/IFrameTransport.h"
#include <avrt.h> #include <avrt.h>
#include "CDebug.h" #include "CDebug.h"
@@ -83,7 +83,7 @@ void CSwapChainProcessor::PublisherThread()
const bool ready = m_frameProcessor->HasReadyFrame(); const bool ready = m_frameProcessor->HasReadyFrame();
if (!ready) if (!ready)
{ {
m_transport.ProcessFrameQueue(); m_transport.ProcessDeliveries();
if (m_frameProcessor->HasReadyFrame()) if (m_frameProcessor->HasReadyFrame())
continue; continue;
@@ -123,12 +123,12 @@ void CSwapChainProcessor::PublisherThread()
} }
uint64_t replayTarget; uint64_t replayTarget;
if (m_transport.GetSharedFrameTarget(current, replayTarget)) if (m_transport.GetPendingDeliveryTarget(current, replayTarget))
{ {
bool retry = false; bool retry = false;
if (replayTarget <= current) if (replayTarget <= current)
{ {
if (m_transport.ReplaySharedFrame(current, retry)) if (m_transport.RetryPendingDelivery(current, retry))
continue; continue;
current = CFrameScheduler::Nanotime(); current = CFrameScheduler::Nanotime();
@@ -205,15 +205,15 @@ void CSwapChainProcessor::PublisherThread()
uint64_t current = CFrameScheduler::Nanotime(); uint64_t current = CFrameScheduler::Nanotime();
uint64_t replayTarget; uint64_t replayTarget;
if (m_transport.GetSharedFrameTarget(current, replayTarget) && if (m_transport.GetPendingDeliveryTarget(current, replayTarget) &&
replayTarget < target) replayTarget < target)
{ {
if (replayTarget <= current) if (replayTarget <= current)
{ {
m_transport.ProcessFrameQueue(); m_transport.ProcessDeliveries();
current = CFrameScheduler::Nanotime(); current = CFrameScheduler::Nanotime();
bool retry = false; bool retry = false;
if (m_transport.ReplaySharedFrame(current, retry)) if (m_transport.RetryPendingDelivery(current, retry))
continue; continue;
current = CFrameScheduler::Nanotime(); current = CFrameScheduler::Nanotime();
@@ -251,7 +251,7 @@ void CSwapChainProcessor::PublisherThread()
} }
const uint64_t publishStart = CFrameScheduler::Nanotime(); const uint64_t publishStart = CFrameScheduler::Nanotime();
m_transport.ProcessFrameQueue(); m_transport.ProcessDeliveries();
if (!m_transport.FrameBufferAvailable(schedule) || if (!m_transport.FrameBufferAvailable(schedule) ||
!m_frameProcessor->Publish(schedule, periodic, publishStart)) !m_frameProcessor->Publish(schedule, periodic, publishStart))
{ {

View File

@@ -21,7 +21,7 @@
#include "d3d/CD3D12Device.h" #include "d3d/CD3D12Device.h"
#include "CDebug.h" #include "CDebug.h"
bool CD3D12Device::m_indirectCopy = false; bool CD3D12Device::s_directHeapFailed = false;
CD3D12Device::CD3D12Device(LUID adapterLuid) : CD3D12Device::CD3D12Device(LUID adapterLuid) :
m_adapterLuid(adapterLuid), m_adapterLuid(adapterLuid),
@@ -60,12 +60,14 @@ static void CALLBACK _D3D12DebugCallback(
description); description);
} }
CD3D12Device::InitResult CD3D12Device::Init(CIVSHMEM &ivshmem, CD3D12Device::InitResult CD3D12Device::Init(
UINT64 &alignSize, bool enableCompute) const DirectFrameBufferMemory& directMemory,
UINT64& alignSize, bool enableCompute)
{ {
HRESULT hr; HRESULT hr;
m_computeEnabled = enableCompute; m_computeEnabled = enableCompute;
m_indirectCopy = !directMemory || s_directHeapFailed;
hr = CreateDXGIFactory2(m_debug ? DXGI_CREATE_FACTORY_DEBUG : 0, IID_PPV_ARGS(&m_factory)); hr = CreateDXGIFactory2(m_debug ? DXGI_CREATE_FACTORY_DEBUG : 0, IID_PPV_ARGS(&m_factory));
if (FAILED(hr)) if (FAILED(hr))
@@ -105,34 +107,37 @@ CD3D12Device::InitResult CD3D12Device::Init(CIVSHMEM &ivshmem,
if (!m_indirectCopy) 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)) if (FAILED(hr))
{ {
DEBUG_ERROR_HR(hr, "Failed to open IVSHMEM as a D3D12Heap"); DEBUG_ERROR_HR(hr,
m_indirectCopy = true; "Failed to open transport memory as a D3D12 heap");
s_directHeapFailed = true;
return InitResult::RETRY; 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; alignSize = heapDesc.Alignment;
m_ivshmemTextureSupported = m_directTextureSupported =
(heapDesc.Flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER) && (heapDesc.Flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER) &&
!(heapDesc.Flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES); !(heapDesc.Flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES);
// test that the heap is usable // test that the heap is usable
if (!HeapTest()) 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 // 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; return InitResult::RETRY;
} }
DEBUG_INFO("Using IVSHMEM as a D3D12Heap"); DEBUG_INFO("Using transport memory as a D3D12 heap");
if (!m_ivshmemTextureSupported) if (!m_directTextureSupported)
DEBUG_WARN("IVSHMEM heap does not support placed textures"); DEBUG_WARN("Transport memory does not support placed textures");
} }
if (!m_copyQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COPY, if (!m_copyQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COPY,
@@ -182,7 +187,7 @@ bool CD3D12Device::HeapTest()
ComPtr<ID3D12Resource> resource; ComPtr<ID3D12Resource> resource;
hr = m_device->CreatePlacedResource( hr = m_device->CreatePlacedResource(
m_ivshmemHeap.Get(), m_transportHeap.Get(),
0, 0,
&desc, &desc,
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_DEST,
@@ -190,7 +195,8 @@ bool CD3D12Device::HeapTest()
IID_PPV_ARGS(&resource)); IID_PPV_ARGS(&resource));
if (FAILED(hr)) 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; return false;
} }
resource->SetName(L"HeapTest"); resource->SetName(L"HeapTest");

View File

@@ -26,8 +26,8 @@
#include <dxgi1_5.h> #include <dxgi1_5.h>
#include <d3d12.h> #include <d3d12.h>
#include "transport/CIVSHMEM.h"
#include "d3d/CD3D12CommandQueue.h" #include "d3d/CD3D12CommandQueue.h"
#include "transport/TransportTypes.h"
using namespace Microsoft::WRL; using namespace Microsoft::WRL;
@@ -37,8 +37,9 @@ struct CD3D12Device
LUID m_adapterLuid; LUID m_adapterLuid;
bool m_debug; bool m_debug;
// static as this needs to persist if set // A failed direct heap can remove the device. Preserve the fallback for
static bool m_indirectCopy; // the replacement device so initialization does not retry forever.
static bool s_directHeapFailed;
ComPtr<ID3D12Debug6 > m_dxDebug; ComPtr<ID3D12Debug6 > m_dxDebug;
ComPtr<ID3D12InfoQueue1> m_infoQueue; ComPtr<ID3D12InfoQueue1> m_infoQueue;
@@ -47,12 +48,13 @@ struct CD3D12Device
ComPtr<IDXGIFactory5> m_factory; ComPtr<IDXGIFactory5> m_factory;
ComPtr<IDXGIAdapter1> m_adapter; ComPtr<IDXGIAdapter1> m_adapter;
ComPtr<ID3D12Device3> m_device; ComPtr<ID3D12Device3> m_device;
ComPtr<ID3D12Heap > m_ivshmemHeap; ComPtr<ID3D12Heap > m_transportHeap;
CD3D12CommandQueue m_copyQueue; CD3D12CommandQueue m_copyQueue;
CD3D12CommandQueue m_computeQueue; CD3D12CommandQueue m_computeQueue;
bool m_computeEnabled = false; bool m_computeEnabled = false;
bool m_ivshmemTextureSupported = false; bool m_indirectCopy = true;
bool m_directTextureSupported = false;
bool HeapTest(); bool HeapTest();
@@ -67,8 +69,8 @@ struct CD3D12Device
SUCCESS SUCCESS
}; };
InitResult Init(CIVSHMEM &ivshmem, UINT64 &alignSize, InitResult Init(const DirectFrameBufferMemory& directMemory,
bool enableCompute); UINT64& alignSize, bool enableCompute);
void DeInit(); void DeInit();
// Wait for all command queues to finish in-flight GPU work and run their // Wait for all command queues to finish in-flight GPU work and run their
@@ -77,9 +79,9 @@ struct CD3D12Device
void WaitForIdle(); void WaitForIdle();
ComPtr<ID3D12Device3> GetDevice() { return m_device; } ComPtr<ID3D12Device3> GetDevice() { return m_device; }
ComPtr<ID3D12Heap > GetHeap() { return m_ivshmemHeap; } ComPtr<ID3D12Heap > GetTransportHeap() { return m_transportHeap; }
bool IsIndirectCopy() { return m_indirectCopy; } bool IsIndirectCopy() const { return m_indirectCopy; }
bool CanUseIVSHMEMTexture() { return m_ivshmemTextureSupported; } bool CanUseDirectTexture() const { return m_directTextureSupported; }
CD3D12CommandSlot * GetCopySlot (); CD3D12CommandSlot * GetCopySlot ();
CD3D12CommandSlot * GetCopySlot (unsigned frameIndex); CD3D12CommandSlot * GetCopySlot (unsigned frameIndex);

View File

@@ -21,7 +21,6 @@
#include "display/CDisplayConfiguration.h" #include "display/CDisplayConfiguration.h"
#include "CDebug.h" #include "CDebug.h"
#include "common/LGMPConfig.h"
#include "util/CSRWLock.h" #include "util/CSRWLock.h"
#include <d3d12.h> #include <d3d12.h>
@@ -59,12 +58,12 @@ bool CDisplayConfiguration::CalculateFrameSize(
bool CDisplayConfiguration::GetResolutionMemoryRequirements( bool CDisplayConfiguration::GetResolutionMemoryRequirements(
uint32_t width, uint32_t height, UINT64 alignment, uint32_t width, uint32_t height, UINT64 alignment,
const FrameMemoryLimits& limits, UINT64& frameSize, UINT64& sharedSize) const FrameMemoryLimits& limits, UINT64& frameSize, UINT64& requiredSize)
{ {
frameSize = 0; frameSize = 0;
sharedSize = 0; requiredSize = 0;
if (!alignment || !limits.frameMemoryOffset || if (!alignment || !limits.frameMemoryOffset || !limits.bufferCount ||
!CalculateFrameSize(width, height, frameSize)) !CalculateFrameSize(width, height, frameSize))
return false; return false;
@@ -76,12 +75,12 @@ bool CDisplayConfiguration::GetResolutionMemoryRequirements(
if (!AlignUp(limits.frameMemoryOffset, alignment, frameMemoryStart)) if (!AlignUp(limits.frameMemoryOffset, alignment, frameMemoryStart))
return false; return false;
sharedSize = frameMemoryStart + requiredSize = frameMemoryStart +
frameAllocationSize * LGMP_Q_FRAME_BUFFER_LEN; frameAllocationSize * limits.bufferCount;
return true; return true;
} }
uint32_t CDisplayConfiguration::RecommendedIVSHMEMSizeMiB( uint32_t CDisplayConfiguration::RecommendedMemorySizeMiB(
UINT64 requiredSize) UINT64 requiredSize)
{ {
UINT64 sizeMiB = requiredSize / 1048576; UINT64 sizeMiB = requiredSize / 1048576;
@@ -135,10 +134,10 @@ bool CDisplayConfiguration::LoadModes(const FrameMemoryLimits& limits)
for (const auto& configuredMode : configuredModes) for (const auto& configuredMode : configuredModes)
{ {
UINT64 frameSize; UINT64 frameSize;
UINT64 requiredIVSHMEMSize; UINT64 requiredMemorySize;
if (!GetResolutionMemoryRequirements(configuredMode.width, if (!GetResolutionMemoryRequirements(configuredMode.width,
configuredMode.height, alignment, limits, frameSize, configuredMode.height, alignment, limits, frameSize,
requiredIVSHMEMSize)) requiredMemorySize))
{ {
DEBUG_WARN("Filtering invalid %s mode %ux%u@%.3f", DEBUG_WARN("Filtering invalid %s mode %ux%u@%.3f",
configuredMode.extraMode ? "extra" : "configured", configuredMode.extraMode ? "extra" : "configured",
@@ -147,15 +146,15 @@ bool CDisplayConfiguration::LoadModes(const FrameMemoryLimits& limits)
continue; continue;
} }
if (requiredIVSHMEMSize > limits.sharedSize) if (requiredMemorySize > limits.capacity)
{ {
DEBUG_WARN( 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.extraMode ? "extra" : "configured",
configuredMode.width, configuredMode.height, configuredMode.width, configuredMode.height,
configuredMode.refreshMilliHz / 1000.0, configuredMode.refreshMilliHz / 1000.0,
(unsigned long long)requiredIVSHMEMSize, (unsigned long long)requiredMemorySize,
(unsigned long long)limits.sharedSize); (unsigned long long)limits.capacity);
continue; continue;
} }
@@ -170,7 +169,7 @@ bool CDisplayConfiguration::LoadModes(const FrameMemoryLimits& limits)
if (newModes.empty()) if (newModes.empty())
{ {
DEBUG_ERROR("No configured display modes fit in IVSHMEM"); DEBUG_ERROR("No configured display modes fit in transport memory");
return false; return false;
} }
@@ -225,20 +224,20 @@ CDisplayConfiguration::SetResolution(
ResolutionResult result; ResolutionResult result;
UINT64 frameSize; UINT64 frameSize;
UINT64 requiredIVSHMEMSize; UINT64 requiredMemorySize;
if (!GetResolutionMemoryRequirements(width, height, limits.alignment, if (!GetResolutionMemoryRequirements(width, height, limits.alignment,
limits, frameSize, requiredIVSHMEMSize)) limits, frameSize, requiredMemorySize))
{ {
DEBUG_WARN("Ignoring invalid resolution request: %ux%u", width, height); DEBUG_WARN("Ignoring invalid resolution request: %ux%u", width, height);
return result; return result;
} }
if (requiredIVSHMEMSize > limits.sharedSize) if (requiredMemorySize > limits.capacity)
{ {
result.status = ResolutionStatus::TOO_LARGE; result.status = ResolutionStatus::TOO_LARGE;
result.requiredMiB = RecommendedIVSHMEMSizeMiB(requiredIVSHMEMSize); result.requiredMiB = RecommendedMemorySizeMiB(requiredMemorySize);
DEBUG_WARN( 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, width, height,
(unsigned long long)frameSize, (unsigned long long)frameSize,
(unsigned long long)limits.maxFrameSize, (unsigned long long)limits.maxFrameSize,

View File

@@ -74,8 +74,8 @@ private:
UINT64& frameSize); UINT64& frameSize);
static bool GetResolutionMemoryRequirements(uint32_t width, static bool GetResolutionMemoryRequirements(uint32_t width,
uint32_t height, UINT64 alignment, const FrameMemoryLimits& limits, uint32_t height, UINT64 alignment, const FrameMemoryLimits& limits,
UINT64& frameSize, UINT64& sharedSize); UINT64& frameSize, UINT64& requiredSize);
static uint32_t RecommendedIVSHMEMSizeMiB(UINT64 requiredSize); static uint32_t RecommendedMemorySizeMiB(UINT64 requiredSize);
public: public:
explicit CDisplayConfiguration(CSettings& settings); explicit CDisplayConfiguration(CSettings& settings);

View File

@@ -57,7 +57,7 @@ private:
IDDCX_MONITOR m_monitor = nullptr; IDDCX_MONITOR m_monitor = nullptr;
// Guards the monitor/replug/swap-chain state. These values are touched by // 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; SRWLOCK m_lock = SRWLOCK_INIT;
bool m_replugMonitor = false; bool m_replugMonitor = false;

View File

@@ -22,6 +22,8 @@
#include "display/IddCxCompat.h" #include "display/IddCxCompat.h"
#include "transport/CPipeServer.h" #include "transport/CPipeServer.h"
#include "transport/IFrameTransport.h"
#include "transport/TransportFactory.h"
#include "CDebug.h" #include "CDebug.h"
#include <dxgi1_2.h> #include <dxgi1_2.h>
@@ -33,8 +35,7 @@ static const UINT IDDCX_VERSION_1_10 = 0x1A00;
CDeviceContext::CDeviceContext(WDFDEVICE wdfDevice) : CDeviceContext::CDeviceContext(WDFDEVICE wdfDevice) :
m_wdfDevice(wdfDevice), m_wdfDevice(wdfDevice),
m_lgmpControl(m_lgmpHost), m_transport(CreateTransport()),
m_frameTransport(m_lgmpHost, m_ivshmem),
m_displayConfiguration(g_settings) m_displayConfiguration(g_settings)
{ {
} }
@@ -49,10 +50,10 @@ CDeviceContext::~CDeviceContext()
m_initTimer = nullptr; m_initTimer = nullptr;
} }
if (m_lgmpTimer) if (m_transportTimer)
{ {
WdfTimerStop(m_lgmpTimer, TRUE); WdfTimerStop(m_transportTimer, TRUE);
m_lgmpTimer = nullptr; m_transportTimer = nullptr;
} }
} }
@@ -156,19 +157,32 @@ void CDeviceContext::InitAdapter()
return; 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 // silently abandoning the adapter (leaving the device loaded but with no
// monitor), retry from a timer until the shared memory becomes available. // monitor), retry from a timer until it can be opened.
if (!m_ivshmemOpened) if (!m_transportOpened)
{ {
if (!m_ivshmem.Init() || !m_ivshmem.Open()) if (!m_transport)
{ {
DEBUG_WARN("IVSHMEM not available yet, scheduling init retry"); DEBUG_ERROR("Failed to create the frame transport");
ScheduleInitRetry();
m_initInProgress.store(0); m_initInProgress.store(0);
return; 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 // 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"); DEBUG_INFO("No hardware render adapter available; using SDR software mode");
QueryIddCxCapabilities(); QueryIddCxCapabilities();
DEBUG_TRACE("Initializing LGMP metadata"); DEBUG_TRACE("Initializing frame transport metadata");
if (!InitializeLGMP()) if (!InitializeTransport())
{ {
m_initInProgress.store(0); m_initInProgress.store(0);
return; return;
} }
DEBUG_TRACE("Loading configured display modes"); DEBUG_TRACE("Loading configured display modes");
if (!m_displayConfiguration.Load(m_frameTransport.GetMemoryLimits())) if (!m_displayConfiguration.Load(m_transport->GetMemoryLimits()))
{ {
m_initInProgress.store(0); m_initInProgress.store(0);
return; return;
@@ -374,7 +388,7 @@ void CDeviceContext::ReplugMonitor()
void CDeviceContext::ReloadSettings() void CDeviceContext::ReloadSettings()
{ {
if (!m_displayConfiguration.ReloadSettings( if (!m_displayConfiguration.ReloadSettings(
m_frameTransport.GetMemoryLimits())) m_transport->GetMemoryLimits()))
return; return;
ReplugMonitor(); ReplugMonitor();
@@ -417,7 +431,7 @@ void CDeviceContext::SetResolution(uint32_t width, uint32_t height)
{ {
const CDisplayConfiguration::ResolutionResult result = const CDisplayConfiguration::ResolutionResult result =
m_displayConfiguration.SetResolution( m_displayConfiguration.SetResolution(
width, height, m_frameTransport.GetMemoryLimits()); width, height, m_transport->GetMemoryLimits());
switch (result.status) 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 m_transport && m_transport->Initialize();
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;
} }
bool CDeviceContext::SetupLGMP(size_t alignSize) bool CDeviceContext::SetupTransport(size_t alignSize)
{ {
// Frame buffers cannot be allocated until the GPU-specific alignment is // Frame buffers cannot be allocated until the GPU-specific alignment is
// known. The swap-chain path may call this again after setup completed. // known. The swap-chain path may call this again after setup completed.
if (m_frameTransport.GetMaxFrameSize()) if (m_transport->Frames().GetMaxFrameSize())
return true; return true;
if (!InitializeLGMP() || !m_frameTransport.Setup(alignSize)) if (!InitializeTransport() || !m_transport->Setup(alignSize))
return false; return false;
WDF_TIMER_CONFIG config; WDF_TIMER_CONFIG config;
@@ -472,7 +474,7 @@ bool CDeviceContext::SetupLGMP(size_t alignSize)
{ {
WDFOBJECT parent = WdfTimerGetParentObject(timer); WDFOBJECT parent = WdfTimerGetParentObject(timer);
auto wrapper = WdfObjectGet_CDeviceContextWrapper(parent); auto wrapper = WdfObjectGet_CDeviceContextWrapper(parent);
wrapper->context->LGMPTimer(); wrapper->context->TransportTimer();
}, },
10); 10);
config.AutomaticSerialization = FALSE; config.AutomaticSerialization = FALSE;
@@ -487,18 +489,18 @@ bool CDeviceContext::SetupLGMP(size_t alignSize)
attribs.ExecutionLevel = WdfExecutionLevelDispatch; attribs.ExecutionLevel = WdfExecutionLevelDispatch;
NTSTATUS status = WdfTimerCreate( NTSTATUS status = WdfTimerCreate(
&config, &attribs, &m_lgmpTimer); &config, &attribs, &m_transportTimer);
if (!NT_SUCCESS(status)) if (!NT_SUCCESS(status))
{ {
DEBUG_ERROR_HR(status, "Timer creation failed"); DEBUG_ERROR_HR(status, "Timer creation failed");
return false; return false;
} }
WdfTimerStart(m_lgmpTimer, WDF_REL_TIMEOUT_IN_MS(10)); WdfTimerStart(m_transportTimer, WDF_REL_TIMEOUT_IN_MS(10));
return true; return true;
} }
void CDeviceContext::LGMPTimer() void CDeviceContext::TransportTimer()
{ {
// Monitor work is deferred off IddCx callback threads. // Monitor work is deferred off IddCx callback threads.
switch (m_monitorManager.TakeDeferredAction()) switch (m_monitorManager.TakeDeferredAction())
@@ -515,74 +517,15 @@ void CDeviceContext::LGMPTimer()
break; break;
} }
const LGMP_STATUS processStatus = m_lgmpHost.Process(); m_transport->Process(*this);
if (processStatus != LGMP_OK) }
{
if (processStatus == LGMP_ERR_CORRUPTED) void CDeviceContext::OnSetCursorPos(int32_t x, int32_t y)
{ {
DEBUG_WARN( g_pipe.SetCursorPos(x, y);
"LGMP reported the shared memory has been corrupted, attempting to recover\n"); }
// TODO: reinitialize LGMP.
return; void CDeviceContext::OnSetResolution(uint32_t width, uint32_t height)
} {
SetResolution(width, height);
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<KVMFRMessage *>(data);
switch (msg->type)
{
case KVMFR_MESSAGE_SETCURSORPOS:
{
KVMFRSetCursorPos * position =
reinterpret_cast<KVMFRSetCursorPos *>(msg);
g_pipe.SetCursorPos(position->x, position->y);
break;
}
case KVMFR_MESSAGE_WINDOWSIZE:
{
KVMFRWindowSize * window =
reinterpret_cast<KVMFRWindowSize *>(msg);
SetResolution(window->w, window->h);
break;
}
case KVMFR_MESSAGE_FRAME_SCHEDULE:
{
const KVMFRFrameSchedule * schedule =
reinterpret_cast<KVMFRFrameSchedule *>(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();
} }

View File

@@ -25,17 +25,15 @@
#include <IddCx.h> #include <IddCx.h>
#include <atomic> #include <atomic>
#include <memory>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "display/CDisplayConfiguration.h" #include "display/CDisplayConfiguration.h"
#include "display/CMonitorManager.h" #include "display/CMonitorManager.h"
#include "transport/CFrameTransport.h" #include "transport/ITransport.h"
#include "transport/CIVSHMEM.h"
#include "transport/CLGMPControl.h"
#include "transport/CLGMPHost.h"
class CDeviceContext class CDeviceContext : private ITransportEvents
{ {
private: private:
WDFDEVICE m_wdfDevice; WDFDEVICE m_wdfDevice;
@@ -43,20 +41,17 @@ private:
LUID m_preferredRenderAdapter = {}; LUID m_preferredRenderAdapter = {};
bool m_havePreferredRenderAdapter = false; bool m_havePreferredRenderAdapter = false;
// At boot IVSHMEM may not have enumerated yet. The retry timer and atomic // At boot the selected transport may not be available yet. The retry timer
// gate keep adapter creation single-threaded until it becomes available. // and atomic gate keep adapter creation single-threaded until it is ready.
WDFTIMER m_initTimer = nullptr; WDFTIMER m_initTimer = nullptr;
bool m_ivshmemOpened = false; bool m_transportOpened = false;
std::atomic<LONG> m_initInProgress = 0; std::atomic<LONG> m_initInProgress = 0;
CIVSHMEM m_ivshmem; std::unique_ptr<ITransport> m_transport;
CLGMPHost m_lgmpHost; CDisplayConfiguration m_displayConfiguration;
CLGMPControl m_lgmpControl; CMonitorManager m_monitorManager;
CFrameTransport m_frameTransport;
CDisplayConfiguration m_displayConfiguration;
CMonitorManager m_monitorManager;
WDFTIMER m_lgmpTimer = nullptr; WDFTIMER m_transportTimer = nullptr;
UINT m_iddCxVersion = 0; UINT m_iddCxVersion = 0;
bool m_hasIddCx110DDIs = false; bool m_hasIddCx110DDIs = false;
@@ -68,8 +63,10 @@ private:
void ScheduleInitRetry(); void ScheduleInitRetry();
void StopInitRetry(); void StopInitRetry();
bool InitializeLGMP(); bool InitializeTransport();
void LGMPTimer(); 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); void SetResolution(uint32_t width, uint32_t height);
public: public:
@@ -79,7 +76,7 @@ public:
CDeviceContext(const CDeviceContext&) = delete; CDeviceContext(const CDeviceContext&) = delete;
CDeviceContext& operator=(const CDeviceContext&) = delete; CDeviceContext& operator=(const CDeviceContext&) = delete;
bool SetupLGMP(size_t alignSize); bool SetupTransport(size_t alignSize);
void InitAdapter(); void InitAdapter();
void FinishAdapterInit(UINT connectorIndex); void FinishAdapterInit(UINT connectorIndex);
@@ -96,14 +93,9 @@ public:
bool CanProcessFP16 () const { return m_canProcessFP16; } bool CanProcessFP16 () const { return m_canProcessFP16; }
bool IsSoftwareMode () const { return m_softwareMode; } bool IsSoftwareMode () const { return m_softwareMode; }
CFrameTransport& GetFrameTransport() ITransport& GetTransport()
{ {
return m_frameTransport; return *m_transport;
}
CLGMPControl& GetLGMPControl()
{
return m_lgmpControl;
} }
CDisplayConfiguration& GetDisplayConfiguration() CDisplayConfiguration& GetDisplayConfiguration()

View File

@@ -53,7 +53,7 @@ NTSTATUS CMonitorContext::AssignSwapChain(
// Build the D3D11 device into a local so the member is never observed // Build the D3D11 device into a local so the member is never observed
// half-constructed. The worker binds it before performing the expensive // 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<CD3D11Device>(renderAdapter); auto dx11Device = std::make_shared<CD3D11Device>(renderAdapter);
const HRESULT initStatus = dx11Device->Init(); const HRESULT initStatus = dx11Device->Init();
if (FAILED(initStatus)) if (FAILED(initStatus))

View File

@@ -22,7 +22,7 @@
#include "CDebug.h" #include "CDebug.h"
#include "config/CSettings.h" #include "config/CSettings.h"
#include "common/LGMPConfig.h" #include "transport/TransportTypes.h"
#include <algorithm> #include <algorithm>
#include <climits> #include <climits>
@@ -61,7 +61,7 @@ struct CRGB24Effect::State
std::shared_ptr<const D12ColorTransform> colorTransform; std::shared_ptr<const D12ColorTransform> 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 SampleCount = 64;
static const unsigned TrimCount = SampleCount / 8; static const unsigned TrimCount = SampleCount / 8;

View File

@@ -18,7 +18,7 @@
* Temple Place, Suite 330, Boston, MA 02111-1307 USA * Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "capture/CFrameScheduler.h" #include "transport/CFrameScheduler.h"
#include "CDebug.h" #include "CDebug.h"
@@ -288,10 +288,10 @@ void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs,
{ {
AcquireSRWLockExclusive(&m_lock); AcquireSRWLockExclusive(&m_lock);
uint32_t oldClientIDs [LGMP_MAX_CLIENTS] = {}; uint32_t oldClientIDs [TRANSPORT_MAX_CLIENTS] = {};
bool wasSubscribed [LGMP_MAX_CLIENTS] = {}; bool wasSubscribed [TRANSPORT_MAX_CLIENTS] = {};
bool wasOwnerCapable[LGMP_MAX_CLIENTS] = {}; bool wasOwnerCapable[TRANSPORT_MAX_CLIENTS] = {};
unsigned clientIndex = 0; unsigned clientIndex = 0;
for (const Client& client : m_clients) for (const Client& client : m_clients)
{ {
oldClientIDs[clientIndex] = client.clientID; oldClientIDs[clientIndex] = client.clientID;
@@ -349,19 +349,19 @@ void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs,
} }
bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID, bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID,
const KVMFRFrameSchedule& schedule, uint64_t now) const FrameScheduleUpdate& schedule, uint64_t now)
{ {
static const KVMFRFrameScheduleFlags validFlags = static const uint32_t validFlags =
KVMFR_FRAME_SCHEDULE_ACTIVE | FRAME_SCHEDULE_ACTIVE |
KVMFR_FRAME_SCHEDULE_RELEASE | FRAME_SCHEDULE_RELEASE |
KVMFR_FRAME_SCHEDULE_RESET | FRAME_SCHEDULE_RESET |
KVMFR_FRAME_SCHEDULE_IMMEDIATE; FRAME_SCHEDULE_IMMEDIATE;
if (!sourceClientID || schedule.clientID != sourceClientID || if (!sourceClientID || schedule.clientID != sourceClientID ||
schedule.flags & ~validFlags) schedule.flags & ~validFlags)
return false; return false;
if (schedule.flags & KVMFR_FRAME_SCHEDULE_RELEASE) if (schedule.flags & FRAME_SCHEDULE_RELEASE)
{ {
AcquireSRWLockExclusive(&m_lock); AcquireSRWLockExclusive(&m_lock);
Client * client = FindClient(schedule.clientID); Client * client = FindClient(schedule.clientID);
@@ -381,7 +381,7 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID,
return true; return true;
} }
if (!(schedule.flags & KVMFR_FRAME_SCHEDULE_ACTIVE) || if (!(schedule.flags & FRAME_SCHEDULE_ACTIVE) ||
schedule.period < MIN_SCHEDULE_PERIOD_NS || schedule.period < MIN_SCHEDULE_PERIOD_NS ||
schedule.period > MAX_PERIOD_NS || schedule.period > MAX_PERIOD_NS ||
schedule.targetSlack >= schedule.period || schedule.targetSlack >= schedule.period ||
@@ -400,7 +400,7 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID,
} }
const bool explicitReset = const bool explicitReset =
(schedule.flags & KVMFR_FRAME_SCHEDULE_RESET) != 0; (schedule.flags & FRAME_SCHEDULE_RESET) != 0;
const bool reset = client->generation != schedule.generation || const bool reset = client->generation != schedule.generation ||
explicitReset; explicitReset;
bool wake = reset || !client->active || bool wake = reset || !client->active ||
@@ -417,7 +417,7 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID,
client->targetSlack = schedule.targetSlack; client->targetSlack = schedule.targetSlack;
client->expiry = now + static_cast<uint64_t>(schedule.lease) * 1000000; client->expiry = now + static_cast<uint64_t>(schedule.lease) * 1000000;
client->active = true; client->active = true;
if (schedule.flags & KVMFR_FRAME_SCHEDULE_IMMEDIATE) if (schedule.flags & FRAME_SCHEDULE_IMMEDIATE)
{ {
client->immediate = true; client->immediate = true;
wake = true; wake = true;
@@ -425,7 +425,7 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID,
wake |= ElectOwner(now, explicitReset ? schedule.clientID : 0); wake |= ElectOwner(now, explicitReset ? schedule.clientID : 0);
if (m_scheduling && client->clientID == m_schedule.clientID && if (m_scheduling && client->clientID == m_schedule.clientID &&
client->generation == m_schedule.generation && client->generation == m_schedule.generation &&
(schedule.flags & KVMFR_FRAME_SCHEDULE_IMMEDIATE)) (schedule.flags & FRAME_SCHEDULE_IMMEDIATE))
{ {
++m_forceRequestTicket; ++m_forceRequestTicket;
++m_republishRequestTicket; ++m_republishRequestTicket;
@@ -439,7 +439,7 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID,
} }
bool CFrameScheduler::ApplyFeedback(Client& client, bool CFrameScheduler::ApplyFeedback(Client& client,
const KVMFRFrameSchedule& schedule) const FrameScheduleUpdate& schedule)
{ {
if (!m_scheduling || client.clientID != m_schedule.clientID || if (!m_scheduling || client.clientID != m_schedule.clientID ||
schedule.generation != m_schedule.generation || schedule.generation != m_schedule.generation ||

View File

@@ -23,11 +23,7 @@
#include <Windows.h> #include <Windows.h>
#include <stdint.h> #include <stdint.h>
extern "C" { #include "transport/TransportTypes.h"
#include <lgmp/lgmp.h>
}
#include "common/KVMFR.h"
class CFrameScheduler class CFrameScheduler
{ {
@@ -79,15 +75,15 @@ private:
bool accepted; bool accepted;
}; };
static const unsigned PUBLICATION_HISTORY_SIZE = 128; static const unsigned PUBLICATION_HISTORY_SIZE = 128;
static const unsigned WORK_TIMING_HISTORY_SIZE = 32; static const unsigned WORK_TIMING_HISTORY_SIZE = 32;
mutable SRWLOCK m_lock = SRWLOCK_INIT; mutable SRWLOCK m_lock = SRWLOCK_INIT;
HANDLE m_wakeEvent = nullptr; HANDLE m_wakeEvent = nullptr;
Client m_clients[LGMP_MAX_CLIENTS] = {}; Client m_clients[TRANSPORT_MAX_CLIENTS] = {};
Schedule m_schedule = {}; Schedule m_schedule = {};
bool m_scheduling = false; bool m_scheduling = false;
uint32_t m_epoch = 0; uint32_t m_epoch = 0;
// A result acknowledges only the request tickets captured by its attempt. // A result acknowledges only the request tickets captured by its attempt.
uint64_t m_forceRequestTicket = 0; uint64_t m_forceRequestTicket = 0;
@@ -122,7 +118,7 @@ private:
Publication * FindPublication(const Schedule& schedule, Publication * FindPublication(const Schedule& schedule,
uint32_t frameSerial); uint32_t frameSerial);
bool ElectOwner(uint64_t now, uint32_t resetClientID = 0); 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 AdvanceCurrentDeadline();
void AdvanceDeadlineSerial(uint64_t count); void AdvanceDeadlineSerial(uint64_t count);
void AdvanceDeadline(uint64_t now); void AdvanceDeadline(uint64_t now);
@@ -139,7 +135,7 @@ public:
void UpdateSubscribers(const uint32_t * clientIDs, unsigned count, void UpdateSubscribers(const uint32_t * clientIDs, unsigned count,
const uint32_t * ownerClientIDs, unsigned ownerCount, uint64_t now); const uint32_t * ownerClientIDs, unsigned ownerCount, uint64_t now);
bool UpdateSchedule(uint32_t sourceClientID, bool UpdateSchedule(uint32_t sourceClientID,
const KVMFRFrameSchedule& schedule, uint64_t now); const FrameScheduleUpdate& schedule, uint64_t now);
bool GetSchedule(Schedule& schedule) const; bool GetSchedule(Schedule& schedule) const;
HANDLE GetWakeEvent() const { return m_wakeEvent; } HANDLE GetWakeEvent() const { return m_wakeEvent; }
void ObserveFrame(uint64_t now); void ObserveFrame(uint64_t now);

View File

@@ -22,19 +22,10 @@
#include <stdint.h> #include <stdint.h>
// 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 struct PreparedFrameBuffer
{ {
unsigned frameIndex; unsigned frameIndex;
uint8_t * mem; uint8_t * mem;
uint64_t heapOffset;
bool fullCopy; bool fullCopy;
}; };

View File

@@ -24,8 +24,9 @@
struct FrameMemoryLimits struct FrameMemoryLimits
{ {
uint64_t sharedSize = 0; uint64_t capacity = 0;
uint64_t frameMemoryOffset = 0; uint64_t frameMemoryOffset = 0;
uint64_t alignment = 0; uint64_t alignment = 0;
uint64_t maxFrameSize = 0; uint64_t maxFrameSize = 0;
unsigned bufferCount = 0;
}; };

View File

@@ -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 <Windows.h>
#include <wdf.h>
#include <IddCx.h>
#include <memory>
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<const D12ColorTransform> transform) = 0;
virtual std::shared_ptr<const D12ColorTransform>
GetColorTransform() const = 0;
};

View File

@@ -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 <Windows.h>
#include <stddef.h>
#include <stdint.h>
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;
};

View File

@@ -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 <stddef.h>
#include <stdint.h>
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;
};

View File

@@ -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 <new>
std::unique_ptr<ITransport> CreateTransport()
{
return std::unique_ptr<ITransport>(new (std::nothrow) CLGMPTransport());
}

View File

@@ -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 <memory>
std::unique_ptr<ITransport> CreateTransport();

View File

@@ -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 <stddef.h>
#include <stdint.h>
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;
}
};

View File

@@ -18,7 +18,7 @@
* Temple Place, Suite 330, Boston, MA 02111-1307 USA * Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "transport/CIVSHMEM.h" #include "transport/lgmp/CIVSHMEM.h"
#include <Windows.h> #include <Windows.h>
#include <SetupAPI.h> #include <SetupAPI.h>

View File

@@ -47,5 +47,5 @@ public:
void Close(); void Close();
size_t GetSize() const { return m_size; } size_t GetSize() const { return m_size; }
void * GetMem () { return m_mem; } void * GetMem () const { return m_mem; }
}; };

View File

@@ -18,7 +18,7 @@
* Temple Place, Suite 330, Boston, MA 02111-1307 USA * Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "transport/CLGMPControl.h" #include "transport/lgmp/CLGMPControl.h"
#include "CDebug.h" #include "CDebug.h"

View File

@@ -20,8 +20,8 @@
#pragma once #pragma once
#include "transport/CLGMPHost.h" #include "transport/lgmp/CLGMPHost.h"
#include "postprocess/D12FrameFormat.h" #include "transport/IControlTransport.h"
#include "common/KVMFR.h" #include "common/KVMFR.h"
@@ -31,9 +31,13 @@
#include <memory> #include <memory>
class CLGMPControl class CLGMPTransport;
class CLGMPControl final : public IControlTransport
{ {
private: private:
friend class CLGMPTransport;
static constexpr int POINTER_SHAPE_BUFFERS = 3; static constexpr int POINTER_SHAPE_BUFFERS = 3;
static constexpr int COLOR_TRANSFORM_BUFFERS = 3; static constexpr int COLOR_TRANSFORM_BUFFERS = 3;
@@ -56,27 +60,26 @@ private:
void SendColorTransform(); void SendColorTransform();
void ResendCursor(); void ResendCursor();
public:
explicit CLGMPControl(CLGMPHost& host) :
m_host(host) {}
~CLGMPControl();
CLGMPControl(const CLGMPControl&) = delete;
CLGMPControl& operator=(const CLGMPControl&) = delete;
bool Initialize(); bool Initialize();
void DeInit(); void DeInit();
LGMP_STATUS ReadDataWithSource(void * data, size_t * size, LGMP_STATUS ReadDataWithSource(void * data, size_t * size,
uint32_t * sourceClientID); uint32_t * sourceClientID);
LGMP_STATUS AckData(); LGMP_STATUS AckData();
bool HasNewSubscribers(); 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, void SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info, const BYTE * data,
UINT sdrWhiteLevel); UINT sdrWhiteLevel) override;
void SetColorTransform( void SetColorTransform(
std::shared_ptr<const D12ColorTransform> transform); std::shared_ptr<const D12ColorTransform> transform) override;
std::shared_ptr<const D12ColorTransform> GetColorTransform() const; std::shared_ptr<const D12ColorTransform>
void ResendState(); GetColorTransform() const override;
}; };

View File

@@ -18,14 +18,30 @@
* Temple Place, Suite 330, Boston, MA 02111-1307 USA * Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "transport/CFrameTransport.h" #include "transport/lgmp/CLGMPFrameTransport.h"
#include "transport/CIVSHMEM.h" #include "transport/lgmp/CIVSHMEM.h"
#include "transport/CLGMPHost.h" #include "transport/lgmp/CLGMPHost.h"
#include "CDebug.h" #include "CDebug.h"
#include <cstring> #include <cstring>
#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 = static const struct LGMPQueueConfig FRAME_QUEUE_CONFIG =
{ {
LGMP_Q_FRAME, // queueID LGMP_Q_FRAME, // queueID
@@ -49,19 +65,19 @@ static bool FrameScheduleMatches(
a.epoch == b.epoch; a.epoch == b.epoch;
} }
CFrameTransport::CFrameTransport( CLGMPFrameTransport::CLGMPFrameTransport(
CLGMPHost& host, CIVSHMEM& ivshmem) : CLGMPHost& host, CIVSHMEM& ivshmem) :
m_host(host), m_host(host),
m_ivshmem(ivshmem) m_ivshmem(ivshmem)
{ {
} }
CFrameTransport::~CFrameTransport() CLGMPFrameTransport::~CLGMPFrameTransport()
{ {
DeInit(); DeInit();
} }
bool CFrameTransport::Initialize() bool CLGMPFrameTransport::Initialize()
{ {
if (m_frameQueue) if (m_frameQueue)
{ {
@@ -100,13 +116,13 @@ bool CFrameTransport::Initialize()
return true; return true;
} }
void CFrameTransport::SealMemoryLayout() void CLGMPFrameTransport::SealMemoryLayout()
{ {
m_frameMemoryOffset = m_frameMemoryOffset =
m_ivshmem.GetSize() - m_host.Available(); 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 // This may get called multiple times as frame buffers cannot be allocated
// until the GPU-specific alignment is known. // until the GPU-specific alignment is known.
@@ -116,7 +132,7 @@ bool CFrameTransport::Setup(size_t alignSize)
m_alignSize = alignSize; m_alignSize = alignSize;
if (!m_alignSize || (m_alignSize & (m_alignSize - 1)) || 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", DEBUG_ERROR("Invalid frame buffer alignment: %llu",
(unsigned long long)m_alignSize); (unsigned long long)m_alignSize);
@@ -147,7 +163,7 @@ bool CFrameTransport::Setup(size_t alignSize)
return false; 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. // alignment unit. Only the bytes after it are usable for pixel data.
const size_t maxFrameSize = frameAllocationSize - m_alignSize; const size_t maxFrameSize = frameAllocationSize - m_alignSize;
DEBUG_INFO("Max Frame Data Size: %u MiB", 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 * Put the framebuffer on the border of the next page, this is to allow
* for aligned DMA transfers by the receiver. * 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_frame[i]->offset = (uint32_t)alignOffset;
m_frameBuffer[i] = reinterpret_cast<FrameBuffer *>( m_frameBuffer[i] = reinterpret_cast<LGMPBuffer *>(
reinterpret_cast<uint8_t *>(m_frame[i]) + alignOffset); reinterpret_cast<uint8_t *>(m_frame[i]) + alignOffset);
m_frameInFlight[i].store(false, std::memory_order_release); m_frameInFlight[i].store(false, std::memory_order_release);
m_frameCompleted[i] = false; m_frameCompleted[i] = false;
@@ -196,7 +212,7 @@ bool CFrameTransport::Setup(size_t alignSize)
return true; return true;
} }
void CFrameTransport::DeInit() void CLGMPFrameTransport::DeInit()
{ {
m_frameScheduler.Reset(); m_frameScheduler.Reset();
@@ -226,18 +242,19 @@ void CFrameTransport::DeInit()
memset(m_frameOwnerQueue, 0, sizeof(m_frameOwnerQueue)); memset(m_frameOwnerQueue, 0, sizeof(m_frameOwnerQueue));
} }
FrameMemoryLimits CFrameTransport::GetMemoryLimits() const FrameMemoryLimits CLGMPFrameTransport::GetMemoryLimits() const
{ {
FrameMemoryLimits limits; FrameMemoryLimits limits;
limits.sharedSize = m_ivshmem.GetSize(); limits.capacity = m_ivshmem.GetSize();
limits.frameMemoryOffset = m_frameMemoryOffset; limits.frameMemoryOffset = m_frameMemoryOffset;
limits.alignment = m_alignSize; limits.alignment = m_alignSize;
limits.maxFrameSize = m_maxFrameSize; limits.maxFrameSize = m_maxFrameSize;
limits.bufferCount = LGMP_Q_FRAME_BUFFER_LEN;
return limits; return limits;
} }
CFrameTransport::SubscriberSnapshot CLGMPFrameTransport::SubscriberSnapshot
CFrameTransport::SnapshotSubscribers() const CLGMPFrameTransport::SnapshotSubscribers() const
{ {
SubscriberSnapshot snapshot; SubscriberSnapshot snapshot;
snapshot.status = lgmpHostGetClientIDs( snapshot.status = lgmpHostGetClientIDs(
@@ -276,7 +293,7 @@ CFrameTransport::SnapshotSubscribers() const
return snapshot; return snapshot;
} }
void CFrameTransport::FinalizeSubscribers( void CLGMPFrameTransport::FinalizeSubscribers(
const SubscriberSnapshot& snapshot, uint64_t now) const SubscriberSnapshot& snapshot, uint64_t now)
{ {
if (snapshot.status == LGMP_OK) if (snapshot.status == LGMP_OK)
@@ -303,14 +320,14 @@ void CFrameTransport::FinalizeSubscribers(
ProcessFrameDeliveries(); ProcessFrameDeliveries();
} }
bool CFrameTransport::UpdateSchedule(uint32_t sourceClientID, bool CLGMPFrameTransport::UpdateSchedule(uint32_t sourceClientID,
const KVMFRFrameSchedule& schedule, uint64_t now) const FrameScheduleUpdate& schedule, uint64_t now)
{ {
return m_frameScheduler.UpdateSchedule(sourceClientID, schedule, now); return m_frameScheduler.UpdateSchedule(sourceClientID, schedule, now);
} }
CFrameTransport::SharedFramePostResult CLGMPFrameTransport::SharedFramePostResult
CFrameTransport::PostSharedFrame(unsigned frameIndex, CLGMPFrameTransport::PostSharedFrame(unsigned frameIndex,
uint32_t excludeClientID, uint64_t now) uint32_t excludeClientID, uint64_t now)
{ {
if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN || if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN ||
@@ -391,7 +408,7 @@ CFrameTransport::PostSharedFrame(unsigned frameIndex,
return SHARED_FRAME_POSTED; return SHARED_FRAME_POSTED;
} }
bool CFrameTransport::PostSharedOwnerFrame(unsigned frameIndex, bool CLGMPFrameTransport::PostSharedOwnerFrame(unsigned frameIndex,
const CFrameScheduler::Schedule& schedule) const CFrameScheduler::Schedule& schedule)
{ {
if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN || !schedule.clientID || if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN || !schedule.clientID ||
@@ -419,7 +436,7 @@ bool CFrameTransport::PostSharedOwnerFrame(unsigned frameIndex,
return true; return true;
} }
void CFrameTransport::ProcessFrameDeliveries() void CLGMPFrameTransport::ProcessFrameDeliveries()
{ {
if (!m_frameQueue) if (!m_frameQueue)
return; return;
@@ -471,7 +488,7 @@ void CFrameTransport::ProcessFrameDeliveries()
m_frameScheduler.NotifyPublisher(); m_frameScheduler.NotifyPublisher();
} }
int CFrameTransport::FindAvailableOwnerQueue( int CLGMPFrameTransport::FindAvailableOwnerQueue(
unsigned preferredIndex) const unsigned preferredIndex) const
{ {
for (unsigned i = 0; i < LGMP_Q_FRAME_LEN; ++i) for (unsigned i = 0; i < LGMP_Q_FRAME_LEN; ++i)
@@ -487,7 +504,7 @@ int CFrameTransport::FindAvailableOwnerQueue(
return -1; return -1;
} }
unsigned CFrameTransport::CountOwnerDeliveries( unsigned CLGMPFrameTransport::CountOwnerDeliveries(
uint32_t clientID) const uint32_t clientID) const
{ {
unsigned count = 0; unsigned count = 0;
@@ -503,7 +520,7 @@ unsigned CFrameTransport::CountOwnerDeliveries(
return count; return count;
} }
bool CFrameTransport::HasMatchingOwnerDelivery( bool CLGMPFrameTransport::HasMatchingOwnerDelivery(
uint32_t clientID, unsigned frameIndex, uint64_t token) const uint32_t clientID, unsigned frameIndex, uint64_t token) const
{ {
for (const OwnerDelivery& delivery : m_ownerDelivery) for (const OwnerDelivery& delivery : m_ownerDelivery)
@@ -526,7 +543,7 @@ bool CFrameTransport::HasMatchingOwnerDelivery(
return false; return false;
} }
bool CFrameTransport::FrameBufferReferenced( bool CLGMPFrameTransport::FrameBufferReferenced(
unsigned frameIndex) const unsigned frameIndex) const
{ {
if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN) if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN)
@@ -548,7 +565,7 @@ bool CFrameTransport::FrameBufferReferenced(
return false; return false;
} }
int CFrameTransport::FindAvailableFrameBuffer( int CLGMPFrameTransport::FindAvailableFrameBuffer(
bool allowReady) const bool allowReady) const
{ {
const LONG readyFrameIndex = const LONG readyFrameIndex =
@@ -582,7 +599,7 @@ int CFrameTransport::FindAvailableFrameBuffer(
return static_cast<int>(readyFrameIndex); return static_cast<int>(readyFrameIndex);
} }
int CFrameTransport::FindNewestCompletedFrame( int CLGMPFrameTransport::FindNewestCompletedFrame(
unsigned excludeFrameIndex) const unsigned excludeFrameIndex) const
{ {
int newestFrame = -1; int newestFrame = -1;
@@ -605,7 +622,7 @@ int CFrameTransport::FindNewestCompletedFrame(
return newestFrame; return newestFrame;
} }
bool CFrameTransport::FrameBufferAvailable( bool CLGMPFrameTransport::FrameBufferAvailable(
const CFrameScheduler::Schedule& schedule, const CFrameScheduler::Schedule& schedule,
bool allowReadyReplacement) bool allowReadyReplacement)
{ {
@@ -642,7 +659,7 @@ bool CFrameTransport::FrameBufferAvailable(
return available; return available;
} }
void CFrameTransport::ProcessFrameQueue() void CLGMPFrameTransport::ProcessDeliveries()
{ {
if (!m_host.IsInitialized()) if (!m_host.IsInitialized())
return; return;
@@ -656,7 +673,7 @@ void CFrameTransport::ProcessFrameQueue()
ProcessFrameDeliveries(); ProcessFrameDeliveries();
} }
bool CFrameTransport::GetSharedFrameTarget(uint64_t now, bool CLGMPFrameTransport::GetPendingDeliveryTarget(uint64_t now,
uint64_t& target) uint64_t& target)
{ {
if (!m_frameQueue) if (!m_frameQueue)
@@ -686,7 +703,7 @@ bool CFrameTransport::GetSharedFrameTarget(uint64_t now,
return result; return result;
} }
bool CFrameTransport::ReplaySharedFrame(uint64_t now, bool& retry) bool CLGMPFrameTransport::RetryPendingDelivery(uint64_t now, bool& retry)
{ {
retry = false; retry = false;
if (!m_frameQueue) if (!m_frameQueue)
@@ -710,7 +727,7 @@ bool CFrameTransport::ReplaySharedFrame(uint64_t now, bool& retry)
return result == SHARED_FRAME_POSTED; return result == SHARED_FRAME_POSTED;
} }
PreparedFrameBuffer CFrameTransport::PrepareFrameBuffer( PreparedFrameBuffer CLGMPFrameTransport::PrepareFrameBuffer(
unsigned pitch, const D12FrameFormat& srcFormat, unsigned pitch, const D12FrameFormat& srcFormat,
const D12FrameFormat& dstFormat, const RECT * dirtyRects, const D12FrameFormat& dstFormat, const RECT * dirtyRects,
unsigned nbDirtyRects, const CFrameScheduler::Schedule& schedule, 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; fb->wp = 0;
result.frameIndex = frameIndex; result.frameIndex = frameIndex;
result.mem = fb->data; result.mem = fb->data;
result.heapOffset = reinterpret_cast<uintptr_t>(fb->data) -
reinterpret_cast<uintptr_t>(m_ivshmem.GetMem());
result.fullCopy = fullCopy; result.fullCopy = fullCopy;
return result; return result;
} }
bool CFrameTransport::PublishFrameBuffer(unsigned frameIndex, bool CLGMPFrameTransport::PublishFrameBuffer(unsigned frameIndex,
const CFrameScheduler::Schedule& schedule, bool& deliveredToOwner) const CFrameScheduler::Schedule& schedule, bool& deliveredToOwner)
{ {
deliveredToOwner = false; deliveredToOwner = false;
@@ -1017,7 +1036,7 @@ bool CFrameTransport::PublishFrameBuffer(unsigned frameIndex,
return true; return true;
} }
bool CFrameTransport::RepublishFrameBuffer( bool CLGMPFrameTransport::RepublishFrameBuffer(
const CFrameScheduler::Schedule& schedule) const CFrameScheduler::Schedule& schedule)
{ {
if (!schedule.clientID) if (!schedule.clientID)
@@ -1118,7 +1137,7 @@ bool CFrameTransport::RepublishFrameBuffer(
return true; return true;
} }
void CFrameTransport::CommitFrameBuffer(unsigned frameIndex, void CLGMPFrameTransport::CommitFrameBuffer(unsigned frameIndex,
const CFrameScheduler::Schedule& schedule, bool periodic, const CFrameScheduler::Schedule& schedule, bool periodic,
bool deliveredToOwner) bool deliveredToOwner)
{ {
@@ -1133,7 +1152,7 @@ void CFrameTransport::CommitFrameBuffer(unsigned frameIndex,
m_frameScheduler.FrameRetained(schedule, now, periodic); m_frameScheduler.FrameRetained(schedule, now, periodic);
} }
bool CFrameTransport::TryFrameSubmitted(unsigned frameIndex, bool CLGMPFrameTransport::TryFrameSubmitted(unsigned frameIndex,
const CFrameScheduler::Schedule& schedule) const CFrameScheduler::Schedule& schedule)
{ {
if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN) if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN)
@@ -1143,17 +1162,17 @@ bool CFrameTransport::TryFrameSubmitted(unsigned frameIndex,
schedule, m_frame[frameIndex]->frameSerial); schedule, m_frame[frameIndex]->frameSerial);
} }
void CFrameTransport::ObserveFrame(uint64_t now) void CLGMPFrameTransport::ObserveFrame(uint64_t now)
{ {
m_frameScheduler.ObserveFrame(now); m_frameScheduler.ObserveFrame(now);
} }
void CFrameTransport::ForceFrame() void CLGMPFrameTransport::ForceFrame()
{ {
m_frameScheduler.ForceFrame(); m_frameScheduler.ForceFrame();
} }
bool CFrameTransport::GetPublishTarget(uint64_t now, bool CLGMPFrameTransport::GetPublishTarget(uint64_t now,
uint64_t& target, CFrameScheduler::Schedule& schedule, bool& periodic, uint64_t& target, CFrameScheduler::Schedule& schedule, bool& periodic,
bool& republish) bool& republish)
{ {
@@ -1161,23 +1180,23 @@ bool CFrameTransport::GetPublishTarget(uint64_t now,
now, target, schedule, periodic, republish); now, target, schedule, periodic, republish);
} }
void CFrameTransport::FrameMissed( void CLGMPFrameTransport::FrameMissed(
const CFrameScheduler::Schedule& schedule, uint64_t now, bool periodic) const CFrameScheduler::Schedule& schedule, uint64_t now, bool periodic)
{ {
m_frameScheduler.FrameMissed(schedule, now, periodic); m_frameScheduler.FrameMissed(schedule, now, periodic);
} }
void CFrameTransport::FrameSuperseded() void CLGMPFrameTransport::FrameSuperseded()
{ {
m_frameScheduler.FrameSuperseded(); m_frameScheduler.FrameSuperseded();
} }
void CFrameTransport::TryRecordFrameTiming(uint64_t duration) void CLGMPFrameTransport::TryRecordFrameTiming(uint64_t duration)
{ {
m_frameScheduler.TryRecordFrameTiming(duration); m_frameScheduler.TryRecordFrameTiming(duration);
} }
void CFrameTransport::AbortFrameBuffer(unsigned frameIndex) void CLGMPFrameTransport::AbortFrameBuffer(unsigned frameIndex)
{ {
if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN) if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN)
return; return;
@@ -1193,7 +1212,7 @@ void CFrameTransport::AbortFrameBuffer(unsigned frameIndex)
ReleaseSRWLockExclusive(&m_framePublishLock); ReleaseSRWLockExclusive(&m_framePublishLock);
} }
void CFrameTransport::FailFrameBuffer(unsigned frameIndex) void CLGMPFrameTransport::FailFrameBuffer(unsigned frameIndex)
{ {
if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN) if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN)
return; return;
@@ -1204,7 +1223,7 @@ void CFrameTransport::FailFrameBuffer(unsigned frameIndex)
CompleteFrameBuffer(frameIndex, false); CompleteFrameBuffer(frameIndex, false);
} }
void CFrameTransport::CompleteFrameBuffer( void CLGMPFrameTransport::CompleteFrameBuffer(
unsigned frameIndex, bool succeeded) unsigned frameIndex, bool succeeded)
{ {
if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN) if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN)
@@ -1232,7 +1251,7 @@ void CFrameTransport::CompleteFrameBuffer(
ReleaseSRWLockExclusive(&m_framePublishLock); ReleaseSRWLockExclusive(&m_framePublishLock);
} }
void CFrameTransport::SetFrameTiming(unsigned frameIndex, void CLGMPFrameTransport::SetFrameTiming(unsigned frameIndex,
uint64_t captureTime, uint64_t postProcessTime, uint64_t copyTime, uint64_t captureTime, uint64_t postProcessTime, uint64_t copyTime,
uint64_t readyTime, uint64_t holdTime, uint64_t readyTime, uint64_t holdTime,
const CFrameScheduler::Schedule& schedule, uint64_t completedAt) const CFrameScheduler::Schedule& schedule, uint64_t completedAt)
@@ -1257,10 +1276,10 @@ void CFrameTransport::SetFrameTiming(unsigned frameIndex,
InterlockedExchange((volatile LONG *)&frame->timingValid, 1); 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 size_t offset, size_t len, bool setWritePos) const
{ {
FrameBuffer * fb = m_frameBuffer[frameIndex]; LGMPBuffer * fb = m_frameBuffer[frameIndex];
memcpy( memcpy(
reinterpret_cast<void *>( reinterpret_cast<void *>(
@@ -1273,11 +1292,11 @@ void CFrameTransport::WriteFrameBuffer(unsigned frameIndex, void * src,
fb->wp = (uint32_t)(offset + len); 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, void * src, size_t offset, size_t rowBytes, size_t pitch,
unsigned rows) const unsigned rows) const
{ {
FrameBuffer * fb = m_frameBuffer[frameIndex]; LGMPBuffer * fb = m_frameBuffer[frameIndex];
uint8_t * dst = fb->data + offset; uint8_t * dst = fb->data + offset;
uint8_t * source = static_cast<uint8_t *>(src) + offset; uint8_t * source = static_cast<uint8_t *>(src) + offset;
for (unsigned row = 0; row < rows; ++row) 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]; const KVMFRFrame * frame = m_frame[frameIndex];
FrameBuffer * fb = m_frameBuffer[frameIndex]; LGMPBuffer * fb = m_frameBuffer[frameIndex];
fb->wp = frame->dataHeight * frame->pitch; fb->wp = frame->dataHeight * frame->pitch;
} }

View File

@@ -28,18 +28,21 @@ extern "C" {
#include "lgmp/host.h" #include "lgmp/host.h"
} }
#include "capture/CFrameScheduler.h"
#include "capture/FrameBufferTypes.h"
#include "common/KVMFR.h" #include "common/KVMFR.h"
#include "postprocess/D12FrameFormat.h" #include "transport/CFrameScheduler.h"
#include "transport/FrameMemoryLimits.h" #include "transport/FrameMemoryLimits.h"
#include "transport/IFrameTransport.h"
class CIVSHMEM; class CIVSHMEM;
class CLGMPHost; class CLGMPHost;
class CLGMPTransport;
struct LGMPBuffer;
class CFrameTransport class CLGMPFrameTransport final : public IFrameTransport
{ {
public: private:
friend class CLGMPTransport;
struct SubscriberSnapshot struct SubscriberSnapshot
{ {
uint32_t clientIDs [LGMP_MAX_CLIENTS] = {}; uint32_t clientIDs [LGMP_MAX_CLIENTS] = {};
@@ -103,7 +106,7 @@ private:
uint32_t m_frameSerial = 0; uint32_t m_frameSerial = 0;
PLGMPMemory m_frameMemory[LGMP_Q_FRAME_BUFFER_LEN] = {}; PLGMPMemory m_frameMemory[LGMP_Q_FRAME_BUFFER_LEN] = {};
KVMFRFrame * m_frame [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_width = 0;
unsigned m_height = 0; unsigned m_height = 0;
@@ -136,74 +139,77 @@ private:
uint32_t excludeClientID, uint64_t now); uint32_t excludeClientID, uint64_t now);
bool PostSharedOwnerFrame(unsigned frameIndex, bool PostSharedOwnerFrame(unsigned frameIndex,
const CFrameScheduler::Schedule& schedule); const CFrameScheduler::Schedule& schedule);
CLGMPFrameTransport(CLGMPHost& host, CIVSHMEM& ivshmem);
public:
CFrameTransport(CLGMPHost& host, CIVSHMEM& ivshmem);
~CFrameTransport();
CFrameTransport(const CFrameTransport&) = delete;
CFrameTransport& operator=(const CFrameTransport&) = delete;
bool Initialize(); bool Initialize();
void SealMemoryLayout(); void SealMemoryLayout();
bool Setup(size_t alignSize); bool Setup(size_t alignSize);
void DeInit(); void DeInit();
FrameMemoryLimits GetMemoryLimits() const; FrameMemoryLimits GetMemoryLimits() const;
size_t GetMaxFrameSize() const { return m_maxFrameSize; }
CIVSHMEM& GetIVSHMEM() { return m_ivshmem; }
SubscriberSnapshot SnapshotSubscribers() const; SubscriberSnapshot SnapshotSubscribers() const;
void FinalizeSubscribers( void FinalizeSubscribers(
const SubscriberSnapshot& snapshot, uint64_t now); const SubscriberSnapshot& snapshot, uint64_t now);
bool UpdateSchedule(uint32_t sourceClientID, 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 FrameBufferAvailable(const CFrameScheduler::Schedule& schedule,
bool allowReadyReplacement = true); bool allowReadyReplacement = true) override;
bool HasPublishedFrame() const bool HasPublishedFrame() const override
{ {
return m_readyFrameIndex.load(std::memory_order_acquire) >= 0; return m_readyFrameIndex.load(std::memory_order_acquire) >= 0;
} }
void ProcessFrameQueue(); void ProcessDeliveries() override;
bool GetSharedFrameTarget(uint64_t now, uint64_t& target); bool GetPendingDeliveryTarget(
bool ReplaySharedFrame(uint64_t now, bool& retry); uint64_t now, uint64_t& target) override;
bool RetryPendingDelivery(uint64_t now, bool& retry) override;
PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch, PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch,
const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat, const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat,
const RECT * dirtyRects, unsigned nbDirtyRects, const RECT * dirtyRects, unsigned nbDirtyRects,
const CFrameScheduler::Schedule& schedule, const CFrameScheduler::Schedule& schedule,
bool allowReadyReplacement = true); bool allowReadyReplacement = true) override;
bool PublishFrameBuffer(unsigned frameIndex, bool PublishFrameBuffer(unsigned frameIndex,
const CFrameScheduler::Schedule& schedule, bool& deliveredToOwner); const CFrameScheduler::Schedule& schedule,
bool RepublishFrameBuffer(const CFrameScheduler::Schedule& schedule); bool& deliveredToOwner) override;
bool RepublishFrameBuffer(
const CFrameScheduler::Schedule& schedule) override;
bool TryFrameSubmitted(unsigned frameIndex, bool TryFrameSubmitted(unsigned frameIndex,
const CFrameScheduler::Schedule& schedule); const CFrameScheduler::Schedule& schedule) override;
void CommitFrameBuffer(unsigned frameIndex, void CommitFrameBuffer(unsigned frameIndex,
const CFrameScheduler::Schedule& schedule, bool periodic, const CFrameScheduler::Schedule& schedule, bool periodic,
bool deliveredToOwner); bool deliveredToOwner) override;
void AbortFrameBuffer(unsigned frameIndex); void AbortFrameBuffer(unsigned frameIndex) override;
void FailFrameBuffer(unsigned frameIndex); void FailFrameBuffer(unsigned frameIndex) override;
void CompleteFrameBuffer(unsigned frameIndex, bool succeeded); void CompleteFrameBuffer(
unsigned frameIndex, bool succeeded) override;
void SetFrameTiming(unsigned frameIndex, uint64_t captureTime, void SetFrameTiming(unsigned frameIndex, uint64_t captureTime,
uint64_t postProcessTime, uint64_t copyTime, uint64_t readyTime, uint64_t postProcessTime, uint64_t copyTime, uint64_t readyTime,
uint64_t holdTime, const CFrameScheduler::Schedule& schedule, uint64_t holdTime, const CFrameScheduler::Schedule& schedule,
uint64_t completedAt); uint64_t completedAt) override;
void WriteFrameBuffer(unsigned frameIndex, void * src, size_t offset, 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, void WriteFrameBufferRows(unsigned frameIndex, void * src,
size_t offset, size_t rowBytes, size_t pitch, unsigned rows) const; size_t offset, size_t rowBytes, size_t pitch,
void FinalizeFrameBuffer(unsigned frameIndex) const; unsigned rows) const override;
void FinalizeFrameBuffer(unsigned frameIndex) const override;
void ObserveFrame(uint64_t now); void ObserveFrame(uint64_t now) override;
void ForceFrame(); void ForceFrame() override;
bool GetPublishTarget(uint64_t now, uint64_t& target, 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, void FrameMissed(const CFrameScheduler::Schedule& schedule,
uint64_t now, bool periodic); uint64_t now, bool periodic) override;
void FrameSuperseded(); void FrameSuperseded() override;
HANDLE GetFrameScheduleEvent() const HANDLE GetFrameScheduleEvent() const override
{ {
return m_frameScheduler.GetWakeEvent(); return m_frameScheduler.GetWakeEvent();
} }
void TryRecordFrameTiming(uint64_t duration); void TryRecordFrameTiming(uint64_t duration) override;
}; };

View File

@@ -18,9 +18,9 @@
* Temple Place, Suite 330, Boston, MA 02111-1307 USA * 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 "platform/CPlatformInfo.h"
#include "CDebug.h" #include "CDebug.h"
#include "VersionInfo.h" #include "VersionInfo.h"

View File

@@ -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<KVMFRMessage *>(data);
switch (msg->type)
{
case KVMFR_MESSAGE_SETCURSORPOS:
{
KVMFRSetCursorPos * position =
reinterpret_cast<KVMFRSetCursorPos *>(msg);
events.OnSetCursorPos(position->x, position->y);
break;
}
case KVMFR_MESSAGE_WINDOWSIZE:
{
KVMFRWindowSize * window =
reinterpret_cast<KVMFRWindowSize *>(msg);
events.OnSetResolution(window->w, window->h);
break;
}
case KVMFR_MESSAGE_FRAME_SCHEDULE:
{
const KVMFRFrameSchedule * schedule =
reinterpret_cast<KVMFRFrameSchedule *>(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()};
}

View File

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