Multi Monitor Display and Video mini port Driver Development
Introduction
This document describes the implementation of display and video mini-port driver for multi-monitor support on Windows XP and 2K3 Operating Systems. This paper evolved from our experience with the Multi-monitor project.
Implementation details with required setup information
The Multi-monitor project mainly involved the development of the display driver and the video mini-port driver modules.
Driver development for a Multi Monitor driver on windows XP, 2K3 requires the following Operating System and Tools.
Requirements for development
- Operating system (windows XP or 2003)
- Software and tools
- Driver Development Kit for XP and windows 2003
- Platform SDK for XP and windows 2003
- VC++ 6.0 Service pack 5
Architecture

The shaded elements in the preceding figure represent services that are supplied with Windows 2000 and later. The unshaded elements indicate that a display driver and video miniport driver are required in order for a graphics adapter to display in the Windows 2000 and later systems.
For every type of graphics card that can be used with an NT-based operating system, there must be both a display driver and a corresponding video miniport driver. The miniport driver is written specifically for one graphics adapter (or family of adapters). The display driver can be written for any number of adapters that share a common drawing interface; for example, the VGA display driver can be used with either the VGA or a miniport driver. This is because the display driver draws, while the miniport driver performs operations such as mode sets and provides information about the hardware to the driver. It is also possible for more than one display driver to work with a particular miniport driver; for example, the 16- and 256-color SVGA display drivers can use the same miniport driver.
How does it work
The Multi Monitor implementation mainly consists of two major modules. They are:
Display Driver
- A display driver is a kernel-mode DLL whose primary responsibility is rendering. When an application calls a Win32 function with device-independent graphics requests, the Graphics Device Interface (GDI) interprets these instructions and calls the display driver. The display driver then translates these requests into commands for the video hardware to draw graphics on the screen.
The display driver can access the hardware directly. This is because there is a wide variety in graphics hardware capabilities, and because display is one of the most time-critical parts of any system. This accessibility and the wide scope of capabilities within GDI provide considerable flexibility when implementing a display driver. - By default, GDI handles drawing operations on standard format bitmaps, such as on hardware that includes a frame buffer. A display driver can hook and implement any of the drawing functions for which the hardware offers special support. For less time-critical operations and more complex operations not supported by the graphics adapter, the driver can punt functions back to GDI and allow GDI to do the work.
- For especially time-critical operations, the display driver has direct access to video hardware registers. For example, the VGA display driver for x86 systems uses optimized assembly code to implement direct access to hardware registers for some drawing and text operations.
Video Miniport driver
The video miniport driver generally handles operations that must interact with other NT kernel components. For example, operations such as hardware initialization and memory mapping require action by the NT I/O subsystem. Video miniport driver responsibilities include resource management, such as hardware configuration, and physical device memory mapping. The video miniport driver must be specific to the video hardware.
The display driver uses the video miniport driver for operations that are not frequently requested; for example, to manage resources, perform physical device memory mapping, ensure that register outputs occur in close proximity, or respond to interrupts.
Note: The video miniport driver must manage all resources (for example, memory resources) shared between the video miniport driver and the display driver. The system does not guarantee that resources acquired in the display driver will always be accessible to the video miniport driver.
The video miniport driver also handles:
- Mode set interaction with the graphics card
- Multiple hardware types, minimizing hardware-type dependency in the display driver
- Mapping the video register into the display driver's address space. I/O ports are directly addressable
Accessing the graphics adapter
To ensure display performance, display drivers can access the graphics card in the following ways:
- Indirectly-by sending IOCTLs to the video miniport driver of the graphics adapter.
- Directly-by reading and writing to video memory (the frame buffer) or hardware registers.
Display Driver/Video Miniport Driver communication
Communicating IOCTLs to the Video Miniport Driver:
The following figure shows how the display driver communicates with the video miniport driver using IOCTLs.

