diff --git a/video/IndirectDisplay/IddSampleApp/IddSampleApp.vcxproj b/video/IndirectDisplay/IddSampleApp/IddSampleApp.vcxproj index 0e8fbdbab..a72a2853b 100644 --- a/video/IndirectDisplay/IddSampleApp/IddSampleApp.vcxproj +++ b/video/IndirectDisplay/IddSampleApp/IddSampleApp.vcxproj @@ -1,10 +1,26 @@ + + Debug + ARM + + + Debug + ARM64 + Debug Win32 + + Release + ARM + + + Release + ARM64 + Release Win32 @@ -31,6 +47,18 @@ v142 Unicode + + Application + true + v142 + Unicode + + + Application + true + v142 + Unicode + Application false @@ -38,6 +66,20 @@ true Unicode + + Application + false + v142 + true + Unicode + + + Application + false + v142 + true + Unicode + Application true @@ -59,9 +101,21 @@ + + + + + + + + + + + + @@ -72,12 +126,24 @@ true + + true + + + true + true false + + false + + + false + false @@ -94,6 +160,32 @@ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;swdevice.lib;%(AdditionalDependencies) + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;swdevice.lib;%(AdditionalDependencies) + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;swdevice.lib;%(AdditionalDependencies) + + Level3 @@ -124,6 +216,40 @@ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;swdevice.lib;%(AdditionalDependencies) + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;swdevice.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;swdevice.lib;%(AdditionalDependencies) + + Level3 @@ -147,4 +273,4 @@ - + \ No newline at end of file diff --git a/video/IndirectDisplay/IddSampleDriver.sln b/video/IndirectDisplay/IddSampleDriver.sln index ec38923bf..c075ebc18 100644 --- a/video/IndirectDisplay/IddSampleDriver.sln +++ b/video/IndirectDisplay/IddSampleDriver.sln @@ -43,6 +43,22 @@ Global {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.ActiveCfg = Release|Win32 {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.Build.0 = Release|Win32 {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.Deploy.0 = Release|Win32 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Debug|ARM.ActiveCfg = Debug|ARM + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Debug|ARM.Build.0 = Debug|ARM + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Debug|ARM64.Build.0 = Debug|ARM64 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Debug|x64.ActiveCfg = Debug|x64 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Debug|x64.Build.0 = Debug|x64 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Debug|x86.ActiveCfg = Debug|Win32 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Debug|x86.Build.0 = Debug|Win32 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Release|ARM.ActiveCfg = Release|ARM + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Release|ARM.Build.0 = Release|ARM + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Release|ARM64.ActiveCfg = Release|ARM64 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Release|ARM64.Build.0 = Release|ARM64 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Release|x64.ActiveCfg = Release|x64 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Release|x64.Build.0 = Release|x64 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Release|x86.ActiveCfg = Release|Win32 + {ED59DFCA-E75B-4DD8-B5C2-6BFF77A225A6}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/video/IndirectDisplay/IddSampleDriver/Driver.cpp b/video/IndirectDisplay/IddSampleDriver/Driver.cpp index a9bd6108f..4ae12af59 100644 --- a/video/IndirectDisplay/IddSampleDriver/Driver.cpp +++ b/video/IndirectDisplay/IddSampleDriver/Driver.cpp @@ -22,6 +22,105 @@ using namespace std; using namespace Microsoft::IndirectDisp; using namespace Microsoft::WRL; +#pragma region SampleMonitors + +static constexpr DWORD IDD_SAMPLE_MONITOR_COUNT = 3; // If monitor count > ARRAYSIZE(s_SampleMonitors), we create edid-less monitors + +// Default modes reported for edid-less monitors. The first mode is set as preferred +static const struct IndirectSampleMonitor::SampleMonitorMode s_SampleDefaultModes[] = +{ + { 1920, 1080, 60 }, + { 1600, 900, 60 }, + { 1024, 768, 75 }, +}; + +// FOR SAMPLE PURPOSES ONLY, Static info about monitors that will be reported to OS +static const struct IndirectSampleMonitor s_SampleMonitors[] = +{ + // Modified EDID from Dell S2719DGF + { + { + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x10,0xAC,0xE6,0xD0,0x55,0x5A,0x4A,0x30,0x24,0x1D,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,0x37,0x4A,0x51,0x58,0x42,0x59,0x32,0x0A,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFC,0x00, + 0x53,0x32,0x37,0x31,0x39,0x44,0x47,0x46,0x0A,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFD,0x00,0x28, + 0x9B,0xFA,0xFA,0x40,0x01,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x2C + }, + { + { 2560, 1440, 144 }, + { 1920, 1080, 60 }, + { 1024, 768, 60 }, + }, + 0 + }, + // Modified EDID from Lenovo Y27fA + { + { + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x30,0xAE,0xBF,0x65,0x01,0x01,0x01,0x01,0x20,0x1A,0x01, + 0x04,0xA5,0x3C,0x22,0x78,0x3B,0xEE,0xD1,0xA5,0x55,0x48,0x9B,0x26,0x12,0x50,0x54,0x00,0x08,0x00, + 0xA9,0xC0,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x68,0xD8,0x00, + 0x18,0xF1,0x70,0x2D,0x80,0x58,0x2C,0x45,0x00,0x53,0x50,0x21,0x00,0x00,0x1E,0x00,0x00,0x00,0x10, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFD,0x00, + 0x30,0x92,0xB4,0xB4,0x22,0x01,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFC,0x00,0x4C, + 0x45,0x4E,0x20,0x59,0x32,0x37,0x66,0x41,0x0A,0x20,0x20,0x20,0x00,0x11 + }, + { + { 3840, 2160, 60 }, + { 1600, 900, 60 }, + { 1024, 768, 60 }, + }, + 0 + } +}; + +#pragma endregion + +#pragma region helpers + +static inline void FillSignalInfo(DISPLAYCONFIG_VIDEO_SIGNAL_INFO& Mode, DWORD Width, DWORD Height, DWORD VSync, bool bMonitorMode) +{ + Mode.totalSize.cx = Mode.activeSize.cx = Width; + Mode.totalSize.cy = Mode.activeSize.cy = Height; + + // See https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_video_signal_info + Mode.AdditionalSignalInfo.vSyncFreqDivider = bMonitorMode ? 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); +} + +static IDDCX_MONITOR_MODE CreateIddCxMonitorMode(DWORD Width, DWORD Height, DWORD VSync, IDDCX_MONITOR_MODE_ORIGIN Origin = IDDCX_MONITOR_MODE_ORIGIN_DRIVER) +{ + IDDCX_MONITOR_MODE Mode = {}; + + Mode.Size = sizeof(Mode); + Mode.Origin = Origin; + FillSignalInfo(Mode.MonitorVideoSignalInfo, Width, Height, VSync, true); + + return Mode; +} + +static IDDCX_TARGET_MODE CreateIddCxTargetMode(DWORD Width, DWORD Height, DWORD VSync) +{ + IDDCX_TARGET_MODE Mode = {}; + + Mode.Size = sizeof(Mode); + FillSignalInfo(Mode.TargetVideoSignalInfo.targetVideoSignalInfo, Width, Height, VSync, false); + + return Mode; +} + +#pragma endregion + extern "C" DRIVER_INITIALIZE DriverEntry; EVT_WDF_DRIVER_DEVICE_ADD IddSampleDeviceAdd; @@ -48,9 +147,22 @@ struct IndirectDeviceContextWrapper } }; +struct IndirectMonitorContextWrapper +{ + IndirectMonitorContext* pContext; + + void Cleanup() + { + delete pContext; + pContext = nullptr; + } +}; + // This macro creates the methods for accessing an IndirectDeviceContextWrapper as a context for a WDF object WDF_DECLARE_CONTEXT_TYPE(IndirectDeviceContextWrapper); +WDF_DECLARE_CONTEXT_TYPE(IndirectMonitorContextWrapper); + extern "C" BOOL WINAPI DllMain( _In_ HINSTANCE hInstance, _In_ UINT dwReason, @@ -241,7 +353,7 @@ void SwapChainProcessor::Run() // For improved performance, make use of the Multimedia Class Scheduler Service, which will intelligently // prioritize this thread for improved throughput in high CPU-load scenarios. DWORD AvTask = 0; - HANDLE AvTaskHandle = AvSetMmThreadCharacteristics(L"Distribution", &AvTask); + HANDLE AvTaskHandle = AvSetMmThreadCharacteristicsW(L"Distribution", &AvTask); RunCore(); @@ -349,55 +461,14 @@ void SwapChainProcessor::RunCore() #pragma region IndirectDeviceContext -const UINT64 MHZ = 1000000; -const UINT64 KHZ = 1000; - -// A list of modes exposed by the sample monitor EDID - FOR SAMPLE PURPOSES ONLY -const DISPLAYCONFIG_VIDEO_SIGNAL_INFO IndirectDeviceContext::s_KnownMonitorModes[] = -{ - // 800 x 600 @ 60Hz - { - 40 * MHZ, // pixel clock rate [Hz] - { 40 * MHZ, 800 + 256 }, // fractional horizontal refresh rate [Hz] - { 40 * MHZ, (800 + 256) * (600 + 28) }, // fractional vertical refresh rate [Hz] - { 800, 600 }, // (horizontal, vertical) active pixel resolution - { 800 + 256, 600 + 28 }, // (horizontal, vertical) total pixel resolution - { { 255, 0 }}, // video standard and vsync divider - DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE - }, - // 640 x 480 @ 60Hz - { - 25175 * KHZ, // pixel clock rate [Hz] - { 25175 * KHZ, 640 + 160 }, // fractional horizontal refresh rate [Hz] - { 25175 * KHZ, (640 + 160) * (480 + 46) }, // fractional vertical refresh rate [Hz] - { 640, 480 }, // (horizontal, vertical) active pixel resolution - { 640 + 160, 480 + 46 }, // (horizontal, vertical) blanking pixel resolution - { { 255, 0 } }, // video standard and vsync divider - DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE - }, -}; - -// This is a sample monitor EDID - FOR SAMPLE PURPOSES ONLY -const BYTE IndirectDeviceContext::s_KnownMonitorEdid[] = -{ - 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x79,0x5E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA6,0x01,0x03,0x80,0x28, - 0x1E,0x78,0x0A,0xEE,0x91,0xA3,0x54,0x4C,0x99,0x26,0x0F,0x50,0x54,0x20,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xA0,0x0F,0x20,0x00,0x31,0x58,0x1C,0x20,0x28,0x80,0x14,0x00, - 0x90,0x2C,0x11,0x00,0x00,0x1E,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E -}; - IndirectDeviceContext::IndirectDeviceContext(_In_ WDFDEVICE WdfDevice) : m_WdfDevice(WdfDevice) { m_Adapter = {}; - m_Monitor = {}; } IndirectDeviceContext::~IndirectDeviceContext() { - m_ProcessingThread.reset(); } void IndirectDeviceContext::InitAdapter() @@ -413,7 +484,7 @@ void IndirectDeviceContext::InitAdapter() AdapterCaps.Size = sizeof(AdapterCaps); // Declare basic feature support for the adapter (required) - AdapterCaps.MaxMonitorsSupported = 1; + AdapterCaps.MaxMonitorsSupported = IDD_SAMPLE_MONITOR_COUNT; AdapterCaps.EndPointDiagnostics.Size = sizeof(AdapterCaps.EndPointDiagnostics); AdapterCaps.EndPointDiagnostics.GammaSupport = IDDCX_FEATURE_IMPLEMENTATION_NONE; AdapterCaps.EndPointDiagnostics.TransmissionType = IDDCX_TRANSMISSION_TYPE_WIRED_OTHER; @@ -454,27 +525,37 @@ void IndirectDeviceContext::InitAdapter() } } -void IndirectDeviceContext::FinishInit() +void IndirectDeviceContext::FinishInit(UINT ConnectorIndex) { // ============================== - // TODO: In a real driver, the EDID should be retrieved dynamically from a connected physical monitor. The EDID - // provided here is purely for demonstration, as it describes only 640x480 @ 60 Hz and 800x600 @ 60 Hz. Monitor - // manufacturers are required to correctly fill in physical monitor attributes in order to allow the OS to optimize - // settings like viewing distance and scale factor. Manufacturers should also use a unique serial number every - // single device to ensure the OS can tell the monitors apart. + // TODO: In a real driver, the EDID should be retrieved dynamically from a connected physical monitor. The EDIDs + // provided here are purely for demonstration. + // Monitor manufacturers are required to correctly fill in physical monitor attributes in order to allow the OS + // to optimize settings like viewing distance and scale factor. Manufacturers should also use a unique serial + // number every single device to ensure the OS can tell the monitors apart. // ============================== WDF_OBJECT_ATTRIBUTES Attr; - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attr, IndirectDeviceContextWrapper); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attr, IndirectMonitorContextWrapper); + // In the sample driver, we report a monitor right away but a real driver would do this when a monitor connection event occurs IDDCX_MONITOR_INFO MonitorInfo = {}; MonitorInfo.Size = sizeof(MonitorInfo); MonitorInfo.MonitorType = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI; - MonitorInfo.ConnectorIndex = 0; + MonitorInfo.ConnectorIndex = ConnectorIndex; + MonitorInfo.MonitorDescription.Size = sizeof(MonitorInfo.MonitorDescription); MonitorInfo.MonitorDescription.Type = IDDCX_MONITOR_DESCRIPTION_TYPE_EDID; - MonitorInfo.MonitorDescription.DataSize = sizeof(s_KnownMonitorEdid); - MonitorInfo.MonitorDescription.pData = const_cast(s_KnownMonitorEdid); + if (ConnectorIndex >= ARRAYSIZE(s_SampleMonitors)) + { + MonitorInfo.MonitorDescription.DataSize = 0; + MonitorInfo.MonitorDescription.pData = nullptr; + } + else + { + MonitorInfo.MonitorDescription.DataSize = IndirectSampleMonitor::szEdidBlock; + MonitorInfo.MonitorDescription.pData = const_cast(s_SampleMonitors[ConnectorIndex].pEdidBlock); + } // ============================== // TODO: The monitor's container ID should be distinct from "this" device's container ID if the monitor is not @@ -496,19 +577,27 @@ void IndirectDeviceContext::FinishInit() NTSTATUS Status = IddCxMonitorCreate(m_Adapter, &MonitorCreate, &MonitorCreateOut); if (NT_SUCCESS(Status)) { - m_Monitor = MonitorCreateOut.MonitorObject; - - // Associate the monitor with this device context - auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(MonitorCreateOut.MonitorObject); - pContext->pContext = this; + // Create a new monitor context object and attach it to the Idd monitor object + auto* pMonitorContextWrapper = WdfObjectGet_IndirectMonitorContextWrapper(MonitorCreateOut.MonitorObject); + pMonitorContextWrapper->pContext = new IndirectMonitorContext(MonitorCreateOut.MonitorObject); // Tell the OS that the monitor has been plugged in IDARG_OUT_MONITORARRIVAL ArrivalOut; - Status = IddCxMonitorArrival(m_Monitor, &ArrivalOut); + Status = IddCxMonitorArrival(MonitorCreateOut.MonitorObject, &ArrivalOut); } } -void IndirectDeviceContext::AssignSwapChain(IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent) +IndirectMonitorContext::IndirectMonitorContext(_In_ IDDCX_MONITOR Monitor) : + m_Monitor(Monitor) +{ +} + +IndirectMonitorContext::~IndirectMonitorContext() +{ + m_ProcessingThread.reset(); +} + +void IndirectMonitorContext::AssignSwapChain(IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent) { m_ProcessingThread.reset(); @@ -526,7 +615,7 @@ void IndirectDeviceContext::AssignSwapChain(IDDCX_SWAPCHAIN SwapChain, LUID Rend } } -void IndirectDeviceContext::UnassignSwapChain() +void IndirectMonitorContext::UnassignSwapChain() { // Stop processing the last swap-chain m_ProcessingThread.reset(); @@ -542,10 +631,13 @@ NTSTATUS IddSampleAdapterInitFinished(IDDCX_ADAPTER AdapterObject, const IDARG_I // This is called when the OS has finished setting up the adapter for use by the IddCx driver. It's now possible // to report attached monitors. - auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(AdapterObject); + auto* pDeviceContextWrapper = WdfObjectGet_IndirectDeviceContextWrapper(AdapterObject); if (NT_SUCCESS(pInArgs->AdapterInitStatus)) { - pContext->pContext->FinishInit(); + for (DWORD i = 0; i < IDD_SAMPLE_MONITOR_COUNT; i++) + { + pDeviceContextWrapper->pContext->FinishInit(i); + } } return STATUS_SUCCESS; @@ -576,27 +668,47 @@ NTSTATUS IddSampleParseMonitorDescription(const IDARG_IN_PARSEMONITORDESCRIPTION // this sample driver, we hard-code the EDID, so this function can generate known modes. // ============================== - pOutArgs->MonitorModeBufferOutputCount = ARRAYSIZE(IndirectDeviceContext::s_KnownMonitorModes); + pOutArgs->MonitorModeBufferOutputCount = IndirectSampleMonitor::szModeList; - if (pInArgs->MonitorModeBufferInputCount < ARRAYSIZE(IndirectDeviceContext::s_KnownMonitorModes)) + if (pInArgs->MonitorModeBufferInputCount < IndirectSampleMonitor::szModeList) { // Return success if there was no buffer, since the caller was only asking for a count of modes return (pInArgs->MonitorModeBufferInputCount > 0) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; } else { - // Copy the known modes to the output buffer - for (DWORD ModeIndex = 0; ModeIndex < ARRAYSIZE(IndirectDeviceContext::s_KnownMonitorModes); ModeIndex++) + // In the sample driver, we have reported some static information about connected monitors + // Check which of the reported monitors this call is for by comparing it to the pointer of + // our known EDID blocks. + + if (pInArgs->MonitorDescription.DataSize != IndirectSampleMonitor::szEdidBlock) + return STATUS_INVALID_PARAMETER; + + DWORD SampleMonitorIdx = 0; + for(; SampleMonitorIdx < ARRAYSIZE(s_SampleMonitors); SampleMonitorIdx++) { - pInArgs->pMonitorModes[ModeIndex].Size = sizeof(IDDCX_MONITOR_MODE); - pInArgs->pMonitorModes[ModeIndex].Origin = IDDCX_MONITOR_MODE_ORIGIN_MONITORDESCRIPTOR; - pInArgs->pMonitorModes[ModeIndex].MonitorVideoSignalInfo = IndirectDeviceContext::s_KnownMonitorModes[ModeIndex]; + if (memcmp(pInArgs->MonitorDescription.pData, s_SampleMonitors[SampleMonitorIdx].pEdidBlock, IndirectSampleMonitor::szEdidBlock) == 0) + { + // Copy the known modes to the output buffer + for (DWORD ModeIndex = 0; ModeIndex < IndirectSampleMonitor::szModeList; ModeIndex++) + { + pInArgs->pMonitorModes[ModeIndex] = CreateIddCxMonitorMode( + s_SampleMonitors[SampleMonitorIdx].pModeList[ModeIndex].Width, + s_SampleMonitors[SampleMonitorIdx].pModeList[ModeIndex].Height, + s_SampleMonitors[SampleMonitorIdx].pModeList[ModeIndex].VSync, + IDDCX_MONITOR_MODE_ORIGIN_MONITORDESCRIPTOR + ); + } + + // Set the preferred mode as represented in the EDID + pOutArgs->PreferredMonitorModeIdx = s_SampleMonitors[SampleMonitorIdx].ulPreferredModeIdx; + + return STATUS_SUCCESS; + } } - // Set the preferred mode as represented in the EDID - pOutArgs->PreferredMonitorModeIdx = 0; - - return STATUS_SUCCESS; + // This EDID block does not belong to the monitors we reported earlier + return STATUS_INVALID_PARAMETER; } } @@ -604,10 +716,6 @@ _Use_decl_annotations_ NTSTATUS IddSampleMonitorGetDefaultModes(IDDCX_MONITOR MonitorObject, const IDARG_IN_GETDEFAULTDESCRIPTIONMODES* pInArgs, IDARG_OUT_GETDEFAULTDESCRIPTIONMODES* pOutArgs) { UNREFERENCED_PARAMETER(MonitorObject); - UNREFERENCED_PARAMETER(pInArgs); - UNREFERENCED_PARAMETER(pOutArgs); - - // Should never be called since we create a single monitor with a known EDID in this sample driver. // ============================== // TODO: In a real driver, this function would be called to generate monitor modes for a monitor with no EDID. @@ -616,29 +724,27 @@ NTSTATUS IddSampleMonitorGetDefaultModes(IDDCX_MONITOR MonitorObject, const IDAR // than an EDID, those modes would also be reported here. // ============================== - return STATUS_NOT_IMPLEMENTED; -} + if (pInArgs->DefaultMonitorModeBufferInputCount == 0) + { + pOutArgs->DefaultMonitorModeBufferOutputCount = ARRAYSIZE(s_SampleDefaultModes); + } + else + { + for (DWORD ModeIndex = 0; ModeIndex < ARRAYSIZE(s_SampleDefaultModes); ModeIndex++) + { + pInArgs->pDefaultMonitorModes[ModeIndex] = CreateIddCxMonitorMode( + s_SampleDefaultModes[ModeIndex].Width, + s_SampleDefaultModes[ModeIndex].Height, + s_SampleDefaultModes[ModeIndex].VSync, + IDDCX_MONITOR_MODE_ORIGIN_DRIVER + ); + } -/// -/// Creates a target mode from the fundamental mode attributes. -/// -void CreateTargetMode(DISPLAYCONFIG_VIDEO_SIGNAL_INFO& Mode, UINT Width, UINT Height, UINT VSync) -{ - Mode.totalSize.cx = Mode.activeSize.cx = Width; - Mode.totalSize.cy = Mode.activeSize.cy = Height; - Mode.AdditionalSignalInfo.vSyncFreqDivider = 1; - Mode.AdditionalSignalInfo.videoStandard = 255; - Mode.vSyncFreq.Numerator = VSync; - Mode.vSyncFreq.Denominator = Mode.hSyncFreq.Denominator = 1; - Mode.hSyncFreq.Numerator = VSync * Height; - Mode.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE; - Mode.pixelRate = ((UINT64) VSync) * ((UINT64) Width) * ((UINT64) Height); -} + pOutArgs->DefaultMonitorModeBufferOutputCount = ARRAYSIZE(s_SampleDefaultModes); + pOutArgs->PreferredMonitorModeIdx = 0; + } -void CreateTargetMode(IDDCX_TARGET_MODE& Mode, UINT Width, UINT Height, UINT VSync) -{ - Mode.Size = sizeof(Mode); - CreateTargetMode(Mode.TargetVideoSignalInfo.targetVideoSignalInfo, Width, Height, VSync); + return STATUS_SUCCESS; } _Use_decl_annotations_ @@ -646,18 +752,24 @@ NTSTATUS IddSampleMonitorQueryModes(IDDCX_MONITOR MonitorObject, const IDARG_IN_ { UNREFERENCED_PARAMETER(MonitorObject); - vector TargetModes(4); + vector TargetModes; // Create a set of modes supported for frame processing and scan-out. These are typically not based on the // monitor's descriptor and instead are based on the static processing capability of the device. The OS will // report the available set of modes for a given output as the intersection of monitor modes with target modes. - CreateTargetMode(TargetModes[0], 1920, 1080, 60); - CreateTargetMode(TargetModes[1], 1024, 768, 60); - CreateTargetMode(TargetModes[2], 800, 600, 60); - CreateTargetMode(TargetModes[3], 640, 480, 60); + TargetModes.push_back(CreateIddCxTargetMode(3840, 2160, 60)); + TargetModes.push_back(CreateIddCxTargetMode(2560, 1440, 144)); + TargetModes.push_back(CreateIddCxTargetMode(2560, 1440, 90)); + TargetModes.push_back(CreateIddCxTargetMode(2560, 1440, 60)); + TargetModes.push_back(CreateIddCxTargetMode(1920, 1080, 144)); + TargetModes.push_back(CreateIddCxTargetMode(1920, 1080, 90)); + TargetModes.push_back(CreateIddCxTargetMode(1920, 1080, 60)); + TargetModes.push_back(CreateIddCxTargetMode(1600, 900, 60)); + TargetModes.push_back(CreateIddCxTargetMode(1024, 768, 75)); + TargetModes.push_back(CreateIddCxTargetMode(1024, 768, 60)); - pOutArgs->TargetModeBufferOutputCount = (UINT)TargetModes.size(); + pOutArgs->TargetModeBufferOutputCount = (UINT) TargetModes.size(); if (pInArgs->TargetModeBufferInputCount >= TargetModes.size()) { @@ -670,16 +782,16 @@ NTSTATUS IddSampleMonitorQueryModes(IDDCX_MONITOR MonitorObject, const IDARG_IN_ _Use_decl_annotations_ NTSTATUS IddSampleMonitorAssignSwapChain(IDDCX_MONITOR MonitorObject, const IDARG_IN_SETSWAPCHAIN* pInArgs) { - auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(MonitorObject); - pContext->pContext->AssignSwapChain(pInArgs->hSwapChain, pInArgs->RenderAdapterLuid, pInArgs->hNextSurfaceAvailable); + auto* pMonitorContextWrapper = WdfObjectGet_IndirectMonitorContextWrapper(MonitorObject); + pMonitorContextWrapper->pContext->AssignSwapChain(pInArgs->hSwapChain, pInArgs->RenderAdapterLuid, pInArgs->hNextSurfaceAvailable); return STATUS_SUCCESS; } _Use_decl_annotations_ NTSTATUS IddSampleMonitorUnassignSwapChain(IDDCX_MONITOR MonitorObject) { - auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(MonitorObject); - pContext->pContext->UnassignSwapChain(); + auto* pMonitorContextWrapper = WdfObjectGet_IndirectMonitorContextWrapper(MonitorObject); + pMonitorContextWrapper->pContext->UnassignSwapChain(); return STATUS_SUCCESS; } diff --git a/video/IndirectDisplay/IddSampleDriver/Driver.h b/video/IndirectDisplay/IddSampleDriver/Driver.h index df69b0e49..373b5a25e 100644 --- a/video/IndirectDisplay/IddSampleDriver/Driver.h +++ b/video/IndirectDisplay/IddSampleDriver/Driver.h @@ -33,6 +33,23 @@ namespace Microsoft { namespace IndirectDisp { + /// + /// Manages the creation and lifetime of a Direct3D render device. + /// + struct IndirectSampleMonitor + { + static constexpr size_t szEdidBlock = 128; + static constexpr size_t szModeList = 3; + + const BYTE pEdidBlock[szEdidBlock]; + const struct SampleMonitorMode { + DWORD Width; + DWORD Height; + DWORD VSync; + } pModeList[szModeList]; + const DWORD ulPreferredModeIdx; + }; + /// /// Manages the creation and lifetime of a Direct3D render device. /// @@ -64,7 +81,6 @@ namespace Microsoft void Run(); void RunCore(); - public: IDDCX_SWAPCHAIN m_hSwapChain; std::shared_ptr m_Device; HANDLE m_hAvailableBufferEvent; @@ -82,22 +98,25 @@ namespace Microsoft virtual ~IndirectDeviceContext(); void InitAdapter(); - void FinishInit(); - - void AssignSwapChain(IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent); - void UnassignSwapChain(); + void FinishInit(UINT ConnectorIndex); protected: - WDFDEVICE m_WdfDevice; IDDCX_ADAPTER m_Adapter; - IDDCX_MONITOR m_Monitor; - - std::unique_ptr m_ProcessingThread; + }; + class IndirectMonitorContext + { public: - static const DISPLAYCONFIG_VIDEO_SIGNAL_INFO s_KnownMonitorModes[]; - static const BYTE s_KnownMonitorEdid[]; - }; + IndirectMonitorContext(_In_ IDDCX_MONITOR Monitor); + virtual ~IndirectMonitorContext(); + + void AssignSwapChain(IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent); + void UnassignSwapChain(); + + private: + IDDCX_MONITOR m_Monitor; + std::unique_ptr m_ProcessingThread; + } ; } } diff --git a/video/IndirectDisplay/IddSampleDriver/IddSampleDriver.vcxproj b/video/IndirectDisplay/IddSampleDriver/IddSampleDriver.vcxproj index 8a4842888..8a21c629b 100644 --- a/video/IndirectDisplay/IddSampleDriver/IddSampleDriver.vcxproj +++ b/video/IndirectDisplay/IddSampleDriver/IddSampleDriver.vcxproj @@ -293,6 +293,7 @@ trace.h Async true + /DUMDF_DRIVER /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=6 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib @@ -305,6 +306,7 @@ trace.h Async true + /DUMDF_DRIVER /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=6 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib