mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-12 00:59:41 +01:00
Merge pull request #20343 from hrydgard/more-polish-work
Avoid getting stuck in a loop when using auto-load-state and the state is bad
This commit is contained in:
16 files changed
+133
-129
No files matched your search
@@ -2,6 +2,7 @@
|
||||
#include <cstring>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -49,8 +49,6 @@ enum class CPUCore;
|
||||
|
||||
// PSP_CoreParameter()
|
||||
struct CoreParameter {
|
||||
CoreParameter() {}
|
||||
|
||||
CPUCore cpuCore;
|
||||
GPUCore gpuCore;
|
||||
|
||||
|
||||
+34
-44
@@ -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<u8> &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()
|
||||
|
||||
+10
-10
@@ -31,7 +31,7 @@ namespace SaveState {
|
||||
WARNING,
|
||||
SUCCESS,
|
||||
};
|
||||
typedef std::function<void(Status status, std::string_view message, void *cbUserData)> Callback;
|
||||
typedef std::function<void(Status status, std::string_view message)> 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<u8> &state);
|
||||
CChunkFileReader::Error LoadFromRam(std::vector<u8> &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();
|
||||
|
||||
@@ -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...
|
||||
|
||||
+1
-3
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
+5
-5
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+60
-33
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,7 @@ private:
|
||||
#ifndef MOBILE_DEVICE
|
||||
bool startDumping_ = false;
|
||||
#endif
|
||||
bool autoLoadFailed_ = false; // to prevent repeat reloads
|
||||
};
|
||||
|
||||
bool MustRunBehind();
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in new issue
Block a user