Emu/UX: Automatic Cache Precompilation for PKG instal
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.7, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.7, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.7, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.7, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, .ci/build-mac.sh, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, .ci/build-mac-arm64.sh, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang (win64, clang, clang64) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run

This commit is contained in:
Elad 2025-11-29 09:15:23 +02:00
parent d625c1d004
commit e09be04df6
7 changed files with 97 additions and 38 deletions

View file

@ -3718,7 +3718,7 @@ extern void ppu_finalize(const ppu_module<lv2_obj>& info, bool force_mem_release
#endif
}
extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_module<lv2_obj>*>* loaded_modules)
extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_module<lv2_obj>*>* 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<std::string>& dir_queue, std::vector<ppu_
break;
}
if (is_fast_compilation)
{
// Skip overlays in fast mode
break;
}
if (!wait_for_memory())
{
// Emulation stopped
@ -4460,7 +4466,7 @@ extern void ppu_initialize()
progress_dialog.reset();
ppu_precompile(dir_queue, &module_list);
ppu_precompile(dir_queue, &module_list, false);
if (Emu.IsStopped())
{

View file

@ -75,7 +75,7 @@ atomic_t<u64> 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<std::string>& dir_queue, std::vector<ppu_module<lv2_obj>*>* loaded_prx);
extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_module<lv2_obj>*>* loaded_prx, bool is_fast_compilation);
extern bool ppu_initialize(const ppu_module<lv2_obj>&, bool check_only = false, u64 file_size = 0);
extern void ppu_finalize(const ppu_module<lv2_obj>&);
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<named_thread>("SPRX Loader"sv, [this, dir_queue]() mutable
g_fxo->init<named_thread>("SPRX Loader"sv, [this, dir_queue, is_fast = m_precompilation_option.is_fast]() mutable
{
std::vector<ppu_module<lv2_obj>*> 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);

View file

@ -120,6 +120,11 @@ namespace utils
struct serial;
};
struct emu_precompilation_option_t
{
bool is_fast = false;
};
class Emulator final
{
atomic_t<system_state> m_state{system_state::stopped};
@ -188,6 +193,7 @@ class Emulator final
};
bs_t<SaveStateExtentionFlags1> 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<std::string> argv;

View file

@ -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_info>& game_data)
void game_list_frame::BatchCreateCPUCaches(const std::vector<game_info>& game_data, bool is_fast_compilation)
{
std::set<std::string> serials;
@ -2433,11 +2437,13 @@ void game_list_frame::BatchCreateCPUCaches(const std::vector<game_info>& 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_info>& 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)
{

View file

@ -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_info>& game_data = {});
void BatchCreateCPUCaches(const std::vector<game_info>& 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 <typename KeyType>
@ -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<std::string>& path_list, const std::string& desc);

View file

@ -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_info> game_data;
std::vector<game_info> 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<std::string, QString>& bootable_paths)
{
std::vector<game_info> 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()

View file

@ -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<void()> 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<std::string, QString>& bootable_paths);
void ShowOptionalGamePreparations(const QString& title, const QString& message, std::map<std::string, QString> game_path);
static bool InstallFileInExData(const std::string& extension, const QString& path, const std::string& filename);