www.codeguru.com/cpp/misc/misc/graphics/article.php/c15709/

Back to Article

Home >> Visual C++ / C++ >> Miscellaneous >> Miscellaneous >> Graphics


Using Windows Vista Built-In Double Buffering
Buffered Painting in Windows Vista
Rating: none

Marc Gregoire (view profile)
December 1, 2008

Environment:  Vista

Go to page: 1  2  Next

The solution to fixing flickering issues when drawing graphics is to use double buffering. Double buffering basically means that an off-screen buffer is created. Everything is rendered to this off-screen buffer and, when drawing is completed, this off-screen buffer is copied to the screen. The end result is that you do not see any flickering and you do not see the drawing being created part by part. A little unknown fact is that Windows Vista has built-in support for double buffering, so managing off-screen buffers, copying data, and so forth are all managed by Windows for you. This article will explain how to use that functionality.

Example Application


(continued)




This article comes with an example application to illustrate the Windows Vista double buffering technique. For demonstration purposes, I created the following rendering function:

void RenderWindow(HDC hdc, RECT& rcClient)
{
   // Fill the entire background with a color
   HBRUSH hBrushWhite = (HBRUSH)GetStockObject(WHITE_BRUSH);
   FillRect(hdc, &rcClient, hBrushWhite);

   // Render some lines of text
   RECT rc = rcClient;
   rc.left += 16;
   static const int NUM = 10;
   for (int i=0; i<NUM; ++i)
   {
      if (bUseBufferedPainting)
         DrawText(hdc, L"Buffered Painting", -1, &rc, DT_TOP);
      else
         DrawText(hdc, L"Unbuffered Painting", -1, &rc, DT_TOP);
      // Spacing between the lines depends on the height of the window
      rc.top += (rcClient.bottom/NUM);
      // Wait a little bit to exaggerate the effect of flickering
      Sleep(10);
   }
}

The sleep call is added to slow down the rendering a little bit. The effect of this is that the flickering with non double buffering will be even more noticeable.

The WM_PAINT handler of the normal, unbuffered rendering is as follows:

case WM_PAINT:
   {
      RECT rc;
      GetClientRect(hWnd, &rc);

      hdc = BeginPaint(hWnd, &ps);
      RenderWindow(hdc, rc);
      EndPaint(hWnd, &ps);
   }
   break;

Nothing special up to now.

Using Double Buffering

Double buffering support in Windows Vista is called Buffered Painting. The first thing you need to do is to include the uxtheme header file and link with the uxtheme library. This can be done as follows:

#include <uxtheme.h>
#pragma comment(lib, "uxtheme.lib")

Before you use any buffered painting functions, it is highly recommended to call BufferedPaintInit. BufferedPaintInit should be called once in every thread that wants to use buffered painting. It will set up some internal buffers that will be reused with every buffered painting operation. Every call to BufferedPaintInit should be matched with a call to BufferedPaintUnInit. When you do not call BufferedPaintInit, it might be that buffered painting will still work but you will have degraded performance because some internal data structures will be created and destroyed every time you use buffered painting. A good idea is to call BufferedPaintInit in your WM_CREATE handler and to call BufferedPaintUnInit in your WM_NCDESTROY handler, as can be seen below.

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
                         LPARAM lParam)
{
   int wmId, wmEvent;
   PAINTSTRUCT ps;
   HDC hdc;

   switch (message)
   {
   case WM_CREATE:
      BufferedPaintInit();
      break;
   case WM_NCDESTROY:
      BufferedPaintUnInit();
      break;
   // ...
   // ...
   default:
      return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

Now, to actually use the buffered painting, you call BeginBufferedPaint which will give you a new device context. This is the off-screen buffer to which you render everything. Once you call EndBufferedPaint, this off-screen buffer can be copied to the screen for you. Below is some code to demonstrate this.

case WM_PAINT:
{
   RECT rc;
   GetClientRect(hWnd, &rc);

   // Normal BeginPaint call
   hdc = BeginPaint(hWnd, &ps);

   if (bUseBufferedPainting)
   {
      // Try to use buffered painting
      HDC hNewDC;
      HPAINTBUFFER hBufferedPaint =
         BeginBufferedPaint(hdc, &rc, BPBF_COMPATIBLEBITMAP,
                            NULL, &hNewDC);
      if (hBufferedPaint)
      {
         // Starting of buffered painting was successful,
         // so render to the new device context
         RenderWindow(hNewDC, rc);
         // Stop buffered painting.
         // The TRUE means the off-screen buffer will be copied
         // to the hdc that was specified in the call
         // to BeginBufferedPaint.
         EndBufferedPaint(hBufferedPaint, TRUE);
      }
      else
      {
         // Buffered painting failed. Use unbuffered method,
         // rendering directly to the screen.
         RenderWindow(hdc, rc);
      }
   }
   else
   {
      RenderWindow(hdc, rc);
   }

   // Normal EndPaint call
   EndPaint(hWnd, &ps);
}
break;

With the call to BeginBufferedPaint, you start your buffered painting. The third parameter to this function defines the type of off-screen buffer that will be created. The following options are available (from MSDN):

  • BPBF_COMPATIBLEBITMAP: Compatible bitmap. The number of bits per pixel is based on the color format of the device associated with the HDC specified with BeginBufferedPaint—typically, this is the display device.
  • BPBF_DIB: Bottom-up device-independent bitmap. The origin of the bitmap is the lower-left corner. Uses 32 bits per pixel.
  • BPBF_TOPDOWNDIB:Top-down device-independent bitmap. The origin of the bitmap is the upper-left corner. Uses 32 bits per pixel.
  • BPBF_TOPDOWNMONODIB: Top-down, monochrome, device-independent bitmap. Uses 1 bit per pixel.

Setting this to, for example, BPBF_DIB will ensure you always have a 32 bit off-screen buffer, so you can always draw in 32 bit regardless of your current monitor settings.

About the Author
Marc graduated from the Catholic University Leuven, Belgium, with a degree in "Burgerlijk ingenieur in de computer wetenschappen" (equivalent to Master of Science in Engineering in Computer Science) in 2003. In 2004 he got the cum laude degree of Master In Artificial Intelligence at the same university. In 2005 he started working for a big software consultancy company. His main expertise is C/C++ and specifically Microsoft VC++ and the MFC framework. Next to C/C++, he also likes C# and uses PHP for creating webpages. Besides his main interest for Windows development, he also has experience in developing C++ programs running 24x7 on Linux platforms and in developing critical 2G,3G software running on Solaris for big telecom operators.

Go to page: 1  2  Next

Downloads

  • BufferedPaintExample_demo.zip - Demo application
  • BufferedPaintExample_src.zip - Demo application source code

    Tools:
    Add www.codeguru.com to your favorites
    Add www.codeguru.com to your browser search box
    IE 7 | Firefox 2.0 | Firefox 1.5.x
    Receive news via our XML/RSS feed






  • internet.commediabistro.comJusttechjobs.comGraphics.com

    Search:

    WebMediaBrands Corporate Info

    Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
    Advertise | Newsletters | Shopping | E-mail Offers | Freelance Jobs