百度首页 | 百度空间
 
查看文章
 
Direct Draw Surfaces
2008/03/04 15:03

Direct Draw Surfaces

Overview

A Direct Draw surface is simply a linear block of display memory. Surfaces can be copied, manipulated, and destroyed. This document describes Direct Draw surfaces and how to use them. You should have read Direct Draw Initialization prior to reading this document.

Performance Considerations

Regardless of the type of graphics application you are developing, you want your graphics to be drawn quickly and smoothly. Poorly written graphics programs will exhibit a behavior known as tearing, in which an image appears to be flashing on the screen. There are a few ways to prevent tearing, and the one we will examine here is back-buffering. In back-buffering, you prepare an off-screen surface to be displayed by drawing whatever images you desire, and then you make the back-buffer visible by flipping the primary surface. The simplest form of back buffering is double-buffering, which will be used throughout the remainder of this document. Note that back-buffering requires the use of full-screen/exclusive mode.

A surface can be stored in video memory or system memory, and Direct Draw gives you the ability to specify where to store a particular surface. Frequently used surfaces should ideally be kept in video memory, because blitting can be performed more quickly if the source exists in video memory. Surfaces that are either too large to fit in video memory or that are infrequently used should be kept in system memory. Also, note that most video chipsets support asynchronous blitting, so you should take advantage of this wherever possible. High-performance video cards support asynchronous blit queues, which further enhance performance by keeping the blitter busy at all times and by lowering CPU utilization.

Creating the Primary Surface

To create the primary surface, you must call IDirectDraw4::CreateSurface(). CreateSurface() has the following prototype:

HRESULT CreateSurface( LPDDSURFACEDESC2 lpDDSurfaceDesc2, LPDIRECTDRAWSURFACE4FAR *lplpDDSurface, IUnknownFAR *pUnkOuter );

pUnkOuter must be NULL. The first parameter is a pointer to a structure that describes the surface you want to create, and the second parameter is a pointer to a pointer to a surface that will be created by the CreateSurface() function. If the surface is successfully created, the function return DD_OK. The following example demonstrates how to create a primary surface with a single back-buffer:

LPDIRECTDRAWSURFACE4 primarySurface = NULL;

DDSURFACEDESC2 primarySurfaceDesc;

// zero out the surface description
ZeroMemory(&primarySurfaceDesc,sizeof(primarySurfaceDesc));

// set the surface description values
primarySurfaceDesc.dwSize = sizeof(primarySurfaceDesc);
primarySurfaceDesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
primarySurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
primarySurfaceDesc.dwBackBufferCount = 1;

// create the primary surface
displayDevice->CreateSurface(&primarySurfaceDesc,&primarySurface, NULL);

At this point, you have created a primary surface that has a single back-buffer. However, you do not have any way of accessing the back-buffer yet. To get a pointer to the back-buffer, call IDirectDrawSurface4::GetAttachedSurface() as shown below:

LPDIRECTDRAWSURFACE4 backSurface = NULL;
DDSCAPS2 primarySurfaceCaps;

primarySurfaceCaps.dwCaps = DDSCAPS_BACKBUFFER;
primarySurface->GetAttachedSurface(&primarySurfaceCaps, &backSurface);

backSurface now points to the back-buffer. GetAttachedSurface() returns DD_OK if it is successful.

Creating Off-Screen Surfaces

As the name implies, an off-screen surface exists in display memory, but is not visible to the user. Off-screen surfaces can be made visible by blitting them to the primary surface. To create an off-screen surface, we once again use our old friend, the CreateSurface() function, only this time DDSURFACEDESC2 structure will be filled differently as shown in the following example:

DDSURFACEDESC2 surfaceDesc;
LPDIRECTDRAWSURFACE4 offScreenSurface = NULL;

// zero out the surface description
ZeroMemory(&surfaceDesc,sizeof(surfaceDesc));

// set the surface description values
surfaceDesc.dwSize = sizeof(surfaceDesc);
surfaceDesc.dwFlags = DDSD_CAPS;

// specify where to create the surface
surfaceDesc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY; // could be DDSCAPS_SYSTEMMEMORY if you want the surface to be located in system memory

