Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

DFB vs. DIB

0.00/5 (No votes)
16 Jun 2004 1  
The difference between DFB and DIB.

Introduction

What is a bitmap and what is a DIB? Is there a difference? Why the Windows API has such functions as CreateBitmap, CreateCompatibleBitmap, CreateDIBitmap, and CreateDIBSection? And what is the difference between SetBitmapBits and SetDIBits?

Honestly speaking, for a long time, I had no answers for all those questions. My guess is that I was not the only one. All that became perfectly clear for me only after I had to write my own kernel-mode video driver.

I believe that every programmer who works with the GDI should know all those answers.

2D-acceleration epopee

What is a video card? Obviously, it is a hardware device that knows to hold an image and transmit it to some display device (CRT monitor or etc.). The image is held in the video card's internal memory (video memory), and the video card produces a signal for the CRT's cathode ray at some rate (refresh rate). This is in general; today's video cards know to do much more.

What is the size of images in general? How many resources do they take? It can be said approximately that an image 640x480 with 8 bits per pixel takes 300k, 800x600 with 16 bpp - 937.5k, and if we talk about 1024x768 with 24bpp - we reach 2.25Mb. It is a lot! If you want to display such an image, you must transfer more than 2Mb through the bus. Suppose now, you want to animate this image somehow (move it, for example). It would take a lot of system resources. And if you want to make some adjustments to the picture on the screen: you must pull it from the video memory, alter it, and then upload it back. Also, think about the drawing complexity: such an image's drawing involves altering hundreds of thousands of pixels, a significant payload for the CPU.

