diff --git a/idd/LGIdd/Device.cpp b/idd/LGIdd/Device.cpp index 0fe9b230..e5d6ee4a 100644 --- a/idd/LGIdd/Device.cpp +++ b/idd/LGIdd/Device.cpp @@ -34,10 +34,10 @@ #include "CDebug.h" #include "display/CDisplayConfiguration.h" #include "display/IddCxCompat.h" -#include "display/device/CDeviceContext.h" -#include "display/monitor/Context.h" +#include "display/CDeviceContext.h" +#include "display/CMonitorContext.h" #include "transport/IControlTransport.h" -#include "transport/CPipeServer.h" +#include "ipc/CPipeServer.h" #include "config/CSettings.h" WDFDEVICE l_wdfDevice = nullptr; diff --git a/idd/LGIdd/Driver.cpp b/idd/LGIdd/Driver.cpp index 47ea777d..c6dc8e9d 100644 --- a/idd/LGIdd/Driver.cpp +++ b/idd/LGIdd/Driver.cpp @@ -24,7 +24,7 @@ #include "CDebug.h" #include "platform/CPlatformInfo.h" #include "VersionInfo.h" -#include "transport/CPipeServer.h" +#include "ipc/CPipeServer.h" NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { diff --git a/idd/LGIdd/LGIdd.vcxproj b/idd/LGIdd/LGIdd.vcxproj index dbec06b7..eb0c3bc5 100644 --- a/idd/LGIdd/LGIdd.vcxproj +++ b/idd/LGIdd/LGIdd.vcxproj @@ -27,20 +27,20 @@ + - - + + + - - @@ -52,8 +52,6 @@ - - @@ -69,16 +67,19 @@ + - - + + + + @@ -94,15 +95,13 @@ - - - + + - diff --git a/idd/LGIdd/LGIdd.vcxproj.filters b/idd/LGIdd/LGIdd.vcxproj.filters index e9fe9002..8c7e3b6f 100644 --- a/idd/LGIdd/LGIdd.vcxproj.filters +++ b/idd/LGIdd/LGIdd.vcxproj.filters @@ -5,15 +5,12 @@ {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + + {6A9D97A5-1A6C-4A95-A2D0-A7C2D6BE459D} + {D2C16E51-6087-4E08-8DA4-5AD1A60EF58E} - - {83AAC4D0-9E4C-4B25-BD54-9186713B2010} - - - {3AF4227D-EBC0-45FB-9670-192E371313D5} - {202B79B2-5CCF-4AD4-B4C5-F5602419683D} @@ -70,6 +67,9 @@ Driver + + IPC + Display @@ -82,11 +82,11 @@ Display - - Display\Device + + Display - - Display\Monitor + + Display Capture @@ -100,6 +100,12 @@ Capture + + Capture + + + Capture + Capture @@ -145,13 +151,7 @@ Post-processing\Effects - - Transport - - - Transport - - + Transport @@ -166,10 +166,10 @@ Transport - + Transport - + Transport @@ -207,6 +207,9 @@ Driver + + IPC + Display @@ -216,11 +219,11 @@ Display - - Display\Device + + Display - - Display\Monitor + + Display Capture @@ -234,21 +237,18 @@ Capture + + Capture + Capture Capture - - Capture - Capture - - Capture - D3D @@ -282,12 +282,6 @@ Post-processing\Effects - - Transport - - - Transport - Transport diff --git a/idd/LGIdd/capture/CFrameBufferPool.h b/idd/LGIdd/capture/CFrameBufferPool.h index c34a333c..dc7bc7fb 100644 --- a/idd/LGIdd/capture/CFrameBufferPool.h +++ b/idd/LGIdd/capture/CFrameBufferPool.h @@ -21,8 +21,8 @@ #pragma once #include "capture/CFrameBufferResource.h" -#include "transport/FrameBufferTypes.h" -#include "transport/TransportTypes.h" +#include "capture/FramePipeline.h" +#include "transport/PreparedFrameBuffer.h" struct CD3D12Device; class IFrameTransport; @@ -33,7 +33,7 @@ private: IFrameTransport * m_transport = nullptr; CD3D12Device * m_dx12 = nullptr; - CFrameBufferResource m_buffers[TRANSPORT_FRAME_BUFFER_COUNT]; + CFrameBufferResource m_buffers[CAPTURE_FRAME_BUFFERS]; public: void Init(IFrameTransport * transport, CD3D12Device * dx12); diff --git a/idd/LGIdd/capture/CFrameBufferResource.h b/idd/LGIdd/capture/CFrameBufferResource.h index 1cf27bb3..8863cad1 100644 --- a/idd/LGIdd/capture/CFrameBufferResource.h +++ b/idd/LGIdd/capture/CFrameBufferResource.h @@ -27,7 +27,7 @@ #include #include -#include "transport/CFrameScheduler.h" +#include "capture/CFrameScheduler.h" #include "d3d/CInteropResource.h" struct CD3D12Device; diff --git a/idd/LGIdd/capture/CFrameProcessor.cpp b/idd/LGIdd/capture/CFrameProcessor.cpp index ac4a34b4..bbce75f5 100644 --- a/idd/LGIdd/capture/CFrameProcessor.cpp +++ b/idd/LGIdd/capture/CFrameProcessor.cpp @@ -29,7 +29,7 @@ CFrameProcessor::CFrameProcessor(IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], + CPostProcessor postProcessors[CAPTURE_PIPELINE_SLOTS], SRWLOCK * pipelineLock, HANDLE terminateEvent) : m_transport(transport), m_dx12(std::move(dx12)), @@ -156,7 +156,7 @@ void CFrameProcessor::GetPreviousDamage( std::unique_ptr CreateFrameProcessor( bool software, IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], + CPostProcessor postProcessors[CAPTURE_PIPELINE_SLOTS], SRWLOCK * pipelineLock, HANDLE terminateEvent) { std::unique_ptr processor; diff --git a/idd/LGIdd/capture/CFrameProcessor.h b/idd/LGIdd/capture/CFrameProcessor.h index 46e92960..eb8afd40 100644 --- a/idd/LGIdd/capture/CFrameProcessor.h +++ b/idd/LGIdd/capture/CFrameProcessor.h @@ -24,8 +24,8 @@ #include "capture/CFrameBufferPool.h" #include "d3d/CInteropResource.h" #include "postprocess/CPostProcessor.h" -#include "transport/CFrameScheduler.h" -#include "transport/TransportTypes.h" +#include "capture/CFrameScheduler.h" +#include "capture/FramePipeline.h" #include #include @@ -76,7 +76,7 @@ protected: public: CFrameProcessor(IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], + CPostProcessor postProcessors[CAPTURE_PIPELINE_SLOTS], SRWLOCK * pipelineLock, HANDLE terminateEvent); virtual ~CFrameProcessor() = default; @@ -98,5 +98,5 @@ public: std::unique_ptr CreateFrameProcessor( bool software, IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], + CPostProcessor postProcessors[CAPTURE_PIPELINE_SLOTS], SRWLOCK * pipelineLock, HANDLE terminateEvent); diff --git a/idd/LGIdd/transport/CFrameScheduler.cpp b/idd/LGIdd/capture/CFrameScheduler.cpp similarity index 99% rename from idd/LGIdd/transport/CFrameScheduler.cpp rename to idd/LGIdd/capture/CFrameScheduler.cpp index c13aa54c..b3c409fb 100644 --- a/idd/LGIdd/transport/CFrameScheduler.cpp +++ b/idd/LGIdd/capture/CFrameScheduler.cpp @@ -18,7 +18,7 @@ * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "transport/CFrameScheduler.h" +#include "capture/CFrameScheduler.h" #include "CDebug.h" @@ -288,10 +288,10 @@ void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs, { AcquireSRWLockExclusive(&m_lock); - uint32_t oldClientIDs [TRANSPORT_MAX_CLIENTS] = {}; - bool wasSubscribed [TRANSPORT_MAX_CLIENTS] = {}; - bool wasOwnerCapable[TRANSPORT_MAX_CLIENTS] = {}; - unsigned clientIndex = 0; + uint32_t oldClientIDs [MAX_CLIENTS] = {}; + bool wasSubscribed [MAX_CLIENTS] = {}; + bool wasOwnerCapable[MAX_CLIENTS] = {}; + unsigned clientIndex = 0; for (const Client& client : m_clients) { oldClientIDs[clientIndex] = client.clientID; diff --git a/idd/LGIdd/transport/CFrameScheduler.h b/idd/LGIdd/capture/CFrameScheduler.h similarity index 87% rename from idd/LGIdd/transport/CFrameScheduler.h rename to idd/LGIdd/capture/CFrameScheduler.h index ef90392b..cd3dce4d 100644 --- a/idd/LGIdd/transport/CFrameScheduler.h +++ b/idd/LGIdd/capture/CFrameScheduler.h @@ -23,11 +23,33 @@ #include #include -#include "transport/TransportTypes.h" +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; +}; class CFrameScheduler { public: + static const unsigned MAX_CLIENTS = 8; + struct Schedule { uint32_t clientID; @@ -78,12 +100,12 @@ private: static const unsigned PUBLICATION_HISTORY_SIZE = 128; static const unsigned WORK_TIMING_HISTORY_SIZE = 32; - mutable SRWLOCK m_lock = SRWLOCK_INIT; - HANDLE m_wakeEvent = nullptr; - Client m_clients[TRANSPORT_MAX_CLIENTS] = {}; - Schedule m_schedule = {}; - bool m_scheduling = false; - uint32_t m_epoch = 0; + mutable SRWLOCK m_lock = SRWLOCK_INIT; + HANDLE m_wakeEvent = nullptr; + Client m_clients[MAX_CLIENTS] = {}; + Schedule m_schedule = {}; + bool m_scheduling = false; + uint32_t m_epoch = 0; // A result acknowledges only the request tickets captured by its attempt. uint64_t m_forceRequestTicket = 0; diff --git a/idd/LGIdd/capture/CHardwareFrameProcessor.cpp b/idd/LGIdd/capture/CHardwareFrameProcessor.cpp index a94512ad..bcad171e 100644 --- a/idd/LGIdd/capture/CHardwareFrameProcessor.cpp +++ b/idd/LGIdd/capture/CHardwareFrameProcessor.cpp @@ -29,7 +29,7 @@ using namespace Microsoft::WRL; -static_assert(TRANSPORT_FRAME_QUEUE_LENGTH == 2, +static_assert(CAPTURE_PIPELINE_SLOTS == 2, "IDD candidate pipeline assumes two slots"); class CPublishPending @@ -72,7 +72,7 @@ public: CHardwareFrameProcessor::CHardwareFrameProcessor( IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], + CPostProcessor postProcessors[CAPTURE_PIPELINE_SLOTS], SRWLOCK * pipelineLock, HANDLE terminateEvent) : CFrameProcessor(transport, std::move(dx12), postProcessors, pipelineLock, terminateEvent) diff --git a/idd/LGIdd/capture/CHardwareFrameProcessor.h b/idd/LGIdd/capture/CHardwareFrameProcessor.h index 6136f828..025a2b28 100644 --- a/idd/LGIdd/capture/CHardwareFrameProcessor.h +++ b/idd/LGIdd/capture/CHardwareFrameProcessor.h @@ -65,8 +65,8 @@ private: bool active = false; }; - FrameCandidate m_candidates[TRANSPORT_FRAME_QUEUE_LENGTH]; - CandidateDamageTail m_candidateDamageTail[TRANSPORT_FRAME_QUEUE_LENGTH]; + FrameCandidate m_candidates[CAPTURE_PIPELINE_SLOTS]; + CandidateDamageTail m_candidateDamageTail[CAPTURE_PIPELINE_SLOTS]; mutable SRWLOCK m_candidateLock = SRWLOCK_INIT; SRWLOCK m_copySubmitLock = SRWLOCK_INIT; uint64_t m_candidateSequence = 0; @@ -91,7 +91,7 @@ private: public: CHardwareFrameProcessor(IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], + CPostProcessor postProcessors[CAPTURE_PIPELINE_SLOTS], SRWLOCK * pipelineLock, HANDLE terminateEvent); bool IsValid() const override; diff --git a/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp b/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp index fba9b60d..1153a644 100644 --- a/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp +++ b/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp @@ -20,7 +20,7 @@ #include "capture/CSoftwareFrameProcessor.h" #include "capture/CFrameProcessorUtil.h" -#include "transport/TransportTypes.h" +#include "capture/FramePipeline.h" #include "transport/IFrameTransport.h" #include "util/CSRWLock.h" #include "CDebug.h" @@ -29,7 +29,7 @@ CSoftwareFrameProcessor::CSoftwareFrameProcessor( IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], + CPostProcessor postProcessors[CAPTURE_PIPELINE_SLOTS], SRWLOCK * pipelineLock, HANDLE terminateEvent) : CFrameProcessor(transport, std::move(dx12), postProcessors, pipelineLock, terminateEvent), diff --git a/idd/LGIdd/capture/CSoftwareFrameProcessor.h b/idd/LGIdd/capture/CSoftwareFrameProcessor.h index 59d53e76..85aa48fb 100644 --- a/idd/LGIdd/capture/CSoftwareFrameProcessor.h +++ b/idd/LGIdd/capture/CSoftwareFrameProcessor.h @@ -33,7 +33,7 @@ private: public: CSoftwareFrameProcessor(IFrameTransport * transport, std::shared_ptr dx12, - CPostProcessor postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH], + CPostProcessor postProcessors[CAPTURE_PIPELINE_SLOTS], SRWLOCK * pipelineLock, HANDLE terminateEvent); bool Submit(const FrameSubmission& submission) override; diff --git a/idd/LGIdd/capture/CSwapChainCursor.cpp b/idd/LGIdd/capture/CSwapChainCursor.cpp deleted file mode 100644 index 67194e49..00000000 --- a/idd/LGIdd/capture/CSwapChainCursor.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/** - * 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 "capture/CSwapChainProcessor.h" - -#include "display/IddCxCompat.h" -#include "display/device/CDeviceContext.h" -#include "transport/IControlTransport.h" - -#include "CDebug.h" - -DWORD CALLBACK CSwapChainProcessor::_CursorThread(LPVOID arg) -{ - reinterpret_cast(arg)->CursorThread(); - return 0; -} - -bool CSwapChainProcessor::QueryHWCursor() -{ - IDARG_IN_QUERY_HWCURSOR in = {}; - in.LastShapeId = m_lastShapeId; - in.pShapeBuffer = m_shapeBuffer; - in.ShapeBufferSizeInBytes = 512 * 512 * 4; - - IDARG_OUT_QUERY_HWCURSOR out = {}; - UINT cursorWhiteLevel = m_sdrWhiteLevel.load(std::memory_order_relaxed); - NTSTATUS status; -#ifdef HAS_IDDCX_110 - if (m_devContext->HasIddCx110DDIs()) - { - IDARG_OUT_QUERY_HWCURSOR3 out3 = {}; - status = IddCxMonitorQueryHardwareCursor3(m_monitor, &in, &out3); - out.IsCursorVisible = out3.IsCursorVisible; - out.X = out3.X; - out.Y = out3.Y; - out.IsCursorShapeUpdated = out3.IsCursorShapeUpdated; - out.CursorShapeInfo = out3.CursorShapeInfo; - if (out3.SdrWhiteLevel) - cursorWhiteLevel = out3.SdrWhiteLevel; - } - else -#endif - { - status = IddCxMonitorQueryHardwareCursor(m_monitor, &in, &out); - } - - if (FAILED(status)) - { - // this occurs if the display went away (ie, screen blanking or disabled) - if (status == STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY) - { - SetEvent(m_terminateEvent.Get()); - return false; - } - - DEBUG_ERROR("IddCxMonitorQueryHardwareCursor failed (0x%08x)", status); - return false; - } - - if (out.IsCursorShapeUpdated) - m_lastShapeId = out.CursorShapeInfo.ShapeId; - - m_control.SendCursor(out, m_shapeBuffer, cursorWhiteLevel); - return true; -} - -void CSwapChainProcessor::CursorThread() -{ - HRESULT hr = 0; - bool running = true; - - while (running) - { - HANDLE waitHandles[] = - { - m_cursorDataEvent.Get(), - m_terminateEvent.Get() - }; - - DWORD waitResult = WaitForMultipleObjects( - ARRAYSIZE(waitHandles), waitHandles, FALSE, 100); - - switch (waitResult) - { - case WAIT_TIMEOUT: - continue; - - // cursorDataEvent - case WAIT_OBJECT_0: - if (!QueryHWCursor()) - return; - continue; - - // terminateEvent - case WAIT_OBJECT_0 + 1: - running = false; - continue; - - default: - hr = HRESULT_FROM_WIN32(waitResult); - DEBUG_ERROR_HR(hr, "WaitForMultipleObjects"); - return; - } - } -} diff --git a/idd/LGIdd/capture/CSwapChainProcessor.cpp b/idd/LGIdd/capture/CSwapChainProcessor.cpp index e559fd10..2d6010b2 100644 --- a/idd/LGIdd/capture/CSwapChainProcessor.cpp +++ b/idd/LGIdd/capture/CSwapChainProcessor.cpp @@ -21,8 +21,8 @@ #include "capture/CSwapChainProcessor.h" #include "capture/CFrameProcessorUtil.h" #include "display/IddCxCompat.h" -#include "display/device/CDeviceContext.h" -#include "display/monitor/Context.h" +#include "display/CDeviceContext.h" +#include "display/CMonitorContext.h" #include "platform/CPlatformInfo.h" #include "transport/IFrameTransport.h" #include "transport/IControlTransport.h" @@ -31,7 +31,7 @@ #include #include #include "CDebug.h" -#include "transport/CPipeServer.h" +#include "ipc/CPipeServer.h" #ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 @@ -737,3 +737,340 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr acquiredBuffer }; return m_frameProcessor->Submit(submission); } + +static const uint64_t PUBLISH_RETRY_NS = 1000000ULL; + +static bool ArmPublishTimer(HANDLE timer, uint64_t delay) +{ + if (!timer) + return false; + + LARGE_INTEGER due = {}; + due.QuadPart = -static_cast((delay + 99) / 100); + if (!due.QuadPart) + due.QuadPart = -1; + return SetWaitableTimer(timer, &due, 0, nullptr, nullptr, FALSE) != FALSE; +} + +DWORD CALLBACK CSwapChainProcessor::_PublisherThread(LPVOID arg) +{ + reinterpret_cast(arg)->PublisherThread(); + return 0; +} + +void CSwapChainProcessor::PublisherThread() +{ + DWORD avTask = 0; + HANDLE avTaskHandle = AvSetMmThreadCharacteristicsW(L"Distribution", &avTask); + if (avTaskHandle && + !AvSetMmThreadPriority(avTaskHandle, AVRT_PRIORITY_HIGH)) + DEBUG_WARN("Failed to raise publisher MMCSS priority: %lu", + GetLastError()); + + const HANDLE scheduleEvent = m_transport.GetFrameScheduleEvent(); + HANDLE idleHandles[] = + { + m_terminateEvent.Get(), + m_frameProcessor->GetReadyEvent(), + scheduleEvent, + }; + HANDLE timerHandles[] = + { + m_terminateEvent.Get(), + m_frameProcessor->GetReadyEvent(), + scheduleEvent, + m_publishTimer.Get(), + }; + const bool cadenceEnabled = m_frameProcessor->UsesCadence(); + + for (;;) + { + const uint64_t now = CFrameScheduler::Nanotime(); + uint64_t target; + CFrameScheduler::Schedule schedule; + bool periodic; + bool republish; + m_transport.GetPublishTarget( + now, target, schedule, periodic, republish); + + const bool ready = m_frameProcessor->HasReadyFrame(); + if (!ready) + { + m_transport.ProcessDeliveries(); + if (m_frameProcessor->HasReadyFrame()) + continue; + + uint64_t current = CFrameScheduler::Nanotime(); + uint64_t cadenceTarget = 0; + if (cadenceEnabled && schedule.deliveryDeadlineSerial && periodic) + { + if (schedule.deadline <= current) + { + m_transport.FrameMissed(schedule, current, periodic); + continue; + } + cadenceTarget = schedule.deadline; + } + + if (republish && m_transport.HasPublishedFrame()) + { + if (m_transport.RepublishFrameBuffer(schedule)) + continue; + + current = CFrameScheduler::Nanotime(); + if (cadenceTarget && cadenceTarget <= current) + { + m_transport.FrameMissed(schedule, current, periodic); + continue; + } + + uint64_t retryTarget = current + PUBLISH_RETRY_NS; + if (cadenceTarget) + retryTarget = min(retryTarget, cadenceTarget); + ArmPublishTimer(m_publishTimer.Get(), retryTarget - current); + if (WaitForMultipleObjects( + ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == + WAIT_OBJECT_0) + break; + continue; + } + + uint64_t replayTarget; + if (m_transport.GetPendingDeliveryTarget(current, replayTarget)) + { + bool retry = false; + if (replayTarget <= current) + { + if (m_transport.RetryPendingDelivery(current, retry)) + continue; + + current = CFrameScheduler::Nanotime(); + if (cadenceTarget && cadenceTarget <= current) + { + m_transport.FrameMissed(schedule, current, periodic); + continue; + } + + if (retry) + replayTarget = current + PUBLISH_RETRY_NS; + else + { + if (cadenceTarget) + replayTarget = cadenceTarget; + else + { + if (m_publishTimer.Get()) + CancelWaitableTimer(m_publishTimer.Get()); + if (WaitForMultipleObjects( + ARRAYSIZE(idleHandles), idleHandles, FALSE, INFINITE) == + WAIT_OBJECT_0) + break; + continue; + } + } + } + + if (cadenceTarget) + replayTarget = min(replayTarget, cadenceTarget); + + current = CFrameScheduler::Nanotime(); + if (cadenceTarget && cadenceTarget <= current) + { + m_transport.FrameMissed(schedule, current, periodic); + continue; + } + if (replayTarget <= current) + continue; + + ArmPublishTimer(m_publishTimer.Get(), replayTarget - current); + if (WaitForMultipleObjects( + ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == + WAIT_OBJECT_0) + break; + continue; + } + + if (cadenceTarget) + { + current = CFrameScheduler::Nanotime(); + if (cadenceTarget <= current) + { + m_transport.FrameMissed(schedule, current, periodic); + continue; + } + + ArmPublishTimer(m_publishTimer.Get(), cadenceTarget - current); + if (WaitForMultipleObjects( + ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == + WAIT_OBJECT_0) + break; + continue; + } + + if (m_publishTimer.Get()) + CancelWaitableTimer(m_publishTimer.Get()); + if (WaitForMultipleObjects( + ARRAYSIZE(idleHandles), idleHandles, FALSE, INFINITE) == + WAIT_OBJECT_0) + break; + continue; + } + + uint64_t current = CFrameScheduler::Nanotime(); + uint64_t replayTarget; + if (m_transport.GetPendingDeliveryTarget(current, replayTarget) && + replayTarget < target) + { + if (replayTarget <= current) + { + m_transport.ProcessDeliveries(); + current = CFrameScheduler::Nanotime(); + bool retry = false; + if (m_transport.RetryPendingDelivery(current, retry)) + continue; + + current = CFrameScheduler::Nanotime(); + if (retry) + replayTarget = current + PUBLISH_RETRY_NS; + else + replayTarget = target; + } + + replayTarget = min(replayTarget, target); + current = CFrameScheduler::Nanotime(); + if (target > current) + { + if (replayTarget <= current) + continue; + + ArmPublishTimer(m_publishTimer.Get(), replayTarget - current); + if (WaitForMultipleObjects( + ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == + WAIT_OBJECT_0) + break; + continue; + } + } + + current = CFrameScheduler::Nanotime(); + if (target > current) + { + ArmPublishTimer(m_publishTimer.Get(), target - current); + if (WaitForMultipleObjects( + ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == + WAIT_OBJECT_0) + break; + continue; + } + + const uint64_t publishStart = CFrameScheduler::Nanotime(); + m_transport.ProcessDeliveries(); + if (!m_transport.FrameBufferAvailable(schedule) || + !m_frameProcessor->Publish(schedule, periodic, publishStart)) + { + ArmPublishTimer(m_publishTimer.Get(), PUBLISH_RETRY_NS); + if (WaitForMultipleObjects( + ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == + WAIT_OBJECT_0) + break; + } + } + + if (avTaskHandle) + AvRevertMmThreadCharacteristics(avTaskHandle); +} + +DWORD CALLBACK CSwapChainProcessor::_CursorThread(LPVOID arg) +{ + reinterpret_cast(arg)->CursorThread(); + return 0; +} + +bool CSwapChainProcessor::QueryHWCursor() +{ + IDARG_IN_QUERY_HWCURSOR in = {}; + in.LastShapeId = m_lastShapeId; + in.pShapeBuffer = m_shapeBuffer; + in.ShapeBufferSizeInBytes = 512 * 512 * 4; + + IDARG_OUT_QUERY_HWCURSOR out = {}; + UINT cursorWhiteLevel = m_sdrWhiteLevel.load(std::memory_order_relaxed); + NTSTATUS status; +#ifdef HAS_IDDCX_110 + if (m_devContext->HasIddCx110DDIs()) + { + IDARG_OUT_QUERY_HWCURSOR3 out3 = {}; + status = IddCxMonitorQueryHardwareCursor3(m_monitor, &in, &out3); + out.IsCursorVisible = out3.IsCursorVisible; + out.X = out3.X; + out.Y = out3.Y; + out.IsCursorShapeUpdated = out3.IsCursorShapeUpdated; + out.CursorShapeInfo = out3.CursorShapeInfo; + if (out3.SdrWhiteLevel) + cursorWhiteLevel = out3.SdrWhiteLevel; + } + else +#endif + { + status = IddCxMonitorQueryHardwareCursor(m_monitor, &in, &out); + } + + if (FAILED(status)) + { + // this occurs if the display went away (ie, screen blanking or disabled) + if (status == STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY) + { + SetEvent(m_terminateEvent.Get()); + return false; + } + + DEBUG_ERROR("IddCxMonitorQueryHardwareCursor failed (0x%08x)", status); + return false; + } + + if (out.IsCursorShapeUpdated) + m_lastShapeId = out.CursorShapeInfo.ShapeId; + + m_control.SendCursor(out, m_shapeBuffer, cursorWhiteLevel); + return true; +} + +void CSwapChainProcessor::CursorThread() +{ + HRESULT hr = 0; + bool running = true; + + while (running) + { + HANDLE waitHandles[] = + { + m_cursorDataEvent.Get(), + m_terminateEvent.Get() + }; + + DWORD waitResult = WaitForMultipleObjects( + ARRAYSIZE(waitHandles), waitHandles, FALSE, 100); + + switch (waitResult) + { + case WAIT_TIMEOUT: + continue; + + // cursorDataEvent + case WAIT_OBJECT_0: + if (!QueryHWCursor()) + return; + continue; + + // terminateEvent + case WAIT_OBJECT_0 + 1: + running = false; + continue; + + default: + hr = HRESULT_FROM_WIN32(waitResult); + DEBUG_ERROR_HR(hr, "WaitForMultipleObjects"); + return; + } + } +} diff --git a/idd/LGIdd/capture/CSwapChainProcessor.h b/idd/LGIdd/capture/CSwapChainProcessor.h index 75d52400..e736e5bc 100644 --- a/idd/LGIdd/capture/CSwapChainProcessor.h +++ b/idd/LGIdd/capture/CSwapChainProcessor.h @@ -56,7 +56,7 @@ private: HANDLE m_newFrameEvent; CInteropResourcePool m_resPool; - CPostProcessor m_postProcessors[TRANSPORT_FRAME_QUEUE_LENGTH]; + CPostProcessor m_postProcessors[CAPTURE_PIPELINE_SLOTS]; std::unique_ptr m_frameProcessor; // Reconfiguration is exclusive while per-candidate recording is shared. SRWLOCK m_pipelineLock = SRWLOCK_INIT; diff --git a/idd/LGIdd/capture/CSwapChainPublisher.cpp b/idd/LGIdd/capture/CSwapChainPublisher.cpp deleted file mode 100644 index 66739fd6..00000000 --- a/idd/LGIdd/capture/CSwapChainPublisher.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/** - * 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 "capture/CSwapChainProcessor.h" - -#include "transport/IFrameTransport.h" - -#include -#include "CDebug.h" - -static const uint64_t PUBLISH_RETRY_NS = 1000000ULL; - -static bool ArmPublishTimer(HANDLE timer, uint64_t delay) -{ - if (!timer) - return false; - - LARGE_INTEGER due = {}; - due.QuadPart = -static_cast((delay + 99) / 100); - if (!due.QuadPart) - due.QuadPart = -1; - return SetWaitableTimer(timer, &due, 0, nullptr, nullptr, FALSE) != FALSE; -} - -DWORD CALLBACK CSwapChainProcessor::_PublisherThread(LPVOID arg) -{ - reinterpret_cast(arg)->PublisherThread(); - return 0; -} - -void CSwapChainProcessor::PublisherThread() -{ - DWORD avTask = 0; - HANDLE avTaskHandle = AvSetMmThreadCharacteristicsW(L"Distribution", &avTask); - if (avTaskHandle && - !AvSetMmThreadPriority(avTaskHandle, AVRT_PRIORITY_HIGH)) - DEBUG_WARN("Failed to raise publisher MMCSS priority: %lu", - GetLastError()); - - const HANDLE scheduleEvent = m_transport.GetFrameScheduleEvent(); - HANDLE idleHandles[] = - { - m_terminateEvent.Get(), - m_frameProcessor->GetReadyEvent(), - scheduleEvent, - }; - HANDLE timerHandles[] = - { - m_terminateEvent.Get(), - m_frameProcessor->GetReadyEvent(), - scheduleEvent, - m_publishTimer.Get(), - }; - const bool cadenceEnabled = m_frameProcessor->UsesCadence(); - - for (;;) - { - const uint64_t now = CFrameScheduler::Nanotime(); - uint64_t target; - CFrameScheduler::Schedule schedule; - bool periodic; - bool republish; - m_transport.GetPublishTarget( - now, target, schedule, periodic, republish); - - const bool ready = m_frameProcessor->HasReadyFrame(); - if (!ready) - { - m_transport.ProcessDeliveries(); - if (m_frameProcessor->HasReadyFrame()) - continue; - - uint64_t current = CFrameScheduler::Nanotime(); - uint64_t cadenceTarget = 0; - if (cadenceEnabled && schedule.deliveryDeadlineSerial && periodic) - { - if (schedule.deadline <= current) - { - m_transport.FrameMissed(schedule, current, periodic); - continue; - } - cadenceTarget = schedule.deadline; - } - - if (republish && m_transport.HasPublishedFrame()) - { - if (m_transport.RepublishFrameBuffer(schedule)) - continue; - - current = CFrameScheduler::Nanotime(); - if (cadenceTarget && cadenceTarget <= current) - { - m_transport.FrameMissed(schedule, current, periodic); - continue; - } - - uint64_t retryTarget = current + PUBLISH_RETRY_NS; - if (cadenceTarget) - retryTarget = min(retryTarget, cadenceTarget); - ArmPublishTimer(m_publishTimer.Get(), retryTarget - current); - if (WaitForMultipleObjects( - ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == - WAIT_OBJECT_0) - break; - continue; - } - - uint64_t replayTarget; - if (m_transport.GetPendingDeliveryTarget(current, replayTarget)) - { - bool retry = false; - if (replayTarget <= current) - { - if (m_transport.RetryPendingDelivery(current, retry)) - continue; - - current = CFrameScheduler::Nanotime(); - if (cadenceTarget && cadenceTarget <= current) - { - m_transport.FrameMissed(schedule, current, periodic); - continue; - } - - if (retry) - replayTarget = current + PUBLISH_RETRY_NS; - else - { - if (cadenceTarget) - replayTarget = cadenceTarget; - else - { - if (m_publishTimer.Get()) - CancelWaitableTimer(m_publishTimer.Get()); - if (WaitForMultipleObjects( - ARRAYSIZE(idleHandles), idleHandles, FALSE, INFINITE) == - WAIT_OBJECT_0) - break; - continue; - } - } - } - - if (cadenceTarget) - replayTarget = min(replayTarget, cadenceTarget); - - current = CFrameScheduler::Nanotime(); - if (cadenceTarget && cadenceTarget <= current) - { - m_transport.FrameMissed(schedule, current, periodic); - continue; - } - if (replayTarget <= current) - continue; - - ArmPublishTimer(m_publishTimer.Get(), replayTarget - current); - if (WaitForMultipleObjects( - ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == - WAIT_OBJECT_0) - break; - continue; - } - - if (cadenceTarget) - { - current = CFrameScheduler::Nanotime(); - if (cadenceTarget <= current) - { - m_transport.FrameMissed(schedule, current, periodic); - continue; - } - - ArmPublishTimer(m_publishTimer.Get(), cadenceTarget - current); - if (WaitForMultipleObjects( - ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == - WAIT_OBJECT_0) - break; - continue; - } - - if (m_publishTimer.Get()) - CancelWaitableTimer(m_publishTimer.Get()); - if (WaitForMultipleObjects( - ARRAYSIZE(idleHandles), idleHandles, FALSE, INFINITE) == - WAIT_OBJECT_0) - break; - continue; - } - - uint64_t current = CFrameScheduler::Nanotime(); - uint64_t replayTarget; - if (m_transport.GetPendingDeliveryTarget(current, replayTarget) && - replayTarget < target) - { - if (replayTarget <= current) - { - m_transport.ProcessDeliveries(); - current = CFrameScheduler::Nanotime(); - bool retry = false; - if (m_transport.RetryPendingDelivery(current, retry)) - continue; - - current = CFrameScheduler::Nanotime(); - if (retry) - replayTarget = current + PUBLISH_RETRY_NS; - else - replayTarget = target; - } - - replayTarget = min(replayTarget, target); - current = CFrameScheduler::Nanotime(); - if (target > current) - { - if (replayTarget <= current) - continue; - - ArmPublishTimer(m_publishTimer.Get(), replayTarget - current); - if (WaitForMultipleObjects( - ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == - WAIT_OBJECT_0) - break; - continue; - } - } - - current = CFrameScheduler::Nanotime(); - if (target > current) - { - ArmPublishTimer(m_publishTimer.Get(), target - current); - if (WaitForMultipleObjects( - ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == - WAIT_OBJECT_0) - break; - continue; - } - - const uint64_t publishStart = CFrameScheduler::Nanotime(); - m_transport.ProcessDeliveries(); - if (!m_transport.FrameBufferAvailable(schedule) || - !m_frameProcessor->Publish(schedule, periodic, publishStart)) - { - ArmPublishTimer(m_publishTimer.Get(), PUBLISH_RETRY_NS); - if (WaitForMultipleObjects( - ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) == - WAIT_OBJECT_0) - break; - } - } - - if (avTaskHandle) - AvRevertMmThreadCharacteristics(avTaskHandle); -} diff --git a/idd/LGIdd/capture/FramePipeline.h b/idd/LGIdd/capture/FramePipeline.h new file mode 100644 index 00000000..ceccb8fe --- /dev/null +++ b/idd/LGIdd/capture/FramePipeline.h @@ -0,0 +1,27 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma once + +enum : unsigned +{ + CAPTURE_PIPELINE_SLOTS = 2, + CAPTURE_FRAME_BUFFERS = 3, +}; diff --git a/idd/LGIdd/d3d/CD3D12Device.h b/idd/LGIdd/d3d/CD3D12Device.h index 0cc635d6..816ec876 100644 --- a/idd/LGIdd/d3d/CD3D12Device.h +++ b/idd/LGIdd/d3d/CD3D12Device.h @@ -27,7 +27,7 @@ #include #include "d3d/CD3D12CommandQueue.h" -#include "transport/TransportTypes.h" +#include "transport/DirectFrameBufferMemory.h" using namespace Microsoft::WRL; diff --git a/idd/LGIdd/display/device/CDeviceContext.cpp b/idd/LGIdd/display/CDeviceContext.cpp similarity index 99% rename from idd/LGIdd/display/device/CDeviceContext.cpp rename to idd/LGIdd/display/CDeviceContext.cpp index 8192d46f..9152fab6 100644 --- a/idd/LGIdd/display/device/CDeviceContext.cpp +++ b/idd/LGIdd/display/CDeviceContext.cpp @@ -18,10 +18,10 @@ * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "display/device/CDeviceContext.h" +#include "display/CDeviceContext.h" #include "display/IddCxCompat.h" -#include "transport/CPipeServer.h" +#include "ipc/CPipeServer.h" #include "transport/IFrameTransport.h" #include "transport/TransportFactory.h" #include "CDebug.h" diff --git a/idd/LGIdd/display/device/CDeviceContext.h b/idd/LGIdd/display/CDeviceContext.h similarity index 100% rename from idd/LGIdd/display/device/CDeviceContext.h rename to idd/LGIdd/display/CDeviceContext.h diff --git a/idd/LGIdd/display/monitor/Context.cpp b/idd/LGIdd/display/CMonitorContext.cpp similarity index 98% rename from idd/LGIdd/display/monitor/Context.cpp rename to idd/LGIdd/display/CMonitorContext.cpp index 416b2fe2..aebe98fb 100644 --- a/idd/LGIdd/display/monitor/Context.cpp +++ b/idd/LGIdd/display/CMonitorContext.cpp @@ -18,8 +18,8 @@ * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "display/monitor/Context.h" -#include "display/device/CDeviceContext.h" +#include "display/CMonitorContext.h" +#include "display/CDeviceContext.h" #include "capture/CSwapChainProcessor.h" #include "d3d/CD3D11Device.h" #include "CDebug.h" diff --git a/idd/LGIdd/display/monitor/Context.h b/idd/LGIdd/display/CMonitorContext.h similarity index 100% rename from idd/LGIdd/display/monitor/Context.h rename to idd/LGIdd/display/CMonitorContext.h diff --git a/idd/LGIdd/display/CMonitorManager.cpp b/idd/LGIdd/display/CMonitorManager.cpp index e8e2b655..08407f7a 100644 --- a/idd/LGIdd/display/CMonitorManager.cpp +++ b/idd/LGIdd/display/CMonitorManager.cpp @@ -20,7 +20,7 @@ #include "display/CMonitorManager.h" -#include "display/monitor/Context.h" +#include "display/CMonitorContext.h" #include "CDebug.h" void CMonitorManager::Create(UINT connectorIndex, IDDCX_ADAPTER adapter, diff --git a/idd/LGIdd/transport/CPipeServer.cpp b/idd/LGIdd/ipc/CPipeServer.cpp similarity index 99% rename from idd/LGIdd/transport/CPipeServer.cpp rename to idd/LGIdd/ipc/CPipeServer.cpp index 9a2d0db7..d98b904b 100644 --- a/idd/LGIdd/transport/CPipeServer.cpp +++ b/idd/LGIdd/ipc/CPipeServer.cpp @@ -18,9 +18,9 @@ * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "transport/CPipeServer.h" +#include "ipc/CPipeServer.h" #include "CDebug.h" -#include "display/device/CDeviceContext.h" +#include "display/CDeviceContext.h" CPipeServer g_pipe; diff --git a/idd/LGIdd/transport/CPipeServer.h b/idd/LGIdd/ipc/CPipeServer.h similarity index 100% rename from idd/LGIdd/transport/CPipeServer.h rename to idd/LGIdd/ipc/CPipeServer.h diff --git a/idd/LGIdd/postprocess/effect/CRGB24Effect.cpp b/idd/LGIdd/postprocess/effect/CRGB24Effect.cpp index 6c5bff94..134121f6 100644 --- a/idd/LGIdd/postprocess/effect/CRGB24Effect.cpp +++ b/idd/LGIdd/postprocess/effect/CRGB24Effect.cpp @@ -22,7 +22,7 @@ #include "CDebug.h" #include "config/CSettings.h" -#include "transport/TransportTypes.h" +#include "capture/FramePipeline.h" #include #include @@ -61,7 +61,7 @@ struct CRGB24Effect::State std::shared_ptr colorTransform; }; - static const unsigned WarmupCount = TRANSPORT_FRAME_QUEUE_LENGTH; + static const unsigned WarmupCount = CAPTURE_PIPELINE_SLOTS; static const unsigned SampleCount = 64; static const unsigned TrimCount = SampleCount / 8; diff --git a/idd/LGIdd/transport/TransportTypes.h b/idd/LGIdd/transport/DirectFrameBufferMemory.h similarity index 63% rename from idd/LGIdd/transport/TransportTypes.h rename to idd/LGIdd/transport/DirectFrameBufferMemory.h index 4a535af5..58e8d96c 100644 --- a/idd/LGIdd/transport/TransportTypes.h +++ b/idd/LGIdd/transport/DirectFrameBufferMemory.h @@ -21,36 +21,6 @@ #pragma once #include -#include - -enum : unsigned -{ - TRANSPORT_FRAME_QUEUE_LENGTH = 2, - TRANSPORT_FRAME_BUFFER_COUNT = 3, - TRANSPORT_MAX_CLIENTS = 8, -}; - -enum : uint32_t -{ - FRAME_SCHEDULE_ACTIVE = 0x1, - FRAME_SCHEDULE_RELEASE = 0x2, - FRAME_SCHEDULE_RESET = 0x4, - FRAME_SCHEDULE_IMMEDIATE = 0x8, -}; - -struct FrameScheduleUpdate -{ - uint32_t clientID; - uint32_t generation; - uint32_t flags; - uint64_t period; - uint64_t targetSlack; - int64_t phaseError; - uint32_t feedbackFrameSerial; - uint32_t feedbackScheduleEpoch; - uint32_t feedbackDeadlineSerial; - uint32_t lease; -}; struct DirectFrameBufferMemory { diff --git a/idd/LGIdd/transport/IFrameTransport.h b/idd/LGIdd/transport/IFrameTransport.h index 982e555b..dc016c7a 100644 --- a/idd/LGIdd/transport/IFrameTransport.h +++ b/idd/LGIdd/transport/IFrameTransport.h @@ -21,9 +21,8 @@ #pragma once #include "postprocess/D12FrameFormat.h" -#include "transport/CFrameScheduler.h" -#include "transport/FrameBufferTypes.h" -#include "transport/TransportTypes.h" +#include "capture/CFrameScheduler.h" +#include "transport/PreparedFrameBuffer.h" #include #include diff --git a/idd/LGIdd/transport/ITransport.h b/idd/LGIdd/transport/ITransport.h index 7f2a7138..4cdd567e 100644 --- a/idd/LGIdd/transport/ITransport.h +++ b/idd/LGIdd/transport/ITransport.h @@ -20,8 +20,8 @@ #pragma once +#include "transport/DirectFrameBufferMemory.h" #include "transport/FrameMemoryLimits.h" -#include "transport/TransportTypes.h" #include #include diff --git a/idd/LGIdd/transport/FrameBufferTypes.h b/idd/LGIdd/transport/PreparedFrameBuffer.h similarity index 100% rename from idd/LGIdd/transport/FrameBufferTypes.h rename to idd/LGIdd/transport/PreparedFrameBuffer.h diff --git a/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.cpp b/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.cpp index e20103f9..ebb199f8 100644 --- a/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.cpp +++ b/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.cpp @@ -35,11 +35,11 @@ struct LGMPBuffer }; #pragma warning(pop) -static_assert(TRANSPORT_FRAME_QUEUE_LENGTH == LGMP_Q_FRAME_LEN, +static_assert(CAPTURE_PIPELINE_SLOTS == LGMP_Q_FRAME_LEN, "The capture pipeline must match the LGMP frame queue"); -static_assert(TRANSPORT_FRAME_BUFFER_COUNT == LGMP_Q_FRAME_BUFFER_LEN, +static_assert(CAPTURE_FRAME_BUFFERS == LGMP_Q_FRAME_BUFFER_LEN, "The capture buffer pool must match the LGMP frame buffers"); -static_assert(TRANSPORT_MAX_CLIENTS == LGMP_MAX_CLIENTS, +static_assert(CFrameScheduler::MAX_CLIENTS == LGMP_MAX_CLIENTS, "The scheduler must support every LGMP client"); static const struct LGMPQueueConfig FRAME_QUEUE_CONFIG = diff --git a/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.h b/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.h index 45c77d19..22948649 100644 --- a/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.h +++ b/idd/LGIdd/transport/lgmp/CLGMPFrameTransport.h @@ -29,7 +29,8 @@ extern "C" { } #include "common/KVMFR.h" -#include "transport/CFrameScheduler.h" +#include "capture/CFrameScheduler.h" +#include "capture/FramePipeline.h" #include "transport/FrameMemoryLimits.h" #include "transport/IFrameTransport.h"