diff options
Diffstat (limited to 'src/yuzu')
| -rw-r--r-- | src/yuzu/applets/profile_select.cpp | 7 | ||||
| -rw-r--r-- | src/yuzu/applets/software_keyboard.cpp | 18 | ||||
| -rw-r--r-- | src/yuzu/applets/web_browser.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.h | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_general.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_general.ui | 20 | ||||
| -rw-r--r-- | src/yuzu/debugger/graphics/graphics_surface.cpp | 206 | ||||
| -rw-r--r-- | src/yuzu/debugger/profiler.cpp | 1 | ||||
| -rw-r--r-- | src/yuzu/debugger/profiler.h | 9 | ||||
| -rw-r--r-- | src/yuzu/game_list.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu/game_list.h | 1 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 48 | ||||
| -rw-r--r-- | src/yuzu/main.h | 1 | 
15 files changed, 201 insertions, 126 deletions
| diff --git a/src/yuzu/applets/profile_select.cpp b/src/yuzu/applets/profile_select.cpp index 5c1b65a2c..f95f7fe3c 100644 --- a/src/yuzu/applets/profile_select.cpp +++ b/src/yuzu/applets/profile_select.cpp @@ -58,10 +58,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)      scroll_area = new QScrollArea; -    buttons = new QDialogButtonBox; -    buttons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); -    buttons->addButton(tr("OK"), QDialogButtonBox::AcceptRole); - +    buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);      connect(buttons, &QDialogButtonBox::accepted, this, &QtProfileSelectionDialog::accept);      connect(buttons, &QDialogButtonBox::rejected, this, &QtProfileSelectionDialog::reject); @@ -163,6 +160,6 @@ void QtProfileSelector::SelectProfile(  void QtProfileSelector::MainWindowFinishedSelection(std::optional<Service::Account::UUID> uuid) {      // Acquire the HLE mutex -    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); +    std::lock_guard lock{HLE::g_hle_lock};      callback(uuid);  } diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp index 8a26fdff1..f3eb29b25 100644 --- a/src/yuzu/applets/software_keyboard.cpp +++ b/src/yuzu/applets/software_keyboard.cpp @@ -75,13 +75,13 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(          length_label->setText(QStringLiteral("%1/%2").arg(text.size()).arg(parameters.max_length));      }); -    buttons = new QDialogButtonBox; -    buttons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); -    buttons->addButton(parameters.submit_text.empty() -                           ? tr("OK") -                           : QString::fromStdU16String(parameters.submit_text), -                       QDialogButtonBox::AcceptRole); - +    buttons = new QDialogButtonBox(QDialogButtonBox::Cancel); +    if (parameters.submit_text.empty()) { +        buttons->addButton(QDialogButtonBox::Ok); +    } else { +        buttons->addButton(QString::fromStdU16String(parameters.submit_text), +                           QDialogButtonBox::AcceptRole); +    }      connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept);      connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject);      layout->addWidget(header_label); @@ -141,12 +141,12 @@ void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message,  void QtSoftwareKeyboard::MainWindowFinishedText(std::optional<std::u16string> text) {      // Acquire the HLE mutex -    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); +    std::lock_guard lock{HLE::g_hle_lock};      text_output(text);  }  void QtSoftwareKeyboard::MainWindowFinishedCheckDialog() {      // Acquire the HLE mutex -    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); +    std::lock_guard lock{HLE::g_hle_lock};      finished_check();  } diff --git a/src/yuzu/applets/web_browser.cpp b/src/yuzu/applets/web_browser.cpp index 979b9ec14..ac80b2fa2 100644 --- a/src/yuzu/applets/web_browser.cpp +++ b/src/yuzu/applets/web_browser.cpp @@ -104,12 +104,12 @@ void QtWebBrowser::OpenPage(std::string_view url, std::function<void()> unpack_r  void QtWebBrowser::MainWindowUnpackRomFS() {      // Acquire the HLE mutex -    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); +    std::lock_guard lock{HLE::g_hle_lock};      unpack_romfs_callback();  }  void QtWebBrowser::MainWindowFinishedBrowsing() {      // Acquire the HLE mutex -    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); +    std::lock_guard lock{HLE::g_hle_lock};      finished_callback();  } diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 05ad19e1d..7438fbc0a 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -67,7 +67,7 @@ void EmuThread::run() {              was_active = false;          } else { -            std::unique_lock<std::mutex> lock(running_mutex); +            std::unique_lock lock{running_mutex};              running_cv.wait(lock, [this] { return IsRunning() || exec_step || stop_run; });          }      } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 7226e690e..3183621bc 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -53,7 +53,7 @@ public:       * @note This function is thread-safe       */      void SetRunning(bool running) { -        std::unique_lock<std::mutex> lock(running_mutex); +        std::unique_lock lock{running_mutex};          this->running = running;          lock.unlock();          running_cv.notify_all(); diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 4650f96a3..dead9f807 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -413,7 +413,6 @@ void Config::ReadValues() {      qt_config->beginGroup("System");      Settings::values.use_docked_mode = ReadSetting("use_docked_mode", false).toBool(); -    Settings::values.enable_nfc = ReadSetting("enable_nfc", true).toBool();      Settings::values.current_user =          std::clamp<int>(ReadSetting("current_user", 0).toInt(), 0, Service::Account::MAX_USERS - 1); @@ -675,7 +674,6 @@ void Config::SaveValues() {      qt_config->beginGroup("System");      WriteSetting("use_docked_mode", Settings::values.use_docked_mode, false); -    WriteSetting("enable_nfc", Settings::values.enable_nfc, true);      WriteSetting("current_user", Settings::values.current_user, 0);      WriteSetting("language_index", Settings::values.language_index, 1); diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 4116b6cd7..389fcf667 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -33,7 +33,6 @@ void ConfigureGeneral::setConfiguration() {      ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);      ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));      ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit); -    ui->enable_nfc->setChecked(Settings::values.enable_nfc);  }  void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) { @@ -48,5 +47,4 @@ void ConfigureGeneral::applyConfiguration() {          ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();      Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked(); -    Settings::values.enable_nfc = ui->enable_nfc->isChecked();  } diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index dff0ad5d0..01d1c0b8e 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -71,26 +71,6 @@        </widget>       </item>       <item> -      <widget class="QGroupBox" name="EmulationGroupBox"> -       <property name="title"> -        <string>Emulation</string> -       </property> -       <layout class="QHBoxLayout" name="EmulationHorizontalLayout"> -        <item> -         <layout class="QVBoxLayout" name="EmulationVerticalLayout"> -          <item> -           <widget class="QCheckBox" name="enable_nfc"> -            <property name="text"> -             <string>Enable NFC</string> -            </property> -           </widget> -          </item> -         </layout> -        </item> -       </layout> -      </widget> -     </item> -     <item>        <widget class="QGroupBox" name="theme_group_box">         <property name="title">          <string>Theme</string> 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 @@  #include <QDebug>  #include <QFileDialog>  #include <QLabel> +#include <QMessageBox>  #include <QMouseEvent>  #include <QPushButton>  #include <QScrollArea> @@ -95,50 +96,91 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Tegra::DebugContext      surface_picker_y_control = new QSpinBox;      surface_picker_y_control->setRange(0, max_dimension - 1); -    surface_format_control = new QComboBox; - +    // clang-format off      // Color formats sorted by Maxwell texture format index -    surface_format_control->addItem(tr("None")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("A8R8G8B8")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("Unknown")); -    surface_format_control->addItem(tr("DXT1")); -    surface_format_control->addItem(tr("DXT23")); -    surface_format_control->addItem(tr("DXT45")); -    surface_format_control->addItem(tr("DXN1")); -    surface_format_control->addItem(tr("DXN2")); +    const QStringList surface_formats{ +        tr("None"), +        QStringLiteral("R32_G32_B32_A32"), +        QStringLiteral("R32_G32_B32"), +        QStringLiteral("R16_G16_B16_A16"), +        QStringLiteral("R32_G32"), +        QStringLiteral("R32_B24G8"), +        QStringLiteral("ETC2_RGB"), +        QStringLiteral("X8B8G8R8"), +        QStringLiteral("A8R8G8B8"), +        QStringLiteral("A2B10G10R10"), +        QStringLiteral("ETC2_RGB_PTA"), +        QStringLiteral("ETC2_RGBA"), +        QStringLiteral("R16_G16"), +        QStringLiteral("G8R24"), +        QStringLiteral("G24R8"), +        QStringLiteral("R32"), +        QStringLiteral("BC6H_SF16"), +        QStringLiteral("BC6H_UF16"), +        QStringLiteral("A4B4G4R4"), +        QStringLiteral("A5B5G5R1"), +        QStringLiteral("A1B5G5R5"), +        QStringLiteral("B5G6R5"), +        QStringLiteral("B6G5R5"), +        QStringLiteral("BC7U"), +        QStringLiteral("G8R8"), +        QStringLiteral("EAC"), +        QStringLiteral("EACX2"), +        QStringLiteral("R16"), +        QStringLiteral("Y8_VIDEO"), +        QStringLiteral("R8"), +        QStringLiteral("G4R4"), +        QStringLiteral("R1"), +        QStringLiteral("E5B9G9R9_SHAREDEXP"), +        QStringLiteral("BF10GF11RF11"), +        QStringLiteral("G8B8G8R8"), +        QStringLiteral("B8G8R8G8"), +        QStringLiteral("DXT1"), +        QStringLiteral("DXT23"), +        QStringLiteral("DXT45"), +        QStringLiteral("DXN1"), +        QStringLiteral("DXN2"), +        QStringLiteral("Z24S8"), +        QStringLiteral("X8Z24"), +        QStringLiteral("S8Z24"), +        QStringLiteral("X4V4Z24__COV4R4V"), +        QStringLiteral("X4V4Z24__COV8R8V"), +        QStringLiteral("V8Z24__COV4R12V"), +        QStringLiteral("ZF32"), +        QStringLiteral("ZF32_X24S8"), +        QStringLiteral("X8Z24_X20V4S8__COV4R4V"), +        QStringLiteral("X8Z24_X20V4S8__COV8R8V"), +        QStringLiteral("ZF32_X20V4X8__COV4R4V"), +        QStringLiteral("ZF32_X20V4X8__COV8R8V"), +        QStringLiteral("ZF32_X20V4S8__COV4R4V"), +        QStringLiteral("ZF32_X20V4S8__COV8R8V"), +        QStringLiteral("X8Z24_X16V8S8__COV4R12V"), +        QStringLiteral("ZF32_X16V8X8__COV4R12V"), +        QStringLiteral("ZF32_X16V8S8__COV4R12V"), +        QStringLiteral("Z16"), +        QStringLiteral("V8Z24__COV8R24V"), +        QStringLiteral("X8Z24_X16V8S8__COV8R24V"), +        QStringLiteral("ZF32_X16V8X8__COV8R24V"), +        QStringLiteral("ZF32_X16V8S8__COV8R24V"), +        QStringLiteral("ASTC_2D_4X4"), +        QStringLiteral("ASTC_2D_5X5"), +        QStringLiteral("ASTC_2D_6X6"), +        QStringLiteral("ASTC_2D_8X8"), +        QStringLiteral("ASTC_2D_10X10"), +        QStringLiteral("ASTC_2D_12X12"), +        QStringLiteral("ASTC_2D_5X4"), +        QStringLiteral("ASTC_2D_6X5"), +        QStringLiteral("ASTC_2D_8X6"), +        QStringLiteral("ASTC_2D_10X8"), +        QStringLiteral("ASTC_2D_12X10"), +        QStringLiteral("ASTC_2D_8X5"), +        QStringLiteral("ASTC_2D_10X5"), +        QStringLiteral("ASTC_2D_10X6"), +    }; +    // clang-format on + +    surface_format_control = new QComboBox; +    surface_format_control->addItems(surface_formats);      surface_info_label = new QLabel();      surface_info_label->setWordWrap(true); @@ -157,22 +199,20 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Tegra::DebugContext      // Connections      connect(this, &GraphicsSurfaceWidget::Update, this, &GraphicsSurfaceWidget::OnUpdate); -    connect(surface_source_list, -            static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, +    connect(surface_source_list, qOverload<int>(&QComboBox::currentIndexChanged), this,              &GraphicsSurfaceWidget::OnSurfaceSourceChanged);      connect(surface_address_control, &CSpinBox::ValueChanged, this,              &GraphicsSurfaceWidget::OnSurfaceAddressChanged); -    connect(surface_width_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), -            this, &GraphicsSurfaceWidget::OnSurfaceWidthChanged); -    connect(surface_height_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), -            this, &GraphicsSurfaceWidget::OnSurfaceHeightChanged); -    connect(surface_format_control, -            static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, +    connect(surface_width_control, qOverload<int>(&QSpinBox::valueChanged), this, +            &GraphicsSurfaceWidget::OnSurfaceWidthChanged); +    connect(surface_height_control, qOverload<int>(&QSpinBox::valueChanged), this, +            &GraphicsSurfaceWidget::OnSurfaceHeightChanged); +    connect(surface_format_control, qOverload<int>(&QComboBox::currentIndexChanged), this,              &GraphicsSurfaceWidget::OnSurfaceFormatChanged); -    connect(surface_picker_x_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), -            this, &GraphicsSurfaceWidget::OnSurfacePickerXChanged); -    connect(surface_picker_y_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), -            this, &GraphicsSurfaceWidget::OnSurfacePickerYChanged); +    connect(surface_picker_x_control, qOverload<int>(&QSpinBox::valueChanged), this, +            &GraphicsSurfaceWidget::OnSurfacePickerXChanged); +    connect(surface_picker_y_control, qOverload<int>(&QSpinBox::valueChanged), this, +            &GraphicsSurfaceWidget::OnSurfacePickerYChanged);      connect(save_surface, &QPushButton::clicked, this, &GraphicsSurfaceWidget::SaveSurface);      auto main_widget = new QWidget; @@ -420,40 +460,56 @@ void GraphicsSurfaceWidget::OnUpdate() {  }  void GraphicsSurfaceWidget::SaveSurface() { -    QString png_filter = tr("Portable Network Graphic (*.png)"); -    QString bin_filter = tr("Binary data (*.bin)"); +    const QString png_filter = tr("Portable Network Graphic (*.png)"); +    const QString bin_filter = tr("Binary data (*.bin)"); -    QString selectedFilter; -    QString filename = QFileDialog::getSaveFileName( +    QString selected_filter; +    const QString filename = QFileDialog::getSaveFileName(          this, tr("Save Surface"), -        QString("texture-0x%1.png").arg(QString::number(surface_address, 16)), -        QString("%1;;%2").arg(png_filter, bin_filter), &selectedFilter); +        QStringLiteral("texture-0x%1.png").arg(QString::number(surface_address, 16)), +        QStringLiteral("%1;;%2").arg(png_filter, bin_filter), &selected_filter);      if (filename.isEmpty()) {          // If the user canceled the dialog, don't save anything.          return;      } -    if (selectedFilter == png_filter) { -        const QPixmap* pixmap = surface_picture_label->pixmap(); +    if (selected_filter == png_filter) { +        const QPixmap* const pixmap = surface_picture_label->pixmap();          ASSERT_MSG(pixmap != nullptr, "No pixmap set"); -        QFile file(filename); -        file.open(QIODevice::WriteOnly); -        if (pixmap) -            pixmap->save(&file, "PNG"); -    } else if (selectedFilter == bin_filter) { +        QFile file{filename}; +        if (!file.open(QIODevice::WriteOnly)) { +            QMessageBox::warning(this, tr("Error"), tr("Failed to open file '%1'").arg(filename)); +            return; +        } + +        if (!pixmap->save(&file, "PNG")) { +            QMessageBox::warning(this, tr("Error"), +                                 tr("Failed to save surface data to file '%1'").arg(filename)); +        } +    } else if (selected_filter == bin_filter) {          auto& gpu = Core::System::GetInstance().GPU(); -        std::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address); +        const std::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address); -        const u8* buffer = Memory::GetPointer(*address); +        const u8* const buffer = Memory::GetPointer(*address);          ASSERT_MSG(buffer != nullptr, "Memory not accessible"); -        QFile file(filename); -        file.open(QIODevice::WriteOnly); -        int size = surface_width * surface_height * Tegra::Texture::BytesPerPixel(surface_format); -        QByteArray data(reinterpret_cast<const char*>(buffer), size); -        file.write(data); +        QFile file{filename}; +        if (!file.open(QIODevice::WriteOnly)) { +            QMessageBox::warning(this, tr("Error"), tr("Failed to open file '%1'").arg(filename)); +            return; +        } + +        const int size = +            surface_width * surface_height * Tegra::Texture::BytesPerPixel(surface_format); +        const QByteArray data(reinterpret_cast<const char*>(buffer), size); +        if (file.write(data) != data.size()) { +            QMessageBox::warning( +                this, tr("Error"), +                tr("Failed to completely write surface data to file. The saved data will " +                   "likely be corrupt.")); +        }      } else {          UNREACHABLE_MSG("Unhandled filter selected");      } diff --git a/src/yuzu/debugger/profiler.cpp b/src/yuzu/debugger/profiler.cpp index 8b30e0a85..86e03e46d 100644 --- a/src/yuzu/debugger/profiler.cpp +++ b/src/yuzu/debugger/profiler.cpp @@ -7,6 +7,7 @@  #include <QMouseEvent>  #include <QPainter>  #include <QString> +#include <QTimer>  #include "common/common_types.h"  #include "common/microprofile.h"  #include "yuzu/debugger/profiler.h" diff --git a/src/yuzu/debugger/profiler.h b/src/yuzu/debugger/profiler.h index eae1e9e3c..8e69fdb06 100644 --- a/src/yuzu/debugger/profiler.h +++ b/src/yuzu/debugger/profiler.h @@ -4,10 +4,11 @@  #pragma once -#include <QAbstractItemModel> -#include <QDockWidget> -#include <QTimer> -#include "common/microprofile.h" +#include <QWidget> + +class QAction; +class QHideEvent; +class QShowEvent;  class MicroProfileDialog : public QWidget {      Q_OBJECT diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index c0e3c5fa9..4422a572b 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -329,6 +329,8 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {      QMenu context_menu;      QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));      QAction* open_lfs_location = context_menu.addAction(tr("Open Mod Data Location")); +    QAction* open_transferable_shader_cache = +        context_menu.addAction(tr("Open Transferable Shader Cache"));      context_menu.addSeparator();      QAction* dump_romfs = context_menu.addAction(tr("Dump RomFS"));      QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); @@ -344,6 +346,8 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {              [&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData); });      connect(open_lfs_location, &QAction::triggered,              [&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::ModData); }); +    connect(open_transferable_shader_cache, &QAction::triggered, +            [&]() { emit OpenTransferableShaderCacheRequested(program_id); });      connect(dump_romfs, &QAction::triggered, [&]() { emit DumpRomFSRequested(program_id, path); });      connect(copy_tid, &QAction::triggered, [&]() { emit CopyTIDRequested(program_id); });      connect(navigate_to_gamedb_entry, &QAction::triggered, diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index b317eb2fc..8ea5cbaaa 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -66,6 +66,7 @@ signals:      void GameChosen(QString game_path);      void ShouldCancelWorker();      void OpenFolderRequested(u64 program_id, GameListOpenTarget target); +    void OpenTransferableShaderCacheRequested(u64 program_id);      void DumpRomFSRequested(u64 program_id, const std::string& game_path);      void CopyTIDRequested(u64 program_id);      void NavigateToGamedbEntryRequested(u64 program_id, diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 41ba3c4c6..2b9db69a3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -37,14 +37,20 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual  #include <glad/glad.h>  #define QT_NO_OPENGL +#include <QClipboard> +#include <QDesktopServices>  #include <QDesktopWidget>  #include <QDialogButtonBox>  #include <QFile>  #include <QFileDialog> +#include <QInputDialog>  #include <QMessageBox> +#include <QProgressBar> +#include <QProgressDialog> +#include <QShortcut> +#include <QStatusBar>  #include <QtConcurrent/QtConcurrent> -#include <QtGui> -#include <QtWidgets> +  #include <fmt/format.h>  #include "common/common_paths.h"  #include "common/detached_tasks.h" @@ -55,11 +61,9 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual  #include "common/microprofile.h"  #include "common/scm_rev.h"  #include "common/scope_exit.h" -#include "common/string_util.h"  #include "common/telemetry.h"  #include "core/core.h"  #include "core/crypto/key_manager.h" -#include "core/file_sys/bis_factory.h"  #include "core/file_sys/card_image.h"  #include "core/file_sys/content_archive.h"  #include "core/file_sys/control_metadata.h" @@ -71,7 +75,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual  #include "core/frontend/applets/software_keyboard.h"  #include "core/hle/kernel/process.h"  #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/filesystem/fsp_ldr.h"  #include "core/hle/service/nfp/nfp.h"  #include "core/hle/service/sm/sm.h"  #include "core/loader/loader.h" @@ -648,6 +651,8 @@ void GMainWindow::RestoreUIState() {  void GMainWindow::ConnectWidgetEvents() {      connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile);      connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); +    connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this, +            &GMainWindow::OnTransferableShaderCacheOpenFile);      connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS);      connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);      connect(game_list, &GameList::NavigateToGamedbEntryRequested, this, @@ -1082,6 +1087,39 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target      QDesktopServices::openUrl(QUrl::fromLocalFile(qpath));  } +void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { +    ASSERT(program_id != 0); + +    const QString tranferable_shader_cache_folder_path = +        QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)) + "opengl" + +        DIR_SEP + "transferable"; + +    const QString transferable_shader_cache_file_path = +        tranferable_shader_cache_folder_path + DIR_SEP + +        QString::fromStdString(fmt::format("{:016X}.bin", program_id)); + +    if (!QFile::exists(transferable_shader_cache_file_path)) { +        QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"), +                             tr("A shader cache for this title does not exist.")); +        return; +    } + +    // Windows supports opening a folder with selecting a specified file in explorer. On every other +    // OS we just open the transferable shader cache folder without preselecting the transferable +    // shader cache file for the selected game. +#if defined(Q_OS_WIN) +    const QString explorer = QStringLiteral("explorer"); +    QStringList param; +    if (!QFileInfo(transferable_shader_cache_file_path).isDir()) { +        param << QStringLiteral("/select,"); +    } +    param << QDir::toNativeSeparators(transferable_shader_cache_file_path); +    QProcess::startDetached(explorer, param); +#else +    QDesktopServices::openUrl(QUrl::fromLocalFile(tranferable_shader_cache_folder_path)); +#endif +} +  static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) {      std::size_t out = 0; diff --git a/src/yuzu/main.h b/src/yuzu/main.h index e07c892cf..7f3aa998e 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -176,6 +176,7 @@ private slots:      /// Called whenever a user selects a game in the game list widget.      void OnGameListLoadFile(QString game_path);      void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); +    void OnTransferableShaderCacheOpenFile(u64 program_id);      void OnGameListDumpRomFS(u64 program_id, const std::string& game_path);      void OnGameListCopyTID(u64 program_id);      void OnGameListNavigateToGamedbEntry(u64 program_id, | 
