Graphics Device Interface

Not to be confused with graphical user interfaces (GUI).
Graphics Device Interface
Component of Microsoft Windows
Typegraphics library
Introduced inWindows 1.0

The Graphics Device Interface, or GDI, is the original 2D graphics API on Microsoft Windows platform. It is one of the three major components of 16-bit Windows together with Kernel and User. GDI has since been complemented by GDI+, DirectDraw, Direct2D, and other APIs, but continues to be the default, basic option for Win32 graphics.

Development history[edit | edit source]

Windows 1.0/2.0[edit | edit source]

When GDI was first developed for Windows 1.0, there was no standard for device-independent graphics on the PC. By the time Windows 1.0 came out, the most common display adapters were the monochrome high-resolution Hercules, the IBM Color Graphics Adapter (CGA), and its supersets, including the Enhanced Graphics Adapter (EGA) and a litany of third-party "Super CGA" cards from clone vendors. However, apart from a few slow graphics calls in the video BIOS, each application had to code special support for each graphics card, usually meaning that they’d only target the most popular cards (meaning that most users of "Super CGA" cards would be stuck with basic CGA compatibility only). The reason for this was simple; on DOS, programmers had to write directly to the hardware, and every display adapter worked differently.

Windows sought to change this with the introduction of the Graphics Display Interface, or GDI, which allowed a programmer to write a graphical application once, and display it on any GDI-supported adapter, or even print any graphics and text output to a GDI printer, in a similar manner to what PostScript was accomplishing around the same time.

