diff --git a/rpcs3/rpcs3qt/game_list_actions.cpp b/rpcs3/rpcs3qt/game_list_actions.cpp index 3e8a57d703..8e53a94df1 100644 --- a/rpcs3/rpcs3qt/game_list_actions.cpp +++ b/rpcs3/rpcs3qt/game_list_actions.cpp @@ -25,6 +25,7 @@ #include LOG_CHANNEL(game_list_log, "GameList"); +LOG_CHANNEL(sys_log, "SYS"); extern atomic_t g_system_progress_canceled; @@ -340,7 +341,7 @@ void game_list_actions::ShowRemoveGameDialog(const std::vector& games if (content_info.is_single_selection) // Single selection { - if (!RemoveContentList(games[0]->info.serial, true)) + if (!RemoveContentList(games[0]->info.serial)) { QMessageBox::critical(m_game_list_frame, tr("Failure!"), caches->isChecked() ? tr("Failed to remove %0 from drive!\nCaches and custom configs have been left intact.").arg(QString::fromStdString(games[0]->info.name)) @@ -351,7 +352,7 @@ void game_list_actions::ShowRemoveGameDialog(const std::vector& games } else // Multi selection { - BatchRemoveContentLists(games, true); + BatchRemoveContentLists(games); } } @@ -363,6 +364,41 @@ void game_list_actions::ShowGameInfoDialog(const std::vector& games) QMessageBox::information(m_game_list_frame, tr("Game Info"), GetContentInfo(games).info); } +void game_list_actions::ShowDiskUsageDialog() +{ + if (m_disk_usage_future.isRunning()) // Still running the last request + return; + + // Disk usage calculation can take a while (in particular on non ssd/m.2 disks) + // so run it on a concurrent thread avoiding to block the entire GUI + m_disk_usage_future = QtConcurrent::run([this]() + { + const std::vector> vfs_disk_usage = rpcs3::utils::get_vfs_disk_usage(); + const u64 cache_disk_usage = rpcs3::utils::get_cache_disk_usage(); + + QString text; + u64 tot_data_size = 0; + + for (const auto& [dev, data_size] : vfs_disk_usage) + { + text += tr("\n %0: %1").arg(QString::fromStdString(dev)).arg(gui::utils::format_byte_size(data_size)); + tot_data_size += data_size; + } + + if (!text.isEmpty()) + text = tr("\n VFS disk usage: %0%1").arg(gui::utils::format_byte_size(tot_data_size)).arg(text); + + text += tr("\n Cache disk usage: %0").arg(gui::utils::format_byte_size(cache_disk_usage)); + + sys_log.success("%s", text); + + Emu.CallFromMainThread([this, text]() + { + QMessageBox::information(m_game_list_frame, tr("Disk usage"), text); + }, nullptr, false); + }); +} + bool game_list_actions::IsGameRunning(const std::string& serial) { return !Emu.IsStopped(true) && (serial == Emu.GetTitleID() || (serial == "vsh.self" && Emu.IsVsh())); @@ -1063,6 +1099,128 @@ void game_list_actions::BatchCreateCPUCaches(const std::vector& games }); } +void game_list_actions::BatchRemoveCustomConfigurations(const std::vector& games, bool is_interactive) +{ + if (is_interactive && QMessageBox::question(m_game_list_frame, tr("Confirm Removal"), tr("Remove custom configuration?")) != QMessageBox::Yes) + { + return; + } + + std::set serials; + + for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games)) + { + if (game->has_custom_config && !serials.count(game->info.serial)) + { + serials.emplace(game->info.serial); + } + } + + const u32 total = ::size32(serials); + + if (total == 0) + { + QMessageBox::information(m_game_list_frame, tr("Custom Configuration Batch Removal"), tr("No files found"), QMessageBox::Ok); + return; + } + + progress_dialog* pdlg = new progress_dialog(tr("Custom Configuration Batch Removal"), tr("Removing all custom configurations"), tr("Cancel"), 0, total, false, m_game_list_frame); + pdlg->setAutoClose(false); + pdlg->setAutoReset(false); + pdlg->open(); + + BatchActionBySerials(pdlg, serials, tr("%0/%1 custom configurations cleared"), [this](const std::string& serial) + { + return !serial.empty() && Emu.IsStopped(true) && RemoveCustomConfiguration(serial); + }, + [](u32 removed, u32 total) + { + game_list_log.notice("Custom Configuration Batch Removal was canceled. %d/%d custom configurations cleared", removed, total); + }, nullptr, true); +} + +void game_list_actions::BatchRemoveCustomPadConfigurations(const std::vector& games, bool is_interactive) +{ + if (is_interactive && QMessageBox::question(m_game_list_frame, tr("Confirm Removal"), tr("Remove custom gamepad configuration?")) != QMessageBox::Yes) + { + return; + } + + std::set serials; + + for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games)) + { + if (game->has_custom_pad_config && !serials.count(game->info.serial)) + { + serials.emplace(game->info.serial); + } + } + + const u32 total = ::size32(serials); + + if (total == 0) + { + QMessageBox::information(m_game_list_frame, tr("Custom Gamepad Configuration Batch Removal"), tr("No files found"), QMessageBox::Ok); + return; + } + + progress_dialog* pdlg = new progress_dialog(tr("Custom Gamepad Configuration Batch Removal"), tr("Removing all custom gamepad configurations"), tr("Cancel"), 0, total, false, m_game_list_frame); + pdlg->setAutoClose(false); + pdlg->setAutoReset(false); + pdlg->open(); + + BatchActionBySerials(pdlg, serials, tr("%0/%1 custom gamepad configurations cleared"), [this](const std::string& serial) + { + return !serial.empty() && Emu.IsStopped(true) && RemoveCustomPadConfiguration(serial); + }, + [](u32 removed, u32 total) + { + game_list_log.notice("Custom Gamepad Configuration Batch Removal was canceled. %d/%d custom gamepad configurations cleared", removed, total); + }, nullptr, true); +} + +void game_list_actions::BatchRemoveShaderCaches(const std::vector& games, bool is_interactive) +{ + if (!ValidateBatchRemoval("shader cache", is_interactive)) + { + return; + } + + std::set serials; + + if (games.empty()) + { + serials.emplace("vsh.self"); + } + + for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games)) + { + serials.emplace(game->info.serial); + } + + const u32 total = ::size32(serials); + + if (total == 0) + { + QMessageBox::information(m_game_list_frame, tr("Shader Cache Batch Removal"), tr("No files found"), QMessageBox::Ok); + return; + } + + progress_dialog* pdlg = new progress_dialog(tr("Shader Cache Batch Removal"), tr("Removing all shader caches"), tr("Cancel"), 0, total, false, m_game_list_frame); + pdlg->setAutoClose(false); + pdlg->setAutoReset(false); + pdlg->open(); + + BatchActionBySerials(pdlg, serials, tr("%0/%1 shader caches cleared"), [this](const std::string& serial) + { + return !serial.empty() && Emu.IsStopped(true) && RemoveShaderCache(serial); + }, + [](u32 removed, u32 total) + { + game_list_log.notice("Shader Cache Batch Removal was canceled. %d/%d caches cleared", removed, total); + }, nullptr, false); +} + void game_list_actions::BatchRemovePPUCaches(const std::vector& games, bool is_interactive) { if (!ValidateBatchRemoval("PPU cache", is_interactive)) @@ -1288,131 +1446,6 @@ void game_list_actions::BatchRemoveContentLists(const std::vector& ga }, false); } -void game_list_actions::BatchRemoveCustomConfigurations(const std::vector& games, bool is_interactive) -{ - if (is_interactive && QMessageBox::question(m_game_list_frame, tr("Confirm Removal"), tr("Remove custom configuration?")) != QMessageBox::Yes) - { - return; - } - - std::set serials; - - for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games)) - { - if (game->has_custom_config && !serials.count(game->info.serial)) - { - serials.emplace(game->info.serial); - } - } - - const u32 total = ::size32(serials); - - if (total == 0) - { - QMessageBox::information(m_game_list_frame, tr("Custom Configuration Batch Removal"), tr("No files found"), QMessageBox::Ok); - return; - } - - progress_dialog* pdlg = new progress_dialog(tr("Custom Configuration Batch Removal"), tr("Removing all custom configurations"), tr("Cancel"), 0, total, false, m_game_list_frame); - pdlg->setAutoClose(false); - pdlg->setAutoReset(false); - pdlg->open(); - - BatchActionBySerials(pdlg, serials, tr("%0/%1 custom configurations cleared"), - [this](const std::string& serial) - { - return !serial.empty() && Emu.IsStopped(true) && RemoveCustomConfiguration(serial); - }, - [](u32 removed, u32 total) - { - game_list_log.notice("Custom Configuration Batch Removal was canceled. %d/%d custom configurations cleared", removed, total); - }, nullptr, true); -} - -void game_list_actions::BatchRemoveCustomPadConfigurations(const std::vector& games, bool is_interactive) -{ - if (is_interactive && QMessageBox::question(m_game_list_frame, tr("Confirm Removal"), tr("Remove custom gamepad configuration?")) != QMessageBox::Yes) - { - return; - } - - std::set serials; - - for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games)) - { - if (game->has_custom_pad_config && !serials.count(game->info.serial)) - { - serials.emplace(game->info.serial); - } - } - - const u32 total = ::size32(serials); - - if (total == 0) - { - QMessageBox::information(m_game_list_frame, tr("Custom Gamepad Configuration Batch Removal"), tr("No files found"), QMessageBox::Ok); - return; - } - - progress_dialog* pdlg = new progress_dialog(tr("Custom Gamepad Configuration Batch Removal"), tr("Removing all custom gamepad configurations"), tr("Cancel"), 0, total, false, m_game_list_frame); - pdlg->setAutoClose(false); - pdlg->setAutoReset(false); - pdlg->open(); - - BatchActionBySerials(pdlg, serials, tr("%0/%1 custom gamepad configurations cleared"), - [this](const std::string& serial) - { - return !serial.empty() && Emu.IsStopped(true) && RemoveCustomPadConfiguration(serial); - }, - [](u32 removed, u32 total) - { - game_list_log.notice("Custom Gamepad Configuration Batch Removal was canceled. %d/%d custom gamepad configurations cleared", removed, total); - }, nullptr, true); -} - -void game_list_actions::BatchRemoveShaderCaches(const std::vector& games, bool is_interactive) -{ - if (!ValidateBatchRemoval("shader cache", is_interactive)) - { - return; - } - - std::set serials; - - if (games.empty()) - { - serials.emplace("vsh.self"); - } - - for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games)) - { - serials.emplace(game->info.serial); - } - - const u32 total = ::size32(serials); - - if (total == 0) - { - QMessageBox::information(m_game_list_frame, tr("Shader Cache Batch Removal"), tr("No files found"), QMessageBox::Ok); - return; - } - - progress_dialog* pdlg = new progress_dialog(tr("Shader Cache Batch Removal"), tr("Removing all shader caches"), tr("Cancel"), 0, total, false, m_game_list_frame); - pdlg->setAutoClose(false); - pdlg->setAutoReset(false); - pdlg->open(); - - BatchActionBySerials(pdlg, serials, tr("%0/%1 shader caches cleared"), - [this](const std::string& serial) - { - return !serial.empty() && Emu.IsStopped(true) && RemoveShaderCache(serial); - }, - [](u32 removed, u32 total) - { - game_list_log.notice("Shader Cache Batch Removal was canceled. %d/%d caches cleared", removed, total); - }, nullptr, false); -} - void game_list_actions::CreateShortcuts(const std::vector& games, const std::set& locations) { if (games.empty()) diff --git a/rpcs3/rpcs3qt/game_list_actions.h b/rpcs3/rpcs3qt/game_list_actions.h index 7c5f603337..ccb97ff89a 100644 --- a/rpcs3/rpcs3qt/game_list_actions.h +++ b/rpcs3/rpcs3qt/game_list_actions.h @@ -3,6 +3,7 @@ #include "gui_game_info.h" #include "shortcut_utils.h" +#include #include class progress_dialog; @@ -53,15 +54,7 @@ public: void ShowRemoveGameDialog(const std::vector& games); void ShowGameInfoDialog(const std::vector& games); - - void BatchCreateCPUCaches(const std::vector& games = {}, bool is_fast_compilation = false, bool is_interactive = false); - void BatchRemoveCustomConfigurations(const std::vector& games = {}, bool is_interactive = false); - void BatchRemoveCustomPadConfigurations(const std::vector& games = {}, bool is_interactive = false); - void BatchRemoveShaderCaches(const std::vector& games = {}, bool is_interactive = false); - void BatchRemovePPUCaches(const std::vector& games = {}, bool is_interactive = false); - void BatchRemoveSPUCaches(const std::vector& games = {}, bool is_interactive = false); - void BatchRemoveHDD1Caches(const std::vector& games = {}, bool is_interactive = false); - void BatchRemoveAllCaches(const std::vector& games = {}, bool is_interactive = false); + void ShowDiskUsageDialog(); // NOTES: // - SetContentList() MUST always be called to set the content's info to be removed by: @@ -69,8 +62,6 @@ public: // - BatchRemoveContentLists() // void SetContentList(u16 content_types, const content_info& content_info); - void BatchRemoveContentLists(const std::vector& games = {}, bool is_interactive = false); - void ClearContentList(bool refresh = false); content_info GetContentInfo(const std::vector& games); @@ -88,6 +79,16 @@ public: bool RemoveAllCaches(const std::string& serial, bool is_interactive = false); bool RemoveContentList(const std::string& serial, bool is_interactive = false); + void BatchCreateCPUCaches(const std::vector& games = {}, bool is_fast_compilation = false, bool is_interactive = false); + void BatchRemoveCustomConfigurations(const std::vector& games = {}, bool is_interactive = false); + void BatchRemoveCustomPadConfigurations(const std::vector& games = {}, bool is_interactive = false); + void BatchRemoveShaderCaches(const std::vector& games = {}, bool is_interactive = false); + void BatchRemovePPUCaches(const std::vector& games = {}, bool is_interactive = false); + void BatchRemoveSPUCaches(const std::vector& games = {}, bool is_interactive = false); + void BatchRemoveHDD1Caches(const std::vector& games = {}, bool is_interactive = false); + void BatchRemoveAllCaches(const std::vector& games = {}, bool is_interactive = false); + void BatchRemoveContentLists(const std::vector& games = {}, bool is_interactive = false); + static bool RemoveContentPath(const std::string& path, const std::string& desc); static u32 RemoveContentPathList(const std::set& path_list, const std::string& desc); static bool RemoveContentBySerial(const std::string& base_dir, const std::string& serial, const std::string& desc); @@ -95,6 +96,7 @@ public: private: game_list_frame* m_game_list_frame = nullptr; std::shared_ptr m_gui_settings; + QFuture m_disk_usage_future; // NOTE: // m_content_info is used by: diff --git a/rpcs3/rpcs3qt/game_list_context_menu.cpp b/rpcs3/rpcs3qt/game_list_context_menu.cpp index bb15bc80ec..720aac8596 100644 --- a/rpcs3/rpcs3qt/game_list_context_menu.cpp +++ b/rpcs3/rpcs3qt/game_list_context_menu.cpp @@ -303,13 +303,6 @@ void game_list_context_menu::show_single_selection_context_menu(const game_info& QAction* remove_game = manage_game_menu->addAction(tr("&Remove %1").arg(gameinfo->localized_category)); remove_game->setEnabled(!is_current_running_game); - // Game info - QAction* game_info = manage_game_menu->addAction(tr("&Game Info")); - connect(game_info, &QAction::triggered, this, [this, gameinfo]() - { - m_game_list_actions->ShowGameInfoDialog({gameinfo}); - }); - // Custom Images menu QMenu* icon_menu = addMenu(tr("&Custom Images")); const std::array custom_icon_actions = @@ -457,8 +450,6 @@ void game_list_context_menu::show_single_selection_context_menu(const game_info& icon_menu->setEnabled(false); } - addSeparator(); - // Open Folder menu QMenu* open_folder_menu = addMenu(tr("&Open Folder")); @@ -575,6 +566,22 @@ void game_list_context_menu::show_single_selection_context_menu(const game_info& QAction* check_compat = addAction(tr("&Check Game Compatibility")); QAction* download_compat = addAction(tr("&Download Compatibility Database")); + addSeparator(); + + // Disk usage + QAction* disk_usage = addAction(tr("&Disk Usage")); + connect(disk_usage, &QAction::triggered, this, [this]() + { + m_game_list_actions->ShowDiskUsageDialog(); + }); + + // Game info + QAction* game_info = addAction(tr("&Game Info")); + connect(game_info, &QAction::triggered, this, [this, gameinfo]() + { + m_game_list_actions->ShowGameInfoDialog({gameinfo}); + }); + connect(boot, &QAction::triggered, m_game_list_frame, [this, gameinfo]() { sys_log.notice("Booting from gamelist per context menu..."); @@ -896,8 +903,25 @@ void game_list_context_menu::show_multi_selection_context_menu(const std::vector m_game_list_actions->ShowRemoveGameDialog(games); }); + addSeparator(); + + QAction* download_compat = addAction(tr("&Download Compatibility Database")); + connect(download_compat, &QAction::triggered, m_game_list_frame, [this] + { + ensure(m_game_list_frame->GetGameCompatibility())->RequestCompatibility(true); + }); + + addSeparator(); + + // Disk usage + QAction* disk_usage = addAction(tr("&Disk Usage")); + connect(disk_usage, &QAction::triggered, this, [this]() + { + m_game_list_actions->ShowDiskUsageDialog(); + }); + // Game info - QAction* game_info = manage_game_menu->addAction(tr("&Game Info")); + QAction* game_info = addAction(tr("&Game Info")); connect(game_info, &QAction::triggered, this, [this, games]() { m_game_list_actions->ShowGameInfoDialog(games); diff --git a/rpcs3/rpcs3qt/log_frame.cpp b/rpcs3/rpcs3qt/log_frame.cpp index 1d2739608d..bbc6fe6145 100644 --- a/rpcs3/rpcs3qt/log_frame.cpp +++ b/rpcs3/rpcs3qt/log_frame.cpp @@ -4,14 +4,10 @@ #include "hex_validator.h" #include "memory_viewer_panel.h" -#include "Emu/System.h" -#include "Emu/system_utils.hpp" #include "Utilities/lockless.h" #include "util/asm.hpp" -#include #include -#include #include #include #include @@ -21,8 +17,6 @@ #include #include -LOG_CHANNEL(sys_log, "SYS"); - extern fs::file g_tty; extern atomic_t g_tty_size; extern std::array, 16> g_tty_input; @@ -171,28 +165,6 @@ log_frame::log_frame(std::shared_ptr _gui_settings, QWidget* paren connect(m_timer, &QTimer::timeout, this, &log_frame::UpdateUI); } -void log_frame::show_disk_usage(const std::vector>& vfs_disk_usage, u64 cache_disk_usage) -{ - QString text; - u64 tot_data_size = 0; - - for (const auto& [dev, data_size] : vfs_disk_usage) - { - text += tr("\n %0: %1").arg(QString::fromStdString(dev)).arg(gui::utils::format_byte_size(data_size)); - tot_data_size += data_size; - } - - if (!text.isEmpty()) - { - text = tr("\n VFS disk usage: %0%1").arg(gui::utils::format_byte_size(tot_data_size)).arg(text); - } - - text += tr("\n Cache disk usage: %0").arg(gui::utils::format_byte_size(cache_disk_usage)); - - sys_log.success("%s", text); - QMessageBox::information(this, tr("Disk usage"), text); -} - void log_frame::SetLogLevel(logs::level lev) const { switch (lev) @@ -273,26 +245,6 @@ void log_frame::CreateAndConnectActions() m_tty->clear(); }); - m_show_disk_usage_act = new QAction(tr("Show Disk Usage"), this); - connect(m_show_disk_usage_act, &QAction::triggered, [this]() - { - if (m_disk_usage_future.isRunning()) - { - return; // Still running the last request - } - - m_disk_usage_future = QtConcurrent::run([this]() - { - const std::vector> vfs_disk_usage = rpcs3::utils::get_vfs_disk_usage(); - const u64 cache_disk_usage = rpcs3::utils::get_cache_disk_usage(); - - Emu.CallFromMainThread([this, vfs_disk_usage, cache_disk_usage]() - { - show_disk_usage(vfs_disk_usage, cache_disk_usage); - }, nullptr, false); - }); - }); - m_perform_goto_on_debugger = new QAction(tr("Go-To on Debugger"), this); connect(m_perform_goto_on_debugger, &QAction::triggered, [this]() { @@ -418,8 +370,6 @@ void log_frame::CreateAndConnectActions() QMenu* menu = m_log->createStandardContextMenu(); menu->addAction(m_clear_act); menu->addSeparator(); - menu->addAction(m_show_disk_usage_act); - menu->addSeparator(); menu->addAction(m_perform_goto_on_debugger); menu->addAction(m_perform_goto_thread_on_debugger); menu->addAction(m_perform_show_in_mem_viewer); diff --git a/rpcs3/rpcs3qt/log_frame.h b/rpcs3/rpcs3qt/log_frame.h index 159fdd38aa..0de081863c 100644 --- a/rpcs3/rpcs3qt/log_frame.h +++ b/rpcs3/rpcs3qt/log_frame.h @@ -8,7 +8,6 @@ #include -#include #include #include #include @@ -39,7 +38,6 @@ protected: private Q_SLOTS: void UpdateUI(); private: - void show_disk_usage(const std::vector>& vfs_disk_usage, u64 cache_disk_usage); void SetLogLevel(logs::level lev) const; void SetTTYLogging(bool val) const; @@ -50,7 +48,6 @@ private: std::unique_ptr m_find_dialog; QTimer* m_timer = nullptr; - QFuture m_disk_usage_future; std::vector m_color; QColor m_color_stack; @@ -75,7 +72,6 @@ private: QAction* m_clear_act = nullptr; QAction* m_clear_tty_act = nullptr; - QAction* m_show_disk_usage_act = nullptr; QAction* m_perform_goto_on_debugger = nullptr; QAction* m_perform_goto_thread_on_debugger = nullptr; QAction* m_perform_show_in_mem_viewer = nullptr;