Prototype quicksave functionality, disabled for now

This commit is contained in:
Mr-Wiseguy
2024-01-13 01:39:08 -05:00
parent a25f967094
commit ecfe2381b0
12 changed files with 420 additions and 3 deletions
+18
View File
@@ -210,6 +210,24 @@ void recomp::poll_inputs() {
InputState.cur_controllers.push_back(controller);
}
}
// Quicksaving is disabled for now and will likely have more limited functionality
// when restored, rather than allowing saving and loading at any point in time.
#if 0
if (InputState.keys) {
static bool save_was_held = false;
static bool load_was_held = false;
bool save_is_held = InputState.keys[SDL_SCANCODE_F5] != 0;
bool load_is_held = InputState.keys[SDL_SCANCODE_F7] != 0;
if (save_is_held && !save_was_held) {
recomp::quicksave_save();
}
else if (load_is_held && !load_was_held) {
recomp::quicksave_load();
}
save_was_held = save_is_held;
}
#endif
}
bool controller_button_state(int32_t input_id) {
+121
View File
@@ -0,0 +1,121 @@
// Quicksaving is disabled for now
#if 0
#include "recomp_helpers.h"
#include "recomp_input.h"
#include "../ultramodern/ultramodern.hpp"
enum class QuicksaveAction {
None,
Save,
Load
};
std::atomic<QuicksaveAction> cur_quicksave_action = QuicksaveAction::None;
void recomp::quicksave_save() {
cur_quicksave_action.store(QuicksaveAction::Save);
}
void recomp::quicksave_load() {
cur_quicksave_action.store(QuicksaveAction::Load);
}
uint8_t saved_rdram[ultramodern::rdram_size];
thread_local recomp_context saved_context;
void save_context(recomp_context* ctx) {
saved_context = *ctx;
}
void load_context(recomp_context* ctx) {
*ctx = saved_context;
// Restore the pointer to the odd floats for correctly handling mips3 float mode.
if (ctx->mips3_float_mode) {
// FR = 1, odd single floats point to their own registers
ctx->f_odd = &ctx->f1.u32l;
}
else {
// FR = 0, odd single floats point to the upper half of the previous register
ctx->f_odd = &ctx->f0.u32h;
}
}
extern "C" void recomp_handle_quicksave_actions(uint8_t* rdram, recomp_context* ctx) {
QuicksaveAction action = cur_quicksave_action.load();
if (action != QuicksaveAction::None) {
PTR(OSMesgQueue) quicksave_enter_mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx);
PTR(OSMesgQueue) quicksave_exit_mq = _arg<1, PTR(OSMesgQueue)>(rdram, ctx);
printf("saving context for thread %d\n", TO_PTR(OSThread, ultramodern::this_thread())->id);
// Save or load the thread's context as needed based on the action.
if (action == QuicksaveAction::Save) {
save_context(ctx);
}
else if (action == QuicksaveAction::Load) {
load_context(ctx);
}
else {
assert(false);
}
// Tell the main thread that one of the other permanent threads is ready for performing a quicksave action.
osSendMesg(rdram, quicksave_enter_mq, NULLPTR, OS_MESG_NOBLOCK);
// Wait for the main thread to signal that other permanent threads are safe to continue.
osRecvMesg(rdram, quicksave_exit_mq, NULLPTR, OS_MESG_BLOCK);
}
}
extern "C" void wake_threads_for_quicksave_action(uint8_t* rdram, recomp_context* ctx);
extern "C" void recomp_handle_quicksave_actions_main(uint8_t* rdram, recomp_context* ctx) {
QuicksaveAction action = cur_quicksave_action.load();
if (action != QuicksaveAction::None) {
PTR(OSMesgQueue) quicksave_enter_mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx);
PTR(OSMesgQueue) quicksave_exit_mq = _arg<1, PTR(OSMesgQueue)>(rdram, ctx);
wake_threads_for_quicksave_action(rdram, ctx);
// Wait for all other permanent threads (hence the minus 1) to signal that they're ready for a quicksave action.
for (uint32_t i = 0; i < ultramodern::permanent_thread_count() - 1; i++) {
osRecvMesg(rdram, quicksave_enter_mq, NULLPTR, OS_MESG_BLOCK);
}
// Allow any temporary threads to complete by lowering this thread's priority to 0.
// TODO this won't cause all temporary threads to complete if any are blocked by permanent threads
// or events like timers. Situations like that will need to be handed on a case-by-case basis for a given game.
if (ultramodern::temporary_thread_count() != 0) {
OSPri old_pri = osGetThreadPri(rdram, NULLPTR);
osSetThreadPri(rdram, NULLPTR, 0);
osSetThreadPri(rdram, NULLPTR, old_pri);
}
if (action == QuicksaveAction::Save) {
std::copy(rdram, rdram + ultramodern::rdram_size, saved_rdram);
}
else if (action == QuicksaveAction::Load) {
std::copy(saved_rdram, saved_rdram + ultramodern::rdram_size, rdram);
}
else {
assert(false);
}
printf("Quicksave action complete\n");
cur_quicksave_action.store(QuicksaveAction::None);
// Tell all other permanent threads that they're good to continue.
for (uint32_t i = 0; i < ultramodern::permanent_thread_count() - 1; i++) {
osSendMesg(rdram, quicksave_exit_mq, NULLPTR, OS_MESG_BLOCK);
}
}
}
#endif
+3 -3
View File
@@ -175,9 +175,9 @@ EXPORT extern "C" void init() {
// Load overlays in the first 1MB
load_overlays(0x1000, (int32_t)entrypoint, 1024 * 1024);
// Allocate rdram_buffer (16MB to give room for any extra addressable data used by recomp)
rdram_buffer = std::make_unique<uint8_t[]>(16 * 1024 * 1024);
std::memset(rdram_buffer.get(), 0, 8 * 1024 * 1024);
// Allocate rdram_buffer
rdram_buffer = std::make_unique<uint8_t[]>(ultramodern::rdram_size);
std::memset(rdram_buffer.get(), 0, ultramodern::rdram_size);
// Initial 1MB DMA (rom address 0x1000 = physical address 0x10001000)
do_rom_read(rdram_buffer.get(), entrypoint, 0x10001000, 0x100000);