这篇文章主要介绍Windows Phone中XAML的渲染处理过程,你能够根据下文中所提到的内容来优化现有的XAML页面,来提升页面渲染的性能。缓存
XAML的渲染包括如下两个阶段:app
1. 光栅化(Rasterization) 光栅化是将图形的表现形式从以基于矢量(vector-based)的图形(好比:线、文字和矩形)转换成基于像素(pixel-based)的图形,从而能够使图像直接显示在屏幕上的处理过程。这个转换过程要先在内存中先为位图分配一个缓冲区,而后将以矢量图形一个像素一个像素的转换成位图,并完成蒙板和梯度值的计算。这个光栅化的过程彻底是由CPU来处理的。ide
2. 组合(Composition) 在每个UIElement都被光栅化以后渲染器按照原始元素Z轴的顺序讲各个缓冲区上的位图层叠到彼此之上。这个处理将各个位图组合到了一块儿,因此渲染器要负责处理元素的透明度和任何转换(如:大小和位置),最终将位图展现在设备的屏幕上。组合处理CPU或者GPU来完成。性能
下面这张图经过将两个UI Element展现在屏幕上,说明了光栅化和组合阶段的过程,其中一个具备不透明蒙板。优化
渲染的过程是很是复杂的,由于屏幕上的图形都是由UI Element的集合组合在一块儿的,而不少UI Element又是由其余UI Element组合的。在内部,XAML使用一种全部元素均可见和渲染的层次结构的视觉树(visual tree)。好比要呈现一个普通的屏幕图形, XAML经过光栅化及组合可视化树中的元素,以减小必须分配的内存缓冲区的数量。这个处理过程将尽量的将元素覆盖到现有的缓冲区中。开发人员能够经过缓冲组合,以指定特定的UI元素如何被分组和由GPU组成。适当的缓存能够显着提升用户界面的帧速率。动画
若是UI Element是可动的,它将浪费一些处理器的时间,直到动画结束才进行光栅化处理。此外,即便元素只移动了其中一小部分,也须要对整个UI Element进行从新组合。为了优化渲染过程,XAML自动推迟了某些元素的组合过程,从而是元素的组合步骤能够迅速的经过GPU来完成。使用GPU来加速渲染过程一般被称为硬件加速。若是您的设备没有GPU或因其余缘由不能硬体加速,XAML采用图形设备接口(GDI )以较低的渲染速度来经过Z轴的顺序一像素一像素绘制UI。this
在XAML中有两个主要的线程:UI线程和Compositor线程。为了建立响应及时的应用,了解这两个线程是很是重要的。
spa
1. UI Thread线程
UI线程负责如下任务:
3d
为了使您的应用程序尽量灵活响应,必须尽可能保持UI线程的轻量和空闲。
2. Compositor Thread
组合线程是一个超轻量级的线程,它为GPU简单的组合元素的纹理,它处理GPU上的被定义为Storyboards类型或者基础纹理的绘制类型的动画。这些动画类型包括:
注意,任何使用了不透明蒙板,非矩形剪切或者大小改变的动画的对象大于2,048 x 2,048像素,它们将在UI线程上光栅化。
为了说明前面的概念,请参阅以下图所示的界面。屏幕上的地球图像制做成动画,绕着屏幕剩余边界。虽然这个屏幕显示了一个很是简单的用户界面,它包括全部上面列出的关键构建模块来讲明渲染过程.
这个图像是由下面这个XAML用户控件构成的。
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="HelloWorld.MainPage" Width="300" Height="200"> <Grid x:Name="LayoutRoot"> <Grid x:Name="_Background" Background="{StaticResource BlueWashBrush}"> <Image x:Name="_LightHexes" Source="Assets/Hexes.png" Stretch="Fill"/> <Image x:Name="_DarkHexes" Source="Assets/BlackHexes.png" Stretch="Fill"> <Image.OpacityMask> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Offset="0"/> <GradientStop Color="#C0FFFFFF" Offset="0.6"/> </LinearGradientBrush> </Image.OpacityMask> </Image> </Grid> <Rectangle x:Name="_Border" Fill="#FF969696" Stroke="White" Margin="0,10,90,10" RadiusX="10" RadiusY="10" HorizontalAlignment="Center" Width="180" Opacity="0.5"/> <TextBlock x:Name="_Label" HorizontalAlignment="Center" Margin="0,0,90,15" VerticalAlignment="Bottom" FontFamily="Verdana" FontSize="21.333" Text="Hello World" TextWrapping="Wrap" FontWeight="Bold"/> <Button x:Name="_Button" HorizontalAlignment="Right" Margin="0,0,8,8" VerticalAlignment="Bottom" Width="75" Content="Close" FontFamily="Verdana" FontSize="16"/> <Image x:Name="_Globe" Height="138" HorizontalAlignment="Center" Margin="0,20,90,0" VerticalAlignment="Top" Width="138" Source="Assets/Globe138x138.png" Stretch="Fill" RenderTransformOrigin="0.5,0.5" CacheMode="BitmapCache"> <Image.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </Image.RenderTransform> </Image> </Grid> </UserControl>
下图展现了上面代码的树形结构。
XAML的渲染过程执行如下步骤来呈现上图所示的可视化树:
注意,在渲染器执行的过程当中遵循如下规则:
在动画过程当中,只有_Globe元素在画面上移动,没有其余任何元素的变化。XAML没有必要逐帧来执行全部光栅化和组合的步骤。最优行为是保存已经完成的每帧动画步骤的结果,经过保存的步骤来组合_Globe。 在前面的代码块22行提到CacheMode属性来明确地告诉渲染器单独对待_Globe元素,以产生缓存的效果。
在XAML中缓存是自动的,不必再设置CacheMode属性。注意,分离缓存的对象和元素分组是缓存和提升动画速度成功的关键。