最近因为工作需要大量的绘制图形,为了提高效率,特提出以下设想:
考虑使用 IDirectDraw7 和 IDirectDrawSurface7 作为绘图背景,其中
1、使用主表面和后背表面,后背表面用来合成图片,主表面仅用来显示图片
2、背景图使用一个单独的表面进行绘制,设置透明色,或者背景填充为地图的底色
3、设备图层使用一个单独的表面进行绘制,设置透明色(SetColorKey);
4、绘图操作可以使用 GDI+ ,通过 Graphics 挂接绘图表面的 HDC;
当主表面需要绘制时:
1、初始化背景表面的背景色为地图的底色;
2、将背景表面叠加到后背表面上;
3、将设备表面叠加到后背表面上;
4、翻转后背表面到主表面上;
当然首先第一步就是做一个简单的程序测试效率,结果大出我的意料之外,测试结果如下:
1、使用 GDI+ (没有启动窗口模式的 DirectDraw) , 绘制一万次四个点的折线平均耗时:2740 毫秒
2、使用 GDI (没有启动窗口模式的 DirectDraw) ,绘制一万次四个点的折线平均耗时:265 毫秒
3、使用 GDI+ (启动窗口模式的 DirectDraw) ,绘制一万次四个点的折线平均耗时:6957 毫秒
4、使用 GDI (启动窗口模式的 DirectDraw) ,绘制一万次四个点的折线平均耗时:234 毫秒
怎么使用 GDI+ 比使用 GDI 的效率差这么多,并且使用窗口模式 DirectDraw (非全屏模式)对 GDI 的效率提高不大,但是对 GDI 的效率则是一个很大的影响;这让人实在是想不明白,最终不得不放弃了这个想法,只好使用最原始的作法:使用 GDI 函数在窗口的 DC 上进行绘图;下面是测试的代码:
测试代码片段
#define TEST_DIRECT_DRAW
#define TEST_GDI_PLUS
LRESULT CDDraw1View::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CPaintDC dcPaint(m_hWnd);
HDC hDC = dcPaint.m_hDC ;
#if defined( TEST_DIRECT_DRAW )
HRESULT hr = S_OK;
if( ! spDirectDraw )
{
hr = DirectDrawCreateEx( NULL , (LPVOID*)& spDirectDraw , IID_IDirectDraw7 , NULL );
spDirectDraw->SetCooperativeLevel( m_hWnd , DDSCL_NORMAL );
}
if( ! spDirectDrawSurface )
{
DDSURFACEDESC2 xSurfaceDesc = { sizeof( DDSURFACEDESC2 ) , 0 };
xSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH ; // DDSD_BACKBUFFERCOUNT
xSurfaceDesc.ddsCaps.dwCaps = 0;//DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX ;
//xSurfaceDesc.dwBackBufferCount = 1;
RECT rcClient; GetClientRect( & rcClient );
xSurfaceDesc.dwWidth = rcClient.right - rcClient.left ;
xSurfaceDesc.dwHeight = rcClient.bottom - rcClient.top ;
hr = spDirectDraw->CreateSurface( & xSurfaceDesc , & spDirectDrawSurface , NULL );
ATLASSERT( SUCCEEDED( hr ) );
}
spDirectDraw->RestoreAllSurfaces( );
spDirectDrawSurface->GetDC( & hDC );
#endif
DWORD dwStart = GetTickCount( );
#if defined( TEST_GDI_PLUS )
Graphics xGraphics( hDC );
Point arPoints[ ] =
{
Point(10, 100),
Point(150, 80),
Point(200, 20),
Point(250, 80),
};
Pen xPen( Color( 255 , 128 , 0 , 0 ) , 1 );
xGraphics.SetSmoothingMode( SmoothingModeAntiAlias );
for( int i = 0 ; i < 10000 ; i ++ )
{
// xGraphics.DrawCurve( & xPen , arPoints , _countof( arPoints ) );
xGraphics.DrawLines( & xPen , arPoints , _countof( arPoints ) );
}
#else
CDCHandle dc( hDC );
CPen hPen; hPen.CreatePen( PS_SOLID , 2 , RGB( 128 , 0 , 0 ) );
dc.SelectPen( hPen.m_hPen );
POINT arPoints[] = { {10, 100} , {150, 80} , {200, 20} ,{250, 80} };
for( int i = 0 ; i < 10000 ; i ++ )
{
dc.Polyline( arPoints , _countof( arPoints ) );
}
#endif
DWORD dwSpend = GetTickCount( ) - dwStart;
AtlTrace( TEXT("Draw 10000 Counts Spend %d MS \n") , dwSpend );
#if defined ( TEST_DIRECT_DRAW )
spDirectDrawSurface->ReleaseDC( hDC );
#endif
return 0;
}