Add project files.

This commit is contained in:
karlf 2017-04-03 16:20:52 -07:00
parent f428f1869f
commit 8ca800d1e1
8 changed files with 1273 additions and 0 deletions

48
IddSampleDriver.sln Normal file
View File

@ -0,0 +1,48 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IddSampleDriver", "IddSampleDriver\IddSampleDriver.vcxproj", "{2D54CB75-8B17-4F11-97DC-847B0244CD46}"
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
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.ActiveCfg = Debug|ARM
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.Build.0 = Debug|ARM
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.Deploy.0 = Debug|ARM
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.ActiveCfg = Debug|ARM64
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.Build.0 = Debug|ARM64
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.Deploy.0 = Debug|ARM64
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.ActiveCfg = Debug|x64
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.Build.0 = Debug|x64
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.Deploy.0 = Debug|x64
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.ActiveCfg = Debug|Win32
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.Build.0 = Debug|Win32
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.Deploy.0 = Debug|Win32
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.ActiveCfg = Release|ARM
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.Build.0 = Release|ARM
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.Deploy.0 = Release|ARM
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.ActiveCfg = Release|ARM64
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.Build.0 = Release|ARM64
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.Deploy.0 = Release|ARM64
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.ActiveCfg = Release|x64
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.Build.0 = Release|x64
{2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.Deploy.0 = Release|x64
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

684
IddSampleDriver/Driver.cpp Normal file
View File

@ -0,0 +1,684 @@
/*++
Copyright (c) Microsoft Corporation
Abstract:
This module contains a sample implementation of an indirect display driver. See the included README.md file and the
various TODO blocks throughout this file and all accompanying files for information on building a production driver.
MSDN documentation on indirect displays can be found at https://msdn.microsoft.com/en-us/library/windows/hardware/mt761968(v=vs.85).aspx.
Environment:
User Mode, UMDF
--*/
#include "Driver.h"
#include "Driver.tmh"
using namespace std;
using namespace Microsoft::IndirectDisp;
using namespace Microsoft::WRL;
extern "C" DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD IddSampleDeviceAdd;
EVT_WDF_DEVICE_D0_ENTRY IddSampleDeviceD0Entry;
EVT_IDD_CX_ADAPTER_INIT_FINISHED IddSampleAdapterInitFinished;
EVT_IDD_CX_ADAPTER_COMMIT_MODES IddSampleAdapterCommitModes;
EVT_IDD_CX_PARSE_MONITOR_DESCRIPTION IddSampleParseMonitorDescription;
EVT_IDD_CX_MONITOR_GET_DEFAULT_DESCRIPTION_MODES IddSampleMonitorGetDefaultModes;
EVT_IDD_CX_MONITOR_QUERY_TARGET_MODES IddSampleMonitorQueryModes;
EVT_IDD_CX_MONITOR_ASSIGN_SWAPCHAIN IddSampleMonitorAssignSwapChain;
EVT_IDD_CX_MONITOR_UNASSIGN_SWAPCHAIN IddSampleMonitorUnassignSwapChain;
struct IndirectDeviceContextWrapper
{
IndirectDeviceContext* 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);
extern "C" BOOL WINAPI DllMain(
_In_ HINSTANCE hInstance,
_In_ UINT dwReason,
_In_opt_ LPVOID lpReserved)
{
UNREFERENCED_PARAMETER(hInstance);
UNREFERENCED_PARAMETER(lpReserved);
UNREFERENCED_PARAMETER(dwReason);
return TRUE;
}
_Use_decl_annotations_
extern "C" NTSTATUS DriverEntry(
PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pRegistryPath
)
{
WDF_DRIVER_CONFIG Config;
NTSTATUS Status;
WDF_OBJECT_ATTRIBUTES Attributes;
WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
WDF_DRIVER_CONFIG_INIT(&Config,
IddSampleDeviceAdd
);
Status = WdfDriverCreate(pDriverObject, pRegistryPath, &Attributes, &Config, WDF_NO_HANDLE);
if (!NT_SUCCESS(Status))
{
return Status;
}
return Status;
}
_Use_decl_annotations_
NTSTATUS IddSampleDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT pDeviceInit)
{
NTSTATUS Status = STATUS_SUCCESS;
WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks;
UNREFERENCED_PARAMETER(Driver);
// Register for power callbacks - in this sample only power-on is needed
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks);
PnpPowerCallbacks.EvtDeviceD0Entry = IddSampleDeviceD0Entry;
WdfDeviceInitSetPnpPowerEventCallbacks(pDeviceInit, &PnpPowerCallbacks);
IDD_CX_CLIENT_CONFIG IddConfig;
IDD_CX_CLIENT_CONFIG_INIT(&IddConfig);
// If the driver wishes to handle custom IoDeviceControl requests, it's necessary to use this callback since IddCx
// redirects IoDeviceControl requests to an internal queue. This sample does not need this.
// IddConfig.EvtIddCxDeviceIoControl = IddSampleIoDeviceControl;
IddConfig.EvtIddCxAdapterInitFinished = IddSampleAdapterInitFinished;
IddConfig.EvtIddCxParseMonitorDescription = IddSampleParseMonitorDescription;
IddConfig.EvtIddCxMonitorGetDefaultDescriptionModes = IddSampleMonitorGetDefaultModes;
IddConfig.EvtIddCxMonitorQueryTargetModes = IddSampleMonitorQueryModes;
IddConfig.EvtIddCxAdapterCommitModes = IddSampleAdapterCommitModes;
IddConfig.EvtIddCxMonitorAssignSwapChain = IddSampleMonitorAssignSwapChain;
IddConfig.EvtIddCxMonitorUnassignSwapChain = IddSampleMonitorUnassignSwapChain;
Status = IddCxDeviceInitConfig(pDeviceInit, &IddConfig);
if (!NT_SUCCESS(Status))
{
return Status;
}
WDF_OBJECT_ATTRIBUTES Attr;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attr, IndirectDeviceContextWrapper);
Attr.EvtCleanupCallback = [](WDFOBJECT Object)
{
// Automatically cleanup the context when the WDF object is about to be deleted
auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(Object);
if (pContext)
{
pContext->Cleanup();
}
};
WDFDEVICE Device = nullptr;
Status = WdfDeviceCreate(&pDeviceInit, &Attr, &Device);
if (!NT_SUCCESS(Status))
{
return Status;
}
Status = IddCxDeviceInitialize(Device);
// Create a new device context object and attach it to the WDF device object
auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(Device);
pContext->pContext = new IndirectDeviceContext(Device);
return Status;
}
_Use_decl_annotations_
NTSTATUS IddSampleDeviceD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState)
{
UNREFERENCED_PARAMETER(PreviousState);
// This function is called by WDF to start the device in the fully-on power state.
auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(Device);
pContext->pContext->InitAdapter();
return STATUS_SUCCESS;
}
#pragma region Direct3DDevice
Direct3DDevice::Direct3DDevice(LUID AdapterLuid) : AdapterLuid(AdapterLuid)
{
}
Direct3DDevice::Direct3DDevice()
{
}
HRESULT Direct3DDevice::Init()
{
// The DXGI factory could be cached, but if a new render adapter appears on the system, a new factory needs to be
// created. If caching is desired, check DxgiFactory->IsCurrent() each time and recreate the factory if !IsCurrent.
HRESULT hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&DxgiFactory));
if (FAILED(hr))
{
return hr;
}
// Find the specified render adapter
hr = DxgiFactory->EnumAdapterByLuid(AdapterLuid, IID_PPV_ARGS(&Adapter));
if (FAILED(hr))
{
return hr;
}
// Create a D3D device using the render adapter. BGRA support is required by the WHQL test suite.
hr = D3D11CreateDevice(Adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, nullptr, 0, D3D11_SDK_VERSION, &Device, nullptr, &DeviceContext);
if (FAILED(hr))
{
// If creating the D3D device failed, it's possible the render GPU was lost (e.g. detachable GPU) or else the
// system is in a transient state.
return hr;
}
return S_OK;
}
#pragma endregion
#pragma region SwapChainProcessor
SwapChainProcessor::SwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, shared_ptr<Direct3DDevice> Device, HANDLE NewFrameEvent)
: m_hSwapChain(hSwapChain), m_Device(Device), m_hAvailableBufferEvent(NewFrameEvent)
{
m_hTerminateEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr));
// Immediately create and run the swap-chain processing thread, passing 'this' as the thread parameter
m_hThread.Attach(CreateThread(nullptr, 0, RunThread, this, 0, nullptr));
}
SwapChainProcessor::~SwapChainProcessor()
{
// Alert the swap-chain processing thread to terminate
SetEvent(m_hTerminateEvent.Get());
if (m_hThread.Get())
{
// Wait for the thread to terminate
WaitForSingleObject(m_hThread.Get(), INFINITE);
}
}
DWORD CALLBACK SwapChainProcessor::RunThread(LPVOID Argument)
{
reinterpret_cast<SwapChainProcessor*>(Argument)->Run();
return 0;
}
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);
RunCore();
// Always delete the swap-chain object when swap-chain processing loop terminates in order to kick the system to
// provide a new swap-chain if necessary.
WdfObjectDelete((WDFOBJECT)m_hSwapChain);
m_hSwapChain = nullptr;
AvRevertMmThreadCharacteristics(AvTaskHandle);
}
void SwapChainProcessor::RunCore()
{
// Get the DXGI device interface
ComPtr<IDXGIDevice> DxgiDevice;
HRESULT hr = m_Device->Device.As(&DxgiDevice);
if (FAILED(hr))
{
return;
}
IDARG_IN_SWAPCHAINSETDEVICE SetDevice = {};
SetDevice.pDevice = DxgiDevice.Get();
hr = IddCxSwapChainSetDevice(m_hSwapChain, &SetDevice);
if (FAILED(hr))
{
return;
}
// Acquire and release buffers in a loop
for (;;)
{
ComPtr<IDXGIResource> AcquiredBuffer;
// Ask for the next buffer from the producer
IDARG_OUT_RELEASEANDACQUIREBUFFER Buffer = {};
hr = IddCxSwapChainReleaseAndAcquireBuffer(m_hSwapChain, &Buffer);
// AcquireBuffer immediately returns STATUS_PENDING if no buffer is yet available
if (hr == E_PENDING)
{
// We must wait for a new buffer
HANDLE WaitHandles [] =
{
m_hAvailableBufferEvent,
m_hTerminateEvent.Get()
};
DWORD WaitResult = WaitForMultipleObjects(ARRAYSIZE(WaitHandles), WaitHandles, FALSE, 16);
if (WaitResult == WAIT_OBJECT_0 || WaitResult == WAIT_TIMEOUT)
{
// We have a new buffer, so try the AcquireBuffer again
continue;
}
else if (WaitResult == WAIT_OBJECT_0 + 1)
{
// We need to terminate
break;
}
else
{
// The wait was cancelled or something unexpected happened
hr = HRESULT_FROM_WIN32(WaitResult);
break;
}
}
else if (SUCCEEDED(hr))
{
AcquiredBuffer.Attach(Buffer.MetaData.pSurface);
// ==============================
// TODO: Process the frame here
//
// This is the most performance-critical section of code in an IddCx driver. It's important that whatever
// is done with the acquired surface be finished as quickly as possible. This operation could be:
// * a GPU copy to another buffer surface for later processing (such as a staging surface for mapping to CPU memory)
// * a GPU encode operation
// * a GPU VPBlt to another surface
// * a GPU custom compute shader encode operation
// ==============================
AcquiredBuffer.Reset();
hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
if (FAILED(hr))
{
break;
}
// ==============================
// TODO: Report frame statistics once the asynchronous encode/send work is completed
//
// Drivers should report information about sub-frame timings, like encode time, send time, etc.
// ==============================
// IddCxSwapChainReportFrameStatistics(m_hSwapChain, ...);
}
else
{
// The swap-chain was likely abandoned (e.g. DXGI_ERROR_ACCESS_LOST), so exit the processing loop
break;
}
}
}
#pragma endregion
#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)
{
}
IndirectDeviceContext::~IndirectDeviceContext()
{
m_ProcessingThread.reset();
}
void IndirectDeviceContext::InitAdapter()
{
// ==============================
// TODO: Update the below diagnostic information in accordance with the target hardware. The strings and version
// numbers are used for telemetry and may be displayed to the user in some situations.
//
// This is also where static per-adapter capabilities are determined.
// ==============================
IDDCX_ADAPTER_CAPS AdapterCaps = {};
AdapterCaps.Size = sizeof(AdapterCaps);
// Declare basic feature support for the adapter (required)
AdapterCaps.MaxMonitorsSupported = 1;
AdapterCaps.EndPointDiagnostics.Size = sizeof(AdapterCaps.EndPointDiagnostics);
AdapterCaps.EndPointDiagnostics.GammaSupport = IDDCX_FEATURE_IMPLEMENTATION_NONE;
AdapterCaps.EndPointDiagnostics.TransmissionType = IDDCX_TRANSMISSION_TYPE_WIRED_OTHER;
// Declare your device strings for telemetry (required)
AdapterCaps.EndPointDiagnostics.pEndPointFriendlyName = L"IddSample Device";
AdapterCaps.EndPointDiagnostics.pEndPointManufacturerName = L"Microsoft";
AdapterCaps.EndPointDiagnostics.pEndPointModelName = L"IddSample Model";
// Declare your hardware and firmware versions (required)
IDDCX_ENDPOINT_VERSION Version = {};
Version.Size = sizeof(Version);
Version.MajorVer = 1;
AdapterCaps.EndPointDiagnostics.pFirmwareVersion = &Version;
AdapterCaps.EndPointDiagnostics.pHardwareVersion = &Version;
// Initialize a WDF context that can store a pointer to the device context object
WDF_OBJECT_ATTRIBUTES Attr;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attr, IndirectDeviceContextWrapper);
IDARG_IN_ADAPTER_INIT AdapterInit = {};
AdapterInit.WdfDevice = m_WdfDevice;
AdapterInit.pCaps = &AdapterCaps;
AdapterInit.ObjectAttributes = &Attr;
// Start the initialization of the adapter, which will trigger the AdapterFinishInit callback later
IDARG_OUT_ADAPTER_INIT AdapterInitOut;
NTSTATUS Status = IddCxAdapterInitAsync(&AdapterInit, &AdapterInitOut);
if (NT_SUCCESS(Status))
{
// Store a reference to the WDF adapter handle
m_Adapter = AdapterInitOut.AdapterObject;
// Store the device context object into the WDF object context
auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(AdapterInitOut.AdapterObject);
pContext->pContext = this;
}
}
void IndirectDeviceContext::FinishInit()
{
// ==============================
// 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.
// ==============================
WDF_OBJECT_ATTRIBUTES Attr;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attr, IndirectDeviceContextWrapper);
IDDCX_MONITOR_INFO MonitorInfo = {};
MonitorInfo.Size = sizeof(MonitorInfo);
MonitorInfo.MonitorType = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI;
MonitorInfo.ConnectorIndex = 0;
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<BYTE*>(s_KnownMonitorEdid);
// ==============================
// TODO: The monitor's container ID should be distinct from "this" device's container ID if the monitor is not
// permanently attached to the display adapter device object. The container ID is typically made unique for each
// monitor and can be used to associate the monitor with other devices, like audio or input devices. In this
// sample we generate a random container ID GUID, but it's best practice to choose a stable container ID for a
// unique monitor or to use "this" device's container ID for a permanent/integrated monitor.
// ==============================
// Create a container ID
CoCreateGuid(&MonitorInfo.MonitorContainerId);
IDARG_IN_MONITORCREATE MonitorCreate = {};
MonitorCreate.ObjectAttributes = &Attr;
MonitorCreate.pMonitorInfo = &MonitorInfo;
// Create a monitor object with the specified monitor descriptor
IDARG_OUT_MONITORCREATE MonitorCreateOut;
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;
// Tell the OS that the monitor has been plugged in
IDARG_OUT_MONITORARRIVAL ArrivalOut;
Status = IddCxMonitorArrival(m_Monitor, &ArrivalOut);
}
}
void IndirectDeviceContext::AssignSwapChain(IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent)
{
m_ProcessingThread.reset();
auto Device = make_shared<Direct3DDevice>(RenderAdapter);
if (FAILED(Device->Init()))
{
// It's important to delete the swap-chain if D3D initialization fails, so that the OS knows to generate a new
// swap-chain and try again.
WdfObjectDelete(SwapChain);
}
else
{
// Create a new swap-chain processing thread
m_ProcessingThread.reset(new SwapChainProcessor(SwapChain, Device, NewFrameEvent));
}
}
void IndirectDeviceContext::UnassignSwapChain()
{
// Stop processing the last swap-chain
m_ProcessingThread.reset();
}
#pragma endregion
#pragma region DDI Callbacks
_Use_decl_annotations_
NTSTATUS IddSampleAdapterInitFinished(IDDCX_ADAPTER AdapterObject, const IDARG_IN_ADAPTER_INIT_FINISHED* pInArgs)
{
// 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);
if (NT_SUCCESS(pInArgs->AdapterInitStatus))
{
pContext->pContext->FinishInit();
}
return STATUS_SUCCESS;
}
_Use_decl_annotations_
NTSTATUS IddSampleAdapterCommitModes(IDDCX_ADAPTER AdapterObject, const IDARG_IN_COMMITMODES* pInArgs)
{
UNREFERENCED_PARAMETER(AdapterObject);
UNREFERENCED_PARAMETER(pInArgs);
// For the sample, do nothing when modes are picked - the swap-chain is taken care of by IddCx
// ==============================
// TODO: In a real driver, this function would be used to reconfigure the device to commit the new modes. Loop
// through pInArgs->pPaths and look for IDDCX_PATH_FLAGS_ACTIVE. Any path not active is inactive (e.g. the monitor
// should be turned off).
// ==============================
return STATUS_SUCCESS;
}
_Use_decl_annotations_
NTSTATUS IddSampleParseMonitorDescription(const IDARG_IN_PARSEMONITORDESCRIPTION* pInArgs, IDARG_OUT_PARSEMONITORDESCRIPTION* pOutArgs)
{
// ==============================
// TODO: In a real driver, this function would be called to generate monitor modes for an EDID by parsing it. In
// this sample driver, we hard-code the EDID, so this function can generate known modes.
// ==============================
pOutArgs->MonitorModeBufferOutputCount = ARRAYSIZE(IndirectDeviceContext::s_KnownMonitorModes);
if (pInArgs->MonitorModeBufferInputCount < ARRAYSIZE(IndirectDeviceContext::s_KnownMonitorModes))
{
// 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++)
{
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];
}
// Set the preferred mode as represented in the EDID
pOutArgs->PreferredMonitorModeIdx = 0;
return STATUS_SUCCESS;
}
}
_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.
// Drivers should report modes that are guaranteed to be supported by the transport protocol and by nearly all
// monitors (such 640x480, 800x600, or 1024x768). If the driver has access to monitor modes from a descriptor other
// than an EDID, those modes would also be reported here.
// ==============================
return STATUS_NOT_IMPLEMENTED;
}
/// <summary>
/// Creates a target mode from the fundamental mode attributes.
/// </summary>
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 = VSync * Width * Height;
}
void CreateTargetMode(IDDCX_TARGET_MODE& Mode, UINT Width, UINT Height, UINT VSync)
{
Mode.Size = sizeof(Mode);
CreateTargetMode(Mode.TargetVideoSignalInfo.targetVideoSignalInfo, Width, Height, VSync);
}
_Use_decl_annotations_
NTSTATUS IddSampleMonitorQueryModes(IDDCX_MONITOR MonitorObject, const IDARG_IN_QUERYTARGETMODES* pInArgs, IDARG_OUT_QUERYTARGETMODES* pOutArgs)
{
UNREFERENCED_PARAMETER(MonitorObject);
vector<IDDCX_TARGET_MODE> TargetModes(4);
// 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);
pOutArgs->TargetModeBufferOutputCount = (UINT)TargetModes.size();
if (pInArgs->TargetModeBufferInputCount >= TargetModes.size())
{
copy(TargetModes.begin(), TargetModes.end(), pInArgs->pTargetModes);
}
return STATUS_SUCCESS;
}
_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);
return STATUS_SUCCESS;
}
_Use_decl_annotations_
NTSTATUS IddSampleMonitorUnassignSwapChain(IDDCX_MONITOR MonitorObject)
{
auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(MonitorObject);
pContext->pContext->UnassignSwapChain();
return STATUS_SUCCESS;
}
#pragma endregion

