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.
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.
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.
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.
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.
On my Windows 7 64 Bit system TextOut is even a bit slower than DrawString! TextRenderer.DrawText is much slower than DrawString.
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.
Related
I've been working on a C#/GDI graphical app for a couple years. I've spent a lot of time optimizing the drawing code. I am drawing to the screen by invalidating a PictureBox control about 10 times a second, and by leveraging subsequent OnPaint event that occurs when Windows triggers it. The OnPaint event gives me access to the Graphics object via the PaintEventArgs param.
Per frame: I draw hundreds of lines, hundreds of rectangles, and I call the Graphics.DrawString() method hundreds of times as well.
I started putting together a SharpDX project in hopes I could draw more 2D elements, and draw faster to the screen. I set up 2 test projects that draw the same 2D elements on the screen using GDI and using SharpDX. I used a C# StopWatch object to detect how long it was taking to draw all the 2D elements. So far, I have not noticed any speed improvement when drawing with SharpDX. Both GDI and SharpDX average about 20millis per draw.
How much of a speed improvement should I expect by using SharpDX? And which portion of the rasterization is supposed to make it faster than GDI?
I worked on a Windows Forms app where the "rendering system" was pluggable, and I initially wrote two rendering systems: one in GDI+, and one in Managed DirectX (a .NET wrapper around DirectX, similar to SharpDX). Because I was doing a lot of drawing of images at arbitrary scales, Managed DirectX blew GDI+ out of the water for our use case. Drawing code that used 1-pixel-wide lines was also very fast in Managed DirectX. Thick lines were much slower than single-pixel lines, because they were actually rendered as triangle strips (which can be drawn quickly by the GPU) whose coordinates had to be calculated by the CPU, and the geometry was complicated by segment joints (which were rounded, if I remember right). Fortunately, in our application we didn't need to draw curves, but those would have to be approximated by small line segments (for single-pixel widths) and triangles (for anything thicker).
It's things like CPU-based approximation and triangulation that slow a Direct3D app down. 3D games use pre-calculated meshes and make use of vertex buffers on the GPU to avoid moving data back and forth from the CPU to GPU. I don't have any data comparing speeds between GDI+ and DirectX, but these are some things to consider.
Direct2D takes a bit of getting used to, but once you get it up and running properly I can promise that you will never look back. I used it to migrate a very large project which was based on DirectDraw with GDI+ Interop and saw a huge performance increase as well as better stability and a more satisfying development experience.
It has received a lot of negative press about performance, particularly when it was first introduced but if you hook it up to a DXGI swap chain (which is very easy to do) and keep your code sensible, the benefits will be most clear.
SharpDX is the right choice and it will only get faster in the near future, with SSE/SIMD driven primitives just around the corner.
I need to speed up my image viewer, and wondering if I should be looking into creating my own DirectX control to do so.
My image viewer displays medical images. They can be pretty large. We're talking 55mb when it comes to mammography. The pixel data is 16bit greyscale stored in a ushort array. Without getting into the gory details, my current approach is loading the pixel data into an ImageSource, and using the WPF Image control.
I've never done anything with DirectX. Is it worth diving into it? Would it be any faster than the native WPF stuff? If so how significantly? Or, should I just forget about DirectX and look into areas where I can improve my current approach?
Before somebody says so, I know WPF utilize DirectX. I'm wondering If removing the WPF layer and writing the DirectX myself will improve performance.
I have some experience drawing multi-gigabyte satellite and chart imagery. Working with imagery around 55MB should probably work okay even without trying to optimize it too much. You haven't really given enough detail to recommend one alternative over the other, so I will give my opinion on the pros and cons.
Using 2D windows APIs will be the simplest to implement and should always be fast enough if you don't need to rotate and simply want to display an image and zoom and pan around. If you treat it as one large image the performance will not be as good when you zoom out if you are drawing with halftoning to give a nice smooth image. This is because it will effectively have to read all 55mb of image every time it draws.
To get around this performance issue you can make multiple bitmaps, effectively mip-mapping your image. As you zoom out you can pick the reduced resolution image closest to the resolution you are trying to draw . If you are not familiar with mip-mapping here is a Wikipedia link:
http://en.wikipedia.org/wiki/Mipmap
Implementing it with DirectX will be 10x as difficult. Different graphics hardware has different maximum texture sizes. Most likely you will need to break your image up in to multiple textures to draw and you will also have to keep track of render states, viewing matrices, etc.
However, if you do use DirectX, you can implement lots of real-time photo adjustments You can do real-time rotation by simply adjusting view matrices. You can do real-time contrast, brightness, gamma, and sharpness easily in a pixel shader.
There are two other API's I might suggest. If you are willing to limit yourself to Vista or later then Direct2D would be a little simpler than Direct3D. Also if you ever will need to implement it on a non-windows platform I would suggest using OpenGL instead. My current project is in Direct3D because a few years ago when we started it OpenGL was falling behind and I didn't forsee the popularity of Android devices. I now wish we had used OpenGL instead.
Try profiling to see where WPF is spending its time. Are you displaying the images at their native resolution? If not it might be worthwhile to do some preprocessing and create 1/2 resolution versions.
I'm developing depth processing (Xbox Kinect, Asus Xtion, etc) applications using OpenNI.
I need a really simple and fast way of drawing on a Windows form when new depth data is available from the sensor (30 or 60 fps depending on resolution).
Currently I'm invalidating a double-buffered panel from a seperate thread when the data becomes available, and then setting pixels of a bitmap in the panel's paint method, yielding a predictably awful 5fps.
System.Drawing.Graphics seems to lack a fast way to set individual pixels, unless anyone can instruct otherwise.
I literally just need to set pixel colours, so would like to avoid using third party high speed rendering APIs if possible, and ideally use something as native as possible.
Does anyone have any suggestions?
If you're using Bitmaps, then you should use LockBits and UnlockBits to access the data directly in memory. In C#, you can get some extra performance by using unsafe code blocks and pointers.
See this link for more information: http://web.archive.org/web/20150227183132/http://bobpowell.net/lockingbits.aspx
image.SetPixel() is very slow when you are replacing many pixels per frame and you need many frames per second.
It will be a lot faster when you use a WriteableBitmap and call CopyPixels
This way you can fill the array with pixel data using multiple threads and simply blit the array to the image in a single call.
EDIT
Note that WriteableBitmap is a WPF class. If you are bound to WinForms you might need to create your own implementation. WPF/WinForms/GDI interop: converting a WriteableBitmap to a System.Drawing.Image?
You could try my LINQ image processing library to work with your "buffer-bitmaps". It uses an accessible LINQ syntax but is very performant for large bitmaps. It is available on Nuget as a single file include in your project.
Hope that helps!
I have a c# application that does text rendering, something on par with a simple wysiwyg text editor.
I'm using TextRenderer.DrawText to render the text to the screen and GetTextExtentPoint32 to measure text so I can position different font styles/sizes on the same line.
In Vista this all works fine. In XP however, Arial renders differently, certain characters like 'o' and 'b' take up more width than in Vista. GetTextExtentPoint32 seems to be measuring the string as it would in Vista though, with the smaller widths. The end result is that every now and then a run of text will overlap the text preceding it because the preceding text gets measured as smaller than it actually is on the screen.
Also, my text rendering code mimics ie's text rendering exactly (for simple formatting and english language only) and ie text rendering seems to be consistent between vista and xp - that's how I noticed the change in size of the different characters.
Anyone have any ideas about what's going on?
In short, TextRenderer.DrawText and GetTextExtentPoint32 don't match up in xp for Arial. DrawText seems to draw certain characters larger and/or smaller than it does in Vista but GetTextExtentPoint32 seems to be measuring the text as it would in Vista (which seems to match the text rendering in ie on both xp and vista). Hope that makes sense.
Note: unfortunately TextRenderer.MeasureString isn't fast or accurate enough to meet my requirements. I tried using it and had to rip it out.
Thanks for taking the time to respond Adrian.
My understanding is that TextRenderer.DrawText actually wraps a call to GDI, bypassing GDI+ text rendering completely. That's why I was confused about GetTextExtentPoint32 not jiving with the output.
I think I found the issue though. It turns out if you set Graphics.TextRenderingHint to System.Drawing.Text.TextRenderingHint.ClearTypeGridFit, or possibly other values, it causes some characters in some fonts to increase or decrease in size. This seems to be true more in XP than in Vista. I haven't seen it happen at all in Vista. Anyway, it looks like GetTextExtentPoint32 is either not capable of recognizing the difference or I am not setting some kind of flag when I make the call.
My solution is to just use the system default textrenderinghint settings.
Actually both TextRenderer's DrawText and MeasureString based on DrawTextEx (and this is User32, not Gdi function).
So you can consider using native marshalled calls to this function instead of MeauseString, because it doing some additional calculations (especially if you are using function override without HDC).
Also maybe this post will be helpful for you too.
I'm not a C# guy, but I believe the .NET rendering is built on top of GDI+. I'm also pretty sure that GDI+ does its own font rendering which uses unhinted scaling.
GetTextExtentPoint32, on the other hand, is part of GDI. GDI uses sizing hints, which can affect the width of characters depending on the font size. In general GDI text at small sizes will look a little bit getter, but it won't scale linearly.
You have to consistently use one model or the other to get pixel-perfect results.
There may be other factors in play that may make this more obvious on XP than on Vista, but the fundamental problem exists in both. These other factors might include DPI settings, DPI scaling, ClearType or antialiasing settings, font-linking (if you're mixing scripts from other alphabets), font substitution (especially in printing), and possibly even different versions of Arial. I'm not even sure GDI+ uses the same default mapping mode as GDI.
Also see my answer on print preview.
I'm trying to visualise a graph and allow people to play with it. I found the excellent Graph# library that can create an initial layout so that part is covered. Now I need to make a control that actually draws it and provides the necessary interactivity.
Graph# comes with a nice visualiser itself, however I don't like it because it is written in WPF (while my app is WinForms), and because I want to add some more interactivity options, which would require quite a remake of it anyway.
The graphs I'm drawing will routinely be pretty large, at about 100 vertices and the same amount of edges (the graphs will be trees 99% of time). That means that the resulting rendering can be up to 2000px by 2000px and even more. The users should be able to zoom in and out, scroll, highlight and drag vertices and edges, and get some popups with additional info when hovering the cursor above a vertex.
I'm worried that the standard System.Drawing might not be able to deliver a decent speed for this. I would like the dragging/zooming/scrolling operations to be smooth, and the popups should open with a little animation as well. Something like 20fps should be a necessity.
I know I can try to speed things up by pre-rendering a lot of the elements and keeping them as bitmaps in memory - but that would probably take up lots of RAM, and I'm still not sure if it would deliver the necessary performance.
What are your thoughts?
"Premature optimization is the root of all evil"
GDI+ can be great for your needs. Don't go and buy 3rd party libraries before you know you even need them.
I've done a thousand polygons on a 1000x800 pixel bitmap and redrawn it completely at over 100 frames per second, using just GDI+
That being said, if you have a lot of drawing to do, and your resolution is big.. Some of the 3rd party drawing libraries can go WAY beyond what managed GDI is capable of.
I recommend leaving Graph# alone, and just hosting it in your Windows Forms application.
The performance you will receive will be much better than trying to reimplement it in System.Drawing.
GDI+ will be plenty fast enough for what you're doing, especially if (as it sounds from your description) everything you're drawing is rectangles and vertical/horizontal lines. Polygons and non-linear shapes are a bit slower, but not much (the speed difference is partially dependent on the SmoothingMode of your Graphics object). Drawing cached Bitmaps with resizing is also quite fast, although it can slow down significantly if you use a high-quality InterpolationMode setting.
As a benchmark, I wrote a .Net Compact Framework GPS application for Windows Mobile that rendered about 10,000 lines on the screen in realtime. This only achieved a frame rate of a few frames per second, but the processing power on a Smartphone is, of course, way less than a modern PC.