From 9fc417b1d06b6f7414a21040e2fe4eea2a874a58 Mon Sep 17 00:00:00 2001 From: TryTwo Date: Mon, 24 Jun 2024 14:18:41 -0700 Subject: [PATCH] MemoryViewWidget: Add OnFrameEnd callback to auto-update memory while a game is running. --- .../DolphinQt/Debugger/MemoryViewWidget.cpp | 26 ++++++++++++++++++- .../DolphinQt/Debugger/MemoryViewWidget.h | 3 +++ .../Core/DolphinQt/Debugger/MemoryWidget.cpp | 25 ++++++++++++++++++ Source/Core/DolphinQt/Debugger/MemoryWidget.h | 6 +++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp index b3593f426b..683dfc9144 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp @@ -225,6 +225,9 @@ MemoryViewWidget::MemoryViewWidget(Core::System& system, QWidget* parent) UpdateDisbatcher(UpdateType::Values); }); + // CPU Thread to Main Thread. + connect(this, &MemoryViewWidget::AutoUpdate, this, + [this] { UpdateDisbatcher(UpdateType::Auto); }); connect(&Settings::Instance(), &Settings::ThemeChanged, this, [this] { UpdateDisbatcher(UpdateType::Full); }); @@ -306,7 +309,12 @@ constexpr int GetCharacterCount(MemoryViewWidget::Type type) void MemoryViewWidget::UpdateDisbatcher(UpdateType type) { - if (!isVisible()) + std::unique_lock lock(m_updating, std::defer_lock); + + // A full update may change parameters like row count, so make sure it goes through. + if (type == UpdateType::Full) + lock.lock(); + else if (!isVisible() || !lock.try_lock()) return; // Check if table needs to be created. @@ -326,6 +334,10 @@ void MemoryViewWidget::UpdateDisbatcher(UpdateType type) GetValues(); UpdateColumns(); break; + case UpdateType::Auto: + // Values were captured on CPU thread while doing a callback. + if (m_values.size() != 0) + UpdateColumns(); default: break; } @@ -517,6 +529,18 @@ void MemoryViewWidget::UpdateColumns() } } +// Always runs on CPU thread from a callback. +void MemoryViewWidget::UpdateOnFrameEnd() +{ + std::unique_lock lock(m_updating, std::try_to_lock); + if (lock) + { + GetValues(); + // Should not directly trigger widget updates on a cpu thread. Signal main thread to do it. + emit AutoUpdate(); + } +} + void MemoryViewWidget::GetValues() { m_values.clear(); diff --git a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h index 1ca7d2c781..3dac963cfa 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h +++ b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h @@ -83,6 +83,7 @@ public: void CreateTable(); void UpdateDisbatcher(UpdateType type = UpdateType::Addresses); void Update(); + void UpdateOnFrameEnd(); void GetValues(); void UpdateFont(const QFont& font); void ToggleBreakpoint(u32 addr, bool row); @@ -98,6 +99,7 @@ public: void SetBPLoggingEnabled(bool enabled); signals: + void AutoUpdate(); void ShowCode(u32 address); void RequestWatch(QString name, u32 address); @@ -130,6 +132,7 @@ private: int m_alignment = 16; int m_data_columns; bool m_dual_view = false; + std::mutex m_updating; QColor m_highlight_color = QColor(120, 255, 255, 100); friend class MemoryViewTable; diff --git a/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp b/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp index 65e8804674..d4d1c830bc 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp @@ -340,13 +340,38 @@ void MemoryWidget::ConnectWidgets() void MemoryWidget::closeEvent(QCloseEvent*) { Settings::Instance().SetMemoryVisible(false); + RemoveAfterFrameEventCallback(); } void MemoryWidget::showEvent(QShowEvent* event) { + RegisterAfterFrameEventCallback(); Update(); } +void MemoryWidget::hideEvent(QHideEvent* event) +{ + RemoveAfterFrameEventCallback(); +} + +void MemoryWidget::RegisterAfterFrameEventCallback() +{ + m_VI_end_field_event = VIEndFieldEvent::Register([this] { AutoUpdateTable(); }, "MemoryWidget"); +} + +void MemoryWidget::RemoveAfterFrameEventCallback() +{ + m_VI_end_field_event.reset(); +} + +void MemoryWidget::AutoUpdateTable() +{ + if (!isVisible()) + return; + + m_memory_view->UpdateOnFrameEnd(); +} + void MemoryWidget::Update() { if (!isVisible()) diff --git a/Source/Core/DolphinQt/Debugger/MemoryWidget.h b/Source/Core/DolphinQt/Debugger/MemoryWidget.h index 75fe40d5f8..0f42800e18 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryWidget.h +++ b/Source/Core/DolphinQt/Debugger/MemoryWidget.h @@ -9,6 +9,7 @@ #include #include "Common/CommonTypes.h" +#include "VideoCommon/VideoEvents.h" class MemoryViewWidget; class QCheckBox; @@ -76,7 +77,11 @@ private: void FindValue(bool next); void closeEvent(QCloseEvent*) override; + void hideEvent(QHideEvent* event) override; void showEvent(QShowEvent* event) override; + void RegisterAfterFrameEventCallback(); + void RemoveAfterFrameEventCallback(); + void AutoUpdateTable(); Core::System& m_system; @@ -109,4 +114,5 @@ private: QRadioButton* m_bp_read_only; QRadioButton* m_bp_write_only; QCheckBox* m_bp_log_check; + Common::EventHook m_VI_end_field_event; };