原文:DFB vs. DIB

原创 2004年07月01日 18:52:00

DFB vs. DIB
By Vladislav Gelfer

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.

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.
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;
}

DFB 和DIB的比较

DFB 和DIB的比较作者: Vladislav Gelfer 翻译: huyoo(空格键)2004-6-25 4:46来源:http://www.codeproject.com/bitmap/DFB...
  • huyoo
  • huyoo
  • 2004年07月01日 18:37
  • 2146

DirectFB架构等基本知识

转载时请注明出处和作者联系方式 作者联系方式:李先静 DirectFB是一个庞大的系统,对它进行彻底分析要花不少时间。幸好多数情况下,只要弄清楚它的基本架构,再重点读一些关键的代码,也就差不多了...
  • yongcai1
  • yongcai1
  • 2013年04月03日 14:25
  • 1148

MFC绘图必知 DDB与DIB的区别

DDB与DIB的区别(转载): DDB(设备相关位图) DDB依赖于具体设备: DDB的颜色模式必需与输出设备相一致。例如,如果当前的显示设备是256色模式,那么DDB必然也是256色的...
  • hnust_xiehonghao
  • hnust_xiehonghao
  • 2014年07月10日 13:02
  • 3872

[DFB] dfb 对图形的renderto

在看DFB有关图形 renderto的部分。   之前一直以为, DFB是没法对图形进行scale的,但后来在DFB讨论群上,一个网友指点了下,才发现DFB对图形这块有很多好玩和有用的东西,只是我不...
  • situzhuge
  • situzhuge
  • 2011年04月16日 14:50
  • 1939

DFB图片显示程序

0. 每个DFB程序都需要一个IDirectFB主接口,大部分程序还需要一个最上层的,用于显示图片或视频的IDirectFBSurface,前者一般命名为dfb,后者一般叫primary,当然也有不喜...
  • jhluroom
  • jhluroom
  • 2011年09月12日 16:51
  • 763

[DFB] 显示字符串 走马灯效果

//字体显示 #include #include #include #include #include static IDirectFB            *dfb = NU...
  • situzhuge
  • situzhuge
  • 2011年04月19日 16:11
  • 1316

DIB位图(Bitmap)的读取和保存

设备无关位图(Device Independent Bitmap)是可以保存在磁盘的位图文件,可以从磁盘读取到内存或者从内存保存到磁盘上。它的文件结构是标准化的,可以在Windows/Linux/Un...
  • BrookIcv
  • BrookIcv
  • 2016年09月30日 21:15
  • 1185

unknown dib file format

Opengl:unknown dib file format
  • chenqiai0
  • chenqiai0
  • 2012年12月19日 09:27
  • 3416

windows下的DDB和DIB

1、 DDB依赖于具体设备: DDB的颜色模式必需与输出设备相一致。例如,如果当前的显示设备是256色模式,那么DDB必然也是256色的。 在256色以下的位图中存储的像素值是系统调色板的索引,...
  • yue7603835
  • yue7603835
  • 2012年03月29日 20:22
  • 3795

MFC基础知识(三)——用DIB位图显示图像

本文主要介绍:DIB位图的一些基础知识和在MFC中如何利用DIB位图显示图像。 一、DIB位图结构及注意点: 1.DIB结构: 一个完整的DIB由两部分组成:一个BITMAPINFO结构和一个存...
  • hong__fang
  • hong__fang
  • 2015年03月11日 15:35
  • 2351
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:原文:DFB vs. DIB
举报原因:
原因补充:

(最多只允许输入30个字)