diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 1997a13b14..d921603c1f 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -6,6 +6,7 @@ #include "Crypto/unself.h" #include "Loader/ELF.h" #include "Loader/mself.hpp" +#include "Emu/localized_string.h" #include "Emu/perf_meter.hpp" #include "Emu/Memory/vm_reservation.h" #include "Emu/Memory/vm_locking.h" @@ -3862,7 +3863,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector progr(std::in_place, "Scanning PPU Executable..."); + std::optional progress_dialog(std::in_place, get_localized_string(localized_string_id::PROGRESS_DIALOG_SCANNING_PPU_EXECUTABLE)); // Make sure we only have one '/' at the end and remove duplicates. for (std::string& dir : dir_queue) @@ -4063,7 +4064,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector fnext = 0; @@ -4380,7 +4381,7 @@ extern void ppu_initialize() auto& _main = g_fxo->get(); - std::optional progr(std::in_place, "Analyzing PPU Executable..."); + std::optional progress_dialog(std::in_place, get_localized_string(localized_string_id::PROGRESS_DIALOG_ANALYZING_PPU_EXECUTABLE)); // Analyse executable if (!_main.analyse(0, _main.elf_entry, _main.seg0_code_end, _main.applied_patches, std::vector{}, [](){ return Emu.IsStopped(); })) @@ -4391,7 +4392,7 @@ extern void ppu_initialize() // Validate analyser results (not required) _main.validate(0); - *progr = "Scanning PPU Modules..."; + *progress_dialog = get_localized_string(localized_string_id::PROGRESS_DIALOG_SCANNING_PPU_MODULES); bool compile_main = false; @@ -4479,7 +4480,7 @@ extern void ppu_initialize() dir_queue.insert(std::end(dir_queue), std::begin(dirs), std::end(dirs)); } - progr.reset(); + progress_dialog.reset(); ppu_precompile(dir_queue, &module_list); @@ -4612,12 +4613,12 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size) } #ifdef LLVM_AVAILABLE - std::optional progr; + std::optional progress_dialog; if (!check_only) { // Initialize progress dialog - progr.emplace("Loading PPU Modules..."); + progress_dialog.emplace(get_localized_string(localized_string_id::PROGRESS_DIALOG_LOADING_PPU_MODULES)); } // Permanently loaded compiled PPU modules (name -> data) @@ -4983,7 +4984,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size) // Create worker threads for compilation if (!workload.empty()) { - *progr = "Compiling PPU Modules..."; + *progress_dialog = get_localized_string(localized_string_id::PROGRESS_DIALOG_COMPILING_PPU_MODULES); u32 thread_count = rpcs3::utils::get_max_threads(); @@ -5096,7 +5097,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size) if (workload.size() < link_workload.size()) { // Only show this message if this task is relevant - *progr = "Linking PPU Modules..."; + *progress_dialog = get_localized_string(localized_string_id::PROGRESS_DIALOG_LINKING_PPU_MODULES); } for (const auto& [obj_name, is_compiled] : link_workload) @@ -5142,9 +5143,9 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size) // Try to patch all single and unregistered BLRs with the same function (TODO: Maybe generalize it into PIC code detection and patching) ppu_intrp_func_t BLR_func = nullptr; - const bool showing_only_apply_stage = !g_progr.load() && !g_progr_ptotal && !g_progr_ftotal && g_progr_ptotal.compare_and_swap_test(0, 1); + const bool showing_only_apply_stage = !g_progr_text.load() && !g_progr_ptotal && !g_progr_ftotal && g_progr_ptotal.compare_and_swap_test(0, 1); - progr = "Applying PPU Code..."; + progress_dialog = get_localized_string(localized_string_id::PROGRESS_DIALOG_APPLYING_PPU_CODE); if (!jit) { diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index 105b794862..e987d701df 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -7,6 +7,7 @@ #include "Emu/system_utils.hpp" #include "Emu/cache_utils.hpp" #include "Emu/IdManager.h" +#include "Emu/localized_string.h" #include "Crypto/sha1.h" #include "Utilities/StrUtil.h" #include "Utilities/JIT.h" @@ -804,7 +805,7 @@ void spu_cache::initialize(bool build_existing_cache) u32 worker_count = 0; - std::optional progr; + std::optional progress_dialog; u32 total_funcs = 0; @@ -827,7 +828,7 @@ void spu_cache::initialize(bool build_existing_cache) { g_progr_ptotal += total_funcs; showing_progress.release(true); - progr.emplace("Building SPU cache..."); + progress_dialog.emplace(get_localized_string(localized_string_id::PROGRESS_DIALOG_BUILDING_SPU_CACHE)); } named_thread_group workers("SPU Worker ", worker_count, [&]() -> uint @@ -937,12 +938,12 @@ void spu_cache::initialize(bool build_existing_cache) if (is_first_thread && !showing_progress) { - if (!g_progr.load() && !g_progr_ptotal && !g_progr_ftotal) + if (!g_progr_text.load() && !g_progr_ptotal && !g_progr_ftotal) { showing_progress = true; g_progr_pdone += pending_progress.exchange(0); g_progr_ptotal += total_funcs; - progr.emplace("Building SPU cache..."); + progress_dialog.emplace(get_localized_string(localized_string_id::PROGRESS_DIALOG_BUILDING_SPU_CACHE)); } } else if (showing_progress && pending_progress) @@ -1114,12 +1115,13 @@ void spu_cache::initialize(bool build_existing_cache) if (is_first_thread && !showing_progress) { - if (!g_progr.load() && !g_progr_ptotal && !g_progr_ftotal) + if (!g_progr_text.load() && !g_progr_ptotal && !g_progr_ftotal) { showing_progress = true; g_progr_pdone += pending_progress.exchange(0); g_progr_ptotal += total_funcs; - progr.emplace("Building SPU cache..."); + + progress_dialog.emplace(get_localized_string(localized_string_id::PROGRESS_DIALOG_BUILDING_SPU_CACHE)); } } else if (showing_progress && pending_progress) diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 685897960f..c5db0d8891 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -3111,7 +3111,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s { // Show visual feedback to the user in case that stopping takes a while. // This needs to be done before actually stopping, because otherwise the necessary threads will be terminated before we can show an image. - if (auto progress_dialog = g_fxo->try_get>(); progress_dialog && g_progr.load()) + if (auto progress_dialog = g_fxo->try_get>(); progress_dialog && g_progr_text.load()) { // We are currently showing a progress dialog. Notify it that we are going to stop emulation. g_system_progress_stopping = true; diff --git a/rpcs3/Emu/localized_string_id.h b/rpcs3/Emu/localized_string_id.h index 1a0f03c32c..70f1f0c700 100644 --- a/rpcs3/Emu/localized_string_id.h +++ b/rpcs3/Emu/localized_string_id.h @@ -269,6 +269,24 @@ enum class localized_string_id HOME_MENU_RELOAD_SAVESTATE, HOME_MENU_RECORDING, + PROGRESS_DIALOG_PROGRESS, + PROGRESS_DIALOG_PROGRESS_ANALYZING, + PROGRESS_DIALOG_REMAINING, + PROGRESS_DIALOG_DONE, + PROGRESS_DIALOG_FILE, + PROGRESS_DIALOG_MODULE, + PROGRESS_DIALOG_OF, + PROGRESS_DIALOG_PLEASE_WAIT, + PROGRESS_DIALOG_STOPPING_PLEASE_WAIT, + PROGRESS_DIALOG_SCANNING_PPU_EXECUTABLE, + PROGRESS_DIALOG_ANALYZING_PPU_EXECUTABLE, + PROGRESS_DIALOG_SCANNING_PPU_MODULES, + PROGRESS_DIALOG_LOADING_PPU_MODULES, + PROGRESS_DIALOG_COMPILING_PPU_MODULES, + PROGRESS_DIALOG_LINKING_PPU_MODULES, + PROGRESS_DIALOG_APPLYING_PPU_CODE, + PROGRESS_DIALOG_BUILDING_SPU_CACHE, + EMULATION_PAUSED_RESUME_WITH_START, EMULATION_RESUMING, EMULATION_FROZEN, diff --git a/rpcs3/Emu/system_progress.cpp b/rpcs3/Emu/system_progress.cpp index 3d6f1bb4b1..834b2c182a 100644 --- a/rpcs3/Emu/system_progress.cpp +++ b/rpcs3/Emu/system_progress.cpp @@ -13,7 +13,7 @@ LOG_CHANNEL(sys_log, "SYS"); // Progress display server synchronization variables -atomic_t g_progr{}; +atomic_t g_progr_text{}; atomic_t g_progr_ftotal{0}; atomic_t g_progr_fdone{0}; atomic_t g_progr_ftotal_bits{0}; @@ -43,11 +43,11 @@ void progress_dialog_server::operator()() const auto get_state = []() { - auto whole_state = std::make_tuple(+g_progr.load(), +g_progr_ftotal, +g_progr_fdone, +g_progr_ftotal_bits, +g_progr_fknown_bits, +g_progr_ptotal, +g_progr_pdone); + auto whole_state = std::make_tuple(+g_progr_text.load(), +g_progr_ftotal, +g_progr_fdone, +g_progr_ftotal_bits, +g_progr_fknown_bits, +g_progr_ptotal, +g_progr_pdone); while (true) { - auto new_state = std::make_tuple(+g_progr.load(), +g_progr_ftotal, +g_progr_fdone, +g_progr_ftotal_bits, +g_progr_fknown_bits, +g_progr_ptotal, +g_progr_pdone); + auto new_state = std::make_tuple(+g_progr_text.load(), +g_progr_ftotal, +g_progr_fdone, +g_progr_ftotal_bits, +g_progr_fknown_bits, +g_progr_ptotal, +g_progr_pdone); if (new_state == whole_state) { @@ -64,7 +64,7 @@ void progress_dialog_server::operator()() while (!g_system_progress_stopping && thread_ctrl::state() != thread_state::aborting) { // Wait for the start condition - const char* text0 = g_progr.load(); + const char* text0 = g_progr_text.load(); while (!text0) { @@ -97,7 +97,7 @@ void progress_dialog_server::operator()() } thread_ctrl::wait_for(5000); - text0 = g_progr.load(); + text0 = g_progr_text.load(); } if (g_system_progress_stopping || thread_ctrl::state() == thread_state::aborting) @@ -131,7 +131,7 @@ void progress_dialog_server::operator()() native_dlg = manager->create(true); native_dlg->show(false, text0, type, msg_dialog_source::sys_progress, nullptr); - native_dlg->progress_bar_set_message(0, "Please wait"); + native_dlg->progress_bar_set_message(0, get_localized_string(localized_string_id::PROGRESS_DIALOG_PLEASE_WAIT)); } } @@ -250,14 +250,16 @@ void progress_dialog_server::operator()() const u64 done = pdone; const u32 value = static_cast(done >= total ? 100 : done * 100 / total); - std::string progr = "Progress:"; + std::string progr; if (ftotal || ptotal) { + progr = get_localized_string(localized_string_id::PROGRESS_DIALOG_PROGRESS); + if (ftotal) - fmt::append(progr, " file %u of %u%s", fdone, ftotal, ptotal ? "," : ""); + fmt::append(progr, " %s %u %s %u%s", get_localized_string(localized_string_id::PROGRESS_DIALOG_FILE), fdone, get_localized_string(localized_string_id::PROGRESS_DIALOG_OF), ftotal, ptotal ? "," : ""); if (ptotal) - fmt::append(progr, " module %u of %u", pdone, ptotal); + fmt::append(progr, " %s %u %s %u", get_localized_string(localized_string_id::PROGRESS_DIALOG_MODULE), pdone, get_localized_string(localized_string_id::PROGRESS_DIALOG_OF), ptotal); const u32 of_1000 = static_cast(done >= total ? 1000 : done * 1000 / total); @@ -303,29 +305,29 @@ void progress_dialog_server::operator()() } else if (done >= total) { - fmt::append(progr, " (done)", minutes, seconds); + fmt::append(progr, " (%s)", get_localized_string(localized_string_id::PROGRESS_DIALOG_DONE)); } else if (hours) { - fmt::append(progr, " (%uh %2um remaining)", hours, minutes); + fmt::append(progr, " (%uh %2um %s)", hours, minutes, get_localized_string(localized_string_id::PROGRESS_DIALOG_REMAINING)); } else if (minutes >= 2) { - fmt::append(progr, " (%um remaining)", minutes); + fmt::append(progr, " (%um %s)", minutes, get_localized_string(localized_string_id::PROGRESS_DIALOG_REMAINING)); } else if (minutes == 0) { - fmt::append(progr, " (%us remaining)", std::max(seconds, 1)); + fmt::append(progr, " (%us %s)", std::max(seconds, 1), get_localized_string(localized_string_id::PROGRESS_DIALOG_REMAINING)); } else { - fmt::append(progr, " (%um %2us remaining)", minutes, seconds); + fmt::append(progr, " (%um %2us %s)", minutes, seconds, get_localized_string(localized_string_id::PROGRESS_DIALOG_REMAINING)); } } } else { - fmt::append(progr, " analyzing..."); + progr = get_localized_string(localized_string_id::PROGRESS_DIALOG_PROGRESS_ANALYZING); } // Changes detected, send update @@ -409,7 +411,7 @@ void progress_dialog_server::operator()() if (native_dlg && g_system_progress_stopping) { - native_dlg->set_text("Stopping. Please wait..."); + native_dlg->set_text(get_localized_string(localized_string_id::PROGRESS_DIALOG_STOPPING_PLEASE_WAIT)); native_dlg->refresh(); } @@ -427,5 +429,5 @@ progress_dialog_server::~progress_dialog_server() g_progr_fknown_bits.release(0); g_progr_ptotal.release(0); g_progr_pdone.release(0); - g_progr.release(progress_dialog_string_t{}); + g_progr_text.release(progress_dialog_string_t{}); } diff --git a/rpcs3/Emu/system_progress.hpp b/rpcs3/Emu/system_progress.hpp index 9dd242ca95..59dad4898f 100644 --- a/rpcs3/Emu/system_progress.hpp +++ b/rpcs3/Emu/system_progress.hpp @@ -15,7 +15,7 @@ struct alignas(16) progress_dialog_string_t } }; -extern atomic_t g_progr; +extern atomic_t g_progr_text; extern atomic_t g_progr_ftotal; extern atomic_t g_progr_fdone; extern atomic_t g_progr_ftotal_bits; @@ -28,23 +28,27 @@ extern atomic_t g_system_progress_stopping; // Initialize progress dialog (can be recursive) class scoped_progress_dialog final { - // Saved previous value - const char* m_prev; +private: + std::string m_text; // Saved current value + std::string m_prev; // Saved previous value u32 m_prev_id; u32 m_id; public: - scoped_progress_dialog(const char* text) noexcept + scoped_progress_dialog(const std::string& text) noexcept { - std::tie(m_prev, m_prev_id, m_id) = g_progr.atomic_op([text = ensure(text)](progress_dialog_string_t& progr) + ensure(!text.empty()); + m_text = text; + + std::tie(m_prev, m_prev_id, m_id) = g_progr_text.atomic_op([this](progress_dialog_string_t& progr) { - const char* old = progr.m_text; + std::string old = progr.m_text ? progr.m_text : std::string(); progr.m_user_count++; progr.m_update_id++; - progr.m_text = text; + progr.m_text = m_text.c_str(); - ensure(progr.m_user_count > 1 || !old); // Ensure it was nullptr before first use - return std::make_tuple(old, progr.m_update_id - 1, progr.m_update_id); + ensure(progr.m_user_count > 1 || old.empty()); // Ensure it was empty before first use + return std::make_tuple(std::move(old), progr.m_update_id - 1, progr.m_update_id); }); } @@ -52,23 +56,26 @@ public: scoped_progress_dialog& operator=(const scoped_progress_dialog&) = delete; - scoped_progress_dialog& operator=(const char* text) noexcept + scoped_progress_dialog& operator=(const std::string& text) noexcept { + ensure(!text.empty()); + m_text = text; + // This method is destroying the previous value and replacing it with a new one - std::tie(m_prev, m_prev_id, m_id) = g_progr.atomic_op([this, text = ensure(text)](progress_dialog_string_t& progr) + std::tie(m_prev, m_prev_id, m_id) = g_progr_text.atomic_op([this](progress_dialog_string_t& progr) { if (m_id == progr.m_update_id) { progr.m_update_id = m_prev_id; - progr.m_text = m_prev; + progr.m_text = m_prev.c_str(); } - const char* old = progr.m_text; - progr.m_text = text; + std::string old = progr.m_text ? progr.m_text : std::string(); + progr.m_text = m_text.c_str(); progr.m_update_id++; ensure(progr.m_user_count > 0); - return std::make_tuple(old, progr.m_update_id - 1, progr.m_update_id); + return std::make_tuple(std::move(old), progr.m_update_id - 1, progr.m_update_id); }); return *this; @@ -76,7 +83,7 @@ public: ~scoped_progress_dialog() noexcept { - g_progr.atomic_op([this](progress_dialog_string_t& progr) + g_progr_text.atomic_op([this](progress_dialog_string_t& progr) { if (progr.m_user_count-- == 1) { @@ -87,7 +94,7 @@ public: else if (m_id == progr.m_update_id) { // Restore text only if no other updates were made by other threads - progr.m_text = ensure(m_prev); + progr.m_text = m_prev.c_str(); progr.m_update_id = m_prev_id; } }); diff --git a/rpcs3/rpcs3qt/gs_frame.cpp b/rpcs3/rpcs3qt/gs_frame.cpp index b86fd5f457..ede79d50f3 100644 --- a/rpcs3/rpcs3qt/gs_frame.cpp +++ b/rpcs3/rpcs3qt/gs_frame.cpp @@ -568,7 +568,7 @@ void gs_frame::hide_on_close() m_gui_settings->SetValue(gui::gs_visibility, current_visibility == Visibility::Hidden ? Visibility::AutomaticVisibility : current_visibility, false); m_gui_settings->SetValue(gui::gs_geometry, geometry(), true); - if (!g_progr.load()) + if (!g_progr_text.load()) { // Hide the dialog before stopping if no progress bar is being shown. // Otherwise users might think that the game softlocked if stopping takes too long. diff --git a/rpcs3/rpcs3qt/localized_emu.h b/rpcs3/rpcs3qt/localized_emu.h index a7301fe322..a95da8b0d0 100644 --- a/rpcs3/rpcs3qt/localized_emu.h +++ b/rpcs3/rpcs3qt/localized_emu.h @@ -289,6 +289,23 @@ private: case localized_string_id::HOME_MENU_SAVESTATE_AND_EXIT: return tr("Save Emulation State And Exit"); case localized_string_id::HOME_MENU_RELOAD_SAVESTATE: return tr("Reload Last Emulation State"); case localized_string_id::HOME_MENU_RECORDING: return tr("Start/Stop Recording"); + case localized_string_id::PROGRESS_DIALOG_PROGRESS: return tr("Progress:"); + case localized_string_id::PROGRESS_DIALOG_PROGRESS_ANALYZING: return tr("Progress: analyzing..."); + case localized_string_id::PROGRESS_DIALOG_REMAINING: return tr("remaining"); + case localized_string_id::PROGRESS_DIALOG_DONE: return tr("done"); + case localized_string_id::PROGRESS_DIALOG_FILE: return tr("file"); + case localized_string_id::PROGRESS_DIALOG_MODULE: return tr("module"); + case localized_string_id::PROGRESS_DIALOG_OF: return tr("of"); + case localized_string_id::PROGRESS_DIALOG_PLEASE_WAIT: return tr("Please wait"); + case localized_string_id::PROGRESS_DIALOG_STOPPING_PLEASE_WAIT: return tr("Stopping. Please wait..."); + case localized_string_id::PROGRESS_DIALOG_SCANNING_PPU_EXECUTABLE: return tr("Scanning PPU Executable..."); + case localized_string_id::PROGRESS_DIALOG_ANALYZING_PPU_EXECUTABLE: return tr("Analyzing PPU Executable..."); + case localized_string_id::PROGRESS_DIALOG_SCANNING_PPU_MODULES: return tr("Scanning PPU Modules..."); + case localized_string_id::PROGRESS_DIALOG_LOADING_PPU_MODULES: return tr("Loading PPU Modules..."); + case localized_string_id::PROGRESS_DIALOG_COMPILING_PPU_MODULES: return tr("Compiling PPU Modules..."); + case localized_string_id::PROGRESS_DIALOG_LINKING_PPU_MODULES: return tr("Linking PPU Modules..."); + case localized_string_id::PROGRESS_DIALOG_APPLYING_PPU_CODE: return tr("Applying PPU Code..."); + case localized_string_id::PROGRESS_DIALOG_BUILDING_SPU_CACHE: return tr("Building SPU Cache..."); case localized_string_id::EMULATION_PAUSED_RESUME_WITH_START: return tr("Press and hold the START button to resume"); case localized_string_id::EMULATION_RESUMING: return tr("Resuming...!"); case localized_string_id::EMULATION_FROZEN: return tr("The PS3 application has likely crashed, you can close it.");