The display driver calls EngDeviceIoControl with an IOCTL to send a synchronous request to the video miniport driver. GDI uses a single buffer for both input and output to pass the request to the I/O subsystem. The I/O subsystem routes the request to the video port, which processes the request with the video miniport driver.
Some IOCTL requests require the miniport driver to access video registers, and others store or retrieve information from the miniport driver's data structures. Generally, no requests require the video miniport driver to perform actual drawing operations.
In general, and unless modularity dictates otherwise, the display driver handles drawing and other time-critical operations. Sending an IOCTL to the miniport driver to perform a time-critical function can degrade system performance.
Accessing the Frame Buffer and Hardware Registers:
There are several ways to reduce display driver size. For example, you can implement only those functions that the display driver can perform faster than GDI, and then specify GDI to perform all other operations. GDI often performs a substantial amount of the drawing to linear frame buffers to reduce the size of the driver. GDI cannot access banked memory directly; therefore, when the frame buffer is not linearly addressable, the display driver must divide the frame buffer into a series of banks and provide a means for GDI to perform its draw operations to the appropriate bank.
The display driver has direct access to I/O-mapped and memory-mapped video registers. This access allows a display driver to achieve high performance. For example, the driver might need to access video hardware registers to send line-drawing commands at high throughput.
Display Driver implimentation
Following is the minimal list of APIs for the Display Driver that has to be implemented. The other DDI functions can be implemented depending on the features supported by the adapter and performance requirements.
DrvEnableDriver()
This is the first function in the display driver to be called by the windows. On receiving this function, the driver version and function pointers for the functions for which GDI hooking is done are reported by the driver to the GDI. The function pointer ordinals are as per the DDK header files. The DRVENABLEDATA should have,
- iDriverVersion at least DDI_DRIVER_VERSION_NT5
- no of drvFn members pointed by the pdrvfn member
- function pointers and their ordinals as declared in the winddi.h
DrvDisableDriver()
This is the last function in the display driver to be called. On receiving this, the Display driver should free up any allocated resources so that it can be unloaded.
DrvEnablePDEV()
This function is called by windows GDI, when it wants to query the device characteristics of the display device. When receiving this call, the display driver should
- GDIINFO structure should be filled as per the DDK documentation
- Fill the DEVINFO structure as per the DDK documentation
- Save the GDI handle hdev coming as input in some private DEVMODE variables
- save the device name pwszDeviceName and display device handle hDriver. return a PDEV value to our private device information structure (similar to the DEVICE_EXTENSION)
DrvDisablePDEV()
This function is called to disable the PDEV object created in the DrvEnablePDEV(). When this function is called, free up any resources allocated during the DrvEnablePDEV().
DrvEnableSurface()
This function is called to create a surface to be used for the drawing operations. Here there can be two methods which can be used to perform the drawing operations.
- Call the EngCreateDeviceSurface() to perform the drawing operations - driver managed surface
- Call the EngModifySurface() to perform some of the drawing operations, if required - device managed surface
DrvDisableSurface()
This function is used to free up any surface specific resources allocated since the DrvEnableSurface(). At least a call to EngDeleteSurface() will be required to delete the surface object created during DrvEnableSurface().
DrvGetModes()
This function is used to enumerate the device modes supported by the display device.
DrvAssertMode()
The logic will depend on the bEnable parameter. If bEnable is true, the display driver should check the dhpdev parameter to see whether it is valid for the device and if so, it can succeed the function. Otherwise, fill with the default values for the dhpdev parameter.
DrvCompletePDEV()
Save the handle so that it can be used in future for calling the GDI functions. This handle is used when calling the EngXXX() functions.
DDI Hook functions:
The display driver will need to use the DDI hook functions to write to display device if it is not using the display memory or display device has features which can be used without the help of GDI.
- DrvCopyBits() - This will be required for write to the display device in case of the video memory map is not available in the display device.
- DrvBitBlt() - This may be required to write the DIB content to the VGA device.
Some more functions may similarly be required depending on the device capabilities and device resource management approach.
Video Miniport Driver implimentation
Following is the list of APIs for Video Mini-port Driver has to be implemented. Functions to be implemented:
DriverEntry()
Initialize the driver extension variables. If required, allocate any resources required.
FindAdapter()
Detect the adapters present in the system with the help of PnP and IO managers. Based upon them, enumerate the displays present in the system. For each device detected, Get a handle/device instance information about them. If the device has any resources, acquire them.
GetPowerState()
If the display device supports the requested power state return power state information. Otherwise, return the error.
GetVideoChildDescriptor()
If we are supporting any monitor configuration, we can provide some information here. Otherwise, we can simply report the child device type as Monitor.
Initialize()
The initialize function can perform any adapter specific initialization. It depends on the video adapter.
SetPowerState()
This is to set the power state of the monitor or the adapter. Based upon the received flags, we should send corresponding command to the adapter to perform the power management operations.
StartIo()
Once the adapter has been initialized, StartIO() is the function called by the video port driver and display driver to perform all the display specific operations. Much of the functionalities supported by the StartIo() include supporting of various video device I/O control codes and supporting the VRP(video request packets). VRPs are similar to IRPs in WDM drivers and is passed by the video port driver to transfer information to/from the video miniport driver.

