diff options
| author | 2014-08-14 19:21:55 +0200 | |
|---|---|---|
| committer | 2014-08-25 22:03:18 +0200 | |
| commit | 26ade98411c1d76540695f15378ff7f6b5388b1a (patch) | |
| tree | db1b6eba40bacdc049d4c3c668ee875b209c73ac | |
| parent | Pica/CommandProcessor: Implement parameter masking. (diff) | |
| download | yuzu-26ade98411c1d76540695f15378ff7f6b5388b1a.tar.gz yuzu-26ade98411c1d76540695f15378ff7f6b5388b1a.tar.xz yuzu-26ade98411c1d76540695f15378ff7f6b5388b1a.zip | |
Pica/citra-qt: Replace command list view and command list debugging code with something more sophisticated.
| -rw-r--r-- | src/citra_qt/debugger/graphics_cmdlists.cpp | 144 | ||||
| -rw-r--r-- | src/citra_qt/debugger/graphics_cmdlists.hxx | 42 | ||||
| -rw-r--r-- | src/citra_qt/main.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/gsp.cpp | 5 | ||||
| -rw-r--r-- | src/video_core/command_processor.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/debug_utils/debug_utils.cpp | 55 | ||||
| -rw-r--r-- | src/video_core/debug_utils/debug_utils.h | 21 | ||||
| -rw-r--r-- | src/video_core/gpu_debugger.h | 63 |
8 files changed, 142 insertions, 194 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 | }; |
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 9a16cf92d..a6b87f781 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp | |||
| @@ -52,11 +52,11 @@ GMainWindow::GMainWindow() | |||
| 52 | 52 | ||
| 53 | graphicsWidget = new GPUCommandStreamWidget(this); | 53 | graphicsWidget = new GPUCommandStreamWidget(this); |
| 54 | addDockWidget(Qt::RightDockWidgetArea, graphicsWidget); | 54 | addDockWidget(Qt::RightDockWidgetArea, graphicsWidget); |
| 55 | callstackWidget->hide(); | 55 | graphicsWidget ->hide(); |
| 56 | 56 | ||
| 57 | graphicsCommandsWidget = new GPUCommandListWidget(this); | 57 | graphicsCommandsWidget = new GPUCommandListWidget(this); |
| 58 | addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget); | 58 | addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget); |
| 59 | callstackWidget->hide(); | 59 | graphicsCommandsWidget->hide(); |
| 60 | 60 | ||
| 61 | QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); | 61 | QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); |
| 62 | debug_menu->addAction(disasmWidget->toggleViewAction()); | 62 | debug_menu->addAction(disasmWidget->toggleViewAction()); |
diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index 027ba5a37..46c5a8ddd 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp | |||
| @@ -230,11 +230,6 @@ void ExecuteCommand(const Command& command, u32 thread_id) { | |||
| 230 | // TODO: Not sure if we are supposed to always write this .. seems to trigger processing though | 230 | // TODO: Not sure if we are supposed to always write this .. seems to trigger processing though |
| 231 | WriteGPURegister(GPU_REG_INDEX(command_processor_config.trigger), 1); | 231 | WriteGPURegister(GPU_REG_INDEX(command_processor_config.trigger), 1); |
| 232 | 232 | ||
| 233 | // TODO: Move this to GPU | ||
| 234 | // TODO: Not sure what units the size is measured in | ||
| 235 | g_debugger.CommandListCalled(params.address, | ||
| 236 | (u32*)Memory::GetPointer(params.address), | ||
| 237 | params.size); | ||
| 238 | SignalInterrupt(InterruptId::P3D); | 233 | SignalInterrupt(InterruptId::P3D); |
| 239 | break; | 234 | break; |
| 240 | } | 235 | } |
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index f7a412bc1..76fdb4e4a 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp | |||
| @@ -33,6 +33,8 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 33 | u32 old_value = registers[id]; | 33 | u32 old_value = registers[id]; |
| 34 | registers[id] = (old_value & ~mask) | (value & mask); | 34 | registers[id] = (old_value & ~mask) | (value & mask); |
| 35 | 35 | ||
| 36 | DebugUtils::OnPicaRegWrite(id, registers[id]); | ||
| 37 | |||
| 36 | switch(id) { | 38 | switch(id) { |
| 37 | // It seems like these trigger vertex rendering | 39 | // It seems like these trigger vertex rendering |
| 38 | case PICA_REG_INDEX(trigger_draw): | 40 | case PICA_REG_INDEX(trigger_draw): |
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index f41249eac..1bbc0330c 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <fstream> | 6 | #include <fstream> |
| 7 | #include <mutex> | ||
| 7 | #include <string> | 8 | #include <string> |
| 8 | 9 | ||
| 9 | #include "video_core/pica.h" | 10 | #include "video_core/pica.h" |
| @@ -260,6 +261,60 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data | |||
| 260 | } | 261 | } |
| 261 | } | 262 | } |
| 262 | 263 | ||
| 264 | static std::unique_ptr<PicaTrace> pica_trace; | ||
| 265 | static std::mutex pica_trace_mutex; | ||
| 266 | static int is_pica_tracing = false; | ||
| 267 | |||
| 268 | void StartPicaTracing() | ||
| 269 | { | ||
| 270 | if (is_pica_tracing) { | ||
| 271 | ERROR_LOG(GPU, "StartPicaTracing called even though tracing already running!"); | ||
| 272 | return; | ||
| 273 | } | ||
| 274 | |||
| 275 | pica_trace_mutex.lock(); | ||
| 276 | pica_trace = std::unique_ptr<PicaTrace>(new PicaTrace); | ||
| 277 | |||
| 278 | is_pica_tracing = true; | ||
| 279 | pica_trace_mutex.unlock(); | ||
| 280 | } | ||
| 281 | |||
| 282 | bool IsPicaTracing() | ||
| 283 | { | ||
| 284 | return is_pica_tracing; | ||
| 285 | } | ||
| 286 | |||
| 287 | void OnPicaRegWrite(u32 id, u32 value) | ||
| 288 | { | ||
| 289 | // Double check for is_pica_tracing to avoid pointless locking overhead | ||
| 290 | if (!is_pica_tracing) | ||
| 291 | return; | ||
| 292 | |||
| 293 | std::unique_lock<std::mutex> lock(pica_trace_mutex); | ||
| 294 | |||
| 295 | if (!is_pica_tracing) | ||
| 296 | return; | ||
| 297 | |||
| 298 | pica_trace->writes.push_back({id, value}); | ||
| 299 | } | ||
| 300 | |||
| 301 | std::unique_ptr<PicaTrace> FinishPicaTracing() | ||
| 302 | { | ||
| 303 | if (!is_pica_tracing) { | ||
| 304 | ERROR_LOG(GPU, "FinishPicaTracing called even though tracing already running!"); | ||
| 305 | return {}; | ||
| 306 | } | ||
| 307 | |||
| 308 | // signalize that no further tracing should be performed | ||
| 309 | is_pica_tracing = false; | ||
| 310 | |||
| 311 | // Wait until running tracing is finished | ||
| 312 | pica_trace_mutex.lock(); | ||
| 313 | std::unique_ptr<PicaTrace> ret(std::move(pica_trace)); | ||
| 314 | pica_trace_mutex.unlock(); | ||
| 315 | return std::move(ret); | ||
| 316 | } | ||
| 317 | |||
| 263 | } // namespace | 318 | } // namespace |
| 264 | 319 | ||
| 265 | } // namespace | 320 | } // namespace |
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h index bd7a0a89b..023500066 100644 --- a/src/video_core/debug_utils/debug_utils.h +++ b/src/video_core/debug_utils/debug_utils.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <memory> | ||
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | 10 | ||
| 10 | #include "video_core/pica.h" | 11 | #include "video_core/pica.h" |
| @@ -38,6 +39,26 @@ private: | |||
| 38 | void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size, | 39 | void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size, |
| 39 | u32 main_offset, const Regs::VSOutputAttributes* output_attributes); | 40 | u32 main_offset, const Regs::VSOutputAttributes* output_attributes); |
| 40 | 41 | ||
| 42 | |||
| 43 | // Utility class to log Pica commands. | ||
| 44 | struct PicaTrace { | ||
| 45 | struct Write : public std::pair<u32,u32> { | ||
| 46 | Write(u32 id, u32 value) : std::pair<u32,u32>(id, value) {} | ||
| 47 | |||
| 48 | u32& Id() { return first; } | ||
| 49 | const u32& Id() const { return first; } | ||
| 50 | |||
| 51 | u32& Value() { return second; } | ||
| 52 | const u32& Value() const { return second; } | ||
| 53 | }; | ||
| 54 | std::vector<Write> writes; | ||
| 55 | }; | ||
| 56 | |||
| 57 | void StartPicaTracing(); | ||
| 58 | bool IsPicaTracing(); | ||
| 59 | void OnPicaRegWrite(u32 id, u32 value); | ||
| 60 | std::unique_ptr<PicaTrace> FinishPicaTracing(); | ||
| 61 | |||
| 41 | } // namespace | 62 | } // namespace |
| 42 | 63 | ||
| 43 | } // namespace | 64 | } // namespace |
diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h index 2ba873457..5a81fcfcb 100644 --- a/src/video_core/gpu_debugger.h +++ b/src/video_core/gpu_debugger.h | |||
| @@ -18,19 +18,6 @@ | |||
| 18 | class GraphicsDebugger | 18 | class GraphicsDebugger |
| 19 | { | 19 | { |
| 20 | public: | 20 | public: |
| 21 | // A few utility structs used to expose data | ||
| 22 | // A vector of commands represented by their raw byte sequence | ||
| 23 | struct PicaCommand : public std::vector<u32> | ||
| 24 | { | ||
| 25 | const Pica::CommandProcessor::CommandHeader& GetHeader() const | ||
| 26 | { | ||
| 27 | const u32& val = at(1); | ||
| 28 | return *(Pica::CommandProcessor::CommandHeader*)&val; | ||
| 29 | } | ||
| 30 | }; | ||
| 31 | |||
| 32 | typedef std::vector<PicaCommand> PicaCommandList; | ||
| 33 | |||
| 34 | // Base class for all objects which need to be notified about GPU events | 21 | // Base class for all objects which need to be notified about GPU events |
| 35 | class DebuggerObserver | 22 | class DebuggerObserver |
| 36 | { | 23 | { |
| @@ -55,16 +42,6 @@ public: | |||
| 55 | ERROR_LOG(GSP, "Received command: id=%x", (int)cmd.id.Value()); | 42 | ERROR_LOG(GSP, "Received command: id=%x", (int)cmd.id.Value()); |
| 56 | } | 43 | } |
| 57 | 44 | ||
| 58 | /** | ||
| 59 | * @param lst command list which triggered this call | ||
| 60 | * @param is_new true if the command list was called for the first time | ||
| 61 | * @todo figure out how to make sure called functions don't keep references around beyond their life time | ||
| 62 | */ | ||
| 63 | virtual void OnCommandListCalled(const PicaCommandList& lst, bool is_new) | ||
| 64 | { | ||
| 65 | ERROR_LOG(GSP, "Command list called: %d", (int)is_new); | ||
| 66 | } | ||
| 67 | |||
| 68 | protected: | 45 | protected: |
| 69 | const GraphicsDebugger* GetDebugger() const | 46 | const GraphicsDebugger* GetDebugger() const |
| 70 | { | 47 | { |
| @@ -93,49 +70,12 @@ public: | |||
| 93 | } ); | 70 | } ); |
| 94 | } | 71 | } |
| 95 | 72 | ||
| 96 | void CommandListCalled(u32 address, u32* command_list, u32 size_in_words) | ||
| 97 | { | ||
| 98 | if (observers.empty()) | ||
| 99 | return; | ||
| 100 | |||
| 101 | PicaCommandList cmdlist; | ||
| 102 | for (u32* parse_pointer = command_list; parse_pointer < command_list + size_in_words;) | ||
| 103 | { | ||
| 104 | const Pica::CommandProcessor::CommandHeader& header = *(Pica::CommandProcessor::CommandHeader*)(&parse_pointer[1]); | ||
| 105 | |||
| 106 | cmdlist.push_back(PicaCommand()); | ||
| 107 | auto& cmd = cmdlist.back(); | ||
| 108 | |||
| 109 | size_t size = 2 + header.extra_data_length; | ||
| 110 | size = (size + 1) / 2 * 2; // align to 8 bytes | ||
| 111 | cmd.reserve(size); | ||
| 112 | std::copy(parse_pointer, parse_pointer + size, std::back_inserter(cmd)); | ||
| 113 | |||
| 114 | parse_pointer += size; | ||
| 115 | } | ||
| 116 | |||
| 117 | auto obj = std::pair<u32,PicaCommandList>(address, cmdlist); | ||
| 118 | auto it = std::find(command_lists.begin(), command_lists.end(), obj); | ||
| 119 | bool is_new = (it == command_lists.end()); | ||
| 120 | if (is_new) | ||
| 121 | command_lists.push_back(obj); | ||
| 122 | |||
| 123 | ForEachObserver([&](DebuggerObserver* observer) { | ||
| 124 | observer->OnCommandListCalled(obj.second, is_new); | ||
| 125 | } ); | ||
| 126 | } | ||
| 127 | |||
| 128 | const GSP_GPU::Command& ReadGXCommandHistory(int index) const | 73 | const GSP_GPU::Command& ReadGXCommandHistory(int index) const |
| 129 | { | 74 | { |
| 130 | // TODO: Is this thread-safe? | 75 | // TODO: Is this thread-safe? |
| 131 | return gx_command_history[index]; | 76 | return gx_command_history[index]; |
| 132 | } | 77 | } |
| 133 | 78 | ||
| 134 | const std::vector<std::pair<u32,PicaCommandList>>& GetCommandLists() const | ||
| 135 | { | ||
| 136 | return command_lists; | ||
| 137 | } | ||
| 138 | |||
| 139 | void RegisterObserver(DebuggerObserver* observer) | 79 | void RegisterObserver(DebuggerObserver* observer) |
| 140 | { | 80 | { |
| 141 | // TODO: Check for duplicates | 81 | // TODO: Check for duplicates |
| @@ -158,7 +98,4 @@ private: | |||
| 158 | std::vector<DebuggerObserver*> observers; | 98 | std::vector<DebuggerObserver*> observers; |
| 159 | 99 | ||
| 160 | std::vector<GSP_GPU::Command> gx_command_history; | 100 | std::vector<GSP_GPU::Command> gx_command_history; |
| 161 | |||
| 162 | // vector of pairs of command lists and their storage address | ||
| 163 | std::vector<std::pair<u32,PicaCommandList>> command_lists; | ||
| 164 | }; | 101 | }; |