diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/citra_qt/debugger/graphics_cmdlists.cpp | 64 | ||||
| -rw-r--r-- | src/citra_qt/debugger/graphics_cmdlists.hxx | 8 | ||||
| -rw-r--r-- | src/video_core/debug_utils/debug_utils.cpp | 57 | ||||
| -rw-r--r-- | src/video_core/debug_utils/debug_utils.h | 9 |
4 files changed, 116 insertions, 22 deletions
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 9e53a03d0..dcd0ced33 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 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 <QLabel> | ||
| 5 | #include <QListView> | 6 | #include <QListView> |
| 6 | #include <QPushButton> | 7 | #include <QPushButton> |
| 7 | #include <QVBoxLayout> | 8 | #include <QVBoxLayout> |
| @@ -9,6 +10,33 @@ | |||
| 9 | 10 | ||
| 10 | #include "graphics_cmdlists.hxx" | 11 | #include "graphics_cmdlists.hxx" |
| 11 | 12 | ||
| 13 | #include "video_core/pica.h" | ||
| 14 | #include "video_core/math.h" | ||
| 15 | |||
| 16 | #include "video_core/debug_utils/debug_utils.h" | ||
| 17 | |||
| 18 | class TextureInfoWidget : public QWidget { | ||
| 19 | public: | ||
| 20 | TextureInfoWidget(u8* src, const Pica::DebugUtils::TextureInfo& info, QWidget* parent = nullptr) : QWidget(parent) { | ||
| 21 | QImage decoded_image(info.width, info.height, QImage::Format_ARGB32); | ||
| 22 | for (int y = 0; y < info.height; ++y) { | ||
| 23 | for (int x = 0; x < info.width; ++x) { | ||
| 24 | Math::Vec4<u8> color = Pica::DebugUtils::LookupTexture(src, x, y, info); | ||
| 25 | decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a())); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | QLabel* image_widget = new QLabel; | ||
| 30 | QPixmap image_pixmap = QPixmap::fromImage(decoded_image); | ||
| 31 | image_pixmap = image_pixmap.scaled(200, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation); | ||
| 32 | image_widget->setPixmap(image_pixmap); | ||
| 33 | |||
| 34 | QVBoxLayout* layout = new QVBoxLayout; | ||
| 35 | layout->addWidget(image_widget); | ||
| 36 | setLayout(layout); | ||
| 37 | } | ||
| 38 | }; | ||
| 39 | |||
| 12 | GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) | 40 | GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) |
| 13 | { | 41 | { |
| 14 | 42 | ||
| @@ -44,6 +72,8 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const | |||
| 44 | } | 72 | } |
| 45 | 73 | ||
| 46 | return QVariant(content); | 74 | return QVariant(content); |
| 75 | } else if (role == CommandIdRole) { | ||
| 76 | return QVariant::fromValue<int>(cmd.cmd_id.Value()); | ||
| 47 | } | 77 | } |
| 48 | 78 | ||
| 49 | return QVariant(); | 79 | return QVariant(); |
| @@ -76,27 +106,59 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& | |||
| 76 | endResetModel(); | 106 | endResetModel(); |
| 77 | } | 107 | } |
| 78 | 108 | ||
| 109 | void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) | ||
| 110 | { | ||
| 111 | QWidget* new_info_widget; | ||
| 112 | |||
| 113 | #define COMMAND_IN_RANGE(cmd_id, reg_name) (cmd_id >= PICA_REG_INDEX(reg_name) && cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::registers.reg_name)) / 4) | ||
| 114 | const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt(); | ||
| 115 | if (COMMAND_IN_RANGE(command_id, texture0)) { | ||
| 116 | u8* src = Memory::GetPointer(Pica::registers.texture0.GetPhysicalAddress()); | ||
| 117 | Pica::DebugUtils::TextureInfo info; | ||
| 118 | info.width = Pica::registers.texture0.width; | ||
| 119 | info.height = Pica::registers.texture0.height; | ||
| 120 | info.stride = 3 * Pica::registers.texture0.width; | ||
| 121 | info.format = Pica::registers.texture0_format; | ||
| 122 | new_info_widget = new TextureInfoWidget(src, info); | ||
| 123 | } else { | ||
| 124 | new_info_widget = new QWidget; | ||
| 125 | } | ||
| 126 | #undef COMMAND_IN_RANGE | ||
| 127 | |||
| 128 | widget()->layout()->removeWidget(command_info_widget); | ||
| 129 | delete command_info_widget; | ||
| 130 | widget()->layout()->addWidget(new_info_widget); | ||
| 131 | command_info_widget = new_info_widget; | ||
| 132 | } | ||
| 79 | 133 | ||
| 80 | GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) | 134 | GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) |
| 81 | { | 135 | { |
| 136 | setObjectName("Pica Command List"); | ||
| 82 | GPUCommandListModel* model = new GPUCommandListModel(this); | 137 | GPUCommandListModel* model = new GPUCommandListModel(this); |
| 83 | 138 | ||
| 84 | QWidget* main_widget = new QWidget; | 139 | QWidget* main_widget = new QWidget; |
| 85 | 140 | ||
| 86 | QTreeView* list_widget = new QTreeView; | 141 | list_widget = new QTreeView; |
| 87 | list_widget->setModel(model); | 142 | list_widget->setModel(model); |
| 88 | list_widget->setFont(QFont("monospace")); | 143 | list_widget->setFont(QFont("monospace")); |
| 89 | list_widget->setRootIsDecorated(false); | 144 | list_widget->setRootIsDecorated(false); |
| 90 | 145 | ||
| 146 | connect(list_widget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)), | ||
| 147 | this, SLOT(SetCommandInfo(const QModelIndex&))); | ||
| 148 | |||
| 149 | |||
| 91 | toggle_tracing = new QPushButton(tr("Start Tracing")); | 150 | toggle_tracing = new QPushButton(tr("Start Tracing")); |
| 92 | 151 | ||
| 93 | connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); | 152 | connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); |
| 94 | connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), | 153 | connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), |
| 95 | model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); | 154 | model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); |
| 96 | 155 | ||
| 156 | command_info_widget = new QWidget; | ||
| 157 | |||
| 97 | QVBoxLayout* main_layout = new QVBoxLayout; | 158 | QVBoxLayout* main_layout = new QVBoxLayout; |
| 98 | main_layout->addWidget(list_widget); | 159 | main_layout->addWidget(list_widget); |
| 99 | main_layout->addWidget(toggle_tracing); | 160 | main_layout->addWidget(toggle_tracing); |
| 161 | main_layout->addWidget(command_info_widget); | ||
| 100 | main_widget->setLayout(main_layout); | 162 | main_widget->setLayout(main_layout); |
| 101 | 163 | ||
| 102 | setWidget(main_widget); | 164 | setWidget(main_widget); |
diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx index 31bd2546d..37fe19053 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.hxx +++ b/src/citra_qt/debugger/graphics_cmdlists.hxx | |||
| @@ -11,12 +11,17 @@ | |||
| 11 | #include "video_core/debug_utils/debug_utils.h" | 11 | #include "video_core/debug_utils/debug_utils.h" |
| 12 | 12 | ||
| 13 | class QPushButton; | 13 | class QPushButton; |
| 14 | class QTreeView; | ||
| 14 | 15 | ||
| 15 | class GPUCommandListModel : public QAbstractListModel | 16 | class GPUCommandListModel : public QAbstractListModel |
| 16 | { | 17 | { |
| 17 | Q_OBJECT | 18 | Q_OBJECT |
| 18 | 19 | ||
| 19 | public: | 20 | public: |
| 21 | enum { | ||
| 22 | CommandIdRole = Qt::UserRole, | ||
| 23 | }; | ||
| 24 | |||
| 20 | GPUCommandListModel(QObject* parent); | 25 | GPUCommandListModel(QObject* parent); |
| 21 | 26 | ||
| 22 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; | 27 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; |
| @@ -40,6 +45,7 @@ public: | |||
| 40 | 45 | ||
| 41 | public slots: | 46 | public slots: |
| 42 | void OnToggleTracing(); | 47 | void OnToggleTracing(); |
| 48 | void SetCommandInfo(const QModelIndex&); | ||
| 43 | 49 | ||
| 44 | signals: | 50 | signals: |
| 45 | void TracingFinished(const Pica::DebugUtils::PicaTrace&); | 51 | void TracingFinished(const Pica::DebugUtils::PicaTrace&); |
| @@ -47,5 +53,7 @@ signals: | |||
| 47 | private: | 53 | private: |
| 48 | std::unique_ptr<Pica::DebugUtils::PicaTrace> pica_trace; | 54 | std::unique_ptr<Pica::DebugUtils::PicaTrace> pica_trace; |
| 49 | 55 | ||
| 56 | QTreeView* list_widget; | ||
| 57 | QWidget* command_info_widget; | ||
| 50 | QPushButton* toggle_tracing; | 58 | QPushButton* toggle_tracing; |
| 51 | }; | 59 | }; |
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 11f87d988..59909c827 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 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 <cassert> | ||
| 6 | |||
| 5 | #include <algorithm> | 7 | #include <algorithm> |
| 6 | #include <condition_variable> | 8 | #include <condition_variable> |
| 7 | #include <list> | 9 | #include <list> |
| @@ -17,6 +19,7 @@ | |||
| 17 | #include "common/log.h" | 19 | #include "common/log.h" |
| 18 | #include "common/file_util.h" | 20 | #include "common/file_util.h" |
| 19 | 21 | ||
| 22 | #include "video_core/math.h" | ||
| 20 | #include "video_core/pica.h" | 23 | #include "video_core/pica.h" |
| 21 | 24 | ||
| 22 | #include "debug_utils.h" | 25 | #include "debug_utils.h" |
| @@ -355,6 +358,30 @@ std::unique_ptr<PicaTrace> FinishPicaTracing() | |||
| 355 | return std::move(ret); | 358 | return std::move(ret); |
| 356 | } | 359 | } |
| 357 | 360 | ||
| 361 | const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& info) { | ||
| 362 | assert(info.format == Pica::Regs::TextureFormat::RGB8); | ||
| 363 | |||
| 364 | // Cf. rasterizer code for an explanation of this algorithm. | ||
| 365 | int texel_index_within_tile = 0; | ||
| 366 | for (int block_size_index = 0; block_size_index < 3; ++block_size_index) { | ||
| 367 | int sub_tile_width = 1 << block_size_index; | ||
| 368 | int sub_tile_height = 1 << block_size_index; | ||
| 369 | |||
| 370 | int sub_tile_index = (x & sub_tile_width) << block_size_index; | ||
| 371 | sub_tile_index += 2 * ((y & sub_tile_height) << block_size_index); | ||
| 372 | texel_index_within_tile += sub_tile_index; | ||
| 373 | } | ||
| 374 | |||
| 375 | const int block_width = 8; | ||
| 376 | const int block_height = 8; | ||
| 377 | |||
| 378 | int coarse_x = (x / block_width) * block_width; | ||
| 379 | int coarse_y = (y / block_height) * block_height; | ||
| 380 | |||
| 381 | const u8* source_ptr = source + coarse_x * block_height * 3 + coarse_y * info.stride + texel_index_within_tile * 3; | ||
| 382 | return { source_ptr[2], source_ptr[1], source_ptr[0], 255 }; | ||
| 383 | } | ||
| 384 | |||
| 358 | void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { | 385 | void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { |
| 359 | // NOTE: Permanently enabling this just trashes hard disks for no reason. | 386 | // NOTE: Permanently enabling this just trashes hard disks for no reason. |
| 360 | // Hence, this is currently disabled. | 387 | // Hence, this is currently disabled. |
| @@ -420,27 +447,15 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { | |||
| 420 | buf = new u8[row_stride * texture_config.height]; | 447 | buf = new u8[row_stride * texture_config.height]; |
| 421 | for (unsigned y = 0; y < texture_config.height; ++y) { | 448 | for (unsigned y = 0; y < texture_config.height; ++y) { |
| 422 | for (unsigned x = 0; x < texture_config.width; ++x) { | 449 | for (unsigned x = 0; x < texture_config.width; ++x) { |
| 423 | // Cf. rasterizer code for an explanation of this algorithm. | 450 | TextureInfo info; |
| 424 | int texel_index_within_tile = 0; | 451 | info.width = texture_config.width; |
| 425 | for (int block_size_index = 0; block_size_index < 3; ++block_size_index) { | 452 | info.height = texture_config.height; |
| 426 | int sub_tile_width = 1 << block_size_index; | 453 | info.stride = row_stride; |
| 427 | int sub_tile_height = 1 << block_size_index; | 454 | info.format = registers.texture0_format; |
| 428 | 455 | Math::Vec4<u8> texture_color = LookupTexture(data, x, y, info); | |
| 429 | int sub_tile_index = (x & sub_tile_width) << block_size_index; | 456 | buf[3 * x + y * row_stride ] = texture_color.r(); |
| 430 | sub_tile_index += 2 * ((y & sub_tile_height) << block_size_index); | 457 | buf[3 * x + y * row_stride + 1] = texture_color.g(); |
| 431 | texel_index_within_tile += sub_tile_index; | 458 | buf[3 * x + y * row_stride + 2] = texture_color.b(); |
| 432 | } | ||
| 433 | |||
| 434 | const int block_width = 8; | ||
| 435 | const int block_height = 8; | ||
| 436 | |||
| 437 | int coarse_x = (x / block_width) * block_width; | ||
| 438 | int coarse_y = (y / block_height) * block_height; | ||
| 439 | |||
| 440 | u8* source_ptr = (u8*)data + coarse_x * block_height * 3 + coarse_y * row_stride + texel_index_within_tile * 3; | ||
| 441 | buf[3 * x + y * row_stride ] = source_ptr[2]; | ||
| 442 | buf[3 * x + y * row_stride + 1] = source_ptr[1]; | ||
| 443 | buf[3 * x + y * row_stride + 2] = source_ptr[0]; | ||
| 444 | } | 459 | } |
| 445 | } | 460 | } |
| 446 | 461 | ||
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h index 26b26e22f..bad4c919a 100644 --- a/src/video_core/debug_utils/debug_utils.h +++ b/src/video_core/debug_utils/debug_utils.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <mutex> | 12 | #include <mutex> |
| 13 | #include <vector> | 13 | #include <vector> |
| 14 | 14 | ||
| 15 | #include "video_core/math.h" | ||
| 15 | #include "video_core/pica.h" | 16 | #include "video_core/pica.h" |
| 16 | 17 | ||
| 17 | namespace Pica { | 18 | namespace Pica { |
| @@ -190,6 +191,14 @@ bool IsPicaTracing(); | |||
| 190 | void OnPicaRegWrite(u32 id, u32 value); | 191 | void OnPicaRegWrite(u32 id, u32 value); |
| 191 | std::unique_ptr<PicaTrace> FinishPicaTracing(); | 192 | std::unique_ptr<PicaTrace> FinishPicaTracing(); |
| 192 | 193 | ||
| 194 | struct TextureInfo { | ||
| 195 | int width; | ||
| 196 | int height; | ||
| 197 | int stride; | ||
| 198 | Pica::Regs::TextureFormat format; | ||
| 199 | }; | ||
| 200 | |||
| 201 | const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& info); | ||
| 193 | void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data); | 202 | void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data); |
| 194 | 203 | ||
| 195 | void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages); | 204 | void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages); |