Professional Documents
Culture Documents
Driver Development Part 6 - Introduction To Display Drivers - CodeProject PDF
Driver Development Part 6 - Introduction To Display Drivers - CodeProject PDF
Driver Development Part 6 - Introduction To Display Drivers - CodeProject PDF
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
Sign in
home
articles
quick answers
discussions
features
community
help
Searchforarticles,questions,tips
Articles Platforms, Frameworks & Libraries Win32/64 SDK & OS Windows General
Rate this:
4.94 79 votes
Introduction
It has been a while since I have updated this series and I have found some free time to write the next version. In
this article, we will take a look at how to write a simple display driver. A display driver is a special type of driver
which fits into a framework that is unlike what we have talked about so far in this series.
The example driver for this article will show how to write a basic display driver which does not have any hardware
associated with it. Instead this display driver will implement graphics to memory and an application will be used
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
1/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
to display those graphics. This method was demonstrated in an article I wrote for the C/C++ User's Journal
however that article was about extending VMWare to support multiple monitors. This article will only be focusing
on display drivers themselves and will not use VMWare but require just your local machine.
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
2/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
3/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
The documentation specifies that you should only use the "VideoPort" APIs in a miniport however since this is
also just a regular system level driver you can still link against any kernel API you wish and I have done this
before. This is not the case with the display driver itself as we will see later.
Since we do not have any hardware our miniport driver will be pretty thin and easy. The following code shows
how the video miniport DriverEntry is constructed:
Hide Shrink
Copy Code
/**********************************************************************
*
*DriverEntry
*
*Thisistheentrypointforthisvideominiportdriver
*
**********************************************************************/
ULONGDriverEntry(PVOIDpContext1,PVOIDpContext2)
{
VIDEO_HW_INITIALIZATION_DATAhwInitData;
VP_STATUSvpStatus;
/*
*TheVideoMiniportis"technically"restrictedtocalling
*"Video*"APIs.
*Thereisadriverthatencapsulatesthisdriverbysettingyour
*driver'sentrypointstolocationsinitself.Itwillthen
*handleyourIRP'sforyouanddeterminewhichoftheentry
*points(providedbelow)intoyourdriverthatshouldbecalled.
*Thisdriverhoweverdoesruninthecontextofsystemmemory
*unliketheGDIcomponent.
*/
VideoPortZeroMemory(&hwInitData,
sizeof(VIDEO_HW_INITIALIZATION_DATA));
hwInitData.HwInitDataSize=sizeof(VIDEO_HW_INITIALIZATION_DATA);
hwInitData.HwFindAdapter=FakeGfxCard_FindAdapter;
hwInitData.HwInitialize=FakeGfxCard_Initialize;
hwInitData.HwStartIO=FakeGfxCard_StartIO;
hwInitData.HwResetHw=FakeGfxCard_ResetHW;
hwInitData.HwInterrupt=FakeGfxCard_VidInterrupt;
hwInitData.HwGetPowerState=FakeGfxCard_GetPowerState;
hwInitData.HwSetPowerState=FakeGfxCard_SetPowerState;
hwInitData.HwGetVideoChildDescriptor=
FakeGfxCard_GetChildDescriptor;
vpStatus=VideoPortInitialize(pContext1,
pContext2,&hwInitData,NULL);
returnvpStatus;
}
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
4/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
I mentioned before you simply pass the DriverObject directly through to the VideoPrt.SYS driver as shown
above. You also fill in a data structure which contains entries into your driver which the VideoPrt.SYS driver will
call to perform various actions. The "HwStartIO" is where you would handle IOCTLs and you can use IOCTLs
between the display driver and the Video Miniport. The display driver would simply call "EngDeviceIoControl"
and this IOCTL will be handled in the miniport's HwStartIO.
The following shows how I have implemented the video miniport functions:
Hide Shrink
Copy Code
/*#pragmaalloc_text(PAGE,FakeGfxCard_ResetHW)CannotbePaged*/
/*#pragmaalloc_text(PAGE,FakeGfxCard_VidInterrupt)CannotbePaged*/
#pragmaalloc_text(PAGE,FakeGfxCard_GetPowerState)
#pragmaalloc_text(PAGE,FakeGfxCard_SetPowerState)
#pragmaalloc_text(PAGE,FakeGfxCard_GetChildDescriptor)
#pragmaalloc_text(PAGE,FakeGfxCard_FindAdapter)
#pragmaalloc_text(PAGE,FakeGfxCard_Initialize)
#pragmaalloc_text(PAGE,FakeGfxCard_StartIO)
/**********************************************************************
*
*FakeGfxCard_ResetHW
*
*Thisroutinewouldresetthehardwarewhenasoftrebootis
*performed.ReturningFALSEfromthisroutinewouldforce
*theHALtoperformanINT10handsetMode3(Text).
*
*WearenotrealhardwaresowewilljustreturnTRUEsotheHAL
*doesnothing.
Article
*
**********************************************************************/
Browse Code
BOOLEANFakeGfxCard_ResetHW(PVOIDHwDeviceExtension,
ULONGColumns,ULONGRows)
Stats
{
returnTRUE;
Revisions
}
/**********************************************************************
Alternatives
*
*FakeGfxCard_VidInterrupt
Comments 118
*
*Checksifit'sadaptergeneratedaninterruptanddismissesit
*orreturnsFALSEifitdidnot.
*
Tagged as
**********************************************************************/
BOOLEANFakeGfxCard_VidInterrupt(PVOIDHwDeviceExtension)
Win2K
{
returnFALSE;
WinXP
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
5/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
}
Win2003
/**********************************************************************
Vista
*
*FakeGfxCard_GetPowerState
C++
*
*Queriesifthedevicecansupporttherequestedpowerstate.
C
*
VisualStudio
**********************************************************************/
VP_STATUSFakeGfxCard_GetPowerState(PVOIDHwDeviceExtension,
Dev
ULONGHwId,PVIDEO_POWER_MANAGEMENTVideoPowerControl)
ASM
{
returnNO_ERROR;
Intermediate
}
Virtualization
/**********************************************************************
*
*FakeGfxCard_SetPowerState
*
*Setsthepowerstate.
*
**********************************************************************/
Related Articles
VP_STATUSFakeGfxCard_SetPowerState(PVOIDHwDeviceExtension,
ULONGHwId,PVIDEO_POWER_MANAGEMENTVideoPowerControl)
Driver Development
{
Part 1: Introduction
returnNO_ERROR;
to Drivers
}
/**********************************************************************
File System Filter
*
Driver Tutorial
*FakeGfxCard_GetChildDescriptor
*
A simple demo for
*Returnsanidentiferforanychilddevicesupported
WDM Driver
*bytheminiport.
*
development
**********************************************************************/
Raw Ethernet Packet
ULONGFakeGfxCard_GetChildDescriptor(PVOIDHwDeviceExtension,
PVIDEO_CHILD_ENUM_INFOChildEnumInfo,PVIDEO_CHILD_TYPEpChildType,
Sending
PVOIDpChildDescriptor,PULONGpUId,PULONGpUnused)
Driver Wizard
{
returnERROR_NO_MORE_DEVICES;
}
/**********************************************************************
*
*FakeGfxCard_FindAdapter
*
*Thisfunctionperformsinitializationspecifictodevices
*maintainedbythisminiportdriver.
*
**********************************************************************/
VP_STATUSFakeGfxCard_FindAdapter(PVOIDHwDeviceExtension,
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
6/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
PVOIDHwContext,PWSTRArgumentString,
PVIDEO_PORT_CONFIG_INFOConfigInfo,PUCHARAgain)
{
returnNO_ERROR;
}
/**********************************************************************
*
*FakeGfxCard_Initialize
*
*Thisinitializesthedevice.
*
**********************************************************************/
BOOLEANFakeGfxCard_Initialize(PVOIDHwDeviceExtension)
{
returnTRUE;
}
/**********************************************************************
*
*FakeGfxCard_StartIO
*
*ThisroutineexecutesrequestsonbehalfoftheGDIDriver
*andthesystem.TheGDIdriverisallowedtoissueIOCTLs
*whichwouldthenbesenttothisroutinetobeperformed
*onit'sbehalf.
*
*WecanaddourownproprietaryIOCTLsheretobeprocessed
*fromtheGDIdriver.
*
**********************************************************************/
BOOLEANFakeGfxCard_StartIO(PVOIDHwDeviceExtension,
PVIDEO_REQUEST_PACKETRequestPacket)
{
RequestPacket>StatusBlock>Status=0;
RequestPacket>StatusBlock>Information=0;
returnTRUE;
}
Since I don't have any hardware I simply implement enough of a miniport to make the system happy. The only
possible API I would intend to use would be "StartIO" if I needed to access or perform an operation on the
system that the display driver is not capable of doing with its limited API set. However in this implementation
there is nothing we need done. Remember, the main purpose of the miniport is to enumerate hardware
devices/resources and manage them. If you don't have any then that removes everything but the necessary to
keep the driver model happy.
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
7/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
8/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
DrvEnableDriver
This is the initial entry point for a display driver and it is not related to DriverEntry in any way. This API passes
in a DRVENABLEDATA structure which is to be filled in with a table of functions which are the entries to the driver.
The table contains a list which is an index value followed by the function pointer. The index value specifies the
function type such as "INDEX_DrvCompletePDEV" which specifies that the function pointer is a pointer to the
DrvCompletePDEV handler in the driver. Some APIs are optional and some are required.
This entry point is simply responsible for returning the list of your functions. You may also do any initialization
you may need to do here. The following is the code from the sample display driver in this article:
Hide Shrink
Copy Code
/*
*DisplayDriversprovidealistoffunctionentrypointsforspecificGDI
*tasks.Theseareidentifiedbyprovidingapredefined"INDEX"value(pre
*defined
*bymicrosoft)followedbythefunctionentrypoint.Therearelevelsof
*flexibility
*onwhichonesyouareREQUIREDandwhichonesaretechnicallyOPTIONAL.
*
*/
DRVFNg_DrvFunctions[]=
{
{INDEX_DrvAssertMode,(PFN)GdiExample_DrvAssertMode},
{INDEX_DrvCompletePDEV,(PFN)GdiExample_DrvCompletePDEV},
{INDEX_DrvCreateDeviceBitmap,(PFN)GdiExample_DrvCreateDeviceBitmap},
{INDEX_DrvDeleteDeviceBitmap,(PFN)GdiExample_DrvDeleteDeviceBitmap},
{INDEX_DrvDestroyFont,(PFN)GdiExample_DrvDestroyFont},
{INDEX_DrvDisablePDEV,(PFN)GdiExample_DrvDisablePDEV},
{INDEX_DrvDisableDriver,(PFN)GdiExample_DrvDisableDriver},
{INDEX_DrvDisableSurface,(PFN)GdiExample_DrvDisableSurface},
{INDEX_DrvSaveScreenBits,(PFN)GdiExample_DrvSaveScreenBits},
{INDEX_DrvEnablePDEV,(PFN)GdiExample_DrvEnablePDEV},
{INDEX_DrvEnableSurface,(PFN)GdiExample_DrvEnableSurface},
{INDEX_DrvEscape,(PFN)GdiExample_DrvEscape},
{INDEX_DrvGetModes,(PFN)GdiExample_DrvGetModes},
{INDEX_DrvMovePointer,(PFN)GdiExample_DrvMovePointer},
{INDEX_DrvNotify,(PFN)GdiExample_DrvNotify},
//{INDEX_DrvRealizeBrush,(PFN)GdiExample_DrvRealizeBrush},
{INDEX_DrvResetPDEV,(PFN)GdiExample_DrvResetPDEV},
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
9/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
{INDEX_DrvSetPalette,(PFN)GdiExample_DrvSetPalette},
{INDEX_DrvSetPointerShape,(PFN)GdiExample_DrvSetPointerShape},
{INDEX_DrvStretchBlt,(PFN)GdiExample_DrvStretchBlt},
{INDEX_DrvSynchronizeSurface,(PFN)GdiExample_DrvSynchronizeSurface},
{INDEX_DrvAlphaBlend,(PFN)GdiExample_DrvAlphaBlend},
{INDEX_DrvBitBlt,(PFN)GdiExample_DrvBitBlt},
{INDEX_DrvCopyBits,(PFN)GdiExample_DrvCopyBits},
{INDEX_DrvFillPath,(PFN)GdiExample_DrvFillPath},
{INDEX_DrvGradientFill,(PFN)GdiExample_DrvGradientFill},
{INDEX_DrvLineTo,(PFN)GdiExample_DrvLineTo},
{INDEX_DrvStrokePath,(PFN)GdiExample_DrvStrokePath},
{INDEX_DrvTextOut,(PFN)GdiExample_DrvTextOut},
{INDEX_DrvTransparentBlt,(PFN)GdiExample_DrvTransparentBlt},
};
ULONGg_ulNumberOfFunctions=sizeof(g_DrvFunctions)/sizeof(DRVFN);
/*********************************************************************
*DrvEnableDriver
*
*Thisistheinitialdriverentrypoint.Thisisthe"DriverEntry"
*equivlentforDisplayandPrinterdrivers.Thisfunctionmust
*returnafunctiontablethatrepresentsallthesupportedentry
*pointsintothisdriver.
*
*********************************************************************/
BOOLDrvEnableDriver(ULONGulEngineVersion,
ULONGulDataSize,DRVENABLEDATA*pDrvEnableData)
{
BOOLbDriverEnabled=FALSE;
/*
*Weonlywanttosupportversions>NT4
*
*/
if(HIWORD(ulEngineVersion)>=0x3&&
ulDataSize>=sizeof(DRVENABLEDATA))
{
pDrvEnableData>iDriverVersion=DDI_DRIVER_VERSION;
pDrvEnableData>pdrvfn=g_DrvFunctions;
pDrvEnableData>c=g_ulNumberOfFunctions;
bDriverEnabled=TRUE;
}
returnbDriverEnabled;
}
DrvDisableDriver
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
10/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
This function handler is called when the display driver is being unloaded. In this handler you can perform any
clean up necessary for what you have created in the DrvEnableDriver call. The following code is from the
sample driver:
Hide Copy Code
/*********************************************************************
*GdiExample_DrvDisableDriver
*
*Thisfunctionisusedtonotifythedriverwhenthedriveris
*gettingreadytobeunloaded.
*
*********************************************************************/
VOIDGdiExample_DrvDisableDriver(VOID)
{
/*
*NoCleanupToDo
*/
}
DrvGetModes
The API called after the driver is loaded and enabled is DrvGetModes. This API is used to query the modes
supported by the device. These modes are used to populate the "Settings" tab in the "Display Properties" dialog.
The modes can be cached so the operating system does not think of them as being dynamic and changing. The
operating system believes this to be a static list and while there are times and ways that this API may be called
more than once for the most part it should not be considered dynamic.
The API is generally called twice the first time it simply asks for the size required to store the modes and the
second time it calls with the correct size. The following code fragment is from the sample driver which only
supports 640x480x32:
Hide Shrink
Copy Code
/*********************************************************************
*GdiExample_DrvGetModes
*
*ThisAPIisusedtoenumeratedisplaymodes.
*
*Thisdriveronlysupports640x480x32
*
*********************************************************************/
ULONGGdiExample_DrvGetModes(HANDLEhDriver,
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
11/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
ULONGcjSize,DEVMODEW*pdm)
{
ULONGulBytesWritten=0,ulBytesNeeded=sizeof(DEVMODEW);
ULONGulReturnValue;
ENGDEBUGPRINT(0,"GdiExample_DrvGetModes\r\n",NULL);
if(pdm==NULL)
{
ulReturnValue=ulBytesNeeded;
}
else
{
ulBytesWritten=sizeof(DEVMODEW);
memset(pdm,0,sizeof(DEVMODEW));
memcpy(pdm>dmDeviceName,DLL_NAME,sizeof(DLL_NAME));
pdm>dmSpecVersion=DM_SPECVERSION;
pdm>dmDriverVersion=DM_SPECVERSION;
pdm>dmDriverExtra=0;
pdm>dmSize=sizeof(DEVMODEW);
pdm>dmBitsPerPel=32;
pdm>dmPelsWidth=640;
pdm>dmPelsHeight=480;
pdm>dmDisplayFrequency=75;
pdm>dmDisplayFlags=0;
pdm>dmPanningWidth=pdm>dmPelsWidth;
pdm>dmPanningHeight=pdm>dmPelsHeight;
pdm>dmFields=DM_BITSPERPEL|DM_PELSWIDTH|
DM_PELSHEIGHT|DM_DISPLAYFLAGS|
DM_DISPLAYFREQUENCY;
ulReturnValue=ulBytesWritten;
}
returnulReturnValue;
}
DrvEnablePDEV
Once a mode is chosen this API is then called which will allow the driver to enable the "physical device". The
purpose of this API is to allow the display driver to create its own private context which will be passed into the
other display entry points. The reason for this private context is that a single display driver may handle multiple
display devices and as such would need to distinguish one display device from another. The return value for this
API is a pointer to the context or instance of the supplied display device.
The selected display setting is passed into this API via the DEVMODE parameter however the sample driver does
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
12/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
not use this method since it's hard coded to setup 800x600x32 mode only.
This API aside from creating an instance structure must also initialize the GDIINFO and DEVINFO data structures
at a minimum. These parameters are important as if you fill in supporting a certain feature and you really do not
you can have graphic corruption as a side effect or even blue screen. The next two parameters that I will mention
are the hDev and hDriver parameters. The hDriver parameter is actually the DEVICE_OBJECT for the display
driver and can be used with APIs such as EngDeviceIoControl to communicate with the miniport driver.
The hDev is the handle to GDI however since the device is in the process of being created it is actually useless. It
is recommended that you wait until the DrvCompletePDEV call before saving and using this handle. The
following code is from the sample driver's DrvEnablePDEV:
Hide Shrink
Copy Code
/*********************************************************************
*GdiExample_DrvEnablePDEV
*
*ThisfunctionwillprovideadescriptionofthePhysicalDevice.
*Thedatareturnedisauserdefineddatacontexttobeusedasa
*handleforthisdisplaydevice.
*
*ThehDriverisahandletotheminiportdriverassociatedwith
*thisdisplaydevice.Thishandlecanbeusedtocommunicateto
*theminiportthroughAPIstosendthingslikeIOCTLs.
*
*********************************************************************/
DHPDEVGdiExample_DrvEnablePDEV(DEVMODEW*pdm,PWSTRpwszLogAddr,
ULONGcPat,HSURF*phsurfPatterns,ULONGcjCaps,
GDIINFO*pGdiInfo,ULONGcjDevInfo,DEVINFO*pDevInfo,
HDEVhdev,PWSTRpwszDeviceName,HANDLEhDriver)
{
PDEVICE_DATApDeviceData=NULL;
ENGDEBUGPRINT(0,"GdiExample_DrvEnablePDEVEnter\r\n",NULL);
pDeviceData=(PDEVICE_DATA)EngAllocMem(0,
sizeof(DEVICE_DATA),FAKE_GFX_TAG);
if(pDeviceData)
{
memset(pDeviceData,0,sizeof(DEVICE_DATA));
memset(pGdiInfo,0,cjCaps);
memset(pDevInfo,0,cjDevInfo);
{
pGdiInfo>ulVersion=0x5000;
pGdiInfo>ulTechnology=DT_RASDISPLAY;
pGdiInfo>ulHorzSize=0;
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
13/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
pGdiInfo>ulVertSize=0;
pGdiInfo>ulHorzRes=RESOLUTION_X;
pGdiInfo>ulVertRes=RESOLUTION_Y;
pGdiInfo>ulPanningHorzRes=0;
pGdiInfo>ulPanningVertRes=0;
pGdiInfo>cBitsPixel=8;
pGdiInfo>cPlanes=4;
pGdiInfo>ulNumColors=20;
pGdiInfo>ulVRefresh=1;
pGdiInfo>ulBltAlignment=1;
pGdiInfo>ulLogPixelsX=96;
pGdiInfo>ulLogPixelsY=96;
pGdiInfo>flTextCaps=TC_RA_ABLE;
pGdiInfo>flRaster=0;
pGdiInfo>ulDACRed=8;
pGdiInfo>ulDACGreen=8;
pGdiInfo>ulDACBlue=8;
pGdiInfo>ulAspectX=0x24;
pGdiInfo>ulNumPalReg=256;
pGdiInfo>ulAspectY=0x24;
pGdiInfo>ulAspectXY=0x33;
pGdiInfo>xStyleStep=1;
pGdiInfo>yStyleStep=1;
pGdiInfo>denStyleStep=3;
pGdiInfo>ptlPhysOffset.x=0;
pGdiInfo>ptlPhysOffset.y=0;
pGdiInfo>szlPhysSize.cx=0;
pGdiInfo>szlPhysSize.cy=0;
pGdiInfo>ciDevice.Red.x=6700;
pGdiInfo>ciDevice.Red.y=3300;
pGdiInfo>ciDevice.Red.Y=0;
pGdiInfo>ciDevice.Green.x=2100;
pGdiInfo>ciDevice.Green.y=7100;
pGdiInfo>ciDevice.Green.Y=0;
pGdiInfo>ciDevice.Blue.x=1400;
pGdiInfo>ciDevice.Blue.y=800;
pGdiInfo>ciDevice.Blue.Y=0;
pGdiInfo>ciDevice.AlignmentWhite.x=3127;
pGdiInfo>ciDevice.AlignmentWhite.y=3290;
pGdiInfo>ciDevice.AlignmentWhite.Y=0;
pGdiInfo>ciDevice.RedGamma=20000;
pGdiInfo>ciDevice.GreenGamma=20000;
pGdiInfo>ciDevice.BlueGamma=20000;
pGdiInfo>ciDevice.Cyan.x=1750;
pGdiInfo>ciDevice.Cyan.y=3950;
pGdiInfo>ciDevice.Cyan.Y=0;
pGdiInfo>ciDevice.Magenta.x=4050;
pGdiInfo>ciDevice.Magenta.y=2050;
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
14/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
pGdiInfo>ciDevice.Magenta.Y=0;
pGdiInfo>ciDevice.Yellow.x=4400;
pGdiInfo>ciDevice.Yellow.y=5200;
pGdiInfo>ciDevice.Yellow.Y=0;
pGdiInfo>ciDevice.MagentaInCyanDye=0;
pGdiInfo>ciDevice.YellowInCyanDye=0;
pGdiInfo>ciDevice.CyanInMagentaDye=0;
pGdiInfo>ciDevice.YellowInMagentaDye=0;
pGdiInfo>ciDevice.CyanInYellowDye=0;
pGdiInfo>ciDevice.MagentaInYellowDye=0;
pGdiInfo>ulDevicePelsDPI=0;
pGdiInfo>ulPrimaryOrder=PRIMARY_ORDER_CBA;
pGdiInfo>ulHTPatternSize=HT_PATSIZE_4x4_M;
pGdiInfo>flHTFlags=HT_FLAG_ADDITIVE_PRIMS;
pGdiInfo>ulHTOutputFormat=HT_FORMAT_32BPP;
*pDevInfo=gDevInfoFrameBuffer;
pDevInfo>iDitherFormat=BMF_32BPP;
}
pDeviceData>pVideoMemory=EngMapFile(L"\\??\\c:\\video.dat",
RESOLUTION_X*RESOLUTION_Y*4,&pDeviceData>pMappedFile);
pDeviceData>hDriver=hDriver;
pDevInfo>hpalDefault=EngCreatePalette(PAL_BITFIELDS,
0,NULL,0xFF0000,0xFF00,0xFF);
}
ENGDEBUGPRINT(0,"GdiExample_DrvEnablePDEVExit\r\n",NULL);
return(DHPDEV)pDeviceData;
}
DrvCompletePDEV
This call is made after the enable to notify the display driver that the device object is now completed. The only
parameters are the private data structure created in the enable call and the completed handle to the GDI device.
Unless you have more initialization to do you generally can just save the GDI handle and move on. The following
is the code from the sample driver:
Hide Copy Code
/*********************************************************************
*GdiExample_DrvCompletePDEV
*
*Thisiscalledtocompletetheprocessofenablingthedevice.
*
*
*********************************************************************/
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
15/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
voidGdiExample_DrvCompletePDEV(DHPDEVdhpdev,HDEVhdev)
{
PDEVICE_DATApDeviceData=(PDEVICE_DATA)dhpdev;
ENGDEBUGPRINT(0,"GdiExample_DrvCompletePDEVEnter\r\n",NULL);
pDeviceData>hdev=hdev;
ENGDEBUGPRINT(0,"GdiExample_DrvCompletePDEVExit\r\n",NULL);
}
DrvDisablePDEV
This API is called when the PDEV is no longer needed and will be destroyed. This is called after
DrvDisableSurface if there is a surface enabled. Our implementation of this API is very simple and will just
perform some clean up of what was created during the creation of the private PDEV structure:
Hide Copy Code
/*********************************************************************
*GdiExample_DrvDisablePDEV
*
*ThisiscalledtodisablethePDEVwecreated.
*
*
*********************************************************************/
voidGdiExample_DrvDisablePDEV(DHPDEVdhpdev)
{
PDEVICE_DATApDeviceData=(PDEVICE_DATA)dhpdev;
UINTdwBytesReturned=0;
ENGDEBUGPRINT(0,"GdiExample_DrvDisablePDEV\r\n",NULL);
if(pDeviceData>pMappedFile)
{
EngUnmapFile(pDeviceData>pMappedFile);
}
EngFreeMem(dhpdev);
}
DrvEnableSurface
This API is called after the PDEV has completed to ask the display driver to create a surface. Also as noted in the
comments below you have two choices when creating a surface. You can create a surface in which the display
driver will manage it or you can create one in which GDI will manage for you. The following code chose the
option of managing its own device surface.
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
16/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
The entire purpose is to define a drawing surface in which GDI will also be able to draw onto. Display drivers have
their own device surfaces and thus will generally want to manage its surface. In doing this it must describe the
surface in a way which GDI can understand and be able to draw on it. This means defining the start address and
even the pitch as display drivers do not generally have linear buffers for all modes. In our case we use the
memory mapped file we created to be our video memory:
Hide Shrink
Copy Code
/*********************************************************************
*GdiExample_DrvEnableSurface
*
*ThisAPIisusedtoenablethephysicaldevicesurface.
*
*Youhavetwochoiceshere.
*
*1.DriverManagesit'sownsurface
*EngCreateDeviceSurfaceCreatethehandle
*EngModifySurfaceLetGDIKnowabouttheobject.
*
*2.GDIManagesthesurface
*EngCreateBitmapCreateahandleinaformatthat
*GDIUnderstands
*EngAssociateSurfaceLetGDIKnowabouttheobject.
*
*
*********************************************************************/
HSURFGdiExample_DrvEnableSurface(DHPDEVdhpdev)
{
HSURFhsurf;
SIZELsizl;
PDEVICE_DATApDeviceData=(PDEVICE_DATA)dhpdev;
ENGDEBUGPRINT(0,"GdiExample_DrvEnableSurface\r\n",NULL);
pDeviceData>pDeviceSurface=
(PDEVICE_SURFACE)EngAllocMem(FL_ZERO_MEMORY,
sizeof(DEVICE_SURFACE),FAKE_GFX_TAG);
sizl.cx=800;
sizl.cy=600;
hsurf=(HSURF)EngCreateDeviceSurface(
(DHSURF)pDeviceData>pDeviceSurface,sizl,BMF_32BPP);
EngModifySurface(hsurf,pDeviceData>hdev,
HOOK_FILLPATH|HOOK_STROKEPATH|HOOK_LINETO|
HOOK_TEXTOUT|HOOK_BITBLT|HOOK_COPYBITS,
MS_NOTSYSTEMMEMORY,(DHSURF)pDeviceData>pDeviceSurface,
pDeviceData>pVideoMemory,800*4,NULL);
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
17/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
return(hsurf);
}
DrvDisableSurface
This API is called to destroy the drawing surface created in the DrvEnableSurface call. This is called before
destroying the PDEV. The following is the code from the example program:
Hide Copy Code
/*********************************************************************
*GdiExample_DrvDisableSurface
*
*ThisAPIiscalledtodisabletheGDISurface.
*
*
*********************************************************************/
voidGdiExample_DrvDisableSurface(DHPDEVdhpdev)
{
PDEVICE_DATApDeviceData=(PDEVICE_DATA)dhpdev;
ENGDEBUGPRINT(0,"GdiExample_DrvDisableSurface\r\n",NULL);
EngDeleteSurface(pDeviceData>hsurf);
pDeviceData>hsurf=NULL;
EngFreeMem(pDeviceData>pDeviceSurface);
pDeviceData>pDeviceSurface=NULL;
}
Sequencing
So, let's go through this one more time for clarity.
18/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
<GDI Calls>
19/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
provided to your driver. This allows you to easily implement extended drawing commands which can behave
correctly in the windowing environment as your driver will be informed of the proper clipping area.
OpenGL support
OpenGL support is done through the use of an "ICD" or "Installable Client Driver". This is a concept originally
created by SGI to help improve the performance of OpenGL on Windows by letting the vendor implement the
graphics pipeline completely. When OpenGL32.DLL gets loaded it simply asks the video driver for it's ICD and if
there is one it's loaded into the process space and OpenGL APIs are serviced by the ICD. The ICD is in full control
of the graphics pipeline and thus each vendor and driver version may have a different implementation.
The usual case is to buffer the OpenGL commands and flush them to the card using the ExtEscape API. The ICD
kit is now maintained by Microsoft and it is not free if you wish to develop for it.
The other method of supporting OpenGL is through something called a "Mini Client Driver" or "MCD". This is
Microsoft's original method for OpenGL support and is similar to an ICD but the MCD lives in the kernel. This
method is not used by any driver vendor that I know of and is very slow which is the reason for the ICD
implementation.
DirectX support
In XPDM, Direct Draw support is done in the GDI driver. This is through the DrvEnableDirectDraw interface.
The user mode portion and some of the kernel for the DirectX graphics pipeline is implemented by Microsoft
supplied system components. The API will simply return back a list of callback interfaces the DirectDraw layer in
the kernel will use to perform specific actions in the hardware.
Direct3D is initialized through the DrvGetDirectDrawInfo in which the GDI driver will claim to support
Direct3D. The supplied callbacks will be called several times to get the appropriate interfaces into the driver
which implement the various features of Direct3D. This is described on MSDN.
20/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
A mirror driver is a not well documented feature in which you can load a video driver that will "mirror" another
display driver. That is they will receive the same calls as the display driver they are mirroring. A mirror driver is
documented to not support DrvGetModes however if you do implement it the returned modes will be cached
and you cannot dynamically change the modes. Although I have heard that implementing DrvGetModes can
help with loading and unloading the display driver on mode switches I was unable to get this to work.
To load a mirror driver the registry key for this device needs to set the "Attach.ToDesktop" value to 1 and
then you call ChangeDisplaySettingsEx with "CDS_UPDATEREGISTRY" on the mirror driver. You then set the
mode you wish to switch to and call ChangeDisplaySettingsEx again on the mirror driver.
The mirror driver does not properly unload at mode switch and generally if there are references to a drawing
surface the driver will not unload. So, in my experience to get a mirror driver to mode switch you need an
application that will detect WM_DISPLAYCHANGE messages. You also need to set "Attach.ToDesktop" to 0 after
you load the display driver. This will help unload the display driver and on WM_DISPLAYCHANGE you can then go
through the procedure to unload the mirror driver.
If you wish to immediately unload the mirror driver without a display change you simply need to follow the same
steps as what loaded it. Set "Attach.ToDesktop" to 0 and then perform the "CDS_UPDATEREGISTRY". You can
then call "ChangeDisplaySettingsEx" again with no parameters to force unloading. Although this seems to
work again everything is done by referencing the display surface so if there are outstanding references to the
display surface the driver will not be unloaded. The mirror driver sample in the DDK does not do all of this and
has some missing pieces such as not implementing the WM_DISPLAYCHANGE and not resetting the
"Attach.ToDesktop" value after loading the mirror driver.
The example
The example driver in this article simply shares a memory mapped file between an application and the display
driver. The display driver will write graphics commands to the memory mapped file and the application simply
acts as a monitor and will just refresh itself ~70 times a second. This is not efficient but it is just an example. The
display driver is installed as a regular hardware driver and is seen just as an ATI or NVIDIA driver would be.
To install the example you will simply need to use the "Add New Hardware" wizard in the control panel. You must
select "Hardware is already installed" and "Manually select hardware from a list". The following picture shows the
list of devices for which you scroll down to the bottom and select "Add a new hardware device":
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
21/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
Then you simply want to select "Have Disk" and find the .INF file that is provided with this project. You will then
need to scroll down this new list and find "Toby Opferman Sample Video Display" as shown in the following
picture:
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
22/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
You will see the following dialog when installing just select "Continue Anyway" unless you do not want to install
the driver. The next thing you do is just enable the second monitor using the display settings and the third tab.
Run the application monitor program provided with this article and you will be shown the second monitor in that
application window:
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
23/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
Homework
Reading and seeing is a good way to learn however I believe you learn more if you actually try and do
something! What I want you to do is take my example and add more display modes! This will require changes to
the application and you can either attempt to make the application detect these display changes through various
methods including WM_DISPLAYCHANGE or simply require the user to restart the application and prompt or
enumerate devices to get the new display settings and adjust the window appropriately.
Here is a little hint. When a new mode is selected you do not always get a DrvDisableSurface,
DrvDisablePDEV, then a DrvEnablePDEV on the new setting. You may instead get a DrvAssertMode. This is
called to switch one PDEV to another as this API passes in a BOOL to inform the driver to enable or disable the
supplied PDEV.
Conclusion
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
24/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
This article showed how to create a very basic display driver to handle GDI commands. The display driver
architecture mentioned in the article only covered XPDM and not the new LDDM as found in Windows Vista. This
is also essentially the extreme basics of "where to get started". Even so hopefully you have learned a little
something about display drivers and the Windows operating system.
License
This article has no explicit license attached to it but may contain usage terms in the article text or the download
files themselves. If in doubt please contact the author via the discussion board below.
A list of licenses authors might use can be found here
Share
EMAIL
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
25/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
Toby Opferman has worked in just about all aspects of Windows development including applications, services
and drivers.
He has also played a variety of roles professionally on a wide range of projects. This has included pure
researching roles, architect roles and developer roles. He also was also solely responsible for debugging traps
and blue screens for a number of years.
Previously of Citrix Systems he is very experienced in the area of Terminal Services. He currently works on
Operating Systems and low level architecture at Intel.
Noise VeryHigh
Layout Normal
Go
Per page 50
Update
Thanks
Gabriel Barros
8Sep14 12:20
Can't compile
Jason Boggess
6Mar13 13:28
Minho Hong
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
3Feb13 6:26
26/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
Member 9067884
12Feb13 20:30
Member 8266113
11Jan13 17:52
Member 8266113
13Jan13 16:07
Member 9067884
12Feb13 20:20
irit
14Jun12 4:22
sonrie69
19Oct11 7:16
Mouse Emulation
Anfet
14Aug11 9:32
ishaq ibrahim
15May11 15:50
Toby Opferman
21May11 19:01
Jack Stephenson
6Mar11 10:26
initialj
4Jun12 0:40
Member 4013784
18Jul10 21:07
Screenshot
CzekoladowyArab
7Nov09 0:09
mirror Driver
javad_2005
voguish.prince
25Sep09 0:20
shigang.z
9Aug09 18:29
proforov
4Aug10 5:22
16Oct09 22:51
12May10 2:36
27/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
Kyomster
6Jun09 14:13
Minho Hong
16Nov13 15:47
vikrant kpr
9May09 16:28
binsa
29Dec08 7:01
AllenZhang
15Mar09 21:06
mwxkingboy
23Dec08 21:59
17Dec08 16:02
mwxkingboy
elo_gc
21Dec08 20:30
17Jan09 3:57
Citrix?
Member 270529
10Nov08 8:35
Mirror callback
Cojocaru Sergiu
13Aug07 12:24
prgmmer
3Aug07 10:44
Superlexx
20Jun07 5:29
Clone Mode
nayanaps
22Apr07 21:59
xinshou
20Mar07 19:08
uday__m
14Mar07 3:05
Problems in Compilation
Sol_Ken
28Feb07 21:07
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
28/29
3/21/2015
DriverDevelopmentPart6:IntroductiontoDisplayDriversCodeProject
bil_geo
30Jan07 4:06
futingcchq dsaf
11Sep08 2:59
AllenZhang
15Mar09 20:47
sonuguec
28Nov06 20:37
Toby Opferman
28Nov06 20:55
sonuguec
28Nov06 22:00
skadeateh
Pepao
News
Suggestion
Question
2Nov06 12:55
Toby Opferman
2Nov06 17:41
Pepao
3Nov06 14:15
Toby Opferman
3Nov06 16:43
30Oct06 23:20
vikas.gupta84
7Nov06 0:14
Refresh
Bug
Answer
Joke
Rant
1 2 3 Next
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150312.1 | Last Updated 30 Jan 2006
http://www.codeproject.com/Articles/12878/DriverDevelopmentPartIntroductiontoDisplay
29/29