mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
[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:
215
idd/LGIdd/transport/lgmp/CLGMPFrameTransport.h
Normal file
215
idd/LGIdd/transport/lgmp/CLGMPFrameTransport.h
Normal file
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* 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 <Windows.h>
|
||||
#include <atomic>
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
#include "lgmp/host.h"
|
||||
}
|
||||
|
||||
#include "common/KVMFR.h"
|
||||
#include "transport/CFrameScheduler.h"
|
||||
#include "transport/FrameMemoryLimits.h"
|
||||
#include "transport/IFrameTransport.h"
|
||||
|
||||
class CIVSHMEM;
|
||||
class CLGMPHost;
|
||||
class CLGMPTransport;
|
||||
struct LGMPBuffer;
|
||||
|
||||
class CLGMPFrameTransport final : public IFrameTransport
|
||||
{
|
||||
private:
|
||||
friend class CLGMPTransport;
|
||||
|
||||
struct SubscriberSnapshot
|
||||
{
|
||||
uint32_t clientIDs [LGMP_MAX_CLIENTS] = {};
|
||||
uint32_t ownerClientIDs[LGMP_MAX_CLIENTS] = {};
|
||||
unsigned clientCount = 0;
|
||||
unsigned ownerClientCount = 0;
|
||||
LGMP_STATUS status = LGMP_OK;
|
||||
};
|
||||
|
||||
private:
|
||||
enum SharedFramePostResult
|
||||
{
|
||||
SHARED_FRAME_FAILED,
|
||||
SHARED_FRAME_IDLE,
|
||||
SHARED_FRAME_POSTED,
|
||||
};
|
||||
|
||||
struct FrameDelivery
|
||||
{
|
||||
uint64_t sharedOwnerToken = 0;
|
||||
unsigned ownerQueueMask = 0;
|
||||
uint32_t sharedOwnerClientID = 0;
|
||||
bool sharedOwnerPending = false;
|
||||
bool sharedPending = false;
|
||||
};
|
||||
|
||||
struct OwnerDelivery
|
||||
{
|
||||
uint64_t token = 0;
|
||||
uint32_t clientID = 0;
|
||||
unsigned frameIndex = 0;
|
||||
bool active = false;
|
||||
};
|
||||
|
||||
CLGMPHost& m_host;
|
||||
CIVSHMEM& m_ivshmem;
|
||||
|
||||
PLGMPHostQueue m_frameQueue = nullptr;
|
||||
PLGMPHostQueue m_frameOwnerQueue[LGMP_Q_FRAME_LEN] = {};
|
||||
|
||||
CFrameScheduler m_frameScheduler;
|
||||
|
||||
size_t m_alignSize = 0;
|
||||
size_t m_frameMemoryOffset = 0;
|
||||
size_t m_maxFrameSize = 0;
|
||||
|
||||
// LGMP publication precedes copy completion. Replay only completed frames;
|
||||
// the deferred index tracks the newest frame still owed to the owner.
|
||||
std::atomic<LONG> m_submittedFrameIndex = -1;
|
||||
std::atomic<LONG> m_readyFrameIndex = -1;
|
||||
LONG m_deferredOwnerFrameIndex = -1;
|
||||
std::atomic<bool> m_frameInFlight[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
||||
bool m_frameCompleted[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
||||
SRWLOCK m_framePublishLock = SRWLOCK_INIT;
|
||||
uint64_t m_framePublishSequence = 0;
|
||||
uint64_t m_frameLastPublishSequence[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
||||
|
||||
FrameDelivery m_frameDelivery[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
||||
OwnerDelivery m_ownerDelivery[LGMP_Q_FRAME_LEN] = {};
|
||||
uint32_t m_formatVer = 0;
|
||||
uint32_t m_frameSerial = 0;
|
||||
PLGMPMemory m_frameMemory[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
||||
KVMFRFrame * m_frame [LGMP_Q_FRAME_BUFFER_LEN] = {};
|
||||
LGMPBuffer * m_frameBuffer[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
||||
|
||||
unsigned m_width = 0;
|
||||
unsigned m_height = 0;
|
||||
unsigned m_frameWidth = 0;
|
||||
unsigned m_frameHeight = 0;
|
||||
unsigned m_pitch = 0;
|
||||
DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN;
|
||||
FrameType m_frameType = FRAME_TYPE_INVALID;
|
||||
|
||||
// Previous HDR metadata used to detect changes for formatVer bumps.
|
||||
uint16_t m_lastHDRDisplayPrimary[3][2] = {};
|
||||
uint16_t m_lastHDRWhitePoint[2] = {};
|
||||
uint32_t m_lastHDRMaxDisplayLuminance = 0;
|
||||
uint32_t m_lastHDRMinDisplayLuminance = 0;
|
||||
uint32_t m_lastHDRMaxContentLightLevel = 0;
|
||||
uint32_t m_lastHDRMaxFrameAverageLightLevel = 0;
|
||||
uint32_t m_lastSDRWhiteLevel = 0;
|
||||
bool m_lastHDRActive = false;
|
||||
bool m_lastHDRMetadata = false;
|
||||
|
||||
void ProcessFrameDeliveries();
|
||||
bool FrameBufferReferenced(unsigned frameIndex) const;
|
||||
int FindAvailableFrameBuffer(bool allowReady) const;
|
||||
int FindNewestCompletedFrame(unsigned excludeFrameIndex) const;
|
||||
int FindAvailableOwnerQueue(unsigned preferredIndex) const;
|
||||
unsigned CountOwnerDeliveries(uint32_t clientID) const;
|
||||
bool HasMatchingOwnerDelivery(uint32_t clientID, unsigned frameIndex,
|
||||
uint64_t token) const;
|
||||
SharedFramePostResult PostSharedFrame(unsigned frameIndex,
|
||||
uint32_t excludeClientID, uint64_t now);
|
||||
bool PostSharedOwnerFrame(unsigned frameIndex,
|
||||
const CFrameScheduler::Schedule& schedule);
|
||||
CLGMPFrameTransport(CLGMPHost& host, CIVSHMEM& ivshmem);
|
||||
bool Initialize();
|
||||
void SealMemoryLayout();
|
||||
bool Setup(size_t alignSize);
|
||||
void DeInit();
|
||||
FrameMemoryLimits GetMemoryLimits() const;
|
||||
SubscriberSnapshot SnapshotSubscribers() const;
|
||||
void FinalizeSubscribers(
|
||||
const SubscriberSnapshot& snapshot, uint64_t now);
|
||||
bool UpdateSchedule(uint32_t sourceClientID,
|
||||
const FrameScheduleUpdate& schedule, uint64_t now);
|
||||
|
||||
public:
|
||||
~CLGMPFrameTransport() override;
|
||||
|
||||
CLGMPFrameTransport(const CLGMPFrameTransport&) = delete;
|
||||
CLGMPFrameTransport& operator=(const CLGMPFrameTransport&) = delete;
|
||||
|
||||
size_t GetMaxFrameSize() const override { return m_maxFrameSize; }
|
||||
|
||||
bool FrameBufferAvailable(const CFrameScheduler::Schedule& schedule,
|
||||
bool allowReadyReplacement = true) override;
|
||||
bool HasPublishedFrame() const override
|
||||
{
|
||||
return m_readyFrameIndex.load(std::memory_order_acquire) >= 0;
|
||||
}
|
||||
void ProcessDeliveries() override;
|
||||
bool GetPendingDeliveryTarget(
|
||||
uint64_t now, uint64_t& target) override;
|
||||
bool RetryPendingDelivery(uint64_t now, bool& retry) override;
|
||||
PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch,
|
||||
const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat,
|
||||
const RECT * dirtyRects, unsigned nbDirtyRects,
|
||||
const CFrameScheduler::Schedule& schedule,
|
||||
bool allowReadyReplacement = true) override;
|
||||
bool PublishFrameBuffer(unsigned frameIndex,
|
||||
const CFrameScheduler::Schedule& schedule,
|
||||
bool& deliveredToOwner) override;
|
||||
bool RepublishFrameBuffer(
|
||||
const CFrameScheduler::Schedule& schedule) override;
|
||||
bool TryFrameSubmitted(unsigned frameIndex,
|
||||
const CFrameScheduler::Schedule& schedule) override;
|
||||
void CommitFrameBuffer(unsigned frameIndex,
|
||||
const CFrameScheduler::Schedule& schedule, bool periodic,
|
||||
bool deliveredToOwner) override;
|
||||
void AbortFrameBuffer(unsigned frameIndex) override;
|
||||
void FailFrameBuffer(unsigned frameIndex) override;
|
||||
void CompleteFrameBuffer(
|
||||
unsigned frameIndex, bool succeeded) override;
|
||||
void SetFrameTiming(unsigned frameIndex, uint64_t captureTime,
|
||||
uint64_t postProcessTime, uint64_t copyTime, uint64_t readyTime,
|
||||
uint64_t holdTime, const CFrameScheduler::Schedule& schedule,
|
||||
uint64_t completedAt) override;
|
||||
void WriteFrameBuffer(unsigned frameIndex, void * src, size_t offset,
|
||||
size_t len, bool setWritePos) const override;
|
||||
void WriteFrameBufferRows(unsigned frameIndex, void * src,
|
||||
size_t offset, size_t rowBytes, size_t pitch,
|
||||
unsigned rows) const override;
|
||||
void FinalizeFrameBuffer(unsigned frameIndex) const override;
|
||||
|
||||
void ObserveFrame(uint64_t now) override;
|
||||
void ForceFrame() override;
|
||||
bool GetPublishTarget(uint64_t now, uint64_t& target,
|
||||
CFrameScheduler::Schedule& schedule, bool& periodic,
|
||||
bool& republish) override;
|
||||
void FrameMissed(const CFrameScheduler::Schedule& schedule,
|
||||
uint64_t now, bool periodic) override;
|
||||
void FrameSuperseded() override;
|
||||
HANDLE GetFrameScheduleEvent() const override
|
||||
{
|
||||
return m_frameScheduler.GetWakeEvent();
|
||||
}
|
||||
void TryRecordFrameTiming(uint64_t duration) override;
|
||||
};
|
||||
Reference in New Issue
Block a user