Friday, 1 August 2008

Increasing WPF rendering performance

Please Note:
This article has been updated and can be found on my new Blog at MrPfister.com


----


Lately I have been coding a lot using WPF and one of the main area's I've been involved in is the 3D rendering, however its easy to find out that there are quite a lot of performance hits across the board when it comes to WPF.

One of the biggest hits is the way it renders, normally WPF will try to do as much as possible using Hardware Graphics Acceleration however certain functionality will cause it to fall back to software based Rasterizing; such as certain BitmapEffects. So I guess there is to limit yourself to features that are fully hardware assisted.

So once everything is using the hardware there still can be slowdowns and stutters caused elsewhere in your program, one of the big issues I've had lately is how WPF handles ImageBrush, when loading an image it will load the entire image which if your rendering a 10mp digital photo can cause a huge slowdown if you're using multiple instances of different brushes. There are a few tricks to start off with, firstly by altering the RenderOptions of the ImageBrush to increase its performance. Below is a sample of code that alters the RenderOptions of the brush _PictureBrush.

RenderOptions.SetCachingHint(_PictureBrush, CachingHint.Cache);
RenderOptions.SetBitmapScalingMode(_PictureBrush, BitmapScalingMode.LowQuality);


However this may not be enough as the pictures are still being loaded into memory, therefore to reduce their footprint, what we want instead to do is to produce and use instead a thumbnail of the original image.

public BitmapImage CreateThumbnail(Uri Source, int PreferredWidth)
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.DecodePixelWidth = PreferredWidth;
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = Source;
bi.EndInit();
return bi;
}

This code takes a Uri Source and creates a thumbnail of the PeferredWidth, thus if you use this method you can drastically reduce the memory requirements of handling images as Brushes.

1 comment:

Steve said...

Since you've mentioned that you have done a lot of work in the area I hope you can answer a question. Is it possible to combine both techniques? I would like to use RenderOptions.SetBitmapScalingMode(_PictureBrush, BitmapScalingMode.LowQuality); because this will make my thumbnail size images appear a lot clearer, but at the same time I would like to limit memory usage by using DecodePixelWidth.
In my tests so far this did not give me the desired results. If I have DecodePixelWidth turned on my images are blurry, but memory usage is low and if I turn it off, the images are a lot clearer but memory usage is up (by a lot!).
Would be great if you could give me few pointers...
- Steve