diff --git a/Common/Thread/ParallelLoop.cpp b/Common/Thread/ParallelLoop.cpp index 2b5f8b0606..4f4036d4e3 100644 --- a/Common/Thread/ParallelLoop.cpp +++ b/Common/Thread/ParallelLoop.cpp @@ -2,6 +2,7 @@ #include #include "Common/Thread/ParallelLoop.h" +#include "Common/Log.h" #include "Common/CPUDetect.h" class LoopRangeTask : public Task { @@ -35,7 +36,7 @@ WaitableCounter *ParallelRangeLoopWaitable(ThreadManager *threadMan, const std:: minSize = 1; } - int numTasks = threadMan->GetNumLooperThreads(); + const int numLooperTasks = threadMan->GetNumLooperThreads(); int range = upper - lower; if (range <= 0) { // Nothing to do. A finished counter allocated to keep the API. @@ -50,14 +51,21 @@ WaitableCounter *ParallelRangeLoopWaitable(ThreadManager *threadMan, const std:: const int fractionalBits = 8; int64_t totalFrac = (int64_t)range << fractionalBits; - int64_t delta = totalFrac / numTasks; + int64_t delta = totalFrac / numLooperTasks; delta = std::max(delta, (int64_t)minSize << fractionalBits); // Now we can compute the actual number of tasks. // Remember that stragglers are done on the current thread // so we don't round up. - numTasks = (int)(totalFrac / delta); + const int numTasks = (int)(totalFrac / delta); + // Sanity check + if (numTasks > numLooperTasks) { + // Something went very wrong in our calculations (seen this in a report). Let's just run it without threads. + _dbg_assert_(false); + loop(lower, upper); + return new WaitableCounter(0); + } WaitableCounter *waitableCounter = new WaitableCounter(numTasks); int64_t counter = (int64_t)lower << fractionalBits; diff --git a/Core/CoreParameter.h b/Core/CoreParameter.h index 43d5549a58..e2097ff329 100644 --- a/Core/CoreParameter.h +++ b/Core/CoreParameter.h @@ -49,8 +49,6 @@ enum class CPUCore; // PSP_CoreParameter() struct CoreParameter { - CoreParameter() {} - CPUCore cpuCore; GPUCore gpuCore; diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index f553a59813..f70098d4d5 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -80,14 +80,13 @@ double g_lastSaveTime = -1.0; struct Operation { // The slot number is for visual purposes only. Set to -1 for operations where we don't display a message for example. - Operation(OperationType t, const Path &f, int slot_, Callback cb, void *cbUserData_) - : type(t), filename(f), callback(cb), slot(slot_), cbUserData(cbUserData_) {} + Operation(OperationType t, const Path &f, int slot_, Callback cb) + : type(t), filename(f), callback(cb), slot(slot_) {} OperationType type; Path filename; Callback callback; int slot; - void *cbUserData; }; CChunkFileReader::Error SaveToRam(std::vector &data) { @@ -427,8 +426,7 @@ double g_lastSaveTime = -1.0; needsProcess = true; } - void Load(const Path &filename, int slot, Callback callback, void *cbUserData) - { + void Load(const Path &filename, int slot, Callback callback) { if (!NetworkAllowSaveState()) { return; } @@ -436,11 +434,10 @@ double g_lastSaveTime = -1.0; rewindStates.NotifyState(); if (coreState == CoreState::CORE_RUNTIME_ERROR) Core_Break(BreakReason::SavestateLoad, 0); - Enqueue(Operation(SAVESTATE_LOAD, filename, slot, callback, cbUserData)); + Enqueue(Operation(SAVESTATE_LOAD, filename, slot, callback)); } - void Save(const Path &filename, int slot, Callback callback, void *cbUserData) - { + void Save(const Path &filename, int slot, Callback callback) { if (!NetworkAllowSaveState()) { return; } @@ -448,27 +445,25 @@ double g_lastSaveTime = -1.0; rewindStates.NotifyState(); if (coreState == CoreState::CORE_RUNTIME_ERROR) Core_Break(BreakReason::SavestateSave, 0); - Enqueue(Operation(SAVESTATE_SAVE, filename, slot, callback, cbUserData)); + Enqueue(Operation(SAVESTATE_SAVE, filename, slot, callback)); } - void Verify(Callback callback, void *cbUserData) - { - Enqueue(Operation(SAVESTATE_VERIFY, Path(), -1, callback, cbUserData)); + void Verify(Callback callback) { + Enqueue(Operation(SAVESTATE_VERIFY, Path(), -1, callback)); } - void Rewind(Callback callback, void *cbUserData) - { + void Rewind(Callback callback) { if (g_netInited) { return; } if (coreState == CoreState::CORE_RUNTIME_ERROR) Core_Break(BreakReason::SavestateRewind, 0); - Enqueue(Operation(SAVESTATE_REWIND, Path(), -1, callback, cbUserData)); + Enqueue(Operation(SAVESTATE_REWIND, Path(), -1, callback)); } static void SaveScreenshot(const Path &filename) { screenshotFailures = 0; - Enqueue(Operation(SAVESTATE_SAVE_SCREENSHOT, filename, -1, nullptr, nullptr)); + Enqueue(Operation(SAVESTATE_SAVE_SCREENSHOT, filename, -1, nullptr)); } bool CanRewind() { @@ -588,7 +583,7 @@ double g_lastSaveTime = -1.0; } } - void LoadSlot(const Path &gameFilename, int slot, Callback callback, void *cbUserData) + void LoadSlot(const Path &gameFilename, int slot, Callback callback) { if (!NetworkAllowSaveState()) { return; @@ -600,7 +595,7 @@ double g_lastSaveTime = -1.0; if (g_Config.bEnableStateUndo) { Path backup = GetSysDirectory(DIRECTORY_SAVESTATE) / LOAD_UNDO_NAME; - auto saveCallback = [=](Status status, std::string_view message, void *data) { + auto saveCallback = [=](Status status, std::string_view message) { if (status != Status::FAILURE) { DeleteIfExists(backup); File::Rename(backup.WithExtraExtension(".tmp"), backup); @@ -609,28 +604,27 @@ double g_lastSaveTime = -1.0; } else { ERROR_LOG(Log::SaveState, "Saving load undo state failed: %.*s", (int)message.size(), message.data()); } - Load(fn, slot, callback, cbUserData); + Load(fn, slot, callback); }; if (!backup.empty()) { - Save(backup.WithExtraExtension(".tmp"), LOAD_UNDO_SLOT, saveCallback, cbUserData); + Save(backup.WithExtraExtension(".tmp"), LOAD_UNDO_SLOT, saveCallback); } else { ERROR_LOG(Log::SaveState, "Saving load undo state failed. Error in the file system."); - Load(fn, slot, callback, cbUserData); + Load(fn, slot, callback); } } else { - Load(fn, slot, callback, cbUserData); + Load(fn, slot, callback); } } else { if (callback) { auto sy = GetI18NCategory(I18NCat::SYSTEM); - callback(Status::FAILURE, sy->T("Failed to load state. Error in the file system."), cbUserData); + callback(Status::FAILURE, sy->T("Failed to load state. Error in the file system.")); } } } - bool UndoLoad(const Path &gameFilename, Callback callback, void *cbUserData) - { + bool UndoLoad(const Path &gameFilename, Callback callback) { if (!NetworkAllowSaveState()) { return false; } @@ -638,26 +632,25 @@ double g_lastSaveTime = -1.0; if (g_Config.sStateLoadUndoGame != GenerateFullDiscId(gameFilename)) { if (callback) { auto sy = GetI18NCategory(I18NCat::SYSTEM); - callback(Status::FAILURE, sy->T("Error: load undo state is from a different game"), cbUserData); + callback(Status::FAILURE, sy->T("Error: load undo state is from a different game")); } return false; } Path fn = GetSysDirectory(DIRECTORY_SAVESTATE) / LOAD_UNDO_NAME; if (!fn.empty()) { - Load(fn, LOAD_UNDO_SLOT, callback, cbUserData); + Load(fn, LOAD_UNDO_SLOT, callback); return true; } else { if (callback) { auto sy = GetI18NCategory(I18NCat::SYSTEM); - callback(Status::FAILURE, sy->T("Failed to load state for load undo. Error in the file system."), cbUserData); + callback(Status::FAILURE, sy->T("Failed to load state for load undo. Error in the file system.")); } return false; } } - void SaveSlot(const Path &gameFilename, int slot, Callback callback, void *cbUserData) - { + void SaveSlot(const Path &gameFilename, int slot, Callback callback) { if (!NetworkAllowSaveState()) { return; } @@ -666,7 +659,7 @@ double g_lastSaveTime = -1.0; Path fnUndo = GenerateSaveSlotFilename(gameFilename, slot, UNDO_STATE_EXTENSION); if (!fn.empty()) { Path shot = GenerateSaveSlotFilename(gameFilename, slot, SCREENSHOT_EXTENSION); - auto renameCallback = [=](Status status, std::string_view message, void *data) { + auto renameCallback = [=](Status status, std::string_view message) { if (status != Status::FAILURE) { if (g_Config.bEnableStateUndo) { DeleteIfExists(fnUndo); @@ -680,7 +673,7 @@ double g_lastSaveTime = -1.0; File::Rename(fn.WithExtraExtension(".tmp"), fn); } if (callback) { - callback(status, message, data); + callback(status, message); } }; // Let's also create a screenshot. @@ -690,11 +683,11 @@ double g_lastSaveTime = -1.0; RenameIfExists(shot, shotUndo); } SaveScreenshot(shot); - Save(fn.WithExtraExtension(".tmp"), slot, renameCallback, cbUserData); + Save(fn.WithExtraExtension(".tmp"), slot, renameCallback); } else { if (callback) { auto sy = GetI18NCategory(I18NCat::SYSTEM); - callback(Status::FAILURE, sy->T("Failed to save state. Error in the file system."), cbUserData); + callback(Status::FAILURE, sy->T("Failed to save state. Error in the file system.")); } } } @@ -720,7 +713,6 @@ double g_lastSaveTime = -1.0; return false; } - bool UndoLastSave(const Path &gameFilename) { if (!NetworkAllowSaveState()) { return false; @@ -732,7 +724,7 @@ double g_lastSaveTime = -1.0; return UndoSaveSlot(gameFilename, g_Config.iStateUndoLastSaveSlot); } - bool HasSaveInSlot(const Path &gameFilename, int slot) + bool HasSaveInSlot(const Path &gameFilename, int slot) { Path fn = GenerateSaveSlotFilename(gameFilename, slot, STATE_EXTENSION); return File::Exists(fn); @@ -1130,8 +1122,9 @@ double g_lastSaveTime = -1.0; break; } - if (op.callback) - op.callback(callbackResult, callbackMessage, op.cbUserData); + if (op.callback) { + op.callback(callbackResult, callbackMessage); + } } if (operations.size()) { // Avoid triggering frame skipping due to slowdown @@ -1146,15 +1139,12 @@ double g_lastSaveTime = -1.0; lastSaveDataGeneration = saveDataGeneration; } - void Cleanup() { - // TODO: Handle this better. + bool PollRestartNeeded() { if (needsRestart) { - std::string error_string; - PSP_Reboot(&error_string); - System_Notify(SystemNotification::BOOT_DONE); - System_Notify(SystemNotification::DISASSEMBLY); needsRestart = false; + return true; } + return false; } void Init() diff --git a/Core/SaveState.h b/Core/SaveState.h index 9af99dc20b..abc0d157bc 100644 --- a/Core/SaveState.h +++ b/Core/SaveState.h @@ -31,7 +31,7 @@ namespace SaveState { WARNING, SUCCESS, }; - typedef std::function Callback; + typedef std::function Callback; static const int NUM_SLOTS = 5; static const char * const STATE_EXTENSION = "ppst"; @@ -47,11 +47,11 @@ namespace SaveState { // Cycle through the 5 savestate slots void PrevSlot(); void NextSlot(); - void SaveSlot(const Path &gameFilename, int slot, Callback callback, void *cbUserData = 0); - void LoadSlot(const Path &gameFilename, int slot, Callback callback, void *cbUserData = 0); + void SaveSlot(const Path &gameFilename, int slot, Callback callback); + void LoadSlot(const Path &gameFilename, int slot, Callback callback); bool UndoSaveSlot(const Path &gameFilename, int slot); bool UndoLastSave(const Path &gameFilename); - bool UndoLoad(const Path &gameFilename, Callback callback, void *cbUserData = 0); + bool UndoLoad(const Path &gameFilename, Callback callback); // Checks whether there's an existing save in the specified slot. bool HasSaveInSlot(const Path &gameFilename, int slot); bool HasUndoSaveInSlot(const Path &gameFilename, int slot); @@ -73,22 +73,22 @@ namespace SaveState { // Load the specified file into the current state (async.) // Warning: callback will be called on a different thread. - void Load(const Path &filename, int slot, Callback callback = Callback(), void *cbUserData = 0); + void Load(const Path &filename, int slot, Callback callback = Callback()); // Save the current state to the specified file (async.) // Warning: callback will be called on a different thread. - void Save(const Path &filename, int slot, Callback callback = Callback(), void *cbUserData = 0); + void Save(const Path &filename, int slot, Callback callback = Callback()); CChunkFileReader::Error SaveToRam(std::vector &state); CChunkFileReader::Error LoadFromRam(std::vector &state, std::string *errorString); // For testing / automated tests. Runs a save state verification pass (async.) // Warning: callback will be called on a different thread. - void Verify(Callback callback = Callback(), void *cbUserData = 0); + void Verify(Callback callback = Callback()); // To go back to a previous snapshot (only if enabled.) // Warning: callback will be called on a different thread. - void Rewind(Callback callback = Callback(), void *cbUserData = 0); + void Rewind(Callback callback = Callback()); // Returns true if there are rewind snapshots available. bool CanRewind(); @@ -108,8 +108,8 @@ namespace SaveState { // Notify save state code that new save data has been written. void NotifySaveData(); - // Cleanup by triggering a restart if needed. - void Cleanup(); + // Checks whether a bad load required the caller to trigger a restart (and if returns true, resets the flag internally). + bool PollRestartNeeded(); // Returns the time since last save. -1 if N/A. double SecondsSinceLastSavestate(); diff --git a/Core/System.cpp b/Core/System.cpp index d785e0835f..b2e41a986f 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -702,19 +702,6 @@ BootState PSP_Reboot(std::string *error_string) { return PSP_Init(PSP_CoreParameter(), error_string); } -void PSP_BeginHostFrame() { - if (gpu) { - gpu->BeginHostFrame(); - } -} - -void PSP_EndHostFrame() { - if (gpu) { - gpu->EndHostFrame(); - } - SaveState::Cleanup(); -} - void PSP_RunLoopWhileState() { // We just run the CPU until we get to vblank. This will quickly sync up pretty nicely. // The actual number of cycles doesn't matter so much here as we will break due to CORE_NEXTFRAME, most of the time hopefully... diff --git a/Core/System.h b/Core/System.h index db3078eab7..6e964e0433 100644 --- a/Core/System.h +++ b/Core/System.h @@ -102,12 +102,10 @@ BootState PSP_Reboot(std::string *error_string); FileLoader *PSP_LoadedFile(); -void PSP_BeginHostFrame(); -void PSP_EndHostFrame(); void PSP_RunLoopWhileState(); void PSP_RunLoopFor(int cycles); -// Call before PSP_BeginHostFrame() in order to not miss any GPU stats. +// Call before gpu->BeginHostFrame() in order to not miss any GPU stats. void PSP_UpdateDebugStats(bool collectStats); // Increments or decrements an internal counter. Intended to be used by debuggers. void PSP_ForceDebugStats(bool enable); diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index 3a31d1269f..1b7e5c493b 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -47,12 +47,6 @@ GPUDebugInterface *gpuDebug; #undef new #endif -bool GPU_IsStarted() { - if (gpu) - return gpu->IsStarted(); - return false; -} - static GPUCommon *CreateGPUCore(GPUCore gpuCore, GraphicsContext *ctx, Draw::DrawContext *draw) { #if PPSSPP_PLATFORM(UWP) // TODO: Can probably remove this special case. diff --git a/GPU/GPU.h b/GPU/GPU.h index 50957e8002..6c0feccc28 100644 --- a/GPU/GPU.h +++ b/GPU/GPU.h @@ -184,7 +184,6 @@ namespace Draw { } bool GPU_Init(GPUCore gpuCore, GraphicsContext *ctx, Draw::DrawContext *draw); -bool GPU_IsStarted(); void GPU_Shutdown(); const char *RasterChannelToString(RasterChannel channel); diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index 850743d880..a78e8e70eb 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -149,7 +149,7 @@ void MainWindow::openmsAct() QDesktopServices::openUrl(QUrl(memorystick)); } -static void SaveStateActionFinished(SaveState::Status status, std::string_view message, void *userdata) +static void SaveStateActionFinished(SaveState::Status status, std::string_view message) { // TODO: Improve messaging? if (status == SaveState::Status::FAILURE) @@ -165,13 +165,13 @@ static void SaveStateActionFinished(SaveState::Status status, std::string_view m void MainWindow::qlstateAct() { Path gamePath = PSP_CoreParameter().fileToStart; - SaveState::LoadSlot(gamePath, 0, SaveStateActionFinished, this); + SaveState::LoadSlot(gamePath, 0, SaveStateActionFinished); } void MainWindow::qsstateAct() { Path gamePath = PSP_CoreParameter().fileToStart; - SaveState::SaveSlot(gamePath, 0, SaveStateActionFinished, this); + SaveState::SaveSlot(gamePath, 0, SaveStateActionFinished); } void MainWindow::lstateAct() @@ -185,7 +185,7 @@ void MainWindow::lstateAct() if (dialog.exec()) { QStringList fileNames = dialog.selectedFiles(); - SaveState::Load(Path(fileNames[0].toStdString()), -1, SaveStateActionFinished, this); + SaveState::Load(Path(fileNames[0].toStdString()), -1, SaveStateActionFinished); } } @@ -200,7 +200,7 @@ void MainWindow::sstateAct() if (dialog.exec()) { QStringList fileNames = dialog.selectedFiles(); - SaveState::Save(Path(fileNames[0].toStdString()), -1, SaveStateActionFinished, this); + SaveState::Save(Path(fileNames[0].toStdString()), -1, SaveStateActionFinished); } } diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index b7bc33b270..b9fb70f0ec 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -493,18 +493,12 @@ void EmuScreen::dialogFinished(const Screen *dialog, DialogResult result) { lastImguiEnabled_ = false; } -static void AfterSaveStateAction(SaveState::Status status, std::string_view message, void *) { +static void AfterSaveStateAction(SaveState::Status status, std::string_view message) { if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR, message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0); } } -static void AfterStateBoot(SaveState::Status status, std::string_view message, void *ignored) { - AfterSaveStateAction(status, message, ignored); - Core_Resume(); - System_Notify(SystemNotification::DISASSEMBLY); -} - void EmuScreen::focusChanged(ScreenFocusChange focusChange) { Screen::focusChanged(focusChange); @@ -551,6 +545,7 @@ void EmuScreen::sendMessage(UIMessage message, const char *value) { RecreateViews(); _dbg_assert_(coreState == CORE_POWERDOWN); if (!PSP_InitStart(PSP_CoreParameter())) { + bootPending_ = false; WARN_LOG(Log::Loader, "Error resetting"); screenManager()->switchScreen(new MainScreen()); return; @@ -567,7 +562,10 @@ void EmuScreen::sendMessage(UIMessage message, const char *value) { } const char *ext = strrchr(value, '.'); if (ext != nullptr && !strcmp(ext, ".ppst")) { - SaveState::Load(Path(value), -1, &AfterStateBoot); + SaveState::Load(Path(value), -1, [](SaveState::Status status, std::string_view message) { + Core_Resume(); + System_Notify(SystemNotification::DISASSEMBLY); + }); } else { PSP_Shutdown(true); Achievements::UnloadGame(); @@ -776,17 +774,6 @@ void EmuScreen::onVKey(VirtKey virtualKeyCode, bool down) { } break; - case VIRTKEY_PAUSE_NO_MENU: - if (down && !NetworkWarnUserIfOnlineAndCantSpeed()) { - // We re-use debug break/resume to implement pause/resume without a menu. - if (coreState == CORE_STEPPING_CPU) { // should we check reason? - Core_Resume(); - } else { - Core_Break(BreakReason::UIPause); - } - } - break; - case VIRTKEY_RESET_EMULATION: if (down) { System_PostUIMessage(UIMessage::REQUEST_GAME_RESET); @@ -815,15 +802,6 @@ void EmuScreen::onVKey(VirtKey virtualKeyCode, bool down) { break; #endif - case VIRTKEY_REWIND: - if (down && !Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate() && !bootPending_) { - if (SaveState::CanRewind()) { - SaveState::Rewind(&AfterSaveStateAction); - } else { - g_OSD.Show(OSDType::MESSAGE_WARNING, sc->T("norewind", "No rewind save states available"), 2.0); - } - } - break; case VIRTKEY_SAVE_STATE: if (down && !Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate() && !bootPending_) { SaveState::SaveSlot(gamePath_, g_Config.iCurrentStateSlot, &AfterSaveStateAction); @@ -967,6 +945,27 @@ void EmuScreen::ProcessVKey(VirtKey virtKey) { } break; + case VIRTKEY_REWIND: + if (!Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate() && !bootPending_) { + if (SaveState::CanRewind()) { + SaveState::Rewind(&AfterSaveStateAction); + } else { + g_OSD.Show(OSDType::MESSAGE_WARNING, sc->T("norewind", "No rewind save states available"), 2.0); + } + } + break; + + case VIRTKEY_PAUSE_NO_MENU: + if (!NetworkWarnUserIfOnlineAndCantSpeed()) { + // We re-use debug break/resume to implement pause/resume without a menu. + if (coreState == CORE_STEPPING_CPU) { // should we check reason? + Core_Resume(); + } else { + Core_Break(BreakReason::UIPause); + } + } + break; + case VIRTKEY_EXIT_APP: { std::string confirmExitMessage = GetConfirmExitMessage(); @@ -1581,9 +1580,9 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { // Just to make sure. if (PSP_IsInited() && !skipBufferEffects) { _dbg_assert_(gpu); - PSP_BeginHostFrame(); + gpu->BeginHostFrame(); gpu->CopyDisplayToOutput(true); - PSP_EndHostFrame(); + gpu->EndHostFrame(); } if (gpu && gpu->PresentedThisFrame()) { framebufferBound = true; @@ -1647,7 +1646,9 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { bool blockedExecution = Achievements::IsBlockingExecution(); uint32_t clearColor = 0; if (!blockedExecution) { - PSP_BeginHostFrame(); + if (gpu) { + gpu->BeginHostFrame(); + } if (SaveState::Process()) { // We might have lost the framebuffer bind if we had one, due to a readback. if (framebufferBound) { @@ -1700,7 +1701,24 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { break; } - PSP_EndHostFrame(); + if (gpu) { + gpu->EndHostFrame(); + } + + if (SaveState::PollRestartNeeded() && !bootPending_) { + PSP_Shutdown(true); + Achievements::UnloadGame(); + + // Restart the boot process + bootPending_ = true; + RecreateViews(); + _dbg_assert_(coreState == CORE_POWERDOWN); + if (!PSP_InitStart(PSP_CoreParameter())) { + bootPending_ = false; + WARN_LOG(Log::Loader, "Error resetting"); + screenManager()->switchScreen(new MainScreen()); + } + } } if (frameStep_) { @@ -1945,6 +1963,10 @@ void EmuScreen::renderUI() { } void EmuScreen::AutoLoadSaveState() { + if (autoLoadFailed_) { + return; + } + int autoSlot = -1; //check if save state has save, if so, load @@ -1963,7 +1985,12 @@ void EmuScreen::AutoLoadSaveState() { } if (g_Config.iAutoLoadSaveState && autoSlot != -1) { - SaveState::LoadSlot(gamePath_, autoSlot, &AfterSaveStateAction); + SaveState::LoadSlot(gamePath_, autoSlot, [this](SaveState::Status status, std::string_view message) { + AfterSaveStateAction(status, message); + if (status == SaveState::Status::FAILURE) { + autoLoadFailed_ = true; + } + }); g_Config.iCurrentStateSlot = autoSlot; } } diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index ae84e3708d..5baa7f85f8 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -155,6 +155,7 @@ private: #ifndef MOBILE_DEVICE bool startDumping_ = false; #endif + bool autoLoadFailed_ = false; // to prevent repeat reloads }; bool MustRunBehind(); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 969e572786..4714219772 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -725,7 +725,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch g_BackgroundAudio.SFX().Init(); if (!boot_filename.empty() && stateToLoad.Valid()) { - SaveState::Load(stateToLoad, -1, [](SaveState::Status status, std::string_view message, void *) { + SaveState::Load(stateToLoad, -1, [](SaveState::Status status, std::string_view message) { if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR, message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0); diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 541ac53bf0..14a0b0edd3 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -64,7 +64,7 @@ #include "UI/RetroAchievementScreens.h" #include "UI/BackgroundAudio.h" -static void AfterSaveStateAction(SaveState::Status status, std::string_view message, void *) { +static void AfterSaveStateAction(SaveState::Status status, std::string_view message) { if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR, message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0); diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 5079620657..3100dea610 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -375,7 +375,7 @@ namespace MainWindow { }); } - static void SaveStateActionFinished(SaveState::Status status, std::string_view message, void *userdata) { + static void SaveStateActionFinished(SaveState::Status status, std::string_view message) { if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR, message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0); } diff --git a/android/jni/TestRunner.cpp b/android/jni/TestRunner.cpp index ed0d9a7037..7779e8d08e 100644 --- a/android/jni/TestRunner.cpp +++ b/android/jni/TestRunner.cpp @@ -127,8 +127,6 @@ bool RunTests() { return false; } - PSP_BeginHostFrame(); - // Run the emu until the test exits INFO_LOG(Log::System, "Test: Entering runloop."); while (true) { @@ -145,7 +143,6 @@ bool RunTests() { break; } } - PSP_EndHostFrame(); std::string expect_results; if (!File::ReadTextFileToString(expectedFile, &expect_results)) { diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 40b57e9877..225e427329 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -215,10 +215,13 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const PSP_UpdateDebugStats((DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::DEBUG_STATS || g_Config.bLogFrameDrops); - PSP_BeginHostFrame(); + if (gpu) { + gpu->BeginHostFrame(); + } Draw::DrawContext *draw = coreParameter.graphicsContext ? coreParameter.graphicsContext->GetDrawContext() : nullptr; - if (draw) + if (draw) { draw->BeginFrame(Draw::DebugFlags::NONE); + } bool passed = true; double deadline = time_now_d() + opt.timeout; @@ -255,7 +258,9 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const Core_Stop(); } } - PSP_EndHostFrame(); + if (gpu) { + gpu->EndHostFrame(); + } if (draw) { draw->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Headless");