103
IddSampleDriver/Driver.h Normal file
View File

@ -0,0 +1,103 @@
#pragma once
#define NOMINMAX
#include <windows.h>
#include <bugcodes.h>
#include <wudfwdm.h>
#include <wdf.h>
#include <iddcx.h>
#include <dxgi1_5.h>
#include <d3d11_2.h>
#include <avrt.h>
#include <wrl.h>
#include <memory>
#include <vector>
#include "Trace.h"
namespace Microsoft
{
namespace WRL
{
namespace Wrappers
{
// Adds a wrapper for thread handles to the existing set of WRL handle wrapper classes
typedef HandleT<HandleTraits::HANDLENullTraits> Thread;
}
}
}
namespace Microsoft
{
namespace IndirectDisp
{
/// <summary>
/// Manages the creation and lifetime of a Direct3D render device.
/// </summary>
struct Direct3DDevice
{
Direct3DDevice(LUID AdapterLuid);
Direct3DDevice();
HRESULT Init();
LUID AdapterLuid;
Microsoft::WRL::ComPtr<IDXGIFactory5> DxgiFactory;
Microsoft::WRL::ComPtr<IDXGIAdapter1> Adapter;
Microsoft::WRL::ComPtr<ID3D11Device> Device;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> DeviceContext;
};
/// <summary>
/// Manages a thread that consumes buffers from an indirect display swap-chain object.
/// </summary>
class SwapChainProcessor
{
public:
SwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, std::shared_ptr<Direct3DDevice> Device, HANDLE NewFrameEvent);
~SwapChainProcessor();
private:
static DWORD CALLBACK RunThread(LPVOID Argument);
void Run();
void RunCore();
public:
IDDCX_SWAPCHAIN m_hSwapChain;
std::shared_ptr<Direct3DDevice> m_Device;
HANDLE m_hAvailableBufferEvent;
Microsoft::WRL::Wrappers::Thread m_hThread;
Microsoft::WRL::Wrappers::Event m_hTerminateEvent;
};
/// <summary>
/// Provides a sample implementation of an indirect display driver.
/// </summary>
class IndirectDeviceContext
{
public:
IndirectDeviceContext(_In_ WDFDEVICE WdfDevice);
virtual ~IndirectDeviceContext();
void InitAdapter();
void FinishInit();
void AssignSwapChain(IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent);
void UnassignSwapChain();
protected:
WDFDEVICE m_WdfDevice;
IDDCX_ADAPTER m_Adapter;
IDDCX_MONITOR m_Monitor;
std::unique_ptr<SwapChainProcessor> m_ProcessingThread;
public:
static const DISPLAYCONFIG_VIDEO_SIGNAL_INFO s_KnownMonitorModes[];
static const BYTE s_KnownMonitorEdid[];
};
}
}

