Architecture Overview
The Virtual Display Driver is a user-mode display driver built on Microsoft’s IddCx framework. It creates virtual displays by implementing the Indirect Display Driver model, integrating with Windows’ graphics stack through Direct3D and the Desktop Window Manager (DWM).
Core Components
Driver Entry Point
The driver implements a standard UMDF driver entry point:
extern "C" DRIVER_INITIALIZE DriverEntry;
// Driver callbacks
EVT_WDF_DRIVER_DEVICE_ADD VirtualDisplayDriverDeviceAdd;
EVT_WDF_DEVICE_D0_ENTRY VirtualDisplayDriverDeviceD0Entry;
The driver runs in User Mode (UMDF) , not kernel mode, providing better stability and easier debugging.
IndirectDeviceContext
The IndirectDeviceContext class manages the virtual display adapter and monitors:
namespace Microsoft :: IndirectDisp {
class IndirectDeviceContext {
public:
IndirectDeviceContext ( _In_ WDFDEVICE WdfDevice );
virtual ~IndirectDeviceContext ();
void InitAdapter ();
void FinishInit ();
void CreateMonitor ( unsigned int index );
void AssignSwapChain ( IDDCX_MONITOR & Monitor ,
IDDCX_SWAPCHAIN SwapChain ,
LUID RenderAdapter ,
HANDLE NewFrameEvent );
void UnassignSwapChain ();
protected:
WDFDEVICE m_WdfDevice; // WDF device object
IDDCX_ADAPTER m_Adapter; // Virtual adapter
IDDCX_MONITOR m_Monitor; // Primary monitor
IDDCX_MONITOR m_Monitor2; // Secondary monitor
std ::unique_ptr < SwapChainProcessor > m_ProcessingThread;
};
}
Adapter Management Creates and manages the virtual display adapter (IDDCX_ADAPTER) that Windows recognizes
Monitor Lifecycle Handles creation, configuration, and destruction of virtual monitors
SwapChain Processing Manages frame buffer exchange between Windows compositor and driver
EDID Handling Loads and provides EDID data to identify monitor capabilities
Direct3DDevice
Manages Direct3D rendering resources for GPU-accelerated buffer processing:
struct Direct3DDevice {
Direct3DDevice ( LUID AdapterLuid );
Direct3DDevice ();
HRESULT Init ();
LUID AdapterLuid; // GPU identifier
Microsoft :: WRL ::ComPtr < IDXGIFactory5 > DxgiFactory; // DXGI factory
Microsoft :: WRL ::ComPtr < IDXGIAdapter1 > Adapter; // GPU adapter
Microsoft :: WRL ::ComPtr < ID3D11Device > Device; // D3D11 device
Microsoft :: WRL ::ComPtr < ID3D11DeviceContext > DeviceContext; // Context
};
GPU Resource Management
The driver implements an efficient device cache:
class IndirectDeviceContext {
private:
static std ::map < LUID, std ::shared_ptr < Direct3DDevice > ,
LuidComparator > s_DeviceCache;
static std ::mutex s_DeviceCacheMutex;
static std ::shared_ptr < Direct3DDevice >
GetOrCreateDevice ( LUID RenderAdapter );
static void CleanupExpiredDevices ();
};
The device cache shares D3D11 devices across multiple virtual monitors using the same GPU, reducing memory overhead and improving performance.
SwapChainProcessor
Processes frames from the Windows compositor in a dedicated thread:
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; // SwapChain handle
std ::shared_ptr < Direct3DDevice > m_Device; // D3D device
HANDLE m_hAvailableBufferEvent; // Frame ready event
Microsoft :: WRL :: Wrappers ::Thread m_hThread; // Processing thread
Microsoft :: WRL :: Wrappers ::Event m_hTerminateEvent; // Shutdown event
};
Frame Processing Pipeline
Wait for Frame
Thread waits on m_hAvailableBufferEvent for new frame from compositor
Acquire Buffer
Call IddCxSwapChainReleaseAndAcquireBuffer() to get the latest frame
Process Frame
Access the Direct3D surface containing the rendered frame
Release Buffer
Call IddCxSwapChainFinishedProcessingFrame() to return buffer
Repeat
Loop continues until monitor is disconnected
Windows Integration
IddCx Callback Events
The driver implements required IddCx callbacks:
// Adapter initialization complete
EVT_IDD_CX_ADAPTER_INIT_FINISHED
VirtualDisplayDriverAdapterInitFinished;
// Commit display mode changes
EVT_IDD_CX_ADAPTER_COMMIT_MODES
VirtualDisplayDriverAdapterCommitModes;
EVT_IDD_CX_ADAPTER_COMMIT_MODES2
VirtualDisplayDriverEvtIddCxAdapterCommitModes2;
// Query adapter capabilities
EVT_IDD_CX_ADAPTER_QUERY_TARGET_INFO
VirtualDisplayDriverEvtIddCxAdapterQueryTargetInfo;
// Parse monitor EDID
EVT_IDD_CX_PARSE_MONITOR_DESCRIPTION
VirtualDisplayDriverParseMonitorDescription;
EVT_IDD_CX_PARSE_MONITOR_DESCRIPTION2
VirtualDisplayDriverEvtIddCxParseMonitorDescription2;
// Enumerate supported modes
EVT_IDD_CX_MONITOR_GET_DEFAULT_DESCRIPTION_MODES
VirtualDisplayDriverMonitorGetDefaultModes;
EVT_IDD_CX_MONITOR_QUERY_TARGET_MODES
VirtualDisplayDriverMonitorQueryModes;
EVT_IDD_CX_MONITOR_QUERY_TARGET_MODES2
VirtualDisplayDriverEvtIddCxMonitorQueryTargetModes2;
// Assign swapchain to monitor
EVT_IDD_CX_MONITOR_ASSIGN_SWAPCHAIN
VirtualDisplayDriverMonitorAssignSwapChain;
// Remove swapchain from monitor
EVT_IDD_CX_MONITOR_UNASSIGN_SWAPCHAIN
VirtualDisplayDriverMonitorUnassignSwapChain;
// Set HDR metadata (IddCx 1.10)
EVT_IDD_CX_MONITOR_SET_DEFAULT_HDR_METADATA
VirtualDisplayDriverEvtIddCxMonitorSetDefaultHdrMetadata;
// Set gamma ramp (IddCx 1.10)
EVT_IDD_CX_MONITOR_SET_GAMMA_RAMP
VirtualDisplayDriverEvtIddCxMonitorSetGammaRamp;
Configuration System
Multi-Source Configuration
The driver supports configuration from multiple sources with priority:
Settings Query System
Implements a unified settings query interface:
std ::map < std ::wstring, std ::pair < std ::wstring, std ::wstring >>
SettingsQueryMap = {
{ L"LoggingEnabled" , { L"LOGS" , L"logging" }},
{ L"HDRPlusEnabled" , { L"HDRPLUS" , L"HDRPlus" }},
{ L"CustomEdidEnabled" , { L"CUSTOMEDID" , L"CustomEdid" }},
// ... 50+ settings
};
// Query functions
bool EnabledQuery ( const std :: wstring & settingKey );
int GetIntegerSetting ( const std :: wstring & settingKey );
std :: wstring GetStringSetting ( const std :: wstring & settingKey );
double GetDoubleSetting ( const std :: wstring & settingKey );
Settings are queried first from registry (HKLM\SOFTWARE\MikeTheTech\VirtualDisplayDriver), then from C:\VirtualDisplayDriver\vdd_settings.xml if not found.
Configuration Categories
Display Settings
Color Settings
HDR Settings
Cursor Settings
UINT numVirtualDisplays; // Number of monitors (1-5)
vector < tuple < int , int , int , int >> monitorModes; // Resolutions
bool customEdid; // Use custom EDID
bool HDRPlus; // 12-bit HDR
bool SDR10; // 10-bit SDR
IDDCX_BITS_PER_COMPONENT SDRCOLOUR; // SDR bit depth
IDDCX_BITS_PER_COMPONENT HDRCOLOUR; // HDR bit depth
wstring ColourFormat; // RGB format
bool hdr10StaticMetadataEnabled;
double maxDisplayMasteringLuminance; // Max nits
double minDisplayMasteringLuminance; // Min nits
int maxContentLightLevel; // MaxCLL
int maxFrameAvgLightLevel; // MaxFALL
bool hardwareCursor; // HW cursor support
bool alphaCursorSupport; // Alpha blending
int CursorMaxX; // Max width (128)
int CursorMaxY; // Max height (128)
IDDCX_XOR_CURSOR_SUPPORT XorCursorSupportLevel;
EDID Integration
EDID Profile Structure
The driver supports loading EDID profiles from XML:
struct EdidProfileData {
vector < tuple < int , int , int , int >> modes; // Resolutions
bool hdr10Supported;
bool dolbyVisionSupported;
bool hdr10PlusSupported;
double maxLuminance;
double minLuminance;
wstring primaryColorSpace; // sRGB, DCI-P3, Rec.2020
double gamma; // Gamma correction
double redX, redY; // Color primaries
double greenX, greenY;
double blueX, blueY;
double whiteX, whiteY;
int preferredWidth, preferredHeight;
double preferredRefresh;
};
EDID Loading Pipeline
Load XML Profile
Parse EDID profile from C:\VirtualDisplayDriver\EDID\monitor_profile.xml
Extract Capabilities
Read supported modes, color primaries, HDR capabilities, and preferred mode
Convert Metadata
Transform EDID data to SMPTE ST.2086 format for HDR
Generate EDID Block
Create binary EDID structure for monitor identification
Apply to Monitor
Provide EDID to IddCxMonitorCreate() during monitor creation
The driver converts EDID color data to SMPTE ST.2086 format:
// Convert EDID chromaticity (0.0-1.0) to SMPTE (0-50000)
UINT16 ConvertChromaticityToSmpte ( double edidValue ) {
if (edidValue < 0.0 ) edidValue = 0.0 ;
if (edidValue > 1.0 ) edidValue = 1.0 ;
return static_cast < UINT16 > (edidValue * 50000.0 );
}
// Convert luminance (nits) to SMPTE (0.0001 cd/m² units)
UINT32 ConvertLuminanceToSmpte ( double nits ) {
if (nits < 0.0001 ) nits = 0.0001 ;
if (nits > 10000.0 ) nits = 10000.0 ;
return static_cast < UINT32 > (nits * 10000.0 );
}
VddHdrMetadata ConvertEdidToSmpteMetadata ( const EdidProfileData & profile );
Multi-GPU Support
GPU Selection
The driver supports targeting specific GPUs via LUID (Locally Unique Identifier):
struct Direct3DDevice {
LUID AdapterLuid; // Identifies the target GPU
Direct3DDevice ( LUID AdapterLuid );
HRESULT Init ();
};
// Select GPU by LUID
std ::shared_ptr < Direct3DDevice >
GetOrCreateDevice (LUID RenderAdapter);
The driver can assign different virtual monitors to different GPUs, enabling advanced multi-GPU configurations.
LUID-based Adapter Selection
struct AdapterOption {
wstring gpuName; // Friendly name
LUID adapterLuid; // PCI bus-based identifier
int pciBusNumber; // PCI slot location
};
Logging and Diagnostics
Logging System
The driver implements a flexible logging system:
void vddlog ( const char* type , const char* message );
// Log levels
vddlog ( "i" , "Information message" );
vddlog ( "w" , "Warning message" );
vddlog ( "e" , "Error message" );
vddlog ( "d" , "Debug message" );
Named Pipe Communication
Logs can be sent through a named pipe for external monitoring:
#define PIPE_NAME L" \\\\ . \\ pipe \\ MTTVirtualDisplayPipe"
HANDLE g_pipeHandle = INVALID_HANDLE_VALUE;
bool sendLogsThroughPipe = true ;
Enable pipe logging in vdd_settings.xml to monitor driver activity in real-time from external applications.
Device Caching
Shares D3D devices across monitors using the same GPU:
static std ::map < LUID, std ::shared_ptr < Direct3DDevice > ,
LuidComparator > s_DeviceCache;
static std ::mutex s_DeviceCacheMutex;
static void CleanupExpiredDevices ();
Thread Management
Dedicated swapchain processing threads:
class SwapChainProcessor {
Microsoft :: WRL :: Wrappers ::Thread m_hThread;
Microsoft :: WRL :: Wrappers ::Event m_hTerminateEvent;
static DWORD CALLBACK RunThread (LPVOID Argument);
};
Memory Management
Smart pointers (std::unique_ptr, std::shared_ptr) for automatic cleanup
COM smart pointers (Microsoft::WRL::ComPtr) for D3D resources
Static caches with mutex protection for thread safety
Data Flow
Security Considerations
User-Mode Execution Runs in Session 0 user mode, not kernel mode, limiting potential damage from crashes
Driver Signing Signed by SignPath Foundation for Windows driver signature enforcement
Limited Privileges UMDF drivers have restricted access compared to kernel drivers
Isolated Crashes Driver failures won’t cause system Blue Screen of Death (BSOD)
File Structure
Virtual Display Driver (HDR)/
├── MttVDD/
│ ├── Driver.cpp # Main driver implementation (170KB)
│ ├── Driver.h # Driver headers and declarations
│ ├── MttVDD.inf # Driver installation file
│ ├── Trace.h # Tracing and diagnostics
│ └── MttVDD.vcxproj # Visual Studio project
├── GetIddCx/
│ └── IddCxVersionQuery.cpp # IddCx version detection utility
├── EDID/
│ └── [EDID profile files]
└── Common/
└── Include/
└── AdapterOption.h # GPU adapter definitions
Next Steps
Virtual Displays Learn about virtual display capabilities and use cases
IddCx Framework Understand the IddCx framework versions and features
Configuration Configure driver settings and parameters
Development Build the driver from source code