diff --git a/.gitignore b/.gitignore index d35a85d1..0b3e355f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,8 @@ module/modules.order */build __pycache__ *.py[co] +*/.vs +idd/Debug +idd/x64 +idd/LGIdd/x64 +idd/LGIdd/Debug diff --git a/idd/LGIdd.sln b/idd/LGIdd.sln new file mode 100644 index 00000000..c8671aab --- /dev/null +++ b/idd/LGIdd.sln @@ -0,0 +1,51 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.33423.256 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LGIdd", "LGIdd\LGIdd.vcxproj", "{1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|ARM.ActiveCfg = Debug|ARM + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|ARM.Build.0 = Debug|ARM + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|ARM.Deploy.0 = Debug|ARM + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|ARM64.Build.0 = Debug|ARM64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x64.ActiveCfg = Debug|x64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x64.Build.0 = Debug|x64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x64.Deploy.0 = Debug|x64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x86.ActiveCfg = Debug|Win32 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x86.Build.0 = Debug|Win32 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x86.Deploy.0 = Debug|Win32 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|ARM.ActiveCfg = Release|ARM + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|ARM.Build.0 = Release|ARM + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|ARM.Deploy.0 = Release|ARM + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|ARM64.ActiveCfg = Release|ARM64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|ARM64.Build.0 = Release|ARM64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|ARM64.Deploy.0 = Release|ARM64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x64.ActiveCfg = Release|x64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x64.Build.0 = Release|x64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x64.Deploy.0 = Release|x64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x86.ActiveCfg = Release|Win32 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x86.Build.0 = Release|Win32 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4B2655CF-46E1-42A7-BD20-024FD2C4BFAA} + EndGlobalSection +EndGlobal diff --git a/idd/LGIdd/CIndirectDeviceContext.cpp b/idd/LGIdd/CIndirectDeviceContext.cpp new file mode 100644 index 00000000..1cb816b3 --- /dev/null +++ b/idd/LGIdd/CIndirectDeviceContext.cpp @@ -0,0 +1,117 @@ +#include "CIndirectDeviceContext.h" +#include "CIndirectMonitorContext.h" + +void CIndirectDeviceContext::InitAdapter() +{ + IDDCX_ADAPTER_CAPS caps = {}; + caps.Size = sizeof(caps); + + caps.MaxMonitorsSupported = 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 Device"; + 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, CIndirectDeviceContextWrapper); + + IDARG_IN_ADAPTER_INIT init = {}; + init.WdfDevice = m_wdfDevice; + init.pCaps = ∩︀ + init.ObjectAttributes = &attr; + + IDARG_OUT_ADAPTER_INIT initOut; + NTSTATUS status = IddCxAdapterInitAsync(&init, &initOut); + if (!NT_SUCCESS(status)) + return; + + m_adapter = initOut.AdapterObject; + + // try to co-exist with the virtual video device by telling IddCx which adapter we prefer to render on + IDXGIFactory * factory = NULL; + IDXGIAdapter * dxgiAdapter; + CreateDXGIFactory(__uuidof(IDXGIFactory), (void **)&factory); + for (UINT i = 0; factory->EnumAdapters(i, &dxgiAdapter) != DXGI_ERROR_NOT_FOUND; ++i) + { + DXGI_ADAPTER_DESC adapterDesc; + dxgiAdapter->GetDesc(&adapterDesc); + dxgiAdapter->Release(); + + if ((adapterDesc.VendorId == 0x1414 && adapterDesc.DeviceId == 0x008c) || // Microsoft Basic Render Driver + (adapterDesc.VendorId == 0x1b36 && adapterDesc.DeviceId == 0x000d) || // QXL + (adapterDesc.VendorId == 0x1234 && adapterDesc.DeviceId == 0x1111)) // QEMU Standard VGA + continue; + + IDARG_IN_ADAPTERSETRENDERADAPTER args = {}; + args.PreferredRenderAdapter = adapterDesc.AdapterLuid; + IddCxAdapterSetRenderAdapter(m_adapter, &args); + break; + } + factory->Release(); + + auto * wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(m_adapter); + wrapper->context = this; +} + +static const BYTE EDID[] = +{ + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x30,0xE8,0x34,0x12,0xC9,0x07,0xCC,0x00, + 0x01,0x21,0x01,0x04,0xA5,0x3C,0x22,0x78,0xFB,0x6C,0xE5,0xA5,0x55,0x50,0xA0,0x23, + 0x0B,0x50,0x54,0x00,0x02,0x00,0xD1,0xC0,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x58,0xE3,0x00,0xA0,0xA0,0xA0,0x29,0x50,0x30,0x20, + 0x35,0x00,0x55,0x50,0x21,0x00,0x00,0x1A,0x00,0x00,0x00,0xFF,0x00,0x4C,0x6F,0x6F, + 0x6B,0x69,0x6E,0x67,0x47,0x6C,0x61,0x73,0x73,0x0A,0x00,0x00,0x00,0xFC,0x00,0x4C, + 0x6F,0x6F,0x6B,0x69,0x6E,0x67,0x20,0x47,0x6C,0x61,0x73,0x73,0x00,0x00,0x00,0xFD, + 0x00,0x28,0x9B,0xFA,0xFA,0x40,0x01,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x4A +}; + +void CIndirectDeviceContext::FinishInit(UINT connectorIndex) +{ + WDF_OBJECT_ATTRIBUTES attr; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, CIndirectMonitorContextWrapper); + + 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; + if (connectorIndex >= 1) + { + info.MonitorDescription.DataSize = 0; + info.MonitorDescription.pData = nullptr; + } + else + { + info.MonitorDescription.DataSize = sizeof(EDID); + info.MonitorDescription.pData = const_cast(EDID); + } + + CoCreateGuid(&info.MonitorContainerId); + + IDARG_IN_MONITORCREATE create = {}; + create.ObjectAttributes = &attr; + create.pMonitorInfo = &info; + + IDARG_OUT_MONITORCREATE createOut; + NTSTATUS status = IddCxMonitorCreate(m_adapter, &create, &createOut); + if (!NT_SUCCESS(status)) + return; + + auto * wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(createOut.MonitorObject); + wrapper->context = new CIndirectMonitorContext(createOut.MonitorObject); + + IDARG_OUT_MONITORARRIVAL out; + status = IddCxMonitorArrival(createOut.MonitorObject, &out); +} \ No newline at end of file diff --git a/idd/LGIdd/CIndirectDeviceContext.h b/idd/LGIdd/CIndirectDeviceContext.h new file mode 100644 index 00000000..a74ac2bf --- /dev/null +++ b/idd/LGIdd/CIndirectDeviceContext.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +class CIndirectDeviceContext +{ +private: + WDFDEVICE m_wdfDevice; + IDDCX_ADAPTER m_adapter = nullptr; + +public: + CIndirectDeviceContext(_In_ WDFDEVICE wdfDevice) : + m_wdfDevice(wdfDevice) {}; + + virtual ~CIndirectDeviceContext() {}; + + void InitAdapter(); + + void FinishInit(UINT connectorIndex); +}; + +struct CIndirectDeviceContextWrapper +{ + CIndirectDeviceContext* context; + + void Cleanup() + { + delete context; + context = nullptr; + } +}; + +WDF_DECLARE_CONTEXT_TYPE(CIndirectDeviceContextWrapper); \ No newline at end of file diff --git a/idd/LGIdd/CIndirectMonitorContext.cpp b/idd/LGIdd/CIndirectMonitorContext.cpp new file mode 100644 index 00000000..e9b111ed --- /dev/null +++ b/idd/LGIdd/CIndirectMonitorContext.cpp @@ -0,0 +1,34 @@ +#include "CIndirectMonitorContext.h" +#include "Direct3DDevice.h" + +CIndirectMonitorContext::CIndirectMonitorContext(_In_ IDDCX_MONITOR monitor) : + m_monitor(monitor) +{ + OutputDebugStringA(__FUNCTION__); +} + +CIndirectMonitorContext::~CIndirectMonitorContext() +{ + OutputDebugStringA(__FUNCTION__); + m_thread.reset(); +} + +void CIndirectMonitorContext::AssignSwapChain(IDDCX_SWAPCHAIN swapChain, LUID renderAdapter, HANDLE newFrameEvent) +{ + OutputDebugStringA(__FUNCTION__); + m_thread.reset(); + auto device = std::make_shared(renderAdapter); + if (FAILED(device->Init())) + { + WdfObjectDelete(swapChain); + return; + } + + m_thread.reset(new CSwapChainProcessor(swapChain, device, newFrameEvent)); +} + +void CIndirectMonitorContext::UnassignSwapChain() +{ + OutputDebugStringA(__FUNCTION__); + m_thread.reset(); +} \ No newline at end of file diff --git a/idd/LGIdd/CIndirectMonitorContext.h b/idd/LGIdd/CIndirectMonitorContext.h new file mode 100644 index 00000000..ea9a3cc8 --- /dev/null +++ b/idd/LGIdd/CIndirectMonitorContext.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +#include +#include "CSwapChainProcessor.h" + +class CIndirectMonitorContext +{ +protected: + IDDCX_MONITOR m_monitor; + std::unique_ptr m_thread; + +public: + CIndirectMonitorContext(_In_ IDDCX_MONITOR monitor); + + virtual ~CIndirectMonitorContext(); + + void AssignSwapChain(IDDCX_SWAPCHAIN swapChain, LUID renderAdapter, HANDLE newFrameEvent); + void UnassignSwapChain(); +}; + +struct CIndirectMonitorContextWrapper +{ + CIndirectMonitorContext* context; + + void Cleanup() + { + delete context; + context = nullptr; + } +}; + +WDF_DECLARE_CONTEXT_TYPE(CIndirectMonitorContextWrapper); \ No newline at end of file diff --git a/idd/LGIdd/CSwapChainProcessor.cpp b/idd/LGIdd/CSwapChainProcessor.cpp new file mode 100644 index 00000000..b92c81e2 --- /dev/null +++ b/idd/LGIdd/CSwapChainProcessor.cpp @@ -0,0 +1,96 @@ +#include "CSwapChainProcessor.h" + +#include + + +CSwapChainProcessor::CSwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, std::shared_ptr device, HANDLE newFrameEvent) : + m_hSwapChain(hSwapChain), + m_device(device), + m_newFrameEvent(newFrameEvent) +{ + OutputDebugStringA(__FUNCTION__); + m_terminateEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr)); + m_thread.Attach(CreateThread(nullptr, 0, RunThread, this, 0, nullptr)); +} + +CSwapChainProcessor::~CSwapChainProcessor() +{ + OutputDebugStringA(__FUNCTION__); + SetEvent(m_terminateEvent.Get()); + if (m_thread.Get()) + WaitForSingleObject(m_thread.Get(), INFINITE); +} + +DWORD CALLBACK CSwapChainProcessor::RunThread(LPVOID argument) +{ + OutputDebugStringA(__FUNCTION__); + reinterpret_cast(argument)->Run(); + return 0; +} + +void CSwapChainProcessor::Run() +{ + DWORD avTask = 0; + HANDLE avTaskHandle = AvSetMmThreadCharacteristicsW(L"Distribution", &avTask); + + RunCore(); + + WdfObjectDelete((WDFOBJECT)m_hSwapChain); + m_hSwapChain = nullptr; + + AvRevertMmThreadCharacteristics(avTaskHandle); +} + +void CSwapChainProcessor::RunCore() +{ + Microsoft::WRL::ComPtr dxgiDevice; + HRESULT hr = m_device->m_device.As(&dxgiDevice); + if (FAILED(hr)) + return; + + IDARG_IN_SWAPCHAINSETDEVICE setDevice = {}; + setDevice.pDevice = dxgiDevice.Get(); + + hr = IddCxSwapChainSetDevice(m_hSwapChain, &setDevice); + if (FAILED(hr)) + return; + + for (;;) + { + Microsoft::WRL::ComPtr acquiredBuffer; + IDARG_OUT_RELEASEANDACQUIREBUFFER buffer = {}; + hr = IddCxSwapChainReleaseAndAcquireBuffer(m_hSwapChain, &buffer); + + if (hr == E_PENDING) + { + HANDLE waitHandles[] = + { + m_newFrameEvent, + m_terminateEvent.Get() + }; + DWORD waitResult = WaitForMultipleObjects(ARRAYSIZE(waitHandles), waitHandles, FALSE, 17); + if (waitResult == WAIT_OBJECT_0 || waitResult == WAIT_TIMEOUT) + continue; + else if (waitResult == WAIT_OBJECT_0 + 1) + break; + else + { + hr = HRESULT_FROM_WIN32(waitResult); + break; + } + } + else if (SUCCEEDED(hr)) + { + //acquiredBuffer.Attach(buffer.MetaData.pSurface); + + //TODO: process the frame + + //acquiredBuffer.Reset(); + hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain); + if (FAILED(hr)) + break; + } + else + break; + } +} \ No newline at end of file diff --git a/idd/LGIdd/CSwapChainProcessor.h b/idd/LGIdd/CSwapChainProcessor.h new file mode 100644 index 00000000..eff8511f --- /dev/null +++ b/idd/LGIdd/CSwapChainProcessor.h @@ -0,0 +1,30 @@ +#pragma once + +#include "Direct3DDevice.h" + +#include +#include +#include +#include + +class CSwapChainProcessor +{ +private: + IDDCX_SWAPCHAIN m_hSwapChain; + std::shared_ptr m_device; + HANDLE m_newFrameEvent; + + Microsoft::WRL::Wrappers::HandleT< + Microsoft::WRL::Wrappers::HandleTraits::HANDLENullTraits> m_thread; + Microsoft::WRL::Wrappers::Event m_terminateEvent; + + static DWORD CALLBACK RunThread(LPVOID argument); + + void Run(); + void RunCore(); + +public: + CSwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, + std::shared_ptr device, HANDLE newFrameEvent); + ~CSwapChainProcessor(); +}; \ No newline at end of file diff --git a/idd/LGIdd/Device.cpp b/idd/LGIdd/Device.cpp new file mode 100644 index 00000000..a1466d34 --- /dev/null +++ b/idd/LGIdd/Device.cpp @@ -0,0 +1,182 @@ +#include "driver.h" +#include "device.tmh" + +#include +#include +#include +#include +#include +#include +#include + +#include "CIndirectDeviceContext.h" +#include "CIndirectMonitorContext.h" + +NTSTATUS LGIddDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previousState) +{ + UNREFERENCED_PARAMETER(previousState); + UNREFERENCED_PARAMETER(device); + + auto * wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(device); + wrapper->context->InitAdapter(); + + return STATUS_SUCCESS; +} + +NTSTATUS LGIddAdapterInitFinished(IDDCX_ADAPTER adapter, const IDARG_IN_ADAPTER_INIT_FINISHED * args) +{ + auto * wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(adapter); + if (!NT_SUCCESS(args->AdapterInitStatus)) + return STATUS_SUCCESS; + + wrapper->context->FinishInit(0); + return STATUS_SUCCESS; +} + +NTSTATUS LGIddAdapterCommitModes(IDDCX_ADAPTER adapter, const IDARG_IN_COMMITMODES* args) +{ + UNREFERENCED_PARAMETER(adapter); + UNREFERENCED_PARAMETER(args); + return STATUS_SUCCESS; +} + +static inline void FillSignalInfo(DISPLAYCONFIG_VIDEO_SIGNAL_INFO & mode, DWORD width, DWORD height, DWORD vsync, bool monitorMode) +{ + mode.totalSize.cx = mode.activeSize.cx = width; + mode.totalSize.cy = mode.activeSize.cy = height; + + mode.AdditionalSignalInfo.vSyncFreqDivider = monitorMode ? 0 : 1; + mode.AdditionalSignalInfo.videoStandard = 255; + + mode.vSyncFreq.Numerator = vsync; + mode.vSyncFreq.Denominator = 1; + mode.hSyncFreq.Numerator = vsync * height; + mode.hSyncFreq.Denominator = 1; + + mode.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE; + mode.pixelRate = ((UINT64)vsync) * ((UINT64)width) * ((UINT64)height); +} + +NTSTATUS LGIddParseMonitorDescription(const IDARG_IN_PARSEMONITORDESCRIPTION* inArgs, + IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs) +{ + outArgs->MonitorModeBufferOutputCount = ARRAYSIZE(DisplayModes); + if (inArgs->MonitorModeBufferInputCount < ARRAYSIZE(DisplayModes)) + return (inArgs->MonitorModeBufferInputCount > 0) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; + + for (UINT i = 0; i < ARRAYSIZE(DisplayModes); ++i) + { + inArgs->pMonitorModes[i].Size = sizeof(IDDCX_MONITOR_MODE); + inArgs->pMonitorModes[i].Origin = IDDCX_MONITOR_MODE_ORIGIN_MONITORDESCRIPTOR; + FillSignalInfo(inArgs->pMonitorModes[i].MonitorVideoSignalInfo, + DisplayModes[i][0], DisplayModes[i][1], DisplayModes[i][2], true); + } + + outArgs->PreferredMonitorModeIdx = PreferredDisplayMode; + return STATUS_SUCCESS; +} + +NTSTATUS LGIddMonitorGetDefaultModes(IDDCX_MONITOR monitor, const IDARG_IN_GETDEFAULTDESCRIPTIONMODES * inArgs, + IDARG_OUT_GETDEFAULTDESCRIPTIONMODES * outArgs) +{ + UNREFERENCED_PARAMETER(monitor); + + outArgs->DefaultMonitorModeBufferOutputCount = ARRAYSIZE(DisplayModes); + if (inArgs->DefaultMonitorModeBufferInputCount < ARRAYSIZE(DisplayModes)) + return (inArgs->DefaultMonitorModeBufferInputCount > 0) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; + + for (UINT i = 0; i < ARRAYSIZE(DisplayModes); ++i) + { + inArgs->pDefaultMonitorModes[i].Size = sizeof(IDDCX_MONITOR_MODE); + inArgs->pDefaultMonitorModes[i].Origin = IDDCX_MONITOR_MODE_ORIGIN_DRIVER; + FillSignalInfo(inArgs->pDefaultMonitorModes[i].MonitorVideoSignalInfo, + DisplayModes[i][0], DisplayModes[i][1], DisplayModes[i][2], true); + } + + outArgs->PreferredMonitorModeIdx = PreferredDisplayMode; + return STATUS_SUCCESS; +} + +NTSTATUS LGIddMonitorQueryTargetModes(IDDCX_MONITOR monitor, const IDARG_IN_QUERYTARGETMODES * inArgs, + IDARG_OUT_QUERYTARGETMODES * outArgs) +{ + UNREFERENCED_PARAMETER(monitor); + + outArgs->TargetModeBufferOutputCount = ARRAYSIZE(DisplayModes); + if (inArgs->TargetModeBufferInputCount < ARRAYSIZE(DisplayModes)) + return (inArgs->TargetModeBufferInputCount > 0) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; + + for (UINT i = 0; i < ARRAYSIZE(DisplayModes); ++i) + { + inArgs->pTargetModes[i].Size = sizeof(IDDCX_TARGET_MODE); + FillSignalInfo(inArgs->pTargetModes[i].TargetVideoSignalInfo.targetVideoSignalInfo, + DisplayModes[i][0], DisplayModes[i][1], DisplayModes[i][2], false); + } + + return STATUS_SUCCESS; +} + +NTSTATUS LGIddMonitorAssignSwapChain(IDDCX_MONITOR monitor, const IDARG_IN_SETSWAPCHAIN* inArgs) +{ + auto * wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor); + wrapper->context->AssignSwapChain(inArgs->hSwapChain, inArgs->RenderAdapterLuid, inArgs->hNextSurfaceAvailable); + return STATUS_SUCCESS; +} + +NTSTATUS LGIddMonitorUnassignSwapChain(IDDCX_MONITOR monitor) +{ + auto* wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor); + wrapper->context->UnassignSwapChain(); + return STATUS_SUCCESS; +} + +NTSTATUS LGIddCreateDevice(_Inout_ PWDFDEVICE_INIT deviceInit) +{ + OutputDebugStringA(__FUNCTION__); + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + pnpPowerCallbacks.EvtDeviceD0Entry = LGIddDeviceD0Entry; + WdfDeviceInitSetPnpPowerEventCallbacks(deviceInit, &pnpPowerCallbacks); + + IDD_CX_CLIENT_CONFIG config; + IDD_CX_CLIENT_CONFIG_INIT(&config); + config.EvtIddCxAdapterInitFinished = LGIddAdapterInitFinished; + config.EvtIddCxAdapterCommitModes = LGIddAdapterCommitModes; + config.EvtIddCxParseMonitorDescription = LGIddParseMonitorDescription; + config.EvtIddCxMonitorGetDefaultDescriptionModes = LGIddMonitorGetDefaultModes; + config.EvtIddCxMonitorQueryTargetModes = LGIddMonitorQueryTargetModes; + config.EvtIddCxMonitorAssignSwapChain = LGIddMonitorAssignSwapChain; + config.EvtIddCxMonitorUnassignSwapChain = LGIddMonitorUnassignSwapChain; + + NTSTATUS status = IddCxDeviceInitConfig(deviceInit, &config); + if (!NT_SUCCESS(status)) + { + OutputDebugStringA(__FUNCTION__ " FAILURE1"); + return status; + } + + WDF_OBJECT_ATTRIBUTES deviceAttributes; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, CIndirectDeviceContextWrapper); + deviceAttributes.EvtCleanupCallback = [](WDFOBJECT object) + { + auto * wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(object); + if (wrapper) + wrapper->Cleanup(); + }; + + WDFDEVICE device = nullptr; + status = WdfDeviceCreate(&deviceInit, &deviceAttributes, &device); + if (!NT_SUCCESS(status)) + { + OutputDebugStringA(__FUNCTION__ " FAILURE2"); + return status; + } + + status = IddCxDeviceInitialize(device); + + auto wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(device); + wrapper->context = new CIndirectDeviceContext(device); + + OutputDebugStringA(__FUNCTION__ " SUCCESS"); + return status; +} diff --git a/idd/LGIdd/Device.h b/idd/LGIdd/Device.h new file mode 100644 index 00000000..12b1361e --- /dev/null +++ b/idd/LGIdd/Device.h @@ -0,0 +1,42 @@ +#pragma once + +#include "public.h" + +#include + +#if 1 +const DWORD DisplayModes[][3] = +{ + {7680, 4800, 120}, {7680, 4320, 120}, {6016, 3384, 120}, {5760, 3600, 120}, + {5760, 3240, 120}, {5120, 2800, 120}, {4096, 2560, 120}, {4096, 2304, 120}, + {3840, 2400, 120}, {3840, 2160, 120}, {3200, 2400, 120}, {3200, 1800, 120}, + {3008, 1692, 120}, {2880, 1800, 120}, {2880, 1620, 120}, {2560, 1600, 120}, + {2560, 1440, 120}, {1920, 1440, 120}, {1920, 1200, 120}, {1920, 1080, 120}, + {1600, 1200, 120}, {1600, 1024, 120}, {1600, 1050, 120}, {1600, 900 , 120}, + {1440, 900 , 120}, {1400, 1050, 120}, {1366, 768 , 120}, {1360, 768 , 120}, + {1280, 1024, 120}, {1280, 960 , 120}, {1280, 800 , 120}, {1280, 768 , 120}, + {1280, 720 , 120}, {1280, 600 , 120}, {1152, 864 , 120}, {1024, 768 , 120}, + {800 , 600 , 120}, {640 , 480 , 120} +}; + +const DWORD PreferredDisplayMode = 19; +#else +const DWORD DisplayModes[][3] = +{ + { 2560, 1440, 144 }, + { 1920, 1080, 60 }, + { 1024, 768, 60 }, +}; + +const DWORD PreferredDisplayMode = 0; +#endif + +typedef struct _DEVICE_CONTEXT +{ + ULONG PrivateDeviceData; // just a placeholder +} +DEVICE_CONTEXT, *PDEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, DeviceGetContext) + +NTSTATUS LGIddCreateDevice(_Inout_ PWDFDEVICE_INIT deviceInit); diff --git a/idd/LGIdd/Direct3DDevice.cpp b/idd/LGIdd/Direct3DDevice.cpp new file mode 100644 index 00000000..63d42ad5 --- /dev/null +++ b/idd/LGIdd/Direct3DDevice.cpp @@ -0,0 +1,28 @@ +#include "Direct3DDevice.h" + +HRESULT Direct3DDevice::Init() +{ + HRESULT hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&m_factory)); + if (FAILED(hr)) + return hr; + + hr = m_factory->EnumAdapterByLuid(m_adapterLuid, IID_PPV_ARGS(&m_adapter)); + if (FAILED(hr)) + return hr; + + hr = D3D11CreateDevice( + m_adapter.Get(), + D3D_DRIVER_TYPE_UNKNOWN, + nullptr, + D3D11_CREATE_DEVICE_BGRA_SUPPORT, + nullptr, + 0, + D3D11_SDK_VERSION, + &m_device, + nullptr, + &m_context); + if (FAILED(hr)) + return hr; + + return S_OK; +} \ No newline at end of file diff --git a/idd/LGIdd/Direct3DDevice.h b/idd/LGIdd/Direct3DDevice.h new file mode 100644 index 00000000..86883d3d --- /dev/null +++ b/idd/LGIdd/Direct3DDevice.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include +#include + +struct Direct3DDevice +{ + Direct3DDevice(LUID adapterLuid) : + m_adapterLuid(adapterLuid) {}; + + Direct3DDevice() + { + m_adapterLuid = LUID{}; + } + + HRESULT Init(); + + LUID m_adapterLuid; + Microsoft::WRL::ComPtr m_factory; + Microsoft::WRL::ComPtr m_adapter; + Microsoft::WRL::ComPtr m_device; + Microsoft::WRL::ComPtr m_context; +}; \ No newline at end of file diff --git a/idd/LGIdd/Driver.cpp b/idd/LGIdd/Driver.cpp new file mode 100644 index 00000000..9bbd6ba9 --- /dev/null +++ b/idd/LGIdd/Driver.cpp @@ -0,0 +1,68 @@ +#include "driver.h" +#include "driver.tmh" + +NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) +{ + OutputDebugStringA(__FUNCTION__); + + WDF_DRIVER_CONFIG config; + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + +#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0 + WPP_INIT_TRACING(MYDRIVER_TRACING_ID); +#else + WPP_INIT_TRACING(DriverObject, RegistryPath); +#endif + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = LGIddEvtDriverContextCleanup; + WDF_DRIVER_CONFIG_INIT(&config, LGIddEvtDeviceAdd); + + status = WdfDriverCreate(DriverObject, RegistryPath, &attributes, &config, WDF_NO_HANDLE); + if (!NT_SUCCESS(status)) + { + OutputDebugStringA(__FUNCTION__ " FAILURE"); + TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status); +#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0 + WPP_CLEANUP(); +#else + WPP_CLEANUP(DriverObject); +#endif + return status; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit"); + OutputDebugStringA(__FUNCTION__ " SUCCESS"); + return status; +} + +NTSTATUS LGIddEvtDeviceAdd(_In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit) +{ + OutputDebugStringA(__FUNCTION__); + + NTSTATUS status; + UNREFERENCED_PARAMETER(Driver); + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); + status = LGIddCreateDevice(DeviceInit); + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit"); + return status; +} + +VOID LGIddEvtDriverContextCleanup(_In_ WDFOBJECT DriverObject) +{ + OutputDebugStringA(__FUNCTION__); + + UNREFERENCED_PARAMETER(DriverObject); + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); + +#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0 + WPP_CLEANUP(); +#else + WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject)); +#endif +} \ No newline at end of file diff --git a/idd/LGIdd/Driver.h b/idd/LGIdd/Driver.h new file mode 100644 index 00000000..64f47938 --- /dev/null +++ b/idd/LGIdd/Driver.h @@ -0,0 +1,13 @@ +#include +#include +#include + +#include "device.h" +#include "trace.h" + +EXTERN_C_START +DRIVER_INITIALIZE DriverEntry; +EXTERN_C_END + +EVT_WDF_DRIVER_DEVICE_ADD LGIddEvtDeviceAdd; +EVT_WDF_OBJECT_CONTEXT_CLEANUP LGIddEvtDriverContextCleanup; \ No newline at end of file diff --git a/idd/LGIdd/LGIdd.inf b/idd/LGIdd/LGIdd.inf new file mode 100644 index 00000000..4df00edd Binary files /dev/null and b/idd/LGIdd/LGIdd.inf differ diff --git a/idd/LGIdd/LGIdd.vcxproj b/idd/LGIdd/LGIdd.vcxproj new file mode 100644 index 00000000..530e2b8b --- /dev/null +++ b/idd/LGIdd/LGIdd.vcxproj @@ -0,0 +1,292 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM + + + Release + ARM + + + Debug + ARM64 + + + Release + ARM64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A} + {32909489-7be5-497b-aafa-db6669d9b44b} + v4.5 + 12.0 + Debug + Win32 + LGIdd + + + WindowsUserModeDriver10.0 + DynamicLibrary + Universal + + + WindowsUserModeDriver10.0 + DynamicLibrary + Universal + + + WindowsUserModeDriver10.0 + DynamicLibrary + Universal + + + WindowsUserModeDriver10.0 + DynamicLibrary + Universal + + + WindowsUserModeDriver10.0 + DynamicLibrary + Universal + + + WindowsUserModeDriver10.0 + DynamicLibrary + Universal + + + WindowsUserModeDriver10.0 + DynamicLibrary + Universal + + + WindowsUserModeDriver10.0 + DynamicLibrary + Universal + + + + Windows10 + true + 2 + Spectre + true + 1 + 4 + 25 + + + + + Windows10 + false + 2 + Spectre + true + 1 + 4 + 25 + + + + + Windows10 + true + 2 + true + 1 + 4 + Spectre + 25 + + + + + Windows10 + false + 2 + true + 1 + 4 + Spectre + 25 + + + + + Windows10 + true + 2 + + + Windows10 + false + 2 + + + Windows10 + true + 2 + + + Windows10 + false + 2 + + + + + + + + + + DbgengRemoteDebugger + true + + + DbgengRemoteDebugger + true + + + DbgengRemoteDebugger + true + + + DbgengRemoteDebugger + true + + + DbgengRemoteDebugger + + + DbgengRemoteDebugger + + + DbgengRemoteDebugger + + + DbgengRemoteDebugger + + + + true + true + trace.h + /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=4 /IDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) + + + %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib + + + + + true + true + trace.h + /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=4 /IDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) + + + %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib + + + + + true + true + trace.h + /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=4 /IDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) + + + %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib + + + + + true + true + trace.h + /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=4 /IDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) + + + %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib + + + + + true + true + trace.h + + + + + true + true + trace.h + + + + + true + true + trace.h + + + + + true + true + trace.h + + + + + + + + + \ No newline at end of file diff --git a/idd/LGIdd/LGIdd.vcxproj.filters b/idd/LGIdd/LGIdd.vcxproj.filters new file mode 100644 index 00000000..e1163cf9 --- /dev/null +++ b/idd/LGIdd/LGIdd.vcxproj.filters @@ -0,0 +1,75 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {8E41214B-6785-4CFE-B992-037D68949A14} + inf;inv;inx;mof;mc; + + + + + + + + Driver Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/idd/LGIdd/LGIdd.vcxproj.user b/idd/LGIdd/LGIdd.vcxproj.user new file mode 100644 index 00000000..c20e0152 --- /dev/null +++ b/idd/LGIdd/LGIdd.vcxproj.user @@ -0,0 +1,15 @@ + + + + DbgengLocalDebugger + + + DbgengLocalDebugger + + + DbgengLocalDebugger + + + DbgengLocalDebugger + + \ No newline at end of file diff --git a/idd/LGIdd/Public.h b/idd/LGIdd/Public.h new file mode 100644 index 00000000..b80ad59b --- /dev/null +++ b/idd/LGIdd/Public.h @@ -0,0 +1,2 @@ +// {997b0b66-b74c-4017-9a89-e4aad41d3780} +DEFINE_GUID (GUID_DEVINTERFACE_LGIdd, 0x997b0b66,0xb74c,0x4017,0x9a,0x89,0xe4,0xaa,0xd4,0x1d,0x37,0x80); \ No newline at end of file diff --git a/idd/LGIdd/Trace.h b/idd/LGIdd/Trace.h new file mode 100644 index 00000000..392c380a --- /dev/null +++ b/idd/LGIdd/Trace.h @@ -0,0 +1,38 @@ +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + MyDriver1TraceGuid, (58bf0aac,4a52,4560,9873,693b645c0a47), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + WPP_DEFINE_BIT(TRACE_DRIVER) \ + WPP_DEFINE_BIT(TRACE_DEVICE) \ + WPP_DEFINE_BIT(TRACE_QUEUE)) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ + WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \ + WPP_LEVEL_LOGGER(flags) + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ + (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); +// end_wpp + +// +// +// Driver specific #defines +// +#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0 + #define MYDRIVER_TRACING_ID L"Microsoft\\UMDF2.0\\LGIdd V1.0" +#endif \ No newline at end of file diff --git a/idd/LGIdd/cpp.hint b/idd/LGIdd/cpp.hint new file mode 100644 index 00000000..51416800 --- /dev/null +++ b/idd/LGIdd/cpp.hint @@ -0,0 +1,4 @@ +// Hint files help the Visual Studio IDE interpret Visual C++ identifiers +// such as names of functions and macros. +// For more information see https://go.microsoft.com/fwlink/?linkid=865984 +#define _In_ _SAL2_Source_(_In_, (), _Pre1_impl_(__notnull_impl_notref) _Pre_valid_impl_ _Deref_pre1_impl_(__readaccess_impl_notref)) \ No newline at end of file