Tore Lervik

CacheMode and why it matters

CacheMode is a property found on most controls you use in your Windows Phone applications. Caching can give a big performance boost to your application, but it can be hard to know where you should use it.

BitmapCache vs. No caching

Think of a simple animation like moving an image from position A to position B on the screen. To animate the move from A to B we move the image a bit each time. Let's say in this example that the image has to be moved 5 times before it reaches position B.

No caching

Without caching the CPU will send the image to the GPU each time it needs to be drawn, and the GPU then draws the image on the correct surface for each frame.

BitmapCache

With caching the GPU will move the image to the correct position for each frame without needing to redraw it.

This means the image with CacheMode set to BitmapCache will only need to be drawn once at position A, and then the GPU moves it for each frame until it's at the correct position. While the image without caching has to be redrawn for each frame. In our example this means the image had to be drawn on the surface 6 times instead of just once.

All Roses Have Thorns

There is a reason the framework doesn't handle caching by itself, and why you also shouldn't use CacheMode="BitmapCache" on every single control. When you add caching to a control, think of it as taking a screenshot of that control and storing the bitmap in the GPU's memory. You will still have the normal memory usage of the control, but now you also have the added memory usage of the bitmap stored in the GPU's memory.
 

What should be cached?

Since you shouldn't cache everything, how can you know what should be cached and what performance that can be gained from it?

EnableRedrawRegions

In Windows Phone there is a setting in your App.xaml.csfile that makes it trivial to look for caching opportunities. In the initializing of the class you will find the following line commented out:

Application.Current.Host.Settings.EnableRedrawRegions = true;

Uncomment this line and run you application on either the emulator or a physical device. What this setting does is adding a shade to each redraw the phone has to do.

By doing this you can easily see if your control is moved, redrawn or even the whole section being redrawn. The image to the right shows my application without any cached controls. Your application should never look like this! ;)

Fixing my application

In my application I have a map, and a collection of controls that I've added to the map. There are two problems with my application that I have to fix.

I need to add CacheMode="BitmapCache" to the map itself to avoid redrawing the whole map. Secondly I need to add myControl.CacheMode = new BitmapCache();for each control I add to the map.

With CacheMode turned Off and On


Other factors to consider

The phone will always redraw as a rectangle around the control. It will also redraw multiple controls in the same draw for better performance. This means that if the phone decides to redraw two or more controls that are slightly apart, it will also redraw the pixels in between these controls.

Fill rate

Fill rate is a number that describes how many pixels the phone had to draw for one frame. A value of 1 represents 384000 (480 x 800) pixels. Since the phone doesn't have to draw the default (black or white) background, the fill rate can sometimes be a number less than 1.

Looking at the image to the right, we see that the fill rate without caching is 2.3546 while it's 1.8042 with caching enabled. Or more accurate: 904166 pixels had to be drawn to display the frame without caching, while only 692812 pixels where required for the frame when I added caching. That's a 30% difference in pixels just by adding caching two places.
 

Summing it all up

You can gain a lot of performance by adding BitmapCache to some of your controls, but remember to use EnableRedrawRegions to find what controls need it the most. I find it easiest to develop my application first, and then start checking if I need to add caching to some controls, this way I avoid caching more than what is really needed. If you just enable it blindly you will most likely end up with very little performance gain and much higher memory consumption.