From b0dbac9a0774cc97f9628dca56ef7c69e7d0df95 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sun, 29 Mar 2026 17:16:54 +0200 Subject: [PATCH 01/10] Qt: hide log frame by default --- rpcs3/rpcs3qt/debugger_frame.cpp | 1 + rpcs3/rpcs3qt/game_list_frame.cpp | 2 ++ rpcs3/rpcs3qt/gui_settings.h | 2 +- rpcs3/rpcs3qt/log_frame.cpp | 2 ++ rpcs3/rpcs3qt/main_window.cpp | 3 --- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index b8ed1d642f..2184974d85 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -58,6 +58,7 @@ debugger_frame::debugger_frame(std::shared_ptr gui_settings, QWidg : custom_dock_widget(tr("Debugger [Press F1 for Help]"), parent) , m_gui_settings(std::move(gui_settings)) { + setObjectName("debugger"); setContentsMargins(0, 0, 0, 0); m_update = new QTimer(this); diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index 7ef27ea0f9..36e26cf43d 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -40,6 +40,8 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings, std , m_emu_settings(std::move(emu_settings)) , m_persistent_settings(std::move(persistent_settings)) { + setObjectName("gamelist"); + m_game_list_actions = std::make_shared(this, m_gui_settings); m_icon_size = gui::gl_icon_size_min; // ensure a valid size diff --git a/rpcs3/rpcs3qt/gui_settings.h b/rpcs3/rpcs3qt/gui_settings.h index c15b4166bf..41be2732ab 100644 --- a/rpcs3/rpcs3qt/gui_settings.h +++ b/rpcs3/rpcs3qt/gui_settings.h @@ -173,7 +173,7 @@ namespace gui const gui_save fd_save_log = gui_save(main_window, "lastExplorePathSaveLog", ""); const gui_save mw_debugger = gui_save(main_window, "debuggerVisible", false); - const gui_save mw_logger = gui_save(main_window, "loggerVisible", true); + const gui_save mw_logger = gui_save(main_window, "loggerVisible", false); const gui_save mw_gamelist = gui_save(main_window, "gamelistVisible", true); const gui_save mw_toolBarVisible = gui_save(main_window, "toolBarVisible", true); const gui_save mw_titleBarsVisible = gui_save(main_window, "titleBarsVisible", true); diff --git a/rpcs3/rpcs3qt/log_frame.cpp b/rpcs3/rpcs3qt/log_frame.cpp index cf570eea7a..61ca66a909 100644 --- a/rpcs3/rpcs3qt/log_frame.cpp +++ b/rpcs3/rpcs3qt/log_frame.cpp @@ -113,6 +113,8 @@ static gui_listener s_gui_listener; log_frame::log_frame(std::shared_ptr _gui_settings, QWidget* parent) : custom_dock_widget(tr("Log"), parent), m_gui_settings(std::move(_gui_settings)) { + setObjectName("logger"); + const int max_block_count_log = m_gui_settings->GetValue(gui::l_limit).toInt(); const int max_block_count_tty = m_gui_settings->GetValue(gui::l_limit_tty).toInt(); diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 130434f0c2..2a366705ab 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -3512,11 +3512,8 @@ void main_window::CreateDockWindows() m_mw->setContextMenuPolicy(Qt::PreventContextMenu); m_game_list_frame = new game_list_frame(m_gui_settings, m_emu_settings, m_persistent_settings, m_mw); - m_game_list_frame->setObjectName("gamelist"); m_debugger_frame = new debugger_frame(m_gui_settings, m_mw); - m_debugger_frame->setObjectName("debugger"); m_log_frame = new log_frame(m_gui_settings, m_mw); - m_log_frame->setObjectName("logger"); m_mw->addDockWidget(Qt::LeftDockWidgetArea, m_game_list_frame); m_mw->addDockWidget(Qt::LeftDockWidgetArea, m_log_frame); From cb3a83cba743cba540dee72d8448308a488d6f35 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Mon, 30 Mar 2026 15:32:37 +0200 Subject: [PATCH 02/10] overlays: add setting for fatal error hint (disabled by default) --- .../Overlays/HomeMenu/overlay_home_menu_settings.cpp | 1 + rpcs3/Emu/localized_string_id.h | 1 + rpcs3/Emu/system_config.h | 1 + rpcs3/rpcs3.cpp | 10 +++++++--- rpcs3/rpcs3qt/emu_settings_type.h | 2 ++ rpcs3/rpcs3qt/localized_emu.h | 1 + rpcs3/rpcs3qt/settings_dialog.cpp | 3 +++ rpcs3/rpcs3qt/settings_dialog.ui | 7 +++++++ rpcs3/rpcs3qt/tooltips.h | 1 + 9 files changed, 24 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp index 65a3b4263d..d9efa0522a 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp @@ -229,6 +229,7 @@ namespace rsx add_checkbox(&g_cfg.misc.show_pressure_intensity_toggle_hint, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_PRESSURE_INTENSITY_TOGGLE_HINT); add_checkbox(&g_cfg.misc.show_analog_limiter_toggle_hint, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_ANALOG_LIMITER_TOGGLE_HINT); add_checkbox(&g_cfg.misc.show_mouse_and_keyboard_toggle_hint, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_MOUSE_AND_KB_TOGGLE_HINT); + add_checkbox(&g_cfg.misc.show_fatal_error_hints, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_FATAL_ERROR_HINTS); add_checkbox(&g_cfg.video.record_with_overlays, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_RECORD_WITH_OVERLAYS); apply_layout(); diff --git a/rpcs3/Emu/localized_string_id.h b/rpcs3/Emu/localized_string_id.h index 0bcf1caf8b..0a2e654d4e 100644 --- a/rpcs3/Emu/localized_string_id.h +++ b/rpcs3/Emu/localized_string_id.h @@ -254,6 +254,7 @@ enum class localized_string_id HOME_MENU_SETTINGS_OVERLAYS_SHOW_PRESSURE_INTENSITY_TOGGLE_HINT, HOME_MENU_SETTINGS_OVERLAYS_SHOW_ANALOG_LIMITER_TOGGLE_HINT, HOME_MENU_SETTINGS_OVERLAYS_SHOW_MOUSE_AND_KB_TOGGLE_HINT, + HOME_MENU_SETTINGS_OVERLAYS_SHOW_FATAL_ERROR_HINTS, HOME_MENU_SETTINGS_OVERLAYS_RECORD_WITH_OVERLAYS, HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY, HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE, diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 099e0243a1..85b84d6b85 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -357,6 +357,7 @@ struct cfg_root : cfg::node cfg::_bool show_pressure_intensity_toggle_hint{ this, "Show pressure intensity toggle hint", true, true }; cfg::_bool show_analog_limiter_toggle_hint{ this, "Show analog limiter toggle hint", true, true }; cfg::_bool show_mouse_and_keyboard_toggle_hint{ this, "Show mouse and keyboard toggle hint", true, true }; + cfg::_bool show_fatal_error_hints{ this, "Show fatal error hints", false, true }; cfg::_bool show_capture_hints{ this, "Show capture hints", true, true }; cfg::_bool use_native_interface{ this, "Use native user interface", true }; cfg::string gdb_server{ this, "GDB Server", "127.0.0.1:2345" }; diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index 921394e311..011dfbe39f 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -68,6 +68,7 @@ DYNAMIC_IMPORT("ntdll.dll", NtSetTimerResolution, NTSTATUS(ULONG DesiredResoluti #include "util/media_utils.h" #include "rpcs3_version.h" #include "Emu/System.h" +#include "Emu/system_config.h" #include "Emu/system_utils.hpp" #include "Emu/RSX/Overlays/overlay_message.h" #include @@ -353,11 +354,14 @@ public: #endif if (msg == logs::level::fatal) { - std::string overlay_msg = "Fatal error: " + _msg.substr(rpcs3_prefix.size()); - fmt::trim_back(overlay_msg, " \t\n"); + if (g_cfg.misc.show_fatal_error_hints) + { + std::string overlay_msg = "Fatal error: " + _msg.substr(rpcs3_prefix.size()); + fmt::trim_back(overlay_msg, " \t\n"); + rsx::overlays::queue_message(overlay_msg, umax); + } // Pause emulation if fatal error encountered - rsx::overlays::queue_message(overlay_msg, umax); Emu.Pause(true); } } diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index 9b9f8a9279..3748aae000 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -189,6 +189,7 @@ enum class emu_settings_type ShowPressureIntensityToggleHint, ShowAnalogLimiterToggleHint, ShowMouseAndKeyboardToggleHint, + ShowFatalErrorHints, ShowCaptureHints, WindowTitleFormat, PauseDuringHomeMenu, @@ -405,6 +406,7 @@ inline static const std::map settings_location { emu_settings_type::ShowPressureIntensityToggleHint, { "Miscellaneous", "Show pressure intensity toggle hint"}}, { emu_settings_type::ShowAnalogLimiterToggleHint, { "Miscellaneous", "Show analog limiter toggle hint"}}, { emu_settings_type::ShowMouseAndKeyboardToggleHint, { "Miscellaneous", "Show mouse and keyboard toggle hint"}}, + { emu_settings_type::ShowFatalErrorHints, { "Miscellaneous", "Show fatal error hints"}}, { emu_settings_type::ShowCaptureHints, { "Miscellaneous", "Show capture hints" }}, { emu_settings_type::SilenceAllLogs, { "Miscellaneous", "Silence All Logs" }}, { emu_settings_type::WindowTitleFormat, { "Miscellaneous", "Window Title Format" }}, diff --git a/rpcs3/rpcs3qt/localized_emu.h b/rpcs3/rpcs3qt/localized_emu.h index fe0451b44c..d4de0bf282 100644 --- a/rpcs3/rpcs3qt/localized_emu.h +++ b/rpcs3/rpcs3qt/localized_emu.h @@ -274,6 +274,7 @@ private: case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_PRESSURE_INTENSITY_TOGGLE_HINT: return tr("Show Pressure Intensity Toggle Hint", "Overlays"); case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_ANALOG_LIMITER_TOGGLE_HINT: return tr( "Show Analog Limiter Toggle Hint", "Overlays"); case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_MOUSE_AND_KB_TOGGLE_HINT: return tr("Show Mouse And Keyboard Toggle Hint", "Overlays"); + case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_FATAL_ERROR_HINTS: return tr("Show Fatal Error Hints", "Overlays"); case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_RECORD_WITH_OVERLAYS: return tr("Record With Overlays", "Overlays"); case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY: return tr("Performance Overlay"); case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE: return tr("Enable Performance Overlay", "Performance Overlay"); diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index f4fcee4985..7bf4f02662 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -1847,6 +1847,9 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceCheckBox(ui->showMouseAndKeyboardToggleHint, emu_settings_type::ShowMouseAndKeyboardToggleHint); SubscribeTooltip(ui->showMouseAndKeyboardToggleHint, tooltips.settings.show_mouse_and_keyboard_toggle_hint); + m_emu_settings->EnhanceCheckBox(ui->showFatalErrorHints, emu_settings_type::ShowFatalErrorHints); + SubscribeTooltip(ui->showFatalErrorHints, tooltips.settings.show_fatal_error_hints); + m_emu_settings->EnhanceCheckBox(ui->showCaptureHints, emu_settings_type::ShowCaptureHints); SubscribeTooltip(ui->showCaptureHints, tooltips.settings.show_capture_hints); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index 282826fcd6..a5bcc011b7 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -3037,6 +3037,13 @@ + + + + Show fatal error hints + + + diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index 0276ac0f82..f09642a826 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -154,6 +154,7 @@ public: const QString show_pressure_intensity_toggle_hint = tr("Shows pressure intensity toggle hint using the native overlay."); const QString show_analog_limiter_toggle_hint = tr("Shows analog limiter toggle hint using the native overlay."); const QString show_mouse_and_keyboard_toggle_hint = tr("Shows mouse and keyboard toggle hint using the native overlay."); + const QString show_fatal_error_hints = tr("Shows fatal error hints using the native overlay."); const QString show_capture_hints = tr("Shows screenshot and recording hints using the native overlay."); const QString use_native_interface = tr("Enables use of native HUD within the game window that can interact with game controllers.\nWhen disabled, regular Qt dialogs are used instead.\nCurrently, the on-screen keyboard only supports the English key layout."); const QString record_with_overlays = tr("Enables recording with overlays.\nThis also affects screenshots."); From 7c9261a4615de0cc45363cb44915ed34ef081a63 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Mon, 30 Mar 2026 15:57:17 +0200 Subject: [PATCH 03/10] overlays: add toggle for boot sequence music --- .../RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp | 1 + rpcs3/Emu/RSX/RSXThread.cpp | 7 +++++-- rpcs3/Emu/localized_string_id.h | 1 + rpcs3/Emu/system_config.h | 1 + rpcs3/rpcs3qt/emu_settings_type.h | 2 ++ rpcs3/rpcs3qt/localized_emu.h | 1 + rpcs3/rpcs3qt/settings_dialog.cpp | 3 +++ rpcs3/rpcs3qt/settings_dialog.ui | 7 +++++++ rpcs3/rpcs3qt/tooltips.h | 1 + 9 files changed, 22 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp index d9efa0522a..9147b7e5c5 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp @@ -221,6 +221,7 @@ namespace rsx home_menu_settings_overlays::home_menu_settings_overlays(s16 x, s16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent) : home_menu_settings_page(x, y, width, height, use_separators, parent, get_localized_string(localized_string_id::HOME_MENU_SETTINGS_OVERLAYS)) { + add_checkbox(&g_cfg.misc.play_music_during_boot, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_PLAY_MUSIC_DURING_BOOT); add_checkbox(&g_cfg.misc.show_trophy_popups, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_TROPHY_POPUPS); add_checkbox(&g_cfg.misc.show_rpcn_popups, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_RPCN_POPUPS); add_checkbox(&g_cfg.misc.show_shader_compilation_hint, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_SHADER_COMPILATION_HINT); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 3392b9693b..a7338cbf56 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -712,9 +712,12 @@ namespace rsx { m_overlay_manager = g_fxo->init(0); - if (const std::string audio_path = Emu.GetSfoDir(true) + "/SND0.AT3"; fs::is_file(audio_path)) + if (g_cfg.misc.play_music_during_boot) { - m_overlay_manager->start_audio(audio_path); + if (const std::string audio_path = Emu.GetSfoDir(true) + "/SND0.AT3"; fs::is_file(audio_path)) + { + m_overlay_manager->start_audio(audio_path); + } } } diff --git a/rpcs3/Emu/localized_string_id.h b/rpcs3/Emu/localized_string_id.h index 0a2e654d4e..c411f6e480 100644 --- a/rpcs3/Emu/localized_string_id.h +++ b/rpcs3/Emu/localized_string_id.h @@ -256,6 +256,7 @@ enum class localized_string_id HOME_MENU_SETTINGS_OVERLAYS_SHOW_MOUSE_AND_KB_TOGGLE_HINT, HOME_MENU_SETTINGS_OVERLAYS_SHOW_FATAL_ERROR_HINTS, HOME_MENU_SETTINGS_OVERLAYS_RECORD_WITH_OVERLAYS, + HOME_MENU_SETTINGS_OVERLAYS_PLAY_MUSIC_DURING_BOOT, HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY, HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE, HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE_FRAMERATE_GRAPH, diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 85b84d6b85..9dbaa0c723 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -364,6 +364,7 @@ struct cfg_root : cfg::node cfg::_bool silence_all_logs{ this, "Silence All Logs", false, true }; cfg::string title_format{ this, "Window Title Format", "FPS: %F | %R | %V | %T [%t]", true }; cfg::_bool pause_during_home_menu{this, "Pause Emulation During Home Menu", false, false }; + cfg::_bool play_music_during_boot{this, "Play music during boot sequence", true, true }; cfg::_bool enable_gamemode{ this, "Enable GameMode", false, false }; } misc{ this }; diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index 3748aae000..db3e3556da 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -193,6 +193,7 @@ enum class emu_settings_type ShowCaptureHints, WindowTitleFormat, PauseDuringHomeMenu, + PlayMusicDuringBoot, EnableGamemode, // Network @@ -411,6 +412,7 @@ inline static const std::map settings_location { emu_settings_type::SilenceAllLogs, { "Miscellaneous", "Silence All Logs" }}, { emu_settings_type::WindowTitleFormat, { "Miscellaneous", "Window Title Format" }}, { emu_settings_type::PauseDuringHomeMenu, { "Miscellaneous", "Pause Emulation During Home Menu" }}, + { emu_settings_type::PlayMusicDuringBoot, { "Miscellaneous", "Play music during boot sequence" }}, { emu_settings_type::EnableGamemode, { "Miscellaneous", "Enable GameMode" }}, // Networking diff --git a/rpcs3/rpcs3qt/localized_emu.h b/rpcs3/rpcs3qt/localized_emu.h index d4de0bf282..ba4960aa73 100644 --- a/rpcs3/rpcs3qt/localized_emu.h +++ b/rpcs3/rpcs3qt/localized_emu.h @@ -276,6 +276,7 @@ private: case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_MOUSE_AND_KB_TOGGLE_HINT: return tr("Show Mouse And Keyboard Toggle Hint", "Overlays"); case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_FATAL_ERROR_HINTS: return tr("Show Fatal Error Hints", "Overlays"); case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_RECORD_WITH_OVERLAYS: return tr("Record With Overlays", "Overlays"); + case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_PLAY_MUSIC_DURING_BOOT: return tr("Play music during boot sequence.", "Overlays"); case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY: return tr("Performance Overlay"); case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE: return tr("Enable Performance Overlay", "Performance Overlay"); case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE_FRAMERATE_GRAPH: return tr("Enable Framerate Graph", "Performance Overlay"); diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 7bf4f02662..7e7f115d22 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -1829,6 +1829,9 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std ui->enableGamemode->setVisible(false); #endif + m_emu_settings->EnhanceCheckBox(ui->playMusicDuringBoot, emu_settings_type::PlayMusicDuringBoot); + SubscribeTooltip(ui->playMusicDuringBoot, tooltips.settings.play_music_during_boot); + m_emu_settings->EnhanceCheckBox(ui->showShaderCompilationHint, emu_settings_type::ShowShaderCompilationHint); SubscribeTooltip(ui->showShaderCompilationHint, tooltips.settings.show_shader_compilation_hint); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index a5bcc011b7..d3b98a2608 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -3009,6 +3009,13 @@ Overlay Settings + + + + Play music during boot sequence + + + diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index f09642a826..caccc1c47b 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -159,6 +159,7 @@ public: const QString use_native_interface = tr("Enables use of native HUD within the game window that can interact with game controllers.\nWhen disabled, regular Qt dialogs are used instead.\nCurrently, the on-screen keyboard only supports the English key layout."); const QString record_with_overlays = tr("Enables recording with overlays.\nThis also affects screenshots."); const QString pause_during_home_menu = tr("When enabled, opening the home menu will also pause emulation.\nWhile most games pause themselves while the home menu is shown, some do not.\nIn that case it can be helpful to pause the emulation whenever the home menu is open."); + const QString play_music_during_boot = tr("Play music during boot sequence if available."); const QString perf_overlay_enabled = tr("Enables or disables the performance overlay."); const QString perf_overlay_framerate_graph_enabled = tr("Enables or disables the framerate graph."); From 1c37f64a58583b2f80ad9bd12f928b49176b60fd Mon Sep 17 00:00:00 2001 From: kayforbe <125169722+kayforbe@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:47:52 +0300 Subject: [PATCH 04/10] Add missing include for MSVC compatibility (#18486) Added missing #include in shortcut_utils.h to fix MSVC build errors (C2059) --- rpcs3/rpcs3qt/shortcut_utils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/rpcs3/rpcs3qt/shortcut_utils.h b/rpcs3/rpcs3qt/shortcut_utils.h index d1ed3962e2..f41741ecdf 100644 --- a/rpcs3/rpcs3qt/shortcut_utils.h +++ b/rpcs3/rpcs3qt/shortcut_utils.h @@ -1,4 +1,5 @@ #pragma once +#include struct gui_game_info; class iso_archive; From 615f416af3081801a9e7973da84b9229173c41a0 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Mon, 30 Mar 2026 13:25:51 +0300 Subject: [PATCH 05/10] SPU Anlyzer: Verify bitset index --- rpcs3/Emu/Cell/SPUCommonRecompiler.cpp | 34 +++++++++++++------------- rpcs3/Emu/Cell/SPULLVMRecompiler.cpp | 7 +++++- rpcs3/Emu/Cell/SPURecompiler.h | 17 ++++++++++--- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index b10845889b..6a9ed7e7ee 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -6087,17 +6087,17 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s u32 ra = s_reg_max, rb = s_reg_max, rc = s_reg_max; - if (m_use_ra.test(pos / 4)) + if (::at32(m_use_ra, pos / 4)) { ra = op.ra; } - if (m_use_rb.test(pos / 4)) + if (::at32(m_use_rb, pos / 4)) { rb = op.rb; } - if (m_use_rc.test(pos / 4)) + if (::at32(m_use_rc, pos / 4)) { rc = op.rc; } @@ -6361,11 +6361,11 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s const auto& b = ::at32(m_bbs, reduced_loop->loop_pc); const auto& b2 = ::at32(m_bbs, bpc); - if (!reduced_loop->loop_dicts.test(i)) + if (!::at32(reduced_loop->loop_dicts, i)) { - if (b.reg_use[i] || (!b.reg_mod.test(i) && b2.reg_use[i])) + if (b.reg_use[i] || (!::at32(b.reg_mod, i) && b2.reg_use[i])) { - if ((b.reg_use[i] && b.reg_mod.test(i)) || b2.reg_mod.test(i)) + if ((b.reg_use[i] && ::at32(b.reg_mod, i)) || ::at32(b2.reg_mod, i)) { reduced_loop->is_constant_expression = false; reduced_loop->loop_writes.set(i); @@ -6598,7 +6598,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s for (u32 i = 0; i < reg->regs.size() && reduced_loop->active; i++) { - if (reg->regs.test(i)) + if (::at32(reg->regs, i)) { if (0) if (i == op_rt || reg->modified == 0) { @@ -6644,11 +6644,11 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s auto reg_org = reduced_loop->find_reg(i); u32 reg_index = i; - if (reg_org && !cond_val_incr_before_cond && reg_org->modified == 0 && reg_org->regs.count() - 1u <= 1u && !reg_org->regs.test(i)) + if (reg_org && !cond_val_incr_before_cond && reg_org->modified == 0 && reg_org->regs.count() - 1u <= 1u && !::at32(reg_org->regs, i)) { for (u32 j = 0; j <= s_reg_127; j++) { - if (reg_org->regs.test(j)) + if (::at32(reg_org->regs, j)) { if (const auto reg_found = reduced_loop->find_reg(j)) { @@ -7040,11 +7040,11 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s const auto& b = ::at32(m_bbs, reduced_loop->loop_pc); const auto& b2 = ::at32(m_bbs, bpc); - if (!reduced_loop->loop_dicts.test(i)) + if (!::at32(reduced_loop->loop_dicts, i)) { - if (b.reg_use[i] || (!b.reg_mod.test(i) && b2.reg_use[i])) + if (b.reg_use[i] || (!::at32(b.reg_mod, i) && b2.reg_use[i])) { - if ((b.reg_use[i] && b.reg_mod.test(i)) || b2.reg_mod.test(i)) + if ((b.reg_use[i] && ::at32(b.reg_mod, i)) || ::at32(b2.reg_mod, i)) { reduced_loop->is_constant_expression = false; reduced_loop->loop_writes.set(i); @@ -8298,17 +8298,17 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s u32 ra = s_reg_max, rb = s_reg_max, rc = s_reg_max; - if (m_use_ra.test(pos / 4)) + if (::at32(m_use_ra, pos / 4)) { ra = op.ra; } - if (m_use_rb.test(pos / 4)) + if (::at32(m_use_rb, pos / 4)) { rb = op.rb; } - if (m_use_rc.test(pos / 4)) + if (::at32(m_use_rc, pos / 4)) { rc = op.rc; } @@ -8575,7 +8575,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s for (u32 i = 0; i < s_reg_max; i++) { - if (pattern.loop_writes.test(i)) + if (::at32(pattern.loop_writes, i)) { if (regs.size() != 1) { @@ -8585,7 +8585,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s fmt::append(regs, " r%u-w", i); } - if (pattern.loop_args.test(i)) + if (::at32(pattern.loop_args, i)) { if (regs.size() != 1) { diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 948c6e8b14..b13c27e376 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -180,7 +180,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator bool is_gpr_not_NaN_hint(u32 i) const noexcept { - return block_wide_reg_store_elimination && bb->reg_maybe_float[i] && bb->reg_use[i] >= 3 && !bb->reg_mod[i]; + return block_wide_reg_store_elimination && ::at32(bb->reg_maybe_float, i) && ::at32(bb->reg_use, i) >= 3 && !::at32(bb->reg_mod, i); } }; @@ -2536,6 +2536,11 @@ public: condition = m_ir->CreateAnd(cond_nans, condition); prev_i = umax; } + + if (is_last) + { + break; + } } } diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index 1fd295f2f6..54ddcb2f1e 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -11,6 +11,17 @@ #include #include +// std::bitset +template + requires requires(std::remove_cvref_t& x, T&& y) { x.count(); x.test(y); x.flip(y); } +[[nodiscard]] constexpr bool at32(CT&& container, T&& index, std::source_location src_loc = std::source_location::current()) +{ + const usz csv = container.size(); + if (csv <= std::forward(index)) [[unlikely]] + fmt::raw_range_error(src_loc, format_object_simplified(index), csv); + return container[std::forward(index)]; +} + // Helper class class spu_cache { @@ -421,7 +432,7 @@ public: return true; } - return regs.count() == 1 && regs.test(reg_val); + return regs.count() == 1 && ::at32(regs, reg_val); } bool is_loop_dictator(u32 reg_val, bool test_predictable = false, bool should_predictable = true) const @@ -431,7 +442,7 @@ public: return false; } - if (regs.count() >= 1 && regs.test(reg_val)) + if (regs.count() >= 1 && ::at32(regs, reg_val)) { if (!test_predictable) { @@ -490,7 +501,7 @@ public: return false; } - if (regs.count() - (regs.test(reg_val) ? 1 : 0)) + if (regs.count() - (::at32(regs, reg_val) ? 1 : 0)) { return false; } From 80f972cd384a5d6304e29fad33582003f36ac9bd Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:30:35 +0300 Subject: [PATCH 06/10] SPU Analyzer: Acknowledge unknown targets --- rpcs3/Emu/Cell/SPUCommonRecompiler.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index 6a9ed7e7ee..fd0a8c33bf 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -2957,7 +2957,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (g_cfg.core.spu_block_size == spu_block_size_type::safe) { // Stop on special instructions (TODO) - m_targets[pos]; + m_targets[pos].push_back(SPU_LS_SIZE); next_block(); break; } @@ -2978,7 +2978,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s spu_log.error("[0x%x] Invalid interrupt flags (DE)", pos); } - m_targets[pos]; + m_targets[pos].push_back(SPU_LS_SIZE); next_block(); break; } @@ -3278,7 +3278,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s { if (type == spu_itype::BI || g_cfg.core.spu_block_size == spu_block_size_type::safe || is_no_return) { - m_targets[pos]; + m_targets[pos].push_back(SPU_LS_SIZE); } else { @@ -3291,6 +3291,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s else { m_targets[pos].push_back(pos + 4); + m_targets[pos].push_back(SPU_LS_SIZE); add_block(pos + 4); } From 83bfbc1399217e35b17ad797d6a119fe56442b82 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 29 Mar 2026 20:38:27 +0300 Subject: [PATCH 07/10] rsx/fp: Fix lane mask computation for varying registers --- rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.cpp b/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.cpp index d00a104e8f..2ec3e2e384 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.cpp +++ b/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.cpp @@ -343,7 +343,8 @@ namespace rsx::assembler::FP std::unordered_set inputs; SRC_Common src { .HEX = instruction->bytecode[operand + 1] }; - if (src.reg_type != RSX_FP_REGISTER_TYPE_TEMP) + if (src.reg_type != RSX_FP_REGISTER_TYPE_TEMP && + src.reg_type != RSX_FP_REGISTER_TYPE_INPUT) { return 0; } From 122ccca50e3508905aff79200e5ada12308275eb Mon Sep 17 00:00:00 2001 From: kd-11 Date: Tue, 31 Mar 2026 00:13:25 +0300 Subject: [PATCH 08/10] rsx: Propagate texture flags when MSAA sampling is required --- rpcs3/Emu/RSX/Program/GLSLCommon.cpp | 5 +++++ .../Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/RSX/Program/GLSLCommon.cpp b/rpcs3/Emu/RSX/Program/GLSLCommon.cpp index 28cbaa61f0..febb5c93bd 100644 --- a/rpcs3/Emu/RSX/Program/GLSLCommon.cpp +++ b/rpcs3/Emu/RSX/Program/GLSLCommon.cpp @@ -418,6 +418,11 @@ namespace glsl enabled_options.push_back("_ENABLE_DEPTH_FORMAT_RECONSTRUCTION"); } + if (props.require_msaa_ops) + { + enabled_options.push_back("_ENABLE_TEXTURE_MULTISAMPLE"); + } + program_common::define_glsl_switches(OS, enabled_options); enabled_options.clear(); diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl index aaf4dc434a..19f3ff3f9c 100644 --- a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl @@ -46,7 +46,7 @@ R"( _texture_bx2_active = false; \ } while (false) #define TEX_FLAGS(index) ((TEX_PARAM(index).flags & ~(_texture_flag_erase)) | _texture_flag_override) -#elif defined(_ENABLE_TEXTURE_ALPHA_KILL) || defined(_ENABLE_FORMAT_CONVERSION) || defined(_ENABLE_DEPTH_FORMAT_RECONSTRUCTION) +#elif defined(_ENABLE_TEXTURE_ALPHA_KILL) || defined(_ENABLE_FORMAT_CONVERSION) || defined(_ENABLE_DEPTH_FORMAT_RECONSTRUCTION) || defined(_ENABLE_TEXTURE_MULTISAMPLE) #define TEX_FLAGS(index) (TEX_PARAM(index).flags) #else #define TEX_FLAGS(index) 0 From bd95c728f0c964849a01769d3d7785e9f87face0 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Mon, 30 Mar 2026 23:04:44 +0300 Subject: [PATCH 09/10] sys_fs: Implement ENOTDIR --- Utilities/File.cpp | 2 + Utilities/File.h | 1 + rpcs3/Emu/Cell/lv2/sys_fs.cpp | 156 +++++++++++++++++++++++++++++++--- rpcs3/Loader/ISO.cpp | 6 +- 4 files changed, 150 insertions(+), 15 deletions(-) diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 490605c792..aff4537dea 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -166,6 +166,7 @@ static fs::error to_error(int e) case ENOTEMPTY: return fs::error::notempty; case EROFS: return fs::error::readonly; case EISDIR: return fs::error::isdir; + case ENOTDIR: return fs::error::notdir; case ENOSPC: return fs::error::nospace; case EXDEV: return fs::error::xdev; default: return fs::error::unknown; @@ -2833,6 +2834,7 @@ void fmt_class_string::format(std::string& out, u64 arg) case fs::error::notempty: return "Not empty"; case fs::error::readonly: return "Read only"; case fs::error::isdir: return "Is a directory"; + case fs::error::notdir: return "Not a directory"; case fs::error::toolong: return "Path too long"; case fs::error::nospace: return "Not enough space on the device"; case fs::error::xdev: return "Device mismatch"; diff --git a/Utilities/File.h b/Utilities/File.h index dd2db42a46..3d332dd0be 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -683,6 +683,7 @@ namespace fs notempty, readonly, isdir, + notdir, toolong, nospace, xdev, diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index beec0fc4e4..2534f6a8c1 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -140,6 +140,32 @@ bool verify_mself(const fs::file& mself_file) return true; } +// TODO: May not be thread-safe (or even, process-safe) +bool has_non_directory_components(std::string_view path) +{ + std::string path0{path}; + + while (true) + { + const std::string sub_path = fs::get_parent_dir(path0); + + if (sub_path.size() >= path0.size()) + { + break; + } + + fs::stat_t stat{}; + if (fs::get_stat(sub_path, stat)) + { + return !stat.is_directory; + } + + path0 = std::move(sub_path); + } + + return false; +} + lv2_fs_mount_info_map::lv2_fs_mount_info_map() { for (auto mp = &g_mp_sys_dev_root; mp; mp = mp->next) // Scan and keep track of pre-mounted devices @@ -899,8 +925,17 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3 switch (auto error = fs::g_tls_error) { + case fs::error::notdir: return {CELL_ENOTDIR}; case fs::error::noent: return {CELL_ENOENT}; - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_path)) + { + return {CELL_ENOTDIR}; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -1372,6 +1407,11 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr path, vm::ptr fd) } default: { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + fmt::throw_exception("unknown error %s", error); } } @@ -1555,6 +1595,10 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr path, vm::ptr { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: + { + return { CELL_ENOTDIR, path}; + } case fs::error::noent: { // Try to analyse split file (TODO) @@ -1594,6 +1638,11 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr path, vm::ptr } default: { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + fmt::throw_exception("unknown error %s", error); } } @@ -1720,6 +1769,10 @@ error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr path, s32 mode) { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: + { + return { CELL_ENOTDIR, path}; + } case fs::error::noent: { return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path}; @@ -1728,7 +1781,15 @@ error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr path, s32 mode) { return {sys_fs.warning, CELL_EEXIST, path}; } - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -1789,9 +1850,18 @@ error_code sys_fs_rename(ppu_thread& ppu, vm::cptr from, vm::cptr to { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: return {CELL_ENOTDIR, from}; case fs::error::noent: return {CELL_ENOENT, from}; case fs::error::exist: return {CELL_EEXIST, to}; - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_from)) + { + return {CELL_ENOTDIR, from}; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -1842,9 +1912,18 @@ error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr path) { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: return {CELL_ENOTDIR, path}; case fs::error::noent: return {CELL_ENOENT, path}; case fs::error::notempty: return {CELL_ENOTEMPTY, path}; - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -1896,11 +1975,23 @@ error_code sys_fs_unlink(ppu_thread& ppu, vm::cptr path) { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: + { + return { CELL_ENOTDIR, path }; + } case fs::error::noent: { return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path}; } - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -2737,7 +2828,15 @@ error_code sys_fs_get_block_size(ppu_thread& ppu, vm::cptr path, vm::ptr path, u64 size) { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: + { + return { CELL_ENOTDIR, path}; + } case fs::error::noent: { return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path}; } - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -2840,7 +2951,10 @@ error_code sys_fs_ftruncate(ppu_thread& ppu, u32 fd, u64 size) switch (auto error = fs::g_tls_error) { case fs::error::ok: - default: fmt::throw_exception("unknown error %s", error); + default: + { + fmt::throw_exception("unknown error %s", error); + } } } @@ -2887,6 +3001,10 @@ error_code sys_fs_chmod(ppu_thread&, vm::cptr path, s32 mode) { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: + { + return { CELL_ENOTDIR, path}; + } case fs::error::noent: { // Try to locate split files @@ -2900,8 +3018,12 @@ error_code sys_fs_chmod(ppu_thread&, vm::cptr path, s32 mode) } default: { - sys_fs.error("sys_fs_chmod(): unknown error %s", error); - return {CELL_EIO, path}; + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + + fmt::throw_exception("unknown error %s", error); } } } @@ -3033,11 +3155,23 @@ error_code sys_fs_utime(ppu_thread& ppu, vm::cptr path, vm::cptr iso_device::open_dir(const std::string& path) if (!node->metadata.is_directory) { - // fs::dir::open -> ::readdir should return ENOTDIR when path is - // pointing to a file instead of a folder, which translates to error::unknown. - // doing the same here. - fs::g_tls_error = fs::error::unknown; + // fs::dir::open -> ::readdir should return ENOTDIR when path is pointing to a file instead of a folder. + fs::g_tls_error = fs::error::notdir; return nullptr; } From ac104a519e80a0960f3b6ce0441aa96c77cabcd2 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Tue, 31 Mar 2026 06:35:34 +0300 Subject: [PATCH 10/10] SPU Analyzer: More fix --- rpcs3/Emu/Cell/SPUCommonRecompiler.cpp | 41 +++++++++++++++++--------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index fd0a8c33bf..4e8c044113 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -3011,7 +3011,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s bool is_no_return = false; - if (pos_next >= lsa && pos_next < limit) + if (sl && pos_next >= lsa && pos_next < limit) { const u32 data_next = ls[pos_next / 4]; const auto type_next = g_spu_itype.decode(data_next); @@ -3274,11 +3274,17 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s spu_log.notice("[0x%x] At 0x%x: ignoring indirect branch (SYNC)", entry_point, pos); } + if (!(af & vf::is_const)) + { + // Possible unknown target + m_targets[pos].emplace_back(SPU_LS_SIZE); + } + if (type == spu_itype::BI || sl || is_no_return) { if (type == spu_itype::BI || g_cfg.core.spu_block_size == spu_block_size_type::safe || is_no_return) { - m_targets[pos].push_back(SPU_LS_SIZE); + m_targets[pos]; } else { @@ -3291,7 +3297,6 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s else { m_targets[pos].push_back(pos + 4); - m_targets[pos].push_back(SPU_LS_SIZE); add_block(pos + 4); } @@ -3884,6 +3889,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s it->second.emplace_back(SPU_LS_SIZE); } + std::sort(it->second.begin(), it->second.end()); it++; } @@ -6313,10 +6319,6 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s case spu_itype::BI: case spu_itype::BISL: case spu_itype::BISLED: - case spu_itype::BIZ: - case spu_itype::BINZ: - case spu_itype::BIHZ: - case spu_itype::BIHNZ: { if (op.e || op.d) { @@ -6417,12 +6419,23 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s } case spu_itype::BRHZ: case spu_itype::BRHNZ: - { - const u32 next_pc = spu_branch_target(pos, 1); - const u32 target = spu_branch_target(pos, op.i16); - const bool is_u16_jump = type == spu_itype::BRHZ || type == spu_itype::BRHNZ; - const bool is_jump_zero = (type == spu_itype::BRZ || type == spu_itype::BRHZ) ^ reduced_loop->is_two_block_loop; + case spu_itype::BIZ: + case spu_itype::BINZ: + case spu_itype::BIHZ: + case spu_itype::BIHNZ: + { + if (type == spu_itype::spu_itype::BIZ || type == spu_itype::BINZ || type == spu_itype::BIHZ || type == spu_itype::BIHNZ) + { + if (op.e || op.d) + { + break_all_patterns(27); + break; + } + } + + const bool is_u16_jump = type == spu_itype::BRHZ || type == spu_itype::BRHNZ || type == spu_itype::BIHZ || type == spu_itype::BIHNZ; + const bool is_jump_zero = (type == spu_itype::BRZ || type == spu_itype::BRHZ || type == spu_itype::BIZ || type == spu_itype::BIHZ) ^ reduced_loop->is_two_block_loop; while (reduced_loop->active) { @@ -6729,8 +6742,8 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s { reduced_loop->cond_val_incr_is_immediate = false; - const u32 op_ra = spu_opcode_t{reg->IMM}.ra; - const u32 op_rb = spu_opcode_t{reg->IMM}.rb; + const u32 op_ra = spu_opcode_t{reg_org->IMM}.ra; + const u32 op_rb = spu_opcode_t{reg_org->IMM}.rb; if (!(op_ra == reg_index || op_rb == reg_index)) {