Add savestate buttons to home menu

This commit is contained in:
Eladash 2023-03-18 21:35:51 +02:00 committed by Megamouse
parent a6313fa46c
commit 79d09d02ed
10 changed files with 142 additions and 10 deletions

View File

@ -42,6 +42,8 @@ public:
// Underlying type
using under = std::underlying_type_t<T>;
ENABLE_BITWISE_SERIALIZATION;
private:
// Underlying value
under m_data;
@ -49,7 +51,7 @@ private:
friend class atomic_bs_t<T>;
// Value constructor
constexpr explicit bs_t(int, under data)
constexpr explicit bs_t(int, under data) noexcept
: m_data(data)
{
}
@ -71,19 +73,19 @@ public:
bs_t() = default;
// Construct from a single bit
constexpr bs_t(T bit)
constexpr bs_t(T bit) noexcept
: m_data(shift(bit))
{
}
// Test for empty bitset
constexpr explicit operator bool() const
constexpr explicit operator bool() const noexcept
{
return m_data != 0;
}
// Extract underlying data
constexpr explicit operator under() const
constexpr explicit operator under() const noexcept
{
return m_data;
}
@ -138,7 +140,7 @@ public:
return bs_t(0, lhs.m_data ^ rhs.m_data);
}
constexpr bool operator ==(bs_t rhs) const
constexpr bool operator ==(bs_t rhs) const noexcept
{
return m_data == rhs.m_data;
}

View File

@ -163,6 +163,13 @@ extern u64 get_sysutil_cb_manager_read_count()
extern bool send_open_home_menu_cmds()
{
auto status = g_fxo->try_get<SysutilMenuOpenStatus>();
if (!status || status->active)
{
return false;
}
// TODO: handle CELL_SYSUTIL_BGMPLAYBACK_STATUS_DISABLE
if (sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0) < 0 ||
sysutil_send_system_cmd(CELL_SYSUTIL_SYSTEM_MENU_OPEN, 0) < 0 ||
@ -171,15 +178,25 @@ extern bool send_open_home_menu_cmds()
return false;
}
status->active = true;
return true;
}
extern void send_close_home_menu_cmds()
{
auto status = g_fxo->try_get<SysutilMenuOpenStatus>();
if (!status || !status->active)
{
return;
}
// TODO: handle CELL_SYSUTIL_BGMPLAYBACK_STATUS_DISABLE
sysutil_send_system_cmd(CELL_SYSUTIL_BGMPLAYBACK_STOP, 0);
sysutil_send_system_cmd(CELL_SYSUTIL_SYSTEM_MENU_CLOSE, 0);
sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0);
status->active = false;
}
template <>

View File

@ -317,6 +317,14 @@ struct CellSysCacheParam
vm::bptr<void> reserved;
};
template <u32 BaseEvent>
struct SysutilEventStatus
{
atomic_t<bool> active = false;
};
using SysutilMenuOpenStatus = SysutilEventStatus<CELL_SYSUTIL_SYSTEM_MENU_OPEN>;
extern void sysutil_register_cb(std::function<s32(ppu_thread&)>&&);
extern s32 sysutil_send_system_cmd(u64 status, u64 param);
s32 sysutil_check_name_string(const char* src, s32 minlen, s32 maxlen);

View File