Binary file not shown.

View File

@ -0,0 +1,302 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Driver.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Driver.h" />
<ClInclude Include="Trace.h" />
</ItemGroup>
<ItemGroup>
<Inf Include="IddSampleDriver.inf" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{2D54CB75-8B17-4F11-97DC-847B0244CD46}</ProjectGuid>
<TemplateGuid>{32909489-7be5-497b-aafa-db6669d9b44b}</TemplateGuid>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
<Configuration>Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
<RootNamespace>IddSampleDriver</RootNamespace>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
<UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
<IndirectDisplayDriver>true</IndirectDisplayDriver>
<IDDCX_VERSION_MAJOR>1</IDDCX_VERSION_MAJOR>
<IDDCX_VERSION_MINOR>0</IDDCX_VERSION_MINOR>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
<UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
<IndirectDisplayDriver>true</IndirectDisplayDriver>
<IDDCX_VERSION_MAJOR>1</IDDCX_VERSION_MAJOR>
<IDDCX_VERSION_MINOR>0</IDDCX_VERSION_MINOR>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
<UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
<IndirectDisplayDriver>true</IndirectDisplayDriver>
<IDDCX_VERSION_MAJOR>1</IDDCX_VERSION_MAJOR>
<IDDCX_VERSION_MINOR>0</IDDCX_VERSION_MINOR>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
<UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
<IndirectDisplayDriver>true</IndirectDisplayDriver>
<IDDCX_VERSION_MAJOR>1</IDDCX_VERSION_MAJOR>
<IDDCX_VERSION_MINOR>0</IDDCX_VERSION_MINOR>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
<UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
<IndirectDisplayDriver>true</IndirectDisplayDriver>
<IDDCX_VERSION_MAJOR>1</IDDCX_VERSION_MAJOR>
<IDDCX_VERSION_MINOR>0</IDDCX_VERSION_MINOR>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
<UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
<IndirectDisplayDriver>true</IndirectDisplayDriver>
<IDDCX_VERSION_MAJOR>1</IDDCX_VERSION_MAJOR>
<IDDCX_VERSION_MINOR>0</IDDCX_VERSION_MINOR>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
<UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
<IndirectDisplayDriver>true</IndirectDisplayDriver>
<IDDCX_VERSION_MAJOR>1</IDDCX_VERSION_MAJOR>
<IDDCX_VERSION_MINOR>0</IDDCX_VERSION_MINOR>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
<UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
<IndirectDisplayDriver>true</IndirectDisplayDriver>
<IDDCX_VERSION_MAJOR>1</IDDCX_VERSION_MAJOR>
<IDDCX_VERSION_MINOR>0</IDDCX_VERSION_MINOR>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<FilesToPackage Include="$(TargetPath)" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<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>
<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>
<Filter Include="Driver Files">
<UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
<Extensions>inf;inv;inx;mof;mc;</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<Inf Include="IddSampleDriver.inf">
<Filter>Driver Files</Filter>
</Inf>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Driver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Trace.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Driver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

