mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 00:31:31 +00:00
[idd] project: organize driver sources by responsibility
Group the IDD sources and Visual Studio filters by subsystem. Split the device and swap-chain implementations into focused units, rename the context classes, and reduce header coupling.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,350 +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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <wdf.h>
|
||||
#include <IddCx.h>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include "CIVSHMEM.h"
|
||||
#include "CSettings.h"
|
||||
#include "CEdid.h"
|
||||
#include "CPostProcessor.h"
|
||||
#include "CFrameScheduler.h"
|
||||
|
||||
extern "C" {
|
||||
#include "lgmp/host.h"
|
||||
}
|
||||
|
||||
#include "common/KVMFR.h"
|
||||
|
||||
// IddCx 1.10 HDR/WCG types are only visible when the WDK targets
|
||||
// (NTDDI >= 0x0A000005) *and* the build flags IDDCX_VERSION_MAJOR/MINOR are set to >= 1.10.
|
||||
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
|
||||
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) && \
|
||||
NTDDI_VERSION >= 0x0A000005
|
||||
#define HAS_IDDCX_110
|
||||
#endif
|
||||
|
||||
#define MAX_POINTER_SIZE (sizeof(KVMFRCursor) + (512 * 512 * 4))
|
||||
#define COLOR_TRANSFORM_BUFFERS 3
|
||||
#define POINTER_SHAPE_BUFFERS 3
|
||||
|
||||
//FIXME: this should not really be done here, this is a hack
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4200)
|
||||
struct FrameBuffer
|
||||
{
|
||||
volatile uint32_t wp;
|
||||
uint8_t data[0];
|
||||
};
|
||||
#pragma warning(pop)
|
||||
|
||||
class CIndirectDeviceContext
|
||||
{
|
||||
private:
|
||||
WDFDEVICE m_wdfDevice;
|
||||
IDDCX_ADAPTER m_adapter = nullptr;
|
||||
IDDCX_MONITOR m_monitor = nullptr;
|
||||
LUID m_preferredRenderAdapter = {};
|
||||
bool m_havePreferredRenderAdapter = false;
|
||||
bool m_replugMonitor = false;
|
||||
bool m_replugPending = false;
|
||||
bool m_monitorDeparted = false;
|
||||
bool m_swapChainAssigned = false;
|
||||
bool m_swapChainReady = false;
|
||||
bool m_waitForSwapChainRelease = false;
|
||||
|
||||
// Guards the adapter/monitor init handshake and the replug state machine
|
||||
// (monitor/replug/swap-chain state, m_doSetMode, m_setMode). These are
|
||||
// touched from the IddCx callback threads, swap-chain thread and LGMP timer.
|
||||
SRWLOCK m_stateLock = SRWLOCK_INIT;
|
||||
|
||||
// Retry state for InitAdapter. At boot the IVSHMEM device may not have
|
||||
// enumerated yet; if so we re-attempt from a timer instead of giving up.
|
||||
WDFTIMER m_initTimer = nullptr;
|
||||
bool m_ivshmemOpened = false;
|
||||
std::atomic<LONG> m_initInProgress = 0;
|
||||
|
||||
CIVSHMEM m_ivshmem;
|
||||
|
||||
PLGMPHost m_lgmp = nullptr;
|
||||
WDFTIMER m_lgmpTimer = nullptr;
|
||||
PLGMPHostQueue m_frameQueue = nullptr;
|
||||
PLGMPHostQueue m_frameOwnerQueue[LGMP_Q_FRAME_LEN] = {};
|
||||
SRWLOCK m_lgmpProcessLock = SRWLOCK_INIT;
|
||||
|
||||
CFrameScheduler m_frameScheduler;
|
||||
|
||||
PLGMPHostQueue m_pointerQueue = nullptr;
|
||||
PLGMPMemory m_pointerMemory [LGMP_Q_POINTER_LEN ] = {};
|
||||
PLGMPMemory m_pointerShapeMemory[POINTER_SHAPE_BUFFERS] = {};
|
||||
PLGMPMemory m_pointerTransformMemory[COLOR_TRANSFORM_BUFFERS] = {};
|
||||
PLGMPMemory m_pointerShape = nullptr;
|
||||
int m_pointerMemoryIndex = 0;
|
||||
int m_pointerShapeIndex = 0;
|
||||
int m_pointerTransformIndex = 0;
|
||||
bool m_cursorVisible = false;
|
||||
int m_cursorX = 0, m_cursorY = 0;
|
||||
|
||||
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] = {};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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] = {};
|
||||
FrameBuffer * 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;
|
||||
|
||||
UINT m_iddCxVersion = 0;
|
||||
bool m_hasIddCx110DDIs = false;
|
||||
bool m_canProcessFP16 = false;
|
||||
bool m_softwareMode = true;
|
||||
|
||||
// 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;
|
||||
|
||||
// Windows display calibration transform. The callback publishes immutable
|
||||
// snapshots so the swap-chain thread never observes a partially updated
|
||||
// matrix or LUT.
|
||||
mutable SRWLOCK m_colorTransformLock = SRWLOCK_INIT;
|
||||
std::shared_ptr<const D12ColorTransform> m_colorTransform;
|
||||
|
||||
void QueryIddCxCapabilities();
|
||||
|
||||
void ScheduleInitRetry();
|
||||
void StopInitRetry();
|
||||
|
||||
bool InitializeLGMP();
|
||||
void DeInitLGMP();
|
||||
void LGMPTimer();
|
||||
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);
|
||||
void ResendCursor();
|
||||
void SendColorTransform();
|
||||
void InitializeEdid();
|
||||
bool GetResolutionMemoryRequirements(uint32_t width, uint32_t height,
|
||||
UINT64 alignment, UINT64& frameSize, UINT64& ivshmemSize) const;
|
||||
|
||||
// Guards m_displayModes and m_edid. The mode list is rebuilt on the LGMP
|
||||
// timer thread (SetResolution) while IddCx concurrently enumerates it on its
|
||||
// own callback threads. The EDID is initialized once and remains immutable.
|
||||
// Never held across an IddCx API call - snapshot then call.
|
||||
mutable SRWLOCK m_modeLock = SRWLOCK_INIT;
|
||||
|
||||
// Serializes registry-backed mode changes with rebuilding m_displayModes.
|
||||
// Reload requests arrive on the pipe thread while dynamic resolution
|
||||
// requests arrive on the LGMP timer thread.
|
||||
SRWLOCK m_modeReloadLock = SRWLOCK_INIT;
|
||||
|
||||
CSettings::DisplayModes m_displayModes;
|
||||
CEdid m_edid;
|
||||
|
||||
CSettings::DisplayMode m_setMode = {};
|
||||
bool m_doSetMode = false;
|
||||
|
||||
// Set by ReplugMonitor after a departure to rebuild the monitor from the LGMP
|
||||
// timer, off the IddCx callback thread.
|
||||
std::atomic<LONG> m_finishInitQueued = 0;
|
||||
std::atomic<LONG> m_replugQueued = 0;
|
||||
|
||||
public:
|
||||
CIndirectDeviceContext(_In_ WDFDEVICE wdfDevice) :
|
||||
m_wdfDevice(wdfDevice) {};
|
||||
|
||||
virtual ~CIndirectDeviceContext() { DeInitLGMP(); }
|
||||
|
||||
bool SetupLGMP(size_t alignSize);
|
||||
|
||||
bool PopulateDefaultModes();
|
||||
void InitAdapter();
|
||||
void FinishAdapterInit(UINT connectorIndex);
|
||||
void FinishInit(UINT connectorIndex);
|
||||
void ReloadSettings();
|
||||
void ReplugMonitor();
|
||||
|
||||
void OnMonitorDestroyed(IDDCX_MONITOR monitor);
|
||||
void OnSwapChainAssigned();
|
||||
void OnSwapChainReleased();
|
||||
void OnSwapChainReady();
|
||||
|
||||
NTSTATUS ParseMonitorDescription(
|
||||
const IDARG_IN_PARSEMONITORDESCRIPTION* inArgs, IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs);
|
||||
NTSTATUS MonitorGetDefaultModes(
|
||||
const IDARG_IN_GETDEFAULTDESCRIPTIONMODES* inArgs, IDARG_OUT_GETDEFAULTDESCRIPTIONMODES* outArgs);
|
||||
NTSTATUS MonitorQueryTargetModes(
|
||||
const IDARG_IN_QUERYTARGETMODES* inArgs, IDARG_OUT_QUERYTARGETMODES* outArgs);
|
||||
|
||||
#ifdef HAS_IDDCX_110
|
||||
NTSTATUS ParseMonitorDescription2(
|
||||
const IDARG_IN_PARSEMONITORDESCRIPTION2* inArgs, IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs);
|
||||
NTSTATUS MonitorQueryTargetModes2(
|
||||
const IDARG_IN_QUERYTARGETMODES2* inArgs, IDARG_OUT_QUERYTARGETMODES* outArgs);
|
||||
#endif
|
||||
|
||||
void SetResolution(uint32_t width, uint32_t height);
|
||||
|
||||
size_t GetAlignSize () const { return m_alignSize ; }
|
||||
size_t GetMaxFrameSize() const { return m_maxFrameSize ; }
|
||||
bool HasIddCx110DDIs() const { return m_hasIddCx110DDIs; }
|
||||
bool CanProcessFP16 () const { return m_canProcessFP16; }
|
||||
bool IsSoftwareMode () const { return m_softwareMode ; }
|
||||
|
||||
struct PreparedFrameBuffer
|
||||
{
|
||||
unsigned frameIndex;
|
||||
uint8_t* mem;
|
||||
bool fullCopy;
|
||||
};
|
||||
|
||||
bool FrameBufferAvailable(const CFrameScheduler::Schedule& schedule,
|
||||
bool allowReadyReplacement = true);
|
||||
bool HasPublishedFrame() const
|
||||
{
|
||||
return m_readyFrameIndex.load(std::memory_order_acquire) >= 0;
|
||||
}
|
||||
void ProcessFrameQueue();
|
||||
bool GetSharedFrameTarget(uint64_t now, uint64_t& target);
|
||||
bool ReplaySharedFrame(uint64_t now, bool& retry);
|
||||
PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch,
|
||||
const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat,
|
||||
const RECT * dirtyRects, unsigned nbDirtyRects,
|
||||
const CFrameScheduler::Schedule& schedule,
|
||||
bool allowReadyReplacement = true);
|
||||
bool PublishFrameBuffer(unsigned frameIndex,
|
||||
const CFrameScheduler::Schedule& schedule, bool& deliveredToOwner);
|
||||
bool RepublishFrameBuffer(const CFrameScheduler::Schedule& schedule);
|
||||
bool TryFrameSubmitted(unsigned frameIndex,
|
||||
const CFrameScheduler::Schedule& schedule);
|
||||
void CommitFrameBuffer(unsigned frameIndex,
|
||||
const CFrameScheduler::Schedule& schedule, bool periodic,
|
||||
bool deliveredToOwner);
|
||||
void AbortFrameBuffer(unsigned frameIndex);
|
||||
void FailFrameBuffer(unsigned frameIndex);
|
||||
void CompleteFrameBuffer(unsigned frameIndex, bool succeeded);
|
||||
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);
|
||||
void WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos) const;
|
||||
void WriteFrameBufferRows(unsigned frameIndex, void * src,
|
||||
size_t offset, size_t rowBytes, size_t pitch, unsigned rows) const;
|
||||
void FinalizeFrameBuffer(unsigned frameIndex) const;
|
||||
|
||||
void ObserveFrame(uint64_t now);
|
||||
void ForceFrame();
|
||||
bool GetPublishTarget(uint64_t now, uint64_t& target,
|
||||
CFrameScheduler::Schedule& schedule, bool& periodic, bool& republish);
|
||||
void FrameMissed(const CFrameScheduler::Schedule& schedule,
|
||||
uint64_t now, bool periodic);
|
||||
void FrameSuperseded();
|
||||
HANDLE GetFrameScheduleEvent() const
|
||||
{
|
||||
return m_frameScheduler.GetWakeEvent();
|
||||
}
|
||||
void TryRecordFrameTiming(uint64_t duration);
|
||||
|
||||
void SendCursor(const IDARG_OUT_QUERY_HWCURSOR & info, const BYTE * data,
|
||||
UINT sdrWhiteLevel);
|
||||
|
||||
void SetColorTransform(std::shared_ptr<const D12ColorTransform> transform);
|
||||
std::shared_ptr<const D12ColorTransform> GetColorTransform() const;
|
||||
|
||||
CIVSHMEM &GetIVSHMEM() { return m_ivshmem; }
|
||||
};
|
||||
|
||||
struct CIndirectDeviceContextWrapper
|
||||
{
|
||||
CIndirectDeviceContext* context;
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
delete context;
|
||||
context = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
WDF_DECLARE_CONTEXT_TYPE(CIndirectDeviceContextWrapper);
|
||||
@@ -1,71 +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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <wdf.h>
|
||||
#include <wrl.h>
|
||||
#include <memory>
|
||||
|
||||
#include "CD3D11Device.h"
|
||||
#include "CD3D12Device.h"
|
||||
#include "CD3D12CommandQueue.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
#define LG_MAX_DIRTY_RECTS 256
|
||||
|
||||
class CInteropResource
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<CD3D11Device> m_dx11Device;
|
||||
std::shared_ptr<CD3D12Device> m_dx12Device;
|
||||
|
||||
/* this value is likely released, it is only used to check if the texture supplied
|
||||
is different, do not rely on it pointing to valid memory */
|
||||
void * m_srcTex;
|
||||
|
||||
ComPtr<ID3D12Resource > m_d12Res;
|
||||
D3D11_TEXTURE2D_DESC m_format;
|
||||
ComPtr<ID3D11Fence > m_d11Fence;
|
||||
ComPtr<ID3D12Fence > m_d12Fence;
|
||||
UINT64 m_fenceValue;
|
||||
bool m_ready;
|
||||
|
||||
RECT m_dirtyRects[LG_MAX_DIRTY_RECTS];
|
||||
unsigned m_nbDirtyRects;
|
||||
|
||||
public:
|
||||
bool Init(std::shared_ptr<CD3D11Device> dx11Device, std::shared_ptr<CD3D12Device> dx12Device, ComPtr<ID3D11Texture2D> srcTex);
|
||||
void Reset();
|
||||
|
||||
bool IsReady() { return m_ready; }
|
||||
bool Compare(const ComPtr<ID3D11Texture2D>& srcTex);
|
||||
bool Signal();
|
||||
bool Sync(CD3D12CommandSlot& slot);
|
||||
void SetFullDamage();
|
||||
void SetDirtyRects(const RECT * dirtyRects, unsigned nbDirtyRects);
|
||||
|
||||
const ComPtr<ID3D12Resource>& GetRes() { return m_d12Res; }
|
||||
const D3D11_TEXTURE2D_DESC& GetFormat() { return m_format; }
|
||||
const RECT * GetDirtyRects() { return m_dirtyRects; }
|
||||
unsigned GetDirtyRectCount() { return m_nbDirtyRects; }
|
||||
};
|
||||
@@ -32,10 +32,13 @@
|
||||
#include <utility>
|
||||
|
||||
#include "CDebug.h"
|
||||
#include "CIndirectDeviceContext.h"
|
||||
#include "CIndirectMonitorContext.h"
|
||||
#include "CPipeServer.h"
|
||||
#include "CSettings.h"
|
||||
#include "display/CDisplayConfiguration.h"
|
||||
#include "display/IddCxCompat.h"
|
||||
#include "display/device/CDeviceContext.h"
|
||||
#include "display/monitor/Context.h"
|
||||
#include "transport/CLGMPControl.h"
|
||||
#include "transport/CPipeServer.h"
|
||||
#include "config/CSettings.h"
|
||||
|
||||
WDFDEVICE l_wdfDevice = nullptr;
|
||||
|
||||
@@ -65,7 +68,7 @@ NTSTATUS LGIddDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previousSta
|
||||
UNREFERENCED_PARAMETER(previousState);
|
||||
|
||||
DEBUG_INFO("Device entered D0, starting adapter initialization");
|
||||
auto * wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(device);
|
||||
auto * wrapper = WdfObjectGet_CDeviceContextWrapper(device);
|
||||
wrapper->context->InitAdapter();
|
||||
|
||||
DEBUG_INFO("Device D0 entry completed");
|
||||
@@ -77,7 +80,7 @@ NTSTATUS LGIddAdapterInitFinished(IDDCX_ADAPTER adapter, const IDARG_IN_ADAPTER_
|
||||
DEBUG_INFO("Adapter initialization callback completed with status 0x%08x",
|
||||
args->AdapterInitStatus);
|
||||
|
||||
auto * wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(adapter);
|
||||
auto * wrapper = WdfObjectGet_CDeviceContextWrapper(adapter);
|
||||
if (!NT_SUCCESS(args->AdapterInitStatus))
|
||||
{
|
||||
DEBUG_ERROR_HR(args->AdapterInitStatus,
|
||||
@@ -110,22 +113,27 @@ NTSTATUS LGIddParseMonitorDescription(const IDARG_IN_PARSEMONITORDESCRIPTION* in
|
||||
if (!l_wdfDevice)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
auto* wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(l_wdfDevice);
|
||||
return wrapper->context->ParseMonitorDescription(inArgs, outArgs);
|
||||
auto * wrapper = WdfObjectGet_CDeviceContextWrapper(l_wdfDevice);
|
||||
return wrapper->context->GetDisplayConfiguration().ParseMonitorDescription(
|
||||
inArgs, outArgs);
|
||||
}
|
||||
|
||||
NTSTATUS LGIddMonitorGetDefaultModes(IDDCX_MONITOR monitor, const IDARG_IN_GETDEFAULTDESCRIPTIONMODES * inArgs,
|
||||
IDARG_OUT_GETDEFAULTDESCRIPTIONMODES * outArgs)
|
||||
{
|
||||
auto* wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor);
|
||||
return wrapper->context->GetDeviceContext()->MonitorGetDefaultModes(inArgs, outArgs);
|
||||
auto * wrapper = WdfObjectGet_CMonitorContextWrapper(monitor);
|
||||
auto * context = wrapper->context->GetDeviceContext();
|
||||
return context->GetDisplayConfiguration().MonitorGetDefaultModes(
|
||||
inArgs, outArgs);
|
||||
}
|
||||
|
||||
NTSTATUS LGIddMonitorQueryTargetModes(IDDCX_MONITOR monitor, const IDARG_IN_QUERYTARGETMODES * inArgs,
|
||||
IDARG_OUT_QUERYTARGETMODES * outArgs)
|
||||
{
|
||||
auto* wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor);
|
||||
return wrapper->context->GetDeviceContext()->MonitorQueryTargetModes(inArgs, outArgs);
|
||||
auto * wrapper = WdfObjectGet_CMonitorContextWrapper(monitor);
|
||||
auto * context = wrapper->context->GetDeviceContext();
|
||||
return context->GetDisplayConfiguration().MonitorQueryTargetModes(
|
||||
inArgs, outArgs);
|
||||
}
|
||||
|
||||
|
||||
@@ -136,8 +144,9 @@ NTSTATUS LGIddParseMonitorDescription2(const IDARG_IN_PARSEMONITORDESCRIPTION2*
|
||||
if (!l_wdfDevice)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
auto* wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(l_wdfDevice);
|
||||
return wrapper->context->ParseMonitorDescription2(inArgs, outArgs);
|
||||
auto * wrapper = WdfObjectGet_CDeviceContextWrapper(l_wdfDevice);
|
||||
return wrapper->context->GetDisplayConfiguration().ParseMonitorDescription2(
|
||||
inArgs, outArgs);
|
||||
}
|
||||
|
||||
NTSTATUS LGIddAdapterQueryTargetInfo(IDDCX_ADAPTER adapter,
|
||||
@@ -145,7 +154,7 @@ NTSTATUS LGIddAdapterQueryTargetInfo(IDDCX_ADAPTER adapter,
|
||||
{
|
||||
UNREFERENCED_PARAMETER(inArgs);
|
||||
|
||||
auto* wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(adapter);
|
||||
auto * wrapper = WdfObjectGet_CDeviceContextWrapper(adapter);
|
||||
const bool hdr = wrapper && wrapper->context &&
|
||||
wrapper->context->CanProcessFP16();
|
||||
|
||||
@@ -182,19 +191,20 @@ NTSTATUS LGIddMonitorSetDefaultHdrMetadata(IDDCX_MONITOR monitor,
|
||||
|
||||
NTSTATUS LGIddMonitorSetGammaRamp(IDDCX_MONITOR monitor, const IDARG_IN_SET_GAMMARAMP* inArgs)
|
||||
{
|
||||
auto* wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor);
|
||||
auto* ctx = wrapper->context->GetDeviceContext();
|
||||
auto * wrapper = WdfObjectGet_CMonitorContextWrapper(monitor);
|
||||
auto * ctx = wrapper->context->GetDeviceContext();
|
||||
auto & control = ctx->GetLGMPControl();
|
||||
|
||||
if (ctx->IsSoftwareMode())
|
||||
{
|
||||
ctx->SetColorTransform(nullptr);
|
||||
control.SetColorTransform(nullptr);
|
||||
DEBUG_INFO("Ignoring display color transform in software mode");
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (inArgs->Type == IDDCX_GAMMARAMP_TYPE_DEFAULT)
|
||||
{
|
||||
ctx->SetColorTransform(nullptr);
|
||||
control.SetColorTransform(nullptr);
|
||||
DEBUG_INFO("Display color transform reset to default");
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@@ -214,7 +224,7 @@ NTSTATUS LGIddMonitorSetGammaRamp(IDDCX_MONITOR monitor, const IDARG_IN_SET_GAMM
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
const auto* input = static_cast<
|
||||
const auto * input = static_cast<
|
||||
const IDDCX_GAMMARAMP_3X4_COLORSPACE_TRANSFORM*>(
|
||||
inArgs->pGammaRampData);
|
||||
auto transform = std::make_shared<D12ColorTransform>();
|
||||
@@ -233,11 +243,11 @@ NTSTATUS LGIddMonitorSetGammaRamp(IDDCX_MONITOR monitor, const IDARG_IN_SET_GAMM
|
||||
|
||||
if (IsIdentityColorTransform(*transform))
|
||||
{
|
||||
ctx->SetColorTransform(nullptr);
|
||||
control.SetColorTransform(nullptr);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ctx->SetColorTransform(std::move(transform));
|
||||
control.SetColorTransform(std::move(transform));
|
||||
DEBUG_INFO("Display color transform updated (matrix:%d lut:%d)",
|
||||
input->MatrixEnabled, input->LutEnabled);
|
||||
return STATUS_SUCCESS;
|
||||
@@ -246,15 +256,17 @@ NTSTATUS LGIddMonitorSetGammaRamp(IDDCX_MONITOR monitor, const IDARG_IN_SET_GAMM
|
||||
NTSTATUS LGIddMonitorQueryTargetModes2(IDDCX_MONITOR monitor, const IDARG_IN_QUERYTARGETMODES2* inArgs,
|
||||
IDARG_OUT_QUERYTARGETMODES* outArgs)
|
||||
{
|
||||
auto* wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor);
|
||||
return wrapper->context->GetDeviceContext()->MonitorQueryTargetModes2(inArgs, outArgs);
|
||||
auto * wrapper = WdfObjectGet_CMonitorContextWrapper(monitor);
|
||||
auto * context = wrapper->context->GetDeviceContext();
|
||||
return context->GetDisplayConfiguration().MonitorQueryTargetModes2(
|
||||
inArgs, outArgs);
|
||||
}
|
||||
#endif
|
||||
|
||||
NTSTATUS LGIddMonitorAssignSwapChain(IDDCX_MONITOR monitor, const IDARG_IN_SETSWAPCHAIN* inArgs)
|
||||
{
|
||||
DEBUG_INFO("Swap chain assigned to monitor %p", monitor);
|
||||
auto * wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor);
|
||||
auto * wrapper = WdfObjectGet_CMonitorContextWrapper(monitor);
|
||||
return wrapper->context->AssignSwapChain(
|
||||
inArgs->hSwapChain, inArgs->RenderAdapterLuid, inArgs->hNextSurfaceAvailable);
|
||||
}
|
||||
@@ -262,7 +274,7 @@ NTSTATUS LGIddMonitorAssignSwapChain(IDDCX_MONITOR monitor, const IDARG_IN_SETSW
|
||||
NTSTATUS LGIddMonitorUnassignSwapChain(IDDCX_MONITOR monitor)
|
||||
{
|
||||
DEBUG_INFO("Swap chain unassigned from monitor %p", monitor);
|
||||
auto* wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor);
|
||||
auto * wrapper = WdfObjectGet_CMonitorContextWrapper(monitor);
|
||||
wrapper->context->UnassignSwapChain();
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@@ -316,10 +328,10 @@ NTSTATUS LGIddCreateDevice(_Inout_ PWDFDEVICE_INIT deviceInit)
|
||||
return status;
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES deviceAttributes;
|
||||
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, CIndirectDeviceContextWrapper);
|
||||
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, CDeviceContextWrapper);
|
||||
deviceAttributes.EvtCleanupCallback = [](WDFOBJECT object)
|
||||
{
|
||||
auto * wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(object);
|
||||
auto * wrapper = WdfObjectGet_CDeviceContextWrapper(object);
|
||||
if (wrapper)
|
||||
{
|
||||
g_pipe.SetDeviceContext(nullptr);
|
||||
@@ -339,8 +351,8 @@ NTSTATUS LGIddCreateDevice(_Inout_ PWDFDEVICE_INIT deviceInit)
|
||||
* callbacks that resolve the context via l_wdfDevice (down-level IddCx that
|
||||
* provides no adapter/monitor context) must never observe a null context.
|
||||
*/
|
||||
auto wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(device);
|
||||
wrapper->context = new CIndirectDeviceContext(device);
|
||||
auto wrapper = WdfObjectGet_CDeviceContextWrapper(device);
|
||||
wrapper->context = new CDeviceContext(device);
|
||||
|
||||
l_wdfDevice = device;
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
#include "driver.tmh"
|
||||
|
||||
#include "CDebug.h"
|
||||
#include "CPlatformInfo.h"
|
||||
#include "platform/CPlatformInfo.h"
|
||||
#include "VersionInfo.h"
|
||||
#include "CPipeServer.h"
|
||||
#include "transport/CPipeServer.h"
|
||||
|
||||
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
|
||||
{
|
||||
@@ -98,4 +98,4 @@ VOID LGIddEvtDriverContextCleanup(_In_ WDFOBJECT DriverObject)
|
||||
#else
|
||||
WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,68 +24,85 @@
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(SolutionDir)LGCommon/*.cpp" />
|
||||
<ClCompile Include="CD3D12CommandQueue.cpp" />
|
||||
<ClCompile Include="CEdid.cpp" />
|
||||
<ClCompile Include="CFrameBufferPool.cpp" />
|
||||
<ClCompile Include="CFrameBufferResource.cpp" />
|
||||
<ClCompile Include="CFrameProcessor.cpp" />
|
||||
<ClCompile Include="CFrameProcessorUtil.cpp" />
|
||||
<ClCompile Include="CFrameScheduler.cpp" />
|
||||
<ClCompile Include="CHardwareFrameProcessor.cpp" />
|
||||
<ClCompile Include="CIndirectDeviceContext.cpp" />
|
||||
<ClCompile Include="CIndirectMonitorContext.cpp" />
|
||||
<ClCompile Include="CInteropResourcePool.cpp" />
|
||||
<ClCompile Include="CInteropResource.cpp" />
|
||||
<ClCompile Include="CIVSHMEM.cpp" />
|
||||
<ClCompile Include="CPipeServer.cpp" />
|
||||
<ClCompile Include="CPlatformInfo.cpp" />
|
||||
<ClCompile Include="CPostProcessor.cpp" />
|
||||
<ClCompile Include="effect\CColorTransformEffect.cpp" />
|
||||
<ClCompile Include="effect\CComputeEffect.cpp" />
|
||||
<ClCompile Include="effect\CDownsampleEffect.cpp" />
|
||||
<ClCompile Include="effect\CHDR16to10Effect.cpp" />
|
||||
<ClCompile Include="effect\CRGB24Effect.cpp" />
|
||||
<ClCompile Include="CSettings.cpp" />
|
||||
<ClCompile Include="CSoftwareFrameProcessor.cpp" />
|
||||
<ClCompile Include="CSwapChainProcessor.cpp" />
|
||||
<ClCompile Include="CD3D12Device.cpp" />
|
||||
<ClCompile Include="$(SolutionDir)LGCommon\*.cpp" />
|
||||
<ClCompile Include="Device.cpp" />
|
||||
<ClCompile Include="CD3D11Device.cpp" />
|
||||
<ClCompile Include="Driver.cpp" />
|
||||
<ClCompile Include="display\CDisplayConfiguration.cpp" />
|
||||
<ClCompile Include="display\CEdid.cpp" />
|
||||
<ClCompile Include="display\CMonitorManager.cpp" />
|
||||
<ClCompile Include="display\device\CDeviceContext.cpp" />
|
||||
<ClCompile Include="display\monitor\Context.cpp" />
|
||||
<ClCompile Include="capture\CFrameBufferPool.cpp" />
|
||||
<ClCompile Include="capture\CFrameBufferResource.cpp" />
|
||||
<ClCompile Include="capture\CFrameProcessor.cpp" />
|
||||
<ClCompile Include="capture\CFrameProcessorUtil.cpp" />
|
||||
<ClCompile Include="capture\CFrameScheduler.cpp" />
|
||||
<ClCompile Include="capture\CHardwareFrameProcessor.cpp" />
|
||||
<ClCompile Include="capture\CSoftwareFrameProcessor.cpp" />
|
||||
<ClCompile Include="capture\CSwapChainCursor.cpp" />
|
||||
<ClCompile Include="capture\CSwapChainProcessor.cpp" />
|
||||
<ClCompile Include="capture\CSwapChainPublisher.cpp" />
|
||||
<ClCompile Include="d3d\CD3D11Device.cpp" />
|
||||
<ClCompile Include="d3d\CD3D12CommandQueue.cpp" />
|
||||
<ClCompile Include="d3d\CD3D12Device.cpp" />
|
||||
<ClCompile Include="d3d\CInteropResource.cpp" />
|
||||
<ClCompile Include="d3d\CInteropResourcePool.cpp" />
|
||||
<ClCompile Include="postprocess\CPostProcessor.cpp" />
|
||||
<ClCompile Include="postprocess\effect\CColorTransformEffect.cpp" />
|
||||
<ClCompile Include="postprocess\effect\CComputeEffect.cpp" />
|
||||
<ClCompile Include="postprocess\effect\CDownsampleEffect.cpp" />
|
||||
<ClCompile Include="postprocess\effect\CHDR16to10Effect.cpp" />
|
||||
<ClCompile Include="postprocess\effect\CRGB24Effect.cpp" />
|
||||
<ClCompile Include="transport\CFrameTransport.cpp" />
|
||||
<ClCompile Include="transport\CIVSHMEM.cpp" />
|
||||
<ClCompile Include="transport\CLGMPControl.cpp" />
|
||||
<ClCompile Include="transport\CLGMPHost.cpp" />
|
||||
<ClCompile Include="transport\CPipeServer.cpp" />
|
||||
<ClCompile Include="config\CSettings.cpp" />
|
||||
<ClCompile Include="platform\CPlatformInfo.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(SolutionDir)/LGCommon/*.h" />
|
||||
<ClInclude Include="CD3D12CommandQueue.h" />
|
||||
<ClInclude Include="CEdid.h" />
|
||||
<ClInclude Include="CFrameBufferPool.h" />
|
||||
<ClInclude Include="CFrameBufferResource.h" />
|
||||
<ClInclude Include="CFrameProcessor.h" />
|
||||
<ClInclude Include="CFrameProcessorUtil.h" />
|
||||
<ClInclude Include="CFrameScheduler.h" />
|
||||
<ClInclude Include="CHardwareFrameProcessor.h" />
|
||||
<ClInclude Include="CIndirectMonitorContext.h" />
|
||||
<ClInclude Include="CInteropResourcePool.h" />
|
||||
<ClInclude Include="CInteropResource.h" />
|
||||
<ClInclude Include="CIVSHMEM.h" />
|
||||
<ClInclude Include="CPipeServer.h" />
|
||||
<ClInclude Include="CPlatformInfo.h" />
|
||||
<ClInclude Include="CPostProcessor.h" />
|
||||
<ClInclude Include="effect\CColorTransformEffect.h" />
|
||||
<ClInclude Include="effect\CComputeEffect.h" />
|
||||
<ClInclude Include="effect\CDownsampleEffect.h" />
|
||||
<ClInclude Include="effect\CHDR16to10Effect.h" />
|
||||
<ClInclude Include="effect\CRGB24Effect.h" />
|
||||
<ClInclude Include="CSettings.h" />
|
||||
<ClInclude Include="CSoftwareFrameProcessor.h" />
|
||||
<ClInclude Include="CSwapChainProcessor.h" />
|
||||
<ClInclude Include="CD3D12Device.h" />
|
||||
<ClInclude Include="$(SolutionDir)LGCommon\*.h" />
|
||||
<ClInclude Include="Device.h" />
|
||||
<ClInclude Include="CD3D11Device.h" />
|
||||
<ClInclude Include="Driver.h" />
|
||||
<ClInclude Include="CIndirectDeviceContext.h" />
|
||||
<ClInclude Include="Public.h" />
|
||||
<ClInclude Include="Trace.h" />
|
||||
<ClInclude Include="display\CDisplayConfiguration.h" />
|
||||
<ClInclude Include="display\CEdid.h" />
|
||||
<ClInclude Include="display\CMonitorManager.h" />
|
||||
<ClInclude Include="display\IddCxCompat.h" />
|
||||
<ClInclude Include="display\device\CDeviceContext.h" />
|
||||
<ClInclude Include="display\monitor\Context.h" />
|
||||
<ClInclude Include="capture\CFrameBufferPool.h" />
|
||||
<ClInclude Include="capture\CFrameBufferResource.h" />
|
||||
<ClInclude Include="capture\FrameBufferTypes.h" />
|
||||
<ClInclude Include="capture\CFrameProcessor.h" />
|
||||
<ClInclude Include="capture\CFrameProcessorUtil.h" />
|
||||
<ClInclude Include="capture\CFrameScheduler.h" />
|
||||
<ClInclude Include="capture\CHardwareFrameProcessor.h" />
|
||||
<ClInclude Include="capture\CSoftwareFrameProcessor.h" />
|
||||
<ClInclude Include="capture\CSwapChainProcessor.h" />
|
||||
<ClInclude Include="d3d\CD3D11Device.h" />
|
||||
<ClInclude Include="d3d\CD3D12CommandQueue.h" />
|
||||
<ClInclude Include="d3d\CD3D12Device.h" />
|
||||
<ClInclude Include="d3d\CInteropResource.h" />
|
||||
<ClInclude Include="d3d\CInteropResourcePool.h" />
|
||||
<ClInclude Include="postprocess\CPostProcessor.h" />
|
||||
<ClInclude Include="postprocess\D12FrameFormat.h" />
|
||||
<ClInclude Include="postprocess\effect\CColorTransformEffect.h" />
|
||||
<ClInclude Include="postprocess\effect\CComputeEffect.h" />
|
||||
<ClInclude Include="postprocess\effect\CDownsampleEffect.h" />
|
||||
<ClInclude Include="postprocess\effect\CHDR16to10Effect.h" />
|
||||
<ClInclude Include="postprocess\effect\CRGB24Effect.h" />
|
||||
<ClInclude Include="transport\CFrameTransport.h" />
|
||||
<ClInclude Include="transport\CIVSHMEM.h" />
|
||||
<ClInclude Include="transport\CLGMPControl.h" />
|
||||
<ClInclude Include="transport\CLGMPHost.h" />
|
||||
<ClInclude Include="transport\CPipeServer.h" />
|
||||
<ClInclude Include="transport\FrameMemoryLimits.h" />
|
||||
<ClInclude Include="config\CSettings.h" />
|
||||
<ClInclude Include="platform\CPlatformInfo.h" />
|
||||
<ClInclude Include="util\CSRWLock.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Inf Include="LGIdd.inf" />
|
||||
@@ -198,7 +215,7 @@
|
||||
<WppRecorderEnabled>true</WppRecorderEnabled>
|
||||
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
|
||||
<AdditionalOptions>/EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=10 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)LGCommon;$(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib;d3dcompiler.lib</AdditionalDependencies>
|
||||
@@ -213,7 +230,7 @@
|
||||
<WppRecorderEnabled>true</WppRecorderEnabled>
|
||||
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
|
||||
<AdditionalOptions>/EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=10 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)LGCommon;$(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib;d3dcompiler.lib</AdditionalDependencies>
|
||||
@@ -228,7 +245,7 @@
|
||||
<WppRecorderEnabled>true</WppRecorderEnabled>
|
||||
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
|
||||
<AdditionalOptions>/EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=10 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)LGCommon;$(SolutionDir)..\repos\LGMP\lgmp\include;$(SolutionDir)..\vendor;$(SolutionDir)..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)LGCommon;$(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib;d3dcompiler.lib</AdditionalDependencies>
|
||||
@@ -243,7 +260,7 @@
|
||||
<WppRecorderEnabled>true</WppRecorderEnabled>
|
||||
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
|
||||
<AdditionalOptions>/EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=10 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)LGCommon;$(SolutionDir)..\repos\LGMP\lgmp\include;$(SolutionDir)..\vendor;$(SolutionDir)..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)LGCommon;$(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib;d3dcompiler.lib</AdditionalDependencies>
|
||||
|
||||
@@ -1,27 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="4.0"
|
||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<Filter Include="Driver">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
<Filter Include="Display">
|
||||
<UniqueIdentifier>{D2C16E51-6087-4E08-8DA4-5AD1A60EF58E}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
<Filter Include="Display\Device">
|
||||
<UniqueIdentifier>{83AAC4D0-9E4C-4B25-BD54-9186713B2010}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Driver Files">
|
||||
<UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
|
||||
<Extensions>inf;inv;inx;mof;mc;</Extensions>
|
||||
<Filter Include="Display\Monitor">
|
||||
<UniqueIdentifier>{3AF4227D-EBC0-45FB-9670-192E371313D5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\effect">
|
||||
<Filter Include="Capture">
|
||||
<UniqueIdentifier>{202B79B2-5CCF-4AD4-B4C5-F5602419683D}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="D3D">
|
||||
<UniqueIdentifier>{4B3C58D3-5F40-49AB-894E-B83EB44E6CF5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Post-processing">
|
||||
<UniqueIdentifier>{A2E40D7C-854F-42E2-8730-A1BFD37A6BB0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Post-processing\Effects">
|
||||
<UniqueIdentifier>{52F1286F-0C64-41B9-92A9-4453C80B1001}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\effect">
|
||||
<UniqueIdentifier>{DB623F3B-5D6A-4F8C-8884-83588A1B58D2}</UniqueIdentifier>
|
||||
<Filter Include="Transport">
|
||||
<UniqueIdentifier>{22FDF1F6-0A8C-4B96-9E74-53D74733CC0A}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Configuration">
|
||||
<UniqueIdentifier>{82810F1C-E51C-4DBD-86B2-1CDE8C16A2A9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Platform">
|
||||
<UniqueIdentifier>{1C677205-7587-4037-9E36-92DFE600B985}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Common">
|
||||
<UniqueIdentifier>{938E49D6-F954-4EBE-80AB-E0F67E677F27}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Utilities">
|
||||
<UniqueIdentifier>{98768720-86D6-4A83-9EBD-2C8BFB51D793}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -30,187 +48,242 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Inf Include="LGIdd.inf">
|
||||
<Filter>Driver Files</Filter>
|
||||
<Filter>Driver</Filter>
|
||||
</Inf>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(SolutionDir)LGCommon\*.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Device.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<Filter>Driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Driver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<Filter>Driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Public.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<Filter>Driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<Filter>Driver</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CIndirectDeviceContext.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="display\CDisplayConfiguration.h">
|
||||
<Filter>Display</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CIndirectMonitorContext.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="display\CEdid.h">
|
||||
<Filter>Display</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CSwapChainProcessor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="display\CMonitorManager.h">
|
||||
<Filter>Display</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CIVSHMEM.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="display\IddCxCompat.h">
|
||||
<Filter>Display</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CPlatformInfo.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="display\device\CDeviceContext.h">
|
||||
<Filter>Display\Device</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CD3D12CommandQueue.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="display\monitor\Context.h">
|
||||
<Filter>Display\Monitor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CInteropResourcePool.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="capture\CFrameBufferPool.h">
|
||||
<Filter>Capture</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CInteropResource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="capture\CFrameBufferResource.h">
|
||||
<Filter>Capture</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CD3D12Device.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="capture\FrameBufferTypes.h">
|
||||
<Filter>Capture</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CD3D11Device.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="capture\CFrameProcessor.h">
|
||||
<Filter>Capture</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CFrameBufferResource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="capture\CFrameProcessorUtil.h">
|
||||
<Filter>Capture</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CFrameBufferPool.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="capture\CFrameScheduler.h">
|
||||
<Filter>Capture</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CFrameProcessor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="capture\CHardwareFrameProcessor.h">
|
||||
<Filter>Capture</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CFrameProcessorUtil.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="capture\CSoftwareFrameProcessor.h">
|
||||
<Filter>Capture</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CHardwareFrameProcessor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="capture\CSwapChainProcessor.h">
|
||||
<Filter>Capture</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CFrameScheduler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="d3d\CD3D11Device.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SolutionDir)/LGCommon/*.h" />
|
||||
<ClInclude Include="CPipeServer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="d3d\CD3D12CommandQueue.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SolutionDir)/LGCommon/*.h" />
|
||||
<ClInclude Include="$(SolutionDir)/LGCommon/*.h" />
|
||||
<ClInclude Include="CSettings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="d3d\CD3D12Device.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CPostProcessor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="d3d\CInteropResource.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CSoftwareFrameProcessor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="d3d\CInteropResourcePool.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="effect\CColorTransformEffect.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="postprocess\CPostProcessor.h">
|
||||
<Filter>Post-processing</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="effect\CComputeEffect.h">
|
||||
<Filter>Header Files\effect</Filter>
|
||||
<ClInclude Include="postprocess\D12FrameFormat.h">
|
||||
<Filter>Post-processing</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="effect\CDownsampleEffect.h">
|
||||
<Filter>Header Files\effect</Filter>
|
||||
<ClInclude Include="postprocess\effect\CColorTransformEffect.h">
|
||||
<Filter>Post-processing\Effects</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="effect\CHDR16to10Effect.h">
|
||||
<Filter>Header Files\effect</Filter>
|
||||
<ClInclude Include="postprocess\effect\CComputeEffect.h">
|
||||
<Filter>Post-processing\Effects</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="effect\CRGB24Effect.h">
|
||||
<Filter>Header Files\effect</Filter>
|
||||
<ClInclude Include="postprocess\effect\CDownsampleEffect.h">
|
||||
<Filter>Post-processing\Effects</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="postprocess\effect\CHDR16to10Effect.h">
|
||||
<Filter>Post-processing\Effects</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="postprocess\effect\CRGB24Effect.h">
|
||||
<Filter>Post-processing\Effects</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="transport\CFrameTransport.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>
|
||||
</ClInclude>
|
||||
<ClInclude Include="transport\CPipeServer.h">
|
||||
<Filter>Transport</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="transport\FrameMemoryLimits.h">
|
||||
<Filter>Transport</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="config\CSettings.h">
|
||||
<Filter>Configuration</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="platform\CPlatformInfo.h">
|
||||
<Filter>Platform</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\CSRWLock.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SolutionDir)/LGCommon/*.h" />
|
||||
<ClInclude Include="$(SolutionDir)/LGCommon/*.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Device.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="$(SolutionDir)LGCommon\*.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Driver.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<Filter>Driver</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CIndirectDeviceContext.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="Device.cpp">
|
||||
<Filter>Driver</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CFrameScheduler.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="display\CDisplayConfiguration.cpp">
|
||||
<Filter>Display</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CIndirectMonitorContext.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="display\CEdid.cpp">
|
||||
<Filter>Display</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CSwapChainProcessor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="display\CMonitorManager.cpp">
|
||||
<Filter>Display</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CIVSHMEM.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="display\device\CDeviceContext.cpp">
|
||||
<Filter>Display\Device</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CPlatformInfo.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="display\monitor\Context.cpp">
|
||||
<Filter>Display\Monitor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CD3D12CommandQueue.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="capture\CFrameBufferPool.cpp">
|
||||
<Filter>Capture</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CInteropResourcePool.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="capture\CFrameBufferResource.cpp">
|
||||
<Filter>Capture</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CInteropResource.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="capture\CFrameProcessor.cpp">
|
||||
<Filter>Capture</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CD3D12Device.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="capture\CFrameProcessorUtil.cpp">
|
||||
<Filter>Capture</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CD3D11Device.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="capture\CFrameScheduler.cpp">
|
||||
<Filter>Capture</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CFrameBufferResource.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="capture\CHardwareFrameProcessor.cpp">
|
||||
<Filter>Capture</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CFrameBufferPool.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="capture\CSoftwareFrameProcessor.cpp">
|
||||
<Filter>Capture</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CFrameProcessor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="capture\CSwapChainCursor.cpp">
|
||||
<Filter>Capture</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CFrameProcessorUtil.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="capture\CSwapChainProcessor.cpp">
|
||||
<Filter>Capture</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CHardwareFrameProcessor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="capture\CSwapChainPublisher.cpp">
|
||||
<Filter>Capture</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(SolutionDir)LGCommon/*.cpp" />
|
||||
<ClCompile Include="CPipeServer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="d3d\CD3D11Device.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(SolutionDir)LGCommon/*.cpp" />
|
||||
<ClCompile Include="CSettings.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="d3d\CD3D12CommandQueue.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CPostProcessor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="d3d\CD3D12Device.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CSoftwareFrameProcessor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="d3d\CInteropResource.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="effect\CColorTransformEffect.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClCompile Include="d3d\CInteropResourcePool.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="effect\CComputeEffect.cpp">
|
||||
<Filter>Source Files\effect</Filter>
|
||||
<ClCompile Include="postprocess\CPostProcessor.cpp">
|
||||
<Filter>Post-processing</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="effect\CDownsampleEffect.cpp">
|
||||
<Filter>Source Files\effect</Filter>
|
||||
<ClCompile Include="postprocess\effect\CColorTransformEffect.cpp">
|
||||
<Filter>Post-processing\Effects</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="effect\CHDR16to10Effect.cpp">
|
||||
<Filter>Source Files\effect</Filter>
|
||||
<ClCompile Include="postprocess\effect\CComputeEffect.cpp">
|
||||
<Filter>Post-processing\Effects</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="effect\CRGB24Effect.cpp">
|
||||
<Filter>Source Files\effect</Filter>
|
||||
<ClCompile Include="postprocess\effect\CDownsampleEffect.cpp">
|
||||
<Filter>Post-processing\Effects</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="postprocess\effect\CHDR16to10Effect.cpp">
|
||||
<Filter>Post-processing\Effects</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="postprocess\effect\CRGB24Effect.cpp">
|
||||
<Filter>Post-processing\Effects</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="transport\CFrameTransport.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>
|
||||
</ClCompile>
|
||||
<ClCompile Include="transport\CPipeServer.cpp">
|
||||
<Filter>Transport</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="config\CSettings.cpp">
|
||||
<Filter>Configuration</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="platform\CPlatformInfo.cpp">
|
||||
<Filter>Platform</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(SolutionDir)LGCommon/*.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -18,15 +18,15 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CFrameBufferPool.h"
|
||||
#include "capture/CFrameBufferPool.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void CFrameBufferPool::Init(
|
||||
CIndirectDeviceContext * device, CD3D12Device * dx12)
|
||||
CFrameTransport * transport, CD3D12Device * dx12)
|
||||
{
|
||||
m_device = device;
|
||||
m_dx12 = dx12;
|
||||
m_transport = transport;
|
||||
m_dx12 = dx12;
|
||||
}
|
||||
|
||||
void CFrameBufferPool::Reset()
|
||||
@@ -36,14 +36,14 @@ void CFrameBufferPool::Reset()
|
||||
}
|
||||
|
||||
CFrameBufferResource * CFrameBufferPool::Get(
|
||||
const CIndirectDeviceContext::PreparedFrameBuffer& buffer,
|
||||
const PreparedFrameBuffer& buffer,
|
||||
size_t minSize, const D3D12_RESOURCE_DESC * textureDesc)
|
||||
{
|
||||
if (buffer.frameIndex > ARRAYSIZE(m_buffers) - 1)
|
||||
return nullptr;
|
||||
|
||||
CFrameBufferResource * fbr = &m_buffers[buffer.frameIndex];
|
||||
if (!fbr->Init(m_device, m_dx12, buffer.frameIndex, buffer.mem,
|
||||
if (!fbr->Init(m_transport, m_dx12, buffer.frameIndex, buffer.mem,
|
||||
minSize, textureDesc))
|
||||
return nullptr;
|
||||
|
||||
@@ -20,25 +20,26 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CFrameBufferResource.h"
|
||||
#include "CIndirectDeviceContext.h"
|
||||
#include "capture/CFrameBufferResource.h"
|
||||
#include "capture/FrameBufferTypes.h"
|
||||
#include "common/KVMFR.h"
|
||||
|
||||
struct CD3D12Device;
|
||||
class CFrameTransport;
|
||||
|
||||
class CFrameBufferPool
|
||||
{
|
||||
CIndirectDeviceContext * m_device = nullptr;
|
||||
CD3D12Device * m_dx12 = nullptr;
|
||||
private:
|
||||
CFrameTransport * m_transport = nullptr;
|
||||
CD3D12Device * m_dx12 = nullptr;
|
||||
|
||||
CFrameBufferResource m_buffers[LGMP_Q_FRAME_BUFFER_LEN];
|
||||
|
||||
public:
|
||||
void Init(CIndirectDeviceContext * device, CD3D12Device * dx12);
|
||||
void Reset();
|
||||
public:
|
||||
void Init(CFrameTransport * transport, CD3D12Device * dx12);
|
||||
void Reset();
|
||||
|
||||
CFrameBufferResource * Get(
|
||||
const CIndirectDeviceContext::PreparedFrameBuffer& buffer,
|
||||
size_t minSize,
|
||||
const D3D12_RESOURCE_DESC * textureDesc = nullptr);
|
||||
CFrameBufferResource * Get(const PreparedFrameBuffer& buffer,
|
||||
size_t minSize,
|
||||
const D3D12_RESOURCE_DESC * textureDesc = nullptr);
|
||||
};
|
||||
@@ -18,21 +18,22 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CFrameBufferResource.h"
|
||||
#include "CFrameProcessorUtil.h"
|
||||
#include "CD3D12Device.h"
|
||||
#include "CIndirectDeviceContext.h"
|
||||
#include "capture/CFrameBufferResource.h"
|
||||
#include "capture/CFrameProcessorUtil.h"
|
||||
#include "d3d/CD3D12Device.h"
|
||||
#include "transport/CFrameTransport.h"
|
||||
#include "transport/CIVSHMEM.h"
|
||||
#include "CDebug.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
bool CFrameBufferResource::Init(CIndirectDeviceContext * device,
|
||||
bool CFrameBufferResource::Init(CFrameTransport * transport,
|
||||
CD3D12Device * dx12, unsigned frameIndex, uint8_t * base, size_t size,
|
||||
const D3D12_RESOURCE_DESC * textureDesc)
|
||||
{
|
||||
m_frameIndex = frameIndex;
|
||||
|
||||
if (size > device->GetMaxFrameSize())
|
||||
if (size > transport->GetMaxFrameSize())
|
||||
{
|
||||
DEBUG_ERROR("Frame size of %llu is too large to fit in shared ram",
|
||||
(unsigned long long)size);
|
||||
@@ -131,14 +132,14 @@ bool CFrameBufferResource::Init(CIndirectDeviceContext * device,
|
||||
{
|
||||
const UINT64 heapOffset =
|
||||
(uintptr_t)base -
|
||||
(uintptr_t)device->GetIVSHMEM().GetMem();
|
||||
(uintptr_t)transport->GetIVSHMEM().GetMem();
|
||||
const D3D12_RESOURCE_ALLOCATION_INFO allocation =
|
||||
dx12->GetDevice()->GetResourceAllocationInfo(0, 1, &desc);
|
||||
allocationSize = allocation.SizeInBytes;
|
||||
const D3D12_HEAP_DESC heapDesc = dx12->GetHeap()->GetDesc();
|
||||
if (!allocation.Alignment ||
|
||||
heapOffset % allocation.Alignment ||
|
||||
allocation.SizeInBytes > device->GetMaxFrameSize() ||
|
||||
allocation.SizeInBytes > transport->GetMaxFrameSize() ||
|
||||
heapOffset > heapDesc.SizeInBytes ||
|
||||
allocation.SizeInBytes > heapDesc.SizeInBytes - heapOffset)
|
||||
{
|
||||
@@ -27,11 +27,11 @@
|
||||
#include <atomic>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "CFrameScheduler.h"
|
||||
#include "CInteropResource.h"
|
||||
#include "capture/CFrameScheduler.h"
|
||||
#include "d3d/CInteropResource.h"
|
||||
|
||||
struct CD3D12Device;
|
||||
class CIndirectDeviceContext;
|
||||
class CFrameTransport;
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
@@ -70,7 +70,7 @@ class CFrameBufferResource
|
||||
void * m_map = nullptr;
|
||||
|
||||
public:
|
||||
bool Init(CIndirectDeviceContext * device, CD3D12Device * dx12,
|
||||
bool Init(CFrameTransport * transport, CD3D12Device * dx12,
|
||||
unsigned frameIndex, uint8_t * base, size_t size,
|
||||
const D3D12_RESOURCE_DESC * textureDesc = nullptr);
|
||||
void Reset();
|
||||
@@ -18,27 +18,27 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CFrameProcessor.h"
|
||||
#include "CFrameProcessorUtil.h"
|
||||
#include "CHardwareFrameProcessor.h"
|
||||
#include "CSoftwareFrameProcessor.h"
|
||||
#include "capture/CFrameProcessor.h"
|
||||
#include "capture/CFrameProcessorUtil.h"
|
||||
#include "capture/CHardwareFrameProcessor.h"
|
||||
#include "capture/CSoftwareFrameProcessor.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
CFrameProcessor::CFrameProcessor(CIndirectDeviceContext * device,
|
||||
CFrameProcessor::CFrameProcessor(CFrameTransport * transport,
|
||||
std::shared_ptr<CD3D12Device> dx12,
|
||||
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN],
|
||||
SRWLOCK * pipelineLock, HANDLE terminateEvent) :
|
||||
m_device(device),
|
||||
m_transport(transport),
|
||||
m_dx12(std::move(dx12)),
|
||||
m_postProcessors(postProcessors),
|
||||
m_pipelineLock(pipelineLock),
|
||||
m_terminateEvent(terminateEvent)
|
||||
{
|
||||
m_readyEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr));
|
||||
m_frameBuffers.Init(m_device, m_dx12.get());
|
||||
m_frameBuffers.Init(m_transport, m_dx12.get());
|
||||
}
|
||||
|
||||
bool CFrameProcessor::IsValid() const
|
||||
@@ -154,7 +154,7 @@ void CFrameProcessor::GetPreviousDamage(
|
||||
}
|
||||
|
||||
std::unique_ptr<CFrameProcessor> CreateFrameProcessor(
|
||||
bool software, CIndirectDeviceContext * device,
|
||||
bool software, CFrameTransport * transport,
|
||||
std::shared_ptr<CD3D12Device> dx12,
|
||||
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN],
|
||||
SRWLOCK * pipelineLock, HANDLE terminateEvent)
|
||||
@@ -162,11 +162,11 @@ std::unique_ptr<CFrameProcessor> CreateFrameProcessor(
|
||||
std::unique_ptr<CFrameProcessor> processor;
|
||||
if (software)
|
||||
processor.reset(new (std::nothrow) CSoftwareFrameProcessor(
|
||||
device, std::move(dx12), postProcessors,
|
||||
transport, std::move(dx12), postProcessors,
|
||||
pipelineLock, terminateEvent));
|
||||
else
|
||||
processor.reset(new (std::nothrow) CHardwareFrameProcessor(
|
||||
device, std::move(dx12), postProcessors,
|
||||
transport, std::move(dx12), postProcessors,
|
||||
pipelineLock, terminateEvent));
|
||||
|
||||
if (!processor || !processor->IsValid())
|
||||
@@ -20,17 +20,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CD3D12Device.h"
|
||||
#include "CFrameBufferPool.h"
|
||||
#include "CIndirectDeviceContext.h"
|
||||
#include "CInteropResource.h"
|
||||
#include "CPostProcessor.h"
|
||||
#include "d3d/CD3D12Device.h"
|
||||
#include "capture/CFrameBufferPool.h"
|
||||
#include "d3d/CInteropResource.h"
|
||||
#include "postprocess/CPostProcessor.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <memory>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
class CFrameTransport;
|
||||
|
||||
struct FrameSubmission
|
||||
{
|
||||
CInteropResource * source;
|
||||
@@ -45,13 +46,13 @@ struct FrameSubmission
|
||||
class CFrameProcessor
|
||||
{
|
||||
protected:
|
||||
CIndirectDeviceContext * m_device;
|
||||
std::shared_ptr<CD3D12Device> m_dx12;
|
||||
CPostProcessor * m_postProcessors;
|
||||
SRWLOCK * m_pipelineLock;
|
||||
HANDLE m_terminateEvent;
|
||||
CFrameBufferPool m_frameBuffers;
|
||||
Wrappers::Event m_readyEvent;
|
||||
CFrameTransport * m_transport;
|
||||
std::shared_ptr<CD3D12Device> m_dx12;
|
||||
CPostProcessor * m_postProcessors;
|
||||
SRWLOCK * m_pipelineLock;
|
||||
HANDLE m_terminateEvent;
|
||||
CFrameBufferPool m_frameBuffers;
|
||||
Wrappers::Event m_readyEvent;
|
||||
|
||||
mutable SRWLOCK m_damageLock = SRWLOCK_INIT;
|
||||
RECT m_previousDamage[LG_MAX_DIRTY_RECTS] = {};
|
||||
@@ -71,7 +72,7 @@ protected:
|
||||
virtual void SetFullDamageLocked();
|
||||
|
||||
public:
|
||||
CFrameProcessor(CIndirectDeviceContext * device,
|
||||
CFrameProcessor(CFrameTransport * transport,
|
||||
std::shared_ptr<CD3D12Device> dx12,
|
||||
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN],
|
||||
SRWLOCK * pipelineLock, HANDLE terminateEvent);
|
||||
@@ -93,7 +94,7 @@ public:
|
||||
};
|
||||
|
||||
std::unique_ptr<CFrameProcessor> CreateFrameProcessor(
|
||||
bool software, CIndirectDeviceContext * device,
|
||||
bool software, CFrameTransport * transport,
|
||||
std::shared_ptr<CD3D12Device> dx12,
|
||||
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN],
|
||||
SRWLOCK * pipelineLock, HANDLE terminateEvent);
|
||||
@@ -18,7 +18,9 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CFrameProcessorUtil.h"
|
||||
#include "capture/CFrameProcessorUtil.h"
|
||||
#include "d3d/CInteropResource.h"
|
||||
#include "postprocess/CPostProcessor.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -20,25 +20,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CInteropResource.h"
|
||||
#include "CPostProcessor.h"
|
||||
#include "postprocess/D12FrameFormat.h"
|
||||
|
||||
class CFrameProcessorSharedLock
|
||||
{
|
||||
private:
|
||||
SRWLOCK * m_lock;
|
||||
|
||||
public:
|
||||
explicit CFrameProcessorSharedLock(SRWLOCK * lock) : m_lock(lock)
|
||||
{
|
||||
AcquireSRWLockShared(m_lock);
|
||||
}
|
||||
|
||||
~CFrameProcessorSharedLock()
|
||||
{
|
||||
ReleaseSRWLockShared(m_lock);
|
||||
}
|
||||
};
|
||||
class CPostProcessor;
|
||||
|
||||
class CFrameProcessorUtil
|
||||
{
|
||||
@@ -18,7 +18,7 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CFrameScheduler.h"
|
||||
#include "capture/CFrameScheduler.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CHardwareFrameProcessor.h"
|
||||
#include "CFrameProcessorUtil.h"
|
||||
#include "capture/CHardwareFrameProcessor.h"
|
||||
#include "capture/CFrameProcessorUtil.h"
|
||||
#include "transport/CFrameTransport.h"
|
||||
#include "util/CSRWLock.h"
|
||||
#include "CDebug.h"
|
||||
|
||||
#include <cstring>
|
||||
@@ -69,10 +71,10 @@ public:
|
||||
};
|
||||
|
||||
CHardwareFrameProcessor::CHardwareFrameProcessor(
|
||||
CIndirectDeviceContext * device, std::shared_ptr<CD3D12Device> dx12,
|
||||
CFrameTransport * transport, std::shared_ptr<CD3D12Device> dx12,
|
||||
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN],
|
||||
SRWLOCK * pipelineLock, HANDLE terminateEvent) :
|
||||
CFrameProcessor(device, std::move(dx12), postProcessors,
|
||||
CFrameProcessor(transport, std::move(dx12), postProcessors,
|
||||
pipelineLock, terminateEvent)
|
||||
{
|
||||
m_candidateAvailableEvent.Attach(
|
||||
@@ -203,7 +205,7 @@ int CHardwareFrameProcessor::AcquireCandidate(
|
||||
ReleaseSRWLockExclusive(&m_candidateLock);
|
||||
|
||||
if (superseded)
|
||||
m_device->FrameSuperseded();
|
||||
m_transport->FrameSuperseded();
|
||||
return selected;
|
||||
}
|
||||
|
||||
@@ -327,10 +329,10 @@ void CHardwareFrameProcessor::CandidateCompletionFunction(
|
||||
if (!result)
|
||||
{
|
||||
processor->SetFullDamage();
|
||||
processor->m_device->ForceFrame();
|
||||
processor->m_transport->ForceFrame();
|
||||
}
|
||||
else if (forceFrame)
|
||||
processor->m_device->ForceFrame();
|
||||
processor->m_transport->ForceFrame();
|
||||
processor->SignalCandidateState();
|
||||
}
|
||||
|
||||
@@ -343,9 +345,9 @@ void CHardwareFrameProcessor::CompletionFunction(
|
||||
|
||||
if (!result)
|
||||
{
|
||||
processor->m_device->FailFrameBuffer(fbRes->GetFrameIndex());
|
||||
processor->m_transport->FailFrameBuffer(fbRes->GetFrameIndex());
|
||||
processor->SetFullDamage();
|
||||
processor->m_device->ForceFrame();
|
||||
processor->m_transport->ForceFrame();
|
||||
processor->ReleaseCandidate(candidateIndex);
|
||||
return;
|
||||
}
|
||||
@@ -374,7 +376,7 @@ void CHardwareFrameProcessor::CompletionFunction(
|
||||
if (processor->m_dx12->IsIndirectCopy())
|
||||
{
|
||||
const uint64_t indirectCopyStart = CFrameScheduler::Nanotime();
|
||||
processor->m_device->WriteFrameBuffer(
|
||||
processor->m_transport->WriteFrameBuffer(
|
||||
fbRes->GetFrameIndex(), fbRes->GetMap(), 0,
|
||||
fbRes->GetFrameSize(), false);
|
||||
indirectCopyTime = CFrameScheduler::Nanotime() - indirectCopyStart;
|
||||
@@ -401,7 +403,7 @@ void CHardwareFrameProcessor::CompletionFunction(
|
||||
|
||||
const uint64_t copyTime = prepareCopyTime + publishCopyTime;
|
||||
|
||||
processor->m_device->FinalizeFrameBuffer(fbRes->GetFrameIndex());
|
||||
processor->m_transport->FinalizeFrameBuffer(fbRes->GetFrameIndex());
|
||||
const uint64_t publishedAt = CFrameScheduler::Nanotime();
|
||||
const uint64_t prepareElapsed = prepareReady >= postProcessStart ?
|
||||
prepareReady - postProcessStart : 0;
|
||||
@@ -416,10 +418,10 @@ void CHardwareFrameProcessor::CompletionFunction(
|
||||
const uint64_t holdTime = publishStart >= prepareReady ?
|
||||
publishStart - prepareReady : 0;
|
||||
|
||||
processor->m_device->SetFrameTiming(fbRes->GetFrameIndex(),
|
||||
processor->m_transport->SetFrameTiming(fbRes->GetFrameIndex(),
|
||||
fbRes->GetCaptureTime(), postProcessTime, copyTime, readyTime, holdTime,
|
||||
fbRes->GetSchedule(), publishedAt);
|
||||
processor->m_device->TryRecordFrameTiming(publishedAt - publishStart);
|
||||
processor->m_transport->TryRecordFrameTiming(publishedAt - publishStart);
|
||||
|
||||
const uint64_t timingToken = fbRes->GetTimingToken();
|
||||
if (timingToken && timingStart && prepareReady >= timingStart &&
|
||||
@@ -432,7 +434,7 @@ void CHardwareFrameProcessor::CompletionFunction(
|
||||
fbRes->IsFullCopy(), totalTime);
|
||||
}
|
||||
|
||||
processor->m_device->CompleteFrameBuffer(fbRes->GetFrameIndex(), true);
|
||||
processor->m_transport->CompleteFrameBuffer(fbRes->GetFrameIndex(), true);
|
||||
processor->ReleaseCandidate(candidateIndex);
|
||||
}
|
||||
|
||||
@@ -442,7 +444,7 @@ bool CHardwareFrameProcessor::Publish(
|
||||
{
|
||||
CPublishPending publishPending(
|
||||
&m_copySubmitLock, &m_publishPending, m_copySubmitEvent.Get());
|
||||
CFrameProcessorSharedLock pipelineLock(m_pipelineLock);
|
||||
CSRWSharedLock pipelineLock(m_pipelineLock);
|
||||
|
||||
int selectedCandidate = -1;
|
||||
uint64_t newestSequence = 0;
|
||||
@@ -491,7 +493,7 @@ bool CHardwareFrameProcessor::Publish(
|
||||
CPostProcessor& postProcessor = m_postProcessors[candidateIndex];
|
||||
const uint64_t candidateSequence = candidate.sequence;
|
||||
|
||||
auto buffer = m_device->PrepareFrameBuffer(
|
||||
auto buffer = m_transport->PrepareFrameBuffer(
|
||||
candidate.pitch, candidate.srcFormat, candidate.dstFormat,
|
||||
candidate.dirtyRects, candidate.nbDirtyRects, schedule);
|
||||
if (!buffer.mem)
|
||||
@@ -504,7 +506,7 @@ bool CHardwareFrameProcessor::Publish(
|
||||
m_frameBuffers.Get(buffer, candidate.frameSize);
|
||||
if (!fbRes)
|
||||
{
|
||||
m_device->AbortFrameBuffer(buffer.frameIndex);
|
||||
m_transport->AbortFrameBuffer(buffer.frameIndex);
|
||||
restoreCandidate();
|
||||
DEBUG_ERROR("Failed to get a CFrameBufferResource from the pool");
|
||||
SetFullDamage();
|
||||
@@ -514,7 +516,7 @@ bool CHardwareFrameProcessor::Publish(
|
||||
CD3D12CommandSlot * copySlot = m_dx12->GetCopySlot(candidateIndex);
|
||||
if (!copySlot)
|
||||
{
|
||||
m_device->AbortFrameBuffer(buffer.frameIndex);
|
||||
m_transport->AbortFrameBuffer(buffer.frameIndex);
|
||||
restoreCandidate();
|
||||
DEBUG_ERROR("Failed to get a copy CommandSlot for publication");
|
||||
SetFullDamage();
|
||||
@@ -548,17 +550,17 @@ bool CHardwareFrameProcessor::Publish(
|
||||
copySlot->EndTiming();
|
||||
|
||||
bool deliveredToOwner;
|
||||
if (!m_device->PublishFrameBuffer(
|
||||
if (!m_transport->PublishFrameBuffer(
|
||||
buffer.frameIndex, schedule, deliveredToOwner))
|
||||
{
|
||||
copySlot->Cancel();
|
||||
m_device->AbortFrameBuffer(buffer.frameIndex);
|
||||
m_transport->AbortFrameBuffer(buffer.frameIndex);
|
||||
restoreCandidate();
|
||||
return false;
|
||||
}
|
||||
CFrameScheduler::Schedule frameSchedule = schedule;
|
||||
if (!deliveredToOwner ||
|
||||
!m_device->TryFrameSubmitted(buffer.frameIndex, schedule))
|
||||
!m_transport->TryFrameSubmitted(buffer.frameIndex, schedule))
|
||||
frameSchedule.phaseEligible = false;
|
||||
fbRes->SetSchedule(frameSchedule);
|
||||
|
||||
@@ -591,15 +593,15 @@ bool CHardwareFrameProcessor::Publish(
|
||||
ReleaseSRWLockShared(&m_candidateLock);
|
||||
if (callbackPending && !copySlot->HasSubmittedWork())
|
||||
{
|
||||
m_device->FailFrameBuffer(buffer.frameIndex);
|
||||
m_transport->FailFrameBuffer(buffer.frameIndex);
|
||||
ReleaseCandidate(candidateIndex);
|
||||
}
|
||||
m_device->ForceFrame();
|
||||
m_transport->ForceFrame();
|
||||
SignalCandidateState();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_device->CommitFrameBuffer(
|
||||
m_transport->CommitFrameBuffer(
|
||||
buffer.frameIndex, schedule, periodic, deliveredToOwner);
|
||||
|
||||
unsigned superseded = 0;
|
||||
@@ -613,7 +615,7 @@ bool CHardwareFrameProcessor::Publish(
|
||||
}
|
||||
ReleaseSRWLockExclusive(&m_candidateLock);
|
||||
for (unsigned i = 0; i < superseded; ++i)
|
||||
m_device->FrameSuperseded();
|
||||
m_transport->FrameSuperseded();
|
||||
SignalCandidateState();
|
||||
return true;
|
||||
}
|
||||
@@ -645,14 +647,14 @@ bool CHardwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
}
|
||||
if (selectedCandidate < 0)
|
||||
{
|
||||
m_device->FrameSuperseded();
|
||||
m_transport->FrameSuperseded();
|
||||
return true;
|
||||
}
|
||||
const unsigned candidateIndex =
|
||||
static_cast<unsigned>(selectedCandidate);
|
||||
FrameCandidate& candidate = m_candidates[candidateIndex];
|
||||
|
||||
CFrameProcessorSharedLock pipelineLock(m_pipelineLock);
|
||||
CSRWSharedLock pipelineLock(m_pipelineLock);
|
||||
CPostProcessor& postProcessor = m_postProcessors[candidateIndex];
|
||||
const D12FrameFormat& dstFormat = postProcessor.GetOutputFormat();
|
||||
|
||||
@@ -813,7 +815,7 @@ bool CHardwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
ReleaseCandidate(candidateIndex);
|
||||
}
|
||||
SetFullDamage();
|
||||
m_device->ForceFrame();
|
||||
m_transport->ForceFrame();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CFrameProcessor.h"
|
||||
#include "capture/CFrameProcessor.h"
|
||||
|
||||
class CHardwareFrameProcessor final : public CFrameProcessor
|
||||
{
|
||||
@@ -89,7 +89,7 @@ private:
|
||||
void SetFullDamageLocked() override;
|
||||
|
||||
public:
|
||||
CHardwareFrameProcessor(CIndirectDeviceContext * device,
|
||||
CHardwareFrameProcessor(CFrameTransport * transport,
|
||||
std::shared_ptr<CD3D12Device> dx12,
|
||||
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN],
|
||||
SRWLOCK * pipelineLock, HANDLE terminateEvent);
|
||||
@@ -18,17 +18,20 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CSoftwareFrameProcessor.h"
|
||||
#include "CFrameProcessorUtil.h"
|
||||
#include "capture/CSoftwareFrameProcessor.h"
|
||||
#include "capture/CFrameProcessorUtil.h"
|
||||
#include "capture/FrameBufferTypes.h"
|
||||
#include "transport/CFrameTransport.h"
|
||||
#include "util/CSRWLock.h"
|
||||
#include "CDebug.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
CSoftwareFrameProcessor::CSoftwareFrameProcessor(
|
||||
CIndirectDeviceContext * device, std::shared_ptr<CD3D12Device> dx12,
|
||||
CFrameTransport * transport, std::shared_ptr<CD3D12Device> dx12,
|
||||
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN],
|
||||
SRWLOCK * pipelineLock, HANDLE terminateEvent) :
|
||||
CFrameProcessor(device, std::move(dx12), postProcessors,
|
||||
CFrameProcessor(transport, std::move(dx12), postProcessors,
|
||||
pipelineLock, terminateEvent),
|
||||
m_directTexture(
|
||||
!m_dx12->IsIndirectCopy() && m_dx12->CanUseIVSHMEMTexture())
|
||||
@@ -44,9 +47,9 @@ void CSoftwareFrameProcessor::CompletionFunction(
|
||||
|
||||
if (!result)
|
||||
{
|
||||
processor->m_device->FailFrameBuffer(fbRes->GetFrameIndex());
|
||||
processor->m_transport->FailFrameBuffer(fbRes->GetFrameIndex());
|
||||
processor->SetFullDamage();
|
||||
processor->m_device->ForceFrame();
|
||||
processor->m_transport->ForceFrame();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -55,7 +58,7 @@ void CSoftwareFrameProcessor::CompletionFunction(
|
||||
{
|
||||
const uint64_t indirectCopyStart = CFrameScheduler::Nanotime();
|
||||
if (fbRes->IsFullCopy())
|
||||
processor->m_device->WriteFrameBuffer(fbRes->GetFrameIndex(),
|
||||
processor->m_transport->WriteFrameBuffer(fbRes->GetFrameIndex(),
|
||||
fbRes->GetMap(), 0, fbRes->GetFrameSize(), false);
|
||||
else
|
||||
{
|
||||
@@ -70,7 +73,7 @@ void CSoftwareFrameProcessor::CompletionFunction(
|
||||
(size_t)rect->left * bytesPerPixel;
|
||||
const size_t rowBytes =
|
||||
(size_t)(rect->right - rect->left) * bytesPerPixel;
|
||||
processor->m_device->WriteFrameBufferRows(fbRes->GetFrameIndex(),
|
||||
processor->m_transport->WriteFrameBufferRows(fbRes->GetFrameIndex(),
|
||||
fbRes->GetMap(), rowOffset, rowBytes, pitch,
|
||||
(unsigned)(rect->bottom - rect->top));
|
||||
}
|
||||
@@ -83,7 +86,7 @@ void CSoftwareFrameProcessor::CompletionFunction(
|
||||
const uint64_t copyReady = CFrameScheduler::Nanotime();
|
||||
const bool gpuTimingValid = slot->GetGPUTimes(gpuStart, gpuEnd);
|
||||
|
||||
processor->m_device->FinalizeFrameBuffer(fbRes->GetFrameIndex());
|
||||
processor->m_transport->FinalizeFrameBuffer(fbRes->GetFrameIndex());
|
||||
const uint64_t publishedAt = CFrameScheduler::Nanotime();
|
||||
const uint64_t postProcessStart = fbRes->GetPostProcessStart();
|
||||
const uint64_t copyStart = fbRes->GetCopyStart();
|
||||
@@ -103,15 +106,15 @@ void CSoftwareFrameProcessor::CompletionFunction(
|
||||
const uint64_t measured = postProcessTime + copyTime;
|
||||
const uint64_t readyTime = elapsed > measured ? elapsed - measured : 0;
|
||||
|
||||
processor->m_device->SetFrameTiming(fbRes->GetFrameIndex(),
|
||||
processor->m_transport->SetFrameTiming(fbRes->GetFrameIndex(),
|
||||
fbRes->GetCaptureTime(), postProcessTime, copyTime, readyTime, 0,
|
||||
fbRes->GetSchedule(), publishedAt);
|
||||
processor->m_device->CompleteFrameBuffer(fbRes->GetFrameIndex(), true);
|
||||
processor->m_transport->CompleteFrameBuffer(fbRes->GetFrameIndex(), true);
|
||||
}
|
||||
|
||||
bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
{
|
||||
CFrameProcessorSharedLock pipelineLock(m_pipelineLock);
|
||||
CSRWSharedLock pipelineLock(m_pipelineLock);
|
||||
CPostProcessor& postProcessor = m_postProcessors[0];
|
||||
const D12FrameFormat& dstFormat = postProcessor.GetOutputFormat();
|
||||
|
||||
@@ -140,7 +143,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
&textureDesc, 0, 1, 0, &layout, nullptr, nullptr, nullptr);
|
||||
const unsigned texturePitch = layout.Footprint.RowPitch;
|
||||
if (texturePitch && textureDesc.Height <=
|
||||
m_device->GetMaxFrameSize() / texturePitch)
|
||||
m_transport->GetMaxFrameSize() / texturePitch)
|
||||
{
|
||||
pitch = texturePitch;
|
||||
frameSize = (size_t)pitch * textureDesc.Height;
|
||||
@@ -158,7 +161,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
DEBUG_WARN("Post-processor output cannot use an IVSHMEM texture");
|
||||
}
|
||||
|
||||
if (!pitch || !frameSize || frameSize > m_device->GetMaxFrameSize())
|
||||
if (!pitch || !frameSize || frameSize > m_transport->GetMaxFrameSize())
|
||||
{
|
||||
DEBUG_ERROR("Software frame does not fit in shared memory");
|
||||
SetFullDamage();
|
||||
@@ -170,10 +173,10 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
CFrameScheduler::Schedule commitSchedule = {};
|
||||
CFrameScheduler::Schedule deliverySchedule = {};
|
||||
CIndirectDeviceContext::PreparedFrameBuffer buffer = {};
|
||||
CD3D12CommandSlot * copySlot = nullptr;
|
||||
CFrameScheduler::Schedule commitSchedule = {};
|
||||
CFrameScheduler::Schedule deliverySchedule = {};
|
||||
PreparedFrameBuffer buffer = {};
|
||||
CD3D12CommandSlot * copySlot = nullptr;
|
||||
RECT currentDirtyRects[LG_MAX_DIRTY_RECTS] = {};
|
||||
unsigned nbDirtyRects = 0;
|
||||
bool hasDamage = false;
|
||||
@@ -181,19 +184,19 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
uint64_t ignoredTarget = 0;
|
||||
bool ignoredPeriodic = false;
|
||||
bool ignoredRepublish = false;
|
||||
m_device->GetPublishTarget(CFrameScheduler::Nanotime(),
|
||||
m_transport->GetPublishTarget(CFrameScheduler::Nanotime(),
|
||||
ignoredTarget, commitSchedule, ignoredPeriodic, ignoredRepublish);
|
||||
deliverySchedule = commitSchedule;
|
||||
deliverySchedule.deliveryDeadlineSerial = 0;
|
||||
deliverySchedule.phaseEligible = false;
|
||||
|
||||
m_device->ProcessFrameQueue();
|
||||
if (!m_device->FrameBufferAvailable(
|
||||
m_transport->ProcessFrameQueue();
|
||||
if (!m_transport->FrameBufferAvailable(
|
||||
deliverySchedule, submission.noImageUpdate))
|
||||
{
|
||||
if (!submission.noImageUpdate)
|
||||
{
|
||||
m_device->FrameSuperseded();
|
||||
m_transport->FrameSuperseded();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -207,7 +210,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
{
|
||||
if (!submission.noImageUpdate)
|
||||
{
|
||||
m_device->FrameSuperseded();
|
||||
m_transport->FrameSuperseded();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -220,7 +223,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
CFrameProcessorUtil::ClipDirtyRects(
|
||||
currentDirtyRects, &nbDirtyRects,
|
||||
dstFormat.width, dstFormat.height);
|
||||
buffer = m_device->PrepareFrameBuffer(
|
||||
buffer = m_transport->PrepareFrameBuffer(
|
||||
pitch, submission.sourceFormat, dstFormat,
|
||||
currentDirtyRects, nbDirtyRects, deliverySchedule,
|
||||
submission.noImageUpdate);
|
||||
@@ -231,7 +234,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
currentDirtyRects, nbDirtyRects, hasDamage);
|
||||
if (!submission.noImageUpdate)
|
||||
{
|
||||
m_device->FrameSuperseded();
|
||||
m_transport->FrameSuperseded();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -251,7 +254,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
if (FAILED(deviceStatus))
|
||||
{
|
||||
copySlot->Cancel();
|
||||
m_device->AbortFrameBuffer(buffer.frameIndex);
|
||||
m_transport->AbortFrameBuffer(buffer.frameIndex);
|
||||
RestorePendingDamage(
|
||||
currentDirtyRects, nbDirtyRects, hasDamage);
|
||||
DEBUG_ERROR_HR(deviceStatus,
|
||||
@@ -272,7 +275,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
if (!fbRes)
|
||||
{
|
||||
copySlot->Cancel();
|
||||
m_device->AbortFrameBuffer(buffer.frameIndex);
|
||||
m_transport->AbortFrameBuffer(buffer.frameIndex);
|
||||
RestorePendingDamage(
|
||||
currentDirtyRects, nbDirtyRects, hasDamage);
|
||||
DEBUG_ERROR("Failed to get a framebuffer for software capture");
|
||||
@@ -284,7 +287,7 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
!submission.source->Sync(*copySlot))
|
||||
{
|
||||
copySlot->Cancel();
|
||||
m_device->AbortFrameBuffer(buffer.frameIndex);
|
||||
m_transport->AbortFrameBuffer(buffer.frameIndex);
|
||||
RestorePendingDamage(
|
||||
currentDirtyRects, nbDirtyRects, hasDamage);
|
||||
SetFullDamage();
|
||||
@@ -322,16 +325,16 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
copySlot->EndTiming();
|
||||
|
||||
bool deliveredToOwner;
|
||||
if (!m_device->PublishFrameBuffer(
|
||||
if (!m_transport->PublishFrameBuffer(
|
||||
buffer.frameIndex, deliverySchedule, deliveredToOwner))
|
||||
{
|
||||
copySlot->Cancel();
|
||||
m_device->AbortFrameBuffer(buffer.frameIndex);
|
||||
m_transport->AbortFrameBuffer(buffer.frameIndex);
|
||||
RestorePendingDamage(
|
||||
currentDirtyRects, nbDirtyRects, hasDamage);
|
||||
if (!submission.noImageUpdate)
|
||||
{
|
||||
m_device->FrameSuperseded();
|
||||
m_transport->FrameSuperseded();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -346,18 +349,18 @@ bool CSoftwareFrameProcessor::Submit(const FrameSubmission& submission)
|
||||
const bool submittedWork = copySlot->HasSubmittedWork();
|
||||
const bool completionHandled = fbRes->CompletionHandled();
|
||||
if (!submittedWork && !completionHandled)
|
||||
m_device->FailFrameBuffer(buffer.frameIndex);
|
||||
m_transport->FailFrameBuffer(buffer.frameIndex);
|
||||
RestorePendingDamage(
|
||||
currentDirtyRects, nbDirtyRects, hasDamage);
|
||||
if (!submittedWork && !completionHandled)
|
||||
{
|
||||
SetFullDamage();
|
||||
m_device->ForceFrame();
|
||||
m_transport->ForceFrame();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
m_device->CommitFrameBuffer(
|
||||
m_transport->CommitFrameBuffer(
|
||||
buffer.frameIndex, commitSchedule, false, deliveredToOwner);
|
||||
return true;
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CFrameProcessor.h"
|
||||
#include "capture/CFrameProcessor.h"
|
||||
|
||||
class CSoftwareFrameProcessor final : public CFrameProcessor
|
||||
{
|
||||
@@ -31,7 +31,7 @@ private:
|
||||
CD3D12CommandSlot * slot, bool result, void * param1, void * param2);
|
||||
|
||||
public:
|
||||
CSoftwareFrameProcessor(CIndirectDeviceContext * device,
|
||||
CSoftwareFrameProcessor(CFrameTransport * transport,
|
||||
std::shared_ptr<CD3D12Device> dx12,
|
||||
CPostProcessor postProcessors[LGMP_Q_FRAME_LEN],
|
||||
SRWLOCK * pipelineLock, HANDLE terminateEvent);
|
||||
122
idd/LGIdd/capture/CSwapChainCursor.cpp
Normal file
122
idd/LGIdd/capture/CSwapChainCursor.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* 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/CLGMPControl.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
|
||||
DWORD CALLBACK CSwapChainProcessor::_CursorThread(LPVOID arg)
|
||||
{
|
||||
reinterpret_cast<CSwapChainProcessor*>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,15 +18,20 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CSwapChainProcessor.h"
|
||||
#include "CFrameProcessorUtil.h"
|
||||
#include "CIndirectMonitorContext.h"
|
||||
#include "CPlatformInfo.h"
|
||||
#include "capture/CSwapChainProcessor.h"
|
||||
#include "capture/CFrameProcessorUtil.h"
|
||||
#include "display/IddCxCompat.h"
|
||||
#include "display/device/CDeviceContext.h"
|
||||
#include "display/monitor/Context.h"
|
||||
#include "platform/CPlatformInfo.h"
|
||||
#include "transport/CFrameTransport.h"
|
||||
#include "transport/CLGMPControl.h"
|
||||
#include "util/CSRWLock.h"
|
||||
|
||||
#include <avrt.h>
|
||||
#include <new>
|
||||
#include "CDebug.h"
|
||||
#include "CPipeServer.h"
|
||||
#include "transport/CPipeServer.h"
|
||||
|
||||
#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
|
||||
#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002
|
||||
@@ -34,34 +39,18 @@
|
||||
|
||||
static const uint32_t HDR_PQ_MIN_LUMINANCE = 50;
|
||||
static const uint32_t HDR_PQ_MAX_LUMINANCE = 10000;
|
||||
static const uint64_t PUBLISH_RETRY_NS = 1000000ULL;
|
||||
|
||||
class CSRWExclusiveLock
|
||||
{
|
||||
private:
|
||||
SRWLOCK * m_lock;
|
||||
|
||||
public:
|
||||
explicit CSRWExclusiveLock(SRWLOCK * lock) : m_lock(lock)
|
||||
{
|
||||
AcquireSRWLockExclusive(m_lock);
|
||||
}
|
||||
|
||||
~CSRWExclusiveLock()
|
||||
{
|
||||
ReleaseSRWLockExclusive(m_lock);
|
||||
}
|
||||
};
|
||||
|
||||
CSwapChainProcessor::CSwapChainProcessor(CIndirectMonitorContext * monitorContext,
|
||||
CSwapChainProcessor::CSwapChainProcessor(CMonitorContext * monitorContext,
|
||||
UINT64 assignmentGeneration, IDDCX_MONITOR monitor,
|
||||
CIndirectDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain,
|
||||
CDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain,
|
||||
LUID renderAdapter, std::shared_ptr<CD3D11Device> dx11Device,
|
||||
HANDLE newFrameEvent) :
|
||||
m_monitorContext(monitorContext),
|
||||
m_assignmentGeneration(assignmentGeneration),
|
||||
m_monitor(monitor),
|
||||
m_devContext(devContext),
|
||||
m_transport(devContext->GetFrameTransport()),
|
||||
m_control(devContext->GetLGMPControl()),
|
||||
m_hSwapChain(hSwapChain),
|
||||
m_renderAdapter(renderAdapter),
|
||||
m_dx11Device(dx11Device),
|
||||
@@ -110,7 +99,7 @@ bool CSwapChainProcessor::InitializePipeline()
|
||||
UINT64 alignSize = CPlatformInfo::GetPageSize();
|
||||
auto dx12Device = std::make_shared<CD3D12Device>(m_renderAdapter);
|
||||
const CD3D12Device::InitResult result = dx12Device->Init(
|
||||
m_devContext->GetIVSHMEM(), alignSize, !m_dx11Device->IsSoftware());
|
||||
m_transport.GetIVSHMEM(), alignSize, !m_dx11Device->IsSoftware());
|
||||
if (result == CD3D12Device::RETRY)
|
||||
{
|
||||
const HRESULT deviceStatus =
|
||||
@@ -175,7 +164,7 @@ bool CSwapChainProcessor::InitializePipeline()
|
||||
}
|
||||
|
||||
m_frameProcessor = CreateFrameProcessor(m_dx11Device->IsSoftware(),
|
||||
m_devContext, m_dx12Device, m_postProcessors,
|
||||
&m_transport, m_dx12Device, m_postProcessors,
|
||||
&m_pipelineLock, m_terminateEvent.Get());
|
||||
if (!m_frameProcessor)
|
||||
{
|
||||
@@ -230,246 +219,6 @@ DWORD CALLBACK CSwapChainProcessor::_SwapChainThread(LPVOID arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ArmPublishTimer(HANDLE timer, uint64_t delay)
|
||||
{
|
||||
if (!timer)
|
||||
return false;
|
||||
|
||||
LARGE_INTEGER due = {};
|
||||
due.QuadPart = -static_cast<LONGLONG>((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<CSwapChainProcessor *>(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_devContext->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_devContext->GetPublishTarget(
|
||||
now, target, schedule, periodic, republish);
|
||||
|
||||
const bool ready = m_frameProcessor->HasReadyFrame();
|
||||
if (!ready)
|
||||
{
|
||||
m_devContext->ProcessFrameQueue();
|
||||
if (m_frameProcessor->HasReadyFrame())
|
||||
continue;
|
||||
|
||||
uint64_t current = CFrameScheduler::Nanotime();
|
||||
uint64_t cadenceTarget = 0;
|
||||
if (cadenceEnabled && schedule.deliveryDeadlineSerial && periodic)
|
||||
{
|
||||
if (schedule.deadline <= current)
|
||||
{
|
||||
m_devContext->FrameMissed(schedule, current, periodic);
|
||||
continue;
|
||||
}
|
||||
cadenceTarget = schedule.deadline;
|
||||
}
|
||||
|
||||
if (republish && m_devContext->HasPublishedFrame())
|
||||
{
|
||||
if (m_devContext->RepublishFrameBuffer(schedule))
|
||||
continue;
|
||||
|
||||
current = CFrameScheduler::Nanotime();
|
||||
if (cadenceTarget && cadenceTarget <= current)
|
||||
{
|
||||
m_devContext->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_devContext->GetSharedFrameTarget(current, replayTarget))
|
||||
{
|
||||
bool retry = false;
|
||||
if (replayTarget <= current)
|
||||
{
|
||||
if (m_devContext->ReplaySharedFrame(current, retry))
|
||||
continue;
|
||||
|
||||
current = CFrameScheduler::Nanotime();
|
||||
if (cadenceTarget && cadenceTarget <= current)
|
||||
{
|
||||
m_devContext->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_devContext->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_devContext->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_devContext->GetSharedFrameTarget(current, replayTarget) &&
|
||||
replayTarget < target)
|
||||
{
|
||||
if (replayTarget <= current)
|
||||
{
|
||||
m_devContext->ProcessFrameQueue();
|
||||
current = CFrameScheduler::Nanotime();
|
||||
bool retry = false;
|
||||
if (m_devContext->ReplaySharedFrame(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_devContext->ProcessFrameQueue();
|
||||
if (!m_devContext->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);
|
||||
}
|
||||
|
||||
void CSwapChainProcessor::SwapChainThread()
|
||||
{
|
||||
DWORD avTask = 0;
|
||||
@@ -813,7 +562,7 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
D3D12_RESOURCE_DESC srcDesc = srcRes->GetRes()->GetDesc();
|
||||
if (!noImageUpdate)
|
||||
{
|
||||
m_devContext->ObserveFrame(postProcessStart);
|
||||
m_transport.ObserveFrame(postProcessStart);
|
||||
m_frameProcessor->AccumulateDamage(
|
||||
srcRes->GetDirtyRects(), srcRes->GetDirtyRectCount());
|
||||
}
|
||||
@@ -824,7 +573,7 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
srcFormat.height = srcDesc.Height;
|
||||
srcFormat.format = CFrameProcessorUtil::GetFrameType(srcDesc.Format);
|
||||
srcFormat.sdrWhiteLevel = sdrWhiteLevel;
|
||||
srcFormat.colorTransform = m_devContext->GetColorTransform();
|
||||
srcFormat.colorTransform = m_control.GetColorTransform();
|
||||
|
||||
switch (colorSpace)
|
||||
{
|
||||
@@ -973,7 +722,7 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
}
|
||||
|
||||
if (needsReconfigure || postProcessFormatChanged || frameMetadataChanged)
|
||||
m_devContext->ForceFrame();
|
||||
m_transport.ForceFrame();
|
||||
|
||||
const FrameSubmission submission =
|
||||
{
|
||||
@@ -987,98 +736,3 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
};
|
||||
return m_frameProcessor->Submit(submission);
|
||||
}
|
||||
|
||||
DWORD CALLBACK CSwapChainProcessor::_CursorThread(LPVOID arg)
|
||||
{
|
||||
reinterpret_cast<CSwapChainProcessor*>(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_devContext->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,41 +20,46 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CD3D11Device.h"
|
||||
#include "CD3D12Device.h"
|
||||
#include "CIndirectDeviceContext.h"
|
||||
#include "CInteropResourcePool.h"
|
||||
#include "CFrameProcessor.h"
|
||||
#include "CPostProcessor.h"
|
||||
#include "d3d/CD3D11Device.h"
|
||||
#include "d3d/CD3D12Device.h"
|
||||
#include "display/IddCxCompat.h"
|
||||
#include "d3d/CInteropResourcePool.h"
|
||||
#include "capture/CFrameProcessor.h"
|
||||
#include "common/KVMFR.h"
|
||||
#include "postprocess/CPostProcessor.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <wrl.h>
|
||||
#include <IddCx.h>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
class CIndirectMonitorContext;
|
||||
class CMonitorContext;
|
||||
class CDeviceContext;
|
||||
class CFrameTransport;
|
||||
class CLGMPControl;
|
||||
|
||||
class CSwapChainProcessor
|
||||
{
|
||||
private:
|
||||
CIndirectMonitorContext * m_monitorContext;
|
||||
UINT64 m_assignmentGeneration;
|
||||
IDDCX_MONITOR m_monitor;
|
||||
CIndirectDeviceContext * m_devContext;
|
||||
IDDCX_SWAPCHAIN m_hSwapChain;
|
||||
LUID m_renderAdapter;
|
||||
std::shared_ptr<CD3D11Device> m_dx11Device;
|
||||
std::shared_ptr<CD3D12Device> m_dx12Device;
|
||||
HANDLE m_newFrameEvent;
|
||||
CMonitorContext * m_monitorContext;
|
||||
UINT64 m_assignmentGeneration;
|
||||
IDDCX_MONITOR m_monitor;
|
||||
CDeviceContext * m_devContext;
|
||||
CFrameTransport & m_transport;
|
||||
CLGMPControl & m_control;
|
||||
IDDCX_SWAPCHAIN m_hSwapChain;
|
||||
LUID m_renderAdapter;
|
||||
std::shared_ptr<CD3D11Device> m_dx11Device;
|
||||
std::shared_ptr<CD3D12Device> m_dx12Device;
|
||||
HANDLE m_newFrameEvent;
|
||||
|
||||
CInteropResourcePool m_resPool;
|
||||
CPostProcessor m_postProcessors[LGMP_Q_FRAME_LEN];
|
||||
CInteropResourcePool m_resPool;
|
||||
CPostProcessor m_postProcessors[LGMP_Q_FRAME_LEN];
|
||||
std::unique_ptr<CFrameProcessor> m_frameProcessor;
|
||||
// Reconfiguration is exclusive while per-candidate recording is shared.
|
||||
SRWLOCK m_pipelineLock = SRWLOCK_INIT;
|
||||
SRWLOCK m_pipelineLock = SRWLOCK_INIT;
|
||||
|
||||
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_thread[3];
|
||||
Wrappers::Event m_terminateEvent;
|
||||
@@ -94,8 +99,9 @@ private:
|
||||
uint64_t captureStart, bool duplicateFrame);
|
||||
|
||||
public:
|
||||
CSwapChainProcessor(CIndirectMonitorContext * monitorContext, UINT64 assignmentGeneration,
|
||||
IDDCX_MONITOR monitor, CIndirectDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain,
|
||||
CSwapChainProcessor(CMonitorContext * monitorContext,
|
||||
UINT64 assignmentGeneration, IDDCX_MONITOR monitor,
|
||||
CDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain,
|
||||
LUID renderAdapter, std::shared_ptr<CD3D11Device> dx11Device,
|
||||
HANDLE newFrameEvent);
|
||||
~CSwapChainProcessor();
|
||||
268
idd/LGIdd/capture/CSwapChainPublisher.cpp
Normal file
268
idd/LGIdd/capture/CSwapChainPublisher.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
/**
|
||||
* 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/CFrameTransport.h"
|
||||
|
||||
#include <avrt.h>
|
||||
#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<LONGLONG>((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<CSwapChainProcessor *>(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.ProcessFrameQueue();
|
||||
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.GetSharedFrameTarget(current, replayTarget))
|
||||
{
|
||||
bool retry = false;
|
||||
if (replayTarget <= current)
|
||||
{
|
||||
if (m_transport.ReplaySharedFrame(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.GetSharedFrameTarget(current, replayTarget) &&
|
||||
replayTarget < target)
|
||||
{
|
||||
if (replayTarget <= current)
|
||||
{
|
||||
m_transport.ProcessFrameQueue();
|
||||
current = CFrameScheduler::Nanotime();
|
||||
bool retry = false;
|
||||
if (m_transport.ReplaySharedFrame(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.ProcessFrameQueue();
|
||||
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);
|
||||
}
|
||||
40
idd/LGIdd/capture/FrameBufferTypes.h
Normal file
40
idd/LGIdd/capture/FrameBufferTypes.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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 <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
|
||||
{
|
||||
unsigned frameIndex;
|
||||
uint8_t * mem;
|
||||
bool fullCopy;
|
||||
};
|
||||
@@ -18,7 +18,7 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CSettings.h"
|
||||
#include "config/CSettings.h"
|
||||
#include "CDebug.h"
|
||||
#include "DefaultDisplayModes.h"
|
||||
#include "RefreshRate.h"
|
||||
@@ -18,7 +18,7 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CD3D11Device.h"
|
||||
#include "d3d/CD3D11Device.h"
|
||||
#include "CDebug.h"
|
||||
|
||||
HRESULT CD3D11Device::Init()
|
||||
@@ -72,4 +72,4 @@ HRESULT CD3D11Device::Init()
|
||||
return hr;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CD3D12CommandQueue.h"
|
||||
#include "d3d/CD3D12CommandQueue.h"
|
||||
#include "CDebug.h"
|
||||
|
||||
static uint64_t ScaleTicks(uint64_t ticks, uint64_t targetFrequency,
|
||||
@@ -18,7 +18,7 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CD3D12Device.h"
|
||||
#include "d3d/CD3D12Device.h"
|
||||
#include "CDebug.h"
|
||||
|
||||
bool CD3D12Device::m_indirectCopy = false;
|
||||
@@ -26,8 +26,8 @@
|
||||
#include <dxgi1_5.h>
|
||||
#include <d3d12.h>
|
||||
|
||||
#include "CIVSHMEM.h"
|
||||
#include "CD3D12CommandQueue.h"
|
||||
#include "transport/CIVSHMEM.h"
|
||||
#include "d3d/CD3D12CommandQueue.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
@@ -18,10 +18,13 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CInteropResource.h"
|
||||
#include "d3d/CInteropResource.h"
|
||||
#include "CDebug.h"
|
||||
|
||||
bool CInteropResource::Init(std::shared_ptr<CD3D11Device> dx11Device, std::shared_ptr<CD3D12Device> dx12Device, ComPtr<ID3D11Texture2D> srcTex)
|
||||
bool CInteropResource::Init(
|
||||
std::shared_ptr<CD3D11Device> dx11Device,
|
||||
std::shared_ptr<CD3D12Device> dx12Device,
|
||||
ComPtr<ID3D11Texture2D> srcTex)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
@@ -112,14 +115,15 @@ void CInteropResource::Reset()
|
||||
m_dx11Device.reset();
|
||||
}
|
||||
|
||||
bool CInteropResource::Compare(const ComPtr<ID3D11Texture2D>& srcTex)
|
||||
bool CInteropResource::Compare(
|
||||
const ComPtr<ID3D11Texture2D>& srcTex) const
|
||||
{
|
||||
if (srcTex.Get() != m_srcTex)
|
||||
return false;
|
||||
|
||||
D3D11_TEXTURE2D_DESC format;
|
||||
srcTex->GetDesc(&format);
|
||||
|
||||
|
||||
return
|
||||
m_format.Width == format.Width &&
|
||||
m_format.Height == format.Height &&
|
||||
@@ -163,6 +167,7 @@ void CInteropResource::SetFullDamage()
|
||||
m_dirtyRects[0].bottom = m_format.Height;
|
||||
m_nbDirtyRects = 1;
|
||||
}
|
||||
|
||||
void CInteropResource::SetDirtyRects(const RECT * dirtyRects, unsigned nbDirtyRects)
|
||||
{
|
||||
if (nbDirtyRects > LG_MAX_DIRTY_RECTS)
|
||||
73
idd/LGIdd/d3d/CInteropResource.h
Normal file
73
idd/LGIdd/d3d/CInteropResource.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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 <wdf.h>
|
||||
#include <wrl.h>
|
||||
#include <memory>
|
||||
|
||||
#include "d3d/CD3D11Device.h"
|
||||
#include "d3d/CD3D12Device.h"
|
||||
#include "d3d/CD3D12CommandQueue.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
#define LG_MAX_DIRTY_RECTS 256
|
||||
|
||||
class CInteropResource
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<CD3D11Device> m_dx11Device;
|
||||
std::shared_ptr<CD3D12Device> m_dx12Device;
|
||||
|
||||
// This value is likely released. It is only used to check if the supplied
|
||||
// texture is different; do not rely on it pointing to valid memory.
|
||||
void * m_srcTex;
|
||||
|
||||
ComPtr<ID3D12Resource > m_d12Res;
|
||||
D3D11_TEXTURE2D_DESC m_format;
|
||||
ComPtr<ID3D11Fence > m_d11Fence;
|
||||
ComPtr<ID3D12Fence > m_d12Fence;
|
||||
UINT64 m_fenceValue;
|
||||
bool m_ready;
|
||||
|
||||
RECT m_dirtyRects[LG_MAX_DIRTY_RECTS];
|
||||
unsigned m_nbDirtyRects;
|
||||
|
||||
public:
|
||||
bool Init(std::shared_ptr<CD3D11Device> dx11Device,
|
||||
std::shared_ptr<CD3D12Device> dx12Device,
|
||||
ComPtr<ID3D11Texture2D> srcTex);
|
||||
void Reset();
|
||||
|
||||
bool IsReady() const { return m_ready; }
|
||||
bool Compare(const ComPtr<ID3D11Texture2D>& srcTex) const;
|
||||
bool Signal();
|
||||
bool Sync(CD3D12CommandSlot& slot);
|
||||
void SetFullDamage();
|
||||
void SetDirtyRects(const RECT * dirtyRects, unsigned nbDirtyRects);
|
||||
|
||||
const ComPtr<ID3D12Resource>& GetRes() const { return m_d12Res; }
|
||||
const D3D11_TEXTURE2D_DESC& GetFormat() const { return m_format; }
|
||||
const RECT * GetDirtyRects() const { return m_dirtyRects; }
|
||||
unsigned GetDirtyRectCount() const { return m_nbDirtyRects; }
|
||||
};
|
||||
@@ -18,10 +18,12 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CInteropResourcePool.h"
|
||||
#include "d3d/CInteropResourcePool.h"
|
||||
#include "CDebug.h"
|
||||
|
||||
void CInteropResourcePool::Init(std::shared_ptr<CD3D11Device> dx11Device, std::shared_ptr<CD3D12Device> dx12Device)
|
||||
void CInteropResourcePool::Init(
|
||||
std::shared_ptr<CD3D11Device> dx11Device,
|
||||
std::shared_ptr<CD3D12Device> dx12Device)
|
||||
{
|
||||
Reset();
|
||||
m_dx11Device = dx11Device;
|
||||
@@ -36,7 +38,8 @@ void CInteropResourcePool::Reset()
|
||||
m_dx12Device.reset();
|
||||
}
|
||||
|
||||
CInteropResource* CInteropResourcePool::Get(ComPtr<ID3D11Texture2D> srcTex)
|
||||
CInteropResource * CInteropResourcePool::Get(
|
||||
ComPtr<ID3D11Texture2D> srcTex)
|
||||
{
|
||||
CInteropResource * res;
|
||||
unsigned freeSlot = POOL_SIZE;
|
||||
@@ -64,4 +67,4 @@ CInteropResource* CInteropResourcePool::Get(ComPtr<ID3D11Texture2D> srcTex)
|
||||
return nullptr;
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -24,23 +24,24 @@
|
||||
#include <wdf.h>
|
||||
#include <wrl.h>
|
||||
#include <d3d11_4.h>
|
||||
#include "CInteropResource.h"
|
||||
#include "d3d/CInteropResource.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
#define POOL_SIZE 10
|
||||
|
||||
class CInteropResourcePool
|
||||
{
|
||||
private:
|
||||
CInteropResource m_pool[POOL_SIZE];
|
||||
|
||||
std::shared_ptr<CD3D11Device> m_dx11Device;
|
||||
std::shared_ptr<CD3D12Device> m_dx12Device;
|
||||
|
||||
public:
|
||||
void Init(std::shared_ptr<CD3D11Device> dx11Device, std::shared_ptr<CD3D12Device> dx12Device);
|
||||
void Reset();
|
||||
private:
|
||||
static constexpr unsigned POOL_SIZE = 10;
|
||||
|
||||
CInteropResource* Get(ComPtr<ID3D11Texture2D> srcTex);
|
||||
};
|
||||
CInteropResource m_pool[POOL_SIZE];
|
||||
|
||||
std::shared_ptr<CD3D11Device> m_dx11Device;
|
||||
std::shared_ptr<CD3D12Device> m_dx12Device;
|
||||
|
||||
public:
|
||||
void Init(std::shared_ptr<CD3D11Device> dx11Device,
|
||||
std::shared_ptr<CD3D12Device> dx12Device);
|
||||
void Reset();
|
||||
|
||||
CInteropResource * Get(ComPtr<ID3D11Texture2D> srcTex);
|
||||
};
|
||||
496
idd/LGIdd/display/CDisplayConfiguration.cpp
Normal file
496
idd/LGIdd/display/CDisplayConfiguration.cpp
Normal file
@@ -0,0 +1,496 @@
|
||||
/**
|
||||
* 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 "display/CDisplayConfiguration.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
#include "common/LGMPConfig.h"
|
||||
#include "util/CSRWLock.h"
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
static const UINT64 FRAME_BYTES_PER_PIXEL = 4;
|
||||
|
||||
bool CDisplayConfiguration::AlignUp(
|
||||
UINT64 value, UINT64 alignment, UINT64& result)
|
||||
{
|
||||
if (!alignment || (alignment & (alignment - 1)))
|
||||
return false;
|
||||
|
||||
const UINT64 mask = alignment - 1;
|
||||
result = (value + mask) & ~mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDisplayConfiguration::CalculateFrameSize(
|
||||
uint32_t width, uint32_t height, UINT64& frameSize)
|
||||
{
|
||||
frameSize = 0;
|
||||
if (!width || !height)
|
||||
return false;
|
||||
|
||||
UINT64 pitch;
|
||||
if (!AlignUp((UINT64)width * FRAME_BYTES_PER_PIXEL,
|
||||
D3D12_TEXTURE_DATA_PITCH_ALIGNMENT, pitch))
|
||||
return false;
|
||||
|
||||
frameSize = pitch * height;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDisplayConfiguration::GetResolutionMemoryRequirements(
|
||||
uint32_t width, uint32_t height, UINT64 alignment,
|
||||
const FrameMemoryLimits& limits, UINT64& frameSize, UINT64& sharedSize)
|
||||
{
|
||||
frameSize = 0;
|
||||
sharedSize = 0;
|
||||
|
||||
if (!alignment || !limits.frameMemoryOffset ||
|
||||
!CalculateFrameSize(width, height, frameSize))
|
||||
return false;
|
||||
|
||||
UINT64 frameAllocationSize;
|
||||
if (!AlignUp(frameSize + alignment, alignment, frameAllocationSize))
|
||||
return false;
|
||||
|
||||
UINT64 frameMemoryStart;
|
||||
if (!AlignUp(limits.frameMemoryOffset, alignment, frameMemoryStart))
|
||||
return false;
|
||||
|
||||
sharedSize = frameMemoryStart +
|
||||
frameAllocationSize * LGMP_Q_FRAME_BUFFER_LEN;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t CDisplayConfiguration::RecommendedIVSHMEMSizeMiB(
|
||||
UINT64 requiredSize)
|
||||
{
|
||||
UINT64 sizeMiB = requiredSize / 1048576;
|
||||
if (requiredSize % 1048576)
|
||||
++sizeMiB;
|
||||
|
||||
UINT64 result = 1;
|
||||
while (result < sizeMiB && result <= UINT32_MAX / 2)
|
||||
result <<= 1;
|
||||
|
||||
return result < sizeMiB ? UINT32_MAX : (uint32_t)result;
|
||||
}
|
||||
|
||||
#ifdef HAS_IDDCX_110
|
||||
static inline IDDCX_WIRE_BITS_PER_COMPONENT GetWireBitsPerComponent(bool hdr)
|
||||
{
|
||||
IDDCX_WIRE_BITS_PER_COMPONENT bits = {};
|
||||
// This describes the virtual monitor wire, not the swap-chain format.
|
||||
// HDR uses a 10-bpc PQ wire while CAN_PROCESS_FP16 requests the FP16/scRGB
|
||||
// source surface that Looking Glass converts for transport.
|
||||
bits.Rgb = IDDCX_BITS_PER_COMPONENT_8;
|
||||
if (hdr)
|
||||
bits.Rgb = (IDDCX_BITS_PER_COMPONENT)(bits.Rgb |
|
||||
IDDCX_BITS_PER_COMPONENT_10);
|
||||
bits.YCbCr444 = IDDCX_BITS_PER_COMPONENT_NONE;
|
||||
bits.YCbCr422 = IDDCX_BITS_PER_COMPONENT_NONE;
|
||||
bits.YCbCr420 = IDDCX_BITS_PER_COMPONENT_NONE;
|
||||
return bits;
|
||||
}
|
||||
#endif
|
||||
|
||||
CDisplayConfiguration::CDisplayConfiguration(CSettings& settings) :
|
||||
m_settings(settings)
|
||||
{
|
||||
}
|
||||
|
||||
bool CDisplayConfiguration::LoadModes(const FrameMemoryLimits& limits)
|
||||
{
|
||||
const CSettings::DisplayModes configuredModes =
|
||||
m_settings.LoadModes();
|
||||
|
||||
// Build the new mode list into a local first so readers never observe a
|
||||
// reallocation of the live container. Publishing it is a pointer swap.
|
||||
CSettings::DisplayModes newModes;
|
||||
newModes.reserve(configuredModes.size());
|
||||
|
||||
const UINT64 alignment = limits.alignment ? limits.alignment :
|
||||
D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
||||
|
||||
bool hasPreferred = false;
|
||||
for (const auto& configuredMode : configuredModes)
|
||||
{
|
||||
UINT64 frameSize;
|
||||
UINT64 requiredIVSHMEMSize;
|
||||
if (!GetResolutionMemoryRequirements(configuredMode.width,
|
||||
configuredMode.height, alignment, limits, frameSize,
|
||||
requiredIVSHMEMSize))
|
||||
{
|
||||
DEBUG_WARN("Filtering invalid %s mode %ux%u@%.3f",
|
||||
configuredMode.extraMode ? "extra" : "configured",
|
||||
configuredMode.width, configuredMode.height,
|
||||
configuredMode.refreshMilliHz / 1000.0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (requiredIVSHMEMSize > limits.sharedSize)
|
||||
{
|
||||
DEBUG_WARN(
|
||||
"Filtering %s mode %ux%u@%.3f: requires %llu bytes of IVSHMEM, only %llu bytes are available",
|
||||
configuredMode.extraMode ? "extra" : "configured",
|
||||
configuredMode.width, configuredMode.height,
|
||||
configuredMode.refreshMilliHz / 1000.0,
|
||||
(unsigned long long)requiredIVSHMEMSize,
|
||||
(unsigned long long)limits.sharedSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
CSettings::DisplayMode mode = configuredMode;
|
||||
if (mode.preferred)
|
||||
{
|
||||
mode.preferred = !hasPreferred;
|
||||
hasPreferred = true;
|
||||
}
|
||||
newModes.push_back(mode);
|
||||
}
|
||||
|
||||
if (newModes.empty())
|
||||
{
|
||||
DEBUG_ERROR("No configured display modes fit in IVSHMEM");
|
||||
return false;
|
||||
}
|
||||
|
||||
// ExtraMode may have been the preferred mode. If it did not fit, promote
|
||||
// the first remaining mode so the list still has a valid preference.
|
||||
if (!hasPreferred)
|
||||
newModes.front().preferred = true;
|
||||
|
||||
CSRWExclusiveLock lock(&m_modeLock);
|
||||
m_modes = std::move(newModes);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDisplayConfiguration::Load(const FrameMemoryLimits& limits)
|
||||
{
|
||||
return LoadModes(limits);
|
||||
}
|
||||
|
||||
bool CDisplayConfiguration::ReloadSettings(
|
||||
const FrameMemoryLimits& limits)
|
||||
{
|
||||
bool modesLoaded = false;
|
||||
{
|
||||
CSRWExclusiveLock reloadLock(&m_reloadLock);
|
||||
|
||||
bool settingsUpdated = true;
|
||||
CSettings::DisplayMode extraMode = {};
|
||||
if (m_settings.GetExtraMode(extraMode))
|
||||
{
|
||||
const unsigned refreshMilliHz =
|
||||
m_settings.GetDefaultRefreshMilliHz();
|
||||
if (extraMode.refreshMilliHz != refreshMilliHz)
|
||||
{
|
||||
extraMode.refreshMilliHz = refreshMilliHz;
|
||||
settingsUpdated = m_settings.SetExtraMode(extraMode);
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsUpdated)
|
||||
modesLoaded = LoadModes(limits);
|
||||
}
|
||||
|
||||
if (!modesLoaded)
|
||||
DEBUG_ERROR("Failed to reload the display mode list");
|
||||
return modesLoaded;
|
||||
}
|
||||
|
||||
CDisplayConfiguration::ResolutionResult
|
||||
CDisplayConfiguration::SetResolution(
|
||||
uint32_t width, uint32_t height, const FrameMemoryLimits& limits)
|
||||
{
|
||||
ResolutionResult result;
|
||||
|
||||
UINT64 frameSize;
|
||||
UINT64 requiredIVSHMEMSize;
|
||||
if (!GetResolutionMemoryRequirements(width, height, limits.alignment,
|
||||
limits, frameSize, requiredIVSHMEMSize))
|
||||
{
|
||||
DEBUG_WARN("Ignoring invalid resolution request: %ux%u", width, height);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (requiredIVSHMEMSize > limits.sharedSize)
|
||||
{
|
||||
result.status = ResolutionStatus::TOO_LARGE;
|
||||
result.requiredMiB = RecommendedIVSHMEMSizeMiB(requiredIVSHMEMSize);
|
||||
DEBUG_WARN(
|
||||
"Refusing resolution %ux%u: frame requires %llu bytes, only %llu bytes are available; IVSHMEM must be at least %u MiB",
|
||||
width, height,
|
||||
(unsigned long long)frameSize,
|
||||
(unsigned long long)limits.maxFrameSize,
|
||||
result.requiredMiB);
|
||||
return result;
|
||||
}
|
||||
|
||||
CSettings::DisplayMode mode = {};
|
||||
mode.width = width;
|
||||
mode.height = height;
|
||||
mode.refreshMilliHz = m_settings.GetDefaultRefreshMilliHz();
|
||||
mode.preferred = true;
|
||||
|
||||
{
|
||||
CSRWExclusiveLock reloadLock(&m_reloadLock);
|
||||
if (!m_settings.SetExtraMode(mode))
|
||||
result.status = ResolutionStatus::SETTINGS_FAILED;
|
||||
else if (!LoadModes(limits))
|
||||
result.status = ResolutionStatus::MODES_FAILED;
|
||||
else
|
||||
{
|
||||
result.status = ResolutionStatus::SUCCESS;
|
||||
result.mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.status != ResolutionStatus::SUCCESS)
|
||||
DEBUG_ERROR("Failed to rebuild the display mode list");
|
||||
return result;
|
||||
}
|
||||
|
||||
void CDisplayConfiguration::InitializeEdid(bool hdr)
|
||||
{
|
||||
CSRWExclusiveLock lock(&m_modeLock);
|
||||
if (m_edid.Size())
|
||||
return;
|
||||
|
||||
m_edid.Build(hdr);
|
||||
m_hdrEnabled = hdr;
|
||||
}
|
||||
|
||||
void CDisplayConfiguration::RebuildEdid(bool hdr)
|
||||
{
|
||||
CSRWExclusiveLock lock(&m_modeLock);
|
||||
m_edid.Build(hdr);
|
||||
m_hdrEnabled = hdr;
|
||||
}
|
||||
|
||||
CDisplayConfiguration::Description
|
||||
CDisplayConfiguration::GetDescription() const
|
||||
{
|
||||
Description result;
|
||||
CSRWSharedLock lock(&m_modeLock);
|
||||
result.modeCount = m_modes.size();
|
||||
if (m_edid.Size())
|
||||
result.edid.assign(m_edid.Data(), m_edid.Data() + m_edid.Size());
|
||||
return result;
|
||||
}
|
||||
|
||||
CSettings::DisplayModes CDisplayConfiguration::SnapshotModes(
|
||||
bool * hdrEnabled) const
|
||||
{
|
||||
CSRWSharedLock lock(&m_modeLock);
|
||||
if (hdrEnabled)
|
||||
*hdrEnabled = m_hdrEnabled;
|
||||
return m_modes;
|
||||
}
|
||||
|
||||
static UINT64 GreatestCommonDivisor(UINT64 a, UINT64 b)
|
||||
{
|
||||
while (b)
|
||||
{
|
||||
const UINT64 remainder = a % b;
|
||||
a = b;
|
||||
b = remainder;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
static void SetSignalRate(DISPLAYCONFIG_RATIONAL& rate,
|
||||
UINT64 numerator, UINT32 denominator)
|
||||
{
|
||||
const UINT64 divisor = GreatestCommonDivisor(numerator, denominator);
|
||||
numerator /= divisor;
|
||||
denominator /= (UINT32)divisor;
|
||||
|
||||
if (numerator <= UINT32_MAX)
|
||||
{
|
||||
rate.Numerator = (UINT32)numerator;
|
||||
rate.Denominator = denominator;
|
||||
return;
|
||||
}
|
||||
|
||||
rate.Numerator =
|
||||
(UINT32)((numerator + denominator / 2) / denominator);
|
||||
rate.Denominator = 1;
|
||||
}
|
||||
|
||||
static inline void FillSignalInfo(DISPLAYCONFIG_VIDEO_SIGNAL_INFO& signal,
|
||||
const CSettings::DisplayMode& mode, bool monitorMode)
|
||||
{
|
||||
CEdid::Timing timing;
|
||||
if (!CEdid::GetTiming(timing, mode))
|
||||
return;
|
||||
|
||||
signal.activeSize.cx = timing.hActive;
|
||||
signal.activeSize.cy = timing.vActive;
|
||||
signal.totalSize.cx = timing.hActive + timing.hBlank;
|
||||
signal.totalSize.cy = timing.vActive + timing.vBlank;
|
||||
|
||||
signal.AdditionalSignalInfo.vSyncFreqDivider = monitorMode ? 0 : 1;
|
||||
signal.AdditionalSignalInfo.videoStandard = 255;
|
||||
|
||||
SetSignalRate(signal.vSyncFreq, mode.refreshMilliHz, 1000);
|
||||
SetSignalRate(signal.hSyncFreq,
|
||||
(UINT64)mode.refreshMilliHz * signal.totalSize.cy, 1000);
|
||||
|
||||
signal.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;
|
||||
signal.pixelRate = timing.pixelClock;
|
||||
}
|
||||
|
||||
NTSTATUS CDisplayConfiguration::ParseMonitorDescription(
|
||||
const IDARG_IN_PARSEMONITORDESCRIPTION * inArgs,
|
||||
IDARG_OUT_PARSEMONITORDESCRIPTION * outArgs) const
|
||||
{
|
||||
const CSettings::DisplayModes modes = SnapshotModes();
|
||||
|
||||
outArgs->MonitorModeBufferOutputCount = (UINT)modes.size();
|
||||
outArgs->PreferredMonitorModeIdx = 0;
|
||||
if (inArgs->MonitorModeBufferInputCount < (UINT)modes.size())
|
||||
return inArgs->MonitorModeBufferInputCount > 0 ?
|
||||
STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS;
|
||||
|
||||
auto * mode = inArgs->pMonitorModes;
|
||||
for (auto it = modes.cbegin(); it != modes.cend(); ++it, ++mode)
|
||||
{
|
||||
mode->Size = sizeof(IDDCX_MONITOR_MODE);
|
||||
mode->Origin = IDDCX_MONITOR_MODE_ORIGIN_MONITORDESCRIPTOR;
|
||||
FillSignalInfo(mode->MonitorVideoSignalInfo, *it, true);
|
||||
|
||||
if (it->preferred)
|
||||
outArgs->PreferredMonitorModeIdx =
|
||||
(UINT)std::distance(modes.cbegin(), it);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS CDisplayConfiguration::MonitorGetDefaultModes(
|
||||
const IDARG_IN_GETDEFAULTDESCRIPTIONMODES * inArgs,
|
||||
IDARG_OUT_GETDEFAULTDESCRIPTIONMODES * outArgs) const
|
||||
{
|
||||
const CSettings::DisplayModes modes = SnapshotModes();
|
||||
|
||||
outArgs->DefaultMonitorModeBufferOutputCount = (UINT)modes.size();
|
||||
outArgs->PreferredMonitorModeIdx = 0;
|
||||
if (inArgs->DefaultMonitorModeBufferInputCount < (UINT)modes.size())
|
||||
return inArgs->DefaultMonitorModeBufferInputCount > 0 ?
|
||||
STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS;
|
||||
|
||||
auto * mode = inArgs->pDefaultMonitorModes;
|
||||
for (auto it = modes.cbegin(); it != modes.cend(); ++it, ++mode)
|
||||
{
|
||||
mode->Size = sizeof(IDDCX_MONITOR_MODE);
|
||||
mode->Origin = IDDCX_MONITOR_MODE_ORIGIN_DRIVER;
|
||||
FillSignalInfo(mode->MonitorVideoSignalInfo, *it, true);
|
||||
|
||||
if (it->preferred)
|
||||
outArgs->PreferredMonitorModeIdx =
|
||||
(UINT)std::distance(modes.cbegin(), it);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS CDisplayConfiguration::MonitorQueryTargetModes(
|
||||
const IDARG_IN_QUERYTARGETMODES * inArgs,
|
||||
IDARG_OUT_QUERYTARGETMODES * outArgs) const
|
||||
{
|
||||
const CSettings::DisplayModes modes = SnapshotModes();
|
||||
|
||||
outArgs->TargetModeBufferOutputCount = (UINT)modes.size();
|
||||
if (inArgs->TargetModeBufferInputCount < (UINT)modes.size())
|
||||
return inArgs->TargetModeBufferInputCount > 0 ?
|
||||
STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS;
|
||||
|
||||
auto * mode = inArgs->pTargetModes;
|
||||
for (auto it = modes.cbegin(); it != modes.cend(); ++it, ++mode)
|
||||
{
|
||||
mode->Size = sizeof(IDDCX_TARGET_MODE);
|
||||
FillSignalInfo(
|
||||
mode->TargetVideoSignalInfo.targetVideoSignalInfo, *it, false);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef HAS_IDDCX_110
|
||||
NTSTATUS CDisplayConfiguration::ParseMonitorDescription2(
|
||||
const IDARG_IN_PARSEMONITORDESCRIPTION2 * inArgs,
|
||||
IDARG_OUT_PARSEMONITORDESCRIPTION * outArgs) const
|
||||
{
|
||||
bool hdrEnabled = false;
|
||||
const CSettings::DisplayModes modes = SnapshotModes(&hdrEnabled);
|
||||
|
||||
outArgs->MonitorModeBufferOutputCount = (UINT)modes.size();
|
||||
outArgs->PreferredMonitorModeIdx = 0;
|
||||
if (inArgs->MonitorModeBufferInputCount < (UINT)modes.size())
|
||||
return inArgs->MonitorModeBufferInputCount > 0 ?
|
||||
STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS;
|
||||
|
||||
auto * mode = inArgs->pMonitorModes;
|
||||
for (auto it = modes.cbegin(); it != modes.cend(); ++it, ++mode)
|
||||
{
|
||||
ZeroMemory(mode, sizeof(*mode));
|
||||
mode->Size = sizeof(IDDCX_MONITOR_MODE2);
|
||||
mode->Origin = IDDCX_MONITOR_MODE_ORIGIN_MONITORDESCRIPTOR;
|
||||
FillSignalInfo(mode->MonitorVideoSignalInfo, *it, true);
|
||||
mode->BitsPerComponent = GetWireBitsPerComponent(hdrEnabled);
|
||||
|
||||
if (it->preferred)
|
||||
outArgs->PreferredMonitorModeIdx =
|
||||
(UINT)std::distance(modes.cbegin(), it);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS CDisplayConfiguration::MonitorQueryTargetModes2(
|
||||
const IDARG_IN_QUERYTARGETMODES2 * inArgs,
|
||||
IDARG_OUT_QUERYTARGETMODES * outArgs) const
|
||||
{
|
||||
bool hdrEnabled = false;
|
||||
const CSettings::DisplayModes modes = SnapshotModes(&hdrEnabled);
|
||||
|
||||
outArgs->TargetModeBufferOutputCount = (UINT)modes.size();
|
||||
if (inArgs->TargetModeBufferInputCount < (UINT)modes.size())
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
if (!inArgs->pTargetModes)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
auto * mode = inArgs->pTargetModes;
|
||||
for (auto it = modes.cbegin(); it != modes.cend(); ++it, ++mode)
|
||||
{
|
||||
ZeroMemory(mode, sizeof(*mode));
|
||||
mode->Size = sizeof(IDDCX_TARGET_MODE2);
|
||||
FillSignalInfo(
|
||||
mode->TargetVideoSignalInfo.targetVideoSignalInfo, *it, false);
|
||||
mode->BitsPerComponent = GetWireBitsPerComponent(hdrEnabled);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
113
idd/LGIdd/display/CDisplayConfiguration.h
Normal file
113
idd/LGIdd/display/CDisplayConfiguration.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* 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 "config/CSettings.h"
|
||||
#include "display/CEdid.h"
|
||||
#include "display/IddCxCompat.h"
|
||||
#include "transport/FrameMemoryLimits.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
class CDisplayConfiguration
|
||||
{
|
||||
public:
|
||||
enum class ResolutionStatus
|
||||
{
|
||||
SUCCESS,
|
||||
INVALID,
|
||||
TOO_LARGE,
|
||||
SETTINGS_FAILED,
|
||||
MODES_FAILED,
|
||||
};
|
||||
|
||||
struct ResolutionResult
|
||||
{
|
||||
ResolutionStatus status = ResolutionStatus::INVALID;
|
||||
CSettings::DisplayMode mode = {};
|
||||
uint32_t requiredMiB = 0;
|
||||
};
|
||||
|
||||
struct Description
|
||||
{
|
||||
size_t modeCount = 0;
|
||||
std::vector<BYTE> edid;
|
||||
};
|
||||
|
||||
private:
|
||||
CSettings& m_settings;
|
||||
|
||||
// Registry-backed changes are serialized before publishing a replacement
|
||||
// mode list. Readers only hold m_modeLock long enough to take a snapshot.
|
||||
SRWLOCK m_reloadLock = SRWLOCK_INIT;
|
||||
mutable SRWLOCK m_modeLock = SRWLOCK_INIT;
|
||||
|
||||
CSettings::DisplayModes m_modes;
|
||||
CEdid m_edid;
|
||||
bool m_hdrEnabled = false;
|
||||
|
||||
bool LoadModes(const FrameMemoryLimits& limits);
|
||||
CSettings::DisplayModes SnapshotModes(bool * hdrEnabled = nullptr) const;
|
||||
|
||||
static bool AlignUp(UINT64 value, UINT64 alignment, UINT64& result);
|
||||
static bool CalculateFrameSize(uint32_t width, uint32_t height,
|
||||
UINT64& frameSize);
|
||||
static bool GetResolutionMemoryRequirements(uint32_t width,
|
||||
uint32_t height, UINT64 alignment, const FrameMemoryLimits& limits,
|
||||
UINT64& frameSize, UINT64& sharedSize);
|
||||
static uint32_t RecommendedIVSHMEMSizeMiB(UINT64 requiredSize);
|
||||
|
||||
public:
|
||||
explicit CDisplayConfiguration(CSettings& settings);
|
||||
|
||||
CDisplayConfiguration(const CDisplayConfiguration&) = delete;
|
||||
CDisplayConfiguration& operator=(const CDisplayConfiguration&) = delete;
|
||||
|
||||
bool Load(const FrameMemoryLimits& limits);
|
||||
bool ReloadSettings(const FrameMemoryLimits& limits);
|
||||
ResolutionResult SetResolution(uint32_t width, uint32_t height,
|
||||
const FrameMemoryLimits& limits);
|
||||
|
||||
void InitializeEdid(bool hdr);
|
||||
void RebuildEdid(bool hdr);
|
||||
Description GetDescription() const;
|
||||
|
||||
NTSTATUS ParseMonitorDescription(
|
||||
const IDARG_IN_PARSEMONITORDESCRIPTION * inArgs,
|
||||
IDARG_OUT_PARSEMONITORDESCRIPTION * outArgs) const;
|
||||
NTSTATUS MonitorGetDefaultModes(
|
||||
const IDARG_IN_GETDEFAULTDESCRIPTIONMODES * inArgs,
|
||||
IDARG_OUT_GETDEFAULTDESCRIPTIONMODES * outArgs) const;
|
||||
NTSTATUS MonitorQueryTargetModes(
|
||||
const IDARG_IN_QUERYTARGETMODES * inArgs,
|
||||
IDARG_OUT_QUERYTARGETMODES * outArgs) const;
|
||||
|
||||
#ifdef HAS_IDDCX_110
|
||||
NTSTATUS ParseMonitorDescription2(
|
||||
const IDARG_IN_PARSEMONITORDESCRIPTION2 * inArgs,
|
||||
IDARG_OUT_PARSEMONITORDESCRIPTION * outArgs) const;
|
||||
NTSTATUS MonitorQueryTargetModes2(
|
||||
const IDARG_IN_QUERYTARGETMODES2 * inArgs,
|
||||
IDARG_OUT_QUERYTARGETMODES * outArgs) const;
|
||||
#endif
|
||||
};
|
||||
@@ -18,7 +18,7 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CEdid.h"
|
||||
#include "display/CEdid.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "CSettings.h"
|
||||
#include "config/CSettings.h"
|
||||
|
||||
class CEdid
|
||||
{
|
||||
252
idd/LGIdd/display/CMonitorManager.cpp
Normal file
252
idd/LGIdd/display/CMonitorManager.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
/**
|
||||
* 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 "display/CMonitorManager.h"
|
||||
|
||||
#include "display/monitor/Context.h"
|
||||
#include "CDebug.h"
|
||||
|
||||
void CMonitorManager::Create(UINT connectorIndex, IDDCX_ADAPTER adapter,
|
||||
std::vector<BYTE> edid, CDeviceContext * owner)
|
||||
{
|
||||
DEBUG_INFO("Creating monitor on connector %u", connectorIndex);
|
||||
|
||||
// We support a single monitor; never create a second one if one already
|
||||
// exists (a replug must clear m_monitor via departure first).
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
const bool haveMonitor = m_monitor != WDF_NO_HANDLE;
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
if (haveMonitor)
|
||||
{
|
||||
DEBUG_WARN("FinishInit skipped: a monitor already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES attr;
|
||||
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, CMonitorContextWrapper);
|
||||
|
||||
DEBUG_INFO("Using %llu-byte monitor EDID",
|
||||
(unsigned long long)edid.size());
|
||||
|
||||
IDDCX_MONITOR_INFO info = {};
|
||||
info.Size = sizeof(info);
|
||||
info.MonitorType = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI;
|
||||
info.ConnectorIndex = connectorIndex;
|
||||
|
||||
info.MonitorDescription.Size = sizeof(info.MonitorDescription);
|
||||
info.MonitorDescription.Type = IDDCX_MONITOR_DESCRIPTION_TYPE_EDID;
|
||||
info.MonitorDescription.DataSize = (UINT)edid.size();
|
||||
info.MonitorDescription.pData = edid.empty() ? nullptr : edid.data();
|
||||
|
||||
HRESULT hr = CoCreateGuid(&info.MonitorContainerId);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to create the monitor container ID");
|
||||
return;
|
||||
}
|
||||
|
||||
IDARG_IN_MONITORCREATE create = {};
|
||||
create.ObjectAttributes = &attr;
|
||||
create.pMonitorInfo = &info;
|
||||
|
||||
IDARG_OUT_MONITORCREATE createOut = {};
|
||||
NTSTATUS status = IddCxMonitorCreate(adapter, &create, &createOut);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR_HR(status, "IddCxMonitorCreate Failed");
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_INFO("Monitor object created (%p)", createOut.MonitorObject);
|
||||
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
m_monitor = createOut.MonitorObject;
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
|
||||
auto * wrapper = WdfObjectGet_CMonitorContextWrapper(m_monitor);
|
||||
wrapper->context = new CMonitorContext(m_monitor, owner);
|
||||
|
||||
IDARG_OUT_MONITORARRIVAL out = {};
|
||||
status = IddCxMonitorArrival(m_monitor, &out);
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_ERROR_HR(status, "IddCxMonitorArrival Failed");
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_INFO("Monitor arrival reported successfully");
|
||||
}
|
||||
|
||||
CMonitorManager::ReplugAction CMonitorManager::Replug()
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
|
||||
if (m_replugMonitor || (m_swapChainAssigned && !m_swapChainReady))
|
||||
{
|
||||
// Coalesce changes received while a swap chain is being initialized, the
|
||||
// old one is draining, or its replacement is being initialized.
|
||||
m_replugPending = true;
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
return ReplugAction::NONE;
|
||||
}
|
||||
|
||||
IDDCX_MONITOR monitor = m_monitor;
|
||||
if (monitor == WDF_NO_HANDLE)
|
||||
{
|
||||
m_replugMonitor = true;
|
||||
m_monitorDeparted = true;
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
// Either no monitor yet, or one is already pending; build it now and
|
||||
// cancel any queued rebuild so we do not create two.
|
||||
m_createQueued.store(0);
|
||||
return ReplugAction::CREATE;
|
||||
}
|
||||
|
||||
// Clear the handle before departing so nothing calls an IddCx monitor API
|
||||
// on a departing/destroyed handle. Create publishes the new one.
|
||||
m_replugMonitor = true;
|
||||
m_monitorDeparted = false;
|
||||
m_waitForSwapChainRelease = m_swapChainAssigned;
|
||||
m_monitor = nullptr;
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
|
||||
DEBUG_TRACE("ReplugMonitor");
|
||||
NTSTATUS status = IddCxMonitorDeparture(monitor);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
m_replugMonitor = false;
|
||||
m_replugPending = false;
|
||||
m_monitorDeparted = false;
|
||||
m_waitForSwapChainRelease = false;
|
||||
m_monitor = monitor;
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
DEBUG_ERROR("IddCxMonitorDeparture Failed (0x%08x)", status);
|
||||
return ReplugAction::NONE;
|
||||
}
|
||||
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
m_monitorDeparted = true;
|
||||
const bool rebuild = !m_waitForSwapChainRelease;
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
|
||||
// If there was no swap chain there will be no unassign callback to queue
|
||||
// the rebuild. Otherwise OnSwapChainReleased does so after teardown drains.
|
||||
if (rebuild)
|
||||
m_createQueued.store(1);
|
||||
|
||||
return ReplugAction::NONE;
|
||||
}
|
||||
|
||||
void CMonitorManager::RequestMode(const CSettings::DisplayMode& mode)
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
m_setMode = mode;
|
||||
m_doSetMode = true;
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
}
|
||||
|
||||
void CMonitorManager::OnDestroyed(IDDCX_MONITOR monitor)
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
if (m_monitor == monitor)
|
||||
m_monitor = nullptr;
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
}
|
||||
|
||||
void CMonitorManager::OnSwapChainAssigned()
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
m_swapChainAssigned = true;
|
||||
m_swapChainReady = false;
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
}
|
||||
|
||||
void CMonitorManager::OnSwapChainReleased()
|
||||
{
|
||||
bool rebuild = false;
|
||||
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
m_swapChainAssigned = false;
|
||||
m_swapChainReady = false;
|
||||
if (m_replugMonitor && m_waitForSwapChainRelease)
|
||||
{
|
||||
m_waitForSwapChainRelease = false;
|
||||
rebuild = m_monitorDeparted;
|
||||
}
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
|
||||
if (rebuild)
|
||||
m_createQueued.store(1);
|
||||
}
|
||||
|
||||
CMonitorManager::ReadyAction CMonitorManager::OnSwapChainReady()
|
||||
{
|
||||
ReadyAction action = {};
|
||||
bool replug = false;
|
||||
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
m_swapChainReady = true;
|
||||
if (m_replugMonitor)
|
||||
{
|
||||
m_replugMonitor = false;
|
||||
m_monitorDeparted = false;
|
||||
if (m_replugPending)
|
||||
{
|
||||
m_replugPending = false;
|
||||
replug = true;
|
||||
}
|
||||
}
|
||||
else if (m_replugPending)
|
||||
{
|
||||
m_replugPending = false;
|
||||
replug = true;
|
||||
}
|
||||
|
||||
// Do not consume the requested mode on an intermediate replacement swap
|
||||
// chain. The last coalesced replug must be the one that applies it.
|
||||
if (!replug && m_doSetMode)
|
||||
{
|
||||
action.mode = m_setMode;
|
||||
m_doSetMode = false;
|
||||
action.setMode = true;
|
||||
}
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
|
||||
action.replug = replug;
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
void CMonitorManager::QueueReplug()
|
||||
{
|
||||
m_replugQueued.store(1);
|
||||
}
|
||||
|
||||
CMonitorManager::DeferredAction CMonitorManager::TakeDeferredAction()
|
||||
{
|
||||
if (m_createQueued.exchange(0))
|
||||
return DeferredAction::CREATE;
|
||||
|
||||
if (m_replugQueued.exchange(0))
|
||||
return DeferredAction::REPLUG;
|
||||
|
||||
return DeferredAction::NONE;
|
||||
}
|
||||
89
idd/LGIdd/display/CMonitorManager.h
Normal file
89
idd/LGIdd/display/CMonitorManager.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* 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 <wdf.h>
|
||||
#include <IddCx.h>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include "config/CSettings.h"
|
||||
|
||||
class CDeviceContext;
|
||||
|
||||
class CMonitorManager
|
||||
{
|
||||
public:
|
||||
enum class ReplugAction
|
||||
{
|
||||
NONE,
|
||||
CREATE,
|
||||
};
|
||||
|
||||
enum class DeferredAction
|
||||
{
|
||||
NONE,
|
||||
CREATE,
|
||||
REPLUG,
|
||||
};
|
||||
|
||||
struct ReadyAction
|
||||
{
|
||||
CSettings::DisplayMode mode = {};
|
||||
bool setMode = false;
|
||||
bool replug = false;
|
||||
};
|
||||
|
||||
private:
|
||||
IDDCX_MONITOR m_monitor = nullptr;
|
||||
|
||||
// Guards the monitor/replug/swap-chain state. These values are touched by
|
||||
// IddCx callback threads, the swap-chain thread, and the LGMP timer.
|
||||
SRWLOCK m_lock = SRWLOCK_INIT;
|
||||
|
||||
bool m_replugMonitor = false;
|
||||
bool m_replugPending = false;
|
||||
bool m_monitorDeparted = false;
|
||||
bool m_swapChainAssigned = false;
|
||||
bool m_swapChainReady = false;
|
||||
bool m_waitForSwapChainRelease = false;
|
||||
|
||||
CSettings::DisplayMode m_setMode = {};
|
||||
bool m_doSetMode = false;
|
||||
|
||||
std::atomic<LONG> m_createQueued = 0;
|
||||
std::atomic<LONG> m_replugQueued = 0;
|
||||
|
||||
public:
|
||||
void Create(UINT connectorIndex, IDDCX_ADAPTER adapter,
|
||||
std::vector<BYTE> edid, CDeviceContext * owner);
|
||||
ReplugAction Replug();
|
||||
void RequestMode(const CSettings::DisplayMode& mode);
|
||||
|
||||
void OnDestroyed(IDDCX_MONITOR monitor);
|
||||
void OnSwapChainAssigned();
|
||||
void OnSwapChainReleased();
|
||||
ReadyAction OnSwapChainReady();
|
||||
void QueueReplug();
|
||||
|
||||
DeferredAction TakeDeferredAction();
|
||||
};
|
||||
34
idd/LGIdd/display/IddCxCompat.h
Normal file
34
idd/LGIdd/display/IddCxCompat.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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 <wdf.h>
|
||||
#include <IddCx.h>
|
||||
|
||||
// IddCx 1.10 HDR/WCG types are only visible when the WDK targets
|
||||
// (NTDDI >= 0x0A000005) and the build flags select IddCx 1.10 or newer.
|
||||
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
|
||||
(IDDCX_VERSION_MAJOR > 1 || \
|
||||
(IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) && \
|
||||
NTDDI_VERSION >= 0x0A000005
|
||||
#define HAS_IDDCX_110
|
||||
#endif
|
||||
588
idd/LGIdd/display/device/CDeviceContext.cpp
Normal file
588
idd/LGIdd/display/device/CDeviceContext.cpp
Normal file
@@ -0,0 +1,588 @@
|
||||
/**
|
||||
* 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 "display/device/CDeviceContext.h"
|
||||
|
||||
#include "display/IddCxCompat.h"
|
||||
#include "transport/CPipeServer.h"
|
||||
#include "CDebug.h"
|
||||
|
||||
#include <dxgi1_2.h>
|
||||
#include <utility>
|
||||
|
||||
// Adapter and monitor lifecycle
|
||||
|
||||
static const UINT IDDCX_VERSION_1_10 = 0x1A00;
|
||||
|
||||
CDeviceContext::CDeviceContext(WDFDEVICE wdfDevice) :
|
||||
m_wdfDevice(wdfDevice),
|
||||
m_lgmpControl(m_lgmpHost),
|
||||
m_frameTransport(m_lgmpHost, m_ivshmem),
|
||||
m_displayConfiguration(g_settings)
|
||||
{
|
||||
}
|
||||
|
||||
CDeviceContext::~CDeviceContext()
|
||||
{
|
||||
// Both callbacks dereference this context. Drain them before the subsystem
|
||||
// members are destroyed in frame, control, host order.
|
||||
if (m_initTimer)
|
||||
{
|
||||
WdfTimerStop(m_initTimer, TRUE);
|
||||
m_initTimer = nullptr;
|
||||
}
|
||||
|
||||
if (m_lgmpTimer)
|
||||
{
|
||||
WdfTimerStop(m_lgmpTimer, TRUE);
|
||||
m_lgmpTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CDeviceContext::QueryIddCxCapabilities()
|
||||
{
|
||||
IDARG_OUT_GETVERSION ver = {};
|
||||
NTSTATUS status = IddCxGetVersion(&ver);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
m_iddCxVersion = 0;
|
||||
m_hasIddCx110DDIs = false;
|
||||
m_canProcessFP16 = false;
|
||||
DEBUG_ERROR_HR(status, "IddCxGetVersion Failed");
|
||||
return;
|
||||
}
|
||||
|
||||
m_iddCxVersion = ver.IddCxVersion;
|
||||
|
||||
#ifdef HAS_IDDCX_110
|
||||
const bool hasIddCx110DDIs =
|
||||
!!IDD_IS_FUNCTION_AVAILABLE(IddCxSwapChainReleaseAndAcquireBuffer2) &&
|
||||
!!IDD_IS_FUNCTION_AVAILABLE(IddCxMonitorQueryHardwareCursor3) &&
|
||||
!!IDD_IS_FUNCTION_AVAILABLE(IddCxMonitorUpdateModes2) &&
|
||||
IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxAdapterQueryTargetInfo) &&
|
||||
IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxAdapterCommitModes2) &&
|
||||
IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxParseMonitorDescription2) &&
|
||||
IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxMonitorQueryTargetModes2) &&
|
||||
IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxMonitorSetDefaultHdrMetaData) &&
|
||||
IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxMonitorSetGammaRamp);
|
||||
#else
|
||||
const bool hasIddCx110DDIs = false;
|
||||
#endif
|
||||
|
||||
m_hasIddCx110DDIs =
|
||||
m_iddCxVersion >= IDDCX_VERSION_1_10 && hasIddCx110DDIs;
|
||||
m_canProcessFP16 = !m_softwareMode && m_hasIddCx110DDIs;
|
||||
|
||||
DEBUG_INFO("IddCx version: 0x%04x", m_iddCxVersion);
|
||||
DEBUG_INFO("IddCx 1.10 HDR/WCG DDIs: %s",
|
||||
m_hasIddCx110DDIs ? "available" : "unavailable");
|
||||
if (m_softwareMode && m_hasIddCx110DDIs)
|
||||
DEBUG_INFO("HDR/WCG disabled for software rendering");
|
||||
}
|
||||
|
||||
void CDeviceContext::ScheduleInitRetry()
|
||||
{
|
||||
// Create the retry timer once; if it already exists it is either running or
|
||||
// will be (re)started below.
|
||||
if (!m_initTimer)
|
||||
{
|
||||
WDF_TIMER_CONFIG config;
|
||||
WDF_TIMER_CONFIG_INIT_PERIODIC(&config,
|
||||
[](WDFTIMER timer) -> void
|
||||
{
|
||||
WDFOBJECT parent = WdfTimerGetParentObject(timer);
|
||||
auto wrapper = WdfObjectGet_CDeviceContextWrapper(parent);
|
||||
wrapper->context->InitAdapter();
|
||||
},
|
||||
500);
|
||||
config.AutomaticSerialization = FALSE;
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES attribs;
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attribs);
|
||||
attribs.ParentObject = m_wdfDevice;
|
||||
attribs.ExecutionLevel = WdfExecutionLevelDispatch;
|
||||
|
||||
NTSTATUS status = WdfTimerCreate(&config, &attribs, &m_initTimer);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR_HR(status, "Init retry timer creation failed");
|
||||
m_initTimer = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WdfTimerStart(m_initTimer, WDF_REL_TIMEOUT_IN_MS(500));
|
||||
}
|
||||
|
||||
void CDeviceContext::StopInitRetry()
|
||||
{
|
||||
if (m_initTimer)
|
||||
WdfTimerStop(m_initTimer, FALSE);
|
||||
}
|
||||
|
||||
void CDeviceContext::InitAdapter()
|
||||
{
|
||||
DEBUG_TRACE("InitAdapter");
|
||||
|
||||
// The adapter only needs to be created once. D0Entry and the retry timer can
|
||||
// both land here, so guard against re-entrancy and repeated creation.
|
||||
if (m_adapter)
|
||||
{
|
||||
DEBUG_TRACE("Adapter initialization skipped: adapter already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
LONG initExpected = 0;
|
||||
if (!m_initInProgress.compare_exchange_strong(initExpected, 1))
|
||||
{
|
||||
DEBUG_TRACE("Adapter initialization skipped: initialization already in progress");
|
||||
return;
|
||||
}
|
||||
|
||||
// At boot the IVSHMEM PCI device may not have enumerated yet. Rather than
|
||||
// silently abandoning the adapter (leaving the device loaded but with no
|
||||
// monitor), retry from a timer until the shared memory becomes available.
|
||||
if (!m_ivshmemOpened)
|
||||
{
|
||||
if (!m_ivshmem.Init() || !m_ivshmem.Open())
|
||||
{
|
||||
DEBUG_WARN("IVSHMEM not available yet, scheduling init retry");
|
||||
ScheduleInitRetry();
|
||||
m_initInProgress.store(0);
|
||||
return;
|
||||
}
|
||||
m_ivshmemOpened = true;
|
||||
}
|
||||
|
||||
// Select the render adapter before advertising capabilities. If no hardware
|
||||
// adapter is available, this is a software-rendered display and must remain
|
||||
// SDR-only; the software path must never depend on compute processing.
|
||||
m_havePreferredRenderAdapter = false;
|
||||
m_preferredRenderAdapter = {};
|
||||
IDXGIFactory1 * factory = NULL;
|
||||
HRESULT factoryStatus = CreateDXGIFactory1(
|
||||
__uuidof(IDXGIFactory1), (void **)&factory);
|
||||
if (FAILED(factoryStatus))
|
||||
DEBUG_ERROR_HR(factoryStatus, "CreateDXGIFactory Failed");
|
||||
else
|
||||
{
|
||||
for (UINT i = 0;; ++i)
|
||||
{
|
||||
IDXGIAdapter1 * dxgiAdapter = nullptr;
|
||||
HRESULT enumStatus = factory->EnumAdapters1(i, &dxgiAdapter);
|
||||
if (enumStatus == DXGI_ERROR_NOT_FOUND)
|
||||
break;
|
||||
if (FAILED(enumStatus))
|
||||
{
|
||||
DEBUG_ERROR_HR(enumStatus, "Failed to enumerate DXGI adapter %u", i);
|
||||
break;
|
||||
}
|
||||
|
||||
DXGI_ADAPTER_DESC1 adapterDesc = {};
|
||||
HRESULT descStatus = dxgiAdapter->GetDesc1(&adapterDesc);
|
||||
dxgiAdapter->Release();
|
||||
if (FAILED(descStatus))
|
||||
{
|
||||
DEBUG_ERROR_HR(descStatus, "Failed to query DXGI adapter %u", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((adapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) ||
|
||||
(adapterDesc.VendorId == 0x1414 && adapterDesc.DeviceId == 0x008c))
|
||||
{
|
||||
DEBUG_INFO("Ignoring software render adapter %ls", adapterDesc.Description);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((adapterDesc.VendorId == 0x1b36 && adapterDesc.DeviceId == 0x000d) || // QXL
|
||||
(adapterDesc.VendorId == 0x1234 && adapterDesc.DeviceId == 0x1111)) // QEMU Standard VGA
|
||||
{
|
||||
DEBUG_INFO("Ignoring display-only adapter %ls (vendor 0x%04x, device 0x%04x)",
|
||||
adapterDesc.Description, adapterDesc.VendorId, adapterDesc.DeviceId);
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_INFO("Selected render adapter %ls (vendor 0x%04x, device 0x%04x)",
|
||||
adapterDesc.Description, adapterDesc.VendorId, adapterDesc.DeviceId);
|
||||
m_preferredRenderAdapter = adapterDesc.AdapterLuid;
|
||||
m_havePreferredRenderAdapter = true;
|
||||
break;
|
||||
}
|
||||
|
||||
factory->Release();
|
||||
}
|
||||
|
||||
m_softwareMode = !m_havePreferredRenderAdapter;
|
||||
if (m_softwareMode)
|
||||
DEBUG_INFO("No hardware render adapter available; using SDR software mode");
|
||||
|
||||
QueryIddCxCapabilities();
|
||||
DEBUG_TRACE("Initializing LGMP metadata");
|
||||
if (!InitializeLGMP())
|
||||
{
|
||||
m_initInProgress.store(0);
|
||||
return;
|
||||
}
|
||||
DEBUG_TRACE("Loading configured display modes");
|
||||
if (!m_displayConfiguration.Load(m_frameTransport.GetMemoryLimits()))
|
||||
{
|
||||
m_initInProgress.store(0);
|
||||
return;
|
||||
}
|
||||
DEBUG_TRACE("Initializing monitor EDID");
|
||||
m_displayConfiguration.InitializeEdid(CanProcessFP16());
|
||||
|
||||
const CDisplayConfiguration::Description description =
|
||||
m_displayConfiguration.GetDescription();
|
||||
DEBUG_INFO("Initializing adapter with %llu modes and a %u-byte EDID",
|
||||
(unsigned long long)description.modeCount,
|
||||
(UINT)description.edid.size());
|
||||
|
||||
IDDCX_ADAPTER_CAPS caps = {};
|
||||
caps.Size = sizeof(caps);
|
||||
|
||||
/**
|
||||
* For some reason if we do not set this flag sometimes windows will
|
||||
* refuse to enumerate our virtual monitor. Intel also noted in their
|
||||
* sources that if this is not set dynamic resolution changes from this
|
||||
* driver will not work. This behaviour is not documented by Microsoft.
|
||||
*/
|
||||
caps.Flags = IDDCX_ADAPTER_FLAGS_USE_SMALLEST_MODE;
|
||||
#ifdef HAS_IDDCX_110
|
||||
if (CanProcessFP16())
|
||||
caps.Flags |= IDDCX_ADAPTER_FLAGS_CAN_PROCESS_FP16;
|
||||
#endif
|
||||
|
||||
caps.MaxMonitorsSupported = 1;
|
||||
caps.StaticDesktopReencodeFrameCount = 1;
|
||||
|
||||
caps.EndPointDiagnostics.Size = sizeof(caps.EndPointDiagnostics);
|
||||
caps.EndPointDiagnostics.GammaSupport = IDDCX_FEATURE_IMPLEMENTATION_NONE;
|
||||
caps.EndPointDiagnostics.TransmissionType = IDDCX_TRANSMISSION_TYPE_OTHER;
|
||||
|
||||
caps.EndPointDiagnostics.pEndPointFriendlyName = L"Looking Glass IDD Driver";
|
||||
caps.EndPointDiagnostics.pEndPointManufacturerName = L"Looking Glass";
|
||||
caps.EndPointDiagnostics.pEndPointModelName = L"Looking Glass";
|
||||
|
||||
IDDCX_ENDPOINT_VERSION ver = {};
|
||||
ver.Size = sizeof(ver);
|
||||
ver.MajorVer = 1;
|
||||
caps.EndPointDiagnostics.pFirmwareVersion = &ver;
|
||||
caps.EndPointDiagnostics.pHardwareVersion = &ver;
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES attr;
|
||||
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, CDeviceContextWrapper);
|
||||
|
||||
IDARG_IN_ADAPTER_INIT init = {};
|
||||
init.WdfDevice = m_wdfDevice;
|
||||
init.pCaps = ∩︀
|
||||
init.ObjectAttributes = &attr;
|
||||
|
||||
IDARG_OUT_ADAPTER_INIT initOut = {};
|
||||
DEBUG_INFO("Calling IddCxAdapterInitAsync with flags 0x%08x",
|
||||
caps.Flags);
|
||||
NTSTATUS status = IddCxAdapterInitAsync(&init, &initOut);
|
||||
if (!NT_SUCCESS(status) && CanProcessFP16())
|
||||
{
|
||||
DEBUG_WARN(
|
||||
"IddCxAdapterInitAsync rejected FP16 adapter capabilities (0x%08x), retrying without HDR/WCG",
|
||||
status);
|
||||
m_canProcessFP16 = false;
|
||||
// The monitor has not been created yet, so replace the provisional HDR
|
||||
// EDID before Windows can observe it.
|
||||
m_displayConfiguration.RebuildEdid(false);
|
||||
caps.Flags = (IDDCX_ADAPTER_FLAGS)(caps.Flags & ~IDDCX_ADAPTER_FLAGS_CAN_PROCESS_FP16);
|
||||
ZeroMemory(&initOut, sizeof(initOut));
|
||||
status = IddCxAdapterInitAsync(&init, &initOut);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR_HR(status, "IddCxAdapterInitAsync Failed");
|
||||
m_initInProgress.store(0);
|
||||
return;
|
||||
}
|
||||
|
||||
m_adapter = initOut.AdapterObject;
|
||||
if (!m_adapter)
|
||||
{
|
||||
DEBUG_ERROR("IddCxAdapterInitAsync succeeded without returning an adapter object");
|
||||
m_initInProgress.store(0);
|
||||
return;
|
||||
}
|
||||
|
||||
auto * wrapper = WdfObjectGet_CDeviceContextWrapper(m_adapter);
|
||||
wrapper->context = this;
|
||||
DEBUG_INFO("IddCxAdapterInitAsync started successfully (adapter %p)",
|
||||
m_adapter);
|
||||
DEBUG_INFO("Adapter context attached; waiting for initialization callback");
|
||||
|
||||
// Adapter is up; no need to keep retrying.
|
||||
StopInitRetry();
|
||||
m_initInProgress.store(0);
|
||||
DEBUG_INFO("Adapter initialization request complete; returning to IddCx");
|
||||
}
|
||||
|
||||
void CDeviceContext::FinishAdapterInit(UINT connectorIndex)
|
||||
{
|
||||
// Try to co-exist with the virtual video device by telling IddCx which
|
||||
// hardware adapter we prefer to render on. Do this only after the adapter
|
||||
// has finished initializing, but before adding its monitor.
|
||||
if (m_havePreferredRenderAdapter)
|
||||
{
|
||||
IDARG_IN_ADAPTERSETRENDERADAPTER args = {};
|
||||
args.PreferredRenderAdapter = m_preferredRenderAdapter;
|
||||
IddCxAdapterSetRenderAdapter(m_adapter, &args);
|
||||
DEBUG_INFO("Preferred render adapter set");
|
||||
}
|
||||
|
||||
FinishInit(connectorIndex);
|
||||
}
|
||||
|
||||
void CDeviceContext::FinishInit(UINT connectorIndex)
|
||||
{
|
||||
CDisplayConfiguration::Description description =
|
||||
m_displayConfiguration.GetDescription();
|
||||
m_monitorManager.Create(
|
||||
connectorIndex, m_adapter, std::move(description.edid), this);
|
||||
}
|
||||
|
||||
void CDeviceContext::ReplugMonitor()
|
||||
{
|
||||
if (m_monitorManager.Replug() ==
|
||||
CMonitorManager::ReplugAction::CREATE)
|
||||
FinishInit(0);
|
||||
}
|
||||
|
||||
void CDeviceContext::ReloadSettings()
|
||||
{
|
||||
if (!m_displayConfiguration.ReloadSettings(
|
||||
m_frameTransport.GetMemoryLimits()))
|
||||
return;
|
||||
|
||||
ReplugMonitor();
|
||||
}
|
||||
|
||||
void CDeviceContext::OnMonitorDestroyed(IDDCX_MONITOR monitor)
|
||||
{
|
||||
m_monitorManager.OnDestroyed(monitor);
|
||||
}
|
||||
|
||||
void CDeviceContext::OnSwapChainAssigned()
|
||||
{
|
||||
m_monitorManager.OnSwapChainAssigned();
|
||||
}
|
||||
|
||||
void CDeviceContext::OnSwapChainReleased()
|
||||
{
|
||||
m_monitorManager.OnSwapChainReleased();
|
||||
}
|
||||
|
||||
void CDeviceContext::OnSwapChainReady()
|
||||
{
|
||||
const CMonitorManager::ReadyAction action =
|
||||
m_monitorManager.OnSwapChainReady();
|
||||
|
||||
// Do not expose the context to pipe reload requests until the initial swap
|
||||
// chain has reached the same ready state used by the replug gate.
|
||||
g_pipe.SetDeviceContext(this);
|
||||
|
||||
if (action.replug)
|
||||
m_monitorManager.QueueReplug();
|
||||
else if (action.setMode)
|
||||
g_pipe.SetDisplayMode(
|
||||
action.mode.width, action.mode.height, action.mode.refreshMilliHz);
|
||||
}
|
||||
|
||||
// Display configuration
|
||||
|
||||
void CDeviceContext::SetResolution(uint32_t width, uint32_t height)
|
||||
{
|
||||
const CDisplayConfiguration::ResolutionResult result =
|
||||
m_displayConfiguration.SetResolution(
|
||||
width, height, m_frameTransport.GetMemoryLimits());
|
||||
|
||||
switch (result.status)
|
||||
{
|
||||
case CDisplayConfiguration::ResolutionStatus::SUCCESS:
|
||||
m_monitorManager.RequestMode(result.mode);
|
||||
// IddCxMonitorUpdateModes[2] does not invalidate Windows' cached mode
|
||||
// list, so depart and re-arrive the monitor to rebuild the topology.
|
||||
ReplugMonitor();
|
||||
break;
|
||||
|
||||
case CDisplayConfiguration::ResolutionStatus::TOO_LARGE:
|
||||
g_pipe.ResolutionRejected(width, height, result.requiredMiB);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// LGMP transport
|
||||
|
||||
bool CDeviceContext::InitializeLGMP()
|
||||
{
|
||||
if (m_lgmpHost.IsInitialized())
|
||||
return true;
|
||||
|
||||
if (!m_lgmpHost.Initialize(m_ivshmem))
|
||||
return false;
|
||||
|
||||
// Preserve the shared-memory layout: frame queues precede the pointer queue
|
||||
// and its retained cursor and color-transform allocations.
|
||||
if (!m_frameTransport.Initialize() || !m_lgmpControl.Initialize())
|
||||
return false;
|
||||
|
||||
m_frameTransport.SealMemoryLayout();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDeviceContext::SetupLGMP(size_t alignSize)
|
||||
{
|
||||
// Frame buffers cannot be allocated until the GPU-specific alignment is
|
||||
// known. The swap-chain path may call this again after setup completed.
|
||||
if (m_frameTransport.GetMaxFrameSize())
|
||||
return true;
|
||||
|
||||
if (!InitializeLGMP() || !m_frameTransport.Setup(alignSize))
|
||||
return false;
|
||||
|
||||
WDF_TIMER_CONFIG config;
|
||||
WDF_TIMER_CONFIG_INIT_PERIODIC(&config,
|
||||
[](WDFTIMER timer) -> void
|
||||
{
|
||||
WDFOBJECT parent = WdfTimerGetParentObject(timer);
|
||||
auto wrapper = WdfObjectGet_CDeviceContextWrapper(parent);
|
||||
wrapper->context->LGMPTimer();
|
||||
},
|
||||
10);
|
||||
config.AutomaticSerialization = FALSE;
|
||||
|
||||
/**
|
||||
* Documentation states that Dispatch is not available under UMDF, however
|
||||
* using Passive returns a not-supported error and Dispatch works.
|
||||
*/
|
||||
WDF_OBJECT_ATTRIBUTES attribs;
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attribs);
|
||||
attribs.ParentObject = m_wdfDevice;
|
||||
attribs.ExecutionLevel = WdfExecutionLevelDispatch;
|
||||
|
||||
NTSTATUS status = WdfTimerCreate(
|
||||
&config, &attribs, &m_lgmpTimer);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR_HR(status, "Timer creation failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
WdfTimerStart(m_lgmpTimer, WDF_REL_TIMEOUT_IN_MS(10));
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDeviceContext::LGMPTimer()
|
||||
{
|
||||
// Monitor work is deferred off IddCx callback threads.
|
||||
switch (m_monitorManager.TakeDeferredAction())
|
||||
{
|
||||
case CMonitorManager::DeferredAction::CREATE:
|
||||
FinishInit(0);
|
||||
return;
|
||||
|
||||
case CMonitorManager::DeferredAction::REPLUG:
|
||||
ReplugMonitor();
|
||||
return;
|
||||
|
||||
case CMonitorManager::DeferredAction::NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
const LGMP_STATUS processStatus = m_lgmpHost.Process();
|
||||
if (processStatus != LGMP_OK)
|
||||
{
|
||||
if (processStatus == LGMP_ERR_CORRUPTED)
|
||||
{
|
||||
DEBUG_WARN(
|
||||
"LGMP reported the shared memory has been corrupted, attempting to recover\n");
|
||||
// TODO: reinitialize LGMP.
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_ERROR("lgmpHostProcess Failed: %s",
|
||||
lgmpStatusString(processStatus));
|
||||
// TODO: shut down LGMP.
|
||||
return;
|
||||
}
|
||||
|
||||
const uint64_t now = CFrameScheduler::Nanotime();
|
||||
|
||||
// Take the frame subscriber snapshot before processing scheduling messages,
|
||||
// then publish both updates together just as the original timer did.
|
||||
const CFrameTransport::SubscriberSnapshot subscribers =
|
||||
m_frameTransport.SnapshotSubscribers();
|
||||
|
||||
uint8_t data[LGMP_MSGS_SIZE];
|
||||
size_t size;
|
||||
uint32_t sourceClientID;
|
||||
LGMP_STATUS status;
|
||||
while ((status = m_lgmpControl.ReadDataWithSource(
|
||||
data, &size, &sourceClientID)) == LGMP_OK)
|
||||
{
|
||||
KVMFRMessage * msg = reinterpret_cast<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();
|
||||
}
|
||||
126
idd/LGIdd/display/device/CDeviceContext.h
Normal file
126
idd/LGIdd/display/device/CDeviceContext.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* 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 <wdf.h>
|
||||
#include <IddCx.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "display/CDisplayConfiguration.h"
|
||||
#include "display/CMonitorManager.h"
|
||||
#include "transport/CFrameTransport.h"
|
||||
#include "transport/CIVSHMEM.h"
|
||||
#include "transport/CLGMPControl.h"
|
||||
#include "transport/CLGMPHost.h"
|
||||
|
||||
class CDeviceContext
|
||||
{
|
||||
private:
|
||||
WDFDEVICE m_wdfDevice;
|
||||
IDDCX_ADAPTER m_adapter = nullptr;
|
||||
LUID m_preferredRenderAdapter = {};
|
||||
bool m_havePreferredRenderAdapter = false;
|
||||
|
||||
// At boot IVSHMEM may not have enumerated yet. The retry timer and atomic
|
||||
// gate keep adapter creation single-threaded until it becomes available.
|
||||
WDFTIMER m_initTimer = nullptr;
|
||||
bool m_ivshmemOpened = false;
|
||||
std::atomic<LONG> m_initInProgress = 0;
|
||||
|
||||
CIVSHMEM m_ivshmem;
|
||||
CLGMPHost m_lgmpHost;
|
||||
CLGMPControl m_lgmpControl;
|
||||
CFrameTransport m_frameTransport;
|
||||
CDisplayConfiguration m_displayConfiguration;
|
||||
CMonitorManager m_monitorManager;
|
||||
|
||||
WDFTIMER m_lgmpTimer = nullptr;
|
||||
|
||||
UINT m_iddCxVersion = 0;
|
||||
bool m_hasIddCx110DDIs = false;
|
||||
bool m_canProcessFP16 = false;
|
||||
bool m_softwareMode = true;
|
||||
|
||||
void QueryIddCxCapabilities();
|
||||
|
||||
void ScheduleInitRetry();
|
||||
void StopInitRetry();
|
||||
|
||||
bool InitializeLGMP();
|
||||
void LGMPTimer();
|
||||
void SetResolution(uint32_t width, uint32_t height);
|
||||
|
||||
public:
|
||||
explicit CDeviceContext(_In_ WDFDEVICE wdfDevice);
|
||||
~CDeviceContext();
|
||||
|
||||
CDeviceContext(const CDeviceContext&) = delete;
|
||||
CDeviceContext& operator=(const CDeviceContext&) = delete;
|
||||
|
||||
bool SetupLGMP(size_t alignSize);
|
||||
|
||||
void InitAdapter();
|
||||
void FinishAdapterInit(UINT connectorIndex);
|
||||
void FinishInit(UINT connectorIndex);
|
||||
void ReloadSettings();
|
||||
void ReplugMonitor();
|
||||
|
||||
void OnMonitorDestroyed(IDDCX_MONITOR monitor);
|
||||
void OnSwapChainAssigned();
|
||||
void OnSwapChainReleased();
|
||||
void OnSwapChainReady();
|
||||
|
||||
bool HasIddCx110DDIs() const { return m_hasIddCx110DDIs; }
|
||||
bool CanProcessFP16 () const { return m_canProcessFP16; }
|
||||
bool IsSoftwareMode () const { return m_softwareMode; }
|
||||
|
||||
CFrameTransport& GetFrameTransport()
|
||||
{
|
||||
return m_frameTransport;
|
||||
}
|
||||
|
||||
CLGMPControl& GetLGMPControl()
|
||||
{
|
||||
return m_lgmpControl;
|
||||
}
|
||||
|
||||
CDisplayConfiguration& GetDisplayConfiguration()
|
||||
{
|
||||
return m_displayConfiguration;
|
||||
}
|
||||
};
|
||||
|
||||
struct CDeviceContextWrapper
|
||||
{
|
||||
CDeviceContext * context;
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
delete context;
|
||||
context = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
WDF_DECLARE_CONTEXT_TYPE(CDeviceContextWrapper);
|
||||
@@ -18,23 +18,26 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CIndirectMonitorContext.h"
|
||||
#include "display/monitor/Context.h"
|
||||
#include "display/device/CDeviceContext.h"
|
||||
#include "capture/CSwapChainProcessor.h"
|
||||
#include "d3d/CD3D11Device.h"
|
||||
#include "CDebug.h"
|
||||
#include "CPipeServer.h"
|
||||
|
||||
CIndirectMonitorContext::CIndirectMonitorContext(_In_ IDDCX_MONITOR monitor, CIndirectDeviceContext * device) :
|
||||
CMonitorContext::CMonitorContext(
|
||||
_In_ IDDCX_MONITOR monitor, CDeviceContext * device) :
|
||||
m_monitor(monitor),
|
||||
m_devContext(device)
|
||||
{
|
||||
}
|
||||
|
||||
CIndirectMonitorContext::~CIndirectMonitorContext()
|
||||
CMonitorContext::~CMonitorContext()
|
||||
{
|
||||
UnassignSwapChain();
|
||||
m_devContext->OnMonitorDestroyed(m_monitor);
|
||||
}
|
||||
|
||||
NTSTATUS CIndirectMonitorContext::AssignSwapChain(
|
||||
NTSTATUS CMonitorContext::AssignSwapChain(
|
||||
IDDCX_SWAPCHAIN swapChain, LUID renderAdapter, HANDLE newFrameEvent)
|
||||
{
|
||||
std::lock_guard<std::mutex> assignGuard(m_assignMutex);
|
||||
@@ -89,7 +92,7 @@ NTSTATUS CIndirectMonitorContext::AssignSwapChain(
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void CIndirectMonitorContext::DetachSwapChain()
|
||||
void CMonitorContext::DetachSwapChain()
|
||||
{
|
||||
// Invalidate setup in progress before waiting for m_lock. This also lets a
|
||||
// worker about to call SetDevice observe an unassign whose callback is
|
||||
@@ -115,7 +118,7 @@ void CIndirectMonitorContext::DetachSwapChain()
|
||||
m_devContext->OnSwapChainReleased();
|
||||
}
|
||||
|
||||
void CIndirectMonitorContext::UnassignSwapChain()
|
||||
void CMonitorContext::UnassignSwapChain()
|
||||
{
|
||||
DetachSwapChain();
|
||||
}
|
||||
@@ -27,12 +27,12 @@
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include "CIndirectDeviceContext.h"
|
||||
#include "CSwapChainProcessor.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
struct CD3D11Device;
|
||||
class CDeviceContext;
|
||||
class CSwapChainProcessor;
|
||||
|
||||
class CIndirectMonitorContext
|
||||
class CMonitorContext
|
||||
{
|
||||
private:
|
||||
IDDCX_MONITOR m_monitor;
|
||||
@@ -48,7 +48,7 @@ private:
|
||||
std::mutex m_assignMutex;
|
||||
std::shared_ptr<CD3D11Device> m_dx11Device;
|
||||
|
||||
CIndirectDeviceContext * m_devContext;
|
||||
CDeviceContext * m_devContext;
|
||||
std::unique_ptr<CSwapChainProcessor> m_swapChain;
|
||||
|
||||
// Incremented whenever the current assignment is replaced or unassigned.
|
||||
@@ -59,10 +59,11 @@ private:
|
||||
void DetachSwapChain();
|
||||
|
||||
public:
|
||||
CIndirectMonitorContext(_In_ IDDCX_MONITOR monitor, CIndirectDeviceContext * device);
|
||||
CMonitorContext(
|
||||
_In_ IDDCX_MONITOR monitor, CDeviceContext * device);
|
||||
|
||||
virtual ~CMonitorContext();
|
||||
|
||||
virtual ~CIndirectMonitorContext();
|
||||
|
||||
NTSTATUS AssignSwapChain(
|
||||
IDDCX_SWAPCHAIN swapChain, LUID renderAdapter, HANDLE newFrameEvent);
|
||||
void UnassignSwapChain();
|
||||
@@ -71,12 +72,12 @@ public:
|
||||
return m_assignmentGeneration.load(std::memory_order_acquire) == generation;
|
||||
}
|
||||
|
||||
CIndirectDeviceContext * GetDeviceContext() { return m_devContext; }
|
||||
CDeviceContext * GetDeviceContext() { return m_devContext; }
|
||||
};
|
||||
|
||||
struct CIndirectMonitorContextWrapper
|
||||
struct CMonitorContextWrapper
|
||||
{
|
||||
CIndirectMonitorContext* context;
|
||||
CMonitorContext * context;
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
@@ -85,4 +86,4 @@ struct CIndirectMonitorContextWrapper
|
||||
}
|
||||
};
|
||||
|
||||
WDF_DECLARE_CONTEXT_TYPE(CIndirectMonitorContextWrapper);
|
||||
WDF_DECLARE_CONTEXT_TYPE(CMonitorContextWrapper);
|
||||
@@ -18,7 +18,7 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CPlatformInfo.h"
|
||||
#include "platform/CPlatformInfo.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
#include <Windows.h>
|
||||
@@ -310,4 +310,4 @@ void CPlatformInfo::InitCPUInfo()
|
||||
}
|
||||
|
||||
_freea(buffer);
|
||||
}
|
||||
}
|
||||
@@ -48,4 +48,4 @@ public:
|
||||
inline static int GetCoreCount() { return m_cores; }
|
||||
inline static int GetProcCount() { return m_procs; }
|
||||
inline static int GetSocketCount() { return m_sockets; }
|
||||
};
|
||||
};
|
||||
@@ -18,14 +18,14 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CPostProcessor.h"
|
||||
#include "postprocess/CPostProcessor.h"
|
||||
|
||||
#include "CD3D12Device.h"
|
||||
#include "d3d/CD3D12Device.h"
|
||||
#include "CDebug.h"
|
||||
#include "effect/CColorTransformEffect.h"
|
||||
#include "effect/CDownsampleEffect.h"
|
||||
#include "effect/CHDR16to10Effect.h"
|
||||
#include "effect/CRGB24Effect.h"
|
||||
#include "postprocess/effect/CColorTransformEffect.h"
|
||||
#include "postprocess/effect/CDownsampleEffect.h"
|
||||
#include "postprocess/effect/CHDR16to10Effect.h"
|
||||
#include "postprocess/effect/CRGB24Effect.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
@@ -23,15 +23,12 @@
|
||||
#include <Windows.h>
|
||||
#include <wrl/client.h>
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_5.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
struct CD3D12Device;
|
||||
#include "postprocess/D12FrameFormat.h"
|
||||
|
||||
extern "C" {
|
||||
#include "common/types.h"
|
||||
}
|
||||
struct CD3D12Device;
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
@@ -42,46 +39,6 @@ enum class PostProcessStatus
|
||||
FAILED
|
||||
};
|
||||
|
||||
struct D12ColorTransform
|
||||
{
|
||||
bool matrixEnabled = false;
|
||||
float matrix[3][4] = {};
|
||||
float scalar = 1.0f;
|
||||
bool lutEnabled = false;
|
||||
float lut[4096][4] = {};
|
||||
};
|
||||
|
||||
bool IsIdentityColorTransform(const D12ColorTransform& transform);
|
||||
|
||||
struct D12FrameFormat
|
||||
{
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
unsigned dataWidth = 0;
|
||||
unsigned dataHeight = 0;
|
||||
unsigned pitch = 0;
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
FrameType format = FRAME_TYPE_INVALID;
|
||||
bool hdr = false;
|
||||
bool hdrPQ = false;
|
||||
bool hdrMetadata = false;
|
||||
uint32_t sdrWhiteLevel = LG_SDR_WHITE_LEVEL_DEFAULT;
|
||||
std::shared_ptr<const D12ColorTransform> colorTransform;
|
||||
|
||||
// HDR static metadata (SMPTE ST 2086)
|
||||
// Display color primaries in 0.00002 units (xy coordinates)
|
||||
uint16_t displayPrimary[3][2];
|
||||
// White point in 0.00002 units
|
||||
uint16_t whitePoint[2];
|
||||
// Max mastering display luminance in whole cd/m²
|
||||
uint32_t maxDisplayLuminance;
|
||||
// Min mastering display luminance in 0.0001 cd/m² units
|
||||
uint32_t minDisplayLuminance;
|
||||
// MaxCLL and MaxFALL in cd/m²
|
||||
uint32_t maxContentLightLevel;
|
||||
uint32_t maxFrameAverageLightLevel;
|
||||
};
|
||||
|
||||
class CPostProcessEffect
|
||||
{
|
||||
public:
|
||||
70
idd/LGIdd/postprocess/D12FrameFormat.h
Normal file
70
idd/LGIdd/postprocess/D12FrameFormat.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 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 <d3d12.h>
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
#include "common/types.h"
|
||||
}
|
||||
|
||||
struct D12ColorTransform
|
||||
{
|
||||
bool matrixEnabled = false;
|
||||
float matrix[3][4] = {};
|
||||
float scalar = 1.0f;
|
||||
bool lutEnabled = false;
|
||||
float lut[4096][4] = {};
|
||||
};
|
||||
|
||||
bool IsIdentityColorTransform(const D12ColorTransform& transform);
|
||||
|
||||
struct D12FrameFormat
|
||||
{
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
unsigned dataWidth = 0;
|
||||
unsigned dataHeight = 0;
|
||||
unsigned pitch = 0;
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
FrameType format = FRAME_TYPE_INVALID;
|
||||
bool hdr = false;
|
||||
bool hdrPQ = false;
|
||||
bool hdrMetadata = false;
|
||||
uint32_t sdrWhiteLevel = LG_SDR_WHITE_LEVEL_DEFAULT;
|
||||
std::shared_ptr<const D12ColorTransform> colorTransform;
|
||||
|
||||
// HDR static metadata (SMPTE ST 2086)
|
||||
// Display color primaries in 0.00002 units (xy coordinates)
|
||||
uint16_t displayPrimary[3][2];
|
||||
// White point in 0.00002 units
|
||||
uint16_t whitePoint[2];
|
||||
// Max mastering display luminance in whole cd/m²
|
||||
uint32_t maxDisplayLuminance;
|
||||
// Min mastering display luminance in 0.0001 cd/m² units
|
||||
uint32_t minDisplayLuminance;
|
||||
// MaxCLL and MaxFALL in cd/m²
|
||||
uint32_t maxContentLightLevel;
|
||||
uint32_t maxFrameAverageLightLevel;
|
||||
};
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../CPostProcessor.h"
|
||||
#include "postprocess/CPostProcessor.h"
|
||||
|
||||
|
||||
#define POST_PROCESS_THREADS_STR "8"
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "CDownsampleEffect.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
#include "../CSettings.h"
|
||||
#include "config/CSettings.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "CRGB24Effect.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
#include "../CSettings.h"
|
||||
#include "config/CSettings.h"
|
||||
#include "common/LGMPConfig.h"
|
||||
|
||||
#include <algorithm>
|
||||
1296
idd/LGIdd/transport/CFrameTransport.cpp
Normal file
1296
idd/LGIdd/transport/CFrameTransport.cpp
Normal file
File diff suppressed because it is too large
Load Diff
209
idd/LGIdd/transport/CFrameTransport.h
Normal file
209
idd/LGIdd/transport/CFrameTransport.h
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* 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 "capture/CFrameScheduler.h"
|
||||
#include "capture/FrameBufferTypes.h"
|
||||
#include "common/KVMFR.h"
|
||||
#include "postprocess/D12FrameFormat.h"
|
||||
#include "transport/FrameMemoryLimits.h"
|
||||
|
||||
class CIVSHMEM;
|
||||
class CLGMPHost;
|
||||
|
||||
class CFrameTransport
|
||||
{
|
||||
public:
|
||||
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] = {};
|
||||
FrameBuffer * 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);
|
||||
|
||||
public:
|
||||
CFrameTransport(CLGMPHost& host, CIVSHMEM& ivshmem);
|
||||
~CFrameTransport();
|
||||
|
||||
CFrameTransport(const CFrameTransport&) = delete;
|
||||
CFrameTransport& operator=(const CFrameTransport&) = delete;
|
||||
|
||||
bool Initialize();
|
||||
void SealMemoryLayout();
|
||||
bool Setup(size_t alignSize);
|
||||
void DeInit();
|
||||
|
||||
FrameMemoryLimits GetMemoryLimits() const;
|
||||
size_t GetMaxFrameSize() const { return m_maxFrameSize; }
|
||||
CIVSHMEM& GetIVSHMEM() { return m_ivshmem; }
|
||||
|
||||
SubscriberSnapshot SnapshotSubscribers() const;
|
||||
void FinalizeSubscribers(
|
||||
const SubscriberSnapshot& snapshot, uint64_t now);
|
||||
bool UpdateSchedule(uint32_t sourceClientID,
|
||||
const KVMFRFrameSchedule& schedule, uint64_t now);
|
||||
|
||||
bool FrameBufferAvailable(const CFrameScheduler::Schedule& schedule,
|
||||
bool allowReadyReplacement = true);
|
||||
bool HasPublishedFrame() const
|
||||
{
|
||||
return m_readyFrameIndex.load(std::memory_order_acquire) >= 0;
|
||||
}
|
||||
void ProcessFrameQueue();
|
||||
bool GetSharedFrameTarget(uint64_t now, uint64_t& target);
|
||||
bool ReplaySharedFrame(uint64_t now, bool& retry);
|
||||
PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch,
|
||||
const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat,
|
||||
const RECT * dirtyRects, unsigned nbDirtyRects,
|
||||
const CFrameScheduler::Schedule& schedule,
|
||||
bool allowReadyReplacement = true);
|
||||
bool PublishFrameBuffer(unsigned frameIndex,
|
||||
const CFrameScheduler::Schedule& schedule, bool& deliveredToOwner);
|
||||
bool RepublishFrameBuffer(const CFrameScheduler::Schedule& schedule);
|
||||
bool TryFrameSubmitted(unsigned frameIndex,
|
||||
const CFrameScheduler::Schedule& schedule);
|
||||
void CommitFrameBuffer(unsigned frameIndex,
|
||||
const CFrameScheduler::Schedule& schedule, bool periodic,
|
||||
bool deliveredToOwner);
|
||||
void AbortFrameBuffer(unsigned frameIndex);
|
||||
void FailFrameBuffer(unsigned frameIndex);
|
||||
void CompleteFrameBuffer(unsigned frameIndex, bool succeeded);
|
||||
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);
|
||||
void WriteFrameBuffer(unsigned frameIndex, void * src, size_t offset,
|
||||
size_t len, bool setWritePos) const;
|
||||
void WriteFrameBufferRows(unsigned frameIndex, void * src,
|
||||
size_t offset, size_t rowBytes, size_t pitch, unsigned rows) const;
|
||||
void FinalizeFrameBuffer(unsigned frameIndex) const;
|
||||
|
||||
void ObserveFrame(uint64_t now);
|
||||
void ForceFrame();
|
||||
bool GetPublishTarget(uint64_t now, uint64_t& target,
|
||||
CFrameScheduler::Schedule& schedule, bool& periodic, bool& republish);
|
||||
void FrameMissed(const CFrameScheduler::Schedule& schedule,
|
||||
uint64_t now, bool periodic);
|
||||
void FrameSuperseded();
|
||||
HANDLE GetFrameScheduleEvent() const
|
||||
{
|
||||
return m_frameScheduler.GetWakeEvent();
|
||||
}
|
||||
void TryRecordFrameTiming(uint64_t duration);
|
||||
};
|
||||
@@ -18,7 +18,7 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CIVSHMEM.h"
|
||||
#include "transport/CIVSHMEM.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <SetupAPI.h>
|
||||
@@ -205,4 +205,4 @@ void CIVSHMEM::Close()
|
||||
|
||||
m_size = 0;
|
||||
m_mem = nullptr;
|
||||
}
|
||||
}
|
||||
301
idd/LGIdd/transport/CLGMPControl.cpp
Normal file
301
idd/LGIdd/transport/CLGMPControl.cpp
Normal file
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
* 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/CLGMPControl.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
static const uint32_t MAX_POINTER_SIZE =
|
||||
(uint32_t)(sizeof(KVMFRCursor) + (512 * 512 * 4));
|
||||
|
||||
static const struct LGMPQueueConfig POINTER_QUEUE_CONFIG =
|
||||
{
|
||||
LGMP_Q_POINTER, //queueID
|
||||
LGMP_Q_POINTER_LEN, //numMesages
|
||||
1000 //subTimeout
|
||||
};
|
||||
|
||||
CLGMPControl::~CLGMPControl()
|
||||
{
|
||||
DeInit();
|
||||
}
|
||||
|
||||
bool CLGMPControl::Initialize()
|
||||
{
|
||||
if (m_pointerQueue)
|
||||
return true;
|
||||
|
||||
LGMP_STATUS status;
|
||||
if ((status = m_host.CreateQueue(
|
||||
POINTER_QUEUE_CONFIG, &m_pointerQueue)) != LGMP_OK)
|
||||
{
|
||||
DEBUG_ERROR("lgmpHostQueueCreate Failed (Pointer): %s",
|
||||
lgmpStatusString(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LGMP_Q_POINTER_LEN; ++i)
|
||||
{
|
||||
if ((status = m_host.Allocate(
|
||||
MAX_POINTER_SIZE, &m_pointerMemory[i])) != LGMP_OK)
|
||||
{
|
||||
DEBUG_ERROR("lgmpHostMemAlloc Failed (Pointer): %s",
|
||||
lgmpStatusString(status));
|
||||
return false;
|
||||
}
|
||||
memset(lgmpHostMemPtr(m_pointerMemory[i]), 0, MAX_POINTER_SIZE);
|
||||
}
|
||||
|
||||
for (int i = 0; i < POINTER_SHAPE_BUFFERS; ++i)
|
||||
{
|
||||
if ((status = m_host.Allocate(
|
||||
MAX_POINTER_SIZE, &m_pointerShapeMemory[i])) != LGMP_OK)
|
||||
{
|
||||
DEBUG_ERROR("lgmpHostMemAlloc Failed (Pointer Shapes): %s",
|
||||
lgmpStatusString(status));
|
||||
return false;
|
||||
}
|
||||
memset(lgmpHostMemPtr(m_pointerShapeMemory[i]), 0, MAX_POINTER_SIZE);
|
||||
}
|
||||
|
||||
for (int i = 0; i < COLOR_TRANSFORM_BUFFERS; ++i)
|
||||
{
|
||||
if ((status = m_host.Allocate(
|
||||
sizeof(KVMFRCursor) + sizeof(KVMFRColorTransform),
|
||||
&m_pointerTransformMemory[i])) != LGMP_OK)
|
||||
{
|
||||
DEBUG_ERROR("lgmpHostMemAlloc Failed (Pointer Transform): %s",
|
||||
lgmpStatusString(status));
|
||||
return false;
|
||||
}
|
||||
memset(lgmpHostMemPtr(m_pointerTransformMemory[i]), 0,
|
||||
sizeof(KVMFRCursor) + sizeof(KVMFRColorTransform));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLGMPControl::DeInit()
|
||||
{
|
||||
for (int i = 0; i < LGMP_Q_POINTER_LEN; ++i)
|
||||
lgmpHostMemFree(&m_pointerMemory[i]);
|
||||
for (int i = 0; i < POINTER_SHAPE_BUFFERS; ++i)
|
||||
lgmpHostMemFree(&m_pointerShapeMemory[i]);
|
||||
for (int i = 0; i < COLOR_TRANSFORM_BUFFERS; ++i)
|
||||
lgmpHostMemFree(&m_pointerTransformMemory[i]);
|
||||
|
||||
m_pointerQueue = nullptr;
|
||||
m_pointerShape = nullptr;
|
||||
m_pointerMemoryIndex = 0;
|
||||
m_pointerShapeIndex = 0;
|
||||
m_pointerTransformIndex = 0;
|
||||
}
|
||||
|
||||
LGMP_STATUS CLGMPControl::ReadDataWithSource(void * data, size_t * size,
|
||||
uint32_t * sourceClientID)
|
||||
{
|
||||
return lgmpHostReadDataWithSource(
|
||||
m_pointerQueue, data, size, sourceClientID);
|
||||
}
|
||||
|
||||
LGMP_STATUS CLGMPControl::AckData()
|
||||
{
|
||||
return lgmpHostAckData(m_pointerQueue);
|
||||
}
|
||||
|
||||
bool CLGMPControl::HasNewSubscribers()
|
||||
{
|
||||
return lgmpHostQueueNewSubs(m_pointerQueue) != 0;
|
||||
}
|
||||
|
||||
void CLGMPControl::SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info,
|
||||
const BYTE * data, UINT sdrWhiteLevel)
|
||||
{
|
||||
PLGMPMemory mem;
|
||||
if (info.CursorShapeInfo.CursorType == IDDCX_CURSOR_SHAPE_TYPE_UNINITIALIZED)
|
||||
{
|
||||
mem = m_pointerMemory[m_pointerMemoryIndex];
|
||||
if (++m_pointerMemoryIndex == LGMP_Q_POINTER_LEN)
|
||||
m_pointerMemoryIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mem = m_pointerShapeMemory[m_pointerShapeIndex];
|
||||
if (++m_pointerShapeIndex == POINTER_SHAPE_BUFFERS)
|
||||
m_pointerShapeIndex = 0;
|
||||
}
|
||||
|
||||
KVMFRCursor * cursor = (KVMFRCursor *)lgmpHostMemPtr(mem);
|
||||
cursor->sdrWhiteLevel = sdrWhiteLevel ?
|
||||
sdrWhiteLevel : KVMFR_SDR_WHITE_LEVEL_DEFAULT;
|
||||
|
||||
m_cursorVisible = info.IsCursorVisible;
|
||||
uint32_t flags = CURSOR_FLAG_VISIBLE_VALID;
|
||||
|
||||
if (info.IsCursorVisible)
|
||||
{
|
||||
m_cursorX = info.X;
|
||||
m_cursorY = info.Y;
|
||||
cursor->x = (int16_t)info.X;
|
||||
cursor->y = (int16_t)info.Y;
|
||||
flags |= CURSOR_FLAG_POSITION | CURSOR_FLAG_VISIBLE;
|
||||
}
|
||||
|
||||
if (info.CursorShapeInfo.CursorType != IDDCX_CURSOR_SHAPE_TYPE_UNINITIALIZED)
|
||||
{
|
||||
memcpy(cursor + 1, data,
|
||||
(size_t)info.CursorShapeInfo.Height * info.CursorShapeInfo.Pitch);
|
||||
|
||||
cursor->hx = (int8_t )info.CursorShapeInfo.XHot;
|
||||
cursor->hy = (int8_t )info.CursorShapeInfo.YHot;
|
||||
cursor->width = (uint32_t)info.CursorShapeInfo.Width;
|
||||
cursor->height = (uint32_t)info.CursorShapeInfo.Height;
|
||||
cursor->pitch = (uint32_t)info.CursorShapeInfo.Pitch;
|
||||
|
||||
switch (info.CursorShapeInfo.CursorType)
|
||||
{
|
||||
case IDDCX_CURSOR_SHAPE_TYPE_ALPHA:
|
||||
cursor->type = CURSOR_TYPE_COLOR;
|
||||
break;
|
||||
|
||||
case IDDCX_CURSOR_SHAPE_TYPE_MASKED_COLOR:
|
||||
cursor->type = CURSOR_TYPE_MASKED_COLOR;
|
||||
break;
|
||||
}
|
||||
|
||||
flags |= CURSOR_FLAG_SHAPE;
|
||||
m_pointerShape = mem;
|
||||
}
|
||||
|
||||
LGMP_STATUS status;
|
||||
while ((status = lgmpHostQueuePost(
|
||||
m_pointerQueue, flags, mem)) != LGMP_OK)
|
||||
{
|
||||
if (status == LGMP_ERR_QUEUE_FULL)
|
||||
{
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_ERROR("lgmpHostQueuePost Failed (Pointer): %s",
|
||||
lgmpStatusString(status));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CLGMPControl::SetColorTransform(
|
||||
std::shared_ptr<const D12ColorTransform> transform)
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_colorTransformLock);
|
||||
m_colorTransform = std::move(transform);
|
||||
ReleaseSRWLockExclusive(&m_colorTransformLock);
|
||||
SendColorTransform();
|
||||
}
|
||||
|
||||
std::shared_ptr<const D12ColorTransform>
|
||||
CLGMPControl::GetColorTransform() const
|
||||
{
|
||||
AcquireSRWLockShared(&m_colorTransformLock);
|
||||
std::shared_ptr<const D12ColorTransform> transform = m_colorTransform;
|
||||
ReleaseSRWLockShared(&m_colorTransformLock);
|
||||
return transform;
|
||||
}
|
||||
|
||||
void CLGMPControl::SendColorTransform()
|
||||
{
|
||||
if (!m_pointerQueue || !m_pointerTransformMemory[0])
|
||||
return;
|
||||
|
||||
PLGMPMemory mem = m_pointerTransformMemory[m_pointerTransformIndex];
|
||||
if (++m_pointerTransformIndex == COLOR_TRANSFORM_BUFFERS)
|
||||
m_pointerTransformIndex = 0;
|
||||
|
||||
KVMFRCursor * cursor = (KVMFRCursor *)lgmpHostMemPtr(mem);
|
||||
KVMFRColorTransform * output =
|
||||
(KVMFRColorTransform *)(cursor + 1);
|
||||
const auto transform = GetColorTransform();
|
||||
|
||||
output->flags = 0;
|
||||
if (transform)
|
||||
{
|
||||
if (transform->matrixEnabled)
|
||||
output->flags |= KVMFR_COLOR_TRANSFORM_MATRIX;
|
||||
if (transform->lutEnabled)
|
||||
output->flags |= KVMFR_COLOR_TRANSFORM_LUT;
|
||||
memcpy(output->matrix, transform->matrix, sizeof(output->matrix));
|
||||
output->scalar = transform->scalar;
|
||||
memcpy(output->lut, transform->lut, sizeof(output->lut));
|
||||
}
|
||||
|
||||
LGMP_STATUS status;
|
||||
while ((status = lgmpHostQueuePost(m_pointerQueue,
|
||||
CURSOR_FLAG_COLOR_TRANSFORM, mem)) != LGMP_OK)
|
||||
{
|
||||
if (status == LGMP_ERR_QUEUE_FULL)
|
||||
{
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_ERROR("lgmpHostQueuePost Failed (Pointer Transform): %s",
|
||||
lgmpStatusString(status));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CLGMPControl::ResendCursor()
|
||||
{
|
||||
PLGMPMemory mem = m_pointerShape;
|
||||
if (!mem)
|
||||
return;
|
||||
|
||||
KVMFRCursor* cursor = (KVMFRCursor*)lgmpHostMemPtr(mem);
|
||||
cursor->x = (int16_t)m_cursorX;
|
||||
cursor->y = (int16_t)m_cursorY;
|
||||
|
||||
const uint32_t flags =
|
||||
CURSOR_FLAG_POSITION | CURSOR_FLAG_SHAPE | CURSOR_FLAG_VISIBLE_VALID |
|
||||
(m_cursorVisible ? CURSOR_FLAG_VISIBLE : 0);
|
||||
|
||||
LGMP_STATUS status;
|
||||
while ((status = lgmpHostQueuePost(
|
||||
m_pointerQueue, flags, mem)) != LGMP_OK)
|
||||
{
|
||||
if (status == LGMP_ERR_QUEUE_FULL)
|
||||
{
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_ERROR("lgmpHostQueuePost Failed (Pointer): %s",
|
||||
lgmpStatusString(status));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CLGMPControl::ResendState()
|
||||
{
|
||||
ResendCursor();
|
||||
SendColorTransform();
|
||||
}
|
||||
82
idd/LGIdd/transport/CLGMPControl.h
Normal file
82
idd/LGIdd/transport/CLGMPControl.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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/CLGMPHost.h"
|
||||
#include "postprocess/D12FrameFormat.h"
|
||||
|
||||
#include "common/KVMFR.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <wdf.h>
|
||||
#include <IddCx.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class CLGMPControl
|
||||
{
|
||||
private:
|
||||
static constexpr int POINTER_SHAPE_BUFFERS = 3;
|
||||
static constexpr int COLOR_TRANSFORM_BUFFERS = 3;
|
||||
|
||||
CLGMPHost& m_host;
|
||||
|
||||
PLGMPHostQueue m_pointerQueue = nullptr;
|
||||
PLGMPMemory m_pointerMemory[LGMP_Q_POINTER_LEN] = {};
|
||||
PLGMPMemory m_pointerShapeMemory[POINTER_SHAPE_BUFFERS] = {};
|
||||
PLGMPMemory m_pointerTransformMemory[COLOR_TRANSFORM_BUFFERS] = {};
|
||||
PLGMPMemory m_pointerShape = nullptr;
|
||||
int m_pointerMemoryIndex = 0;
|
||||
int m_pointerShapeIndex = 0;
|
||||
int m_pointerTransformIndex = 0;
|
||||
bool m_cursorVisible = false;
|
||||
int m_cursorX = 0;
|
||||
int m_cursorY = 0;
|
||||
|
||||
mutable SRWLOCK m_colorTransformLock = SRWLOCK_INIT;
|
||||
std::shared_ptr<const D12ColorTransform> m_colorTransform;
|
||||
|
||||
void SendColorTransform();
|
||||
void ResendCursor();
|
||||
|
||||
public:
|
||||
explicit CLGMPControl(CLGMPHost& host) :
|
||||
m_host(host) {}
|
||||
~CLGMPControl();
|
||||
|
||||
CLGMPControl(const CLGMPControl&) = delete;
|
||||
CLGMPControl& operator=(const CLGMPControl&) = delete;
|
||||
|
||||
bool Initialize();
|
||||
void DeInit();
|
||||
|
||||
LGMP_STATUS ReadDataWithSource(void * data, size_t * size,
|
||||
uint32_t * sourceClientID);
|
||||
LGMP_STATUS AckData();
|
||||
bool HasNewSubscribers();
|
||||
|
||||
void SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info, const BYTE * data,
|
||||
UINT sdrWhiteLevel);
|
||||
void SetColorTransform(
|
||||
std::shared_ptr<const D12ColorTransform> transform);
|
||||
std::shared_ptr<const D12ColorTransform> GetColorTransform() const;
|
||||
void ResendState();
|
||||
};
|
||||
165
idd/LGIdd/transport/CLGMPHost.cpp
Normal file
165
idd/LGIdd/transport/CLGMPHost.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* 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/CLGMPHost.h"
|
||||
|
||||
#include "transport/CIVSHMEM.h"
|
||||
#include "platform/CPlatformInfo.h"
|
||||
#include "CDebug.h"
|
||||
#include "VersionInfo.h"
|
||||
|
||||
#include "common/KVMFR.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
CLGMPHost::~CLGMPHost()
|
||||
{
|
||||
DeInit();
|
||||
}
|
||||
|
||||
bool CLGMPHost::Initialize(CIVSHMEM& ivshmem)
|
||||
{
|
||||
if (m_host)
|
||||
return true;
|
||||
|
||||
std::stringstream ss;
|
||||
{
|
||||
KVMFR kvmfr = {};
|
||||
memcpy_s(kvmfr.magic, sizeof(kvmfr.magic), KVMFR_MAGIC, sizeof(KVMFR_MAGIC) - 1);
|
||||
kvmfr.version = KVMFR_VERSION;
|
||||
kvmfr.features =
|
||||
KVMFR_FEATURE_SETCURSORPOS |
|
||||
KVMFR_FEATURE_WINDOWSIZE |
|
||||
KVMFR_FEATURE_FRAME_SCHEDULE;
|
||||
strncpy_s(kvmfr.hostver, LG_VERSION_STR, sizeof(kvmfr.hostver) - 1);
|
||||
ss.write(reinterpret_cast<const char *>(&kvmfr), sizeof(kvmfr));
|
||||
}
|
||||
|
||||
{
|
||||
const std::string & model = CPlatformInfo::GetCPUModel();
|
||||
|
||||
KVMFRRecord_VMInfo * vmInfo = static_cast<KVMFRRecord_VMInfo *>(calloc(1, sizeof(*vmInfo)));
|
||||
if (!vmInfo)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate KVMFRRecord_VMInfo");
|
||||
return false;
|
||||
}
|
||||
vmInfo->cpus = static_cast<uint8_t>(CPlatformInfo::GetProcCount ());
|
||||
vmInfo->cores = static_cast<uint8_t>(CPlatformInfo::GetCoreCount ());
|
||||
vmInfo->sockets = static_cast<uint8_t>(CPlatformInfo::GetSocketCount());
|
||||
|
||||
const uint8_t * uuid = CPlatformInfo::GetUUID();
|
||||
memcpy_s (vmInfo->uuid, sizeof(vmInfo->uuid), uuid, 16);
|
||||
strncpy_s(vmInfo->capture, "Looking Glass IDD Driver", sizeof(vmInfo->capture));
|
||||
|
||||
KVMFRRecord * record = static_cast<KVMFRRecord *>(calloc(1, sizeof(*record)));
|
||||
if (!record)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate KVMFRRecord");
|
||||
return false;
|
||||
}
|
||||
|
||||
record->type = KVMFR_RECORD_VMINFO;
|
||||
record->size = sizeof(*vmInfo) + (uint32_t)model.length() + 1;
|
||||
|
||||
ss.write(reinterpret_cast<const char*>(record ), sizeof(*record));
|
||||
ss.write(reinterpret_cast<const char*>(vmInfo ), sizeof(*vmInfo));
|
||||
ss.write(reinterpret_cast<const char*>(model.c_str()), model.length() + 1);
|
||||
}
|
||||
|
||||
{
|
||||
KVMFRRecord_OSInfo * osInfo = static_cast<KVMFRRecord_OSInfo *>(calloc(1, sizeof(*osInfo)));
|
||||
if (!osInfo)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate KVMFRRecord_OSInfo");
|
||||
return false;
|
||||
}
|
||||
|
||||
osInfo->os = KVMFR_OS_WINDOWS;
|
||||
|
||||
const std::string & osName = CPlatformInfo::GetProductName();
|
||||
|
||||
KVMFRRecord* record = static_cast<KVMFRRecord*>(calloc(1, sizeof(*record)));
|
||||
if (!record)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate KVMFRRecord");
|
||||
return false;
|
||||
}
|
||||
|
||||
record->type = KVMFR_RECORD_OSINFO;
|
||||
record->size = sizeof(*osInfo) + (uint32_t)osName.length() + 1;
|
||||
|
||||
ss.write(reinterpret_cast<const char*>(record), sizeof(*record));
|
||||
ss.write(reinterpret_cast<const char*>(osInfo), sizeof(*osInfo));
|
||||
ss.write(reinterpret_cast<const char*>(osName.c_str()), osName.length() + 1);
|
||||
}
|
||||
|
||||
LGMP_STATUS status;
|
||||
std::string udata = ss.str();
|
||||
|
||||
if ((status = lgmpHostInit(ivshmem.GetMem(), (uint32_t)ivshmem.GetSize(),
|
||||
&m_host, (uint32_t)udata.size(), (uint8_t*)&udata[0])) != LGMP_OK)
|
||||
{
|
||||
DEBUG_ERROR("lgmpHostInit Failed: %s", lgmpStatusString(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLGMPHost::DeInit()
|
||||
{
|
||||
if (m_host)
|
||||
lgmpHostFree(&m_host);
|
||||
}
|
||||
|
||||
LGMP_STATUS CLGMPHost::Process()
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_processLock);
|
||||
const LGMP_STATUS status = lgmpHostProcess(m_host);
|
||||
ReleaseSRWLockExclusive(&m_processLock);
|
||||
return status;
|
||||
}
|
||||
|
||||
LGMP_STATUS CLGMPHost::CreateQueue(
|
||||
const struct LGMPQueueConfig& config, PLGMPHostQueue * queue)
|
||||
{
|
||||
return lgmpHostQueueNew(m_host, config, queue);
|
||||
}
|
||||
|
||||
LGMP_STATUS CLGMPHost::Allocate(uint32_t size, PLGMPMemory * memory)
|
||||
{
|
||||
return lgmpHostMemAlloc(m_host, size, memory);
|
||||
}
|
||||
|
||||
LGMP_STATUS CLGMPHost::AllocateAligned(uint32_t size,
|
||||
uint32_t alignment, PLGMPMemory * memory)
|
||||
{
|
||||
return lgmpHostMemAllocAligned(m_host, size, alignment, memory);
|
||||
}
|
||||
|
||||
size_t CLGMPHost::Available() const
|
||||
{
|
||||
return lgmpHostMemAvail(m_host);
|
||||
}
|
||||
59
idd/LGIdd/transport/CLGMPHost.h
Normal file
59
idd/LGIdd/transport/CLGMPHost.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
#include "lgmp/host.h"
|
||||
}
|
||||
|
||||
class CIVSHMEM;
|
||||
|
||||
class CLGMPHost
|
||||
{
|
||||
private:
|
||||
PLGMPHost m_host = nullptr;
|
||||
SRWLOCK m_processLock = SRWLOCK_INIT;
|
||||
|
||||
public:
|
||||
CLGMPHost() = default;
|
||||
~CLGMPHost();
|
||||
|
||||
CLGMPHost(const CLGMPHost&) = delete;
|
||||
CLGMPHost& operator=(const CLGMPHost&) = delete;
|
||||
|
||||
bool Initialize(CIVSHMEM& ivshmem);
|
||||
void DeInit();
|
||||
|
||||
bool IsInitialized() const { return m_host != nullptr; }
|
||||
LGMP_STATUS Process();
|
||||
|
||||
LGMP_STATUS CreateQueue(const struct LGMPQueueConfig& config,
|
||||
PLGMPHostQueue * queue);
|
||||
LGMP_STATUS Allocate(uint32_t size, PLGMPMemory * memory);
|
||||
LGMP_STATUS AllocateAligned(uint32_t size, uint32_t alignment,
|
||||
PLGMPMemory * memory);
|
||||
size_t Available() const;
|
||||
};
|
||||
@@ -18,9 +18,9 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "CPipeServer.h"
|
||||
#include "transport/CPipeServer.h"
|
||||
#include "CDebug.h"
|
||||
#include "CIndirectDeviceContext.h"
|
||||
#include "display/device/CDeviceContext.h"
|
||||
|
||||
CPipeServer g_pipe;
|
||||
|
||||
@@ -266,7 +266,7 @@ void CPipeServer::HandleReloadSettings()
|
||||
ReleaseSRWLockShared(&m_deviceContextLock);
|
||||
}
|
||||
|
||||
void CPipeServer::SetDeviceContext(CIndirectDeviceContext* context)
|
||||
void CPipeServer::SetDeviceContext(CDeviceContext * context)
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_deviceContextLock);
|
||||
m_deviceContext = context;
|
||||
@@ -32,7 +32,7 @@ using namespace Microsoft::WRL;
|
||||
using namespace Microsoft::WRL::Wrappers;
|
||||
using namespace Microsoft::WRL::Wrappers::HandleTraits;
|
||||
|
||||
class CIndirectDeviceContext;
|
||||
class CDeviceContext;
|
||||
|
||||
class CPipeServer
|
||||
{
|
||||
@@ -45,8 +45,8 @@ class CPipeServer
|
||||
bool m_running = false;
|
||||
bool m_connected = false;
|
||||
|
||||
SRWLOCK m_deviceContextLock = SRWLOCK_INIT;
|
||||
CIndirectDeviceContext* m_deviceContext = nullptr;
|
||||
SRWLOCK m_deviceContextLock = SRWLOCK_INIT;
|
||||
CDeviceContext * m_deviceContext = nullptr;
|
||||
|
||||
void _DeInit();
|
||||
|
||||
@@ -63,7 +63,7 @@ class CPipeServer
|
||||
bool Init();
|
||||
void DeInit();
|
||||
|
||||
void SetDeviceContext(CIndirectDeviceContext* context);
|
||||
void SetDeviceContext(CDeviceContext * context);
|
||||
|
||||
void SetCursorPos(uint32_t x, uint32_t y);
|
||||
void SetDisplayMode(
|
||||
31
idd/LGIdd/transport/FrameMemoryLimits.h
Normal file
31
idd/LGIdd/transport/FrameMemoryLimits.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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 <stdint.h>
|
||||
|
||||
struct FrameMemoryLimits
|
||||
{
|
||||
uint64_t sharedSize = 0;
|
||||
uint64_t frameMemoryOffset = 0;
|
||||
uint64_t alignment = 0;
|
||||
uint64_t maxFrameSize = 0;
|
||||
};
|
||||
63
idd/LGIdd/util/CSRWLock.h
Normal file
63
idd/LGIdd/util/CSRWLock.h
Normal 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 <Windows.h>
|
||||
|
||||
class CSRWSharedLock
|
||||
{
|
||||
private:
|
||||
SRWLOCK * m_lock;
|
||||
|
||||
public:
|
||||
explicit CSRWSharedLock(SRWLOCK * lock) : m_lock(lock)
|
||||
{
|
||||
AcquireSRWLockShared(m_lock);
|
||||
}
|
||||
|
||||
~CSRWSharedLock()
|
||||
{
|
||||
ReleaseSRWLockShared(m_lock);
|
||||
}
|
||||
|
||||
CSRWSharedLock(const CSRWSharedLock&) = delete;
|
||||
CSRWSharedLock& operator=(const CSRWSharedLock&) = delete;
|
||||
};
|
||||
|
||||
class CSRWExclusiveLock
|
||||
{
|
||||
private:
|
||||
SRWLOCK * m_lock;
|
||||
|
||||
public:
|
||||
explicit CSRWExclusiveLock(SRWLOCK * lock) : m_lock(lock)
|
||||
{
|
||||
AcquireSRWLockExclusive(m_lock);
|
||||
}
|
||||
|
||||
~CSRWExclusiveLock()
|
||||
{
|
||||
ReleaseSRWLockExclusive(m_lock);
|
||||
}
|
||||
|
||||
CSRWExclusiveLock(const CSRWExclusiveLock&) = delete;
|
||||
CSRWExclusiveLock& operator=(const CSRWExclusiveLock&) = delete;
|
||||
};
|
||||
Reference in New Issue
Block a user