CPU and memory Optimizations concerning shaders in Silverlight


Recently, I had to use Silverlight shaders for my personal needs, that article explains memory and CPU usage when you define shaders on objects.

First, each time you apply one of the shaders provided by default (DropShadow and Blur)  on a UIElement, actually you generate two bitmaps into RAM at runtime. The first bitmap is a simple rasterization of the UIElement, the second bitmap is that bitmap with the effect applied to it. In terms of performance, that behavior, wich is logic, can lead to some issues if you don't take care about few points :

First, we can calculate the memory used by an effect applied to a 200 * 200 UIElement. We consider that each pixel (40000) are encoded into 4 bytes :

  • Alpha is coded on 1 byte (called octet in french) and 8 bits, leads to 256 possible values from 0 to 255 or 0x00 to 0xFF in Hexadecimal
  • Red | 1 byte | 8 bits | 0xFF | 0-255
  • Green | 1 byte | 8 bits | 0xFF | 0-255
  • Blue  | 1 byte | 8 bits | 0xFF | 0-255

The first rasterized bitmap is contained by the RAM as it is made at runtime. As there's no compression for it you can calculate his weight with the formula below :
PixelsWidth * PixelsHeight * 4 Bytes = total weight of the intermediate bitmap in RAM

In our case the bitmap is about 160 Kbyte, but it's just the first bitmap. The second will at least take 160 kBytes plus extra size needed to render effect. The total size is about 400 kbyte if you consider that these effect create a bigger  rendered surface area than the original bounding box does.

Concerning customs pixels shaders, the behaviors is slighty different as there's a direct rasterisation wich creates by the way, a single bitmap into memory. This is a pretty good advantage in terms of memory usage but CPU usage increases. Indeed, the intermediate bitmap is here to aleviate CPU as it avoid to calculate it each time for translate transforms. When you translate an UIElement wich displays an effect, the intermediate bitmap is not recreated. For other operations, it is always regenerated. For example, if you decide to animate the scale or rotation or skew of a rectangle, the intermediate bitmap will be recreated each time. For a 60 max fps, Silverlight will create about 60 intermediate bitmaps and 60 bitmaps with final effect. Designers and developers must take care about that, as memory and CPU charge could increase drasticly and reduce performances... To avoid or limit that behavior, Microsoft has limited the max size of an effect to 2048 pixels for width and height.

All bitmaps, including intermediates, hang around for the life of the Effect+UIElement pairing. When the Effect is removed or a UIElement destroyed, all surfaces are released at once. CacheMode (bitmap cache) or 3D usage will create intermediate bitmaps in every way.

Jason Prado in charge at Microsoft on that topic kindly helps me to clarify some Silverlight behaviors concerning shaders. You will find some best practices below :

* Smaller area is better.

* The most important thing is to not trigger rerasterization of a UIElement. Rerasterization means we have to run the effect again, and both of these steps are expensive. Many changes, e.g. changing the color of a Rectangle, trigger rerasterization.

* Don't run effects on elements that change every frame. Trigger rerasterization as rarely as possible..

* BlurEffect is slow. It's a separated two-pass gaussian blur, but it is still an inherently slow operation if you want visual quality that is at all passable. Keep the radius low. At Radius >= 10, you start to notice serious performance degradation.

Bookmark and Share

Leave a Reply

Security Code:


 

Auteur du livre “Pratique de Silverlight” aux éditions Pearson

Categories

Archives