2012-02-09 3 views
1

Окружающая среда Информация:Silverlight 5: Ужасные проблемы с производительностью DropShadowEffect

Windows 7 64bit SP1

6GB памяти

Intel (R) ядро ​​(TM) i5-2400S CPU @ 2.50GHz (4 ядра)

Silverlight 5

у меня очень те проблемы с производительностью с DropShadowEffect в Silerlight.

Я создал свернутое демо для него: http://www.peterlee.com.cn/public/ShadowEffectTestDemo/ShadowEffectTestTestPage.html

Нажмите кнопку Zoom, чтобы попытаться увеличить холст (с формой звезды с DropShadowEffect). Вы обнаружите, что когда Zoom = 64, ваш процессор и память очень сумасшедшие.

Но если вы удалите DropShadowEffect, нажав кнопку Remove Effect, а затем увеличьте его, все будет в порядке.

Однако, если мы используем TextBlock с DropShadowEffect, все в порядке. Вы можете попробовать его, нажав на кнопку «Использовать TextBlock`.

Я не знаю, что Silverlight имеет дело с TextBlock и моей заказной форме звезды для DropShadowEffect.

Пожалуйста, помогите мне. Спасибо.

UPDATE: Согласно ответам:

Я также пробовал в режиме Release (теперь образец демо-ссылка была построена в режиме выпуска);

Я также добавил GPA ускорение предложил ChrisF:

<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

Я попытался запустить WinDbg против вашего приложения и слить приложение. вот Result. Теперь не волнуйтесь, я тоже не понимаю его половины. Но я пошел немного глубже, и, похоже, есть большое количество массивов/списков, где по крайней мере 80% равны нулю.

Возможно, вы захотите взглянуть на WinDbg. Вот небольшой Tutorial

Я стараюсь смотреть на него утром, если я могу, и я надеюсь, что я помог вам по крайней мере в правильном направлении

+0

Привет Риккос. Я попытался установить WinDbg, но у меня возникла проблема с установкой Windows SDK. Что касается исходной проблемы, я думаю, что это могут быть проблемы с Silverlight. Но я просто не понимаю, почему «TextBlock» с «DropShadowEffect» в порядке. –

+0

BTW, я обновил образец, если вы хотите сделать более глубокий анализ. –

0

Вот мой трюк: никогда не используйте DropShadowEffect.Создайте клон того, что вы хотите создать для тени, поставьте его поверх основного содержимого и используйте BlurEffect. Гораздо лучше производительность, гораздо лучшее качество. Понятия не имею почему.

+0

Привет, Zenexer, клон, как тень, также является моей предварительной идеей. но эффект будет выглядеть не так хорошо, как «DropShadowEffect». Я также пробовал «BlurEffect», все еще очень медленный. –

0

Я думаю, что проблема здесь:

uie.CacheMode = new BitmapCache(); 

Как правило, это говорит о том, чтобы попробовать Silverlight и кэш растрового изображения в памяти, так что компьютер не нуждается в повторной визуализации элемента в приложении.

Посмотрите здесь предложенные советы по SilverLight производительности:

http://msdn.microsoft.com/en-us/library/cc189071(v=vs.95).aspx

+0

Спасибо за ваш ответ. 'uie.CacheMode = new BitmapCache();' здесь использовался для тестирования ускорения GPU ''. У меня такая же проблема с этим утверждением или без него. –

0

Проблема связана с тем, как работает визуализация трубопровода Silverlight. DropShadowEffect - это всего лишь пиксельный шейдер, а пиксельные шейдеры работают в Silverlight, создавая буферизованную копию изображения, к которому они будут применены, а затем позволяют изменять свойства пикселя реального изображения, используя значения буферизованной копии. Эта буферизованная копия - это полное изображение и не зависит от отсечения. Поскольку масштабирование создает очень большое изображение с предварительным обрезкой, пиксельный шейдер должен сделать физическую буферизированную копию очень большого предварительно обрезанного изображения ... вот почему производительность настолько плоха, когда вы увеличиваете масштаб.

Единственное решение, которое я нашел для этого, - отключить эффект пиксельного шейдера во время масштабирования (или панорамирования увеличенного изображения) и добавить его обратно при увеличении изображения (или завершение панорамирования). Таким образом, вы не несете штраф за производительность пиксельного шейдера, применяемого для каждого кадра масштабирования или панорамирования.

+0

Привет, Майк, что вы подразумеваете под «отключением эффекта пиксельного шейдера»? Вы хотите удалить «DropShadowEffect» при масштабировании или панорамировании? –

Смежные вопросы