Rendering fast with GDI+ - What to do and what not to do!

原文:http://www.codeproject.com/Tips/66909/Rendering-fast-with-GDIplus-What-to-do-and-what-no.aspx
Everyone knows GDI+ is generally slow in rendering, what is not so obvious is what combination of settings is the fastest.I have an app which renders a lot of items, which may be drawn or are bitmap-sourced 'sprites', onto a full page (usually 1024x768). The first attempts ran at around 3...
Everyone knows GDI+ is generally slow in rendering, what is not so obvious is what combination of settings is the fastest.
 
I have an app which renders a lot of items, which may be drawn or are bitmap-sourced 'sprites', onto a full page (usually 1024x768). The first attempts ran at around  3 frames/sec - with the speedups noted here I got the rate upto  41fps.
 
My application roughly does the following:
 
    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
    }
 
What to do 
Always use PixelFormat32bppPARGB

That's pre-multiplied Alpha, even though the particular image or Bitmap may not have any Alpha.
 
Since the user of my app can use several formats for a background (including .png), then just loading the image using...
 
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 )
    ...
 
...could result in one of several formats. 
What we want is a 'solid' background in a known format, so I redraw the loaded bitmap into a new bitmap with a fixed format.
 
PixelFormat32bppRGB would seem appropriate as this would remove any alpha (tranparency) component which might be present - however, this will not result in the fastest rendering. 
 
What we want is  PixelFormatPARGB with all the Alpha set to 'solid'.
In my case I just:
 
    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;
 
More generally, you could draw the loaded bitmap into an RGB bitmap and then draw the RGB bitmap into a PARGB bitmap.
 
I do the same sort of thing for the sprite bitmaps, but here I want to preserve any transparency - just get the format to be 'PARGB'.
 
Set the Graphics options

The following settings are generally the fastest:
 
    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;
 
Use these settings for 'blitting' bitmaps at 1:1 scale, as in the above example we're simply copying the bitmap to the output window.
 
However, the results will be somewhat disappointing if you are doing any scaling, rendering of sprites or text.
 
For drawing sprites and such, these settings are good quality and reasonably fast:
 
   pGraphics->SetCompositingMode( CompositingModeSourceOver );  // 'Over for tranparency
   pGraphics->SetCompositingQuality( CompositingQualityHighSpeed );
   pGraphics->SetPixelOffsetMode( PixelOffsetModeHighSpeed );
   pGraphics->SetSmoothingMode( SmoothingModeHighSpeed );              
   pGraphics->SetInterpolationMode( InterpolationModeHighQuality );   
 
Do NOT think that, for example,  InterpolationModeLowQuality should be faster... it isn't (don't ask me why!).
 
The  fastest settings for drawing sprites with transparency, if you can handle some edge effects, are:
 
    pGraphics->SetCompositingMode( CompositingModeSourceOver );
    pGraphics->SetCompositingQuality( CompositingQualityHighSpeed );
    pGraphics->SetSmoothingMode( SmoothingModeNone );
    pGraphics->SetPixelOffsetMode( PixelOffsetModeHalf );
    pGraphics->SetInterpolationMode( InterpolationModeNearestNeighbor );
 
Note:
Some of these settings are interrelated,  InterpolationModeNearestNeighbor is only the fastest if you have PixelOffsetModeHalf also set.
 

Just a word of caution: PixelOffsetModeHalf does have some other effects - GetVisibleClipBounds() will return {1,1,X,Y} rather than {0,0,X,Y}, which will cause LockBits() to fail.

 
For scaling one whole bitmap into another, I use:
 
    // 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 );
    }
 
For completeness, here's what I set for drawing text with  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 );
 
What not to do

Don't mix bitmap formats

Rendering an ARGB bitmap onto an RGB bitmap can be slower by more than a factor of 10 compared to two PARGB bitmaps. Generally, it seems that ARGB always causes GDI+ to internally do a load of pre-multiplying and eats the CPU.
 

Don't even think about threads

I mention this 'cos I tried... (my app actually needs to output to 4 monitors on a single machine) the code worked fine, but GDI+ is not designed for multithreading and at best, if you get the CRITICAL_SECTION's right, almost renders sequentially anyway.
 
See the notes in MSDN under GDI+ Security Considerations, it's right there at the end (in a locked filing cabinet marked "Beware of the leopard").
 

Guess...

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]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
cd C:\Program Files\FlightGear fgfs --fg-root=C:\Program Files\FlightGear\data --aircraft=ufo --in-air --fdm=null --telnet=5501 --telnet=5502 --telnet=5503 --disable-ai-traffic --disable-real-weather-fetch --disable-random-objects --disable-terrasync --disable-clouds --disable-sound --disable-panel --disable-hud --disable-specular-highlight --timeofday=noon --prop:/sim/rendering/multi-sample-buffers=1 --prop:/sim/rendering/multi-samples=2 --prop:/sim/rendering/draw-mask-clouds=false --prop:/sim/rendering/draw-mask-terrain=true --prop:/sim/rendering/draw-mask-objects=true --prop:/sim/rendering/draw-mask-lights=true --prop:/sim/rendering/draw-mask-internal=true --prop:/sim/rendering/draw-mask-cockpit=true --prop:/sim/rendering/draw-mask-effects=true --prop:/sim/rendering/draw-mask-overlay=true --prop:/sim/rendering/draw-mask-world=true --prop:/sim/rendering/draw-mask-panel=true --prop:/sim/rendering/draw-mask-vr=true --prop:/sim/rendering/draw-mask-2d=true --prop:/sim/rendering/draw-mask-3d=true --prop:/sim/rendering/draw-mask-sky=true --prop:/sim/rendering/draw-mask-shadows=true --prop:/sim/rendering/draw-mask-cabin=true --prop:/sim/rendering/draw-mask-weather=true --prop:/sim/rendering/draw-mask-stereo=true --prop:/sim/rendering/draw-mask-internal-cockpit=true --prop:/sim/rendering/draw-mask-internal-windows=true --prop:/sim/rendering/draw-mask-internal-instruments=true --prop:/sim/rendering/draw-mask-internal-overlay=true --prop:/sim/rendering/draw-mask-internal-effects=true --prop:/sim/rendering/draw-mask-internal-lights=true --prop:/sim/rendering/draw-mask-internal-world=true --prop:/sim/rendering/draw-mask-internal-panel=true --prop:/sim/rendering/draw-mask-internal-3d=true --prop:/sim/rendering/draw-mask-internal-sky=true --prop:/sim/rendering/draw-mask-internal-cabin=true --prop:/sim/rendering/draw-mask-internal-weather=true --prop:/sim/rendering/draw-mask-internal-stereo=true --prop:/sim/rendering/draw-mask-internal-shadow=true --prop:/sim/rendering/draw-mask-internal-stall=true --prop:/sim/rendering/draw-mask-internal-aoa=true --prop:/sim/rendering/draw-mask-internal-thermal=false --prop:/sim/rendering/draw-mask-internal-ice=false --prop:/sim/rendering/draw-mask-internal-glass=true --prop:/sim/rendering/draw-mask-internal-dead=true --prop:/sim/rendering/draw-mask-internal-reflection=true程序显示错误unknown command-line option: enable-hud-2d怎么解决
05-10

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值