diff options
Diffstat (limited to 'Ryujinx.Profiler/UI')
| -rw-r--r-- | Ryujinx.Profiler/UI/ProfileButton.cs | 110 | ||||
| -rw-r--r-- | Ryujinx.Profiler/UI/ProfileSorters.cs | 32 | ||||
| -rw-r--r-- | Ryujinx.Profiler/UI/ProfileWindow.cs | 773 | ||||
| -rw-r--r-- | Ryujinx.Profiler/UI/ProfileWindowBars.cs | 85 | ||||
| -rw-r--r-- | Ryujinx.Profiler/UI/ProfileWindowGraph.cs | 151 | ||||
| -rw-r--r-- | Ryujinx.Profiler/UI/ProfileWindowManager.cs | 95 | ||||
| -rw-r--r-- | Ryujinx.Profiler/UI/SharpFontHelpers/FontService.cs | 257 |
7 files changed, 0 insertions, 1503 deletions
diff --git a/Ryujinx.Profiler/UI/ProfileButton.cs b/Ryujinx.Profiler/UI/ProfileButton.cs deleted file mode 100644 index 7e2ae728..00000000 --- a/Ryujinx.Profiler/UI/ProfileButton.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using OpenTK; -using OpenTK.Graphics.OpenGL; -using Ryujinx.Profiler.UI.SharpFontHelpers; - -namespace Ryujinx.Profiler.UI -{ - public class ProfileButton - { - // Store font service - private FontService _fontService; - - // Layout information - private int _left, _right; - private int _bottom, _top; - private int _height; - private int _padding; - - // Label information - private int _labelX, _labelY; - private string _label; - - // Misc - private Action _clicked; - private bool _visible; - - public ProfileButton(FontService fontService, Action clicked) - : this(fontService, clicked, 0, 0, 0, 0, 0) - { - _visible = false; - } - - public ProfileButton(FontService fontService, Action clicked, int x, int y, int padding, int height, int width) - : this(fontService, "", clicked, x, y, padding, height, width) - { - _visible = false; - } - - public ProfileButton(FontService fontService, string label, Action clicked, int x, int y, int padding, int height, int width = -1) - { - _fontService = fontService; - _clicked = clicked; - - UpdateSize(label, x, y, padding, height, width); - } - - public int UpdateSize(string label, int x, int y, int padding, int height, int width = -1) - { - _visible = true; - _label = label; - - if (width == -1) - { - // Dummy draw to measure size - width = (int)_fontService.DrawText(label, 0, 0, height, false); - } - - UpdateSize(x, y, padding, width, height); - - return _right - _left; - } - - public void UpdateSize(int x, int y, int padding, int width, int height) - { - _height = height; - _left = x; - _bottom = y; - _labelX = x + padding / 2; - _labelY = y + padding / 2; - _top = y + height + padding; - _right = x + width + padding; - } - - public void Draw() - { - if (!_visible) - { - return; - } - - // Draw backing rectangle - GL.Begin(PrimitiveType.Triangles); - GL.Color3(Color.Black); - GL.Vertex2(_left, _bottom); - GL.Vertex2(_left, _top); - GL.Vertex2(_right, _top); - - GL.Vertex2(_right, _top); - GL.Vertex2(_right, _bottom); - GL.Vertex2(_left, _bottom); - GL.End(); - - // Use font service to draw label - _fontService.DrawText(_label, _labelX, _labelY, _height); - } - - public bool ProcessClick(int x, int y) - { - // If button contains x, y - if (x > _left && x < _right && - y > _bottom && y < _top) - { - _clicked(); - return true; - } - - return false; - } - } -} diff --git a/Ryujinx.Profiler/UI/ProfileSorters.cs b/Ryujinx.Profiler/UI/ProfileSorters.cs deleted file mode 100644 index 9f66de22..00000000 --- a/Ryujinx.Profiler/UI/ProfileSorters.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Ryujinx.Profiler.UI -{ - public static class ProfileSorters - { - public class InstantAscending : IComparer<KeyValuePair<ProfileConfig, TimingInfo>> - { - public int Compare(KeyValuePair<ProfileConfig, TimingInfo> pair1, KeyValuePair<ProfileConfig, TimingInfo> pair2) - => pair2.Value.Instant.CompareTo(pair1.Value.Instant); - } - - public class AverageAscending : IComparer<KeyValuePair<ProfileConfig, TimingInfo>> - { - public int Compare(KeyValuePair<ProfileConfig, TimingInfo> pair1, KeyValuePair<ProfileConfig, TimingInfo> pair2) - => pair2.Value.AverageTime.CompareTo(pair1.Value.AverageTime); - } - - public class TotalAscending : IComparer<KeyValuePair<ProfileConfig, TimingInfo>> - { - public int Compare(KeyValuePair<ProfileConfig, TimingInfo> pair1, KeyValuePair<ProfileConfig, TimingInfo> pair2) - => pair2.Value.TotalTime.CompareTo(pair1.Value.TotalTime); - } - - public class TagAscending : IComparer<KeyValuePair<ProfileConfig, TimingInfo>> - { - public int Compare(KeyValuePair<ProfileConfig, TimingInfo> pair1, KeyValuePair<ProfileConfig, TimingInfo> pair2) - => StringComparer.CurrentCulture.Compare(pair1.Key.Search, pair2.Key.Search); - } - } -} diff --git a/Ryujinx.Profiler/UI/ProfileWindow.cs b/Ryujinx.Profiler/UI/ProfileWindow.cs deleted file mode 100644 index 1db70bc7..00000000 --- a/Ryujinx.Profiler/UI/ProfileWindow.cs +++ /dev/null @@ -1,773 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text.RegularExpressions; -using OpenTK; -using OpenTK.Graphics; -using OpenTK.Graphics.OpenGL; -using OpenTK.Input; -using Ryujinx.Common; -using Ryujinx.Profiler.UI.SharpFontHelpers; - -namespace Ryujinx.Profiler.UI -{ - public partial class ProfileWindow : GameWindow - { - // List all buttons for index in button array - private enum ButtonIndex - { - TagTitle = 0, - InstantTitle = 1, - AverageTitle = 2, - TotalTitle = 3, - FilterBar = 4, - ShowHideInactive = 5, - Pause = 6, - ChangeDisplay = 7, - - // Don't automatically draw after here - ToggleFlags = 8, - Step = 9, - - // Update this when new buttons are added. - // These are indexes to the enum list - Autodraw = 8, - Count = 10, - } - - // Font service - private FontService _fontService; - - // UI variables - private ProfileButton[] _buttons; - - private bool _initComplete = false; - private bool _visible = true; - private bool _visibleChanged = true; - private bool _viewportUpdated = true; - private bool _redrawPending = true; - private bool _displayGraph = true; - private bool _displayFlags = true; - private bool _showInactive = true; - private bool _paused = false; - private bool _doStep = false; - - // Layout - private const int LineHeight = 16; - 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; - private float _minScroll = 0; - private float _maxScroll = 0; - - // Profile data storage - private List<KeyValuePair<ProfileConfig, TimingInfo>> _sortedProfileData; - private long _captureTime; - - // Input - private bool _backspaceDown = false; - private bool _prevBackspaceDown = false; - private double _backspaceDownTime = 0; - - // F35 used as no key - private Key _graphControlKey = Key.F35; - - // Event management - private double _updateTimer; - private double _processEventTimer; - private bool _profileUpdated = false; - private readonly object _profileDataLock = new object(); - - public ProfileWindow() - // Graphics mode enables 2xAA - : base(1280, 720, new GraphicsMode(new ColorFormat(8, 8, 8, 8), 1, 1, 2)) - { - Title = "Profiler"; - Location = new Point(DisplayDevice.Default.Width - 1280, - (DisplayDevice.Default.Height - 720) - 50); - - if (Profile.UpdateRate <= 0) - { - // Perform step regardless of flag type - Profile.RegisterFlagReceiver((t) => - { - if (!_paused) - { - _doStep = true; - } - }); - } - - // Large number to force an update on first update - _updateTimer = 0xFFFF; - - Init(); - - // Release context for render thread - Context.MakeCurrent(null); - } - - public void ToggleVisible() - { - _visible = !_visible; - _visibleChanged = true; - } - - private void SetSort(IComparer<KeyValuePair<ProfileConfig, TimingInfo>> filter) - { - _sortAction = filter; - _profileUpdated = true; - } - -#region OnLoad - /// <summary> - /// Setup OpenGL and load resources - /// </summary> - public void Init() - { - GL.ClearColor(Color.Black); - _fontService = new FontService(); - _fontService.InitializeTextures(); - _fontService.UpdateScreenHeight(Height); - - _buttons = new ProfileButton[(int)ButtonIndex.Count]; - _buttons[(int)ButtonIndex.TagTitle] = new ProfileButton(_fontService, () => SetSort(new ProfileSorters.TagAscending())); - _buttons[(int)ButtonIndex.InstantTitle] = new ProfileButton(_fontService, () => SetSort(new ProfileSorters.InstantAscending())); - _buttons[(int)ButtonIndex.AverageTitle] = new ProfileButton(_fontService, () => SetSort(new ProfileSorters.AverageAscending())); - _buttons[(int)ButtonIndex.TotalTitle] = new ProfileButton(_fontService, () => SetSort(new ProfileSorters.TotalAscending())); - _buttons[(int)ButtonIndex.Step] = new ProfileButton(_fontService, () => _doStep = true); - _buttons[(int)ButtonIndex.FilterBar] = new ProfileButton(_fontService, () => - { - _profileUpdated = true; - _regexEnabled = !_regexEnabled; - }); - - _buttons[(int)ButtonIndex.ShowHideInactive] = new ProfileButton(_fontService, () => - { - _profileUpdated = true; - _showInactive = !_showInactive; - }); - - _buttons[(int)ButtonIndex.Pause] = new ProfileButton(_fontService, () => - { - _profileUpdated = true; - _paused = !_paused; - }); - - _buttons[(int)ButtonIndex.ToggleFlags] = new ProfileButton(_fontService, () => - { - _displayFlags = !_displayFlags; - _redrawPending = true; - }); - - _buttons[(int)ButtonIndex.ChangeDisplay] = new ProfileButton(_fontService, () => - { - _displayGraph = !_displayGraph; - _redrawPending = true; - }); - - Visible = _visible; - } -#endregion - -#region OnResize - /// <summary> - /// Respond to resize events - /// </summary> - /// <param name="e">Contains information on the new GameWindow size.</param> - /// <remarks>There is no need to call the base implementation.</remarks> - protected override void OnResize(EventArgs e) - { - _viewportUpdated = true; - } -#endregion - -#region OnClose - /// <summary> - /// Intercept close event and hide instead - /// </summary> - protected override void OnClosing(CancelEventArgs e) - { - // Hide window - _visible = false; - _visibleChanged = true; - - // Cancel close - e.Cancel = true; - - base.OnClosing(e); - } -#endregion - -#region OnUpdateFrame - /// <summary> - /// Profile Update Loop - /// </summary> - /// <param name="e">Contains timing information.</param> - /// <remarks>There is no need to call the base implementation.</remarks> - public void Update(FrameEventArgs e) - { - if (_visibleChanged) - { - Visible = _visible; - _visibleChanged = false; - } - - // Backspace handling - if (_backspaceDown) - { - if (!_prevBackspaceDown) - { - _backspaceDownTime = 0; - FilterBackspace(); - } - else - { - _backspaceDownTime += e.Time; - if (_backspaceDownTime > 0.3) - { - _backspaceDownTime -= 0.05; - FilterBackspace(); - } - } - } - _prevBackspaceDown = _backspaceDown; - - // Get timing data if enough time has passed - _updateTimer += e.Time; - if (_doStep || ((Profile.UpdateRate > 0) && (!_paused && (_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 ? _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 argException) - { - // 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; - } - - // Check for events 20 times a second - _processEventTimer += e.Time; - if (_processEventTimer > 0.05) - { - ProcessEvents(); - - if (_graphControlKey != Key.F35) - { - switch (_graphControlKey) - { - case Key.Left: - _graphPosition += (long) (GraphMoveSpeed * e.Time); - break; - - case Key.Right: - _graphPosition = Math.Max(_graphPosition - (long) (GraphMoveSpeed * e.Time), 0); - break; - - case Key.Up: - _graphZoom = MathF.Min(_graphZoom + (float) (GraphZoomSpeed * e.Time), 100.0f); - break; - - case Key.Down: - _graphZoom = MathF.Max(_graphZoom - (float) (GraphZoomSpeed * e.Time), 1f); - break; - } - - _redrawPending = true; - } - - _processEventTimer = 0; - } - } -#endregion - -#region OnRenderFrame - /// <summary> - /// Profile Render Loop - /// </summary> - /// <remarks>There is no need to call the base implementation.</remarks> - public void Draw() - { - if (!_visible || !_initComplete) - { - return; - } - - // Update viewport - if (_viewportUpdated) - { - GL.Viewport(0, 0, Width, Height); - - GL.MatrixMode(MatrixMode.Projection); - GL.LoadIdentity(); - GL.Ortho(0, Width, 0, Height, 0.0, 4.0); - - _fontService.UpdateScreenHeight(Height); - - _viewportUpdated = false; - _redrawPending = true; - } - - if (!_redrawPending) - { - return; - } - - // Frame setup - GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - GL.ClearColor(Color.Black); - - _fontService.fontColor = Color.White; - int verticalIndex = 0; - - float width; - float maxWidth = 0; - float yOffset = _scrollPos - TitleHeight; - float xOffset = 10; - float timingDataLeft; - float timingWidth; - - // Background lines to make reading easier - #region Background Lines - GL.Enable(EnableCap.ScissorTest); - GL.Scissor(0, BottomBarHeight, Width, Height - TitleHeight - BottomBarHeight); - GL.Begin(PrimitiveType.Triangles); - GL.Color3(0.2f, 0.2f, 0.2f); - for (int i = 0; i < _sortedProfileData.Count; i += 2) - { - float top = GetLineY(yOffset, LineHeight, LinePadding, false, i - 1); - float bottom = GetLineY(yOffset, LineHeight, LinePadding, false, i); - - // Skip rendering out of bounds bars - if (top < 0 || bottom > Height) - continue; - - GL.Vertex2(0, bottom); - GL.Vertex2(0, top); - GL.Vertex2(Width, top); - - GL.Vertex2(Width, top); - GL.Vertex2(Width, bottom); - GL.Vertex2(0, bottom); - } - GL.End(); - _maxScroll = (LineHeight + LinePadding) * (_sortedProfileData.Count - 1); -#endregion - - lock (_profileDataLock) - { -// Display category -#region Category - verticalIndex = 0; - foreach (var entry in _sortedProfileData) - { - if (entry.Key.Category == null) - { - verticalIndex++; - continue; - } - - float y = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex++); - width = _fontService.DrawText(entry.Key.Category, xOffset, y, LineHeight); - - if (width > maxWidth) - { - maxWidth = width; - } - } - GL.Disable(EnableCap.ScissorTest); - - width = _fontService.DrawText("Category", xOffset, Height - TitleFontHeight, TitleFontHeight); - if (width > maxWidth) - maxWidth = width; - - xOffset += maxWidth + ColumnSpacing; -#endregion - -// Display session group -#region Session Group - maxWidth = 0; - verticalIndex = 0; - - GL.Enable(EnableCap.ScissorTest); - foreach (var entry in _sortedProfileData) - { - if (entry.Key.SessionGroup == null) - { - verticalIndex++; - continue; - } - - float y = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex++); - width = _fontService.DrawText(entry.Key.SessionGroup, xOffset, y, LineHeight); - - if (width > maxWidth) - { - maxWidth = width; - } - } - GL.Disable(EnableCap.ScissorTest); - - width = _fontService.DrawText("Group", xOffset, Height - TitleFontHeight, TitleFontHeight); - if (width > maxWidth) - maxWidth = width; - - xOffset += maxWidth + ColumnSpacing; -#endregion - -// Display session item -#region Session Item - maxWidth = 0; - verticalIndex = 0; - GL.Enable(EnableCap.ScissorTest); - foreach (var entry in _sortedProfileData) - { - if (entry.Key.SessionItem == null) - { - verticalIndex++; - continue; - } - - float y = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex++); - width = _fontService.DrawText(entry.Key.SessionItem, xOffset, y, LineHeight); - - if (width > maxWidth) - { - maxWidth = width; - } - } - GL.Disable(EnableCap.ScissorTest); - - width = _fontService.DrawText("Item", xOffset, Height - TitleFontHeight, TitleFontHeight); - if (width > maxWidth) - maxWidth = width; - - xOffset += maxWidth + ColumnSpacing; - _buttons[(int)ButtonIndex.TagTitle].UpdateSize(0, Height - TitleFontHeight, 0, (int)xOffset, TitleFontHeight); -#endregion - - // Timing data - timingWidth = Width - xOffset - 370; - timingDataLeft = xOffset; - - GL.Scissor((int)xOffset, BottomBarHeight, (int)timingWidth, Height - TitleHeight - BottomBarHeight); - - if (_displayGraph) - { - DrawGraph(xOffset, yOffset, timingWidth); - } - else - { - DrawBars(xOffset, yOffset, timingWidth); - } - - GL.Scissor(0, BottomBarHeight, Width, Height - TitleHeight - BottomBarHeight); - - if (!_displayGraph) - { - _fontService.DrawText("Blue: Instant, Green: Avg, Red: Total", xOffset, Height - TitleFontHeight, TitleFontHeight); - } - - xOffset = Width - 360; - -// Display timestamps -#region Timestamps - verticalIndex = 0; - long totalInstant = 0; - long totalAverage = 0; - long totalTime = 0; - long totalCount = 0; - - GL.Enable(EnableCap.ScissorTest); - foreach (var entry in _sortedProfileData) - { - float y = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex++); - - _fontService.DrawText($"{GetTimeString(entry.Value.Instant)} ({entry.Value.InstantCount})", xOffset, y, LineHeight); - - _fontService.DrawText(GetTimeString(entry.Value.AverageTime), 150 + xOffset, y, LineHeight); - - _fontService.DrawText(GetTimeString(entry.Value.TotalTime), 260 + xOffset, y, LineHeight); - - totalInstant += entry.Value.Instant; - totalAverage += entry.Value.AverageTime; - totalTime += entry.Value.TotalTime; - totalCount += entry.Value.InstantCount; - } - GL.Disable(EnableCap.ScissorTest); - - float yHeight = Height - TitleFontHeight; - - _fontService.DrawText("Instant (Count)", xOffset, yHeight, TitleFontHeight); - _buttons[(int)ButtonIndex.InstantTitle].UpdateSize((int)xOffset, (int)yHeight, 0, 130, TitleFontHeight); - - _fontService.DrawText("Average", 150 + xOffset, yHeight, TitleFontHeight); - _buttons[(int)ButtonIndex.AverageTitle].UpdateSize((int)(150 + xOffset), (int)yHeight, 0, 130, TitleFontHeight); - - _fontService.DrawText("Total (ms)", 260 + xOffset, yHeight, TitleFontHeight); - _buttons[(int)ButtonIndex.TotalTitle].UpdateSize((int)(260 + xOffset), (int)yHeight, 0, Width, TitleFontHeight); - - // Totals - yHeight = FilterHeight + 3; - int textHeight = LineHeight - 2; - - _fontService.fontColor = new Color(100, 100, 255, 255); - float tempWidth = _fontService.DrawText($"Host {GetTimeString(_timingFlagsLast[(int)TimingFlagType.SystemFrame])} " + - $"({GetTimeString(_timingFlagsAverages[(int)TimingFlagType.SystemFrame])})", 5, yHeight, textHeight); - - _fontService.fontColor = Color.Red; - _fontService.DrawText($"Game {GetTimeString(_timingFlagsLast[(int)TimingFlagType.FrameSwap])} " + - $"({GetTimeString(_timingFlagsAverages[(int)TimingFlagType.FrameSwap])})", 15 + tempWidth, yHeight, textHeight); - _fontService.fontColor = Color.White; - - - _fontService.DrawText($"{GetTimeString(totalInstant)} ({totalCount})", xOffset, yHeight, textHeight); - _fontService.DrawText(GetTimeString(totalAverage), 150 + xOffset, yHeight, textHeight); - _fontService.DrawText(GetTimeString(totalTime), 260 + xOffset, yHeight, textHeight); -#endregion - } - -#region Bottom bar - // Show/Hide Inactive - float widthShowHideButton = _buttons[(int)ButtonIndex.ShowHideInactive].UpdateSize($"{(_showInactive ? "Hide" : "Show")} Inactive", 5, 5, 4, 16); - - // Play/Pause - float widthPlayPauseButton = _buttons[(int)ButtonIndex.Pause].UpdateSize(_paused ? "Play" : "Pause", 15 + (int)widthShowHideButton, 5, 4, 16) + widthShowHideButton; - - // Step - float widthStepButton = widthPlayPauseButton; - - if (_paused) - { - widthStepButton += _buttons[(int)ButtonIndex.Step].UpdateSize("Step", (int)(25 + widthPlayPauseButton), 5, 4, 16) + 10; - _buttons[(int)ButtonIndex.Step].Draw(); - } - - // Change display - float widthChangeDisplay = _buttons[(int)ButtonIndex.ChangeDisplay].UpdateSize($"View: {(_displayGraph ? "Graph" : "Bars")}", 25 + (int)widthStepButton, 5, 4, 16) + widthStepButton; - - width = widthChangeDisplay; - - if (_displayGraph) - { - width += _buttons[(int) ButtonIndex.ToggleFlags].UpdateSize($"{(_displayFlags ? "Hide" : "Show")} Flags", 35 + (int)widthChangeDisplay, 5, 4, 16) + 10; - _buttons[(int)ButtonIndex.ToggleFlags].Draw(); - } - - // Filter bar - _fontService.DrawText($"{(_regexEnabled ? "Regex " : "Filter")}: {_filterText}", 35 + width, 7, 16); - _buttons[(int)ButtonIndex.FilterBar].UpdateSize((int)(45 + width), 0, 0, Width, FilterHeight); -#endregion - - // Draw buttons - for (int i = 0; i < (int)ButtonIndex.Autodraw; i++) - { - _buttons[i].Draw(); - } - -// Dividing lines -#region Dividing lines - GL.Color3(Color.White); - GL.Begin(PrimitiveType.Lines); - // Top divider - GL.Vertex2(0, Height -TitleHeight); - GL.Vertex2(Width, Height - TitleHeight); - - // Bottom divider - GL.Vertex2(0, FilterHeight); - GL.Vertex2(Width, FilterHeight); - - GL.Vertex2(0, BottomBarHeight); - GL.Vertex2(Width, BottomBarHeight); - - // Bottom vertical dividers - GL.Vertex2(widthShowHideButton + 10, 0); - GL.Vertex2(widthShowHideButton + 10, FilterHeight); - - GL.Vertex2(widthPlayPauseButton + 20, 0); - GL.Vertex2(widthPlayPauseButton + 20, FilterHeight); - - if (_paused) - { - GL.Vertex2(widthStepButton + 20, 0); - GL.Vertex2(widthStepButton + 20, FilterHeight); - } - - if (_displayGraph) - { - GL.Vertex2(widthChangeDisplay + 30, 0); - GL.Vertex2(widthChangeDisplay + 30, FilterHeight); - } - - GL.Vertex2(width + 30, 0); - GL.Vertex2(width + 30, FilterHeight); - - // Column dividers - float timingDataTop = Height - TitleHeight; - - GL.Vertex2(timingDataLeft, FilterHeight); - GL.Vertex2(timingDataLeft, timingDataTop); - - GL.Vertex2(timingWidth + timingDataLeft, FilterHeight); - GL.Vertex2(timingWidth + timingDataLeft, timingDataTop); - GL.End(); -#endregion - - _redrawPending = false; - SwapBuffers(); - } -#endregion - - 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 Height + offset - lineHeight - padding - ((lineHeight + padding) * line) + ((centre) ? padding : 0); - } - - protected override void OnKeyPress(KeyPressEventArgs e) - { - _filterText += e.KeyChar; - _profileUpdated = true; - } - - protected override void OnKeyDown(KeyboardKeyEventArgs e) - { - switch (e.Key) - { - case Key.BackSpace: - _profileUpdated = _backspaceDown = true; - return; - - case Key.Left: - case Key.Right: - case Key.Up: - case Key.Down: - _graphControlKey = e.Key; - return; - } - base.OnKeyUp(e); - } - - protected override void OnKeyUp(KeyboardKeyEventArgs e) - { - // Can't go into switch as value isn't constant - if (e.Key == Profile.Controls.Buttons.ToggleProfiler) - { - ToggleVisible(); - return; - } - - switch (e.Key) - { - case Key.BackSpace: - _backspaceDown = false; - return; - - case Key.Left: - case Key.Right: - case Key.Up: - case Key.Down: - _graphControlKey = Key.F35; - return; - } - base.OnKeyUp(e); - } - - protected override void OnMouseUp(MouseButtonEventArgs e) - { - foreach (ProfileButton button in _buttons) - { - if (button.ProcessClick(e.X, Height - e.Y)) - return; - } - } - - protected override void OnMouseWheel(MouseWheelEventArgs e) - { - _scrollPos += e.Delta * -30; - if (_scrollPos < _minScroll) - _scrollPos = _minScroll; - if (_scrollPos > _maxScroll) - _scrollPos = _maxScroll; - - _redrawPending = true; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Profiler/UI/ProfileWindowBars.cs b/Ryujinx.Profiler/UI/ProfileWindowBars.cs deleted file mode 100644 index ab5b4fd1..00000000 --- a/Ryujinx.Profiler/UI/ProfileWindowBars.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; -using OpenTK; -using OpenTK.Graphics.OpenGL; - -namespace Ryujinx.Profiler.UI -{ - public partial class ProfileWindow - { - private void DrawBars(float xOffset, float yOffset, float width) - { - if (_sortedProfileData.Count != 0) - { - long maxAverage; - long maxTotal; - - int verticalIndex = 0; - float barHeight = (LineHeight - LinePadding) / 3.0f; - - // Get max values - long maxInstant = maxAverage = maxTotal = 0; - 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); - } - - GL.Enable(EnableCap.ScissorTest); - GL.Begin(PrimitiveType.Triangles); - foreach (var entry in _sortedProfileData) - { - // Instant - GL.Color3(Color.Blue); - float bottom = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex++); - float top = bottom + barHeight; - float right = (float)entry.Value.Instant / maxInstant * width + xOffset; - - // Skip rendering out of bounds bars - if (top < 0 || bottom > Height) - continue; - - GL.Vertex2(xOffset, bottom); - GL.Vertex2(xOffset, top); - GL.Vertex2(right, top); - - GL.Vertex2(right, top); - GL.Vertex2(right, bottom); - GL.Vertex2(xOffset, bottom); - - // Average - GL.Color3(Color.Green); - top += barHeight; - bottom += barHeight; - right = (float)entry.Value.AverageTime / maxAverage * width + xOffset; - - GL.Vertex2(xOffset, bottom); - GL.Vertex2(xOffset, top); - GL.Vertex2(right, top); - - GL.Vertex2(right, top); - GL.Vertex2(right, bottom); - GL.Vertex2(xOffset, bottom); - - // Total - GL.Color3(Color.Red); - top += barHeight; - bottom += barHeight; - right = (float)entry.Value.TotalTime / maxTotal * width + xOffset; - - GL.Vertex2(xOffset, bottom); - GL.Vertex2(xOffset, top); - GL.Vertex2(right, top); - - GL.Vertex2(right, top); - GL.Vertex2(right, bottom); - GL.Vertex2(xOffset, bottom); - } - - GL.End(); - GL.Disable(EnableCap.ScissorTest); - } - } - } -} diff --git a/Ryujinx.Profiler/UI/ProfileWindowGraph.cs b/Ryujinx.Profiler/UI/ProfileWindowGraph.cs deleted file mode 100644 index 6a4a52a9..00000000 --- a/Ryujinx.Profiler/UI/ProfileWindowGraph.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System; -using OpenTK; -using OpenTK.Graphics.OpenGL; -using Ryujinx.Common; - -namespace Ryujinx.Profiler.UI -{ - public partial class ProfileWindow - { - // Color index equal to timing flag type as int - private Color[] _timingFlagColors = 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(_timingFlagColors[(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); - } - } - } -} diff --git a/Ryujinx.Profiler/UI/ProfileWindowManager.cs b/Ryujinx.Profiler/UI/ProfileWindowManager.cs deleted file mode 100644 index 13603029..00000000 --- a/Ryujinx.Profiler/UI/ProfileWindowManager.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System.Threading; -using OpenTK; -using OpenTK.Input; -using Ryujinx.Common; - -namespace Ryujinx.Profiler.UI -{ - public class ProfileWindowManager - { - private ProfileWindow _window; - private Thread _profileThread; - private Thread _renderThread; - private bool _profilerRunning; - - // Timing - private double _prevTime; - - public ProfileWindowManager() - { - if (Profile.ProfilingEnabled()) - { - _profilerRunning = true; - _prevTime = 0; - _profileThread = new Thread(ProfileLoop) - { - Name = "Profiler.ProfileThread" - }; - _profileThread.Start(); - } - } - - public void ToggleVisible() - { - if (Profile.ProfilingEnabled()) - { - _window.ToggleVisible(); - } - } - - public void Close() - { - if (_window != null) - { - _profilerRunning = false; - _window.Close(); - _window.Dispose(); - } - - _window = null; - } - - public void UpdateKeyInput(KeyboardState keyboard) - { - if (Profile.Controls.TogglePressed(keyboard)) - { - ToggleVisible(); - } - Profile.Controls.SetPrevKeyboardState(keyboard); - } - - private void ProfileLoop() - { - using (_window = new ProfileWindow()) - { - // Create thread for render loop - _renderThread = new Thread(RenderLoop) - { - Name = "Profiler.RenderThread" - }; - _renderThread.Start(); - - while (_profilerRunning) - { - double time = (double)PerformanceCounter.ElapsedTicks / PerformanceCounter.TicksPerSecond; - _window.Update(new FrameEventArgs(time - _prevTime)); - _prevTime = time; - - // Sleep to be less taxing, update usually does very little - Thread.Sleep(1); - } - } - } - - private void RenderLoop() - { - _window.Context.MakeCurrent(_window.WindowInfo); - - while (_profilerRunning) - { - _window.Draw(); - Thread.Sleep(1); - } - } - } -} diff --git a/Ryujinx.Profiler/UI/SharpFontHelpers/FontService.cs b/Ryujinx.Profiler/UI/SharpFontHelpers/FontService.cs deleted file mode 100644 index 32846977..00000000 --- a/Ryujinx.Profiler/UI/SharpFontHelpers/FontService.cs +++ /dev/null @@ -1,257 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; -using OpenTK; -using OpenTK.Graphics.OpenGL; -using SharpFont; - -namespace Ryujinx.Profiler.UI.SharpFontHelpers -{ - public class FontService - { - private struct CharacterInfo - { - public float Left; - public float Right; - public float Top; - public float Bottom; - - public int Width; - public float Height; - - public float AspectRatio; - - public float BearingX; - public float BearingY; - public float Advance; - } - - private const int SheetWidth = 1024; - private const int SheetHeight = 512; - private int ScreenWidth, ScreenHeight; - private int CharacterTextureSheet; - private CharacterInfo[] characters; - - public Color fontColor { get; set; } = Color.Black; - - private string GetFontPath() - { - string fontFolder = Environment.GetFolderPath(Environment.SpecialFolder.Fonts); - - // Only uses Arial, add more fonts here if wanted - string path = Path.Combine(fontFolder, "arial.ttf"); - if (File.Exists(path)) - { - return path; - } - - throw new Exception($"Profiler exception. Required font Courier New or Arial not installed to {fontFolder}"); - } - - public void InitializeTextures() - { - // Create and init some vars - uint[] rawCharacterSheet = new uint[SheetWidth * SheetHeight]; - int x; - int y; - int lineOffset; - int maxHeight; - - x = y = lineOffset = maxHeight = 0; - characters = new CharacterInfo[94]; - - // Get font - var font = new FontFace(File.OpenRead(GetFontPath())); - - // Update raw data for each character - for (int i = 0; i < 94; i++) - { - var surface = RenderSurface((char)(i + 33), font, out float xBearing, out float yBearing, out float advance); - - characters[i] = UpdateTexture(surface, ref rawCharacterSheet, ref x, ref y, ref lineOffset); - characters[i].BearingX = xBearing; - characters[i].BearingY = yBearing; - characters[i].Advance = advance; - - if (maxHeight < characters[i].Height) - maxHeight = (int)characters[i].Height; - } - - // Fix height for characters shorter than line height - for (int i = 0; i < 94; i++) - { - characters[i].BearingX /= characters[i].Width; - characters[i].BearingY /= maxHeight; - characters[i].Advance /= characters[i].Width; - characters[i].Height /= maxHeight; - characters[i].AspectRatio = (float)characters[i].Width / maxHeight; - } - - // Convert raw data into texture - CharacterTextureSheet = GL.GenTexture(); - GL.BindTexture(TextureTarget.Texture2D, CharacterTextureSheet); - - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Clamp); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Clamp); - - GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, SheetWidth, SheetHeight, 0, PixelFormat.Rgba, PixelType.UnsignedInt8888, rawCharacterSheet); - - GL.BindTexture(TextureTarget.Texture2D, 0); - } - - public void UpdateScreenHeight(int height) - { - ScreenHeight = height; - } - - public float DrawText(string text, float x, float y, float height, bool draw = true) - { - float originalX = x; - - // Skip out of bounds draw - if (y < height * -2 || y > ScreenHeight + height * 2) - { - draw = false; - } - - if (draw) - { - // Use font map texture - GL.BindTexture(TextureTarget.Texture2D, CharacterTextureSheet); - - // Enable blending and textures - GL.Enable(EnableCap.Texture2D); - GL.Enable(EnableCap.Blend); - GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); - - // Draw all characters - GL.Begin(PrimitiveType.Triangles); - GL.Color4(fontColor); - } - - for (int i = 0; i < text.Length; i++) - { - if (text[i] == ' ') - { - x += height / 4; - continue; - } - - CharacterInfo charInfo = characters[text[i] - 33]; - float width = (charInfo.AspectRatio * height); - x += (charInfo.BearingX * charInfo.AspectRatio) * width; - float right = x + width; - if (draw) - { - DrawChar(charInfo, x, right, y + height * (charInfo.Height - charInfo.BearingY), y - height * charInfo.BearingY); - } - x = right + charInfo.Advance * charInfo.AspectRatio + 1; - } - - if (draw) - { - GL.End(); - - // Cleanup for caller - GL.BindTexture(TextureTarget.Texture2D, 0); - GL.Disable(EnableCap.Texture2D); - GL.Disable(EnableCap.Blend); - } - - // Return width of rendered text - return x - originalX; - } - - private void DrawChar(CharacterInfo charInfo, float left, float right, float top, float bottom) - { - GL.TexCoord2(charInfo.Left, charInfo.Bottom); GL.Vertex2(left, bottom); - GL.TexCoord2(charInfo.Left, charInfo.Top); GL.Vertex2(left, top); - GL.TexCoord2(charInfo.Right, charInfo.Top); GL.Vertex2(right, top); - - GL.TexCoord2(charInfo.Right, charInfo.Top); GL.Vertex2(right, top); - GL.TexCoord2(charInfo.Right, charInfo.Bottom); GL.Vertex2(right, bottom); - GL.TexCoord2(charInfo.Left, charInfo.Bottom); GL.Vertex2(left, bottom); - } - - public unsafe Surface RenderSurface(char c, FontFace font, out float xBearing, out float yBearing, out float advance) - { - var glyph = font.GetGlyph(c, 64); - xBearing = glyph.HorizontalMetrics.Bearing.X; - yBearing = glyph.RenderHeight - glyph.HorizontalMetrics.Bearing.Y; - advance = glyph.HorizontalMetrics.Advance; - - var surface = new Surface - { - Bits = Marshal.AllocHGlobal(glyph.RenderWidth * glyph.RenderHeight), - Width = glyph.RenderWidth, - Height = glyph.RenderHeight, - Pitch = glyph.RenderWidth - }; - - var stuff = (byte*)surface.Bits; - for (int i = 0; i < surface.Width * surface.Height; i++) - *stuff++ = 0; - - glyph.RenderTo(surface); - - return surface; - } - - private CharacterInfo UpdateTexture(Surface surface, ref uint[] rawCharMap, ref int posX, ref int posY, ref int lineOffset) - { - int width = surface.Width; - int height = surface.Height; - int len = width * height; - byte[] data = new byte[len]; - - // Get character bitmap - Marshal.Copy(surface.Bits, data, 0, len); - - // Find a slot - if (posX + width > SheetWidth) - { - posX = 0; - posY += lineOffset; - lineOffset = 0; - } - - // Update lineOffset - if (lineOffset < height) - { - lineOffset = height + 1; - } - - // Copy char to sheet - for (int y = 0; y < height; y++) - { - int destOffset = (y + posY) * SheetWidth + posX; - int sourceOffset = y * width; - - for (int x = 0; x < width; x++) - { - rawCharMap[destOffset + x] = (uint)((0xFFFFFF << 8) | data[sourceOffset + x]); - } - } - - // Generate character info - CharacterInfo charInfo = new CharacterInfo() - { - Left = (float)posX / SheetWidth, - Right = (float)(posX + width) / SheetWidth, - Top = (float)(posY - 1) / SheetHeight, - Bottom = (float)(posY + height) / SheetHeight, - Width = width, - Height = height, - }; - - // Update x - posX += width + 1; - - // Give the memory back - Marshal.FreeHGlobal(surface.Bits); - return charInfo; - } - } -}
\ No newline at end of file |