@ -5,6 +5,7 @@
extern atomic_t<bool> g_user_asked_for_recording;
extern atomic_t<bool> g_user_asked_for_screenshot;
extern bool boot_last_savestate(bool testing);
namespace rsx
{
@ -39,6 +40,46 @@ namespace rsx
return page_navigation::exit;
});
const bool suspend_mode = g_cfg.savestate.suspend_emu.get();
std::unique_ptr<overlay_element> save_state = std::make_unique<home_menu_entry>(get_localized_string(suspend_mode ? localized_string_id::HOME_MENU_SAVESTATE_AND_EXIT : localized_string_id::HOME_MENU_SAVESTATE));
add_item(save_state, [suspend_mode](pad_button btn) -> page_navigation
{
if (btn != pad_button::cross) return page_navigation::stay;
rsx_log.notice("User selected savestate in home menu");
Emu.CallFromMainThread([suspend_mode]()
{
Emu.Kill(false, true);
if (!suspend_mode)
{
Emu.Restart();
}
});
return page_navigation::exit;
});
if (!suspend_mode && boot_last_savestate(true))
{
std::unique_ptr<overlay_element> reload_state = std::make_unique<home_menu_entry>(get_localized_string(localized_string_id::HOME_MENU_RELOAD_SAVESTATE));
add_item(reload_state, [](pad_button btn) -> page_navigation
{
if (btn != pad_button::cross) return page_navigation::stay;
rsx_log.notice("User selected reload savestate in home menu");
Emu.CallFromMainThread([]()
{
boot_last_savestate(false);
});
return page_navigation::exit;
});
}
std::unique_ptr<overlay_element> recording = std::make_unique<home_menu_entry>(get_localized_string(localized_string_id::HOME_MENU_RECORDING));
add_item(recording, [](pad_button btn) -> page_navigation
{

View File

@ -22,6 +22,7 @@
#include "Emu/Cell/lv2/sys_overlay.h"
#include "Emu/Cell/lv2/sys_spu.h"
#include "Emu/Cell/Modules/cellGame.h"
#include "Emu/Cell/Modules/cellSysutil.h"
#include "Emu/title.h"
#include "Emu/IdManager.h"
@ -84,6 +85,8 @@ extern bool is_savestate_version_compatible(const std::vector<std::pair<u16, u16
extern std::vector<std::pair<u16, u16>> read_used_savestate_versions();
std::string get_savestate_path(std::string_view title_id, std::string_view boot_path);
extern void send_close_home_menu_cmds();
fs::file g_tty;
atomic_t<s64> g_tty_size{0};
std::array<std::deque<std::string>, 16> g_tty_input;
@ -206,7 +209,12 @@ void init_fxo_for_exec(utils::serial* ar, bool full = false)
if (ar)
{
Emu.ExecDeserializationRemnants();
ar->pos += 32; // Reserved area
auto flags = (*ar)(Emu.m_savestate_extension_flags1);
const usz advance = (Emu.m_savestate_extension_flags1 & Emulator::SaveStateExtentionFlags1::SupportsMenuOpenResume ? 32 : 31);
ar->pos += advance; // Reserved area
}
}
@ -888,6 +896,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
}
m_state_inspection_savestate = g_cfg.savestate.state_inspection_mode.get();
m_savestate_extension_flags1 = {};
bool resolve_path_as_vfs_path = false;
@ -2248,11 +2257,29 @@ void Emulator::FinalizeRunRequest()
spu.state.notify_one(cpu_flag::stop);
};
if (m_savestate_extension_flags1 & SaveStateExtentionFlags1::ShouldCloseMenu)
{
g_fxo->get<SysutilMenuOpenStatus>().active = true;
}
idm::select<named_thread<spu_thread>>(on_select);
lv2_obj::make_scheduler_ready();
m_state.compare_and_swap_test(system_state::starting, system_state::running);
if (m_savestate_extension_flags1 & SaveStateExtentionFlags1::ShouldCloseMenu)
{
std::thread([this, info = ProcureCurrentEmulationCourseInformation()]()
{
std::this_thread::sleep_for(2s);
CallFromMainThread([this]()
{
send_close_home_menu_cmds();
}, info);
}).detach();
}
}
bool Emulator::Pause(bool freeze_emulation, bool show_resume_message)
@ -2579,6 +2606,7 @@ std::shared_ptr<utils::serial> Emulator::Kill(bool allow_autoexit, bool savestat
m_config_path.clear();
m_config_mode = cfg_mode::custom;
read_used_savestate_versions();
m_savestate_extension_flags1 = {};
return to_ar;
}
@ -2755,6 +2783,16 @@ std::shared_ptr<utils::serial> Emulator::Kill(bool allow_autoexit, bool savestat
ar(std::array<u8, 32>{}); // Reserved for future use
vm::save(ar);
g_fxo->save(ar);
bs_t<SaveStateExtentionFlags1> extension_flags{SaveStateExtentionFlags1::SupportsMenuOpenResume};
if (g_fxo->get<SysutilMenuOpenStatus>().active)
{
extension_flags += SaveStateExtentionFlags1::ShouldCloseMenu;
}
ar(extension_flags);
ar(std::array<u8, 32>{}); // Reserved for future use
ar(timestamp);
});
@ -2874,6 +2912,7 @@ std::shared_ptr<utils::serial> Emulator::Kill(bool allow_autoexit, bool savestat
m_config_mode = cfg_mode::custom;
m_ar.reset();
read_used_savestate_versions();
m_savestate_extension_flags1 = {};
// Always Enable display sleep, not only if it was prevented.
enable_display_sleep();

View File

@ -2,6 +2,7 @@
#include "util/types.hpp"
#include "util/atomic.hpp"
#include "Utilities/bit_set.h"
#include <functional>
#include <memory>
#include <string>
@ -158,6 +159,16 @@ class Emulator final
}
}
enum class SaveStateExtentionFlags1 : u8
{
SupportsMenuOpenResume,
ShouldCloseMenu,
__bitset_enum_max,
};
bs_t<SaveStateExtentionFlags1> m_savestate_extension_flags1{};
public:
static constexpr std::string_view game_id_boot_prefix = "%RPCS3_GAMEID%:";
static constexpr std::string_view vfs_boot_prefix = "%RPCS3_VFS%:";

