14

We need to optimize the text rendering for a C# Windows Forms application displaying a large number of small strings in an irregular grid. At any time there can be well over 5000 cells visible that update 4 times per second. The font family and size is consistent across the cells, though the color may vary from cell to cell, as will bold/italic/plain.

I've seen conflicting information on the web about TextRenderer.DrawText vs. Graphics.DrawString being the fastest/best, which reduces to a GDI vs. GDI+ comparison at the Win32 level.

I've also seen radically different results on Windows XP vs. Windows Vista, but my main target is Windows XP. Articles promising great advances under WinFX and DirectX 10 aren't helpful here :-)

What's the best approach here? I'm not afraid of introducing a small C++/CLI layer and optimizing device context handling to squeeze out more performance, but I'd like some definitive advice about which direction to take.

EDIT: Thanks for the initial responses. I'll be trying a combination of background bitmap rendering and sticking with the GDI equivalent calls.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dave Moore
  • 4,397
  • 7
  • 25
  • 34

6 Answers6

6

A Microsoft developer has posted a GDI vs. GDI+ Text Rendering Performance article on his blog which answers the raw speed question: on his system, GDI DrawText was about 6 times faster than GDI+ DrawString.

If you need to be a real speed demon, TextOut is faster than DrawText, but you'll have to take care of clipping and word-wrapping yourself. ExtTextOut supports clipping.

GDI rendering (TextRenderer) will be more consistent with other parts of Windows using GDI; GDI+ tries to be device-independent and so some spacing and emboldening are inconsistent. See the SQL Server 2005 Surface Area Configuration tool for an example of inconsistent rendering.

Mike Dimmick
  • 9,662
  • 2
  • 23
  • 48
  • The sample app in the blog link is the one I used when I saw the big difference between Vista and XP - on my Vista PC, GDI and GDI+ were equal, while on XP I see the 6x difference the author mentions... This is probably a Vista driver issue, but highlights some of the difficulties here - thanks! – Dave Moore Sep 16 '08 at 12:18
  • 1
    Historical note: ExtTextOut used to be the quickest way to draw a solid rectangle on some cards/drivers :) – Roger Lipscombe Jan 23 '09 at 16:37
  • Unfortunately the article mentioned no longer seems to exist, here is a backup: http://blogs.msdn.com/cjacks/archive/2006/05/19/602021.aspx – NiKiZe Jan 08 '20 at 15:01
  • Not even the backup exists anymore. Microsoft are frantic about leaving about old advice as they try to hoard and steer their developer base towards their intended "replacement APIs". Their preferred tool to do so is "obsolete" previous content as if Windows isn't de-facto backwards compatible. Anyway, here's the backup of the backup by a party that specifically doesn't remove content if they can avoid it: https://web.archive.org/web/20100128095845/http://blogs.msdn.com/cjacks/archive/2006/05/19/602021.aspx – Armen Michaeli Mar 15 '23 at 18:06
4

5000+ text rendering is slow even with GDI, especially if you need scrolling. Create a separate rendering thread and notify the UI thread every 200 ms and bitblt the current results. It gives a smooth user experience.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
3

On my Windows 7 64 Bit system TextOut is even a bit slower than DrawString! TextRenderer.DrawText is much slower than DrawString.

fritz
  • 377
  • 1
  • 5
  • 11
2

GDI is faster at drawing in general that GDI+. I worked on a project that had to draw thousands of lines and text strings and switching from GDI+ to GDI made a significant performance improvement. That was using Windows XP so I cannot comment on Vista. I would also recommend using double buffering for your drawing to also improve performance. Create a compatible off screen bitmap and reuse that each time you need to draw.

Phil Wright
  • 22,580
  • 14
  • 83
  • 137
2

Creating a C++/CLI interop class to do the drawing in native code will result in crazy-fast drawing. We've witnesses this and measured it.

If you're not up to doing that, we've found graphics.DrawString is just slightly faster than than TextRenderer.DrawText.

Judah Gabriel Himango
  • 58,906
  • 38
  • 158
  • 212
0

From recent experience, fastest text output is achieved via ExtTextOut with ETO_GLYPH_INDEX flag. This comes at a price, and it’s that you aren’t printing characters anymore, but font glyphs directly. This means that you need to translate your regular character strings to glyph indexes strings prior calling ExtTextOut, either by calling GetCharacterPlacement everytime, or calling this function just once to build your own translation table, that will be valid until a new font is selected in the DC. Remember that glyph indexes are 16bit, so you can store them in a Unicode string and call ExtTextOutW version regardless of original string character size.

Chungalin
  • 420
  • 4
  • 5