diff options
Diffstat (limited to 'Ryujinx.Debugger/UI/ProfilerWidget.cs')
| -rw-r--r-- | Ryujinx.Debugger/UI/ProfilerWidget.cs | 803 |
1 files changed, 0 insertions, 803 deletions
diff --git a/Ryujinx.Debugger/UI/ProfilerWidget.cs b/Ryujinx.Debugger/UI/ProfilerWidget.cs deleted file mode 100644 index 84dff5de..00000000 --- a/Ryujinx.Debugger/UI/ProfilerWidget.cs +++ /dev/null @@ -1,803 +0,0 @@ -using Gtk; -using Ryujinx.Common; -using Ryujinx.Debugger.Profiler; -using SkiaSharp; -using SkiaSharp.Views.Desktop; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading; - -using GUI = Gtk.Builder.ObjectAttribute; - -namespace Ryujinx.Debugger.UI -{ - public class ProfilerWidget : Box - { - private Thread _profilerThread; - private double _prevTime; - private bool _profilerRunning; - - private TimingFlag[] _timingFlags; - - private bool _initComplete = false; - private bool _redrawPending = true; - private bool _doStep = false; - - // Layout - private const int LineHeight = 16; - private const int MinimumColumnWidth = 200; - private const int TitleHeight = 24; - private const int TitleFontHeight = 16; - private const int LinePadding = 2; - private const int ColumnSpacing = 15; - private const int FilterHeight = 24; - private const int BottomBarHeight = FilterHeight + LineHeight; - - // Sorting - private List<KeyValuePair<ProfileConfig, TimingInfo>> _unsortedProfileData; - private IComparer<KeyValuePair<ProfileConfig, TimingInfo>> _sortAction = new ProfileSorters.TagAscending(); - - // Flag data - private long[] _timingFlagsAverages; - private long[] _timingFlagsLast; - - // Filtering - private string _filterText = ""; - private bool _regexEnabled = false; - - // Scrolling - private float _scrollPos = 0; - - // Profile data storage - private List<KeyValuePair<ProfileConfig, TimingInfo>> _sortedProfileData; - private long _captureTime; - - // Graph - private SKColor[] _timingFlagColors = new[] - { - new SKColor(150, 25, 25, 50), // FrameSwap = 0 - new SKColor(25, 25, 150, 50), // SystemFrame = 1 - }; - - private const float GraphMoveSpeed = 40000; - private const float GraphZoomSpeed = 50; - - private float _graphZoom = 1; - private float _graphPosition = 0; - private int _rendererHeight => _renderer.AllocatedHeight; - private int _rendererWidth => _renderer.AllocatedWidth; - - // Event management - private long _lastOutputUpdate; - private long _lastOutputDraw; - private long _lastOutputUpdateDuration; - private long _lastOutputDrawDuration; - private double _lastFrameTimeMs; - private double _updateTimer; - private bool _profileUpdated = false; - private readonly object _profileDataLock = new object(); - - private SkRenderer _renderer; - -#pragma warning disable CS0649 - [GUI] ScrolledWindow _scrollview; - [GUI] CheckButton _enableCheckbutton; - [GUI] Scrollbar _outputScrollbar; - [GUI] Entry _filterBox; - [GUI] ComboBox _modeBox; - [GUI] CheckButton _showFlags; - [GUI] CheckButton _showInactive; - [GUI] Button _stepButton; - [GUI] CheckButton _pauseCheckbutton; -#pragma warning restore CS0649 - - public ProfilerWidget() : this(new Builder("Ryujinx.Debugger.UI.ProfilerWidget.glade")) { } - - public ProfilerWidget(Builder builder) : base(builder.GetObject("_profilerBox").Handle) - { - builder.Autoconnect(this); - - this.KeyPressEvent += ProfilerWidget_KeyPressEvent; - - this.Expand = true; - - _renderer = new SkRenderer(); - _renderer.Expand = true; - - _outputScrollbar.ValueChanged += _outputScrollbar_ValueChanged; - - _renderer.DrawGraphs += _renderer_DrawGraphs; - - _filterBox.Changed += _filterBox_Changed; - - _stepButton.Clicked += _stepButton_Clicked; - - _scrollview.Add(_renderer); - - if (Profile.UpdateRate <= 0) - { - // Perform step regardless of flag type - Profile.RegisterFlagReceiver((t) => - { - if (_pauseCheckbutton.Active) - { - _doStep = true; - } - }); - } - } - - private void _stepButton_Clicked(object sender, EventArgs e) - { - if (_pauseCheckbutton.Active) - { - _doStep = true; - } - - _profileUpdated = true; - } - - private void _filterBox_Changed(object sender, EventArgs e) - { - _filterText = _filterBox.Text; - _profileUpdated = true; - } - - private void _outputScrollbar_ValueChanged(object sender, EventArgs e) - { - _scrollPos = -(float)Math.Max(0, _outputScrollbar.Value); - _profileUpdated = true; - } - - private void _renderer_DrawGraphs(object sender, EventArgs e) - { - if (e is SKPaintSurfaceEventArgs se) - { - Draw(se.Surface.Canvas); - } - } - - public void RegisterParentDebugger(DebuggerWidget debugger) - { - debugger.DebuggerEnabled += Debugger_DebuggerAttached; - debugger.DebuggerDisabled += Debugger_DebuggerDettached; - } - - private void Debugger_DebuggerDettached(object sender, EventArgs e) - { - _profilerRunning = false; - - if (_profilerThread != null) - { - _profilerThread.Join(); - } - } - - private void Debugger_DebuggerAttached(object sender, EventArgs e) - { - _profilerRunning = false; - - if (_profilerThread != null) - { - _profilerThread.Join(); - } - - _profilerRunning = true; - - _profilerThread = new Thread(UpdateLoop) - { - Name = "Profiler.UpdateThread" - }; - _profilerThread.Start(); - } - - private void ProfilerWidget_KeyPressEvent(object o, Gtk.KeyPressEventArgs args) - { - switch (args.Event.Key) - { - case Gdk.Key.Left: - _graphPosition += (long)(GraphMoveSpeed * _lastFrameTimeMs); - break; - - case Gdk.Key.Right: - _graphPosition = Math.Max(_graphPosition - (long)(GraphMoveSpeed * _lastFrameTimeMs), 0); - break; - - case Gdk.Key.Up: - _graphZoom = MathF.Min(_graphZoom + (float)(GraphZoomSpeed * _lastFrameTimeMs), 100.0f); - break; - - case Gdk.Key.Down: - _graphZoom = MathF.Max(_graphZoom - (float)(GraphZoomSpeed * _lastFrameTimeMs), 1f); - break; - } - _profileUpdated = true; - } - - public void UpdateLoop() - { - _lastOutputUpdate = PerformanceCounter.ElapsedTicks; - _lastOutputDraw = PerformanceCounter.ElapsedTicks; - - while (_profilerRunning) - { - _lastOutputUpdate = PerformanceCounter.ElapsedTicks; - int timeToSleepMs = (_pauseCheckbutton.Active || !_enableCheckbutton.Active) ? 33 : 1; - - if (Profile.ProfilingEnabled() && _enableCheckbutton.Active) - { - double time = (double)PerformanceCounter.ElapsedTicks / PerformanceCounter.TicksPerSecond; - - Update(time - _prevTime); - - _lastOutputUpdateDuration = PerformanceCounter.ElapsedTicks - _lastOutputUpdate; - _prevTime = time; - - Gdk.Threads.AddIdle(1000, ()=> - { - _renderer.QueueDraw(); - - return true; - }); - } - - Thread.Sleep(timeToSleepMs); - } - } - - public void Update(double frameTime) - { - _lastFrameTimeMs = frameTime; - - // Get timing data if enough time has passed - _updateTimer += frameTime; - - if (_doStep || ((Profile.UpdateRate > 0) && (!_pauseCheckbutton.Active && (_updateTimer > Profile.UpdateRate)))) - { - _updateTimer = 0; - _captureTime = PerformanceCounter.ElapsedTicks; - _timingFlags = Profile.GetTimingFlags(); - _doStep = false; - _profileUpdated = true; - - _unsortedProfileData = Profile.GetProfilingData(); - - (_timingFlagsAverages, _timingFlagsLast) = Profile.GetTimingAveragesAndLast(); - } - - // Filtering - if (_profileUpdated) - { - lock (_profileDataLock) - { - _sortedProfileData = _showInactive.Active ? _unsortedProfileData : _unsortedProfileData.FindAll(kvp => kvp.Value.IsActive); - - if (_sortAction != null) - { - _sortedProfileData.Sort(_sortAction); - } - - if (_regexEnabled) - { - try - { - Regex filterRegex = new Regex(_filterText, RegexOptions.IgnoreCase); - if (_filterText != "") - { - _sortedProfileData = _sortedProfileData.Where((pair => filterRegex.IsMatch(pair.Key.Search))).ToList(); - } - } - catch (ArgumentException) - { - // Skip filtering for invalid regex - } - } - else - { - // Regular filtering - _sortedProfileData = _sortedProfileData.Where((pair => pair.Key.Search.ToLower().Contains(_filterText.ToLower()))).ToList(); - } - } - - _profileUpdated = false; - _redrawPending = true; - _initComplete = true; - } - } - - private string GetTimeString(long timestamp) - { - float time = (float)timestamp / PerformanceCounter.TicksPerMillisecond; - - return (time < 1) ? $"{time * 1000:F3}us" : $"{time:F3}ms"; - } - - private void FilterBackspace() - { - if (_filterText.Length <= 1) - { - _filterText = ""; - } - else - { - _filterText = _filterText.Remove(_filterText.Length - 1, 1); - } - } - - private float GetLineY(float offset, float lineHeight, float padding, bool centre, int line) - { - return offset + lineHeight + padding + ((lineHeight + padding) * line) - ((centre) ? padding : 0); - } - - public void Draw(SKCanvas canvas) - { - _lastOutputDraw = PerformanceCounter.ElapsedTicks; - if (!Visible || - !_initComplete || - !_enableCheckbutton.Active || - !_redrawPending) - { - return; - } - - float viewTop = TitleHeight + 5; - float viewBottom = _rendererHeight - FilterHeight - LineHeight; - - float columnWidth; - float maxColumnWidth = MinimumColumnWidth; - float yOffset = _scrollPos + viewTop; - float xOffset = 10; - float timingWidth; - - float contentHeight = GetLineY(0, LineHeight, LinePadding, false, _sortedProfileData.Count - 1); - - _outputScrollbar.Adjustment.Upper = contentHeight; - _outputScrollbar.Adjustment.Lower = 0; - _outputScrollbar.Adjustment.PageSize = viewBottom - viewTop; - - - SKPaint textFont = new SKPaint() - { - Color = SKColors.White, - TextSize = LineHeight - }; - - SKPaint titleFont = new SKPaint() - { - Color = SKColors.White, - TextSize = TitleFontHeight - }; - - SKPaint evenItemBackground = new SKPaint() - { - Color = SKColors.Gray - }; - - canvas.Save(); - canvas.ClipRect(new SKRect(0, viewTop, _rendererWidth, viewBottom), SKClipOperation.Intersect); - - for (int i = 1; i < _sortedProfileData.Count; i += 2) - { - float top = GetLineY(yOffset, LineHeight, LinePadding, false, i - 1); - float bottom = GetLineY(yOffset, LineHeight, LinePadding, false, i); - - canvas.DrawRect(new SKRect(0, top, _rendererWidth, bottom), evenItemBackground); - } - - lock (_profileDataLock) - { - // Display category - - for (int verticalIndex = 0; verticalIndex < _sortedProfileData.Count; verticalIndex++) - { - KeyValuePair<ProfileConfig, TimingInfo> entry = _sortedProfileData[verticalIndex]; - - if (entry.Key.Category == null) - { - continue; - } - - float y = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex); - - canvas.DrawText(entry.Key.Category, new SKPoint(xOffset, y), textFont); - - columnWidth = textFont.MeasureText(entry.Key.Category); - - if (columnWidth > maxColumnWidth) - { - maxColumnWidth = columnWidth; - } - } - - canvas.Restore(); - canvas.DrawText("Category", new SKPoint(xOffset, TitleFontHeight + 2), titleFont); - - columnWidth = titleFont.MeasureText("Category"); - - if (columnWidth > maxColumnWidth) - { - maxColumnWidth = columnWidth; - } - - xOffset += maxColumnWidth + ColumnSpacing; - - canvas.DrawLine(new SKPoint(xOffset - ColumnSpacing / 2, 0), new SKPoint(xOffset - ColumnSpacing / 2, viewBottom), textFont); - - // Display session group - maxColumnWidth = MinimumColumnWidth; - - canvas.Save(); - canvas.ClipRect(new SKRect(0, viewTop, _rendererWidth, viewBottom), SKClipOperation.Intersect); - - for (int verticalIndex = 0; verticalIndex < _sortedProfileData.Count; verticalIndex++) - { - KeyValuePair<ProfileConfig, TimingInfo> entry = _sortedProfileData[verticalIndex]; - - if (entry.Key.SessionGroup == null) - { - continue; - } - - float y = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex); - - canvas.DrawText(entry.Key.SessionGroup, new SKPoint(xOffset, y), textFont); - - columnWidth = textFont.MeasureText(entry.Key.SessionGroup); - - if (columnWidth > maxColumnWidth) - { - maxColumnWidth = columnWidth; - } - } - - canvas.Restore(); - canvas.DrawText("Group", new SKPoint(xOffset, TitleFontHeight + 2), titleFont); - - columnWidth = titleFont.MeasureText("Group"); - - if (columnWidth > maxColumnWidth) - { - maxColumnWidth = columnWidth; - } - - xOffset += maxColumnWidth + ColumnSpacing; - - canvas.DrawLine(new SKPoint(xOffset - ColumnSpacing / 2, 0), new SKPoint(xOffset - ColumnSpacing / 2, viewBottom), textFont); - - // Display session item - maxColumnWidth = MinimumColumnWidth; - - canvas.Save(); - canvas.ClipRect(new SKRect(0, viewTop, _rendererWidth, viewBottom), SKClipOperation.Intersect); - - for (int verticalIndex = 0; verticalIndex < _sortedProfileData.Count; verticalIndex++) - { - KeyValuePair<ProfileConfig, TimingInfo> entry = _sortedProfileData[verticalIndex]; - - if (entry.Key.SessionItem == null) - { - continue; - } - - float y = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex); - - canvas.DrawText(entry.Key.SessionItem, new SKPoint(xOffset, y), textFont); - - columnWidth = textFont.MeasureText(entry.Key.SessionItem); - - if (columnWidth > maxColumnWidth) - { - maxColumnWidth = columnWidth; - } - } - - canvas.Restore(); - canvas.DrawText("Item", new SKPoint(xOffset, TitleFontHeight + 2), titleFont); - - columnWidth = titleFont.MeasureText("Item"); - - if (columnWidth > maxColumnWidth) - { - maxColumnWidth = columnWidth; - } - - xOffset += maxColumnWidth + ColumnSpacing; - - timingWidth = _rendererWidth - xOffset - 370; - - canvas.Save(); - canvas.ClipRect(new SKRect(0, viewTop, _rendererWidth, viewBottom), SKClipOperation.Intersect); - canvas.DrawLine(new SKPoint(xOffset, 0), new SKPoint(xOffset, _rendererHeight), textFont); - - int mode = _modeBox.Active; - - canvas.Save(); - canvas.ClipRect(new SKRect(xOffset, yOffset,xOffset + timingWidth,yOffset + contentHeight), - SKClipOperation.Intersect); - - switch (mode) - { - case 0: - DrawGraph(xOffset, yOffset, timingWidth, canvas); - break; - case 1: - DrawBars(xOffset, yOffset, timingWidth, canvas); - - canvas.DrawText("Blue: Instant, Green: Avg, Red: Total", - new SKPoint(xOffset, _rendererHeight - TitleFontHeight), titleFont); - break; - } - - canvas.Restore(); - canvas.DrawLine(new SKPoint(xOffset + timingWidth, 0), new SKPoint(xOffset + timingWidth, _rendererHeight), textFont); - - xOffset = _rendererWidth - 360; - - // Display timestamps - long totalInstant = 0; - long totalAverage = 0; - long totalTime = 0; - long totalCount = 0; - - for (int verticalIndex = 0; verticalIndex < _sortedProfileData.Count; verticalIndex++) - { - KeyValuePair<ProfileConfig, TimingInfo> entry = _sortedProfileData[verticalIndex]; - - float y = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex); - - canvas.DrawText($"{GetTimeString(entry.Value.Instant)} ({entry.Value.InstantCount})", new SKPoint(xOffset, y), textFont); - canvas.DrawText(GetTimeString(entry.Value.AverageTime), new SKPoint(150 + xOffset, y), textFont); - canvas.DrawText(GetTimeString(entry.Value.TotalTime), new SKPoint(260 + xOffset, y), textFont); - - totalInstant += entry.Value.Instant; - totalAverage += entry.Value.AverageTime; - totalTime += entry.Value.TotalTime; - totalCount += entry.Value.InstantCount; - } - - canvas.Restore(); - canvas.DrawLine(new SKPoint(0, viewTop), new SKPoint(_rendererWidth, viewTop), titleFont); - - float yHeight = 0 + TitleFontHeight; - - canvas.DrawText("Instant (Count)", new SKPoint(xOffset, yHeight), titleFont); - canvas.DrawText("Average", new SKPoint(150 + xOffset, yHeight), titleFont); - canvas.DrawText("Total (ms)", new SKPoint(260 + xOffset, yHeight), titleFont); - - // Totals - yHeight = _rendererHeight - FilterHeight + 3; - - int textHeight = LineHeight - 2; - - SKPaint detailFont = new SKPaint() - { - Color = new SKColor(100, 100, 255, 255), - TextSize = textHeight - }; - - canvas.DrawLine(new SkiaSharp.SKPoint(0, viewBottom), new SkiaSharp.SKPoint(_rendererWidth,viewBottom), textFont); - - string hostTimeString = $"Host {GetTimeString(_timingFlagsLast[(int)TimingFlagType.SystemFrame])} " + - $"({GetTimeString(_timingFlagsAverages[(int)TimingFlagType.SystemFrame])})"; - - canvas.DrawText(hostTimeString, new SKPoint(5, yHeight), detailFont); - - float tempWidth = detailFont.MeasureText(hostTimeString); - - detailFont.Color = SKColors.Red; - - string gameTimeString = $"Game {GetTimeString(_timingFlagsLast[(int)TimingFlagType.FrameSwap])} " + - $"({GetTimeString(_timingFlagsAverages[(int)TimingFlagType.FrameSwap])})"; - - canvas.DrawText(gameTimeString, new SKPoint(15 + tempWidth, yHeight), detailFont); - - tempWidth += detailFont.MeasureText(gameTimeString); - - detailFont.Color = SKColors.White; - - canvas.DrawText($"Profiler: Update {GetTimeString(_lastOutputUpdateDuration)} Draw {GetTimeString(_lastOutputDrawDuration)}", - new SKPoint(20 + tempWidth, yHeight), detailFont); - - detailFont.Color = SKColors.White; - - canvas.DrawText($"{GetTimeString(totalInstant)} ({totalCount})", new SKPoint(xOffset, yHeight), detailFont); - canvas.DrawText(GetTimeString(totalAverage), new SKPoint(150 + xOffset, yHeight), detailFont); - canvas.DrawText(GetTimeString(totalTime), new SKPoint(260 + xOffset, yHeight), detailFont); - - _lastOutputDrawDuration = PerformanceCounter.ElapsedTicks - _lastOutputDraw; - } - } - - private void DrawGraph(float xOffset, float yOffset, float width, SKCanvas canvas) - { - if (_sortedProfileData.Count != 0) - { - int left, right; - float top, bottom; - - 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; - - // Draw timing flags - if (_showFlags.Active) - { - TimingFlagType prevType = TimingFlagType.Count; - - SKPaint timingPaint = new SKPaint - { - Color = _timingFlagColors.First() - }; - - foreach (TimingFlag timingFlag in _timingFlags) - { - if (prevType != timingFlag.FlagType) - { - prevType = timingFlag.FlagType; - timingPaint.Color = _timingFlagColors[(int)prevType]; - } - - int x = (int)(graphRight - ((graphPositionTicks - timingFlag.Timestamp) / timeWidthTicks) * width); - - if (x > xOffset) - { - canvas.DrawLine(new SKPoint(x, yOffset), new SKPoint(x, _rendererHeight), timingPaint); - } - } - } - - SKPaint barPaint = new SKPaint() - { - Color = SKColors.Green, - }; - - // Draw bars - for (int verticalIndex = 0; verticalIndex < _sortedProfileData.Count; verticalIndex++) - { - KeyValuePair<ProfileConfig, TimingInfo> entry = _sortedProfileData[verticalIndex]; - long furthest = 0; - - bottom = GetLineY(yOffset, LineHeight, LinePadding, false, verticalIndex); - top = bottom + barHeight; - - // Skip rendering out of bounds bars - if (top < 0 || bottom > _rendererHeight) - { - continue; - } - - barPaint.Color = SKColors.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); - - left = (int)Math.Max(xOffset +1, left); - - // Make sure width is at least 1px - right = Math.Max(left + 1, right); - - canvas.DrawRect(new SKRect(left, top, right, bottom), barPaint); - } - - // Currently capturing timestamp - barPaint.Color = SKColors.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); - - left = (int)Math.Max(xOffset + 1, left); - - canvas.DrawRect(new SKRect(left, top, graphRight, bottom), barPaint); - } - } - - string label = $"-{MathF.Round(_graphPosition, 2)} ms"; - - SKPaint labelPaint = new SKPaint() - { - Color = SKColors.White, - TextSize = LineHeight - }; - - float labelWidth = labelPaint.MeasureText(label); - - canvas.DrawText(label,new SKPoint(graphRight - labelWidth - LinePadding, FilterHeight + LinePadding) , labelPaint); - - canvas.DrawText($"-{MathF.Round((float)((timeWidthTicks / PerformanceCounter.TicksPerMillisecond) + _graphPosition), 2)} ms", - new SKPoint(xOffset + LinePadding, FilterHeight + LinePadding), labelPaint); - } - } - - private void DrawBars(float xOffset, float yOffset, float width, SKCanvas canvas) - { - if (_sortedProfileData.Count != 0) - { - long maxAverage = 0; - long maxTotal = 0; - long maxInstant = 0; - - float barHeight = (LineHeight - LinePadding) / 3.0f; - - // Get max values - foreach (KeyValuePair<ProfileConfig, TimingInfo> kvp in _sortedProfileData) - { - maxInstant = Math.Max(maxInstant, kvp.Value.Instant); - maxAverage = Math.Max(maxAverage, kvp.Value.AverageTime); - maxTotal = Math.Max(maxTotal, kvp.Value.TotalTime); - } - - SKPaint barPaint = new SKPaint() - { - Color = SKColors.Blue - }; - - for (int verticalIndex = 0; verticalIndex < _sortedProfileData.Count; verticalIndex++) - { - KeyValuePair<ProfileConfig, TimingInfo> entry = _sortedProfileData[verticalIndex]; - // Instant - barPaint.Color = SKColors.Blue; - - float bottom = GetLineY(yOffset, LineHeight, LinePadding, false, verticalIndex); - float top = bottom + barHeight; - float right = (float)entry.Value.Instant / maxInstant * width + xOffset; - - // Skip rendering out of bounds bars - if (top < 0 || bottom > _rendererHeight) - { - continue; - } - - canvas.DrawRect(new SKRect(xOffset, top, right, bottom), barPaint); - - // Average - barPaint.Color = SKColors.Green; - - top += barHeight; - bottom += barHeight; - right = (float)entry.Value.AverageTime / maxAverage * width + xOffset; - - canvas.DrawRect(new SKRect(xOffset, top, right, bottom), barPaint); - - // Total - barPaint.Color = SKColors.Red; - - top += barHeight; - bottom += barHeight; - right = (float)entry.Value.TotalTime / maxTotal * width + xOffset; - - canvas.DrawRect(new SKRect(xOffset, top, right, bottom), barPaint); - } - } - } - } -} |