View File

@ -167,6 +167,9 @@ enum class localized_string_id
HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY,
HOME_MENU_SETTINGS_DEBUG,
HOME_MENU_SCREENSHOT,
HOME_MENU_SAVESTATE,
HOME_MENU_SAVESTATE_AND_EXIT,
HOME_MENU_RELOAD_SAVESTATE,
HOME_MENU_RECORDING,
EMULATION_PAUSED_RESUME_WITH_START,

View File

@ -174,7 +174,7 @@ std::vector<std::pair<u16, u16>> read_used_savestate_versions()
return used_serial;
}
bool boot_last_savestate()
bool boot_last_savestate(bool testing)
{
if (!g_cfg.savestate.suspend_emu && !Emu.GetTitleID().empty() && (Emu.IsRunning() || Emu.GetStatus() == system_state::paused))
{
@ -203,7 +203,15 @@ bool boot_last_savestate()
}
}
if (fs::is_file(savestate_path))
const bool result = fs::is_file(savestate_path);
if (testing)
{
sys_log.trace("boot_last_savestate(true) returned %s.", result);
return result;
}
if (result)
{
sys_log.success("Booting the most recent savestate \'%s\' using the Reload shortcut.", savestate_path);
Emu.GracefulShutdown(false);

View File

@ -372,8 +372,8 @@ void gs_frame::handle_shortcut(gui::shortcuts::shortcut shortcut_key, const QKey
return;
}
extern bool boot_last_savestate();
boot_last_savestate();
extern bool boot_last_savestate(bool testing);
boot_last_savestate(false);
}
break;
}

View File

@ -186,6 +186,9 @@ private:
case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY: return tr("Performance Overlay");
case localized_string_id::HOME_MENU_SETTINGS_DEBUG: return tr("Debug");
case localized_string_id::HOME_MENU_SCREENSHOT: return tr("Take Screenshot");
case localized_string_id::HOME_MENU_SAVESTATE: return tr("Save Emulation State");
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::EMULATION_PAUSED_RESUME_WITH_START: return tr("Press and hold the START button to resume");
case localized_string_id::EMULATION_RESUMING: return tr("Resuming...!");