63
IddSampleDriver/Trace.h Normal file
View File

@ -0,0 +1,63 @@
/*++
Module Name:
Internal.h
Abstract:
This module contains the local type definitions for the
driver.
Environment:
Windows User-Mode Driver Framework 2
--*/
//
// Define the tracing flags.
//
// Tracing GUID - b254994f-46e6-4718-80a0-0a3aa50d6ce4
//
#define WPP_CONTROL_GUIDS \
WPP_DEFINE_CONTROL_GUID( \
MyDriver1TraceGuid, (b254994f,46e6,4718,80a0,0a3aa50d6ce4), \
\
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
// TODO: Update the name of the tracing provider
#define MYDRIVER_TRACING_ID L"Microsoft\\UMDF2.0\\IddSampleDriver V1.0"
#endif

34
README.md Normal file
View File

@ -0,0 +1,34 @@
# Indirect Display Driver Sample #
This is a sample driver that shows how to create a Windows Indirect Display Driver using the IddCx class extension driver.
## Background reading ##
Start at the [Indirect Display Driver Model Overview](https://msdn.microsoft.com/en-us/library/windows/hardware/mt761968(v=vs.85).aspx) on MSDN.
## Customizing the sample ##
The sample driver code is very simplistic and does nothing more than enumerate a single monitor when its device enters the D0/started power state. Throughout the code, there are `TODO` blocks with important information on implementing functionality in a production driver.
### Code structure ###
* `Direct3DDevice` class
* Contains logic for enumerating the correct render GPU from DXGI and creating a D3D device.
* Manages the lifetime of a DXGI factory and a D3D device created for the render GPU the system is using to render frames for your indirect display device's swap-chain.
* `SwapChainProcessor` class
* Processes frames for a swap-chain assigned to the monitor object on a dedicated thread.
* The sample code does nothing with the frames, but demonstrates a correct processing loop with error handling and notifying the OS of frame completion.
* `IndirectDeviceContext` class
* Processes device callbacks from IddCx.
* Manages the creation and arrival of the sample monitor.
* Handles swap-chain arrival and departure by creating a `Direct3DDevice` and handing it off to a `SwapChainProcessor`.
### First steps ###
Consider the capabilities of your device. If the device supports multiple monitors being hotplugged and removed at runtime, you may want to abstract the monitors further from the `IndirectDeviceContext` class.
The INF file included in the sample needs updating for production use. One field, `DeviceGroupId`, controls how the UMDF driver gets pooled with other UMDF drivers in the same process. Since indirect display drivers tend to be more complicated than other driver classes, it's highly recommended that you pick a unique string for this field which will cause instances of your device driver to pool in a dedicated process. This will improve system reliability in case your driver encounters a problem since other drivers will not be affected.
Ensure the device information reported to `IddCxAdapterInitAsync` is accurate. This information determines how the device is reported to the OS and what static features (like support for gamma tables) the device will have available. If some information cannot be known immediately in the `EvtDeviceD0Entry` callback, IddCx allows the driver to call `IddCxAdapterInitAsync` at any point after D0 entry, before D0 exit.
Careful attention should be paid to the frame processing loop. This will directly impact the performance of the user's system, so making use of the [Multimedia Class Scheduler Service](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684247(v=vs.85).aspx) and DXGI's support for [GPU prioritization](https://msdn.microsoft.com/en-us/library/windows/desktop/bb174534(v=vs.85).aspx) should be considered. Any significant work should be performed outside the main processing loop, such as by queuing work in a thread pool. See `SwapChainProcessor::RunCore` for more information.