diff --git a/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.cpp b/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.cpp index 26cf591454..e702ae80c2 100644 --- a/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.cpp +++ b/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.cpp @@ -3,21 +3,48 @@ #include "BreakpointModel.h" +#include "QtHost.h" +#include "QtUtils.h" +#include "Debugger/DebuggerSettingsManager.h" + #include "DebugTools/DebugInterface.h" #include "DebugTools/Breakpoints.h" #include "DebugTools/DisassemblyManager.h" #include "common/Console.h" -#include "QtHost.h" -#include "QtUtils.h" #include #include +std::map BreakpointModel::s_instances; + BreakpointModel::BreakpointModel(DebugInterface& cpu, QObject* parent) : QAbstractTableModel(parent) , m_cpu(cpu) { + if (m_cpu.getCpuType() == BREAKPOINT_EE) + { + connect(g_emu_thread, &EmuThread::onGameChanged, this, [this](const QString& title) { + if (title.isEmpty()) + return; + + if (rowCount() == 0) + DebuggerSettingsManager::loadGameSettings(this); + }); + + DebuggerSettingsManager::loadGameSettings(this); + } + + connect(this, &BreakpointModel::dataChanged, this, &BreakpointModel::refreshData); +} + +BreakpointModel* BreakpointModel::getInstance(DebugInterface& cpu) +{ + auto iterator = s_instances.find(cpu.getCpuType()); + if (iterator == s_instances.end()) + iterator = s_instances.emplace(cpu.getCpuType(), new BreakpointModel(cpu)).first; + + return iterator->second; } int BreakpointModel::rowCount(const QModelIndex&) const @@ -33,10 +60,10 @@ int BreakpointModel::columnCount(const QModelIndex&) const QVariant BreakpointModel::data(const QModelIndex& index, int role) const { size_t row = static_cast(index.row()); - if (row >= m_breakpoints.size()) + if (!index.isValid() || row >= m_breakpoints.size()) return QVariant(); - BreakpointMemcheck bp_mc = m_breakpoints[row]; + const BreakpointMemcheck& bp_mc = m_breakpoints[row]; if (role == Qt::DisplayRole) { @@ -271,12 +298,14 @@ Qt::ItemFlags BreakpointModel::flags(const QModelIndex& index) const bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, int role) { - std::string error; + size_t row = static_cast(index.row()); + if (!index.isValid() || row >= m_breakpoints.size()) + return false; + + const BreakpointMemcheck& bp_mc = m_breakpoints[row]; if (role == Qt::CheckStateRole && index.column() == BreakpointColumns::ENABLED) { - auto bp_mc = m_breakpoints.at(index.row()); - if (const auto* bp = std::get_if(&bp_mc)) { Host::RunOnCPUThread([cpu = this->m_cpu.getCpuType(), bp = *bp, enabled = value.toBool()] { @@ -295,8 +324,6 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i } else if (role == Qt::EditRole && index.column() == BreakpointColumns::CONDITION) { - auto bp_mc = m_breakpoints.at(index.row()); - if (auto* bp = std::get_if(&bp_mc)) { const QString condValue = value.toString(); @@ -314,6 +341,7 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i { PostfixExpression expr; + std::string error; if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr, error)) { QMessageBox::warning(nullptr, "Condition Error", QString::fromStdString(error)); @@ -347,6 +375,7 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i { PostfixExpression expr; + std::string error; if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr, error)) { QMessageBox::warning(nullptr, "Condition Error", QString::fromStdString(error)); diff --git a/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.h b/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.h index 267bfde42d..fd603bb858 100644 --- a/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.h +++ b/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.h @@ -34,8 +34,7 @@ public: ExportRole = Qt::UserRole + 1, }; - static constexpr QHeaderView::ResizeMode HeaderResizeModes[BreakpointColumns::COLUMN_COUNT] = - { + static constexpr QHeaderView::ResizeMode HeaderResizeModes[BreakpointColumns::COLUMN_COUNT] = { QHeaderView::ResizeMode::ResizeToContents, QHeaderView::ResizeMode::ResizeToContents, QHeaderView::ResizeMode::ResizeToContents, @@ -45,7 +44,7 @@ public: QHeaderView::ResizeMode::ResizeToContents, }; - explicit BreakpointModel(DebugInterface& cpu, QObject* parent = nullptr); + static BreakpointModel* getInstance(DebugInterface& cpu); int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; @@ -63,6 +62,10 @@ public: void clear(); private: + BreakpointModel(DebugInterface& cpu, QObject* parent = nullptr); + DebugInterface& m_cpu; std::vector m_breakpoints; + + static std::map s_instances; }; diff --git a/pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.cpp b/pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.cpp index 070614adac..2348db2d9b 100644 --- a/pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.cpp +++ b/pcsx2-qt/Debugger/Breakpoints/BreakpointWidget.cpp @@ -12,23 +12,10 @@ BreakpointWidget::BreakpointWidget(const DebuggerWidgetParameters& parameters) : DebuggerWidget(parameters, DISALLOW_MULTIPLE_INSTANCES) - , m_model(new BreakpointModel(cpu())) + , m_model(BreakpointModel::getInstance(cpu())) { m_ui.setupUi(this); - if (cpu().getCpuType() == BREAKPOINT_EE) - { - connect(g_emu_thread, &EmuThread::onGameChanged, this, [this](const QString& title) { - if (title.isEmpty()) - return; - - if (m_model->rowCount() == 0) - DebuggerSettingsManager::loadGameSettings(m_model); - }); - - DebuggerSettingsManager::loadGameSettings(m_model); - } - m_ui.breakpointList->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_ui.breakpointList, &QTableView::customContextMenuRequested, this, &BreakpointWidget::openContextMenu); connect(m_ui.breakpointList, &QTableView::doubleClicked, this, &BreakpointWidget::onDoubleClicked); @@ -39,13 +26,6 @@ BreakpointWidget::BreakpointWidget(const DebuggerWidgetParameters& parameters) m_ui.breakpointList->horizontalHeader()->setSectionResizeMode(i, mode); i++; } - - connect(m_model, &BreakpointModel::dataChanged, m_model, &BreakpointModel::refreshData); - - receiveEvent([this](const DebuggerEvents::BreakpointsChanged& event) -> bool { - m_model->refreshData(); - return true; - }); } void BreakpointWidget::onDoubleClicked(const QModelIndex& index) diff --git a/pcsx2-qt/Debugger/DebuggerEvents.h b/pcsx2-qt/Debugger/DebuggerEvents.h index 5f42375cc8..c614b52908 100644 --- a/pcsx2-qt/Debugger/DebuggerEvents.h +++ b/pcsx2-qt/Debugger/DebuggerEvents.h @@ -47,10 +47,6 @@ namespace DebuggerEvents { }; - struct BreakpointsChanged : Event - { - }; - // Add the address to the saved addresses list and switch to that tab. struct AddToSavedAddresses : Event { diff --git a/pcsx2-qt/Debugger/DisassemblyWidget.cpp b/pcsx2-qt/Debugger/DisassemblyWidget.cpp index 80a6e66328..8edf1c262e 100644 --- a/pcsx2-qt/Debugger/DisassemblyWidget.cpp +++ b/pcsx2-qt/Debugger/DisassemblyWidget.cpp @@ -3,6 +3,7 @@ #include "DisassemblyWidget.h" +#include "Debugger/Breakpoints/BreakpointModel.h" #include "Debugger/JsonValueWrapper.h" #include "DebugTools/DebugInterface.h" @@ -12,6 +13,7 @@ #include "QtUtils.h" #include "QtHost.h" +#include #include #include #include @@ -185,22 +187,7 @@ void DisassemblyWidget::contextJumpToCursor() void DisassemblyWidget::contextToggleBreakpoint() { - if (!cpu().isAlive()) - return; - - const u32 selectedAddressStart = m_selectedAddressStart; - const BreakPointCpu cpuType = cpu().getCpuType(); - if (CBreakPoints::IsAddressBreakPoint(cpuType, selectedAddressStart)) - { - Host::RunOnCPUThread([cpuType, selectedAddressStart] { CBreakPoints::RemoveBreakPoint(cpuType, selectedAddressStart); }); - } - else - { - Host::RunOnCPUThread([cpuType, selectedAddressStart] { CBreakPoints::AddBreakPoint(cpuType, selectedAddressStart); }); - } - - broadcastEvent(DebuggerEvents::BreakpointsChanged()); - this->repaint(); + toggleBreakpoint(m_selectedAddressStart); } void DisassemblyWidget::contextFollowBranch() @@ -559,21 +546,7 @@ void DisassemblyWidget::mousePressEvent(QMouseEvent* event) void DisassemblyWidget::mouseDoubleClickEvent(QMouseEvent* event) { - if (!cpu().isAlive()) - return; - - const u32 selectedAddress = (static_cast(event->position().y()) / m_rowHeight * 4) + m_visibleStart; - const BreakPointCpu cpuType = cpu().getCpuType(); - if (CBreakPoints::IsAddressBreakPoint(cpuType, selectedAddress)) - { - Host::RunOnCPUThread([cpuType, selectedAddress] { CBreakPoints::RemoveBreakPoint(cpuType, selectedAddress); }); - } - else - { - Host::RunOnCPUThread([cpuType, selectedAddress] { CBreakPoints::AddBreakPoint(cpuType, selectedAddress); }); - } - broadcastEvent(DebuggerEvents::BreakpointsChanged()); - this->repaint(); + toggleBreakpoint((static_cast(event->position().y()) / m_rowHeight * 4) + m_visibleStart); } void DisassemblyWidget::wheelEvent(QWheelEvent* event) @@ -916,6 +889,27 @@ void DisassemblyWidget::gotoAddress(u32 address, bool should_set_focus) this->setFocus(); } +void DisassemblyWidget::toggleBreakpoint(u32 address) +{ + if (!cpu().isAlive()) + return; + + QPointer disassembly_widget(this); + + Host::RunOnCPUThread([cpu = &cpu(), address, disassembly_widget] { + if (!CBreakPoints::IsAddressBreakPoint(cpu->getCpuType(), address)) + CBreakPoints::AddBreakPoint(cpu->getCpuType(), address); + else + CBreakPoints::RemoveBreakPoint(cpu->getCpuType(), address); + + QtHost::RunOnUIThread([cpu, disassembly_widget]() { + BreakpointModel::getInstance(*cpu)->refreshData(); + if (disassembly_widget) + disassembly_widget->repaint(); + }); + }); +} + bool DisassemblyWidget::AddressCanRestore(u32 start, u32 end) { for (u32 i = start; i <= end; i += 4) diff --git a/pcsx2-qt/Debugger/DisassemblyWidget.h b/pcsx2-qt/Debugger/DisassemblyWidget.h index a38c8bb4c9..44729db6e9 100644 --- a/pcsx2-qt/Debugger/DisassemblyWidget.h +++ b/pcsx2-qt/Debugger/DisassemblyWidget.h @@ -62,6 +62,8 @@ public slots: void gotoProgramCounterOnPause(); void gotoAddress(u32 address, bool should_set_focus); + void toggleBreakpoint(u32 address); + private: Ui::DisassemblyWidget m_ui; diff --git a/pcsx2-qt/Debugger/Memory/SavedAddressesModel.cpp b/pcsx2-qt/Debugger/Memory/SavedAddressesModel.cpp index 069873e339..8139500ab1 100644 --- a/pcsx2-qt/Debugger/Memory/SavedAddressesModel.cpp +++ b/pcsx2-qt/Debugger/Memory/SavedAddressesModel.cpp @@ -6,93 +6,112 @@ #include "common/Console.h" +std::map SavedAddressesModel::s_instances; + SavedAddressesModel::SavedAddressesModel(DebugInterface& cpu, QObject* parent) : QAbstractTableModel(parent) , m_cpu(cpu) { } +SavedAddressesModel* SavedAddressesModel::getInstance(DebugInterface& cpu) +{ + auto iterator = s_instances.find(cpu.getCpuType()); + if (iterator == s_instances.end()) + iterator = s_instances.emplace(cpu.getCpuType(), new SavedAddressesModel(cpu)).first; + + return iterator->second; +} + QVariant SavedAddressesModel::data(const QModelIndex& index, int role) const { + size_t row = static_cast(index.row()); + if (!index.isValid() || row >= m_savedAddresses.size()) + return false; + + const SavedAddress& entry = m_savedAddresses[row]; + if (role == Qt::CheckStateRole) - { return QVariant(); - } if (role == Qt::DisplayRole || role == Qt::EditRole) { - SavedAddress savedAddress = m_savedAddresses.at(index.row()); switch (index.column()) { case HeaderColumns::ADDRESS: - return QString::number(savedAddress.address, 16).toUpper(); + return QString::number(entry.address, 16).toUpper(); case HeaderColumns::LABEL: - return savedAddress.label; + return entry.label; case HeaderColumns::DESCRIPTION: - return savedAddress.description; + return entry.description; } } if (role == Qt::UserRole) { - SavedAddress savedAddress = m_savedAddresses.at(index.row()); switch (index.column()) { case HeaderColumns::ADDRESS: - return savedAddress.address; + return entry.address; case HeaderColumns::LABEL: - return savedAddress.label; + return entry.label; case HeaderColumns::DESCRIPTION: - return savedAddress.description; + return entry.description; } } + return QVariant(); } bool SavedAddressesModel::setData(const QModelIndex& index, const QVariant& value, int role) { - if (role == Qt::CheckStateRole) - { + size_t row = static_cast(index.row()); + if (!index.isValid() || row >= m_savedAddresses.size()) + return false; + + SavedAddress& entry = m_savedAddresses[row]; + + if (role == Qt::CheckStateRole) return false; - } if (role == Qt::EditRole) { - SavedAddress addressToEdit = m_savedAddresses.at(index.row()); if (index.column() == HeaderColumns::ADDRESS) { bool ok = false; const u32 address = value.toString().toUInt(&ok, 16); if (ok) - addressToEdit.address = address; + entry.address = address; else return false; } + if (index.column() == HeaderColumns::DESCRIPTION) - addressToEdit.description = value.toString(); + entry.description = value.toString(); + if (index.column() == HeaderColumns::LABEL) - addressToEdit.label = value.toString(); - m_savedAddresses.at(index.row()) = addressToEdit; + entry.label = value.toString(); emit dataChanged(index, index, QList(role)); return true; } else if (role == Qt::UserRole) { - SavedAddress addressToEdit = m_savedAddresses.at(index.row()); if (index.column() == HeaderColumns::ADDRESS) { const u32 address = value.toUInt(); - addressToEdit.address = address; + entry.address = address; } + if (index.column() == HeaderColumns::DESCRIPTION) - addressToEdit.description = value.toString(); + entry.description = value.toString(); + if (index.column() == HeaderColumns::LABEL) - addressToEdit.label = value.toString(); - m_savedAddresses.at(index.row()) = addressToEdit; + entry.label = value.toString(); emit dataChanged(index, index, QList(role)); return true; } + return false; } @@ -155,6 +174,7 @@ bool SavedAddressesModel::removeRows(int row, int count, const QModelIndex& pare { if (row < 0 || count < 1 || static_cast(row + count) > m_savedAddresses.size()) return false; + beginRemoveRows(parent, row, row + count - 1); m_savedAddresses.erase(m_savedAddresses.begin() + row, m_savedAddresses.begin() + row + count); endRemoveRows(); diff --git a/pcsx2-qt/Debugger/Memory/SavedAddressesModel.h b/pcsx2-qt/Debugger/Memory/SavedAddressesModel.h index 2434721f31..da11ed61a2 100644 --- a/pcsx2-qt/Debugger/Memory/SavedAddressesModel.h +++ b/pcsx2-qt/Debugger/Memory/SavedAddressesModel.h @@ -20,7 +20,7 @@ public: QString description; }; - enum HeaderColumns: int + enum HeaderColumns : int { ADDRESS = 0, LABEL, @@ -28,14 +28,14 @@ public: COLUMN_COUNT }; - static constexpr QHeaderView::ResizeMode HeaderResizeModes[HeaderColumns::COLUMN_COUNT] = - { + static constexpr QHeaderView::ResizeMode HeaderResizeModes[HeaderColumns::COLUMN_COUNT] = { QHeaderView::ResizeMode::ResizeToContents, QHeaderView::ResizeMode::ResizeToContents, QHeaderView::ResizeMode::Stretch, }; - explicit SavedAddressesModel(DebugInterface& cpu, QObject* parent = nullptr); + static SavedAddressesModel* getInstance(DebugInterface& cpu); + QVariant data(const QModelIndex& index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; @@ -49,6 +49,10 @@ public: void clear(); private: + SavedAddressesModel(DebugInterface& cpu, QObject* parent = nullptr); + DebugInterface& m_cpu; std::vector m_savedAddresses; + + static std::map s_instances; }; diff --git a/pcsx2-qt/Debugger/Memory/SavedAddressesWidget.cpp b/pcsx2-qt/Debugger/Memory/SavedAddressesWidget.cpp index 264533d29d..6cfe174c85 100644 --- a/pcsx2-qt/Debugger/Memory/SavedAddressesWidget.cpp +++ b/pcsx2-qt/Debugger/Memory/SavedAddressesWidget.cpp @@ -11,7 +11,7 @@ SavedAddressesWidget::SavedAddressesWidget(const DebuggerWidgetParameters& parameters) : DebuggerWidget(parameters, DISALLOW_MULTIPLE_INSTANCES) - , m_model(new SavedAddressesModel(cpu(), this)) + , m_model(SavedAddressesModel::getInstance(cpu())) { m_ui.setupUi(this); @@ -37,7 +37,7 @@ SavedAddressesWidget::SavedAddressesWidget(const DebuggerWidgetParameters& param } QTableView* savedAddressesTableView = m_ui.savedAddressesList; - connect(m_model, &QAbstractItemModel::dataChanged, [savedAddressesTableView](const QModelIndex& topLeft) { + connect(m_model, &QAbstractItemModel::dataChanged, this, [savedAddressesTableView](const QModelIndex& topLeft) { savedAddressesTableView->resizeColumnToContents(topLeft.column()); }); @@ -141,18 +141,23 @@ void SavedAddressesWidget::contextPasteCSV() void SavedAddressesWidget::contextNew() { - qobject_cast(m_ui.savedAddressesList->model())->addRow(); + m_model->addRow(); const u32 row_count = m_model->rowCount(); m_ui.savedAddressesList->edit(m_model->index(row_count - 1, 0)); } void SavedAddressesWidget::addAddress(u32 address) { - qobject_cast(m_ui.savedAddressesList->model())->addRow(); - const u32 row_count = m_model->rowCount(); - const QModelIndex address_index = m_model->index(row_count - 1, 0); + m_model->addRow(); + + u32 row_count = m_model->rowCount(); + + QModelIndex address_index = m_model->index(row_count - 1, SavedAddressesModel::ADDRESS); m_model->setData(address_index, address, Qt::UserRole); - m_ui.savedAddressesList->edit(m_model->index(row_count - 1, 1)); + + QModelIndex label_index = m_model->index(row_count - 1, SavedAddressesModel::LABEL); + if (label_index.isValid()) + m_ui.savedAddressesList->edit(label_index); } void SavedAddressesWidget::saveToDebuggerSettings()