You can view the live demo here.
When Scott Guthrie first talked about the new Silverlight 3 features, and mentioned GPU acceleration (and 3D), I was very enthusiastic. Finally, we can do great, GPU accelerated 3D stuff in Silverlight! WPF has cool GPU acceleration features even for simple vector graphics, we will have the same performance advantages in Silverlight! Then, in March, during the MVP Summit I have learned what GPU acceleration is really for, and felt disappointed. Are you serious? 3D is done in software? Shader effects are done in software? What is all this good for then?
Then, as the role and functionality of GPU acceleration was explained in more detail, I grew more interested and appreciative of the feature. Sure, it can’t do a lot of things I was expecting, but for limited scenarios it is actually very useful. I will share with you details on when and how to take advantage of GPU acceleration in Silverlight 3.
The demo application
This article has a companion demo application that shows when GPU Acceleration is usable. The lion art I used is courtesy of my friend, Krisztian Hadi. Of course, you need Silverlight 3 to run it. If you have a powerful, multi-core processor, I recommend limiting the number of cores available for your browser to 1, so that you can really appreciate the difference between CPU and GPU.
Figure 1: The demo application
Enabling GPU Acceleration
GPU acceleration is disabled by default. To enable it, you have to opt-in on two levels: both for the plugin, and for each element you wish to accelerate. If you know WPF, you may recall that GPU acceleration in WPF is handled automatically. The Silverlight team has chosen a different approach: you can turn GPU acceleration on and off manually, allowing for a much finer control. Also, while the GPU logic in WPF is very smart, sometimes it doesn’t do the right thing. With the manual opt-in approach, Silverlight does not have to run the “do I put do this with CPU or GPU” algorithm, and therefore saves precious CPU resources.
Many great articles have been written about how to enable GPU acceleration in Silverlight, so I’ll just sum it up quickly here.
First, you have to enable the GPU Acceleration for the entire plugin. To do this, you have to add a parameter to the
<object> tag in your HTML file that hosts the Silverlight application:
Listing 1: Enabling GPU Acceleration in the HTML host page.
You can only enable GPU Acceleration in the HTML page. If it is not enabled here, then you won’t be able to use any GPU related functionality.
On Windows, GPU acceleration works in both windowed and full screen applications. On Mac OSX, GPU acceleration only works in full screen. Your users also should have a DirectX 9 compatible video card and drivers for Windows, or an OpenGL2 compatible video card for the Mac.
To enable GPU Acceleration for a Silverlight element (for example, a canvas):
Listing 2: Enabling GPU Acceleraion for a Silverlight element from XAML
Bitmap Cache? I thought we were discussing GPU Acceleration!
To understand how GPU Acceleration really works in Silverlight 3, it is important to note that you don’t specify something like “UseGPU” or “AccelerateThisALotUsingGPU”, but you define a Cache Mode. Because Silverlight 3’s GPU acceleration is nothing more (or less) than Caching a bitmap on the GPU, most of what I am about to say can be traced back to the “Cache” word.
If you mark an element with
CacheMode=”BitmapCache”, it (along with its visual subtree) gets rendered on the CPU once, but the resulting bitmap is cached on the graphics card. This means that when an object is often changed (like there is a color or path animation in it which changes he element on every frame), it will have to be recalculated and re-uploaded to the graphics card. In this case, you may even lose performance.
So, what can the GPU do with the cached bitmaps? In Silverlight 3, the GPU can:
- Scale the bitmap - RenderTransform
- Rotate the bitmap - RenderTransform
- Change the opacity of the bitmap - Opacity
- Clip the bitmap (if the clip is rectangular).
The GPU does NOT accelerate the following, at least in Silverlight 3:
- Perspective transformation
- Pixel shader effects
So, if you’re scaling, rotating, fading or clipping part of your scene, you can instruct Silverlight to do the animation on the GPU. This may not sound like a lot, but it can really help in a lot of cases.
Demistifying the Frame Rate Counter
You can turn on the Frame Rate Counter by adding the following to your Silverlight
<object> tag in HTML:
You can also enable it in code:
The frame rate counter has four items. Most people know what the first one is, but it is not easy to find information on the rest:
- The first number shows the frame rate. (not hard to guess)
- The second number shows how many kilobytes of GPU memory are used
- The third number shows the total number of GPU accelerated surfaces
- The fourth number shows the number of GPU accelerated surfaces that are not explicitly asked to be GPU accelerated – or the number of implicit surfaces. More on this later.
It is important to see that different video cards have different amount of memory. If Silverlight runs out of video memory, performance will drop as in this case Silverlight falls back to pure software rendering. You can query the GPU vendor, driver version and device ID using the
Analytics.GpuCollection object, but there is no further support for determining the amount of available video memory.
Figure 2: Cache Visualization
Cache visualization allows you to see what elements are accelerated on the GPU, what elements are not, and which elements are implicit surfaces. You can turn on Cache Visualization on the hosting HTML page, or from code at runtime.
Listing 3: Enable Cache Visualization on the object tag of the HTML page
Listing 4: Enable Cache Visualization from code
Cache visualization shows cached objects in their natural color, and non-cached ones in red. Note that the control panel is above the lions. Therefore it also has to be cached on the GPU otherwise the GPU would not be able to blend it over the lions, and therefore the entire scene could not take advantage of GPU acceleration. We have not marked the control panel to be
BitmapCached, so Silverlight has done this for us automatically. The control panel is thus an implicit surface, and displayed in green on the Cache Visualization.
Render At Scale
Silverlight has vector based graphics, but bitmap caching works with bitmaps. The key difference between bitmap and vector graphics is that you can magnify vector graphics almost infinitely without loss of quality. On the other hand, bitmaps become “blocky” or pixelated when magnified heavily. Although the GPU tries to help the situation by applying bilinear filtering with the scale function, it can only help so much.
Figure 3: Pixelization effect upon magnifying
To help with the unwanted pixelation effect, you can set the
RenderAtScale property of the
Listing 5: Setting RenderAtScale from code
Listing 6: Setting RenderAtScale from XAML
The above code will instruct Silverlight to render the vector of the lion at 4x scale. However, this will increase the required video memory by 16, and rendering the to-be-cached bitmap will also be much slower. You can see the effect of
RenderAtScale by turning on the “High Res Bitmap” checkbox in the sample while having GPU Acceleration on.
Cache and invalidation
So, what happens if you cache a text box, and its text changes? Do you have to initiate the re-caching of the bitmap? Fortunately, Silverlight keeps track of dirty surfaces by checking for property changes, and automatically re-renders the changed surfaces and caches them again. Of course, this can slow down the application – click on “Invert Eyes” in the demo to see how. (Remember to use only one processor core as the effect may be unnoticeable with two).
GPU Acceleration can help get more out of your animations, but you need to know the ins and outs to really use it properly. The rule of thumb is to only apply Bitmap Caching if you have a fairly rarely changing content that you need to move or rotate around the scene, or change its opacity during an animation. And keep looking at the handy tuning tools in Silverlight 3, such as the performance counters and the cache visualization.
Hopefully this article helped you understand how and why Silverlight 3’s GPU acceleration works the way it does, and you can go on create really nice, compelling animations! Don’t forget to let me know about them and please leave your feedback and questions below.
You can view the live demo here.
András is a Silverlight MVP and Insider, and is very passionate about user experience. He is the owner and idea man behind Hungarian consulting company http://www.response.hu. Follow me on Twitter - vbandi.
View complete profile here.
Please login to rate or to leave a comment.