aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Debugger
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Debugger')
-rw-r--r--Ryujinx.Debugger/Debugger.cs32
-rw-r--r--Ryujinx.Debugger/Profiler/DumpProfile.cs35
-rw-r--r--Ryujinx.Debugger/Profiler/InternalProfile.cs223
-rw-r--r--Ryujinx.Debugger/Profiler/Profile.cs143
-rw-r--r--Ryujinx.Debugger/Profiler/ProfileConfig.cs254
-rw-r--r--Ryujinx.Debugger/Profiler/ProfileSorters.cs32
-rw-r--r--Ryujinx.Debugger/Profiler/ProfilerConfiguration.cs29
-rw-r--r--Ryujinx.Debugger/Profiler/Settings.cs17
-rw-r--r--Ryujinx.Debugger/Profiler/TimingFlag.cs17
-rw-r--r--Ryujinx.Debugger/Profiler/TimingInfo.cs174
-rw-r--r--Ryujinx.Debugger/ProfilerConfig.jsonc28
-rw-r--r--Ryujinx.Debugger/Ryujinx.Debugger.csproj43
-rw-r--r--Ryujinx.Debugger/UI/DebuggerWidget.cs44
-rw-r--r--Ryujinx.Debugger/UI/DebuggerWidget.glade44
-rw-r--r--Ryujinx.Debugger/UI/ProfilerWidget.cs803
-rw-r--r--Ryujinx.Debugger/UI/ProfilerWidget.glade232
-rw-r--r--Ryujinx.Debugger/UI/SkRenderer.cs23
17 files changed, 0 insertions, 2173 deletions
diff --git a/Ryujinx.Debugger/Debugger.cs b/Ryujinx.Debugger/Debugger.cs
deleted file mode 100644
index 6dd3354c..00000000
--- a/Ryujinx.Debugger/Debugger.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using System;
-using Ryujinx.Debugger.UI;
-
-namespace Ryujinx.Debugger
-{
- public class Debugger : IDisposable
- {
- public DebuggerWidget Widget { get; set; }
-
- public Debugger()
- {
- Widget = new DebuggerWidget();
- }
-
- public void Enable()
- {
- Widget.Enable();
- }
-
- public void Disable()
- {
- Widget.Disable();
- }
-
- public void Dispose()
- {
- Disable();
-
- Widget.Dispose();
- }
- }
-}
diff --git a/Ryujinx.Debugger/Profiler/DumpProfile.cs b/Ryujinx.Debugger/Profiler/DumpProfile.cs
deleted file mode 100644
index e73314d4..00000000
--- a/Ryujinx.Debugger/Profiler/DumpProfile.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using Ryujinx.Common;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace Ryujinx.Debugger.Profiler
-{
- public static class DumpProfile
- {
- public static void ToFile(string path, InternalProfile profile)
- {
- String fileData = "Category,Session Group,Session Item,Count,Average(ms),Total(ms)\r\n";
-
- foreach (KeyValuePair<ProfileConfig, TimingInfo> time in profile.Timers.OrderBy(key => key.Key.Tag))
- {
- fileData += $"{time.Key.Category}," +
- $"{time.Key.SessionGroup}," +
- $"{time.Key.SessionItem}," +
- $"{time.Value.Count}," +
- $"{time.Value.AverageTime / PerformanceCounter.TicksPerMillisecond}," +
- $"{time.Value.TotalTime / PerformanceCounter.TicksPerMillisecond}\r\n";
- }
-
- // Ensure file directory exists before write
- FileInfo fileInfo = new FileInfo(path);
- if (fileInfo == null)
- throw new Exception("Unknown logging error, probably a bad file path");
- if (fileInfo.Directory != null && !fileInfo.Directory.Exists)
- Directory.CreateDirectory(fileInfo.Directory.FullName);
-
- File.WriteAllText(fileInfo.FullName, fileData);
- }
- }
-}
diff --git a/Ryujinx.Debugger/Profiler/InternalProfile.cs b/Ryujinx.Debugger/Profiler/InternalProfile.cs
deleted file mode 100644
index 0bda9e04..00000000
--- a/Ryujinx.Debugger/Profiler/InternalProfile.cs
+++ /dev/null
@@ -1,223 +0,0 @@
-using Ryujinx.Common;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Ryujinx.Debugger.Profiler
-{
- public class InternalProfile
- {
- private struct TimerQueueValue
- {
- public ProfileConfig Config;
- public long Time;
- public bool IsBegin;
- }
-
- internal Dictionary<ProfileConfig, TimingInfo> Timers { get; set; }
-
- private readonly object _timerQueueClearLock = new object();
- private ConcurrentQueue<TimerQueueValue> _timerQueue;
-
- private int _sessionCounter = 0;
-
- // Cleanup thread
- private readonly Thread _cleanupThread;
- private bool _cleanupRunning;
- private readonly long _history;
- private long _preserve;
-
- // Timing flags
- private TimingFlag[] _timingFlags;
- private long[] _timingFlagAverages;
- private long[] _timingFlagLast;
- private long[] _timingFlagLastDelta;
- private int _timingFlagCount;
- private int _timingFlagIndex;
-
- private int _maxFlags;
-
- private Action<TimingFlag> _timingFlagCallback;
-
- public InternalProfile(long history, int maxFlags)
- {
- _maxFlags = maxFlags;
- Timers = new Dictionary<ProfileConfig, TimingInfo>();
- _timingFlags = new TimingFlag[_maxFlags];
- _timingFlagAverages = new long[(int)TimingFlagType.Count];
- _timingFlagLast = new long[(int)TimingFlagType.Count];
- _timingFlagLastDelta = new long[(int)TimingFlagType.Count];
- _timerQueue = new ConcurrentQueue<TimerQueueValue>();
- _history = history;
- _cleanupRunning = true;
-
- // Create cleanup thread.
- _cleanupThread = new Thread(CleanupLoop)
- {
- Name = "Profiler.CleanupThread"
- };
- _cleanupThread.Start();
- }
-
- private void CleanupLoop()
- {
- bool queueCleared = false;
-
- while (_cleanupRunning)
- {
- // Ensure we only ever have 1 instance modifying timers or timerQueue
- if (Monitor.TryEnter(_timerQueueClearLock))
- {
- queueCleared = ClearTimerQueue();
-
- // Calculate before foreach to mitigate redundant calculations
- long cleanupBefore = PerformanceCounter.ElapsedTicks - _history;
- long preserveStart = _preserve - _history;
-
- // Each cleanup is self contained so run in parallel for maximum efficiency
- Parallel.ForEach(Timers, (t) => t.Value.Cleanup(cleanupBefore, preserveStart, _preserve));
-
- Monitor.Exit(_timerQueueClearLock);
- }
-
- // Only sleep if queue was successfully cleared
- if (queueCleared)
- {
- Thread.Sleep(5);
- }
- }
- }
-
- private bool ClearTimerQueue()
- {
- int count = 0;
-
- while (_timerQueue.TryDequeue(out TimerQueueValue item))
- {
- if (!Timers.TryGetValue(item.Config, out TimingInfo value))
- {
- value = new TimingInfo();
- Timers.Add(item.Config, value);
- }
-
- if (item.IsBegin)
- {
- value.Begin(item.Time);
- }
- else
- {
- value.End(item.Time);
- }
-
- // Don't block for too long as memory disposal is blocked while this function runs
- if (count++ > 10000)
- {
- return false;
- }
- }
-
- return true;
- }
-
- public void FlagTime(TimingFlagType flagType)
- {
- int flagId = (int)flagType;
-
- _timingFlags[_timingFlagIndex] = new TimingFlag()
- {
- FlagType = flagType,
- Timestamp = PerformanceCounter.ElapsedTicks
- };
-
- _timingFlagCount = Math.Max(_timingFlagCount + 1, _maxFlags);
-
- // Work out average
- if (_timingFlagLast[flagId] != 0)
- {
- _timingFlagLastDelta[flagId] = _timingFlags[_timingFlagIndex].Timestamp - _timingFlagLast[flagId];
- _timingFlagAverages[flagId] = (_timingFlagAverages[flagId] == 0) ? _timingFlagLastDelta[flagId] :
- (_timingFlagLastDelta[flagId] + _timingFlagAverages[flagId]) >> 1;
- }
- _timingFlagLast[flagId] = _timingFlags[_timingFlagIndex].Timestamp;
-
- // Notify subscribers
- _timingFlagCallback?.Invoke(_timingFlags[_timingFlagIndex]);
-
- if (++_timingFlagIndex >= _maxFlags)
- {
- _timingFlagIndex = 0;
- }
- }
-
- public void BeginProfile(ProfileConfig config)
- {
- _timerQueue.Enqueue(new TimerQueueValue()
- {
- Config = config,
- IsBegin = true,
- Time = PerformanceCounter.ElapsedTicks,
- });
- }
-
- public void EndProfile(ProfileConfig config)
- {
- _timerQueue.Enqueue(new TimerQueueValue()
- {
- Config = config,
- IsBegin = false,
- Time = PerformanceCounter.ElapsedTicks,
- });
- }
-
- public string GetSession()
- {
- // Can be called from multiple threads so we need to ensure no duplicate sessions are generated
- return Interlocked.Increment(ref _sessionCounter).ToString();
- }
-
- public List<KeyValuePair<ProfileConfig, TimingInfo>> GetProfilingData()
- {
- _preserve = PerformanceCounter.ElapsedTicks;
-
- lock (_timerQueueClearLock)
- {
- ClearTimerQueue();
- return Timers.ToList();
- }
- }
-
- public TimingFlag[] GetTimingFlags()
- {
- int count = Math.Max(_timingFlagCount, _maxFlags);
- TimingFlag[] outFlags = new TimingFlag[count];
-
- for (int i = 0, sourceIndex = _timingFlagIndex; i < count; i++, sourceIndex++)
- {
- if (sourceIndex >= _maxFlags)
- sourceIndex = 0;
- outFlags[i] = _timingFlags[sourceIndex];
- }
-
- return outFlags;
- }
-
- public (long[], long[]) GetTimingAveragesAndLast()
- {
- return (_timingFlagAverages, _timingFlagLastDelta);
- }
-
- public void RegisterFlagReceiver(Action<TimingFlag> receiver)
- {
- _timingFlagCallback = receiver;
- }
-
- public void Dispose()
- {
- _cleanupRunning = false;
- _cleanupThread.Join();
- }
- }
-}
diff --git a/Ryujinx.Debugger/Profiler/Profile.cs b/Ryujinx.Debugger/Profiler/Profile.cs
deleted file mode 100644
index 1be638da..00000000
--- a/Ryujinx.Debugger/Profiler/Profile.cs
+++ /dev/null
@@ -1,143 +0,0 @@
-using Ryujinx.Common;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-
-namespace Ryujinx.Debugger.Profiler
-{
- public static class Profile
- {
- public static float UpdateRate => _settings.UpdateRate;
- public static long HistoryLength => _settings.History;
-
-#pragma warning disable CS0649
- private static InternalProfile _profileInstance;
-#pragma warning restore CS0649
- private static ProfilerSettings _settings;
-
- [Conditional("USE_DEBUGGING")]
- public static void Initialize()
- {
- var config = ProfilerConfiguration.Load(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ProfilerConfig.jsonc"));
-
- _settings = new ProfilerSettings()
- {
- Enabled = config.Enabled,
- FileDumpEnabled = config.DumpPath != "",
- DumpLocation = config.DumpPath,
- UpdateRate = (config.UpdateRate <= 0) ? -1 : 1.0f / config.UpdateRate,
- History = (long)(config.History * PerformanceCounter.TicksPerSecond),
- MaxLevel = config.MaxLevel,
- MaxFlags = config.MaxFlags,
- };
- }
-
- public static bool ProfilingEnabled()
- {
-#if USE_DEBUGGING
- if (!_settings.Enabled)
- return false;
-
- if (_profileInstance == null)
- _profileInstance = new InternalProfile(_settings.History, _settings.MaxFlags);
-
- return true;
-#else
- return false;
-#endif
- }
-
- [Conditional("USE_DEBUGGING")]
- public static void FinishProfiling()
- {
- if (!ProfilingEnabled())
- return;
-
- if (_settings.FileDumpEnabled)
- DumpProfile.ToFile(_settings.DumpLocation, _profileInstance);
-
- _profileInstance.Dispose();
- }
-
- [Conditional("USE_DEBUGGING")]
- public static void FlagTime(TimingFlagType flagType)
- {
- if (!ProfilingEnabled())
- return;
- _profileInstance.FlagTime(flagType);
- }
-
- [Conditional("USE_DEBUGGING")]
- public static void RegisterFlagReceiver(Action<TimingFlag> receiver)
- {
- if (!ProfilingEnabled())
- return;
- _profileInstance.RegisterFlagReceiver(receiver);
- }
-
- [Conditional("USE_DEBUGGING")]
- public static void Begin(ProfileConfig config)
- {
- if (!ProfilingEnabled())
- return;
- if (config.Level > _settings.MaxLevel)
- return;
- _profileInstance.BeginProfile(config);
- }
-
- [Conditional("USE_DEBUGGING")]
- public static void End(ProfileConfig config)
- {
- if (!ProfilingEnabled())
- return;
- if (config.Level > _settings.MaxLevel)
- return;
- _profileInstance.EndProfile(config);
- }
-
- public static string GetSession()
- {
-#if USE_DEBUGGING
- if (!ProfilingEnabled())
- return null;
- return _profileInstance.GetSession();
-#else
- return "";
-#endif
- }
-
- public static List<KeyValuePair<ProfileConfig, TimingInfo>> GetProfilingData()
- {
-#if USE_DEBUGGING
- if (!ProfilingEnabled())
- return new List<KeyValuePair<ProfileConfig, TimingInfo>>();
- return _profileInstance.GetProfilingData();
-#else
- return new List<KeyValuePair<ProfileConfig, TimingInfo>>();
-#endif
- }
-
- public static TimingFlag[] GetTimingFlags()
- {
-#if USE_DEBUGGING
- if (!ProfilingEnabled())
- return new TimingFlag[0];
- return _profileInstance.GetTimingFlags();
-#else
- return new TimingFlag[0];
-#endif
- }
-
- public static (long[], long[]) GetTimingAveragesAndLast()
- {
-#if USE_DEBUGGING
- if (!ProfilingEnabled())
- return (new long[0], new long[0]);
- return _profileInstance.GetTimingAveragesAndLast();
-#else
- return (new long[0], new long[0]);
-#endif
- }
- }
-}
diff --git a/Ryujinx.Debugger/Profiler/ProfileConfig.cs b/Ryujinx.Debugger/Profiler/ProfileConfig.cs
deleted file mode 100644
index 0ec3e26d..00000000
--- a/Ryujinx.Debugger/Profiler/ProfileConfig.cs
+++ /dev/null
@@ -1,254 +0,0 @@
-using System;
-
-namespace Ryujinx.Debugger.Profiler
-{
- public struct ProfileConfig : IEquatable<ProfileConfig>
- {
- public string Category;
- public string SessionGroup;
- public string SessionItem;
-
- public int Level;
-
- // Private cached variables
- private string _cachedTag;
- private string _cachedSession;
- private string _cachedSearch;
-
- // Public helpers to get config in more user friendly format,
- // Cached because they never change and are called often
- public string Search
- {
- get
- {
- if (_cachedSearch == null)
- {
- _cachedSearch = $"{Category}.{SessionGroup}.{SessionItem}";
- }
-
- return _cachedSearch;
- }
- }
-
- public string Tag
- {
- get
- {
- if (_cachedTag == null)
- _cachedTag = $"{Category}{(Session == "" ? "" : $" ({Session})")}";
- return _cachedTag;
- }
- }
-
- public string Session
- {
- get
- {
- if (_cachedSession == null)
- {
- if (SessionGroup != null && SessionItem != null)
- {
- _cachedSession = $"{SessionGroup}: {SessionItem}";
- }
- else if (SessionGroup != null)
- {
- _cachedSession = $"{SessionGroup}";
- }
- else if (SessionItem != null)
- {
- _cachedSession = $"---: {SessionItem}";
- }
- else
- {
- _cachedSession = "";
- }
- }
-
- return _cachedSession;
- }
- }
-
- /// <summary>
- /// The default comparison is far too slow for the number of comparisons needed because it doesn't know what's important to compare
- /// </summary>
- /// <param name="obj">Object to compare to</param>
- /// <returns></returns>
- public bool Equals(ProfileConfig cmpObj)
- {
- // Order here is important.
- // Multiple entries with the same item is considerable less likely that multiple items with the same group.
- // Likewise for group and category.
- return (cmpObj.SessionItem == SessionItem &&
- cmpObj.SessionGroup == SessionGroup &&
- cmpObj.Category == Category);
- }
- }
-
- /// <summary>
- /// Predefined configs to make profiling easier,
- /// nested so you can reference as Profiles.Category.Group.Item where item and group may be optional
- /// </summary>
- public static class Profiles
- {
- public static class CPU
- {
- public static ProfileConfig TranslateTier0 = new ProfileConfig()
- {
- Category = "CPU",
- SessionGroup = "TranslateTier0"
- };
-
- public static ProfileConfig TranslateTier1 = new ProfileConfig()
- {
- Category = "CPU",
- SessionGroup = "TranslateTier1"
- };
- }
-
- public static class Input
- {
- public static ProfileConfig ControllerInput = new ProfileConfig
- {
- Category = "Input",
- SessionGroup = "ControllerInput"
- };
-
- public static ProfileConfig TouchInput = new ProfileConfig
- {
- Category = "Input",
- SessionGroup = "TouchInput"
- };
- }
-
- public static class GPU
- {
- public static class Engine2d
- {
- public static ProfileConfig TextureCopy = new ProfileConfig()
- {
- Category = "GPU.Engine2D",
- SessionGroup = "TextureCopy"
- };
- }
-
- public static class Engine3d
- {
- public static ProfileConfig CallMethod = new ProfileConfig()
- {
- Category = "GPU.Engine3D",
- SessionGroup = "CallMethod",
- };
-
- public static ProfileConfig VertexEnd = new ProfileConfig()
- {
- Category = "GPU.Engine3D",
- SessionGroup = "VertexEnd"
- };
-
- public static ProfileConfig ClearBuffers = new ProfileConfig()
- {
- Category = "GPU.Engine3D",
- SessionGroup = "ClearBuffers"
- };
-
- public static ProfileConfig SetFrameBuffer = new ProfileConfig()
- {
- Category = "GPU.Engine3D",
- SessionGroup = "SetFrameBuffer",
- };
-
- public static ProfileConfig SetZeta = new ProfileConfig()
- {
- Category = "GPU.Engine3D",
- SessionGroup = "SetZeta"
- };
-
- public static ProfileConfig UploadShaders = new ProfileConfig()
- {
- Category = "GPU.Engine3D",
- SessionGroup = "UploadShaders"
- };
-
- public static ProfileConfig UploadTextures = new ProfileConfig()
- {
- Category = "GPU.Engine3D",
- SessionGroup = "UploadTextures"
- };
-
- public static ProfileConfig UploadTexture = new ProfileConfig()
- {
- Category = "GPU.Engine3D",
- SessionGroup = "UploadTexture"
- };
-
- public static ProfileConfig UploadConstBuffers = new ProfileConfig()
- {
- Category = "GPU.Engine3D",
- SessionGroup = "UploadConstBuffers"
- };
-
- public static ProfileConfig UploadVertexArrays = new ProfileConfig()
- {
- Category = "GPU.Engine3D",
- SessionGroup = "UploadVertexArrays"
- };
-
- public static ProfileConfig ConfigureState = new ProfileConfig()
- {
- Category = "GPU.Engine3D",
- SessionGroup = "ConfigureState"
- };
- }
-
- public static class EngineM2mf
- {
- public static ProfileConfig CallMethod = new ProfileConfig()
- {
- Category = "GPU.EngineM2mf",
- SessionGroup = "CallMethod",
- };
-
- public static ProfileConfig Execute = new ProfileConfig()
- {
- Category = "GPU.EngineM2mf",
- SessionGroup = "Execute",
- };
- }
-
- public static class EngineP2mf
- {
- public static ProfileConfig CallMethod = new ProfileConfig()
- {
- Category = "GPU.EngineP2mf",
- SessionGroup = "CallMethod",
- };
-
- public static ProfileConfig Execute = new ProfileConfig()
- {
- Category = "GPU.EngineP2mf",
- SessionGroup = "Execute",
- };
-
- public static ProfileConfig PushData = new ProfileConfig()
- {
- Category = "GPU.EngineP2mf",
- SessionGroup = "PushData",
- };
- }
-
- public static class Shader
- {
- public static ProfileConfig Decompile = new ProfileConfig()
- {
- Category = "GPU.Shader",
- SessionGroup = "Decompile",
- };
- }
- }
-
- public static ProfileConfig ServiceCall = new ProfileConfig()
- {
- Category = "ServiceCall",
- };
- }
-}
diff --git a/Ryujinx.Debugger/Profiler/ProfileSorters.cs b/Ryujinx.Debugger/Profiler/ProfileSorters.cs
deleted file mode 100644
index 2b730af5..00000000
--- a/Ryujinx.Debugger/Profiler/ProfileSorters.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Ryujinx.Debugger.Profiler
-{
- 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.Debugger/Profiler/ProfilerConfiguration.cs b/Ryujinx.Debugger/Profiler/ProfilerConfiguration.cs
deleted file mode 100644
index 73ef8f55..00000000
--- a/Ryujinx.Debugger/Profiler/ProfilerConfiguration.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using Ryujinx.Common.Utilities;
-using System.IO;
-
-namespace Ryujinx.Debugger.Profiler
-{
- public class ProfilerConfiguration
- {
- public bool Enabled { get; private set; }
- public string DumpPath { get; private set; }
- public float UpdateRate { get; private set; }
- public int MaxLevel { get; private set; }
- public int MaxFlags { get; private set; }
- public float History { get; private set; }
-
- /// <summary>
- /// Loads a configuration file from disk
- /// </summary>
- /// <param name="path">The path to the JSON configuration file</param>
- public static ProfilerConfiguration Load(string path)
- {
- if (!File.Exists(path))
- {
- throw new FileNotFoundException($"Profiler configuration file {path} not found");
- }
-
- return JsonHelper.DeserializeFromFile<ProfilerConfiguration>(path);
- }
- }
-}
diff --git a/Ryujinx.Debugger/Profiler/Settings.cs b/Ryujinx.Debugger/Profiler/Settings.cs
deleted file mode 100644
index 52aa0d84..00000000
--- a/Ryujinx.Debugger/Profiler/Settings.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace Ryujinx.Debugger.Profiler
-{
- public class ProfilerSettings
- {
- // Default settings for profiler
- public bool Enabled { get; set; } = false;
- public bool FileDumpEnabled { get; set; } = false;
- public string DumpLocation { get; set; } = "";
- public float UpdateRate { get; set; } = 0.1f;
- public int MaxLevel { get; set; } = 0;
- public int MaxFlags { get; set; } = 1000;
-
- // 19531225 = 5 seconds in ticks on most pc's.
- // It should get set on boot to the time specified in config
- public long History { get; set; } = 19531225;
- }
-}
diff --git a/Ryujinx.Debugger/Profiler/TimingFlag.cs b/Ryujinx.Debugger/Profiler/TimingFlag.cs
deleted file mode 100644
index 8a34ac99..00000000
--- a/Ryujinx.Debugger/Profiler/TimingFlag.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace Ryujinx.Debugger.Profiler
-{
- public enum TimingFlagType
- {
- FrameSwap = 0,
- SystemFrame = 1,
-
- // Update this for new flags
- Count = 2,
- }
-
- public struct TimingFlag
- {
- public TimingFlagType FlagType;
- public long Timestamp;
- }
-}
diff --git a/Ryujinx.Debugger/Profiler/TimingInfo.cs b/Ryujinx.Debugger/Profiler/TimingInfo.cs
deleted file mode 100644
index 90bd63d2..00000000
--- a/Ryujinx.Debugger/Profiler/TimingInfo.cs
+++ /dev/null
@@ -1,174 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Ryujinx.Debugger.Profiler
-{
- public struct Timestamp
- {
- public long BeginTime;
- public long EndTime;
- }
-
- public class TimingInfo
- {
- // Timestamps
- public long TotalTime { get; set; }
- public long Instant { get; set; }
-
- // Measurement counts
- public int Count { get; set; }
- public int InstantCount { get; set; }
-
- // Work out average
- public long AverageTime => (Count == 0) ? -1 : TotalTime / Count;
-
- // Intentionally not locked as it's only a get count
- public bool IsActive => _timestamps.Count > 0;
-
- public long BeginTime
- {
- get
- {
- lock (_timestampLock)
- {
- if (_depth > 0)
- {
- return _currentTimestamp.BeginTime;
- }
-
- return -1;
- }
- }
- }
-
- // Timestamp collection
- private List<Timestamp> _timestamps;
- private readonly object _timestampLock = new object();
- private readonly object _timestampListLock = new object();
- private Timestamp _currentTimestamp;
-
- // Depth of current timer,
- // each begin call increments and each end call decrements
- private int _depth;
-
- public TimingInfo()
- {
- _timestamps = new List<Timestamp>();
- _depth = 0;
- }
-
- public void Begin(long beginTime)
- {
- lock (_timestampLock)
- {
- // Finish current timestamp if already running
- if (_depth > 0)
- {
- EndUnsafe(beginTime);
- }
-
- BeginUnsafe(beginTime);
- _depth++;
- }
- }
-
- private void BeginUnsafe(long beginTime)
- {
- _currentTimestamp.BeginTime = beginTime;
- _currentTimestamp.EndTime = -1;
- }
-
- public void End(long endTime)
- {
- lock (_timestampLock)
- {
- _depth--;
-
- if (_depth < 0)
- {
- throw new Exception("Timing info end called without corresponding begin");
- }
-
- EndUnsafe(endTime);
-
- // Still have others using this timing info so recreate start for them
- if (_depth > 0)
- {
- BeginUnsafe(endTime);
- }
- }
- }
-
- private void EndUnsafe(long endTime)
- {
- _currentTimestamp.EndTime = endTime;
- lock (_timestampListLock)
- {
- _timestamps.Add(_currentTimestamp);
- }
-
- long delta = _currentTimestamp.EndTime - _currentTimestamp.BeginTime;
- TotalTime += delta;
- Instant += delta;
-
- Count++;
- InstantCount++;
- }
-
- // Remove any timestamps before given timestamp to free memory
- public void Cleanup(long before, long preserveStart, long preserveEnd)
- {
- lock (_timestampListLock)
- {
- int toRemove = 0;
- int toPreserveStart = 0;
- int toPreserveLen = 0;
-
- for (int i = 0; i < _timestamps.Count; i++)
- {
- if (_timestamps[i].EndTime < preserveStart)
- {
- toPreserveStart++;
- InstantCount--;
- Instant -= _timestamps[i].EndTime - _timestamps[i].BeginTime;
- }
- else if (_timestamps[i].EndTime < preserveEnd)
- {
- toPreserveLen++;
- }
- else if (_timestamps[i].EndTime < before)
- {
- toRemove++;
- InstantCount--;
- Instant -= _timestamps[i].EndTime - _timestamps[i].BeginTime;
- }
- else
- {
- // Assume timestamps are in chronological order so no more need to be removed
- break;
- }
- }
-
- if (toPreserveStart > 0)
- {
- _timestamps.RemoveRange(0, toPreserveStart);
- }
-
- if (toRemove > 0)
- {
- _timestamps.RemoveRange(toPreserveLen, toRemove);
- }
- }
- }
-
- public Timestamp[] GetAllTimestamps()
- {
- lock (_timestampListLock)
- {
- Timestamp[] returnTimestamps = new Timestamp[_timestamps.Count];
- _timestamps.CopyTo(returnTimestamps);
- return returnTimestamps;
- }
- }
- }
-}
diff --git a/Ryujinx.Debugger/ProfilerConfig.jsonc b/Ryujinx.Debugger/ProfilerConfig.jsonc
deleted file mode 100644
index e6714386..00000000
--- a/Ryujinx.Debugger/ProfilerConfig.jsonc
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- // Enable profiling (Only available on a profiling enabled builds)
- "enabled": true,
-
- // Set profile file dump location, if blank file dumping disabled. (e.g. `ProfileDump.csv`)
- "dump_path": "",
-
- // Update rate for profiler UI, in hertz. -1 updates every time a frame is issued
- "update_rate": 4.0,
-
- // Set how long to keep profiling data in seconds, reduce if profiling is taking too much RAM
- "history": 5.0,
-
- // Set the maximum profiling level. Higher values may cause a heavy load on your system but will allow you to profile in more detail
- "max_level": 0,
-
- // Sets the maximum number of flags to keep
- "max_flags": 1000,
-
- // Keyboard Controls
- // https://github.com/opentk/opentk/blob/master/src/OpenTK/Input/Key.cs
- "controls": {
- "buttons": {
- // Show/Hide the profiler
- "toggle_profiler": "F2"
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Debugger/Ryujinx.Debugger.csproj b/Ryujinx.Debugger/Ryujinx.Debugger.csproj
deleted file mode 100644
index 4888d756..00000000
--- a/Ryujinx.Debugger/Ryujinx.Debugger.csproj
+++ /dev/null
@@ -1,43 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFramework>netcoreapp3.1</TargetFramework>
- <LangVersion>8.0</LangVersion>
- <Configurations>Debug;Release;Profile Release;Profile Debug</Configurations>
- </PropertyGroup>
-
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile Debug|AnyCPU'">
- <DefineConstants>TRACE;USE_DEBUGGING</DefineConstants>
- </PropertyGroup>
-
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile Release|AnyCPU'">
- <DefineConstants>TRACE;USE_DEBUGGING</DefineConstants>
- </PropertyGroup>
-
- <ItemGroup>
- <None Remove="UI\DebuggerWidget.glade" />
- <None Remove="UI\ProfilerWidget.glade" />
- </ItemGroup>
-
- <ItemGroup>
- <EmbeddedResource Include="UI\DebuggerWidget.glade" />
- <EmbeddedResource Include="UI\ProfilerWidget.glade" />
- </ItemGroup>
-
- <ItemGroup>
- <PackageReference Include="GtkSharp" Version="3.22.25.56" />
- <PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="1.68.1.1" />
- <PackageReference Include="SkiaSharp.Views.Gtk3" Version="1.68.1.1" />
- </ItemGroup>
-
- <ItemGroup>
- <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
- </ItemGroup>
-
- <ItemGroup>
- <None Update="ProfilerConfig.jsonc">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
- </ItemGroup>
-
-</Project>
diff --git a/Ryujinx.Debugger/UI/DebuggerWidget.cs b/Ryujinx.Debugger/UI/DebuggerWidget.cs
deleted file mode 100644
index 1eb45735..00000000
--- a/Ryujinx.Debugger/UI/DebuggerWidget.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using Gtk;
-using System;
-using GUI = Gtk.Builder.ObjectAttribute;
-
-namespace Ryujinx.Debugger.UI
-{
- public class DebuggerWidget : Box
- {
- public event EventHandler DebuggerEnabled;
- public event EventHandler DebuggerDisabled;
-
-#pragma warning disable CS0649
- [GUI] Notebook _widgetNotebook;
-#pragma warning restore CS0649
-
- public DebuggerWidget() : this(new Builder("Ryujinx.Debugger.UI.DebuggerWidget.glade")) { }
-
- public DebuggerWidget(Builder builder) : base(builder.GetObject("_debuggerBox").Handle)
- {
- builder.Autoconnect(this);
-
- LoadProfiler();
- }
-
- public void LoadProfiler()
- {
- ProfilerWidget widget = new ProfilerWidget();
-
- widget.RegisterParentDebugger(this);
-
- _widgetNotebook.AppendPage(widget, new Label("Profiler"));
- }
-
- public void Enable()
- {
- DebuggerEnabled.Invoke(this, null);
- }
-
- public void Disable()
- {
- DebuggerDisabled.Invoke(this, null);
- }
- }
-}
diff --git a/Ryujinx.Debugger/UI/DebuggerWidget.glade b/Ryujinx.Debugger/UI/DebuggerWidget.glade
deleted file mode 100644
index 7e6e691d..00000000
--- a/Ryujinx.Debugger/UI/DebuggerWidget.glade
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.21.0 -->
-<interface>
- <requires lib="gtk+" version="3.20"/>
- <object class="GtkBox" id="_debuggerBox">
- <property name="name">DebuggerBox</property>
- <property name="width_request">1024</property>
- <property name="height_request">720</property>
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkNotebook" id="_widgetNotebook">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <child>
- <placeholder/>
- </child>
- <child type="tab">
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child type="tab">
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child type="tab">
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
-</interface>
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);
- }
- }
- }
- }
-}
diff --git a/Ryujinx.Debugger/UI/ProfilerWidget.glade b/Ryujinx.Debugger/UI/ProfilerWidget.glade
deleted file mode 100644
index 00dd4f70..00000000
--- a/Ryujinx.Debugger/UI/ProfilerWidget.glade
+++ /dev/null
@@ -1,232 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.21.0 -->
-<interface>
- <requires lib="gtk+" version="3.20"/>
- <object class="GtkListStore" id="viewMode">
- <columns>
- <!-- column-name mode -->
- <column type="gint"/>
- <!-- column-name label -->
- <column type="gchararray"/>
- </columns>
- <data>
- <row>
- <col id="0">0</col>
- <col id="1" translatable="yes">Graph</col>
- </row>
- <row>
- <col id="0">1</col>
- <col id="1" translatable="yes">Bars</col>
- </row>
- </data>
- </object>
- <object class="GtkBox" id="_profilerBox">
- <property name="name">ProfilerBox</property>
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">5</property>
- <property name="margin_right">5</property>
- <property name="margin_top">5</property>
- <property name="margin_bottom">5</property>
- <property name="orientation">vertical</property>
- <property name="spacing">10</property>
- <child>
- <object class="GtkCheckButton" id="_enableCheckbutton">
- <property name="label" translatable="yes">Enable Profiler</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkScrolledWindow" id="_scrollview">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="vscrollbar_policy">never</property>
- <property name="shadow_type">in</property>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrollbar" id="_outputScrollbar">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">10</property>
- <child>
- <object class="GtkCheckButton" id="_showInactive">
- <property name="label" translatable="yes">Show Inactive</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="_showFlags">
- <property name="label" translatable="yes">Show Flags</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="_pauseCheckbutton">
- <property name="label" translatable="yes">Paused</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">View Mode: </property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkComboBox" id="_modeBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="model">viewMode</property>
- <property name="active">0</property>
- <child>
- <object class="GtkCellRendererText" id="modeTextRenderer"/>
- <attributes>
- <attribute name="text">1</attribute>
- </attributes>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Filter: </property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="_filterBox">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">4</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="_stepButton">
- <property name="label" translatable="yes">Step</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">5</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
-</interface>
diff --git a/Ryujinx.Debugger/UI/SkRenderer.cs b/Ryujinx.Debugger/UI/SkRenderer.cs
deleted file mode 100644
index a95e4542..00000000
--- a/Ryujinx.Debugger/UI/SkRenderer.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using SkiaSharp;
-using SkiaSharp.Views.Gtk;
-using System;
-
-namespace Ryujinx.Debugger.UI
-{
- public class SkRenderer : SKDrawingArea
- {
- public event EventHandler DrawGraphs;
-
- public SkRenderer()
- {
- this.PaintSurface += SkRenderer_PaintSurface;
- }
-
- private void SkRenderer_PaintSurface(object sender, SkiaSharp.Views.Desktop.SKPaintSurfaceEventArgs e)
- {
- e.Surface.Canvas.Clear(SKColors.Black);
-
- DrawGraphs.Invoke(this, e);
- }
- }
-}