State: Use RunOnCPUThread to invoke save state handlers
This ensures that the emulated state is only touched by the CPU thread
This commit is contained in:
parent
df45e714a3
commit
a25a4e0708
|
@ -204,27 +204,31 @@ void LoadFromBuffer(std::vector<u8>& buffer)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::RunAsCPUThread([&] {
|
Core::RunOnCPUThread(
|
||||||
u8* ptr = &buffer[0];
|
[&] {
|
||||||
PointerWrap p(&ptr, PointerWrap::MODE_READ);
|
u8* ptr = &buffer[0];
|
||||||
DoState(p);
|
PointerWrap p(&ptr, PointerWrap::MODE_READ);
|
||||||
});
|
DoState(p);
|
||||||
|
},
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveToBuffer(std::vector<u8>& buffer)
|
void SaveToBuffer(std::vector<u8>& buffer)
|
||||||
{
|
{
|
||||||
Core::RunAsCPUThread([&] {
|
Core::RunOnCPUThread(
|
||||||
u8* ptr = nullptr;
|
[&] {
|
||||||
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
|
u8* ptr = nullptr;
|
||||||
|
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
|
||||||
|
|
||||||
DoState(p);
|
DoState(p);
|
||||||
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
|
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
|
||||||
buffer.resize(buffer_size);
|
buffer.resize(buffer_size);
|
||||||
|
|
||||||
ptr = &buffer[0];
|
ptr = &buffer[0];
|
||||||
p.SetMode(PointerWrap::MODE_WRITE);
|
p.SetMode(PointerWrap::MODE_WRITE);
|
||||||
DoState(p);
|
DoState(p);
|
||||||
});
|
},
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return state number not in map
|
// return state number not in map
|
||||||
|
@ -381,42 +385,44 @@ static void CompressAndDumpState(CompressAndDumpState_args save_args)
|
||||||
|
|
||||||
void SaveAs(const std::string& filename, bool wait)
|
void SaveAs(const std::string& filename, bool wait)
|
||||||
{
|
{
|
||||||
Core::RunAsCPUThread([&] {
|
Core::RunOnCPUThread(
|
||||||
// Measure the size of the buffer.
|
[&] {
|
||||||
u8* ptr = nullptr;
|
// Measure the size of the buffer.
|
||||||
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
|
u8* ptr = nullptr;
|
||||||
DoState(p);
|
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
|
||||||
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
|
DoState(p);
|
||||||
|
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
|
||||||
|
|
||||||
// Then actually do the write.
|
// Then actually do the write.
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lk(g_cs_current_buffer);
|
std::lock_guard<std::mutex> lk(g_cs_current_buffer);
|
||||||
g_current_buffer.resize(buffer_size);
|
g_current_buffer.resize(buffer_size);
|
||||||
ptr = &g_current_buffer[0];
|
ptr = &g_current_buffer[0];
|
||||||
p.SetMode(PointerWrap::MODE_WRITE);
|
p.SetMode(PointerWrap::MODE_WRITE);
|
||||||
DoState(p);
|
DoState(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.GetMode() == PointerWrap::MODE_WRITE)
|
if (p.GetMode() == PointerWrap::MODE_WRITE)
|
||||||
{
|
{
|
||||||
Core::DisplayMessage("Saving State...", 1000);
|
Core::DisplayMessage("Saving State...", 1000);
|
||||||
|
|
||||||
CompressAndDumpState_args save_args;
|
CompressAndDumpState_args save_args;
|
||||||
save_args.buffer_vector = &g_current_buffer;
|
save_args.buffer_vector = &g_current_buffer;
|
||||||
save_args.buffer_mutex = &g_cs_current_buffer;
|
save_args.buffer_mutex = &g_cs_current_buffer;
|
||||||
save_args.filename = filename;
|
save_args.filename = filename;
|
||||||
save_args.wait = wait;
|
save_args.wait = wait;
|
||||||
|
|
||||||
Flush();
|
Flush();
|
||||||
g_save_thread = std::thread(CompressAndDumpState, save_args);
|
g_save_thread = std::thread(CompressAndDumpState, save_args);
|
||||||
g_compressAndDumpStateSyncEvent.Wait();
|
g_compressAndDumpStateSyncEvent.Wait();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// someone aborted the save by changing the mode?
|
// someone aborted the save by changing the mode?
|
||||||
Core::DisplayMessage("Unable to save: Internal DoState Error", 4000);
|
Core::DisplayMessage("Unable to save: Internal DoState Error", 4000);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadHeader(const std::string& filename, StateHeader& header)
|
bool ReadHeader(const std::string& filename, StateHeader& header)
|
||||||
|
@ -525,64 +531,66 @@ void LoadAs(const std::string& filename)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::RunAsCPUThread([&] {
|
Core::RunOnCPUThread(
|
||||||
g_loadDepth++;
|
[&] {
|
||||||
|
g_loadDepth++;
|
||||||
|
|
||||||
// Save temp buffer for undo load state
|
// Save temp buffer for undo load state
|
||||||
if (!Movie::IsJustStartingRecordingInputFromSaveState())
|
if (!Movie::IsJustStartingRecordingInputFromSaveState())
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lk(g_cs_undo_load_buffer);
|
std::lock_guard<std::mutex> lk(g_cs_undo_load_buffer);
|
||||||
SaveToBuffer(g_undo_load_buffer);
|
SaveToBuffer(g_undo_load_buffer);
|
||||||
if (Movie::IsMovieActive())
|
if (Movie::IsMovieActive())
|
||||||
Movie::SaveRecording(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm");
|
Movie::SaveRecording(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm");
|
||||||
else if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"))
|
else if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"))
|
||||||
File::Delete(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm");
|
File::Delete(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
bool loadedSuccessfully = false;
|
bool loadedSuccessfully = false;
|
||||||
|
|
||||||
// brackets here are so buffer gets freed ASAP
|
// brackets here are so buffer gets freed ASAP
|
||||||
{
|
{
|
||||||
std::vector<u8> buffer;
|
std::vector<u8> buffer;
|
||||||
LoadFileStateData(filename, buffer);
|
LoadFileStateData(filename, buffer);
|
||||||
|
|
||||||
if (!buffer.empty())
|
if (!buffer.empty())
|
||||||
{
|
{
|
||||||
u8* ptr = &buffer[0];
|
u8* ptr = &buffer[0];
|
||||||
PointerWrap p(&ptr, PointerWrap::MODE_READ);
|
PointerWrap p(&ptr, PointerWrap::MODE_READ);
|
||||||
DoState(p);
|
DoState(p);
|
||||||
loaded = true;
|
loaded = true;
|
||||||
loadedSuccessfully = (p.GetMode() == PointerWrap::MODE_READ);
|
loadedSuccessfully = (p.GetMode() == PointerWrap::MODE_READ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loaded)
|
if (loaded)
|
||||||
{
|
{
|
||||||
if (loadedSuccessfully)
|
if (loadedSuccessfully)
|
||||||
{
|
{
|
||||||
Core::DisplayMessage(StringFromFormat("Loaded state from %s", filename.c_str()), 2000);
|
Core::DisplayMessage(StringFromFormat("Loaded state from %s", filename.c_str()), 2000);
|
||||||
if (File::Exists(filename + ".dtm"))
|
if (File::Exists(filename + ".dtm"))
|
||||||
Movie::LoadInput(filename + ".dtm");
|
Movie::LoadInput(filename + ".dtm");
|
||||||
else if (!Movie::IsJustStartingRecordingInputFromSaveState() &&
|
else if (!Movie::IsJustStartingRecordingInputFromSaveState() &&
|
||||||
!Movie::IsJustStartingPlayingInputFromSaveState())
|
!Movie::IsJustStartingPlayingInputFromSaveState())
|
||||||
Movie::EndPlayInput(false);
|
Movie::EndPlayInput(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Core::DisplayMessage("The savestate could not be loaded", OSD::Duration::NORMAL);
|
Core::DisplayMessage("The savestate could not be loaded", OSD::Duration::NORMAL);
|
||||||
|
|
||||||
// since we could be in an inconsistent state now (and might crash or whatever), undo.
|
// since we could be in an inconsistent state now (and might crash or whatever), undo.
|
||||||
if (g_loadDepth < 2)
|
if (g_loadDepth < 2)
|
||||||
UndoLoadState();
|
UndoLoadState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_on_after_load_callback)
|
if (s_on_after_load_callback)
|
||||||
s_on_after_load_callback();
|
s_on_after_load_callback();
|
||||||
|
|
||||||
g_loadDepth--;
|
g_loadDepth--;
|
||||||
});
|
},
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetOnAfterLoadCallback(AfterLoadCallbackFunc callback)
|
void SetOnAfterLoadCallback(AfterLoadCallbackFunc callback)
|
||||||
|
|
Loading…
Reference in New Issue