GDI+ performance tricks [closed]

为君一笑 提交于 2020-06-24 04:02:18

问题


Does anyone know of any reliable (and, hopefully, extensive) books/websites that discuss GDI+ performance (beyond the obvious)?

For example, I recently came across this excellent experiment. I also recently noticed that Graphics.FillPath() is way, way faster than Graphics.DrawPath(). I'd love to know what other vital bits of information I'm missing.

Goodwill, David


回答1:


Hmmm. There is no gain in knowing that FillPath is faster than DrawPath if you need to draw the path's outline!

The best way to optimise GDI+ is exactly the same as for any other code: Firstly, don't optimise it. Instead:

  • Start by writing it so it simply works, and then decide if it is actually too slow.
  • Then examine your "algorithm":
    • Simplify what you are drawing (reduce the number of things you are drawing) and it will go faster (and in most cases will look better for having reduced the clutter).
    • Are you drawing your entire display every time, or are you using the clip rectangle to avoid drawing parts of the image that don't need to be updated?
    • Examine how you draw things. Are you creating and destroying resources (e.g. brushes and pens) for every redraw? Cache them in a member variable. Are you over-drawing the same pixel multiple times? (e.g. drawing the background then drawing a bitmap on top then drawing a rectangle on top of that - perhaps you can avoid some of these redraws). Are you drawing a curve using 100 polygon segments when it looks good enough with only 10 segments? When the window scrolls, do you get the OS to move the existing image so you only need to redraw the newly exposed strip, or do you waste time redrawing the entire window?
    • Are you using transforms or are you doing lengthy positioning calculations in your code?
    • Check any loops and make sure you move as much code out of them as possible - precalculate values you use within the loop, etc. Make sure your loops iterate over your data in a cpu-cache-friendly direction/manner where possible.
    • Is there anything in your data that you are processing during the redraw? Perhaps some of this can be precalculated or organised in a more rendering-optimal form. e.g. Would a different type of list be faster to enumerate your data from? Are you processing 1000 data items to find the 10 you need to draw?
    • Can you achieve the same look with a different approach? e.g. You can draw a chess board by drawing 64 squares in alternating black and white. It might be faster to draw 32 black and then 32 white squares so you avoid state changes between the rects. But you can actually draw it using a white background clear, 4 black rectangles, and 4 XOR rectangles (8 rects instead of 64 => much faster algorithm).
  • Are there parts of the image that don't change often? Try caching them in an offscreen bitmap to minimise the amount you have to "rebuild" for each redraw. Remember that you can still render the offscreen bitmap(s) and then layer graphics primitives on top of them, so you may find a lot more "static" image area than you realise.
  • Are you rendering bitmap images? Try converting them to the screen's pixel format and cache them in that "native" form rather than making GDI+ convert them every time they are drawn.
  • Turn down the quality settings if you are happy with the trade-off of lower quality for faster rendering

Once you have done all these things you can start looking for books about optimising the rendering. If it is still too slow, of course. Run a profiler to find out which parts of the rendering are the slowest.

Where you think you might be able to make gains, try different ways of rendering things (e.g. it's likely that Graphics.Clear() will be much faster than filling the background with FillRectangle()), or different rendering orders (draw all the things of one colour first, in case state changes cost you time - batching operations is often very important with modern graphics cards. A single call that draws multiple polygons is usually faster than making multiple single-polygon calls, so can you accumulate all your polys into a deferred-rendering buffer and then commit them all at the end of your rendering pass?)

After that, you may have to look at using GDI or DirectX to get closer to the hardware.




回答2:


This may not be the answer you are looking for, but consider not using GDI+ at all. I had to recently rewrite the rendering stack of a 2D-CAM application, and the most important requirement was to get good anti-aliased lines fast (the anti-aliasing was what prompted us to rewrite the existing GDI renderer).

Here are some results I got with a render of 200 items (each item is itself some lines and small filled-shape markers). These are frame rates (on Windows 7), so higher is better:

200 items: GDI=51, GDI+=20, D2D=59, WPF=33, GL=59.

(D2D is Direct2D, GL is OpenGL). Already you can see that GDI+ is trailing. WPF is perhaps handicapped in being a retained mode API, but then OpenGL is double-buffered as well and looks just as smooth.

At 1000 items, the difference is more marked:

GDI=23, GDI+=5, D2D=17, WPF=2, GL=40.

That's right, WPF has fallen to 2 FPS by now, and GDI+ is crawling along at 5 FPS. So consider D2D, or simply go back to OpenGL. That's what we are using now and 3 months into the rewrite, I think we made the right choice. The programming model itself is a lot cleaner than D2D seems to be.

Note that the WPF render we are using is highly optimized; no callbacks, no events, no binding. We just get a DrawingContext and draw everything on it each frame using the lowest level primitives so there is no event overhead.

If you are interested, let me know, and I can send you the test suites I used so you can fiddle around with that.

(One reason I might steer clear of GDI+ is that it is unlikely to ever be hardware accelerated).



来源:https://stackoverflow.com/questions/1690422/gdi-performance-tricks

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!