环境信息:
Windows 7 64位SP1
6GB内存
Intel(R)Core(TM)i5-2400S CPU @ 2.50GHz(4核)
Silverlight 5
我在Silerlight中遇到DropShadowEffect
非常可怕的性能问题。
我为它创建了一个最小化的演示: http://www.peterlee.com.cn/public/ShadowEffectTestDemo/ShadowEffectTestTestPage.html
单击按钮Zoom
以尝试缩放画布(带有DropShadowEffect
的星形)。你会发现当Zoom = 64
时,你的CPU和内存非常疯狂。
但是,如果您通过点击DropShadowEffect
按钮删除Remove Effect
,然后将其缩放,一切正常。
但是,如果我们使用TextBlock
DropShadowEffect
,一切都很好。您可以通过单击“使用TextBlock”按钮来尝试它。
我不知道Silverlight正在处理TextBlock和DropShadowEffect
的自定义Star形状。
请帮帮我。感谢。
更新: 根据回复:
我也在发布模式下尝试过(现在示例演示链接是在发布模式下构建的);
我还添加了ChrisF提出的GPA加速:
<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="ShadowEffectTest.xap"/>
<param name="onError" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="5.0.61118.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0" style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
</a>
</object>
这是更新的代码
MainPage.xmal:
<UserControl x:Class="ShadowEffectTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button x:Name="btnZoom" Width="75" Height="23" Content="Zoom"
Grid.Column="0" Grid.Row="0"
Click="btnZoom_Click"/>
<Button x:Name="btnRemoveEffect" Width="100" Height="23" Content="Remove Effect"
Grid.Row="0" Grid.Column="1"
Click="btnRemoveEffect_Click"/>
<Button x:Name="btnUseTextBlock" Width="120" Height="23" Content="Use TextBlock"
Grid.Row="1" Grid.Column="0"
Click="btnUseTextBlock_Click" />
<Canvas x:Name="mainCanvas" Width="200" Height="150" Background="LightBlue"
Grid.Column="1" Grid.Row="1" />
</Grid>
</UserControl>
MainPage.xaml.cs中:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Windows.Media.Effects;
namespace ShadowEffectTest
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
// These are the points for a Star shape
List<Point> points = new List<Point>()
{
new Point(0, 36.3634469292486),
new Point(-12.3606797688474, 43.2188191057189),
new Point(-24.7213595376948, 50.0741912821893),
new Point(-37.0820393065422, 56.9295634586596),
new Point(-34.4313595448175, 42.9654855127096),
new Point(-31.7806797830927, 29.0014075667595),
new Point(-29.130000021368, 15.0373296208095),
new Point(-39.4200000080385, 5.31010468057062),
new Point(-49.709999994709, -4.41712025966827),
new Point(-59.9999999813794, -14.1443451999072),
new Point(-46.0011100186002, -15.919247828416),
new Point(-32.002220055821, -17.694150456925),
new Point(-18.0033300930418, -19.4690530854338),
new Point(-12.0022200620278, -32.3361808961241),
new Point(-6.00111003101392, -45.2033087068145),
new Point(0, -58.0704365175048),
new Point(6.00111003101392, -45.2033087068145),
new Point(12.0022200620278, -32.3361808961241),
new Point(18.0033300930418, -19.4690530854338),
new Point(32.002220055821, -17.694150456925),
new Point(46.0011100186002, -15.919247828416),
new Point(59.9999999813794, -14.1443451999072),
new Point(49.709999994709, -4.41712025966827),
new Point(39.4200000080385, 5.31010468057062),
new Point(29.130000021368, 15.0373296208095),
new Point(31.7806797830927, 29.0014075667595),
new Point(34.4313595448175, 42.9654855127096),
new Point(37.0820393065422, 56.9295634586596),
new Point(24.7213595376948, 50.0741912821893),
new Point(12.3606797688474, 43.2188191057189),
new Point(0, 36.3634469292486)
};
uie = RenderBezier(points);
// This the evil for the performance issues (crazy memory and CPU)
uie.Effect = ShadowEffect;
uie.CacheMode = new BitmapCache();
uie.SetValue(Canvas.LeftProperty, 25.0);
uie.SetValue(Canvas.TopProperty, 25.0);
mainCanvas.Children.Add(uie);
}
private UIElement uie = null;
public Path RenderBezier(List<Point> ctrlPoints, List<List<Point>> innersCtrlPoints = null)
{
// Step 0: Merge ctrlPoints lists
List<List<Point>> ctrlPointsLists;
if (innersCtrlPoints == null)
{
ctrlPointsLists = new List<List<Point>>(1);
ctrlPointsLists.Add(ctrlPoints);
}
else
{
ctrlPointsLists = new List<List<Point>>(1 + innersCtrlPoints.Count);
ctrlPointsLists.Add(ctrlPoints);
foreach (List<Point> list in innersCtrlPoints)
ctrlPointsLists.Add(list);
}
PathGeometry pg = new PathGeometry();
foreach (List<Point> list in ctrlPointsLists)
{
// Step 0: check (Debug.Assert)
Debug.Assert(list.Count % 3 == 1,
"public Path RenderBezier(IList<Point> ctrlPoints): number of control points is not 3n+1.");
int n = (list.Count - 1) / 3; // Number of BezierSegments
Debug.Assert(n > 0,
"public Path RenderBezier(IList<Point> ctrlPoints): at least one Bezier segment required.");
// Step 1: Add BezierSegments to PathFigure
PathFigure pf = new PathFigure();
pf.StartPoint = list[0];
for (int i = 0; i < n; ++i)
pf.Segments.Add(GetBezierSegment(
list[3 * i + 1],
list[3 * i + 2],
list[3 * i + 3]
));
// Step 2: Add PathFigures to PathGeometry
pg.Figures.Add(pf);
}
// Step 3: Add PathGemotry to GeometryGroup
GeometryGroup gg = new GeometryGroup();
gg.Children.Add(pg);
// Step 4: Set GeometryGroup as Path.Data
Path path = new Path();
path.Data = gg;
// Step 5: Set some Path properties
// if (ShowOutline)
{
path.Stroke = new SolidColorBrush(Colors.Black);
path.StrokeThickness = 1.0;
path.StrokeEndLineCap = PenLineCap.Round;
path.StrokeLineJoin = PenLineJoin.Round;
path.StrokeStartLineCap = PenLineCap.Round;
}
// Finally, return it
return path;
}
// This the evil for the performance issues (crazy memory and CPU)
private static DropShadowEffect ShadowEffect
{
get
{
return new DropShadowEffect()
{
Color = Colors.Blue,
BlurRadius = 5,
Direction = 0,
ShadowDepth = 0
};
}
}
private static BezierSegment GetBezierSegment(Point p1, Point p2, Point p3)
{
BezierSegment bs = new BezierSegment();
bs.Point1 = p1;
bs.Point2 = p2;
bs.Point3 = p3;
return bs;
}
public static readonly double[] ZoomingSteps = new double[]
{
1.0,
1.5,
2.0,
3.0,
4.0,
6.0,
8.0,
12.0,
16.0,
24.0,
32.0,
48.0,
64.0,
128.0
};
private int index = 0;
private void btnZoom_Click(object sender, RoutedEventArgs e)
{
if (index >= ZoomingSteps.Length - 1)
return;
ScaleTransform st = new ScaleTransform();
st.ScaleX = st.ScaleY = ZoomingSteps[index++];
btnZoom.Content = ZoomingSteps[index].ToString();
mainCanvas.RenderTransform = st;
}
private void btnRemoveEffect_Click(object sender, RoutedEventArgs e)
{
index = 0;
btnZoom.Content = "Zoom";
uie.Effect = null;
mainCanvas.RenderTransform = new ScaleTransform();
}
// If I use TextBlock as the child UIElement, then everything is okay
// path = new TextBlock() { Text = "Text Block" };
private void btnUseTextBlock_Click(object sender, RoutedEventArgs e)
{
mainCanvas.Children.Remove(uie);
index = 0;
btnZoom.Content = "Zoom";
uie = new TextBlock() { Text = "Text Block" };
mainCanvas.Children.Add(uie);
uie.Effect = ShadowEffect;
uie.CacheMode = new BitmapCache();
mainCanvas.RenderTransform = new ScaleTransform();
}
}
}
答案 0 :(得分:0)
我已经尝试针对您的应用程序运行WinDbg并转储应用程序。这是Result.现在别担心,我也不理解其中的一半。但是我走得更远了,似乎有大量的数组/列表,其中至少80%为空。
如果可以的话,我会在早上试着看看它,我希望我能帮助你朝着正确的方向前进
答案 1 :(得分:0)
这是我的诀窍:永远不要使用DropShadowEffect。创建要为其创建投影的任何内容的克隆,将其放在主要内容后面,并在其上使用BlurEffect。性能更好,质量更好。我不明白为什么。
答案 2 :(得分:0)
我认为问题在于:
uie.CacheMode = new BitmapCache();
通常,这会告诉silverlight尝试将位图缓存在内存中,以便计算机不需要在应用程序中重新呈现元素。
在此处查看有关silverlight性能的建议提示:
http://msdn.microsoft.com/en-us/library/cc189071(v=vs.95).aspx
答案 3 :(得分:0)
问题与Silverlight的渲染管道如何工作有关。 DropShadowEffect只是一个像素着色器,像素着色器通过创建它们将应用的图像的缓冲副本在Silverlight中工作,然后允许您使用缓冲副本的值更改实际图像的像素属性。此缓冲副本是整个图像,不受剪切影响。由于缩放会创建一个非常大的预剪裁图像,因此像素着色器必须制作一个非常大的预剪裁图像的物理缓冲副本......这就是缩放时性能如此糟糕的原因。
我找到的唯一解决方案是在缩放(或平移缩放的图像)时禁用像素着色器效果,并在放大图像时将其添加回来(或平移完成)。这样,您不会因为缩放或平移的每一帧而应用像素着色器的性能损失。