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:
parent
c3dbb920fa
commit
c1eafc53f2
|
@ -1151,72 +1151,12 @@ FORCEINLINE void rot_BMP_map(const s32 auxX, const s32 auxY, const int lg, const
|
||||||
|
|
||||||
void gpu_savestate(EMUFILE &os)
|
void gpu_savestate(EMUFILE &os)
|
||||||
{
|
{
|
||||||
const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo();
|
GPU->SaveState(os);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gpu_loadstate(EMUFILE &is, int size)
|
bool gpu_loadstate(EMUFILE &is, int size)
|
||||||
{
|
{
|
||||||
const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo();
|
return GPU->LoadState(is, size);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -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)
|
void GPUEventHandlerDefault::DidFrameBegin(const size_t line, const bool isFrameSkipRequested, const size_t pageCount, u8 &selectedBufferIndexInOut)
|
||||||
{
|
{
|
||||||
if ( (pageCount > 1) && (line == 0) && !isFrameSkipRequested )
|
if ( (pageCount > 1) && (line == 0) && !isFrameSkipRequested )
|
||||||
|
|
|
@ -1864,6 +1864,9 @@ public:
|
||||||
template<NDSColorFormat OUTPUTFORMAT> void RenderLine(const size_t l);
|
template<NDSColorFormat OUTPUTFORMAT> void RenderLine(const size_t l);
|
||||||
void UpdateAverageBacklightIntensityTotal();
|
void UpdateAverageBacklightIntensityTotal();
|
||||||
void ClearWithColor(const u16 colorBGRA5551);
|
void ClearWithColor(const u16 colorBGRA5551);
|
||||||
|
|
||||||
|
void SaveState(EMUFILE &os);
|
||||||
|
bool LoadState(EMUFILE &is, int size);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPUClientFetchObject
|
class GPUClientFetchObject
|
||||||
|
|
|
@ -1231,7 +1231,7 @@ struct Sequencer
|
||||||
if (!divider.load(is)) return false;
|
if (!divider.load(is)) return false;
|
||||||
if (!sqrtunit.load(is)) return false;
|
if (!sqrtunit.load(is)) return false;
|
||||||
if (!gxfifo.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;
|
if (version >= 1) if(!wifi.load(is)) return false;
|
||||||
#define LOAD(I,X,Y) if(!I##_##X##_##Y .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);
|
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)
|
void nds_savestate(EMUFILE &os)
|
||||||
{
|
{
|
||||||
//version
|
//version
|
||||||
os.write_32LE(3);
|
os.write_32LE(4);
|
||||||
|
|
||||||
sequencer.save(os);
|
sequencer.save(os);
|
||||||
|
|
||||||
|
@ -1782,7 +1782,13 @@ bool nds_loadstate(EMUFILE &is, int size)
|
||||||
u32 version;
|
u32 version;
|
||||||
if (is.read_32LE(version) != 1) return false;
|
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;
|
bool temp = true;
|
||||||
temp &= sequencer.load(is, version);
|
temp &= sequencer.load(is, version);
|
||||||
|
|
|
@ -1095,6 +1095,7 @@ static bool ReadStateChunks(EMUFILE &is, s32 totalsize)
|
||||||
{
|
{
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
bool haveInfo = false;
|
bool haveInfo = false;
|
||||||
|
bool chunkError = false;
|
||||||
|
|
||||||
s64 save_time = 0;
|
s64 save_time = 0;
|
||||||
u32 romsize = 0;
|
u32 romsize = 0;
|
||||||
|
@ -1122,6 +1123,7 @@ static bool ReadStateChunks(EMUFILE &is, s32 totalsize)
|
||||||
if (!is.read_32LE(t)) { ret=false; break; }
|
if (!is.read_32LE(t)) { ret=false; break; }
|
||||||
if (t == 0xFFFFFFFF) break;
|
if (t == 0xFFFFFFFF) break;
|
||||||
if (!is.read_32LE(size)) { ret=false; break; }
|
if (!is.read_32LE(size)) { ret=false; break; }
|
||||||
|
u32 endPos = is.ftell() + size;
|
||||||
|
|
||||||
switch(t)
|
switch(t)
|
||||||
{
|
{
|
||||||
|
@ -1169,10 +1171,21 @@ static bool ReadStateChunks(EMUFILE &is, s32 totalsize)
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is.ftell() != endPos)
|
||||||
|
{
|
||||||
|
// Should we just go ahead and return false?
|
||||||
|
chunkError = true;
|
||||||
|
is.fseek(endPos, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
if(!ret)
|
if(!ret)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chunkError)
|
||||||
|
msgbox->warn("There was an error loading the savestate. Your game session is probably corrupt now.");
|
||||||
|
|
||||||
if (haveInfo)
|
if (haveInfo)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue