Save States: Manually merge in most of the changes (with the exception of the GPU framebuffer rescaling and reformatting code) based on several commits in PR #190 by @SuuperW.

This commit is contained in:
rogerman 2018-10-26 00:17:08 -07:00
parent c3dbb920fa
commit c1eafc53f2
4 changed files with 117 additions and 65 deletions

View File

@ -1151,72 +1151,12 @@ FORCEINLINE void rot_BMP_map(const s32 auxX, const s32 auxY, const int lg, const
void gpu_savestate(EMUFILE &os)
{
const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo();
const GPUEngineA *mainEngine = GPU->GetEngineMain();
const GPUEngineB *subEngine = GPU->GetEngineSub();
//version
os.write_32LE(1);
os.fwrite((u8 *)dispInfo.masterCustomBuffer, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(u16) * 2);
os.write_32LE(mainEngine->savedBG2X.value);
os.write_32LE(mainEngine->savedBG2Y.value);
os.write_32LE(mainEngine->savedBG3X.value);
os.write_32LE(mainEngine->savedBG3Y.value);
os.write_32LE(subEngine->savedBG2X.value);
os.write_32LE(subEngine->savedBG2Y.value);
os.write_32LE(subEngine->savedBG3X.value);
os.write_32LE(subEngine->savedBG3Y.value);
GPU->SaveState(os);
}
bool gpu_loadstate(EMUFILE &is, int size)
{
const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo();
GPUEngineA *mainEngine = GPU->GetEngineMain();
GPUEngineB *subEngine = GPU->GetEngineSub();
//read version
u32 version;
//sigh.. shouldve used a new version number
if (size == GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(u16) * 2)
{
version = 0;
}
else if (size == 0x30024)
{
is.read_32LE(version);
version = 1;
}
else
{
if (is.read_32LE(version) != 1) return false;
}
if (version > 1) return false;
is.fread((u8 *)dispInfo.masterCustomBuffer, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(u16) * 2);
if (version == 1)
{
is.read_32LE(mainEngine->savedBG2X.value);
is.read_32LE(mainEngine->savedBG2Y.value);
is.read_32LE(mainEngine->savedBG3X.value);
is.read_32LE(mainEngine->savedBG3Y.value);
is.read_32LE(subEngine->savedBG2X.value);
is.read_32LE(subEngine->savedBG2Y.value);
is.read_32LE(subEngine->savedBG3X.value);
is.read_32LE(subEngine->savedBG3Y.value);
//removed per nitsuja feedback. anyway, this same thing will happen almost immediately in gpu line=0
//mainEngine->refreshAffineStartRegs(-1,-1);
//subEngine->refreshAffineStartRegs(-1,-1);
}
mainEngine->ParseAllRegisters();
subEngine->ParseAllRegisters();
return !is.fail();
return GPU->LoadState(is, size);
}
/*****************************************************************************/
@ -9081,6 +9021,96 @@ void GPUSubsystem::ClearWithColor(const u16 colorBGRA5551)
}
}
void GPUSubsystem::SaveState(EMUFILE &os)
{
// Savestate chunk version
os.write_32LE(2);
// Version 0
os.fwrite((u8 *)this->_displayInfo.masterCustomBuffer, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(u16) * 2);
// Version 1
os.write_32LE(this->_engineMain->savedBG2X.value);
os.write_32LE(this->_engineMain->savedBG2Y.value);
os.write_32LE(this->_engineMain->savedBG3X.value);
os.write_32LE(this->_engineMain->savedBG3Y.value);
os.write_32LE(this->_engineSub->savedBG2X.value);
os.write_32LE(this->_engineSub->savedBG2Y.value);
os.write_32LE(this->_engineSub->savedBG3X.value);
os.write_32LE(this->_engineSub->savedBG3Y.value);
// Version 2
os.write_floatLE(_backlightIntensityTotal[0]);
os.write_floatLE(_backlightIntensityTotal[1]);
}
bool GPUSubsystem::LoadState(EMUFILE &is, int size)
{
u32 version;
//sigh.. shouldve used a new version number
if (size == GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(u16) * 2)
{
version = 0;
}
else if (size == 0x30024)
{
is.read_32LE(version);
version = 1;
}
else
{
if (is.read_32LE(version) < 1) return false;
}
if (version > 2) return false;
// Version 0
is.fread((u8 *)this->_displayInfo.masterCustomBuffer, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(u16) * 2);
// Version 1
if (version >= 1)
{
is.read_32LE(this->_engineMain->savedBG2X.value);
is.read_32LE(this->_engineMain->savedBG2Y.value);
is.read_32LE(this->_engineMain->savedBG3X.value);
is.read_32LE(this->_engineMain->savedBG3Y.value);
is.read_32LE(this->_engineSub->savedBG2X.value);
is.read_32LE(this->_engineSub->savedBG2Y.value);
is.read_32LE(this->_engineSub->savedBG3X.value);
is.read_32LE(this->_engineSub->savedBG3Y.value);
//removed per nitsuja feedback. anyway, this same thing will happen almost immediately in gpu line=0
//this->_engineMain->refreshAffineStartRegs(-1,-1);
//this->_engineSub->refreshAffineStartRegs(-1,-1);
}
// Version 2
if (version >= 2)
{
is.read_floatLE(_backlightIntensityTotal[0]);
is.read_floatLE(_backlightIntensityTotal[1]);
}
else
{
// UpdateAverageBacklightIntensityTotal() adds to _backlightIntensityTotal, and is called 263 times per frame.
// Of these, 71 calls are after _displayInfo.backlightIntensity is set.
// This emulates those calls as a way of guessing what the backlight values were in a savestate which doesn't contain that information.
this->_backlightIntensityTotal[0] = 0.0f;
this->_backlightIntensityTotal[1] = 0.0f;
this->UpdateAverageBacklightIntensityTotal();
this->_displayInfo.backlightIntensity[0] = this->_backlightIntensityTotal[0];
this->_displayInfo.backlightIntensity[1] = this->_backlightIntensityTotal[1];
this->_backlightIntensityTotal[0] *= 71;
this->_backlightIntensityTotal[1] *= 71;
}
// Parse all GPU engine related registers based on a previously read MMU savestate chunk.
this->_engineMain->ParseAllRegisters();
this->_engineSub->ParseAllRegisters();
return !is.fail();
}
void GPUEventHandlerDefault::DidFrameBegin(const size_t line, const bool isFrameSkipRequested, const size_t pageCount, u8 &selectedBufferIndexInOut)
{
if ( (pageCount > 1) && (line == 0) && !isFrameSkipRequested )

View File

@ -1864,6 +1864,9 @@ public:
template<NDSColorFormat OUTPUTFORMAT> void RenderLine(const size_t l);
void UpdateAverageBacklightIntensityTotal();
void ClearWithColor(const u16 colorBGRA5551);
void SaveState(EMUFILE &os);
bool LoadState(EMUFILE &is, int size);
};
class GPUClientFetchObject

View File

@ -1231,7 +1231,7 @@ struct Sequencer
if (!divider.load(is)) return false;
if (!sqrtunit.load(is)) return false;
if (!gxfifo.load(is)) return false;
if (!readslot1.load(is)) return false;
if (version >= 4) if (!readslot1.load(is)) return false;
if (version >= 1) if(!wifi.load(is)) return false;
#define LOAD(I,X,Y) if(!I##_##X##_##Y .load(is)) return false;
LOAD(timer,0,0); LOAD(timer,0,1); LOAD(timer,0,2); LOAD(timer,0,3);
@ -1762,7 +1762,7 @@ static bool loadUserInput(EMUFILE &is, int version);
void nds_savestate(EMUFILE &os)
{
//version
os.write_32LE(3);
os.write_32LE(4);
sequencer.save(os);
@ -1782,7 +1782,13 @@ bool nds_loadstate(EMUFILE &is, int size)
u32 version;
if (is.read_32LE(version) != 1) return false;
if (version > 3) return false;
if (version > 4) return false;
// hacky fix; commit 281268e added to the saved info but didn't update version
if (version == 3)
{
if (size == 497)
version = 4;
}
bool temp = true;
temp &= sequencer.load(is, version);

View File

@ -1095,6 +1095,7 @@ static bool ReadStateChunks(EMUFILE &is, s32 totalsize)
{
bool ret = true;
bool haveInfo = false;
bool chunkError = false;
s64 save_time = 0;
u32 romsize = 0;
@ -1122,6 +1123,7 @@ static bool ReadStateChunks(EMUFILE &is, s32 totalsize)
if (!is.read_32LE(t)) { ret=false; break; }
if (t == 0xFFFFFFFF) break;
if (!is.read_32LE(size)) { ret=false; break; }
u32 endPos = is.ftell() + size;
switch(t)
{
@ -1169,9 +1171,20 @@ static bool ReadStateChunks(EMUFILE &is, s32 totalsize)
default:
return false;
}
if (is.ftell() != endPos)
{
// Should we just go ahead and return false?
chunkError = true;
is.fseek(endPos, SEEK_SET);
}
if(!ret)
return false;
}
if (chunkError)
msgbox->warn("There was an error loading the savestate. Your game session is probably corrupt now.");
if (haveInfo)
{