displayDevice->CreateSurface(&surfaceDesc,&offScreenSurface, NULL);

Flipping the Primary Surface

The primary surface consists of the currently visible surface and n back buffers. When you flip the primary surface, you cause the surface that has not been displayed in the longest time to be displayed. So the primary surface, along with its associated backbuffers, can be thought of as a circular queue. You may flip the primary surface by calling the IDirectDrawSurface4::Flip() function as shown in the following function:

bool Flip()
    {
    if (primarySurface->GetFlipStatus(DDGFS_CANFLIP) != DD_OK)
        return false;    // cannot flip now, try again later

    primarySurface->Flip(NULL, NULL);
    return true;
    }

Note that this function is asynchronous. It will not wait until the flip operation can be performed before returning. Instead, you must call Flip() until it returns true, indicating a successful primary surface flip. A flip operation will always be synchronized with the video hardware's vertical blank, so if you are using a video mode that has a 70 hz refresh rate, then at most 70 flip operations can occur in one second.

Blitting to a Surface

Blitting to a surface is beyond the scope of this document -- see Direct Draw Blitting for a discussion of this topic.

Restoring Lost Surfaces

Direct Draw does not guarantee that an allocated surface will persist for the life of a program. In fact, there are two situations that can cause one or more of your surfaces to be lost:
  • An application (not necessarily yours) changes the video mode.
  • An application requested and received exclusive mode access to the screen and freed all the memory currently allocated to surfaces.
You can determine if a surface has been lost if a method that operates on a surface returns DDERR_SURFACELOST. Alternatively, you can call IDirectDrawSurface4::IsLost() before using the surface in order to determine if it still exists or not. However, I do not recommend using IsLost() because surfaces can be lost in the period of time between the call to IsLost and the point in execution where the surface is used.

Once you have determined that a surface is lost, you can restore the memory that was allocated to a surface with a call to IDirectDrawSurface4::Restore(). This method only reallocates the memory associated with a surface; it does not restore the contents of a surface. Your program must recreate the contents of any lost surfaces on its own. In the games I've helped to develop, my team and I used a "SurfaceManager" class which took care of loading, restoring, reloading, and deleting surfaces as needed.

Direct Draw 4 introduced the IDirectDraw4::RestoreAllSurfaces() method, which will restore the memory allocated to all of the surfaces that a program has created. Just like with the Restore() method, your program must explicitely restore the contents of the lost surfaces. A good time to call RestoreAllSurfaces() is after changing the display mode, since some or all of your surfaces will have been toasted by the mode change.

GDI Compatibility

Programmers tend to make a logical distinction between the Windows GDI and Direct Draw, as though the two could not be combined. However, the two work well together. Because of the inheritance relationship that exists in DirectX, Windows GDI functions (TextOut, SetPixel, etc.) can be used to manipulate Direct Draw surfaces. However, you should use Direct Draw as much as possible to maximize performance.

Definitions

Asynchronous Blit -- A block transfer that occurs in the background, without the intervention of the CPU.

Back-Buffer -- An off-screen surface representing the future contents of the display screen that can be prepared before it is shown.

Blit -- Short, pronounceable term that stands for block transfer. A block transfer is simply copying one block of memory to another.

Double-Buffering -- When the primary surface has only one attached back-buffer.

GDI -- An acronym for Graphics Device Interface. Windows applications have historically used the GDI to perform all graphics operations, but Direct Draw has extended the capabilities and performance of Windows graphics.

Primary Surface -- A surface that consists of the visible, on-screen surface and zero or more back-buffers. The next back buffer in the circular queue can be made visible by flipping the primary surface.

Tearing -- When on-screen images appear to be flashing. A characteristic of a poorly designed animation application.


Author: Rodney Myers -- 5/15/99
Modified on 7/2/99 Sections affected: Definitions, Restoring Lost Surfaces, Flipping the Primary Surface.

http://www.mtsu.edu/~csjudy/directX/DirectDraw/Surfaces.html


类别:Windows Application | 添加到搜藏 | 浏览() | 评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码:
 

     

©2008 Baidu