ProfileWindowGraph.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. using System;
  2. using OpenTK;
  3. using OpenTK.Graphics.OpenGL;
  4. using Ryujinx.Common;
  5. namespace Ryujinx.Profiler.UI
  6. {
  7. public partial class ProfileWindow
  8. {
  9. // Color index equal to timing flag type as int
  10. private Color[] _timingFlagColors = new[]
  11. {
  12. new Color(150, 25, 25, 50), // FrameSwap = 0
  13. new Color(25, 25, 150, 50), // SystemFrame = 1
  14. };
  15. private TimingFlag[] _timingFlags;
  16. private const float GraphMoveSpeed = 40000;
  17. private const float GraphZoomSpeed = 50;
  18. private float _graphZoom = 1;
  19. private float _graphPosition = 0;
  20. private void DrawGraph(float xOffset, float yOffset, float width)
  21. {
  22. if (_sortedProfileData.Count != 0)
  23. {
  24. int left, right;
  25. float top, bottom;
  26. int verticalIndex = 0;
  27. float graphRight = xOffset + width;
  28. float barHeight = (LineHeight - LinePadding);
  29. long history = Profile.HistoryLength;
  30. double timeWidthTicks = history / (double)_graphZoom;
  31. long graphPositionTicks = (long)(_graphPosition * PerformanceCounter.TicksPerMillisecond);
  32. long ticksPerPixel = (long)(timeWidthTicks / width);
  33. // Reset start point if out of bounds
  34. if (timeWidthTicks + graphPositionTicks > history)
  35. {
  36. graphPositionTicks = history - (long)timeWidthTicks;
  37. _graphPosition = (float)graphPositionTicks / PerformanceCounter.TicksPerMillisecond;
  38. }
  39. graphPositionTicks = _captureTime - graphPositionTicks;
  40. GL.Enable(EnableCap.ScissorTest);
  41. // Draw timing flags
  42. if (_displayFlags)
  43. {
  44. TimingFlagType prevType = TimingFlagType.Count;
  45. GL.Enable(EnableCap.Blend);
  46. GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
  47. GL.Begin(PrimitiveType.Lines);
  48. foreach (TimingFlag timingFlag in _timingFlags)
  49. {
  50. if (prevType != timingFlag.FlagType)
  51. {
  52. prevType = timingFlag.FlagType;
  53. GL.Color4(_timingFlagColors[(int)prevType]);
  54. }
  55. int x = (int)(graphRight - ((graphPositionTicks - timingFlag.Timestamp) / timeWidthTicks) * width);
  56. GL.Vertex2(x, 0);
  57. GL.Vertex2(x, Height);
  58. }
  59. GL.End();
  60. GL.Disable(EnableCap.Blend);
  61. }
  62. // Draw bars
  63. GL.Begin(PrimitiveType.Triangles);
  64. foreach (var entry in _sortedProfileData)
  65. {
  66. long furthest = 0;
  67. bottom = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex);
  68. top = bottom + barHeight;
  69. // Skip rendering out of bounds bars
  70. if (top < 0 || bottom > Height)
  71. {
  72. verticalIndex++;
  73. continue;
  74. }
  75. GL.Color3(Color.Green);
  76. foreach (Timestamp timestamp in entry.Value.GetAllTimestamps())
  77. {
  78. // Skip drawing multiple timestamps on same pixel
  79. if (timestamp.EndTime < furthest)
  80. continue;
  81. furthest = timestamp.EndTime + ticksPerPixel;
  82. left = (int)(graphRight - ((graphPositionTicks - timestamp.BeginTime) / timeWidthTicks) * width);
  83. right = (int)(graphRight - ((graphPositionTicks - timestamp.EndTime) / timeWidthTicks) * width);
  84. // Make sure width is at least 1px
  85. right = Math.Max(left + 1, right);
  86. GL.Vertex2(left, bottom);
  87. GL.Vertex2(left, top);
  88. GL.Vertex2(right, top);
  89. GL.Vertex2(right, top);
  90. GL.Vertex2(right, bottom);
  91. GL.Vertex2(left, bottom);
  92. }
  93. // Currently capturing timestamp
  94. GL.Color3(Color.Red);
  95. long entryBegin = entry.Value.BeginTime;
  96. if (entryBegin != -1)
  97. {
  98. left = (int)(graphRight - ((graphPositionTicks - entryBegin) / timeWidthTicks) * width);
  99. // Make sure width is at least 1px
  100. left = Math.Min(left - 1, (int)graphRight);
  101. GL.Vertex2(left, bottom);
  102. GL.Vertex2(left, top);
  103. GL.Vertex2(graphRight, top);
  104. GL.Vertex2(graphRight, top);
  105. GL.Vertex2(graphRight, bottom);
  106. GL.Vertex2(left, bottom);
  107. }
  108. verticalIndex++;
  109. }
  110. GL.End();
  111. GL.Disable(EnableCap.ScissorTest);
  112. string label = $"-{MathF.Round(_graphPosition, 2)} ms";
  113. // Dummy draw for measure
  114. float labelWidth = _fontService.DrawText(label, 0, 0, LineHeight, false);
  115. _fontService.DrawText(label, graphRight - labelWidth - LinePadding, FilterHeight + LinePadding, LineHeight);
  116. _fontService.DrawText($"-{MathF.Round((float)((timeWidthTicks / PerformanceCounter.TicksPerMillisecond) + _graphPosition), 2)} ms", xOffset + LinePadding, FilterHeight + LinePadding, LineHeight);
  117. }
  118. }
  119. }
  120. }