diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/yuzu/debugger/graphics/graphics_surface.cpp | 206 |
1 files changed, 131 insertions, 75 deletions
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp index 11023ed63..f2d14becf 100644 --- a/src/yuzu/debugger/graphics/graphics_surface.cpp +++ b/src/yuzu/debugger/graphics/graphics_surface.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <QDebug> | 7 | #include <QDebug> |
| 8 | #include <QFileDialog> | 8 | #include <QFileDialog> |
| 9 | #include <QLabel> | 9 | #include <QLabel> |
| 10 | #include <QMessageBox> | ||
| 10 | #include <QMouseEvent> | 11 | #include <QMouseEvent> |
| 11 | #include <QPushButton> | 12 | #include <QPushButton> |
| 12 | #include <QScrollArea> | 13 | #include <QScrollArea> |
| @@ -95,50 +96,91 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Tegra::DebugContext | |||
| 95 | surface_picker_y_control = new QSpinBox; | 96 | surface_picker_y_control = new QSpinBox; |
| 96 | surface_picker_y_control->setRange(0, max_dimension - 1); | 97 | surface_picker_y_control->setRange(0, max_dimension - 1); |
| 97 | 98 | ||
| 98 | surface_format_control = new QComboBox; | 99 | // clang-format off |
| 99 | |||
| 100 | // Color formats sorted by Maxwell texture format index | 100 | // Color formats sorted by Maxwell texture format index |
| 101 | surface_format_control->addItem(tr("None")); | 101 | const QStringList surface_formats{ |
| 102 | surface_format_control->addItem(tr("Unknown")); | 102 | tr("None"), |
| 103 | surface_format_control->addItem(tr("Unknown")); | 103 | QStringLiteral("R32_G32_B32_A32"), |
| 104 | surface_format_control->addItem(tr("Unknown")); | 104 | QStringLiteral("R32_G32_B32"), |
| 105 | surface_format_control->addItem(tr("Unknown")); | 105 | QStringLiteral("R16_G16_B16_A16"), |
| 106 | surface_format_control->addItem(tr("Unknown")); | 106 | QStringLiteral("R32_G32"), |
| 107 | surface_format_control->addItem(tr("Unknown")); | 107 | QStringLiteral("R32_B24G8"), |
| 108 | surface_format_control->addItem(tr("Unknown")); | 108 | QStringLiteral("ETC2_RGB"), |
| 109 | surface_format_control->addItem(tr("A8R8G8B8")); | 109 | QStringLiteral("X8B8G8R8"), |
| 110 | surface_format_control->addItem(tr("Unknown")); | 110 | QStringLiteral("A8R8G8B8"), |
| 111 | surface_format_control->addItem(tr("Unknown")); | 111 | QStringLiteral("A2B10G10R10"), |
| 112 | surface_format_control->addItem(tr("Unknown")); | 112 | QStringLiteral("ETC2_RGB_PTA"), |
| 113 | surface_format_control->addItem(tr("Unknown")); | 113 | QStringLiteral("ETC2_RGBA"), |
| 114 | surface_format_control->addItem(tr("Unknown")); | 114 | QStringLiteral("R16_G16"), |
| 115 | surface_format_control->addItem(tr("Unknown")); | 115 | QStringLiteral("G8R24"), |
| 116 | surface_format_control->addItem(tr("Unknown")); | 116 | QStringLiteral("G24R8"), |
| 117 | surface_format_control->addItem(tr("Unknown")); | 117 | QStringLiteral("R32"), |
| 118 | surface_format_control->addItem(tr("Unknown")); | 118 | QStringLiteral("BC6H_SF16"), |
| 119 | surface_format_control->addItem(tr("Unknown")); | 119 | QStringLiteral("BC6H_UF16"), |
| 120 | surface_format_control->addItem(tr("Unknown")); | 120 | QStringLiteral("A4B4G4R4"), |
| 121 | surface_format_control->addItem(tr("Unknown")); | 121 | QStringLiteral("A5B5G5R1"), |
| 122 | surface_format_control->addItem(tr("Unknown")); | 122 | QStringLiteral("A1B5G5R5"), |
| 123 | surface_format_control->addItem(tr("Unknown")); | 123 | QStringLiteral("B5G6R5"), |
| 124 | surface_format_control->addItem(tr("Unknown")); | 124 | QStringLiteral("B6G5R5"), |
| 125 | surface_format_control->addItem(tr("Unknown")); | 125 | QStringLiteral("BC7U"), |
| 126 | surface_format_control->addItem(tr("Unknown")); | 126 | QStringLiteral("G8R8"), |
| 127 | surface_format_control->addItem(tr("Unknown")); | 127 | QStringLiteral("EAC"), |
| 128 | surface_format_control->addItem(tr("Unknown")); | 128 | QStringLiteral("EACX2"), |
| 129 | surface_format_control->addItem(tr("Unknown")); | 129 | QStringLiteral("R16"), |
| 130 | surface_format_control->addItem(tr("Unknown")); | 130 | QStringLiteral("Y8_VIDEO"), |
| 131 | surface_format_control->addItem(tr("Unknown")); | 131 | QStringLiteral("R8"), |
| 132 | surface_format_control->addItem(tr("Unknown")); | 132 | QStringLiteral("G4R4"), |
| 133 | surface_format_control->addItem(tr("Unknown")); | 133 | QStringLiteral("R1"), |
| 134 | surface_format_control->addItem(tr("Unknown")); | 134 | QStringLiteral("E5B9G9R9_SHAREDEXP"), |
| 135 | surface_format_control->addItem(tr("Unknown")); | 135 | QStringLiteral("BF10GF11RF11"), |
| 136 | surface_format_control->addItem(tr("Unknown")); | 136 | QStringLiteral("G8B8G8R8"), |
| 137 | surface_format_control->addItem(tr("DXT1")); | 137 | QStringLiteral("B8G8R8G8"), |
| 138 | surface_format_control->addItem(tr("DXT23")); | 138 | QStringLiteral("DXT1"), |
| 139 | surface_format_control->addItem(tr("DXT45")); | 139 | QStringLiteral("DXT23"), |
| 140 | surface_format_control->addItem(tr("DXN1")); | 140 | QStringLiteral("DXT45"), |
| 141 | surface_format_control->addItem(tr("DXN2")); | 141 | QStringLiteral("DXN1"), |
| 142 | QStringLiteral("DXN2"), | ||
| 143 | QStringLiteral("Z24S8"), | ||
| 144 | QStringLiteral("X8Z24"), | ||
| 145 | QStringLiteral("S8Z24"), | ||
| 146 | QStringLiteral("X4V4Z24__COV4R4V"), | ||
| 147 | QStringLiteral("X4V4Z24__COV8R8V"), | ||
| 148 | QStringLiteral("V8Z24__COV4R12V"), | ||
| 149 | QStringLiteral("ZF32"), | ||
| 150 | QStringLiteral("ZF32_X24S8"), | ||
| 151 | QStringLiteral("X8Z24_X20V4S8__COV4R4V"), | ||
| 152 | QStringLiteral("X8Z24_X20V4S8__COV8R8V"), | ||
| 153 | QStringLiteral("ZF32_X20V4X8__COV4R4V"), | ||
| 154 | QStringLiteral("ZF32_X20V4X8__COV8R8V"), | ||
| 155 | QStringLiteral("ZF32_X20V4S8__COV4R4V"), | ||
| 156 | QStringLiteral("ZF32_X20V4S8__COV8R8V"), | ||
| 157 | QStringLiteral("X8Z24_X16V8S8__COV4R12V"), | ||
| 158 | QStringLiteral("ZF32_X16V8X8__COV4R12V"), | ||
| 159 | QStringLiteral("ZF32_X16V8S8__COV4R12V"), | ||
| 160 | QStringLiteral("Z16"), | ||
| 161 | QStringLiteral("V8Z24__COV8R24V"), | ||
| 162 | QStringLiteral("X8Z24_X16V8S8__COV8R24V"), | ||
| 163 | QStringLiteral("ZF32_X16V8X8__COV8R24V"), | ||
| 164 | QStringLiteral("ZF32_X16V8S8__COV8R24V"), | ||
| 165 | QStringLiteral("ASTC_2D_4X4"), | ||
| 166 | QStringLiteral("ASTC_2D_5X5"), | ||
| 167 | QStringLiteral("ASTC_2D_6X6"), | ||
| 168 | QStringLiteral("ASTC_2D_8X8"), | ||
| 169 | QStringLiteral("ASTC_2D_10X10"), | ||
| 170 | QStringLiteral("ASTC_2D_12X12"), | ||
| 171 | QStringLiteral("ASTC_2D_5X4"), | ||
| 172 | QStringLiteral("ASTC_2D_6X5"), | ||
| 173 | QStringLiteral("ASTC_2D_8X6"), | ||
| 174 | QStringLiteral("ASTC_2D_10X8"), | ||
| 175 | QStringLiteral("ASTC_2D_12X10"), | ||
| 176 | QStringLiteral("ASTC_2D_8X5"), | ||
| 177 | QStringLiteral("ASTC_2D_10X5"), | ||
| 178 | QStringLiteral("ASTC_2D_10X6"), | ||
| 179 | }; | ||
| 180 | // clang-format on | ||
| 181 | |||
| 182 | surface_format_control = new QComboBox; | ||
| 183 | surface_format_control->addItems(surface_formats); | ||
| 142 | 184 | ||
| 143 | surface_info_label = new QLabel(); | 185 | surface_info_label = new QLabel(); |
| 144 | surface_info_label->setWordWrap(true); | 186 | surface_info_label->setWordWrap(true); |
| @@ -157,22 +199,20 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Tegra::DebugContext | |||
| 157 | 199 | ||
| 158 | // Connections | 200 | // Connections |
| 159 | connect(this, &GraphicsSurfaceWidget::Update, this, &GraphicsSurfaceWidget::OnUpdate); | 201 | connect(this, &GraphicsSurfaceWidget::Update, this, &GraphicsSurfaceWidget::OnUpdate); |
| 160 | connect(surface_source_list, | 202 | connect(surface_source_list, qOverload<int>(&QComboBox::currentIndexChanged), this, |
| 161 | static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, | ||
| 162 | &GraphicsSurfaceWidget::OnSurfaceSourceChanged); | 203 | &GraphicsSurfaceWidget::OnSurfaceSourceChanged); |
| 163 | connect(surface_address_control, &CSpinBox::ValueChanged, this, | 204 | connect(surface_address_control, &CSpinBox::ValueChanged, this, |
| 164 | &GraphicsSurfaceWidget::OnSurfaceAddressChanged); | 205 | &GraphicsSurfaceWidget::OnSurfaceAddressChanged); |
| 165 | connect(surface_width_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), | 206 | connect(surface_width_control, qOverload<int>(&QSpinBox::valueChanged), this, |
| 166 | this, &GraphicsSurfaceWidget::OnSurfaceWidthChanged); | 207 | &GraphicsSurfaceWidget::OnSurfaceWidthChanged); |
| 167 | connect(surface_height_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), | 208 | connect(surface_height_control, qOverload<int>(&QSpinBox::valueChanged), this, |
| 168 | this, &GraphicsSurfaceWidget::OnSurfaceHeightChanged); | 209 | &GraphicsSurfaceWidget::OnSurfaceHeightChanged); |
| 169 | connect(surface_format_control, | 210 | connect(surface_format_control, qOverload<int>(&QComboBox::currentIndexChanged), this, |
| 170 | static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, | ||
| 171 | &GraphicsSurfaceWidget::OnSurfaceFormatChanged); | 211 | &GraphicsSurfaceWidget::OnSurfaceFormatChanged); |
| 172 | connect(surface_picker_x_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), | 212 | connect(surface_picker_x_control, qOverload<int>(&QSpinBox::valueChanged), this, |
| 173 | this, &GraphicsSurfaceWidget::OnSurfacePickerXChanged); | 213 | &GraphicsSurfaceWidget::OnSurfacePickerXChanged); |
| 174 | connect(surface_picker_y_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), | 214 | connect(surface_picker_y_control, qOverload<int>(&QSpinBox::valueChanged), this, |
| 175 | this, &GraphicsSurfaceWidget::OnSurfacePickerYChanged); | 215 | &GraphicsSurfaceWidget::OnSurfacePickerYChanged); |
| 176 | connect(save_surface, &QPushButton::clicked, this, &GraphicsSurfaceWidget::SaveSurface); | 216 | connect(save_surface, &QPushButton::clicked, this, &GraphicsSurfaceWidget::SaveSurface); |
| 177 | 217 | ||
| 178 | auto main_widget = new QWidget; | 218 | auto main_widget = new QWidget; |
| @@ -420,40 +460,56 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
| 420 | } | 460 | } |
| 421 | 461 | ||
| 422 | void GraphicsSurfaceWidget::SaveSurface() { | 462 | void GraphicsSurfaceWidget::SaveSurface() { |
| 423 | QString png_filter = tr("Portable Network Graphic (*.png)"); | 463 | const QString png_filter = tr("Portable Network Graphic (*.png)"); |
| 424 | QString bin_filter = tr("Binary data (*.bin)"); | 464 | const QString bin_filter = tr("Binary data (*.bin)"); |
| 425 | 465 | ||
| 426 | QString selectedFilter; | 466 | QString selected_filter; |
| 427 | QString filename = QFileDialog::getSaveFileName( | 467 | const QString filename = QFileDialog::getSaveFileName( |
| 428 | this, tr("Save Surface"), | 468 | this, tr("Save Surface"), |
| 429 | QString("texture-0x%1.png").arg(QString::number(surface_address, 16)), | 469 | QStringLiteral("texture-0x%1.png").arg(QString::number(surface_address, 16)), |
| 430 | QString("%1;;%2").arg(png_filter, bin_filter), &selectedFilter); | 470 | QStringLiteral("%1;;%2").arg(png_filter, bin_filter), &selected_filter); |
| 431 | 471 | ||
| 432 | if (filename.isEmpty()) { | 472 | if (filename.isEmpty()) { |
| 433 | // If the user canceled the dialog, don't save anything. | 473 | // If the user canceled the dialog, don't save anything. |
| 434 | return; | 474 | return; |
| 435 | } | 475 | } |
| 436 | 476 | ||
| 437 | if (selectedFilter == png_filter) { | 477 | if (selected_filter == png_filter) { |
| 438 | const QPixmap* pixmap = surface_picture_label->pixmap(); | 478 | const QPixmap* const pixmap = surface_picture_label->pixmap(); |
| 439 | ASSERT_MSG(pixmap != nullptr, "No pixmap set"); | 479 | ASSERT_MSG(pixmap != nullptr, "No pixmap set"); |
| 440 | 480 | ||
| 441 | QFile file(filename); | 481 | QFile file{filename}; |
| 442 | file.open(QIODevice::WriteOnly); | 482 | if (!file.open(QIODevice::WriteOnly)) { |
| 443 | if (pixmap) | 483 | QMessageBox::warning(this, tr("Error"), tr("Failed to open file '%1'").arg(filename)); |
| 444 | pixmap->save(&file, "PNG"); | 484 | return; |
| 445 | } else if (selectedFilter == bin_filter) { | 485 | } |
| 486 | |||
| 487 | if (!pixmap->save(&file, "PNG")) { | ||
| 488 | QMessageBox::warning(this, tr("Error"), | ||
| 489 | tr("Failed to save surface data to file '%1'").arg(filename)); | ||
| 490 | } | ||
| 491 | } else if (selected_filter == bin_filter) { | ||
| 446 | auto& gpu = Core::System::GetInstance().GPU(); | 492 | auto& gpu = Core::System::GetInstance().GPU(); |
| 447 | std::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address); | 493 | const std::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address); |
| 448 | 494 | ||
| 449 | const u8* buffer = Memory::GetPointer(*address); | 495 | const u8* const buffer = Memory::GetPointer(*address); |
| 450 | ASSERT_MSG(buffer != nullptr, "Memory not accessible"); | 496 | ASSERT_MSG(buffer != nullptr, "Memory not accessible"); |
| 451 | 497 | ||
| 452 | QFile file(filename); | 498 | QFile file{filename}; |
| 453 | file.open(QIODevice::WriteOnly); | 499 | if (!file.open(QIODevice::WriteOnly)) { |
| 454 | int size = surface_width * surface_height * Tegra::Texture::BytesPerPixel(surface_format); | 500 | QMessageBox::warning(this, tr("Error"), tr("Failed to open file '%1'").arg(filename)); |
| 455 | QByteArray data(reinterpret_cast<const char*>(buffer), size); | 501 | return; |
| 456 | file.write(data); | 502 | } |
| 503 | |||
| 504 | const int size = | ||
| 505 | surface_width * surface_height * Tegra::Texture::BytesPerPixel(surface_format); | ||
| 506 | const QByteArray data(reinterpret_cast<const char*>(buffer), size); | ||
| 507 | if (file.write(data) != data.size()) { | ||
| 508 | QMessageBox::warning( | ||
| 509 | this, tr("Error"), | ||
| 510 | tr("Failed to completely write surface data to file. The saved data will " | ||
| 511 | "likely be corrupt.")); | ||
| 512 | } | ||
| 457 | } else { | 513 | } else { |
| 458 | UNREACHABLE_MSG("Unhandled filter selected"); | 514 | UNREACHABLE_MSG("Unhandled filter selected"); |
| 459 | } | 515 | } |