Flipping Surfaces and GDI's Frame Rate

DirectDraw has extended flipping surfaces to encompass more than page flipping and more than visible surface flipping. Any surface can now be constructed as a flipping surface. This has many advantages over the traditional, limited scope of page flipping.

When an IDirectDrawSurface::Flip method operation is requested in DirectDraw, the surface memory areas associated with the DirectDrawSurface objects being flipped are switched. Surfaces attached to the DirectDrawSurface objects being flipped are not affected. For example, in a double-buffered situation, an application that draws on the back buffer always uses the same DirectDrawSurface object. The surface memory underneath the object is just switched with the front buffer when the IDirectDrawSurface::Flip method is requested.

If the front buffer is visible, either because it is the primary surface or because it is an overlay that is currently visible, subsequent calls to the IDirectDrawSurface::Lock method or the IDirectDrawSurface::Blt method that target the back buffer will fail with the DDERR_WASSTILLDRAWING return value until the next vertical refresh occurs. This behavior occurs because the front buffer's previous surface memory, which is no longer attached to the back buffer, is still being drawn to the physical display by the hardware. This situation disappears during the next vertical refresh because the hardware that updates the physical display re-reads the location of the display memory on every refresh.

This physical requirement makes calling the IDirectDrawSurface::Flip method on visible surfaces an asynchronous command. A good practice to follow when building games, for example, is to perform all of the non-visual elements of the game after this method is called. When the input, audio, game play, and system memory drawing operations have been completed, begin the drawing tasks that require gaining access to the visible back buffers.

When your application needs to run in a window and still requires a flipping environment, it will attempt to create a flipping overlay surface. If the hardware does not support overlays, you can create a primary surface that page flips, and when a surface that GDI is not aware of is about to become the primary surface, blit the contents of the primary surface that GDI is writing to onto the buffer that is about to become visible. This takes little, if any, processing time because the blits are performed asynchronously. It can, however, consume considerable blitter bandwidth that is dependent on screen resolution and the size of the window that is being page flipped. As long as the frame rate does not dip below 20 frames a second, GDI will appear to be operating correctly.

Before you instantiate a DirectDraw object, GDI is already using your display memory to display itself. When you call DirectDraw to instantiate a primary surface, the memory address of that surface will be the same as GDI is currently using.

If you create a complex surface with a back buffer, GDI will first point to the display memory for the primary surface. Since GDI has no knowledge of DirectDraw, GDI will continue operating on this surface, even if you have flipped it and it is now the non-visible back buffer.

Many applications will begin by creating one large window that covers the entire screen. As long as your application is active and has the focus, GDI will not attempt to write into its copy of the buffer since nothing it controls needs redrawing.

For other scenarios, always remember that GDI only knows about the original surface, and never knows if it is currently the primary surface or a back buffer. If you do not need the GDI screen, then use the above technique. If you do need GDI, you can try this technique:

·Create a primary surface with two back buffers.

·Blit the initial primary surface (the GDI surface) to the middle back buffer.

·Flip(NULL) to put GDI into last place and make your initial copy visible.

After you have done this, copy from the GDI buffer to the middle buffer, draw what you want the user to see on that buffer, then use the code below, which keeps GDI safely on the bottom and oscillates between the other two buffers.

pPrimary->Flip(pMiddle)