From 1ab3a0bd7346f16df6a46863f3130e961b5d2fbe Mon Sep 17 00:00:00 2001 From: Megamouse Date: Fri, 3 Jan 2025 20:22:36 +0100 Subject: [PATCH] RSX/Qt: Reuse gs_frame if possible --- rpcs3/Emu/Cell/lv2/sys_process.cpp | 3 ++ rpcs3/Emu/RSX/GL/GLGSRender.cpp | 8 ++++ rpcs3/Emu/RSX/GL/GLGSRender.h | 1 + rpcs3/Emu/RSX/GSFrameBase.h | 1 + rpcs3/Emu/RSX/GSRender.cpp | 7 ++- rpcs3/Emu/RSX/GSRender.h | 3 ++ .../HomeMenu/overlay_home_menu_main_menu.cpp | 1 + .../HomeMenu/overlay_home_menu_savestate.cpp | 1 + rpcs3/Emu/System.cpp | 16 ++++++- rpcs3/Emu/System.h | 11 +++++ rpcs3/main_application.cpp | 4 +- rpcs3/main_application.h | 5 ++- rpcs3/rpcs3qt/gl_gs_frame.cpp | 5 +++ rpcs3/rpcs3qt/gl_gs_frame.h | 1 + rpcs3/rpcs3qt/gs_frame.cpp | 5 +++ rpcs3/rpcs3qt/gs_frame.h | 1 + rpcs3/rpcs3qt/gui_application.cpp | 43 +++++++++++++++---- rpcs3/rpcs3qt/main_window.cpp | 1 + 18 files changed, 101 insertions(+), 16 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 8038ffc248..45eb5c1858 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -498,6 +498,9 @@ void lv2_exitspawn(ppu_thread& ppu, std::vector& argv, std::vector< }; signal_system_cache_can_stay(); + + // Make sure we keep the game window opened + Emu.SetContinuousMode(true); Emu.Kill(false); }); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 3e60af9f68..a2d080c86e 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -52,6 +52,14 @@ GLGSRender::GLGSRender(utils::serial* ar) noexcept : GSRender(ar) backend_config.supports_normalized_barycentrics = true; } +GLGSRender::~GLGSRender() +{ + if (m_frame) + { + m_frame->reset(); + } +} + extern CellGcmContextData current_context; void GLGSRender::set_viewport() diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index 866fe288e6..c8c6ba89dd 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -159,6 +159,7 @@ public: GLGSRender(utils::serial* ar) noexcept; GLGSRender() noexcept : GLGSRender(nullptr) {} + virtual ~GLGSRender(); private: diff --git a/rpcs3/Emu/RSX/GSFrameBase.h b/rpcs3/Emu/RSX/GSFrameBase.h index f345f6255e..fd91244ffe 100644 --- a/rpcs3/Emu/RSX/GSFrameBase.h +++ b/rpcs3/Emu/RSX/GSFrameBase.h @@ -14,6 +14,7 @@ public: virtual ~GSFrameBase() = default; virtual void close() = 0; + virtual void reset() = 0; virtual bool shown() = 0; virtual void hide() = 0; virtual void show() = 0; diff --git a/rpcs3/Emu/RSX/GSRender.cpp b/rpcs3/Emu/RSX/GSRender.cpp index 917a772a34..2025842dab 100644 --- a/rpcs3/Emu/RSX/GSRender.cpp +++ b/rpcs3/Emu/RSX/GSRender.cpp @@ -18,7 +18,7 @@ GSRender::~GSRender() { m_context = nullptr; - if (m_frame) + if (m_frame && !m_continuous_mode) { m_frame->close(); } @@ -39,7 +39,10 @@ void GSRender::on_exit() if (m_frame) { - m_frame->hide(); + if (!m_continuous_mode) + { + m_frame->hide(); + } m_frame->delete_context(m_context); m_context = nullptr; } diff --git a/rpcs3/Emu/RSX/GSRender.h b/rpcs3/Emu/RSX/GSRender.h index eea040bf29..d2a6fd9c5f 100644 --- a/rpcs3/Emu/RSX/GSRender.h +++ b/rpcs3/Emu/RSX/GSRender.h @@ -21,12 +21,15 @@ class GSRender : public rsx::thread protected: GSFrameBase* m_frame; draw_context_t m_context = nullptr; + bool m_continuous_mode = false; public: ~GSRender() override; GSRender(utils::serial* ar) noexcept; + void set_continuous_mode(bool continuous_mode) { m_continuous_mode = continuous_mode; } + void on_init_thread() override; void on_exit() override; diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_main_menu.cpp b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_main_menu.cpp index d02b3ffbe2..2bce50e829 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_main_menu.cpp +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_main_menu.cpp @@ -114,6 +114,7 @@ namespace rsx Emu.CallFromMainThread([]() { + Emu.SetContinuousMode(true); Emu.Restart(false); }); return page_navigation::exit; diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_savestate.cpp b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_savestate.cpp index 2ff9711d5b..60fbbd8224 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_savestate.cpp +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_savestate.cpp @@ -26,6 +26,7 @@ namespace rsx if (!suspend_mode) { Emu.after_kill_callback = []() { Emu.Restart(); }; + Emu.SetContinuousMode(true); } Emu.Kill(false, true); }); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 551e7de36d..704319d0a8 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -60,6 +60,8 @@ #include "Emu/RSX/VK/VulkanAPI.h" #endif +#include "Emu/RSX/GSRender.h" + LOG_CHANNEL(sys_log, "SYS"); // Preallocate 32 MiB @@ -1005,6 +1007,16 @@ void Emulator::SetForceBoot(bool force_boot) m_force_boot = force_boot; } +void Emulator::SetContinuousMode(bool continuous_mode) +{ + m_continuous_mode = continuous_mode; + + if (GSRender* render = static_cast(g_fxo->try_get())) + { + render->set_continuous_mode(continuous_mode); + } +} + game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, usz recursion_count) { if (recursion_count == 0 && m_restrict_emu_state_change) @@ -2897,6 +2909,9 @@ void qt_events_aware_op(int repeat_duration_ms, std::function wrapped_op void Emulator::GracefulShutdown(bool allow_autoexit, bool async_op, bool savestate) { + // Make sure we close the game window + Emu.SetContinuousMode(false); + // Ensure no game has booted inbetween const auto guard = Emu.MakeEmulationStateGuard(); @@ -3278,7 +3293,6 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s thread_ctrl::wait_for(5'000); } - *closed_sucessfully = true; })); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index d9d1991b3e..747d6d494b 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -154,6 +154,7 @@ class Emulator final // 2. It signifies that we don't want to exit on Kill(), for example if we want to transition to another application. bool m_force_boot = false; + bool m_continuous_mode = false; bool m_has_gui = true; bool m_state_inspection_savestate = false; @@ -346,6 +347,15 @@ public: return m_config_mode == cfg_mode::continuous; } + bool ContinuousModeEnabled(bool reset) + { + if (reset) + { + return std::exchange(m_continuous_mode, false); + } + return m_continuous_mode; + } + class emulation_state_guard_t { class Emulator* _this = nullptr; @@ -385,6 +395,7 @@ public: bool BootRsxCapture(const std::string& path); void SetForceBoot(bool force_boot); + void SetContinuousMode(bool continuous_mode); game_boot_result Load(const std::string& title_id = "", bool is_disc_patch = false, usz recursion_count = 0); void Run(bool start_playtime); diff --git a/rpcs3/main_application.cpp b/rpcs3/main_application.cpp index 0040bb235e..d86d6523b2 100644 --- a/rpcs3/main_application.cpp +++ b/rpcs3/main_application.cpp @@ -133,7 +133,7 @@ EmuCallbacks main_application::CreateCallbacks() basic_keyboard_handler* ret = g_fxo->init(Emu.DeserialManager()); ensure(ret); ret->moveToThread(get_thread()); - ret->SetTargetWindow(m_game_window); + ret->SetTargetWindow(reinterpret_cast(m_game_window)); break; } } @@ -170,7 +170,7 @@ EmuCallbacks main_application::CreateCallbacks() basic_mouse_handler* ret = g_fxo->init(Emu.DeserialManager()); ensure(ret); ret->moveToThread(get_thread()); - ret->SetTargetWindow(m_game_window); + ret->SetTargetWindow(reinterpret_cast(m_game_window)); break; } case mouse_handler::raw: diff --git a/rpcs3/main_application.h b/rpcs3/main_application.h index e378eb5c53..dd0806970d 100644 --- a/rpcs3/main_application.h +++ b/rpcs3/main_application.h @@ -1,9 +1,10 @@ #pragma once #include -#include +#include struct EmuCallbacks; +class gs_frame; class main_application { @@ -25,5 +26,5 @@ protected: EmuCallbacks CreateCallbacks(); std::string m_active_user; - QWindow* m_game_window = nullptr; // (Currently) only needed so that pad handlers have a valid target for event filtering. + gs_frame* m_game_window = nullptr; }; diff --git a/rpcs3/rpcs3qt/gl_gs_frame.cpp b/rpcs3/rpcs3qt/gl_gs_frame.cpp index 1e3f6f8fc4..94b6aa964f 100644 --- a/rpcs3/rpcs3qt/gl_gs_frame.cpp +++ b/rpcs3/rpcs3qt/gl_gs_frame.cpp @@ -28,6 +28,11 @@ gl_gs_frame::gl_gs_frame(QScreen* screen, const QRect& geometry, const QIcon& ap show(); } +void gl_gs_frame::reset() +{ + m_primary_context = nullptr; +} + draw_context_t gl_gs_frame::make_context() { auto context = new GLContext(); diff --git a/rpcs3/rpcs3qt/gl_gs_frame.h b/rpcs3/rpcs3qt/gl_gs_frame.h index bc6e9ad65e..d1129f8e3a 100644 --- a/rpcs3/rpcs3qt/gl_gs_frame.h +++ b/rpcs3/rpcs3qt/gl_gs_frame.h @@ -20,6 +20,7 @@ private: public: explicit gl_gs_frame(QScreen* screen, const QRect& geometry, const QIcon& appIcon, std::shared_ptr gui_settings, bool force_fullscreen); + void reset() override; draw_context_t make_context() override; void set_current(draw_context_t ctx) override; void delete_context(draw_context_t ctx) override; diff --git a/rpcs3/rpcs3qt/gs_frame.cpp b/rpcs3/rpcs3qt/gs_frame.cpp index 8af0b84757..ef4131c3b4 100644 --- a/rpcs3/rpcs3qt/gs_frame.cpp +++ b/rpcs3/rpcs3qt/gs_frame.cpp @@ -328,6 +328,7 @@ void gs_frame::handle_shortcut(gui::shortcuts::shortcut shortcut_key, const QKey { Emu.Restart(); }; + Emu.SetContinuousMode(true); } Emu.Kill(false, true); @@ -623,6 +624,10 @@ void gs_frame::close() }); } +void gs_frame::reset() +{ +} + bool gs_frame::shown() { return QWindow::isVisible(); diff --git a/rpcs3/rpcs3qt/gs_frame.h b/rpcs3/rpcs3qt/gs_frame.h index 97a777360c..a6d5f41b19 100644 --- a/rpcs3/rpcs3qt/gs_frame.h +++ b/rpcs3/rpcs3qt/gs_frame.h @@ -80,6 +80,7 @@ protected: void showEvent(QShowEvent *event) override; void close() override; + void reset() override; bool shown() override; void hide() override; diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index 0a3ff110ce..08af646b50 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -348,6 +348,28 @@ void gui_application::InitializeConnects() std::unique_ptr gui_application::get_gs_frame() { + // Load AppIcon + const QIcon app_icon = m_main_window ? m_main_window->GetAppIcon() : gui::utils::get_app_icon_from_path(Emu.GetBoot(), Emu.GetTitleID()); + + if (m_game_window) + { + // Check if the continuous mode is enabled. We reset the mode after each use in order to ensure that it is only used when explicitly needed. + const bool continuous_mode_enabled = Emu.ContinuousModeEnabled(true); + + if (Emu.IsChildProcess() || continuous_mode_enabled) + { + gui_log.notice("gui_application: Re-using old game window (IsChildProcess=%d, ContinuousModeEnabled=%d)", Emu.IsChildProcess(), continuous_mode_enabled); + + if (!app_icon.isNull()) + { + m_game_window->setIcon(app_icon); + } + return std::unique_ptr(m_game_window); + } + } + + gui_log.notice("gui_application: Creating new game window"); + extern const std::unordered_map, value_hash> g_video_out_resolution_map; auto [w, h] = ::at32(g_video_out_resolution_map, g_cfg.video.resolution); @@ -424,9 +446,6 @@ std::unique_ptr gui_application::get_gs_frame() frame_geometry.setSize(QSize(w, h)); } - // Load AppIcon - const QIcon app_icon = m_main_window ? m_main_window->GetAppIcon() : gui::utils::get_app_icon_from_path(Emu.GetBoot(), Emu.GetTitleID()); - gs_frame* frame = nullptr; switch (g_cfg.video.renderer.get()) @@ -446,6 +465,12 @@ std::unique_ptr gui_application::get_gs_frame() m_game_window = frame; + connect(m_game_window, &gs_frame::destroyed, this, [this]() + { + gui_log.notice("gui_application: Deleting old game window"); + m_game_window = nullptr; + }); + return std::unique_ptr(frame); } @@ -582,10 +607,10 @@ void gui_application::InitializeCallbacks() { switch (type) { - case 0: static_cast(m_game_window)->progress_reset(value); break; - case 1: static_cast(m_game_window)->progress_increment(value); break; - case 2: static_cast(m_game_window)->progress_set_limit(value); break; - case 3: static_cast(m_game_window)->progress_set_value(value); break; + case 0: m_game_window->progress_reset(value); break; + case 1: m_game_window->progress_increment(value); break; + case 2: m_game_window->progress_set_limit(value); break; + case 3: m_game_window->progress_set_value(value); break; default: gui_log.fatal("Unknown type in handle_taskbar_progress(type=%d, value=%d)", type, value); break; } } @@ -1045,7 +1070,7 @@ void gui_application::OnShortcutChange() { if (m_game_window) { - static_cast(m_game_window)->update_shortcuts(); + m_game_window->update_shortcuts(); } } @@ -1074,7 +1099,7 @@ void gui_application::OnAppStateChanged(Qt::ApplicationState state) } const auto emu_state = Emu.GetStatus(); - const bool is_active = state == Qt::ApplicationActive; + const bool is_active = state & Qt::ApplicationActive; if (emu_state != system_state::paused && emu_state != system_state::running) { diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index f499cd6474..0702e43020 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -2590,6 +2590,7 @@ void main_window::CreateConnects() { Emu.Restart(); }; + Emu.SetContinuousMode(true); } Emu.Kill(false, true);