Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ProcessInfoRenderer.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Windows.Media;
6 using System.Windows.Controls;
7 using System.Windows;
8 using System.Windows.Input;
9 using System.Globalization;
10 using SiliconStudio.Paradox.DebugTools.DataStructures;
11 using SiliconStudio.Presentation.Core;
12 
13 namespace SiliconStudio.Paradox.DebugTools
14 {
16  {
17  public ProcessInfo ProcessData { get; set; }
18 
20  {
21  RoutedEvent = ProcessInfoRenderer.RenderEvent;
22  }
23  }
24 
26  {
27  public FrameInfo FrameData { get; set; }
28 
30  {
31  RoutedEvent = ProcessInfoRenderer.LastFrameRenderEvent;
32  }
33  }
34 
35  /// <summary>
36  /// Renders a full micro threading process.
37  /// </summary>
38  public class ProcessInfoRenderer : Canvas
39  {
40  public static readonly DependencyProperty ThreadLineHeightProperty = DependencyProperty.Register("ThreadLineHeight", typeof(double), typeof(ProcessInfoRenderer),
41  new FrameworkPropertyMetadata(32.0, FrameworkPropertyMetadataOptions.AffectsRender));
42  public static readonly DependencyProperty ThreadLineHeightMarginProperty = DependencyProperty.Register("ThreadLineHeightMargin", typeof(double), typeof(ProcessInfoRenderer),
43  new FrameworkPropertyMetadata(2.0, FrameworkPropertyMetadataOptions.AffectsRender));
44  public static readonly DependencyProperty PixelsPerSecondProperty = DependencyProperty.Register("PixelsPerSecond", typeof(double), typeof(ProcessInfoRenderer),
45  new FrameworkPropertyMetadata(100.0, FrameworkPropertyMetadataOptions.AffectsRender));
46 
47  private static readonly DependencyPropertyKey LastFrameTimePropertyKey = DependencyProperty.RegisterReadOnly("LastFrameTime", typeof(double), typeof(ProcessInfoRenderer), new PropertyMetadata());
48  public static readonly DependencyProperty LastFrameTimeProperty = LastFrameTimePropertyKey.DependencyProperty;
49 
50  private readonly Brush defaultBrush = new SolidColorBrush(Color.FromArgb(0xFF, 0x64, 0x95, 0xED));
51  private readonly Pen defaultPen = new Pen(Brushes.Black, 0.4);
52  private readonly Pen delimiterPen = new Pen(Brushes.LightGray, 0.5);
53 
54  public delegate void RenderRoutedEventHandler(object sender, RenderRoutedEventArgs e);
55  public static readonly RoutedEvent RenderEvent = EventManager.RegisterRoutedEvent("Render", RoutingStrategy.Bubble, typeof(RenderRoutedEventHandler), typeof(ProcessInfoRenderer));
56 
57  public delegate void FrameRenderRoutedEventHandler(object sender, FrameRenderRoutedEventArgs e);
58  public static readonly RoutedEvent LastFrameRenderEvent = EventManager.RegisterRoutedEvent("LastFrameRender", RoutingStrategy.Bubble, typeof(FrameRenderRoutedEventHandler), typeof(ProcessInfoRenderer));
59 
60  public event RenderRoutedEventHandler Render
61  {
62  add { AddHandler(RenderEvent, value); }
63  remove { RemoveHandler(RenderEvent, value); }
64  }
65 
66  public event FrameRenderRoutedEventHandler LastFrameRender
67  {
68  add { AddHandler(LastFrameRenderEvent, value); }
69  remove { RemoveHandler(LastFrameRenderEvent, value); }
70  }
71 
72  private void RaiseRenderEvent(ProcessInfo processData)
73  {
74  RaiseEvent(new RenderRoutedEventArgs { ProcessData = processData });
75  }
76 
77  private void RaiseLastFrameRenderEvent(ProcessInfo processData, FrameInfo frameData)
78  {
79  RaiseEvent(new FrameRenderRoutedEventArgs { ProcessData = processData, FrameData = frameData });
80  }
81 
82  public double ThreadLineHeight
83  {
84  get { return (double)GetValue(ThreadLineHeightProperty); }
85  set { SetValue(ThreadLineHeightProperty, value); }
86  }
87 
88  public double ThreadLineHeightMargin
89  {
90  get { return (double)GetValue(ThreadLineHeightMarginProperty); }
91  set { SetValue(ThreadLineHeightMarginProperty, value); }
92  }
93 
94  public double PixelsPerSecond
95  {
96  get { return (double)GetValue(PixelsPerSecondProperty); }
97  set { SetValue(PixelsPerSecondProperty, value); }
98  }
99 
101  {
102  defaultBrush.Freeze();
103  defaultPen.Freeze();
104  }
105 
106  /// <summary>
107  /// This method moves the previously rendered frame and only renders the newly added one.
108  /// It automatically removes the first frame when the maximum frame count is reached.
109  /// </summary>
110  /// <param name="processInfo">Instance that stores the whole micro threading process data.</param>
111  /// <param name="alignRight">Indicates whether render is right aligned or left aligned.
112  /// <remarks>Right align produces more realistic time-related render.</remarks>
113  /// </param>
114  public void RenderLastFrame(ProcessInfo processInfo, bool alignRight = true)
115  {
116  if (processInfo == null)
117  throw new ArgumentNullException("processInfo");
118 
119  if (processInfo.Frames.Count == 0)
120  return;
121 
123  Children.RemoveAt(0);
124 
125  FrameInfo lastFrame = processInfo.Frames.Last();
126  SetValue(LastFrameTimePropertyKey, lastFrame.EndTime);
127 
128  double offset = processInfo.Frames[0].BeginTime;
129 
130  if (alignRight)
131  offset = lastFrame.EndTime - (ActualWidth / PixelsPerSecond);
132 
133  for (int i = 0; i < Children.Count; i++)
134  Children[i].SetValue(Canvas.LeftProperty, (processInfo.Frames[i].BeginTime - offset) * PixelsPerSecond);
135 
136  UIElement frameControl = CreateFrameElement(lastFrame);
137 
138  if (frameControl != null)
139  {
140  frameControl.SetValue(Canvas.LeftProperty, (lastFrame.BeginTime - offset) * PixelsPerSecond);
141  Children.Add(frameControl);
142  }
143 
144  RaiseLastFrameRenderEvent(processInfo, lastFrame);
145  }
146 
147  /// <summary>
148  /// Clears any previous render and perform a new one from scratch.
149  /// </summary>
150  /// <param name="processInfo">Instance that stores the whole micro threading process data.</param>
151  public void RenderAllFrames(ProcessInfo processInfo)
152  {
153  if (processInfo == null)
154  throw new ArgumentNullException("processInfo");
155 
156  if (processInfo.Frames.Count == 0)
157  return;
158 
159  Children.Clear();
160 
161  double offset = processInfo.Frames[0].BeginTime;
162 
163  foreach (FrameInfo frame in processInfo.Frames)
164  {
165  UIElement frameControl = CreateFrameElement(frame);
166 
167  if (frameControl != null)
168  {
169  frameControl.SetValue(Canvas.LeftProperty, (frame.BeginTime - offset) * PixelsPerSecond);
170  Children.Add(frameControl);
171  }
172  }
173 
174  RaiseRenderEvent(processInfo);
175  }
176 
177  private int maxThreadCount = 0;
178 
179  /// <summary>
180  /// Creates the render elements of all threads over one frame.
181  /// </summary>
182  /// <param name="frame">Instance that stores all thread data.</param>
183  /// <returns>Returns a <c>Panel</c> (<c>Canvas</c>) containing rendered thread elements for the given frame.</returns>
184  private FrameworkElement CreateFrameElement(FrameInfo frame)
185  {
186  if (frame == null)
187  throw new ArgumentNullException("frame");
188 
189  if (frame.ThreadItems.Count == 0)
190  return null;
191 
192  if (frame.ThreadItems.Count > maxThreadCount)
193  {
194  maxThreadCount = frame.ThreadItems.Count;
195  InvalidateVisual();
196  }
197 
198  Canvas canvas = new Canvas();
199 
200  int threadIndex = 0;
201  foreach (ThreadInfo thread in frame.ThreadItems)
202  {
203  UIElement frameThread = CreateFrameThreadElement(frame.BeginTime, thread);
204 
205  if (frameThread != null)
206  {
207  frameThread.SetValue(Canvas.TopProperty, threadIndex * ThreadLineHeight);
208  canvas.Children.Add(frameThread);
209  }
210 
211  threadIndex++;
212  }
213 
214  VisualElement frameDelimiter = new VisualElement(CreateLine(maxThreadCount * ThreadLineHeight));
215  frameDelimiter.SetValue(Canvas.LeftProperty, -(delimiterPen.Thickness / 2.0));
216  canvas.Children.Add(frameDelimiter);
217 
218  double w = (frame.EndTime - frame.BeginTime) * PixelsPerSecond;
219  canvas.Children.Add(new VisualElement(CreateText(frame.FrameNumber.ToString(), w, ThreadLineHeight)));
220 
221  return canvas;
222  }
223 
224  protected override void OnRender(DrawingContext dc)
225  {
226  base.OnRender(dc);
227 
228  for (int i = 0; i < maxThreadCount + 1; i++)
229  {
230  double y = i * ThreadLineHeight;
231  dc.DrawLine(delimiterPen, new Point(0.0, y), new Point(ActualWidth, y));
232  }
233  }
234 
235  /// <summary>
236  /// Creates the render element for a thread over one frame.
237  /// </summary>
238  /// <param name="frameBeginTime">Time offset (in second) to align all micro threads render on the frame time.</param>
239  /// <param name="thread">Instance that stores all micro thread events.</param>
240  /// <returns>Returns a <c>UIElement</c> (<c>VisualContainerElement</c>) containing rendered micro thread elements for the given thread.</returns>
241  private UIElement CreateFrameThreadElement(double frameBeginTime, ThreadInfo thread)
242  {
243  if (thread == null)
244  throw new ArgumentNullException("thread");
245 
246  if (thread.MicroThreadItems.Count == 0)
247  return null;
248 
249  double y = ThreadLineHeightMargin;
250  double h = ThreadLineHeight - ThreadLineHeightMargin * 2.0;
251 
252  VisualContainerElement container = new VisualContainerElement();
253 
254  foreach (MicroThreadInfo microThread in thread.MicroThreadItems)
255  {
256  double x = (microThread.BeginTime - frameBeginTime) * PixelsPerSecond;
257  double w = (microThread.EndTime - microThread.BeginTime) * PixelsPerSecond;
258 
259  if (w <= 0.0)
260  continue;
261 
262  container.AddVisual(CreateRectangle(x, y, w, h));
263  }
264 
265  return container;
266  }
267 
268  private Visual CreateRectangle(double x, double y, double w, double h)
269  {
270  DrawingVisual visual = new DrawingVisual();
271 
272  using (DrawingContext context = visual.RenderOpen())
273  {
274  context.DrawRectangle(defaultBrush, defaultPen, new Rect(x, y, w, h));
275  }
276 
277  return visual;
278  }
279 
280  private Visual CreateLine(double h)
281  {
282  DrawingVisual visual = new DrawingVisual();
283 
284  using (DrawingContext context = visual.RenderOpen())
285  {
286  context.DrawLine(delimiterPen, new Point(0.0, 0.0), new Point(0.0, h));
287  }
288 
289  return visual;
290  }
291 
292  private Visual CreateText(string text, double w, double h)
293  {
294  DrawingVisual visual = new DrawingVisual();
295 
296  using (DrawingContext context = visual.RenderOpen())
297  {
298  FormattedText ft = new FormattedText(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface("Arial"), 18.0, Brushes.Gray);
299  context.DrawText(ft, new Point((w - ft.Width) / 2.0, (h - ft.Height) / 2.0));
300  }
301 
302  return visual;
303  }
304 
305  /*
306  protected override void OnMouseWheel(MouseWheelEventArgs e)
307  {
308  bool applyMatrix = true;
309  Matrix m = LayoutTransform.Value;
310 
311  Point pos = e.GetPosition(this);
312 
313  if (e.Delta > 0)
314  {
315  m.ScaleAt(1.5, 1.5, pos.X, pos.Y);
316  }
317  else
318  {
319  m.ScaleAt(1.0 / 1.5, 1.0 / 1.5, pos.X, pos.Y);
320  if (m.M11 < 1.0)
321  applyMatrix = false;
322  }
323 
324  if (applyMatrix)
325  LayoutTransform = new MatrixTransform(m);
326 
327  base.OnMouseWheel(e);
328  }
329  */
330  }
331 }
void RenderAllFrames(ProcessInfo processInfo)
Clears any previous render and perform a new one from scratch.
const int MaximumCapturedFrames
Maximum number of micro threads execution frames stored by the monitoring manager.
Manager class that monitors the micro threads executions.
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Definition: DirectXTexP.h:191
Renders a full micro threading process.
void RenderLastFrame(ProcessInfo processInfo, bool alignRight=true)
This method moves the previously rendered frame and only renders the newly added one. It automatically removes the first frame when the maximum frame count is reached.
SiliconStudio.Core.Mathematics.Color Color
Definition: ColorPicker.cs:14
System.Windows.Point Point
Definition: ColorPicker.cs:15