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.