aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Profiler/UI/ProfileWindowGraph.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Profiler/UI/ProfileWindowGraph.cs')
-rw-r--r--Ryujinx.Profiler/UI/ProfileWindowGraph.cs151
1 files changed, 151 insertions, 0 deletions
diff --git a/Ryujinx.Profiler/UI/ProfileWindowGraph.cs b/Ryujinx.Profiler/UI/ProfileWindowGraph.cs
new file mode 100644
index 00000000..9d34be97
--- /dev/null
+++ b/Ryujinx.Profiler/UI/ProfileWindowGraph.cs
@@ -0,0 +1,151 @@
+using System;
+using OpenTK;
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Common;
+
+namespace Ryujinx.Profiler.UI
+{
+ public partial class ProfileWindow
+ {
+ // Colour index equal to timing flag type as int
+ private Color[] _timingFlagColours = new[]
+ {
+ new Color(150, 25, 25, 50), // FrameSwap = 0
+ new Color(25, 25, 150, 50), // SystemFrame = 1
+ };
+
+ private TimingFlag[] _timingFlags;
+
+ private const float GraphMoveSpeed = 40000;
+ private const float GraphZoomSpeed = 50;
+
+ private float _graphZoom = 1;
+ private float _graphPosition = 0;
+
+ private void DrawGraph(float xOffset, float yOffset, float width)
+ {
+ if (_sortedProfileData.Count != 0)
+ {
+ int left, right;
+ float top, bottom;
+
+ int verticalIndex = 0;
+ float graphRight = xOffset + width;
+ float barHeight = (LineHeight - LinePadding);
+ long history = Profile.HistoryLength;
+ double timeWidthTicks = history / (double)_graphZoom;
+ long graphPositionTicks = (long)(_graphPosition * PerformanceCounter.TicksPerMillisecond);
+ long ticksPerPixel = (long)(timeWidthTicks / width);
+
+ // Reset start point if out of bounds
+ if (timeWidthTicks + graphPositionTicks > history)
+ {
+ graphPositionTicks = history - (long)timeWidthTicks;
+ _graphPosition = (float)graphPositionTicks / PerformanceCounter.TicksPerMillisecond;
+ }
+
+ graphPositionTicks = _captureTime - graphPositionTicks;
+
+ GL.Enable(EnableCap.ScissorTest);
+
+ // Draw timing flags
+ if (_displayFlags)
+ {
+ TimingFlagType prevType = TimingFlagType.Count;
+
+ GL.Enable(EnableCap.Blend);
+ GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
+
+ GL.Begin(PrimitiveType.Lines);
+ foreach (TimingFlag timingFlag in _timingFlags)
+ {
+ if (prevType != timingFlag.FlagType)
+ {
+ prevType = timingFlag.FlagType;
+ GL.Color4(_timingFlagColours[(int)prevType]);
+ }
+
+ int x = (int)(graphRight - ((graphPositionTicks - timingFlag.Timestamp) / timeWidthTicks) * width);
+ GL.Vertex2(x, 0);
+ GL.Vertex2(x, Height);
+ }
+ GL.End();
+ GL.Disable(EnableCap.Blend);
+ }
+
+ // Draw bars
+ GL.Begin(PrimitiveType.Triangles);
+ foreach (var entry in _sortedProfileData)
+ {
+ long furthest = 0;
+
+ bottom = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex);
+ top = bottom + barHeight;
+
+ // Skip rendering out of bounds bars
+ if (top < 0 || bottom > Height)
+ {
+ verticalIndex++;
+ continue;
+ }
+
+
+ GL.Color3(Color.Green);
+ foreach (Timestamp timestamp in entry.Value.GetAllTimestamps())
+ {
+ // Skip drawing multiple timestamps on same pixel
+ if (timestamp.EndTime < furthest)
+ continue;
+ furthest = timestamp.EndTime + ticksPerPixel;
+
+ left = (int)(graphRight - ((graphPositionTicks - timestamp.BeginTime) / timeWidthTicks) * width);
+ right = (int)(graphRight - ((graphPositionTicks - timestamp.EndTime) / timeWidthTicks) * width);
+
+ // Make sure width is at least 1px
+ right = Math.Max(left + 1, right);
+
+ GL.Vertex2(left, bottom);
+ GL.Vertex2(left, top);
+ GL.Vertex2(right, top);
+
+ GL.Vertex2(right, top);
+ GL.Vertex2(right, bottom);
+ GL.Vertex2(left, bottom);
+ }
+
+ // Currently capturing timestamp
+ GL.Color3(Color.Red);
+ long entryBegin = entry.Value.BeginTime;
+ if (entryBegin != -1)
+ {
+ left = (int)(graphRight - ((graphPositionTicks - entryBegin) / timeWidthTicks) * width);
+
+ // Make sure width is at least 1px
+ left = Math.Min(left - 1, (int)graphRight);
+
+ GL.Vertex2(left, bottom);
+ GL.Vertex2(left, top);
+ GL.Vertex2(graphRight, top);
+
+ GL.Vertex2(graphRight, top);
+ GL.Vertex2(graphRight, bottom);
+ GL.Vertex2(left, bottom);
+ }
+
+ verticalIndex++;
+ }
+
+ GL.End();
+ GL.Disable(EnableCap.ScissorTest);
+
+ string label = $"-{MathF.Round(_graphPosition, 2)} ms";
+
+ // Dummy draw for measure
+ float labelWidth = _fontService.DrawText(label, 0, 0, LineHeight, false);
+ _fontService.DrawText(label, graphRight - labelWidth - LinePadding, FilterHeight + LinePadding, LineHeight);
+
+ _fontService.DrawText($"-{MathF.Round((float)((timeWidthTicks / PerformanceCounter.TicksPerMillisecond) + _graphPosition), 2)} ms", xOffset + LinePadding, FilterHeight + LinePadding, LineHeight);
+ }
+ }
+ }
+}