GDI+的快速渲染-什么该做,什么不该做

原文:http://www.codeproject.com/Tips/66909/Rendering-fast-with-GDIplus-What-to-do-and-what-no.aspx

翻译于2015-1-07 


  每个人都知道GDI+在渲染过程中通常是缓慢的,然而怎样的设置最快却并不为人所知。我有一个的APP,它包含了很多 可以被绘制为有位图图源的精灵在一个页面上(通常是1024*768).第一次尝试跑了大约3帧/秒,通过加速后,我获得的速率高达41帧/秒。


  我的应用程序大致做了以下内容:
  load a background Bitmap: bgndBitmap
    load any Bitmaps used for 'sprites': spriteBitmap
    create a Bitmap to render into: renderBitmap
    create a Graphics object to draw on the Bitmap
    while( forever )
    {
         draw bgndBitmap 
         for( all items... )
             draw part of spriteBitmap
 
         draw the renderBitmap into a dialog
    }
 
  什么该做
  始终使用PixelFormat32bppPARGB
  
  预乘Alpha,即使有些特定的图像或位图可能不会有任何的Alpha.由于我的应用程序的用户可以使用多种格式的背景(包括png),那么就加载图像使用...
  Bitmap *LoadABitmap( char *filename )
{
    WCHAR wname[1024];
    MultiByteToWideChar( CP_ACP, 0, filename, -1, wname, 1000 );
    Bitmap *loadBmp= new Bitmap( wname, FALSE );
    if( loadBmp->GetLastStatus() == Ok )
    ...
...可能导致几种格式之一.
  我们要的是一个已知的格式的“坚实的背景,所以我们重绘已经加载的位图到一个固定格式的新的位图上.


  PixelFormat32bppRGB似乎合适,因为这将消除任何可能存在的alpha(透明度)组件 - 然而这将不会导致最快的渲染.


  我们所需的是所有Alpha设置为固定的PixelFormatPARGB.
  在我的例子我仅仅:
    Bitmap *newBmp= new Bitmap( loadBmp->GetWidth(), loadBmp->GetHeight(),
                               PixelFormat32bppPARGB );
    Graphics *pGraphics= new Graphics( newBmp );
 
    pGraphics->Clear( 0xffffffff );  // clear to solid white
    
    Rect sizeR( 0,0,loadBmp->GetWidth(), loadBmp->GetHeight());
    pGraphics->DrawImage( loadBmp, sizeR, 0,0, 
                             (int)loadBmp->GetWidth(),
                             (int)loadBmp->GetHeight(), 
                             UnitPixel );
    delete pGraphics;
    delete loadBmp;
 
    return newBmp;


  更通常的,你可以绘制已经加载好的位图到一个RGB位图中,然后再绘制RGB位图到PARGB位图中.


  我做了相同风格的位图精灵,但这里我想保留任何透明度——只是让格式“PARGB”。


  设置图像选项


  接下来的设置一般来说是最快的:
  Graphics *pGraphics= Graphics::FromHWND( hwndMyPictureWindow, FALSE );
 
    pGraphics->SetCompositingMode( CompositingModeSourceCopy );
    pGraphics->SetCompositingQuality( CompositingQualityHighSpeed );
    pGraphics->SetPixelOffsetMode( PixelOffsetModeNone );
    pGraphics->SetSmoothingMode( SmoothingModeNone );
    pGraphics->SetInterpolationMode( InterpolationModeDefault );
 
    pGraphics->DrawImage( RenderBitmap, 0, 0 );
    delete pOutputGraphics;


   使用这些设置为“块传输'的位图,在1:1的比例,如上面的例子中,我们只是简单地复制位图到输出窗口。


  然后,如果你正在做任何缩放,精灵的渲染或者文本,结果将是有点令人失望的。


  对于正在绘制的精灵等,这些设置都是高质量和相当快的:
   pGraphics->SetCompositingMode( CompositingModeSourceOver );  // 'Over for tranparency
   pGraphics->SetCompositingQuality( CompositingQualityHighSpeed );
   pGraphics->SetPixelOffsetMode( PixelOffsetModeHighSpeed );
   pGraphics->SetSmoothingMode( SmoothingModeHighSpeed );              
   pGraphics->SetInterpolationMode( InterpolationModeHighQuality );   


  我认为不是,例如,InterpolationModeLowQuality 应该更快,但他不是(不要问我为什么!).
  
  最快的设置对于正在绘制的透明的精灵,如果你可以处理一些边缘效应:
    pGraphics->SetCompositingMode( CompositingModeSourceOver );
    pGraphics->SetCompositingQuality( CompositingQualityHighSpeed );
    pGraphics->SetSmoothingMode( SmoothingModeNone );
    pGraphics->SetPixelOffsetMode( PixelOffsetModeHalf );
    pGraphics->SetInterpolationMode( InterpolationModeNearestNeighbor );


  注:
  其中的一些设置是相互关联的,InterpolationModeNearestNeighbor仅仅在你有PixelOffsetModeHalf设定时是最快的。
  
  只是一个警告:PixelOffsetModeHalf 有一些其他的效应-GetVisibleClipBounds()将返回 {1,1,X,Y} ,而不是 {0,0,X,Y},这将导致LockBits()失败.


  对于缩放一整个位图到另外一个,我用
 // set quality for scaling
    pGraphics->SetCompositingMode( CompositingModeSourceCopy );
    pGraphics->SetCompositingQuality( CompositingQualityHighSpeed );
    pGraphics->SetPixelOffsetMode( PixelOffsetModeHighSpeed );
    pGraphics->SetSmoothingMode( SmoothingModeHighSpeed );
    pDestGraphics->SetInterpolationMode( InterpolationModeHighQuality );
 
    if( g_RenderFastest )  // global flag to render fastest, but reduce quality
    {
        pGraphics->SetInterpolationMode( InterpolationModeDefault );
        pGraphics->SetSmoothingMode( SmoothingModeNone );
        pGraphics->SetPixelOffsetMode( PixelOffsetModeHalf );
    }


  为了完整性,这里有我对于 正在绘制的文字DrawString()的设置:
    pGraphics->SetCompositingMode( CompositingModeSourceOver );
    pGraphics->SetCompositingQuality( CompositingQualityHighSpeed );
    pGraphics->SetInterpolationMode( InterpolationModeHighQuality );
    pGraphics->SetPixelOffsetMode( PixelOffsetModeHighSpeed );
    pGraphics->SetSmoothingMode( SmoothingModeNone );
    // Note: TextRenderingHintClearTypeGridFit looks real crap
    //       if we're drawing onto a transparent object
    //       but now we're not... anyhow, this is OK:
    pToGraphics->SetTextRenderingHint( TextRenderingHintAntiAliasGridFit );


  什么是不该做的
  不要混合位图格式
  渲染一个ARGB位图到一个RGB位图10倍慢于两张PARGB位图.通常的,似乎总是ARGB导致GDI+在内部做了预乘吃的CPU。
  
  想都别想线程


  我提到这点是因为我想...(我的app事实上需要显示在一个机器的4个显示器上)代码运行得很好,但GDI +不是为多线程设计的,如果你获得的临界区是正确的,几乎都是正常顺序渲染的。


  参阅MSDN中关于 Gdi+安全方面的考虑,他最终是正确的(in a locked filing cabinet marked "Beware of the leopard")


  猜测...
  
  The options available are not obvious, so if you're doing some investigation, you must profile your code to see what effect each of 'em has. Guessing doesn't work, what may sound like a faster/less quality option probably isn't.


  The End


  That's the lot, hope it's of some use to someone.
 
  Yours,
  Tony Wilk
 
  [mail at tonywilk dot co dot uk]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值