diff options
| author | 2016-12-21 17:19:12 -0500 | |
|---|---|---|
| committer | 2016-12-21 17:19:21 -0500 | |
| commit | 8309d0dade37684076ad530bfbca5d4ffc6d1f4d (patch) | |
| tree | c7eb1050f664df4aad518c55b6648807b0cef2db /src/citra_qt/debugger/graphics_cmdlists.cpp | |
| parent | Merge pull request #2319 from yuriks/profile-scopes (diff) | |
| download | yuzu-8309d0dade37684076ad530bfbca5d4ffc6d1f4d.tar.gz yuzu-8309d0dade37684076ad530bfbca5d4ffc6d1f4d.tar.xz yuzu-8309d0dade37684076ad530bfbca5d4ffc6d1f4d.zip | |
citra-qt: Move graphics debugging code into its own folder
Keeps all graphics debugging stuff from cluttering up the root debugger
folder
Diffstat (limited to 'src/citra_qt/debugger/graphics_cmdlists.cpp')
| -rw-r--r-- | src/citra_qt/debugger/graphics_cmdlists.cpp | 259 |
1 files changed, 0 insertions, 259 deletions
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp deleted file mode 100644 index 98b619dea..000000000 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ /dev/null | |||
| @@ -1,259 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QApplication> | ||
| 6 | #include <QClipboard> | ||
| 7 | #include <QComboBox> | ||
| 8 | #include <QHeaderView> | ||
| 9 | #include <QLabel> | ||
| 10 | #include <QListView> | ||
| 11 | #include <QMainWindow> | ||
| 12 | #include <QPushButton> | ||
| 13 | #include <QSpinBox> | ||
| 14 | #include <QTreeView> | ||
| 15 | #include <QVBoxLayout> | ||
| 16 | #include "citra_qt/debugger/graphics_cmdlists.h" | ||
| 17 | #include "citra_qt/util/spinbox.h" | ||
| 18 | #include "citra_qt/util/util.h" | ||
| 19 | #include "common/vector_math.h" | ||
| 20 | #include "video_core/debug_utils/debug_utils.h" | ||
| 21 | #include "video_core/pica.h" | ||
| 22 | #include "video_core/pica_state.h" | ||
| 23 | |||
| 24 | namespace { | ||
| 25 | QImage LoadTexture(const u8* src, const Pica::DebugUtils::TextureInfo& info) { | ||
| 26 | QImage decoded_image(info.width, info.height, QImage::Format_ARGB32); | ||
| 27 | for (int y = 0; y < info.height; ++y) { | ||
| 28 | for (int x = 0; x < info.width; ++x) { | ||
| 29 | Math::Vec4<u8> color = Pica::DebugUtils::LookupTexture(src, x, y, info, true); | ||
| 30 | decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a())); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | return decoded_image; | ||
| 35 | } | ||
| 36 | |||
| 37 | class TextureInfoWidget : public QWidget { | ||
| 38 | public: | ||
| 39 | TextureInfoWidget(const u8* src, const Pica::DebugUtils::TextureInfo& info, | ||
| 40 | QWidget* parent = nullptr) | ||
| 41 | : QWidget(parent) { | ||
| 42 | QLabel* image_widget = new QLabel; | ||
| 43 | QPixmap image_pixmap = QPixmap::fromImage(LoadTexture(src, info)); | ||
| 44 | image_pixmap = image_pixmap.scaled(200, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation); | ||
| 45 | image_widget->setPixmap(image_pixmap); | ||
| 46 | |||
| 47 | QVBoxLayout* layout = new QVBoxLayout; | ||
| 48 | layout->addWidget(image_widget); | ||
| 49 | setLayout(layout); | ||
| 50 | } | ||
| 51 | }; | ||
| 52 | } // Anonymous namespace | ||
| 53 | |||
| 54 | GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) {} | ||
| 55 | |||
| 56 | int GPUCommandListModel::rowCount(const QModelIndex& parent) const { | ||
| 57 | return static_cast<int>(pica_trace.writes.size()); | ||
| 58 | } | ||
| 59 | |||
| 60 | int GPUCommandListModel::columnCount(const QModelIndex& parent) const { | ||
| 61 | return 4; | ||
| 62 | } | ||
| 63 | |||
| 64 | QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { | ||
| 65 | if (!index.isValid()) | ||
| 66 | return QVariant(); | ||
| 67 | |||
| 68 | const auto& write = pica_trace.writes[index.row()]; | ||
| 69 | |||
| 70 | if (role == Qt::DisplayRole) { | ||
| 71 | switch (index.column()) { | ||
| 72 | case 0: | ||
| 73 | return QString::fromLatin1(Pica::Regs::GetCommandName(write.cmd_id).c_str()); | ||
| 74 | case 1: | ||
| 75 | return QString("%1").arg(write.cmd_id, 3, 16, QLatin1Char('0')); | ||
| 76 | case 2: | ||
| 77 | return QString("%1").arg(write.mask, 4, 2, QLatin1Char('0')); | ||
| 78 | case 3: | ||
| 79 | return QString("%1").arg(write.value, 8, 16, QLatin1Char('0')); | ||
| 80 | } | ||
| 81 | } else if (role == CommandIdRole) { | ||
| 82 | return QVariant::fromValue<int>(write.cmd_id); | ||
| 83 | } | ||
| 84 | |||
| 85 | return QVariant(); | ||
| 86 | } | ||
| 87 | |||
| 88 | QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientation, int role) const { | ||
| 89 | switch (role) { | ||
| 90 | case Qt::DisplayRole: { | ||
| 91 | switch (section) { | ||
| 92 | case 0: | ||
| 93 | return tr("Command Name"); | ||
| 94 | case 1: | ||
| 95 | return tr("Register"); | ||
| 96 | case 2: | ||
| 97 | return tr("Mask"); | ||
| 98 | case 3: | ||
| 99 | return tr("New Value"); | ||
| 100 | } | ||
| 101 | |||
| 102 | break; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | return QVariant(); | ||
| 107 | } | ||
| 108 | |||
| 109 | void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace) { | ||
| 110 | beginResetModel(); | ||
| 111 | |||
| 112 | pica_trace = trace; | ||
| 113 | |||
| 114 | endResetModel(); | ||
| 115 | } | ||
| 116 | |||
| 117 | #define COMMAND_IN_RANGE(cmd_id, reg_name) \ | ||
| 118 | (cmd_id >= PICA_REG_INDEX(reg_name) && \ | ||
| 119 | cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::g_state.regs.reg_name)) / 4) | ||
| 120 | |||
| 121 | void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { | ||
| 122 | const unsigned int command_id = | ||
| 123 | list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); | ||
| 124 | if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) || | ||
| 125 | COMMAND_IN_RANGE(command_id, texture2)) { | ||
| 126 | |||
| 127 | unsigned texture_index; | ||
| 128 | if (COMMAND_IN_RANGE(command_id, texture0)) { | ||
| 129 | texture_index = 0; | ||
| 130 | } else if (COMMAND_IN_RANGE(command_id, texture1)) { | ||
| 131 | texture_index = 1; | ||
| 132 | } else if (COMMAND_IN_RANGE(command_id, texture2)) { | ||
| 133 | texture_index = 2; | ||
| 134 | } else { | ||
| 135 | UNREACHABLE_MSG("Unknown texture command"); | ||
| 136 | } | ||
| 137 | |||
| 138 | const auto texture = Pica::g_state.regs.GetTextures()[texture_index]; | ||
| 139 | const auto config = texture.config; | ||
| 140 | const auto format = texture.format; | ||
| 141 | const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format); | ||
| 142 | |||
| 143 | // TODO: Open a surface debugger | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { | ||
| 148 | QWidget* new_info_widget = nullptr; | ||
| 149 | |||
| 150 | const unsigned int command_id = | ||
| 151 | list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); | ||
| 152 | if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) || | ||
| 153 | COMMAND_IN_RANGE(command_id, texture2)) { | ||
| 154 | |||
| 155 | unsigned texture_index; | ||
| 156 | if (COMMAND_IN_RANGE(command_id, texture0)) { | ||
| 157 | texture_index = 0; | ||
| 158 | } else if (COMMAND_IN_RANGE(command_id, texture1)) { | ||
| 159 | texture_index = 1; | ||
| 160 | } else { | ||
| 161 | texture_index = 2; | ||
| 162 | } | ||
| 163 | |||
| 164 | const auto texture = Pica::g_state.regs.GetTextures()[texture_index]; | ||
| 165 | const auto config = texture.config; | ||
| 166 | const auto format = texture.format; | ||
| 167 | |||
| 168 | const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format); | ||
| 169 | const u8* src = Memory::GetPhysicalPointer(config.GetPhysicalAddress()); | ||
| 170 | new_info_widget = new TextureInfoWidget(src, info); | ||
| 171 | } | ||
| 172 | if (command_info_widget) { | ||
| 173 | delete command_info_widget; | ||
| 174 | command_info_widget = nullptr; | ||
| 175 | } | ||
| 176 | if (new_info_widget) { | ||
| 177 | widget()->layout()->addWidget(new_info_widget); | ||
| 178 | command_info_widget = new_info_widget; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | #undef COMMAND_IN_RANGE | ||
| 182 | |||
| 183 | GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) | ||
| 184 | : QDockWidget(tr("Pica Command List"), parent) { | ||
| 185 | setObjectName("Pica Command List"); | ||
| 186 | GPUCommandListModel* model = new GPUCommandListModel(this); | ||
| 187 | |||
| 188 | QWidget* main_widget = new QWidget; | ||
| 189 | |||
| 190 | list_widget = new QTreeView; | ||
| 191 | list_widget->setModel(model); | ||
| 192 | list_widget->setFont(GetMonospaceFont()); | ||
| 193 | list_widget->setRootIsDecorated(false); | ||
| 194 | list_widget->setUniformRowHeights(true); | ||
| 195 | |||
| 196 | #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) | ||
| 197 | list_widget->header()->setSectionResizeMode(QHeaderView::ResizeToContents); | ||
| 198 | #else | ||
| 199 | list_widget->header()->setResizeMode(QHeaderView::ResizeToContents); | ||
| 200 | #endif | ||
| 201 | |||
| 202 | connect(list_widget->selectionModel(), | ||
| 203 | SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), this, | ||
| 204 | SLOT(SetCommandInfo(const QModelIndex&))); | ||
| 205 | connect(list_widget, SIGNAL(doubleClicked(const QModelIndex&)), this, | ||
| 206 | SLOT(OnCommandDoubleClicked(const QModelIndex&))); | ||
| 207 | |||
| 208 | toggle_tracing = new QPushButton(tr("Start Tracing")); | ||
| 209 | QPushButton* copy_all = new QPushButton(tr("Copy All")); | ||
| 210 | |||
| 211 | connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); | ||
| 212 | connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), model, | ||
| 213 | SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); | ||
| 214 | |||
| 215 | connect(copy_all, SIGNAL(clicked()), this, SLOT(CopyAllToClipboard())); | ||
| 216 | |||
| 217 | command_info_widget = nullptr; | ||
| 218 | |||
| 219 | QVBoxLayout* main_layout = new QVBoxLayout; | ||
| 220 | main_layout->addWidget(list_widget); | ||
| 221 | { | ||
| 222 | QHBoxLayout* sub_layout = new QHBoxLayout; | ||
| 223 | sub_layout->addWidget(toggle_tracing); | ||
| 224 | sub_layout->addWidget(copy_all); | ||
| 225 | main_layout->addLayout(sub_layout); | ||
| 226 | } | ||
| 227 | main_widget->setLayout(main_layout); | ||
| 228 | |||
| 229 | setWidget(main_widget); | ||
| 230 | } | ||
| 231 | |||
| 232 | void GPUCommandListWidget::OnToggleTracing() { | ||
| 233 | if (!Pica::DebugUtils::IsPicaTracing()) { | ||
| 234 | Pica::DebugUtils::StartPicaTracing(); | ||
| 235 | toggle_tracing->setText(tr("Finish Tracing")); | ||
| 236 | } else { | ||
| 237 | pica_trace = Pica::DebugUtils::FinishPicaTracing(); | ||
| 238 | emit TracingFinished(*pica_trace); | ||
| 239 | toggle_tracing->setText(tr("Start Tracing")); | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | void GPUCommandListWidget::CopyAllToClipboard() { | ||
| 244 | QClipboard* clipboard = QApplication::clipboard(); | ||
| 245 | QString text; | ||
| 246 | |||
| 247 | QAbstractItemModel* model = static_cast<QAbstractItemModel*>(list_widget->model()); | ||
| 248 | |||
| 249 | for (int row = 0; row < model->rowCount({}); ++row) { | ||
| 250 | for (int col = 0; col < model->columnCount({}); ++col) { | ||
| 251 | QModelIndex index = model->index(row, col); | ||
| 252 | text += model->data(index).value<QString>(); | ||
| 253 | text += '\t'; | ||
| 254 | } | ||
| 255 | text += '\n'; | ||
| 256 | } | ||
| 257 | |||
| 258 | clipboard->setText(text); | ||
| 259 | } | ||