diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 95536540f5..0982ed79e4 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -3718,7 +3718,7 @@ extern void ppu_finalize(const ppu_module& info, bool force_mem_release #endif } -extern void ppu_precompile(std::vector& dir_queue, std::vector*>* loaded_modules) +extern void ppu_precompile(std::vector& dir_queue, std::vector*>* loaded_modules, bool is_fast_compilation) { if (g_cfg.core.ppu_decoder != ppu_decoder_type::llvm) { @@ -4166,6 +4166,12 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector g_watchdog_hold_ctr{0}; extern bool ppu_load_exec(const ppu_exec_object&, bool virtual_load, const std::string&, utils::serial* = nullptr); extern void spu_load_exec(const spu_exec_object&); extern void spu_load_rel_exec(const spu_rel_object&); -extern void ppu_precompile(std::vector& dir_queue, std::vector*>* loaded_prx); +extern void ppu_precompile(std::vector& dir_queue, std::vector*>* loaded_prx, bool is_fast_compilation); extern bool ppu_initialize(const ppu_module&, bool check_only = false, u64 file_size = 0); extern void ppu_finalize(const ppu_module&); extern void ppu_unload_prx(const lv2_prx&); @@ -1684,7 +1684,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, } } - g_fxo->init("SPRX Loader"sv, [this, dir_queue]() mutable + g_fxo->init("SPRX Loader"sv, [this, dir_queue, is_fast = m_precompilation_option.is_fast]() mutable { std::vector*> mod_list; @@ -1705,7 +1705,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, return; } - ppu_precompile(dir_queue, mod_list.empty() ? nullptr : &mod_list); + ppu_precompile(dir_queue, mod_list.empty() ? nullptr : &mod_list, is_fast); if (Emu.IsStopped()) { @@ -3230,6 +3230,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s read_used_savestate_versions(); m_savestate_extension_flags1 = {}; m_emu_state_close_pending = false; + m_precompilation_option = {}; // Enable logging rpcs3::utils::configure_logs(true); @@ -3824,6 +3825,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s read_used_savestate_versions(); m_savestate_extension_flags1 = {}; m_emu_state_close_pending = false; + m_precompilation_option = {}; initialize_timebased_time(0, true); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 0c26d09a4b..954a041e9e 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -120,6 +120,11 @@ namespace utils struct serial; }; +struct emu_precompilation_option_t +{ + bool is_fast = false; +}; + class Emulator final { atomic_t m_state{system_state::stopped}; @@ -188,6 +193,7 @@ class Emulator final }; bs_t m_savestate_extension_flags1{}; + emu_precompilation_option_t m_precompilation_option{}; public: static constexpr std::string_view game_id_boot_prefix = "%RPCS3_GAMEID%:"; @@ -245,6 +251,11 @@ public: m_state = system_state::running; } + void SetPrecompileCacheOption(emu_precompilation_option_t option) + { + m_precompilation_option = option; + } + void Init(); std::vector argv; diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index 313e043613..162b8cb0f6 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -2011,10 +2011,11 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) menu.exec(global_pos); } -bool game_list_frame::CreateCPUCaches(const std::string& path, const std::string& serial) +bool game_list_frame::CreateCPUCaches(const std::string& path, const std::string& serial, bool is_fast_compilation) { Emu.GracefulShutdown(false); Emu.SetForceBoot(true); + Emu.SetPrecompileCacheOption(emu_precompilation_option_t{.is_fast = is_fast_compilation}); if (const auto error = Emu.BootGame(fs::is_file(path) ? fs::get_parent_dir(path) : path, serial, true); error != game_boot_result::no_errors) { @@ -2026,9 +2027,9 @@ bool game_list_frame::CreateCPUCaches(const std::string& path, const std::string return true; } -bool game_list_frame::CreateCPUCaches(const game_info& game) +bool game_list_frame::CreateCPUCaches(const game_info& game, bool is_fast_compilation) { - return game && CreateCPUCaches(game->info.path, game->info.serial); + return game && CreateCPUCaches(game->info.path, game->info.serial, is_fast_compilation); } bool game_list_frame::RemoveCustomConfiguration(const std::string& title_id, const game_info& game, bool is_interactive) @@ -2404,6 +2405,9 @@ void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set connect(pdlg, &progress_dialog::canceled, this, [pdlg](){ pdlg->deleteLater(); }); QApplication::beep(); + // Signal termination back to the callback + action(""); + if (refresh_on_finish && index) { Refresh(true); @@ -2414,7 +2418,7 @@ void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set QTimer::singleShot(1, this, *periodic_func); } -void game_list_frame::BatchCreateCPUCaches(const std::vector& game_data) +void game_list_frame::BatchCreateCPUCaches(const std::vector& game_data, bool is_fast_compilation) { std::set serials; @@ -2433,11 +2437,13 @@ void game_list_frame::BatchCreateCPUCaches(const std::vector& game_da if (total == 0) { QMessageBox::information(this, tr("LLVM Cache Batch Creation"), tr("No titles found"), QMessageBox::Ok); + Q_EMIT NotifyBatchedGameActionFinished(); return; } if (!m_gui_settings->GetBootConfirmation(this)) { + Q_EMIT NotifyBatchedGameActionFinished(); return; } @@ -2459,13 +2465,19 @@ void game_list_frame::BatchCreateCPUCaches(const std::vector& game_da BatchActionBySerials(pdlg, serials, tr("%0\nProgress: %1/%2 caches compiled").arg(main_label), [&, game_data](const std::string& serial) { + if (serial.empty()) + { + Q_EMIT NotifyBatchedGameActionFinished(); + return false; + } + if (Emu.IsStopped(true)) { const auto it = std::find_if(m_game_data.begin(), m_game_data.end(), FN(x->info.serial == serial)); if (it != m_game_data.end()) { - return CreateCPUCaches((*it)->info.path, serial); + return CreateCPUCaches((*it)->info.path, serial, is_fast_compilation); } } @@ -2512,7 +2524,7 @@ void game_list_frame::BatchRemovePPUCaches() BatchActionBySerials(pdlg, serials, tr("%0/%1 caches cleared"), [this](const std::string& serial) { - return Emu.IsStopped(true) && RemovePPUCache(GetCacheDirBySerial(serial)); + return !serial.empty() &&Emu.IsStopped(true) && RemovePPUCache(GetCacheDirBySerial(serial)); }, [this](u32, u32) { @@ -2551,7 +2563,7 @@ void game_list_frame::BatchRemoveSPUCaches() BatchActionBySerials(pdlg, serials, tr("%0/%1 caches cleared"), [this](const std::string& serial) { - return Emu.IsStopped(true) && RemoveSPUCache(GetCacheDirBySerial(serial)); + return !serial.empty() && Emu.IsStopped(true) && RemoveSPUCache(GetCacheDirBySerial(serial)); }, [this](u32 removed, u32 total) { @@ -2586,7 +2598,7 @@ void game_list_frame::BatchRemoveCustomConfigurations() BatchActionBySerials(pdlg, serials, tr("%0/%1 custom configurations cleared"), [this](const std::string& serial) { - return Emu.IsStopped(true) && RemoveCustomConfiguration(serial); + return !serial.empty() && Emu.IsStopped(true) && RemoveCustomConfiguration(serial); }, [this](u32 removed, u32 total) { @@ -2620,7 +2632,7 @@ void game_list_frame::BatchRemoveCustomPadConfigurations() BatchActionBySerials(pdlg, serials, tr("%0/%1 custom pad configurations cleared"), [this](const std::string& serial) { - return Emu.IsStopped(true) && RemoveCustomPadConfiguration(serial); + return !serial.empty() && Emu.IsStopped(true) && RemoveCustomPadConfiguration(serial); }, [this](u32 removed, u32 total) { @@ -2659,7 +2671,7 @@ void game_list_frame::BatchRemoveShaderCaches() BatchActionBySerials(pdlg, serials, tr("%0/%1 shader caches cleared"), [this](const std::string& serial) { - return Emu.IsStopped(true) && RemoveShadersCache(GetCacheDirBySerial(serial)); + return !serial.empty() && Emu.IsStopped(true) && RemoveShadersCache(GetCacheDirBySerial(serial)); }, [this](u32 removed, u32 total) { diff --git a/rpcs3/rpcs3qt/game_list_frame.h b/rpcs3/rpcs3qt/game_list_frame.h index 0252cbf84f..fb366c933c 100644 --- a/rpcs3/rpcs3qt/game_list_frame.h +++ b/rpcs3/rpcs3qt/game_list_frame.h @@ -64,7 +64,7 @@ public: bool IsEntryVisible(const game_info& game, bool search_fallback = false) const; public Q_SLOTS: - void BatchCreateCPUCaches(const std::vector& game_data = {}); + void BatchCreateCPUCaches(const std::vector& game_data = {}, bool is_fast_compilation = false); void BatchRemovePPUCaches(); void BatchRemoveSPUCaches(); void BatchRemoveCustomConfigurations(); @@ -96,6 +96,7 @@ Q_SIGNALS: void FocusToSearchBar(); void Refreshed(); void RequestSaveStateManager(const game_info& game); + void NotifyBatchedGameActionFinished(); public: template @@ -135,8 +136,8 @@ private: bool RemovePPUCache(const std::string& base_dir, bool is_interactive = false); bool RemoveSPUCache(const std::string& base_dir, bool is_interactive = false); void RemoveHDD1Cache(const std::string& base_dir, const std::string& title_id, bool is_interactive = false); - static bool CreateCPUCaches(const std::string& path, const std::string& serial = {}); - static bool CreateCPUCaches(const game_info& game); + static bool CreateCPUCaches(const std::string& path, const std::string& serial = {}, bool is_fast_compilation = false); + static bool CreateCPUCaches(const game_info& game, bool is_fast_compilation = false); static bool RemoveContentPath(const std::string& path, const std::string& desc); static u32 RemoveContentPathList(const std::vector& path_list, const std::string& desc); diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 38767ceabb..34154d846d 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -1187,7 +1187,13 @@ bool main_window::HandlePackageInstallation(QStringList file_paths, bool from_bo } } - ShowOptionalGamePreparations(tr("Success!"), tr("Successfully installed software from package(s)!"), std::move(paths)); + // Executes after PrecompileCachesFromInstalledPackages + m_notify_batch_game_action_cb = [this, paths]() mutable + { + ShowOptionalGamePreparations(tr("Success!"), tr("Successfully installed software from package(s)!"), std::move(paths)); + }; + + PrecompileCachesFromInstalledPackages(paths); }); } @@ -2368,8 +2374,7 @@ void main_window::ShowOptionalGamePreparations(const QString& title, const QStri #else QCheckBox* quick_check = new QCheckBox(tr("Add launcher shortcut(s)")); #endif - QCheckBox* precompile_check = new QCheckBox(tr("Precompile caches")); - QLabel* label = new QLabel(tr("%1\nWould you like to install shortcuts to the installed software and precompile caches? (%2 new software detected)\n\n").arg(message).arg(bootable_paths.size()), dlg); + QLabel* label = new QLabel(tr("%1\nWould you like to install shortcuts to the installed software? (%2 new software detected)\n\n").arg(message).arg(bootable_paths.size()), dlg); vlayout->addWidget(label); vlayout->addStretch(10); @@ -2377,10 +2382,6 @@ void main_window::ShowOptionalGamePreparations(const QString& title, const QStri vlayout->addStretch(3); vlayout->addWidget(quick_check); vlayout->addStretch(3); - vlayout->addWidget(precompile_check); - vlayout->addStretch(3); - - precompile_check->setToolTip(tr("Spend time building data needed for game boot now instead of at launch.")); QDialogButtonBox* btn_box = new QDialogButtonBox(QDialogButtonBox::Ok); @@ -2391,7 +2392,6 @@ void main_window::ShowOptionalGamePreparations(const QString& title, const QStri { const bool create_desktop_shortcuts = desk_check->isChecked(); const bool create_app_shortcut = quick_check->isChecked(); - const bool create_caches = precompile_check->isChecked(); dlg->hide(); dlg->accept(); @@ -2411,12 +2411,11 @@ void main_window::ShowOptionalGamePreparations(const QString& title, const QStri locations.insert(gui::utils::shortcut_location::applications); } - if (locations.empty() && !create_caches) + if (locations.empty()) { return; } - std::vector game_data; std::vector game_data_shortcuts; for (const auto& [boot_path, title_id] : paths) @@ -2431,11 +2430,6 @@ void main_window::ShowOptionalGamePreparations(const QString& title, const QStri { game_data_shortcuts.push_back(gameinfo); } - - if (create_caches) - { - game_data.push_back(gameinfo); - } } break; @@ -2447,17 +2441,39 @@ void main_window::ShowOptionalGamePreparations(const QString& title, const QStri { m_game_list_frame->CreateShortcuts(game_data_shortcuts, locations); } - - if (!game_data.empty()) - { - m_game_list_frame->BatchCreateCPUCaches(game_data); - } }); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->open(); } + +void main_window::PrecompileCachesFromInstalledPackages(const std::map& bootable_paths) +{ + std::vector game_data; + + for (const auto& [boot_path, title_id] : bootable_paths) + { + for (const game_info& gameinfo : m_game_list_frame->GetGameInfo()) + { + if (gameinfo && gameinfo->info.serial == title_id.toStdString()) + { + if (Emu.IsPathInsideDir(boot_path, gameinfo->info.path)) + { + game_data.push_back(gameinfo); + } + + break; + } + } + } + + if (!game_data.empty()) + { + m_game_list_frame->BatchCreateCPUCaches(game_data, true); + } +} + void main_window::CreateActions() { ui->exitAct->setShortcuts(QKeySequence::Quit); @@ -3401,6 +3417,15 @@ void main_window::CreateConnects() connect(ui->mw_searchbar, &QLineEdit::textChanged, m_game_list_frame, &game_list_frame::SetSearchText); connect(ui->mw_searchbar, &QLineEdit::returnPressed, m_game_list_frame, &game_list_frame::FocusAndSelectFirstEntryIfNoneIs); connect(m_game_list_frame, &game_list_frame::FocusToSearchBar, this, [this]() { ui->mw_searchbar->setFocus(); }); + + connect(m_game_list_frame, &game_list_frame::NotifyBatchedGameActionFinished, this, [this]() mutable + { + if (m_notify_batch_game_action_cb) + { + m_notify_batch_game_action_cb(); + m_notify_batch_game_action_cb = {}; + } + }); } void main_window::CreateDockWindows() diff --git a/rpcs3/rpcs3qt/main_window.h b/rpcs3/rpcs3qt/main_window.h index c712d01fd3..4e5b498587 100644 --- a/rpcs3/rpcs3qt/main_window.h +++ b/rpcs3/rpcs3qt/main_window.h @@ -48,6 +48,7 @@ class main_window : public QMainWindow bool m_save_slider_pos = false; bool m_requested_show_logs_on_exit = false; int m_other_slider_pos = 0; + std::function m_notify_batch_game_action_cb; QIcon m_app_icon; QIcon m_icon_play; @@ -141,6 +142,7 @@ private: void CreateDockWindows(); void EnableMenus(bool enabled) const; void ShowTitleBars(bool show) const; + void PrecompileCachesFromInstalledPackages(const std::map& bootable_paths); void ShowOptionalGamePreparations(const QString& title, const QString& message, std::map game_path); static bool InstallFileInExData(const std::string& extension, const QString& path, const std::string& filename);