From 4a258e6788b1d179c95c811bcf8dc9a5c2220757 Mon Sep 17 00:00:00 2001 From: Sour Date: Wed, 20 Nov 2019 19:12:08 -0500 Subject: [PATCH] Debugger: Event Viewer - Added refresh speed options --- GUI.NET/Config/DebugInfo.cs | 2 + .../Controls/ctrlScanlineCycleSelect.cs | 1 + GUI.NET/Debugger/WindowRefreshManager.cs | 92 +++++++++++++++++++ GUI.NET/Debugger/frmEventViewer.Designer.cs | 73 ++++++++++++++- GUI.NET/Debugger/frmEventViewer.cs | 77 ++++++++++------ GUI.NET/GUI.NET.csproj | 1 + 6 files changed, 216 insertions(+), 30 deletions(-) create mode 100644 GUI.NET/Debugger/WindowRefreshManager.cs diff --git a/GUI.NET/Config/DebugInfo.cs b/GUI.NET/Config/DebugInfo.cs index e9f8c95e..7acad032 100644 --- a/GUI.NET/Config/DebugInfo.cs +++ b/GUI.NET/Config/DebugInfo.cs @@ -154,6 +154,8 @@ namespace Mesen.GUI.Config public Point EventViewerLocation; public Size EventViewerSize; + public bool EventViewerAutoRefresh = true; + public RefreshSpeed EventViewerAutoRefreshSpeed = RefreshSpeed.Normal; public bool EventViewerRefreshOnBreak = true; public bool EventViewerShowPpuWrite2000 = true; public bool EventViewerShowPpuWrite2001 = true; diff --git a/GUI.NET/Debugger/Controls/ctrlScanlineCycleSelect.cs b/GUI.NET/Debugger/Controls/ctrlScanlineCycleSelect.cs index 3c4b0498..c2062369 100644 --- a/GUI.NET/Debugger/Controls/ctrlScanlineCycleSelect.cs +++ b/GUI.NET/Debugger/Controls/ctrlScanlineCycleSelect.cs @@ -19,6 +19,7 @@ namespace Mesen.GUI.Debugger.Controls public int Scanline { get { return _scanline; } } public int Cycle { get { return _cycle; } } + public int ViewerId { get { return _ppuViewerId; } } public ctrlScanlineCycleSelect() { diff --git a/GUI.NET/Debugger/WindowRefreshManager.cs b/GUI.NET/Debugger/WindowRefreshManager.cs new file mode 100644 index 00000000..a410dc95 --- /dev/null +++ b/GUI.NET/Debugger/WindowRefreshManager.cs @@ -0,0 +1,92 @@ +using Mesen.GUI.Config; +using Mesen.GUI.Debugger.Controls; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using static Mesen.GUI.InteropEmu; + +namespace Mesen.GUI.Debugger +{ + public class WindowRefreshManager : IDisposable + { + private IRefresh _window; + private NotificationListener _notifListener; + private Stopwatch _timer; + private long _lastUpdate = 0; + private long _minDelay = 0; + + public bool AutoRefresh { get; set; } + public RefreshSpeed AutoRefreshSpeed { get; set; } + + public WindowRefreshManager(IRefresh window) + { + _window = window; + _notifListener = new NotificationListener(ConfigManager.Config.DebugInfo.DebugConsoleId); + _notifListener.OnNotification += OnNotificationReceived; + _timer = Stopwatch.StartNew(); + } + + public void Dispose() + { + _notifListener.Dispose(); + } + + private void RefreshContent() + { + _lastUpdate = _timer.ElapsedTicks; + _window.RefreshData(); + ((Form)_window).BeginInvoke((Action)(() => { + _window.RefreshViewer(); + + //Limit FPS to 3x time it takes for a single update (rough estimate), and cap based on requested fps. + int divider; + switch(this.AutoRefreshSpeed) { + default: + case RefreshSpeed.Low: divider = 20; break; + case RefreshSpeed.Normal: divider = 40; break; + case RefreshSpeed.High: divider = 80; break; + } + + _minDelay = Math.Max(Stopwatch.Frequency / divider, (long)((_timer.ElapsedTicks - _lastUpdate) * 2)); + })); + } + + private void OnNotificationReceived(NotificationEventArgs e) + { + switch(e.NotificationType) { + case ConsoleNotificationType.CodeBreak: + RefreshContent(); + break; + + case ConsoleNotificationType.EventViewerDisplayFrame: + if(_window.ScanlineCycleSelect == null && this.AutoRefresh && (_timer.ElapsedTicks - _lastUpdate) > _minDelay) { + RefreshContent(); + } + break; + + case ConsoleNotificationType.PpuViewerDisplayFrame: + if(_window.ScanlineCycleSelect != null && this.AutoRefresh && e.Parameter.ToInt32() == _window.ScanlineCycleSelect.ViewerId && (_timer.ElapsedTicks - _lastUpdate) > _minDelay) { + RefreshContent(); + } + break; + + case ConsoleNotificationType.GameLoaded: + //Configuration is lost when debugger is restarted (when switching game or power cycling) + _window.ScanlineCycleSelect?.RefreshSettings(); + break; + } + } + } + + public interface IRefresh + { + void RefreshData(); + void RefreshViewer(); + + ctrlScanlineCycleSelect ScanlineCycleSelect { get; } + } +} diff --git a/GUI.NET/Debugger/frmEventViewer.Designer.cs b/GUI.NET/Debugger/frmEventViewer.Designer.cs index a76e4625..548f2c2c 100644 --- a/GUI.NET/Debugger/frmEventViewer.Designer.cs +++ b/GUI.NET/Debugger/frmEventViewer.Designer.cs @@ -16,9 +16,6 @@ if(disposing && (components != null)) { components.Dispose(); } - if(this._notifListener != null) { - this._notifListener.Dispose(); - } base.Dispose(disposing); } @@ -81,6 +78,13 @@ this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.mnuClose = new System.Windows.Forms.ToolStripMenuItem(); this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuRefresh = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuAutoRefreshSpeed = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuAutoRefreshLow = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuAutoRefreshNormal = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuAutoRefreshHigh = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuAutoRefresh = new System.Windows.Forms.ToolStripMenuItem(); this.mnuRefreshOnBreak = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); this.mnuResetColors = new System.Windows.Forms.ToolStripMenuItem(); @@ -730,6 +734,10 @@ // viewToolStripMenuItem // this.viewToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuRefresh, + this.mnuAutoRefreshSpeed, + this.toolStripSeparator1, + this.mnuAutoRefresh, this.mnuRefreshOnBreak, this.toolStripMenuItem1, this.mnuResetColors, @@ -740,6 +748,58 @@ this.viewToolStripMenuItem.Size = new System.Drawing.Size(44, 20); this.viewToolStripMenuItem.Text = "View"; // + // mnuRefresh + // + this.mnuRefresh.Image = global::Mesen.GUI.Properties.Resources.Reset; + this.mnuRefresh.Name = "mnuRefresh"; + this.mnuRefresh.Size = new System.Drawing.Size(198, 22); + this.mnuRefresh.Text = "Refresh"; + this.mnuRefresh.Click += new System.EventHandler(this.mnuRefresh_Click); + // + // mnuAutoRefreshSpeed + // + this.mnuAutoRefreshSpeed.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuAutoRefreshLow, + this.mnuAutoRefreshNormal, + this.mnuAutoRefreshHigh}); + this.mnuAutoRefreshSpeed.Image = global::Mesen.GUI.Properties.Resources.Speed; + this.mnuAutoRefreshSpeed.Name = "mnuAutoRefreshSpeed"; + this.mnuAutoRefreshSpeed.Size = new System.Drawing.Size(198, 22); + this.mnuAutoRefreshSpeed.Text = "Auto-refresh Speed"; + // + // mnuAutoRefreshLow + // + this.mnuAutoRefreshLow.Name = "mnuAutoRefreshLow"; + this.mnuAutoRefreshLow.Size = new System.Drawing.Size(159, 22); + this.mnuAutoRefreshLow.Text = "Low (15 FPS)"; + // + // mnuAutoRefreshNormal + // + this.mnuAutoRefreshNormal.Name = "mnuAutoRefreshNormal"; + this.mnuAutoRefreshNormal.Size = new System.Drawing.Size(159, 22); + this.mnuAutoRefreshNormal.Text = "Normal (30 FPS)"; + // + // mnuAutoRefreshHigh + // + this.mnuAutoRefreshHigh.Name = "mnuAutoRefreshHigh"; + this.mnuAutoRefreshHigh.Size = new System.Drawing.Size(159, 22); + this.mnuAutoRefreshHigh.Text = "High (60 FPS)"; + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(195, 6); + // + // mnuAutoRefresh + // + this.mnuAutoRefresh.Checked = true; + this.mnuAutoRefresh.CheckOnClick = true; + this.mnuAutoRefresh.CheckState = System.Windows.Forms.CheckState.Checked; + this.mnuAutoRefresh.Name = "mnuAutoRefresh"; + this.mnuAutoRefresh.Size = new System.Drawing.Size(198, 22); + this.mnuAutoRefresh.Text = "Auto-refresh"; + this.mnuAutoRefresh.CheckedChanged += new System.EventHandler(this.mnuAutoRefresh_CheckedChanged); + // // mnuRefreshOnBreak // this.mnuRefreshOnBreak.CheckOnClick = true; @@ -874,5 +934,12 @@ private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2; private System.Windows.Forms.ToolStripMenuItem mnuZoomIn; private System.Windows.Forms.ToolStripMenuItem mnuZoomOut; + private System.Windows.Forms.ToolStripMenuItem mnuRefresh; + private System.Windows.Forms.ToolStripMenuItem mnuAutoRefreshSpeed; + private System.Windows.Forms.ToolStripMenuItem mnuAutoRefreshLow; + private System.Windows.Forms.ToolStripMenuItem mnuAutoRefreshNormal; + private System.Windows.Forms.ToolStripMenuItem mnuAutoRefreshHigh; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.ToolStripMenuItem mnuAutoRefresh; } } \ No newline at end of file diff --git a/GUI.NET/Debugger/frmEventViewer.cs b/GUI.NET/Debugger/frmEventViewer.cs index 73cd2f37..ff5a0523 100644 --- a/GUI.NET/Debugger/frmEventViewer.cs +++ b/GUI.NET/Debugger/frmEventViewer.cs @@ -1,4 +1,5 @@ using Mesen.GUI.Config; +using Mesen.GUI.Debugger.Controls; using Mesen.GUI.Forms; using System; using System.Collections.Generic; @@ -12,13 +13,14 @@ using System.Windows.Forms; namespace Mesen.GUI.Debugger { - public partial class frmEventViewer : BaseForm + public partial class frmEventViewer : BaseForm, IRefresh { - private DateTime _lastUpdate = DateTime.MinValue; + private WindowRefreshManager _refreshManager; private InteropEmu.NotificationListener _notifListener; private EntityBinder _binder = new EntityBinder(); private bool _inListViewTab = false; - private bool _refreshing = false; + + public ctrlScanlineCycleSelect ScanlineCycleSelect => null; public frmEventViewer() { @@ -77,12 +79,6 @@ namespace Mesen.GUI.Debugger _binder.AddBinding(nameof(DebugInfo.EventViewerShowPreviousFrameEvents), chkShowPreviousFrameEvents); _binder.AddBinding(nameof(DebugInfo.EventViewerShowNtscBorders), chkShowNtscBorders); - this.GetData(); - - _binder.UpdateUI(); - - this.RefreshViewer(); - DebugWorkspaceManager.GetWorkspace(); RestoreLocation(ConfigManager.Config.DebugInfo.EventViewerLocation, ConfigManager.Config.DebugInfo.EventViewerSize); @@ -90,12 +86,27 @@ namespace Mesen.GUI.Debugger this._notifListener = new InteropEmu.NotificationListener(ConfigManager.Config.DebugInfo.DebugConsoleId); this._notifListener.OnNotification += this._notifListener_OnNotification; + DebugInfo cfg = ConfigManager.Config.DebugInfo; + _refreshManager = new WindowRefreshManager(this); + _refreshManager.AutoRefresh = cfg.EventViewerAutoRefresh; + _refreshManager.AutoRefreshSpeed = cfg.EventViewerAutoRefreshSpeed; + mnuAutoRefresh.Checked = cfg.EventViewerAutoRefresh; + mnuAutoRefreshLow.Click += (s, evt) => _refreshManager.AutoRefreshSpeed = RefreshSpeed.Low; + mnuAutoRefreshNormal.Click += (s, evt) => _refreshManager.AutoRefreshSpeed = RefreshSpeed.Normal; + mnuAutoRefreshHigh.Click += (s, evt) => _refreshManager.AutoRefreshSpeed = RefreshSpeed.High; + mnuAutoRefreshSpeed.DropDownOpening += (s, evt) => UpdateRefreshSpeedMenu(); + + this.RefreshData(); + _binder.UpdateUI(); + this.RefreshViewer(); + InitShortcuts(); } } private void InitShortcuts() { + mnuRefresh.InitShortcut(this, nameof(DebuggerShortcutsConfig.Refresh)); mnuZoomIn.InitShortcut(this, nameof(DebuggerShortcutsConfig.ZoomIn)); mnuZoomOut.InitShortcut(this, nameof(DebuggerShortcutsConfig.ZoomOut)); @@ -108,10 +119,15 @@ namespace Mesen.GUI.Debugger base.OnFormClosing(e); this._notifListener.OnNotification -= this._notifListener_OnNotification; + _notifListener?.Dispose(); + _refreshManager?.Dispose(); _binder.UpdateObject(); - ConfigManager.Config.DebugInfo.EventViewerLocation = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Location : this.Location; - ConfigManager.Config.DebugInfo.EventViewerSize = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Size : this.Size; + DebugInfo cfg = ConfigManager.Config.DebugInfo; + cfg.EventViewerAutoRefresh = _refreshManager.AutoRefresh; + cfg.EventViewerAutoRefreshSpeed = _refreshManager.AutoRefreshSpeed; + cfg.EventViewerLocation = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Location : this.Location; + cfg.EventViewerSize = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Size : this.Size; ConfigManager.ApplyChanges(); } @@ -121,23 +137,14 @@ namespace Mesen.GUI.Debugger case InteropEmu.ConsoleNotificationType.CodeBreak: case InteropEmu.ConsoleNotificationType.GamePaused: if(ConfigManager.Config.DebugInfo.EventViewerRefreshOnBreak) { - this.GetData(); + this.RefreshData(); this.BeginInvoke((MethodInvoker)(() => this.RefreshViewer())); } break; - - case InteropEmu.ConsoleNotificationType.EventViewerDisplayFrame: - if(!_refreshing && (DateTime.Now - _lastUpdate).Milliseconds >= 32) { - //Update at ~30 fps at most - this.GetData(); - this.BeginInvoke((MethodInvoker)(() => this.RefreshViewer())); - _lastUpdate = DateTime.Now; - } - break; } } - private void GetData() + public void RefreshData() { if(_inListViewTab) { ctrlEventViewerListView.GetData(); @@ -146,16 +153,14 @@ namespace Mesen.GUI.Debugger } } - private void RefreshViewer() + public void RefreshViewer() { if(_binder.Updating) { return; } - _refreshing = true; _binder.UpdateObject(); ctrlEventViewerPpuView.RefreshViewer(); - _refreshing = false; } private void mnuClose_Click(object sender, EventArgs e) @@ -166,7 +171,7 @@ namespace Mesen.GUI.Debugger private void tabMain_SelectedIndexChanged(object sender, EventArgs e) { _inListViewTab = tabMain.SelectedTab == tpgListView; - GetData(); + RefreshData(); } private void mnuRefreshOnBreak_Click(object sender, EventArgs e) @@ -180,7 +185,7 @@ namespace Mesen.GUI.Debugger ConfigManager.Config.DebugInfo.EventViewerShowPreviousFrameEvents = chkShowPreviousFrameEvents.Checked; ConfigManager.ApplyChanges(); if(InteropEmu.DebugIsExecutionStopped()) { - this.GetData(); + this.RefreshData(); this.RefreshViewer(); } } @@ -218,5 +223,23 @@ namespace Mesen.GUI.Debugger picBreakpoint.BackColor = ColorTranslator.FromHtml("#1898E4"); picDmcDmaRead.BackColor = ColorTranslator.FromHtml("#A9FEFC"); } + + private void mnuRefresh_Click(object sender, EventArgs e) + { + RefreshData(); + RefreshViewer(); + } + + private void mnuAutoRefresh_CheckedChanged(object sender, EventArgs e) + { + _refreshManager.AutoRefresh = mnuAutoRefresh.Checked; + } + + private void UpdateRefreshSpeedMenu() + { + mnuAutoRefreshLow.Checked = _refreshManager.AutoRefreshSpeed == RefreshSpeed.Low; + mnuAutoRefreshNormal.Checked = _refreshManager.AutoRefreshSpeed == RefreshSpeed.Normal; + mnuAutoRefreshHigh.Checked = _refreshManager.AutoRefreshSpeed == RefreshSpeed.High; + } } } diff --git a/GUI.NET/GUI.NET.csproj b/GUI.NET/GUI.NET.csproj index 9a676dec..16c8c1b4 100644 --- a/GUI.NET/GUI.NET.csproj +++ b/GUI.NET/GUI.NET.csproj @@ -893,6 +893,7 @@ Form + BaseConfigForm.cs