All that led to several inventions in 2D-imaging.

  1. Video cards that handle drawing instructions. That means that in order to draw "hello world" on the screen, you don't need anymore to synthesize the output image and then upload it to the video memory. Now, you can just send an instruction to the video card's internal processor with all its parameters (font, string, brush, placement, etc.), and the clever video card will do the entire job. You save the CPU clocks (during video card's processor work, the CPU can do other jobs), and you also need to transfer almost nothing through the bus, just the drawing parameters.
  2. Device-managed bitmaps (and frame buffers). Suppose you want to display something above your image and then remove it. Of course, there is no such a thing as 'above', the screen is flat. Theoretically, you have to download the obscured part of your image and store it somewhere (a bitmap), display there another image, and then upload the saved bitmap back. Nowadays, there is no need for it. Video cards have much more video memory than one screen takes. Part of this video memory is used for the so-called device-managed bitmaps. Video cards can perform drawing operations on them, between them, and between them and the screen. Again, there is a great performance advantage.

Terminology

Before we continue, let's agree on the terminology.

  • Bitmap. It is a kind of a data block that represents a rectangular image. It has sizes and a specific format. Well, historically bitmap ("bit-map") meant a matrix with a specified color depth (bits per pixel), whereas each bit somehow represented a specific pixel's color (or part of it). But under Windows 98/2K, bitmaps can also have compressed formats: JPG, PNG, RLE, so that strictly speaking, bitmaps are not always just matrixes.
  • Device context (DC). It is just an abstract structure that holds several attributes and handles to other drawing objects. It is not a device, it doesn't consume significant resources. You don't draw on DC. In fact, you draw on either bitmap (which is selected into it), or on the device that is represented by this DC. In fact, it is only needed to supply some default parameters for drawing functions; otherwise every such a function would take dozens of parameters. For instance, when you call TextOut, you supply it only the string and its placement, whereas there are also font, background and foreground colors, fill mode, clipping region, coordinates transform and etc.
  • Device-independent bitmap (DIB). It is a bitmap with known pixel format. The data it contains (bits) reside in the system memory and can be accessed by the application directly. In other words, to draw "hello world" on it, you can either select it into a DC and call TextOut function (or etc.), or you can directly alter its bits (you must know which). The effect would be the same.
  • Device-format bitmap (DFB), or device-dependent bitmap (DDB). It is a bitmap that is managed by the hardware device (usually a video card). The manufacturer is free to manage the image the way he wants, so that the pixel format is not defined. Hence, you cannot access the image's data directly. It is also usually kept in the non-system memory (video memory). To draw "hello world" on it, you can use GDI's TextOut function, which ends in the graphics card's driver call.

I expressly defined the terminology more precisely. This is because functions names in the GDI API are very confusing. From the GDI function names, it could be concluded that a �bitmap� is something that is opposed to a DIB, whereas in fact, a DIB is just a special case of a �bitmap�. In fact, DIBs are opposed to DFBs, both are bitmaps but managed differently.

There had to be CreateDIBxxx and CreateDFBxxx functions, whereas GDI calls them CreateDIBxxx and CreateBitmapxxx. In some places (but not all), the �Bitmap� term in fact should be replaced by DFB. So � never rely on the function name! Always see the description of what it does.

A word about Windows video driver architecture.

The Windows video driver architecture is designed to take as much advantages of the video card�s hardware 2D-accelerations as possible. However, the video card does not have to support all known 2D-acceleration techniques; in fact, it does not have to support any of them at all.

Every drawing instruction addressed to the video card ends in some point in the video card�s driver call. This driver is responsible to operate the video card in the proper way (which is manufacturer-dependent) so that the video driver plays the role of the hardware abstraction layer; provides a hardware-independent interface to the hardware.

There is a very basic set of functionality that the video driver must implement. It includes setting a specific video mode to the device, and transferring bits to and from the device. So the video card does not have to support 2D-accelerations at all.

In addition, there is a set of functionality that the video driver may implement. It includes managing its own bitmaps (DFBs), and supporting several drawing operations on them (and between them) such as bit-block transfer (with or without pixel format conversion), text functions, alpha-blending, stretching, gradient fills, and etc. Every such a function, even if it is reported to the OS by the driver, has a right to refuse to work at any time.

What does that mean? First of all, you have to understand that the video card�s driver is involved only for drawing operations on its-managed surfaces, which are the display or a DFB. If you draw something on a DIB, the video card is not involved at all.

Suppose now, you call AlphaBlend GDI function, whereas the DC represents either a display or a DFB. First, it checks if the video card supports alpha-blending acceleration (if it does. it must have provided a pointer to its function). If it does � the OS calls the driver-supplied DrvAlphaBlend function, otherwise Windows EngAlphaBlend function is involved. The video card�s driver examines parameters supplied in its DrvAlphaBlend function and decides if it wishes to handle it. If it does � it calls the video card in the hardware-dependent way (through so-called miniport driver); otherwise the driver is free to call the EngAlphaBlend function to do the job, as if it didn�t supply the DrvAlphaBlend at all.

Now, what EngAlphaBlend function does? It must perform somehow the alpha-blending operation, although the video driver didn�t support it. In such a case, the OS breaks the requested operation into simpler tasks and calls the video driver again. For instance, it could synthesize the resulting image within the system memory (DIB), and than ask the video driver to draw that DIB. Or it could convert the source parameters (which could be bitmaps as well) into other formats, eliminating the need for the driver to convert from one format to another, and than retry the DrvAlphaBlend. Again, the driver has a right not to handle the call, and the OS must continue to simplify the driver�s job. In such a way, it can reach a very basic level, which the driver can�t refuse to execute.

So that, as we can see, the Windows driver architecture knows to take advantages of the hardware 2D-accelerations, whereas the only thing that is mandatory for the video card is to know to transfer the image to and from the display.

DFB vs DIB.

After we know the difference between DFB and DIB, let�s discuss their advantages.

Drawing operations on DFBs are hardware-accelerated (at least part of them), hence they are usually very fast. Also, transfers between them and between them and the display are very fast too. So, why would we want to use DIBs at all?

The reason is that sometimes drawing output we need is so complex that it can�t be expressed in terms of standard GDI functions. In such cases, it is better to have a system-memory pointer to the image�s bits and alter them directly. Well, this is not an easy way, but it gives the best possible performance, and it is used generally by graphics-oriented programs, such as Photoshop, ACDSee, and etc. Another way is to use nothing but SetPixel and GetPixel functions, to build the image pixel by pixel. Doing so for DFBs leads to a catastrophic performance degradation, because every such a call involves a heavy transaction, whereas calling those functions for DIBs is OK.

GDI API.

How do we create a DFB and a DIB? First of all: there is no function that is guaranteed to create a DFB! As we know, the video driver is not required to support DFBs at all. And even if it does, it is allowed to refuse, either because of the video memory shortage or because the pixel format you ask is not supported or not accelerated by the video card. There are functions that attempt to create a DFB. If it fails � they create and return a DIB with adequate parameters. Those functions are CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap (when the DC refers to a DFB or a device), and CreateDIBitmap, although its name is confusing.

BTW, I�ve looked on a couple of video drivers' source code. All of them supported DFBs only with the pixel format identical to the current display�s format, and some of them supported monochrome DFBs regardless of the current video mode.

However, there is a function that is guaranteed to create a DIB. And, there is only one such a function. It is called CreateDIBSection. (Again, never rely on a function name, always see its description!)

Now, suppose we have a bitmap handle, HBITMAP. How do we know what it refers to, a DFB or a DIB? Calling GetObjectType won�t help, because they both are OBJ_BITMAP. Fortunately, there is a way to discover who is who. I discovered it occasionally. You can call GetObject function to fill the BITMAP structure with the bitmap�s parameters. If the bmBits member is NULL � the bitmap is a DFB, otherwise it�s a DIB.

Useful tips.

Suppose you have a bitmap for some owner-draw GUI stuff or animations. And this bitmap won�t change; you are not going to draw on it. Indeed, a DBF would be much more efficient here than a DIB. So, if you create it by yourself � use CreateBitmap to attempt to create a DFB. But sometimes you receive a bitmap handle from other functions, such as LoadBitmap, LoadImage, and etc. Some of them usually try to create DFBs, and some don�t. In such cases, the following two conversion functions would be useful:

// This function converts the given bitmap to a DFB.

// Returns true if the conversion took place,

// false if the conversion either unneeded or unavailable

bool ConvertToDFB(HBITMAP& hBitmap)
{
  bool bConverted = false;
  BITMAP stBitmap;
  if (GetObject(hBitmap, sizeof(stBitmap), &stBitmap) && stBitmap.bmBits)
  {
    // that is a DIB. Now we attempt to create

    // a DFB with the same sizes, and with the pixel

    // format of the display (to omit conversions

    // every time we draw it).

    HDC hScreen = GetDC(NULL);
    if (hScreen)
    {
      HBITMAP hDfb = 
              CreateCompatibleBitmap(hScreen, 
      stBitmap.bmWidth, stBitmap.bmHeight);
      if (hDfb)
      {
        // now let's ensure what we've created is a DIB.

        if (GetObject(hDfb, sizeof(stBitmap), 
                   &stBitmap) && !stBitmap.bmBits)
        {
          // ok, we're lucky. Now we have

          // to transfer the image to the DFB.

          HDC hMemSrc = CreateCompatibleDC(NULL);
          if (hMemSrc)
          {
            HGDIOBJ hOldSrc = SelectObject(hMemSrc, hBitmap);
            if (hOldSrc)
            {
              HDC hMemDst = CreateCompatibleDC(NULL);
              if (hMemDst)
              {
                HGDIOBJ hOldDst = SelectObject(hMemDst, hDfb);
                if (hOldDst)
                {
                  // transfer the image using BitBlt

                  // function. It will probably end in the

                  // call to driver's DrvCopyBits function.

                  if (BitBlt(hMemDst, 0, 0, 
                        stBitmap.bmWidth, stBitmap.bmHeight, 
                        hMemSrc, 0, 0, SRCCOPY))
                    bConverted = true; // success


                  VERIFY(SelectObject(hMemDst, hOldDst));
                }
                VERIFY(DeleteDC(hMemDst));
              }
              VERIFY(SelectObject(hMemSrc, hOldSrc));
            }
            VERIFY(DeleteDC(hMemSrc));
          }
        }

        if (bConverted)
        {
          VERIFY(DeleteObject(hBitmap)); // it's no longer needed

          hBitmap = hDfb;
        }
        else
          VERIFY(DeleteObject(hDfb));
      }
      ReleaseDC(NULL, hScreen);
    }
  }
  return bConverted;
}

// This function converts the given bitmap to a DIB.

// Returns true if the conversion took place,

// false if the conversion either unneeded or unavailable

bool ConvertToDIB(HBITMAP& hBitmap)
{
  bool bConverted = false;
  BITMAP stBitmap;
  if (GetObject(hBitmap, sizeof(stBitmap), 
            &stBitmap) && !stBitmap.bmBits)
  {
    // that is a DFB. Now we attempt to create

    // a DIB with the same sizes and pixel format.

    HDC hScreen = GetDC(NULL);
    if (hScreen)
    {
      union {
        BITMAPINFO stBitmapInfo;
        BYTE pReserveSpace[sizeof(BITMAPINFO) 
                     + 0xFF * sizeof(RGBQUAD)];
      };
      ZeroMemory(pReserveSpace, sizeof(pReserveSpace));
      stBitmapInfo.bmiHeader.biSize = sizeof(stBitmapInfo.bmiHeader);
      stBitmapInfo.bmiHeader.biWidth = stBitmap.bmWidth;
      stBitmapInfo.bmiHeader.biHeight = stBitmap.bmHeight;
      stBitmapInfo.bmiHeader.biPlanes = 1;
      stBitmapInfo.bmiHeader.biBitCount = stBitmap.bmBitsPixel;
      stBitmapInfo.bmiHeader.biCompression = BI_RGB;

      if (stBitmap.bmBitsPixel <= 8)
      {
        stBitmapInfo.bmiHeader.biClrUsed = 
                        1 << stBitmap.bmBitsPixel;
        // This image is paletted-managed.

        // Hence we have to synthesize its palette.

      }
      stBitmapInfo.bmiHeader.biClrImportant = 
                       stBitmapInfo.bmiHeader.biClrUsed;

      PVOID pBits;
      HBITMAP hDib = CreateDIBSection(hScreen, 
        &stBitmapInfo, DIB_RGB_COLORS, &pBits, NULL, 0);

      if (hDib)
      {
        // ok, we're lucky. Now we have

        // to transfer the image to the DFB.

        HDC hMemSrc = CreateCompatibleDC(NULL);
        if (hMemSrc)
        {
          HGDIOBJ hOldSrc = SelectObject(hMemSrc, hBitmap);
          if (hOldSrc)
          {
            HDC hMemDst = CreateCompatibleDC(NULL);
            if (hMemDst)
            {
              HGDIOBJ hOldDst = SelectObject(hMemDst, hDib);
              if (hOldDst)
              {
                if (stBitmap.bmBitsPixel <= 8)
                {
                  // take the DFB's palette and set it to our DIB

                  HPALETTE hPalette = 
                    (HPALETTE) GetCurrentObject(hMemSrc, OBJ_PAL);
                  if (hPalette)
                  {
                    PALETTEENTRY pPaletteEntries[0x100];
                    UINT nEntries = GetPaletteEntries(hPalette, 
                                    0, stBitmapInfo.bmiHeader.biClrUsed, 
                                    pPaletteEntries);
                    if (nEntries)
                    {
                      ASSERT(nEntries <= 0x100);
                      for (UINT nIndex = 0; nIndex < nEntries; nIndex++)
                        pPaletteEntries[nEntries].peFlags = 0;
                      VERIFY(SetDIBColorTable(hMemDst, 0, 
                        nEntries, (RGBQUAD*) pPaletteEntries) == nEntries);

                    }
                  }
                }

                // transfer the image using BitBlt function.

                // It will probably end in the

                // call to driver's DrvCopyBits function.

                if (BitBlt(hMemDst, 0, 0, stBitmap.bmWidth, 
                      stBitmap.bmHeight, hMemSrc, 0, 0, SRCCOPY))
                  bConverted = true; // success


                VERIFY(SelectObject(hMemDst, hOldDst));
              }
              VERIFY(DeleteDC(hMemDst));
            }
            VERIFY(SelectObject(hMemSrc, hOldSrc));
          }
          VERIFY(DeleteDC(hMemSrc));
        }

        if (bConverted)
        {
          VERIFY(DeleteObject(hBitmap)); // it's no longer needed

          hBitmap = hDib;
        }
        else
          VERIFY(DeleteObject(hDib));
      }
      ReleaseDC(NULL, hScreen);
    }
  }
  return bConverted;
}

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