RSX/Qt: Reuse gs_frame if possible

This commit is contained in:
Megamouse 2025-01-03 20:22:36 +01:00
parent 99f1f4c22a
commit 1ab3a0bd73
18 changed files with 101 additions and 16 deletions

View file

@ -498,6 +498,9 @@ void lv2_exitspawn(ppu_thread& ppu, std::vector<std::string>& argv, std::vector<
};
signal_system_cache_can_stay();
// Make sure we keep the game window opened
Emu.SetContinuousMode(true);
Emu.Kill(false);
});

View file

@ -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()

View file

@ -159,6 +159,7 @@ public:
GLGSRender(utils::serial* ar) noexcept;
GLGSRender() noexcept : GLGSRender(nullptr) {}
virtual ~GLGSRender();
private:

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -114,6 +114,7 @@ namespace rsx
Emu.CallFromMainThread([]()
{
Emu.SetContinuousMode(true);
Emu.Restart(false);
});
return page_navigation::exit;

View file

@ -26,6 +26,7 @@ namespace rsx
if (!suspend_mode)
{
Emu.after_kill_callback = []() { Emu.Restart(); };
Emu.SetContinuousMode(true);
}
Emu.Kill(false, true);
});

View file

@ -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<GSRender*>(g_fxo->try_get<rsx::thread>()))
{
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<bool()> 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;
}));

View file

@ -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);

View file

@ -133,7 +133,7 @@ EmuCallbacks main_application::CreateCallbacks()
basic_keyboard_handler* ret = g_fxo->init<KeyboardHandlerBase, basic_keyboard_handler>(Emu.DeserialManager());
ensure(ret);
ret->moveToThread(get_thread());
ret->SetTargetWindow(m_game_window);
ret->SetTargetWindow(reinterpret_cast<QWindow*>(m_game_window));
break;
}
}
@ -170,7 +170,7 @@ EmuCallbacks main_application::CreateCallbacks()
basic_mouse_handler* ret = g_fxo->init<MouseHandlerBase, basic_mouse_handler>(Emu.DeserialManager());
ensure(ret);
ret->moveToThread(get_thread());
ret->SetTargetWindow(m_game_window);
ret->SetTargetWindow(reinterpret_cast<QWindow*>(m_game_window));
break;
}
case mouse_handler::raw:

View file

@ -1,9 +1,10 @@
#pragma once
#include <string>
#include <QWindow>
#include <QThread>
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;
};

View file

@ -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();

View file

@ -20,6 +20,7 @@ private:
public:
explicit gl_gs_frame(QScreen* screen, const QRect& geometry, const QIcon& appIcon, std::shared_ptr<gui_settings> 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;

View file

@ -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();

View file

@ -80,6 +80,7 @@ protected:
void showEvent(QShowEvent *event) override;
void close() override;
void reset() override;
bool shown() override;
void hide() override;

View file

@ -348,6 +348,28 @@ void gui_application::InitializeConnects()
std::unique_ptr<gs_frame> 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<gs_frame>(m_game_window);
}
}
gui_log.notice("gui_application: Creating new game window");
extern const std::unordered_map<video_resolution, std::pair<int, int>, value_hash<video_resolution>> 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<gs_frame> 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<gs_frame> 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<gs_frame>(frame);
}
@ -582,10 +607,10 @@ void gui_application::InitializeCallbacks()
{
switch (type)
{
case 0: static_cast<gs_frame*>(m_game_window)->progress_reset(value); break;
case 1: static_cast<gs_frame*>(m_game_window)->progress_increment(value); break;
case 2: static_cast<gs_frame*>(m_game_window)->progress_set_limit(value); break;
case 3: static_cast<gs_frame*>(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<gs_frame*>(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)
{

View file

@ -2590,6 +2590,7 @@ void main_window::CreateConnects()
{
Emu.Restart();
};
Emu.SetContinuousMode(true);
}
Emu.Kill(false, true);