GDIs main primitives included plotting pixels, drawing lines, drawing/filling polygons (including arcs, ellipses, rectangles, etc.), and drawing text; perfect for business applications, mainly concerned with text and charts. The fundamental core primitive in GDI is the Device Context, referred to by a handle (the Windows type HDC). To perform drawing operations, the user perform them onto an HDC, which contains certain pieces of state attached to it:

  • The current font, pen, brush, etc. (controlling how GDI draws certain primitives)
  • The bitmap selected into it (the surface to which drawing occurs, backed by driver-owned memory in a driver-dependent format)
  • The attached display driver (code within the driver is called to perform drawing operations

An HDC could be owned by a printer driver, display driver, or anything else. Two contexts were developed to specify which graphics should be used on.

Display Contexts[edit | edit source]

Display Contexts refer to graphics displayed directly onto the screen, meaning the user can’t select a bitmap into them (any drawing operations performed onto them are displayed directly onto the screen), and are obtained through API calls such as GetDC or BeginPaint (that obtains a Display Context from a window handle) or CreateDC, which gets a DC to the entire device.

Memory Device Contexts[edit | edit source]

Memory Device Contexts, on the other hand, are essentially off-screen surfaces that the user can draw to, and later blit to the Display Context. They are created via the CreateCompatibleDC API call, so that any memory DCs are stored in a format compatible with the target Display Context.

Problems with Contexts[edit | edit source]

The trouble was that support for color graphics/images interchange was almost nonexistent. GDI had minimal support for color; while the user could call SetPixel with an RGB value, or initialize brush, pen, or text colors, but once the user’ve drawn those RGB values to the screen, it’s now converted to whatever format is on the display and there’s no way to get it back into RGB. Windows did have the GetBitmapBits API call to retrieve the contents of a device-dependent-bitmap, but it would be stored into the array in a device-dependent format, which wouldn’t necessarily be meaningful to the programmer except to pass into SetBitmapBits, which allowed one to set the bits in a device-dependent-bitmap, but the way those bits were interpreted was entirely up to the display driver.

It’s also worth noting that the type of bitmap the user can select into a device context is dependent on what device the device context belongs to; the user have to use a bitmap in a compatible color format, hence why bitmaps are created using the CreateCompatibleBitmap API call, which ensures a compatible color format, though monochrome bitmaps could select into any device context, being the only device-independent format available. The user could initialize a bitmap from an array using CreateBitmap, but there was no guarantee it’d be able to be selected into a given DC, since the user had to specify the color format by itself, which is then up to the interpretation of the display adapter, many of which did color differently, often using bitplanes.

Windows 3.0[edit | edit source]

Windows 3.0 added support for the Device Independent Bitmap (DIB) format from Microsoft’s concurrently-developing OS/2 product. DIBs are stored in a packed-pixel arrangement consistent with how linear framebuffers work. However, Microsoft still provided no way for one to directly access or edit the bits of an HBITMAP, which continued to be stored in device-dependent format, potentially in memory that Windows didn’t even have access to. This meant that there was no way to select a DIB into a Memory DC and use the fast BitBlt or StretchBlt operations to copy it onto the screen. Instead, the user had to use one of four functions:

  • SetDIBits: Copy a DIB with a specified color table into a device-dependent bitmap
  • GetDIBits: Copy from a DDB into a DIB, using a specified color table
  • SetDIBitsToDevice: Draw a DIB directly onto a device context, mapping the DIBs colors (either specified directly or through a specified color table) to the logical palette selected into the DC
  • StretchDIBits: Draw a DIB directly onto a device context with stretching, using a specified color table

These operations did work (though depending on palettes, they could be lossy), but they tended to be much slower than their counterparts using DDBs, making fast display of DIBs to the screen impractical, making it difficult to develop fast games, animation, or full-motion video applications that run under Windows. Not being able to read the bits of an HBITMAP was problematic if the user wanted to be able to use GDI’s array of graphics primitives to draw into a color image that the user could later save to disk and share.

To address the latter problem, Microsoft developed DIB.DRV for Windows 3.0 with Multimedia Extensions (included with Windows 3.1), essentially a GDI display driver, only instead of the screen being the target surface, it let the user create device contexts wrapped around DIBs by calling CreateDC("DIB", NULL, NULL, (LPDEVMODE)lpBMI) where lpBMI is a pointer to the BITMAPINFOHEADER structure, which in a DIB/BMP file is followed by the DIB bits. This allowed one to quickly and easily retrieve the results of any GDI drawing operations. However, this wasn’t a solution to the problem of quickly displaying DIBs, since the speedy BitBlt function implemented by display drivers is designed to let the user copy between device contexts owned by the same driver, not different drivers, and DIB.DRV provided no means of copying DIBs onto the screen, having no knowledge of the DISPLAY driver.

Windows NT 3.5 and Windows 95[edit | edit source]

Windows NT 3.50 added the CreateDIBSection API call to GDI, which allowed one to create an HBITMAP backed by a device-independent bitmap in user-accessible memory, and thus select it into a device context and use it for drawing operations. This meant that not only could one select a DIB into a memory device context and then quickly blit from there to a Display Context, but also that one could use the DIB as the drawing surface and use GDI to draw into it. The reason for the naming of the API is that Windows NT memory objects are referred to as “sections”, and in fact the user can create a DIB section around existing memory by passing a section handle (a handle to a memory-mapped file view); otherwise, GDI (really, CSRSS/WINSRV) will create one for the user and map it into the address space of the calling process. The DIB section is in shared memory between the user's application and the subsystem server process where GDI and the display driver live, allowing programmers to use both their code and GDI to draw onto the same surface quickly.

Windows 95 also added this API call, in conjunction with the introduction of the DIB engine (first detailed in the 1992 Chicago specification, and implemented as early as July 1992). The DIB engine was designed to simplify development of Windows 95 display drivers, allowing video card vendors to simply ship a “minidriver” (the equivalent of NT kernel-mode video miniport drivers) which provided code to set video modes, switch banks, and provide a pointer to the framebuffer, while the DIB engine would take care of everything else. The DIB engine (DIBENG.DLL) was essentially a GDI display driver written in 32-bit x86 assembly and could perform GDI drawing operations onto DIBs for flat framebuffers. Once the driver developer gained access to the framebuffer as one large DIB (either using DCI, or DVA, which had by then been renamed to VFLATD.386 and later VFLATD.VXD, and had the same source code being built for VfW and Windows 95 via conditional compilation), the DIB engine could then be used to draw onto it. Since the DIB engine device contexts are based on DIBs, blitting between them is simple. Windows NT display drivers could work in a similar manner, since GDI on NT also provided a DIB engine.

WinG was a port of an early version of the Chicago DIB engine to Windows 3.1x, and most of its functions are parallels to GDI calls added in Windows 95 / NT 3.5, with WinGCreateBitmap mapping to CreateDIBSection, WinGSetDIBColorTable mapping to SetDIBColorTable, WinGCreateDC mapping to CreateCompatibleDC and so on. Fundamentally, WinG allows the programmer to create a device context based on a DIB, and both use GDI to draw into it and quickly draw that device context to the screen.

Windows NT[edit | edit source]

When Microsoft began developing the Win32 "personality" for Windows NT, it was designed, like the POSIX and OS/2 Subsystems, to be hosted in user-mode on top of the kernel, inside of a Subsystem Server. The Client-Server Runtime Subsystem (CSRSS.EXE) process hosted both GDI and USER, and display drivers were user-mode DLLs loaded into the address space of CSRSS, which communicated via IOCTLs with a video miniport driver in kernel-mode to map video memory. The entry points inside of GDI32.DLL and USER32.DLL communicated to the subsystem server via NT's Local Procedure Call (LPC) mechanism.

To facilitate DCI support and allow use of the DIB engine on banked framebuffer displays, a virtual flat framebuffer device was implemented on Windows NT 3.51. In Windows NT 4.0, core GDI and USER functionality was moved from the user-mode subsystem server to a kernel-mode module, WIN32K.SYS, for additional speed.

Windows Vista[edit | edit source]

When using a WDDM-based display driver with the Desktop Window Manager active, each window is represented with a Direct3D texture. GDI rendering to windows occurred in software via the Canonical Display Device, CDD.SYS, which could draw onto the texture. WDDM 1.1 on Windows 7 and above restored some hardware acceleration for GDI, including BitBlt.

GDI+[edit | edit source]

In 2001, Microsoft released GDI+ alongside Windows XP, with it also being available as a redistributable DLL for Windows NT 4.0, Windows 2000, Windows 98, and Windows Me. GDI+ was a C++-based object-oriented API, adding support for anti-aliased 2D graphics, full RGBA alpha-blending support, and modern graphics formats such as JPEG and PNG. However, it has no hardware acceleration, instead rendering in software, making it significantly slower than GDI.

Initial versions of GDI+ used DCI to render directly to the framebuffer for maximum speed, as DirectDraw support was not universal among older drivers on certain systems. However, this made GDI+ incompatible with accessibility software such as magnifiers and screen-readers, so it was later changed to use CreateDIBSection.

The .NET Framework's System.Drawing namespace provides a managed interface to GDI+.