Silverlight 3 and GPU Acceleration

I learnt something this week so I thought I’d share.

I’ve heard a number of people say “Silverlight 3 has hardware acceleration” and I didn’t really know what it meant (and perhaps still don’t, fully) so I thought I’d do a bit of an experiment with it.

In Silverlight 3, the hardware acceleration feature is opt-in – if you don’t switch on hardware acceleration then you’ll see no effect from it.

How do you switch it on? There’s a new parameter to the Silverlight plug-in called enableGPUAcceleration which would leave you with an object tag looking like;

        <object data="data:application/x-silverlight-2," type="application/x-silverlight-2"
            width="100%" height="100%">
            
            <param name="enableGPUAcceleration" value="true" />
            <param name="source" value="ClientBin/SilverlightApplication18.xap" />
            
        </object>

means that the slides that I produced up here;

http://www.slideshare.net/ukdpe/mtaultydevweeksilverlight

for Silverlight 2 are now a little out of date as we have new parameters for the plug-in. There’s also another one called;

enableCacheVisualization

which you can toggle on/off to see where hardware optimisations are being applied – areas where optimisations are not being applied will be coloured (red) whereas areas where the optimisations are being applied will use their usual colours.

For instance, in this little example here;

image 

I’ve set the enableGPUAcceleration parameter to be true and I’m then displaying a MediaElement which is not benefitting from hardware acceleration and you can see that because it’s red and enableCacheVisualization is switched on.

In Silverlight 3, the UIElement class gets a new public property called CacheMode which is of type CacheMode and the only concrete class derived from CacheMode as far as I know is the BitmapCache. If I change my definition of my MediaElement so that it sets its CacheMode to an instance of BitmapCache as below;

        <MediaElement
            Grid.Row="1"
            CacheMode="BitmapCache"
            Margin="10"
            Source="/bear.wmv"
            Stretch="Fill"/>

then that version of the application as below;

image

displays the video without the red highlight which indicates that it’s being accelerated. The video that I’ve chosen to embed here is pretty low quality but I see on my machine ( just using Task Manager );

  • without hardware acceleration – approx 20% CPUs usage (I have 2)
  • with hardware acceleration – approx 10% CPUs usage

Note – with a more complex video ( that I didn’t want to embed in that XAP because of size ) I noticed a drop from about 80% CPU to about 50% CPU so perhaps that’s more realistic – I imagine there are many factors like the original bitrate, the stretched resolution and so on to take into account here.

Now, to the best of my knowledge, this kind of video acceleration only affects MediaElement and it does not effect areas of the screen that you paint with video – e.g. using a VideoBrush so that’s something to be aware of.

However, there’s another side to using the CacheMode property and that’s to use it for non-video content because CacheMode is not a property of MediaElement, it’s a property of UIElement.

What that means is that we can set CacheMode on pretty much arbitrary content – so, for example, the application below;

image

is just displaying some vector graphics and is scaling the content using an animation that scales from 1x size to 4x size over a period of 2 seconds. In the application, enableGPUAcceleration is switched on as is enableCacheVisualization and that’s why it’s all coloured red but the content is contained in a Viewbox which has its CacheMode data bound to the little ComboBox at the bottom of the screen. That allows me to switch on a BitmapCache with two different settings for its property RenderAtScale.

With RenderAtScale set to 0.75, the bitmap will be produced at 0.75 times the usual scale of the content and then cached. That means that when the animation blows the content up to 4x size, it’s going to look a bit blocky as you can see below;

image

but the content has lost its red colouring because it is now making use of the BitmapCache. If I change the RenderAtScale to 4.0 then the bitmap is going to match quite nicely to the size that I ultimately animate to so it’ll look good at the “top” of the animation as in;

image

but it’ll look a bit “blocky” when it’s reduced down to the natural size because it’s just shrinking the bitmap so it’s a trade-off but I’m getting the benefit of not having to pay for the vectors to be scaled each time but, instead, just scaling the bitmap that’s been cached. In terms of CPU usage, on my machine I see;

  • with CacheMode=Null around 20% of CPUs usage
  • with CacheMode=Something around 10% of CPUs usage

So, there’s definite benefits to making use of CacheMode if you’ve got content that you are happy to treat as a bitmap whilst you manipulate it ( for animations and so on ).

The first time that I experimented with this I thought that using CacheMode meant that the content that was being cached was “read only”. That is – I didn’t realise that Silverlight was smart enough to do this caching but still present live content.

What do I mean? Well, let’s take the previous example and replace the clock-face ( which is just a sample from Expression Design 2 ) and replace it with a live piece of UI like a DataGrid as in;

image

which runs for me at;

  • CacheMode=Null approx 30% CPU
  • CacheMode=Something approx 10% CPU

have a play with it (if you’ve got the SL3 runtime) and watch your CPU(s) whilst changing the mode and still being able to interact with the grid.