diff options
Diffstat (limited to 'src/citra_qt/debugger')
| -rw-r--r-- | src/citra_qt/debugger/graphics_cmdlists.cpp | 144 | ||||
| -rw-r--r-- | src/citra_qt/debugger/graphics_cmdlists.hxx | 42 |
2 files changed, 62 insertions, 124 deletions
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index e98560a19..71dd166cd 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp | |||
| @@ -2,53 +2,21 @@ | |||
| 2 | // Licensed under GPLv2 | 2 | // Licensed under GPLv2 |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "graphics_cmdlists.hxx" | 5 | #include <QListView> |
| 6 | #include <QPushButton> | ||
| 7 | #include <QVBoxLayout> | ||
| 6 | #include <QTreeView> | 8 | #include <QTreeView> |
| 7 | 9 | ||
| 8 | extern GraphicsDebugger g_debugger; | 10 | #include "graphics_cmdlists.hxx" |
| 9 | |||
| 10 | GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractItemModel(parent) | ||
| 11 | { | ||
| 12 | root_item = new TreeItem(TreeItem::ROOT, 0, NULL, this); | ||
| 13 | |||
| 14 | connect(this, SIGNAL(CommandListCalled()), this, SLOT(OnCommandListCalledInternal()), Qt::UniqueConnection); | ||
| 15 | } | ||
| 16 | |||
| 17 | QModelIndex GPUCommandListModel::index(int row, int column, const QModelIndex& parent) const | ||
| 18 | { | ||
| 19 | TreeItem* item; | ||
| 20 | |||
| 21 | if (!parent.isValid()) { | ||
| 22 | item = root_item; | ||
| 23 | } else { | ||
| 24 | item = (TreeItem*)parent.internalPointer(); | ||
| 25 | } | ||
| 26 | |||
| 27 | return createIndex(row, column, item->children[row]); | ||
| 28 | } | ||
| 29 | 11 | ||
| 30 | QModelIndex GPUCommandListModel::parent(const QModelIndex& child) const | 12 | GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) |
| 31 | { | 13 | { |
| 32 | if (!child.isValid()) | ||
| 33 | return QModelIndex(); | ||
| 34 | |||
| 35 | TreeItem* item = (TreeItem*)child.internalPointer(); | ||
| 36 | |||
| 37 | if (item->parent == NULL) | ||
| 38 | return QModelIndex(); | ||
| 39 | 14 | ||
| 40 | return createIndex(item->parent->index, 0, item->parent); | ||
| 41 | } | 15 | } |
| 42 | 16 | ||
| 43 | int GPUCommandListModel::rowCount(const QModelIndex& parent) const | 17 | int GPUCommandListModel::rowCount(const QModelIndex& parent) const |
| 44 | { | 18 | { |
| 45 | TreeItem* item; | 19 | return pica_trace.writes.size(); |
| 46 | if (!parent.isValid()) { | ||
| 47 | item = root_item; | ||
| 48 | } else { | ||
| 49 | item = (TreeItem*)parent.internalPointer(); | ||
| 50 | } | ||
| 51 | return item->children.size(); | ||
| 52 | } | 20 | } |
| 53 | 21 | ||
| 54 | int GPUCommandListModel::columnCount(const QModelIndex& parent) const | 22 | int GPUCommandListModel::columnCount(const QModelIndex& parent) const |
| @@ -61,79 +29,67 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const | |||
| 61 | if (!index.isValid()) | 29 | if (!index.isValid()) |
| 62 | return QVariant(); | 30 | return QVariant(); |
| 63 | 31 | ||
| 64 | const TreeItem* item = (const TreeItem*)index.internalPointer(); | 32 | const auto& writes = pica_trace.writes; |
| 65 | 33 | const Pica::CommandProcessor::CommandHeader cmd{writes[index.row()].Id()}; | |
| 66 | if (item->type == TreeItem::COMMAND_LIST) | 34 | const u32 val{writes[index.row()].Value()}; |
| 67 | { | 35 | |
| 68 | const GraphicsDebugger::PicaCommandList& cmdlist = command_lists[item->index].second; | 36 | if (role == Qt::DisplayRole) { |
| 69 | u32 address = command_lists[item->index].first; | 37 | QString content; |
| 70 | 38 | if (index.column() == 0) { | |
| 71 | if (role == Qt::DisplayRole && index.column() == 0) | 39 | content = QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str()); |
| 72 | { | 40 | content.append(" "); |
| 73 | return QVariant(QString("0x%1 bytes at 0x%2").arg(cmdlist.size(), 0, 16).arg(address, 8, 16, QLatin1Char('0'))); | 41 | } else if (index.column() == 1) { |
| 74 | } | 42 | content.append(QString("%1 ").arg(cmd.hex, 8, 16, QLatin1Char('0'))); |
| 75 | } | 43 | content.append(QString("%1 ").arg(val, 8, 16, QLatin1Char('0'))); |
| 76 | else | ||
| 77 | { | ||
| 78 | // index refers to a specific command | ||
| 79 | const GraphicsDebugger::PicaCommandList& cmdlist = command_lists[item->parent->index].second; | ||
| 80 | const GraphicsDebugger::PicaCommand& cmd = cmdlist[item->index]; | ||
| 81 | const Pica::CommandProcessor::CommandHeader& header = cmd.GetHeader(); | ||
| 82 | |||
| 83 | if (role == Qt::DisplayRole) { | ||
| 84 | QString content; | ||
| 85 | if (index.column() == 0) { | ||
| 86 | content = QString::fromLatin1(Pica::Regs::GetCommandName(header.cmd_id).c_str()); | ||
| 87 | content.append(" "); | ||
| 88 | } else if (index.column() == 1) { | ||
| 89 | for (int j = 0; j < cmd.size(); ++j) | ||
| 90 | content.append(QString("%1 ").arg(cmd[j], 8, 16, QLatin1Char('0'))); | ||
| 91 | } | ||
| 92 | |||
| 93 | return QVariant(content); | ||
| 94 | } | 44 | } |
| 45 | |||
| 46 | return QVariant(content); | ||
| 95 | } | 47 | } |
| 96 | 48 | ||
| 97 | return QVariant(); | 49 | return QVariant(); |
| 98 | } | 50 | } |
| 99 | 51 | ||
| 100 | void GPUCommandListModel::OnCommandListCalled(const GraphicsDebugger::PicaCommandList& lst, bool is_new) | 52 | void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace) |
| 101 | { | 53 | { |
| 102 | emit CommandListCalled(); | 54 | beginResetModel(); |
| 55 | |||
| 56 | pica_trace = trace; | ||
| 57 | |||
| 58 | endResetModel(); | ||
| 103 | } | 59 | } |
| 104 | 60 | ||
| 105 | 61 | ||
| 106 | void GPUCommandListModel::OnCommandListCalledInternal() | 62 | GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) |
| 107 | { | 63 | { |
| 108 | beginResetModel(); | 64 | GPUCommandListModel* model = new GPUCommandListModel(this); |
| 109 | 65 | ||
| 110 | command_lists = GetDebugger()->GetCommandLists(); | 66 | QWidget* main_widget = new QWidget; |
| 111 | 67 | ||
| 112 | // delete root item and rebuild tree | 68 | QTreeView* list_widget = new QTreeView; |
| 113 | delete root_item; | 69 | list_widget->setModel(model); |
| 114 | root_item = new TreeItem(TreeItem::ROOT, 0, NULL, this); | 70 | list_widget->setFont(QFont("monospace")); |
| 71 | list_widget->setRootIsDecorated(false); | ||
| 115 | 72 | ||
| 116 | for (int command_list_idx = 0; command_list_idx < command_lists.size(); ++command_list_idx) { | 73 | QPushButton* toggle_tracing = new QPushButton(tr("Start Tracing")); |
| 117 | TreeItem* command_list_item = new TreeItem(TreeItem::COMMAND_LIST, command_list_idx, root_item, root_item); | ||
| 118 | root_item->children.push_back(command_list_item); | ||
| 119 | 74 | ||
| 120 | const GraphicsDebugger::PicaCommandList& command_list = command_lists[command_list_idx].second; | 75 | connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); |
| 121 | for (int command_idx = 0; command_idx < command_list.size(); ++command_idx) { | 76 | connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), |
| 122 | TreeItem* command_item = new TreeItem(TreeItem::COMMAND, command_idx, command_list_item, command_list_item); | 77 | model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); |
| 123 | command_list_item->children.push_back(command_item); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | 78 | ||
| 127 | endResetModel(); | 79 | QVBoxLayout* main_layout = new QVBoxLayout; |
| 80 | main_layout->addWidget(list_widget); | ||
| 81 | main_layout->addWidget(toggle_tracing); | ||
| 82 | main_widget->setLayout(main_layout); | ||
| 83 | |||
| 84 | setWidget(main_widget); | ||
| 128 | } | 85 | } |
| 129 | 86 | ||
| 130 | GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) | 87 | void GPUCommandListWidget::OnToggleTracing() |
| 131 | { | 88 | { |
| 132 | GPUCommandListModel* model = new GPUCommandListModel(this); | 89 | if (!Pica::DebugUtils::IsPicaTracing()) { |
| 133 | g_debugger.RegisterObserver(model); | 90 | Pica::DebugUtils::StartPicaTracing(); |
| 134 | 91 | } else { | |
| 135 | QTreeView* tree_widget = new QTreeView; | 92 | pica_trace = Pica::DebugUtils::FinishPicaTracing(); |
| 136 | tree_widget->setModel(model); | 93 | emit TracingFinished(*pica_trace); |
| 137 | tree_widget->setFont(QFont("monospace")); | 94 | } |
| 138 | setWidget(tree_widget); | ||
| 139 | } | 95 | } |
diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx index b4e6e3c8a..479ef0326 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.hxx +++ b/src/citra_qt/debugger/graphics_cmdlists.hxx | |||
| @@ -4,53 +4,28 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <QAbstractItemModel> | 7 | #include <QAbstractListModel> |
| 8 | #include <QDockWidget> | 8 | #include <QDockWidget> |
| 9 | 9 | ||
| 10 | #include "video_core/gpu_debugger.h" | 10 | #include "video_core/gpu_debugger.h" |
| 11 | #include "video_core/debug_utils/debug_utils.h" | ||
| 11 | 12 | ||
| 12 | // TODO: Rename class, since it's not actually a list model anymore... | 13 | class GPUCommandListModel : public QAbstractListModel |
| 13 | class GPUCommandListModel : public QAbstractItemModel, public GraphicsDebugger::DebuggerObserver | ||
| 14 | { | 14 | { |
| 15 | Q_OBJECT | 15 | Q_OBJECT |
| 16 | 16 | ||
| 17 | public: | 17 | public: |
| 18 | GPUCommandListModel(QObject* parent); | 18 | GPUCommandListModel(QObject* parent); |
| 19 | 19 | ||
| 20 | QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; | ||
| 21 | QModelIndex parent(const QModelIndex& child) const; | ||
| 22 | int columnCount(const QModelIndex& parent = QModelIndex()) const; | 20 | int columnCount(const QModelIndex& parent = QModelIndex()) const; |
| 23 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; | 21 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; |
| 24 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; | 22 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; |
| 25 | 23 | ||
| 26 | public: | ||
| 27 | void OnCommandListCalled(const GraphicsDebugger::PicaCommandList& lst, bool is_new) override; | ||
| 28 | |||
| 29 | public slots: | 24 | public slots: |
| 30 | void OnCommandListCalledInternal(); | 25 | void OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace); |
| 31 | |||
| 32 | signals: | ||
| 33 | void CommandListCalled(); | ||
| 34 | 26 | ||
| 35 | private: | 27 | private: |
| 36 | struct TreeItem : public QObject | 28 | Pica::DebugUtils::PicaTrace pica_trace; |
| 37 | { | ||
| 38 | enum Type { | ||
| 39 | ROOT, | ||
| 40 | COMMAND_LIST, | ||
| 41 | COMMAND | ||
| 42 | }; | ||
| 43 | |||
| 44 | TreeItem(Type type, int index, TreeItem* item_parent, QObject* parent) : QObject(parent), type(type), index(index), parent(item_parent) {} | ||
| 45 | |||
| 46 | Type type; | ||
| 47 | int index; | ||
| 48 | std::vector<TreeItem*> children; | ||
| 49 | TreeItem* parent; | ||
| 50 | }; | ||
| 51 | |||
| 52 | std::vector<std::pair<u32,GraphicsDebugger::PicaCommandList>> command_lists; | ||
| 53 | TreeItem* root_item; | ||
| 54 | }; | 29 | }; |
| 55 | 30 | ||
| 56 | class GPUCommandListWidget : public QDockWidget | 31 | class GPUCommandListWidget : public QDockWidget |
| @@ -60,5 +35,12 @@ class GPUCommandListWidget : public QDockWidget | |||
| 60 | public: | 35 | public: |
| 61 | GPUCommandListWidget(QWidget* parent = 0); | 36 | GPUCommandListWidget(QWidget* parent = 0); |
| 62 | 37 | ||
| 38 | public slots: | ||
| 39 | void OnToggleTracing(); | ||
| 40 | |||
| 41 | signals: | ||
| 42 | void TracingFinished(const Pica::DebugUtils::PicaTrace&); | ||
| 43 | |||
| 63 | private: | 44 | private: |
| 45 | std::unique_ptr<Pica::DebugUtils::PicaTrace> pica_trace; | ||
| 64 | }; | 46 | }; |