May 9, 2008

WPFPerf and software rendering

 

The WPFPerf tool that is included with the windows SDK can be a very useful tool in finding areas of your application that is being rendered using the WPF software pipeline.

Recently I was profiling an application looking for areas that could be improved, performance wise, at the WPF level. One thing I thought to do was use the WPFPerf tool and look for elements that were being software rendered and see if I could modify them to use the hardware pipeline and still get desired effect. See here for more information on the two pipelines.

To find the areas that are using software rendering the Perfortator plug-in gives a nice, albeit cheesy, visual cue. By enabling "Draw software rendering with purple tint"

Purple[1]

Come on guys, really? Is that really what the option is called? I wonder what the property is called in code ShowSoftwareRenderingUsingPurpleShadeBecauseMyKidWasWatchingBarneyWhileIWasWritingThisFuction.

But I digress, The functionality works well.

FullApp_thumb[1]

So a discovery I made was that WPF is able to use the hardware rendering pipeline to render bitmap drop shadows (which is typically documented as being software rendered) but only if the drop shadow is rectangular. In my case I had a button template that was using a border element ad applying a drop shadow to the border element to give the drop shadow effect on the button

SoftwareRender_thumb[1]

<Style x:Key="SoftwareRenderTemplate">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Height="22">
<Border Background="Gray" Height="22" Margin="0,0,0,0">
<Border.BitmapEffect>
<DropShadowBitmapEffect Opacity="0.5" ShadowDepth="3" Softness="0.285"/>
</Border.BitmapEffect>
<ContentPresenter x:Name="ButtonContent" Width="Auto" Content="{TemplateBinding Content}" OpacityMask="{TemplateBinding Foreground}" HorizontalAlignment="Center" VerticalAlignment="Center" Height="Auto" Margin="10,0,10,0"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>



When I built the template this way and ran Perforator it showed me that the button was using software rendering. Which is what I would have expected. However, if I modify the template to use a rectangle shape instead of a border element. Then apply the drop shadow effect to the the rectangle I noticed that Perforator no longer indicated (which means to remove the lovely purple tint) that the button was using software rendering. This is not what I would have expected.



<Style x:Key="HardwareRenderTemplate">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Height="22">
<Rectangle Fill="Gray" Height="22" Margin="0,0,0,0" Stroke="{x:Null}">
<Rectangle.BitmapEffect>
<DropShadowBitmapEffect Opacity="0.5" ShadowDepth="3" Softness="0.285"/>
</Rectangle.BitmapEffect>
</Rectangle>
<ContentPresenter x:Name="ButtonContent" Width="Auto" Content="{TemplateBinding Content}" OpacityMask="{TemplateBinding Foreground}" HorizontalAlignment="Center" VerticalAlignment="Center" Height="Auto" Margin="10,0,10,0"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>



HardwareRender_thumb[1]



I searched around a bit to try and determine what was going on here and the information is sparse (hence my blog entry) But I did find one source that hints to the fact that the underlying implementation of the drop shadow effect is optimized when sticking to rectangular shapes.



So there it is. If you really like drop shadows but don't want to get hammered by the performance this is one way to do it.