How to: High performance graphics in WPF
Microsoft DPE: “WPF is ever best super performance oriented technology for creating hyper multi point graphs, using parallelism and huge in-memory persistence vector scrounged math distributed calculations… And ever more with branded new Microsoft Windows Vista 7.
Client: Errr, well…. Let’s try to apply it for our VB program…
DPE: You can easily do it yourself, but it’d be better to call someone from Microsoft Consulting Services.
Client: Let it be…
MCS: Well. It’s too huge for WPF to scale… WPF uses a retained rendering system. It saves every little pixel and make you able scale and repaint very often without the composition system blocking on callbacks to your code. However, 1,000,000 retained pixels is too huge to scale…
Client: I want it scale. They promised… They told, it’ll scale. Make it to do what I want it to do!!!
MCS: Errr, well. Let it be!
This is very common dialog between DPE, MCS and clients. Sales men want it to do, what he need it to do. Client want it to do what sales men promised to do and Services men should make it to do what they both want it to do. Today we’ll speak about retained, lazy and loose models to produce large scale graphics.
First problem: multithreading
Even before we start to work, you should know, that we cannot create dependency objects in thread other, then current UI thread. We can use locks, mutexes, semaphores, however we still can not create Dependency Objects in other thread. In order to get rid of it, we’ll have to use INofityPropertyChanged implementation, instead of Dependency Objects. This means, no Dependency Properties.
So, we’ll start with following code (I’ll reuse nice code written by Luis Diego Fallas to create Mandelbrot Fractal set)
class FractsCollection : INotifyPropertyChanged
{
Second problem: rendering thread
Well, the problem is knows. There is only one UI thread. We wont it be only one, so we’ll use our own HostVisual by Dwayne Need to enhance the performance.
Third problem: Retained objects
Actually, this is not problem. This is feature. And it can be extremely useful if you want to retain layout. Let’s create a simple example: Dragon curve fractal. It has limited number of points, generated by well known final algorithm. So, we’ll create our own geometry, derived from Shape class. The fasted geometry is StreamGeometry, so let’s use it. First of all let’s create the class and save the array of points.
public class DragonShape:Shape
{
StreamGeometry dragonGeometry;
double _angle;
List<Point> Points;
Then we’ll generate the pattern
void GeneratePattern()
{
ThreadPool.QueueUserWorkItem(delegate
{
Move(5);
Turn(GetNextPoint * System.Math.PI / 180.0);
Then, by overriding DefiningGeometry property, create the fractal
protected override System.Windows.Media.Geometry DefiningGeometry
{
get {
using (StreamGeometryContext context = dragonGeometry.Open())
{
context.BeginFigure(Points[0], false, false);
context.PolyLineTo(Points, true, false);
}
return (Geometry)dragonGeometry.GetAsFrozen();}
}
Don’t forget to tell the shape, that geometry was changed
this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, (SendOrPostCallback)delegate
{
this.InvalidateVisual();
}, null);
Now, run it and we’ll have very nice vector fractal generated that can be easily resized and scaled. Here the result.
This method will work fine for 1,000, even 10,000 points. But after a while you’ll experience performance degradation. What to do? The client wants 10,000,000 (!) points (and in Winforms GDI+ it works for him)
Let’s try to understand why. Because it is not retain. It’s image! So, let’s use image to make the play fair.
The fastest BitmapSource is InteropBitmap. It has an ability to update itself from the memory section. That’s exactly what we’ll use
format = PixelFormats.Bgr32;
max = format.BitsPerPixel;
uint count = (uint)(sWidth * sHeight * format.BitsPerPixel / 8);
section = CreateFileMapping(new IntPtr(-1), IntPtr.Zero, 0×04, 0, count, null);
map = MapViewOfFile(section, 0xF001F, 0, 0, count);
pixels = new byte[count];
Marshal.Copy(pixels, 0, map, (int)count);
source = System.Windows.Interop.Imaging.CreateBitmapSourceFromMemorySection(section, (int)sWidth, (int)sHeight, format, (int)(sWidth * format.BitsPerPixel / 8), 0) as InteropBitmap;
ThreadPool.QueueUserWorkItem(delegate
{
while (true)
{
Generate();
}
});
To get the source to bind to we’ll get frozen image. Call Invalidate first to reread the source.
InteropBitmap source;
public BitmapSource Source
{
get
{
source.Invalidate();
return (BitmapSource)source.GetAsFrozen();
}
}
Now, when we ready to display we can just put pixels simultaneously (by using Parallel extension and PLINQ) and tell the WPF that our count and ImageSource property updated upon each pixel.
unsafe
{
uint* pBuffer = (uint*)map;
Parallel.For(0, (int)sHeight, delegate(int yi)
{
foreach (var p in from xi in Enumerable.Range(0, (int)sWidth).AsParallel()
let mappedX = xF(xi)
let mappedY = yF(yi)
let p0 = new TranslatePoint(xF(xi), yF(yi))
let function = constructor(p0)
select new
{
x = xi,
y = yi,
xD = mappedX,
yD = mappedY,
i = apply(function, p0)
.TakeWhile(
(x, j) => j < max && x.NormSquared() < 4.0)
.Count()
})
{
pBuffer[(int)(p.x + p.y * sWidth)] = (uint)(uint)((uint)0xFF << 24) |
(uint)(p.i << 16) |
(uint)(5*p.i <<|
(uint)(15*p.i); ;
count++;
FireUpdate();
}
});
}void FireUpdate()
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(“PixelCount”));
PropertyChanged(this, new PropertyChangedEventArgs(“Source”));
}
}
We done. Now let’s see how fast it can be to generate and display 10,000,000 live pixels (it’s about 16,000×16,00x32bit image) in screen. The maximum, I was able to get with my Dell Latitude D820 was 1,200,000 x 1,200,000 pixels indexed 4 bit image (it’s about 100,000,000 points) and my memory is over
Not bad, ah? So WPF scales and DPE are right? Not quite right, but let them to do their work and we’ll be behind to come all client’s dreams (and DPE’s promises) true.
Have a nice day and be good people. Now you can use WPF for drawing big number of points.
March 2nd, 2008 · Comments (17)
17 Responses to “How to: High performance graphics in WPF”
Leave a Reply
Discover other tags
My tools
- .NET Framework Detector
- Duplicate images finder
- Exchange Security Policy for Windows Mobile Devices Fix
- Gas Price Windows Vista SideBar gadget
- Israel Traffic Information Windows Vista SideBar gadget
- Localization fix for SAP ES Explorer for Visual Studio
- LocTester
- RTL and LTR in Windows Live Writer
- Silverlight controls library
- Snipping tool integration plugin for WLW
- USB FM receiver library
- Vista Battery Saver
- WebCam control for WPF
- Windows Live SkyDrive attachment for Windows Live Writer
- Wireless Migrator
- WPF Virtual Keyboard




January 1st, 2009 at 12:39 am
Hi
This is very intresting article.
Could you please upload the source?
Thanks
January 1st, 2009 at 12:39 am
Hi
I have the same problem as Nirupama.
I need to display 4000 objects and each object contain 100 polyline segments.
Could you please upload the source?
Any Help would be highly appreciated.
Thanks
Roman
January 1st, 2009 at 12:39 am
I tried to reproduce your code but it seems fairly impossible: too many things are missing. Is this meant to be a sample or are there lots of proprietary things so you can’t provide all the code?
January 1st, 2009 at 12:39 am
Nirupama, I think, that the best choice for you is InteropBitmap. It allows you to create and fully manage underlying image source. Seek for it in my blog
January 1st, 2009 at 12:39 am
Hi..
Thsi is a gentle reminder..for the above query…
Please do give in your inputs…That would be of great help..
Thanks and Regards,
Nirupama
January 1st, 2009 at 12:39 am
Hi,
Thanks a lot for the response..Writeable Bitmap fits really well in the scenario. Am able to create a smooth running graph at high rate using the writeable bitmap..
Another challenge on that is whether would I be able to Scale the graph using some smart way rather than performing basic bitmap scaling.
Also when I am asigning the bitmap source from writeable bitmap as a source to Image, the changes in the dPI value does not reflect,, are the wPF elements like Image or canvas the culprits… I need to change the DPI settings of the image from the default of 96..
Thanks in Advance
Nirupama
January 1st, 2009 at 12:39 am
Nirupama, if there is user interaction (mouse over, etc), you probably should check WritableBitmap. If not, use InteropBitmap, but it tiers
January 1st, 2009 at 12:39 am
Hi,
I wanted to develop a WPF project that has very intense performance requirements, and I thought it was best to consult you on this before designing the app.
The application would be rendering data obtained from a medical hardware as charts. For this, the requirements are:
1) Requires rendering of almost 250 points every 4 milliseconds in a chart (to be connected by a line or Bezier curve). The rendered points will also have a spectrum of colors (as in a heatmap).
2) The rendered points would move when new data is pumped by the hardware and rendered (as in a ECG)
3) At any given point there could be over a 150,000 moving points on the chart (because the chart window would display data of 3-5 seconds).
4) Also later we would like to retain the history of data points of past 60 seconds or so.
5) There could be upto 12 such chart displays running parallel at the same time in a window on the application.
I seek your thoughts on what could be the best approach for rendering these points and animating them. Some kind of selectively invalidating the UI would be desirable here. Also what are the recommended options for storing this much data for history purpose. The problem demands something at a very low level in the WPF stack.
How much workable would it be to draw a very specific curve using interop bitmap method. Given the requirement what will suit best?
Any Help would be highly appreciated,
Thanks in Advance
January 1st, 2009 at 12:39 am
Hi
This is very intresting article.
Could you please upload the source?
Thanks
January 1st, 2009 at 12:39 am
This is really hot struff. Reminds me of Benoit Mandelbrot's coffe-table book on fractals. I hope you'll write some more and include downloadable sample Visual Studio soln.
January 1st, 2009 at 12:39 am
Eric, WritableBitmap is good candidate for such work, however, it still much slower, then InteropBitmap, that, actually, refreshes itself directly from memory section.
January 1st, 2009 at 12:39 am
Tamir,
I'm one of the people regularly complaining about the need to solve the million-point problem in WPF, so I am thrilled to have another approach to try, so thank you. I'm curious, though, if you know what relationship there might be between your approach with InteropBitmap and the new and improved WriteableBitmap class that is coming in beta in late Spring in the next update to WPF?
Thanks,
Eric
January 1st, 2009 at 12:39 am
Pingback from Daily Bits – March 3, 2008 | Alvin Ashcraft’s Daily Geek Bits
January 1st, 2009 at 12:39 am
You’ve been kicked (a good thing) – Trackback from DotNetKicks.com
March 16th, 2011 at 5:40 am
Hello!
Please could you upload the source code? I can’t seem to put together all the peaces of the code you posted and I think that would help a LOT of people!
Thank you!
January 7th, 2012 at 6:24 pm
Code?
February 14th, 2012 at 6:22 am
[...] for Tamir Khason for pointing me in the right direction for creating an interop bitmap. Thanks to Dwayne Need for [...]