This is Part 3 of the translation of the performance chapter of the Windows Phone developer book I co-authored with many of my Hungarian peers. Other parts of this series can be found here.
There are a number of ways to create animation on Windows Phone. Let’s start with the one that is used the less frequently – procedural animation.
Let’s take a 12-eyed Vuvrian spaceship captain, and get him really drunk:
Imagine that his ship is buzzed by a Tie Fighter. Our little app will simulate what the drunk Vuvrian is seeing as he’s desperately trying to open his eyes while the Tie Fighter is buzzing him with the starry space in the background.
To do this, we will have to create a TIEFighter.xaml user control. I won’t copy its code here, you can download it together with the solution later. But here is what it looks like:
The essence of procedural animation is to recalculate the position of every object, in every frame. Again, the full code will be available, I would only like to emphasize the key parts here.
In order to launch the ProceduralAnim sample, a little modification has to be made in the Properties/WMAppManifest.xml file:
<DefaultTask Name ="_default" NavigationPage="ProceduralAnim.xaml"/>
The animator code itself can be found in the ProceduralAnim.xaml.cs file, in the CompositionTargetOnRendering event handler. This is the Rendering event of the CompositionTarget class, called every time the UI thread is preparing to draw a new frame. Here is what the event handler looks like:
private int frameCount = 0;
private void CompositionTargetOnRendering(object sender, EventArgs eventArgs)
if (frameCount >= 100)
frameCount = 0;
for (int i = 0; i < Ties.Count; i++)
var tieFighter = Ties[i];
CompositeTransform tr = (CompositeTransform) tieFighter.RenderTransform;
tieFighter.Opacity = frameCount/100.0;
double scale = 1 + frameCount/100.0;
tr.ScaleX = scale;
tr.ScaleY = scale;
tr.Rotation = frameCount / (i+1.0);
Ties is a list of TIEFighter objects. The above code simply iterates through every Tie Fighter, and changes their opacity, size and rotation based on where we are in the animation. If there are three Tie Fighters shown (indicating that the drunk Vuvrian has three eyes open), here is the result:
The little numbers on the right side of the screens are the Frame Rate Counters. It is worth a detour to investigate them at this point.
Frame Rate Counters
The constructor in App.xaml.cs has the following lines:
1: // Show graphics profiling information while debugging.
2: if (System.Diagnostics.Debugger.IsAttached)
4: // Display the current frame rate counters.
5: Application.Current.Host.Settings.EnableFrameRateCounter = true;
7: // Show the areas of the app that are being redrawn in each frame.
8: //Application.Current.Host.Settings.EnableRedrawRegions = true;
10: // Enable non-production analysis visualization mode,
11: // which shows areas of a page that are handed off to GPU with a colored overlay.
12: //Application.Current.Host.Settings.EnableCacheVisualization = true;
14: // Disable the application idle detection by setting the UserIdleDetectionMode property of the
15: // application's PhoneApplicationService object to Disabled.
16: // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run
17: // and consume battery power when the user is not using the phone.
18: PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
Line 5 makes the application show the frame rate counters, if the application is started with a debugger attached (F5). Here is a closer look:
What do these numbers mean? Here is a summary from left to right:
|Composition thread frame rate
||Indicates how many times the screen is refreshed per second. If this number is smaller than 60 (50 on some devices), the animations lose their fluidity. If it decreases below 30, even less keen-eyed users will start to notice the problem, and the number turns red
|UI thread frame rate
||The UI thread is where the rendering (rasterizing) happens, and where our code runs by default (unless we start a new thread). A slow UI thread frame rate usually means that the application will not be responsive. Animations can still be fluid on the Composition thread, and utilizing the GPU – but the user experience will definitely suffer if the UI thread is overloaded.
|Texture memory usage
||Indicates the amount of video- and system memory used by the textures
|Number of Explicit Surfaces
||Shows the number of Explicit Surfaces used by the GPU. If a FrameworkElement object has its CacheMode property set to BitmapCache, this counter increases.
|Number of Implicit Surfaces
||The number of Implicit Surfaces used by the GPU. (this will be explained later, I promise)
||One of the most important performance indicator of the GPU. GPUs can only draw so much pixels per second. In the case of Windows Phone 7, the display consists of 480*800 pixels, and the GPU of a first generation phone can fill this about 2.5 times per frame.
A Fill Rate of 1 means that the GPU is drawing 1 screen worth of pixels per frame. If this number is increased above 2.5, the GPU becomes the bottleneck. If the numbers grow beyond 3, it turns red, because the animations lose their fluidity. Pay attention that seemingly innocent actions, like setting a background color for the application increases the Fill Rate by 1, since the GPU has to draw this background first. It is a good practice to keep the background transparent, if we are using the system theme.
The above screenshots indicate that the emulator can run the UI thread with 15 fps (frame per second). My first generation phone shows 12-13 fps. The problem is not caused by the high Fill Rate, since it is a constant 1. Even with one Tie Fighter, the phone is only able to animate at 20-30 fps. What can be the reason for this?
Turning the Redraw Regions option on, an adept eye can immediately see the problem. Here is what you can see on the screen:
The SIlverlight runtime tries to optimize drawing speed by only redrawing the areas that change between two frames. The Redraw Regions option tints these areas with a different color for every frame. (this does tax the CPU, so don’t perform performance measurements while this option is on).
The picture above shows that a significant part of the screen has to be re-rendered as the Tie Fighter moves above the stars and below the controls. Also, the Tie Fighter itself gets redrawn for every single frame, since its size and rotation are continuously changing. This rasterizing / rendering work is performed by the CPU – no wonder that it cannot do better than 20-25 frames per second.
In Part 1 of this series, I mentioned that the GPU is especially optimized for tasks like rotating and scaling textures (and many more). So, isn’t it time to take advantage of the GPU? Yes – but stay tuned, the GPU will be the topic of the next blog post.
Mar 14 2012, 12:50 AM