Save States: Properly rescale and convert the internal 3D framebuffer to and from a standard format -- 32-bit RGBA8888. (Related to commit c1eafc5 and completes all the work in PR #190 by @SuuperW.)

This commit is contained in:
rogerman 2018-10-27 22:54:30 -07:00
parent 79687d3031
commit 0beabec97c
5 changed files with 168 additions and 29 deletions

View File

@ -718,8 +718,8 @@ static FORCEINLINE void CopyLineExpand(void *__restrict dst, const void *__restr
} }
template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE> template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE>
static void CopyLineExpandHinted(const void *__restrict srcBuffer, const size_t srcLineIndex, void CopyLineExpandHinted(const void *__restrict srcBuffer, const size_t srcLineIndex,
void *__restrict dstBuffer, const size_t dstLineIndex, const size_t dstLineWidth, const size_t dstLineCount) void *__restrict dstBuffer, const size_t dstLineIndex, const size_t dstLineWidth, const size_t dstLineCount)
{ {
switch (INTEGERSCALEHINT) switch (INTEGERSCALEHINT)
{ {
@ -784,7 +784,7 @@ static void CopyLineExpandHinted(const void *__restrict srcBuffer, const size_t
} }
template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE> template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE>
static void CopyLineExpandHinted(const GPUEngineLineInfo &lineInfo, const void *__restrict srcBuffer, void *__restrict dstBuffer) void CopyLineExpandHinted(const GPUEngineLineInfo &lineInfo, const void *__restrict srcBuffer, void *__restrict dstBuffer)
{ {
CopyLineExpandHinted<INTEGERSCALEHINT, USELINEINDEX, NEEDENDIANSWAP, ELEMENTSIZE>(srcBuffer, lineInfo.indexNative, CopyLineExpandHinted<INTEGERSCALEHINT, USELINEINDEX, NEEDENDIANSWAP, ELEMENTSIZE>(srcBuffer, lineInfo.indexNative,
dstBuffer, lineInfo.indexCustom, lineInfo.widthCustom, lineInfo.renderCount); dstBuffer, lineInfo.indexCustom, lineInfo.widthCustom, lineInfo.renderCount);
@ -1184,8 +1184,8 @@ static FORCEINLINE void CopyLineReduce(void *__restrict dst, const void *__restr
} }
template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE> template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE>
static void CopyLineReduceHinted(const void *__restrict srcBuffer, const size_t srcLineIndex, const size_t srcLineWidth, void CopyLineReduceHinted(const void *__restrict srcBuffer, const size_t srcLineIndex, const size_t srcLineWidth,
void *__restrict dstBuffer, const size_t dstLineIndex) void *__restrict dstBuffer, const size_t dstLineIndex)
{ {
switch (INTEGERSCALEHINT) switch (INTEGERSCALEHINT)
{ {
@ -1250,7 +1250,7 @@ static void CopyLineReduceHinted(const void *__restrict srcBuffer, const size_t
} }
template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE> template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE>
static void CopyLineReduceHinted(const GPUEngineLineInfo &lineInfo, const void *__restrict srcBuffer, void *__restrict dstBuffer) void CopyLineReduceHinted(const GPUEngineLineInfo &lineInfo, const void *__restrict srcBuffer, void *__restrict dstBuffer)
{ {
CopyLineReduceHinted<INTEGERSCALEHINT, USELINEINDEX, NEEDENDIANSWAP, ELEMENTSIZE>(srcBuffer, lineInfo.indexCustom, lineInfo.widthCustom, CopyLineReduceHinted<INTEGERSCALEHINT, USELINEINDEX, NEEDENDIANSWAP, ELEMENTSIZE>(srcBuffer, lineInfo.indexCustom, lineInfo.widthCustom,
dstBuffer, lineInfo.indexNative); dstBuffer, lineInfo.indexNative);
@ -6393,7 +6393,6 @@ GPUEngineA::GPUEngineA()
_captureWorkingB16 = (u16 *)malloc_alignedPage(GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(u16)); _captureWorkingB16 = (u16 *)malloc_alignedPage(GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(u16));
_captureWorkingA32 = (FragmentColor *)malloc_alignedPage(GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(FragmentColor)); _captureWorkingA32 = (FragmentColor *)malloc_alignedPage(GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(FragmentColor));
_captureWorkingB32 = (FragmentColor *)malloc_alignedPage(GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(FragmentColor)); _captureWorkingB32 = (FragmentColor *)malloc_alignedPage(GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(FragmentColor));
gfx3d_Update3DFramebuffers(_3DFramebufferMain, _3DFramebuffer16);
} }
GPUEngineA::~GPUEngineA() GPUEngineA::~GPUEngineA()
@ -6404,7 +6403,6 @@ GPUEngineA::~GPUEngineA()
free_aligned(this->_captureWorkingB16); free_aligned(this->_captureWorkingB16);
free_aligned(this->_captureWorkingA32); free_aligned(this->_captureWorkingA32);
free_aligned(this->_captureWorkingB32); free_aligned(this->_captureWorkingB32);
gfx3d_Update3DFramebuffers(NULL, NULL);
} }
GPUEngineA* GPUEngineA::Allocate() GPUEngineA* GPUEngineA::Allocate()
@ -6552,7 +6550,6 @@ void GPUEngineA::SetCustomFramebufferSize(size_t w, size_t h)
this->_captureWorkingB16 = newCaptureWorkingB16; this->_captureWorkingB16 = newCaptureWorkingB16;
this->_captureWorkingA32 = newCaptureWorkingA32; this->_captureWorkingA32 = newCaptureWorkingA32;
this->_captureWorkingB32 = newCaptureWorkingB32; this->_captureWorkingB32 = newCaptureWorkingB32;
gfx3d_Update3DFramebuffers(this->_3DFramebufferMain, this->_3DFramebuffer16);
const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo();
@ -8133,6 +8130,19 @@ GPUSubsystem::GPUSubsystem()
gfx3d_init(); gfx3d_init();
for (size_t line = 0; line < GPU_VRAM_BLOCK_LINES + 1; line++)
{
GPUEngineLineInfo &lineInfo = this->_lineInfo[line];
lineInfo.indexNative = line;
lineInfo.indexCustom = lineInfo.indexNative;
lineInfo.widthCustom = GPU_FRAMEBUFFER_NATIVE_WIDTH;
lineInfo.renderCount = 1;
lineInfo.pixelCount = GPU_FRAMEBUFFER_NATIVE_WIDTH;
lineInfo.blockOffsetNative = lineInfo.indexNative * GPU_FRAMEBUFFER_NATIVE_WIDTH;
lineInfo.blockOffsetCustom = lineInfo.indexCustom * GPU_FRAMEBUFFER_NATIVE_WIDTH;
}
_engineMain = GPUEngineA::Allocate(); _engineMain = GPUEngineA::Allocate();
_engineSub = GPUEngineB::Allocate(); _engineSub = GPUEngineB::Allocate();
@ -8443,6 +8453,11 @@ const NDSDisplayInfo& GPUSubsystem::GetDisplayInfo()
return this->_displayInfo; return this->_displayInfo;
} }
const GPUEngineLineInfo& GPUSubsystem::GetLineInfoAtIndex(size_t l)
{
return this->_lineInfo[l];
}
u32 GPUSubsystem::GetFPSRender3D() const u32 GPUSubsystem::GetFPSRender3D() const
{ {
return this->_render3DFrameCount; return this->_render3DFrameCount;
@ -8593,6 +8608,19 @@ void GPUSubsystem::SetCustomFramebufferSize(size_t w, size_t h)
_gpuDstToSrcSSSE3_u16_8e = newGpuDstToSrcSSSE3_u16_8e; _gpuDstToSrcSSSE3_u16_8e = newGpuDstToSrcSSSE3_u16_8e;
_gpuDstToSrcSSSE3_u32_4e = newGpuDstToSrcSSSE3_u32_4e; _gpuDstToSrcSSSE3_u32_4e = newGpuDstToSrcSSSE3_u32_4e;
for (size_t line = 0; line < GPU_VRAM_BLOCK_LINES + 1; line++)
{
GPUEngineLineInfo &lineInfo = this->_lineInfo[line];
lineInfo.indexNative = line;
lineInfo.indexCustom = _gpuCaptureLineIndex[lineInfo.indexNative];
lineInfo.widthCustom = w;
lineInfo.renderCount = _gpuCaptureLineCount[lineInfo.indexNative];
lineInfo.pixelCount = lineInfo.widthCustom * lineInfo.renderCount;
lineInfo.blockOffsetNative = lineInfo.indexNative * GPU_FRAMEBUFFER_NATIVE_WIDTH;
lineInfo.blockOffsetCustom = lineInfo.indexCustom * lineInfo.widthCustom;
}
CurrentRenderer->RenderFinish(); CurrentRenderer->RenderFinish();
CurrentRenderer->SetRenderNeedsFinish(false); CurrentRenderer->SetRenderNeedsFinish(false);
@ -9153,8 +9181,8 @@ u8* GPUSubsystem::_DownscaleAndConvertForSavestate(const NDSDisplayID displayID,
isIntermediateBufferMissing = (intermediateBuffer == NULL); isIntermediateBufferMissing = (intermediateBuffer == NULL);
if (!isIntermediateBufferMissing) if (!isIntermediateBufferMissing)
{ {
const u32 *src = (u32 *)this->_displayInfo.customBuffer[displayID]; const u32 *__restrict src = (u32 *__restrict)this->_displayInfo.customBuffer[displayID];
u32 *dst = (u32 *)intermediateBuffer; u32 *__restrict dst = (u32 *__restrict)intermediateBuffer;
for (size_t l = 0; l < GPU_FRAMEBUFFER_NATIVE_HEIGHT; l++) for (size_t l = 0; l < GPU_FRAMEBUFFER_NATIVE_HEIGHT; l++)
{ {
@ -9650,3 +9678,7 @@ template void GPUEngineBase::ParseReg_BGnY<GPULayerID_BG3>();
template void GPUSubsystem::RenderLine<NDSColorFormat_BGR555_Rev>(const size_t l); template void GPUSubsystem::RenderLine<NDSColorFormat_BGR555_Rev>(const size_t l);
template void GPUSubsystem::RenderLine<NDSColorFormat_BGR666_Rev>(const size_t l); template void GPUSubsystem::RenderLine<NDSColorFormat_BGR666_Rev>(const size_t l);
template void GPUSubsystem::RenderLine<NDSColorFormat_BGR888_Rev>(const size_t l); template void GPUSubsystem::RenderLine<NDSColorFormat_BGR888_Rev>(const size_t l);
// These functions are used in gfx3d.cpp
template void CopyLineExpandHinted<0xFFFF, false, true, 4>(const GPUEngineLineInfo &lineInfo, const void *__restrict srcBuffer, void *__restrict dstBuffer);
template void CopyLineReduceHinted<0xFFFF, false, true, 4>(const GPUEngineLineInfo &lineInfo, const void *__restrict srcBuffer, void *__restrict dstBuffer);

View File

@ -1763,6 +1763,7 @@ private:
GPUEngineB *_engineSub; GPUEngineB *_engineSub;
NDSDisplay *_display[2]; NDSDisplay *_display[2];
float _backlightIntensityTotal[2]; float _backlightIntensityTotal[2];
GPUEngineLineInfo _lineInfo[GPU_VRAM_BLOCK_LINES + 1];
int _pending3DRendererID; int _pending3DRendererID;
bool _needChange3DRenderer; bool _needChange3DRenderer;
@ -1797,6 +1798,7 @@ public:
void ForceFrameStop(); void ForceFrameStop();
const NDSDisplayInfo& GetDisplayInfo(); // Frontends need to call this whenever they need to read the video buffers from the emulator core const NDSDisplayInfo& GetDisplayInfo(); // Frontends need to call this whenever they need to read the video buffers from the emulator core
const GPUEngineLineInfo& GetLineInfoAtIndex(size_t l);
u32 GetFPSRender3D() const; u32 GetFPSRender3D() const;
GPUEngineA* GetEngineMain(); GPUEngineA* GetEngineMain();
@ -1898,6 +1900,20 @@ public:
void SetClientData(void *clientData); void SetClientData(void *clientData);
}; };
template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE>
void CopyLineExpandHinted(const void *__restrict srcBuffer, const size_t srcLineIndex,
void *__restrict dstBuffer, const size_t dstLineIndex, const size_t dstLineWidth, const size_t dstLineCount);
template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE>
void CopyLineExpandHinted(const GPUEngineLineInfo &lineInfo, const void *__restrict srcBuffer, void *__restrict dstBuffer);
template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE>
void CopyLineReduceHinted(const void *__restrict srcBuffer, const size_t srcLineIndex, const size_t srcLineWidth,
void *__restrict dstBuffer, const size_t dstLineIndex);
template <s32 INTEGERSCALEHINT, bool USELINEINDEX, bool NEEDENDIANSWAP, size_t ELEMENTSIZE>
void CopyLineReduceHinted(const GPUEngineLineInfo &lineInfo, const void *__restrict srcBuffer, void *__restrict dstBuffer);
extern GPUSubsystem *GPU; extern GPUSubsystem *GPU;
extern MMU_struct MMU; extern MMU_struct MMU;

View File

@ -283,8 +283,7 @@ static float normalTable[1024];
#define fix10_2float(v) (((float)((s32)(v))) / (float)(1<<9)) #define fix10_2float(v) (((float)((s32)(v))) / (float)(1<<9))
// Color buffer that is filled by the 3D renderer and is read by the GPU engine. // Color buffer that is filled by the 3D renderer and is read by the GPU engine.
static FragmentColor *_gfx3d_colorMain = NULL; static CACHE_ALIGN FragmentColor _gfx3d_savestateBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT];
static u16 *_gfx3d_color16 = NULL;
// Matrix stack handling // Matrix stack handling
//TODO: decouple stack pointers from matrix stack type //TODO: decouple stack pointers from matrix stack type
@ -609,6 +608,7 @@ void gfx3d_reset()
memset(gxPIPE.param, 0, sizeof(gxPIPE.param)); memset(gxPIPE.param, 0, sizeof(gxPIPE.param));
memset(colorRGB, 0, sizeof(colorRGB)); memset(colorRGB, 0, sizeof(colorRGB));
memset(&tempVertInfo, 0, sizeof(tempVertInfo)); memset(&tempVertInfo, 0, sizeof(tempVertInfo));
memset(_gfx3d_savestateBuffer, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(u32));
MatrixInit(mtxCurrent[MATRIXMODE_PROJECTION]); MatrixInit(mtxCurrent[MATRIXMODE_PROJECTION]);
MatrixInit(mtxCurrent[MATRIXMODE_POSITION]); MatrixInit(mtxCurrent[MATRIXMODE_POSITION]);
@ -2717,24 +2717,54 @@ SFORMAT SF_GFX3D[]={
{ "GTVC", 4, 1, &tempVertInfo.count}, { "GTVC", 4, 1, &tempVertInfo.count},
{ "GTVM", 4, 4, tempVertInfo.map}, { "GTVM", 4, 4, tempVertInfo.map},
{ "GTVF", 4, 1, &tempVertInfo.first}, { "GTVF", 4, 1, &tempVertInfo.first},
{ "G3CX", 1, 4*GPU_FRAMEBUFFER_NATIVE_WIDTH*GPU_FRAMEBUFFER_NATIVE_HEIGHT, _gfx3d_colorMain}, { "G3CX", 1, 4*GPU_FRAMEBUFFER_NATIVE_WIDTH*GPU_FRAMEBUFFER_NATIVE_HEIGHT, _gfx3d_savestateBuffer},
{ 0 } { 0 }
}; };
void gfx3d_Update3DFramebuffers(FragmentColor *framebufferMain, u16 *framebuffer16)
{
_gfx3d_colorMain = framebufferMain;
_gfx3d_color16 = framebuffer16;
}
//-------------savestate //-------------savestate
void gfx3d_savestate(EMUFILE &os) void gfx3d_PrepareSaveStateBufferWrite()
{ {
if (CurrentRenderer->GetRenderNeedsFinish()) if (CurrentRenderer->GetRenderNeedsFinish())
{ {
GPU->ForceRender3DFinishAndFlush(true); GPU->ForceRender3DFinishAndFlush(true);
} }
const size_t w = CurrentRenderer->GetFramebufferWidth();
const size_t h = CurrentRenderer->GetFramebufferHeight();
if ( (w == GPU_FRAMEBUFFER_NATIVE_WIDTH) && (h == GPU_FRAMEBUFFER_NATIVE_HEIGHT) ) // Framebuffer is at the native size
{
if (CurrentRenderer->GetColorFormat() == NDSColorFormat_BGR666_Rev)
{
ColorspaceConvertBuffer6665To8888<false, false>((u32 *)CurrentRenderer->GetFramebuffer(), (u32 *)_gfx3d_savestateBuffer, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT);
}
else
{
ColorspaceCopyBuffer32<false, false>((u32 *)CurrentRenderer->GetFramebuffer(), (u32 *)_gfx3d_savestateBuffer, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT);
}
}
else // Framebuffer is at a custom size
{
const FragmentColor *__restrict src = CurrentRenderer->GetFramebuffer();
FragmentColor *__restrict dst = _gfx3d_savestateBuffer;
for (size_t l = 0; l < GPU_FRAMEBUFFER_NATIVE_HEIGHT; l++)
{
const GPUEngineLineInfo &lineInfo = GPU->GetLineInfoAtIndex(l);
CopyLineReduceHinted<0xFFFF, false, true, 4>(lineInfo, src, dst);
src += lineInfo.pixelCount;
dst += GPU_FRAMEBUFFER_NATIVE_WIDTH;
}
if (CurrentRenderer->GetColorFormat() == NDSColorFormat_BGR666_Rev)
{
ColorspaceConvertBuffer6665To8888<false, false>((u32 *)_gfx3d_savestateBuffer, (u32 *)_gfx3d_savestateBuffer, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT);
}
}
}
void gfx3d_savestate(EMUFILE &os)
{
//version //version
os.write_32LE(4); os.write_32LE(4);
@ -2905,6 +2935,59 @@ bool gfx3d_loadstate(EMUFILE &is, int size)
return true; return true;
} }
void gfx3d_FinishLoadStateBufferRead()
{
const Render3DDeviceInfo &deviceInfo = CurrentRenderer->GetDeviceInfo();
switch (deviceInfo.renderID)
{
case RENDERID_NULL:
memset(CurrentRenderer->GetFramebuffer(), 0, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(FragmentColor));
break;
case RENDERID_SOFTRASTERIZER:
{
const size_t w = CurrentRenderer->GetFramebufferWidth();
const size_t h = CurrentRenderer->GetFramebufferHeight();
if ( (w == GPU_FRAMEBUFFER_NATIVE_WIDTH) && (h == GPU_FRAMEBUFFER_NATIVE_HEIGHT) ) // Framebuffer is at the native size
{
if (CurrentRenderer->GetColorFormat() == NDSColorFormat_BGR666_Rev)
{
ColorspaceConvertBuffer8888To6665<false, false>((u32 *)_gfx3d_savestateBuffer, (u32 *)CurrentRenderer->GetFramebuffer(), GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT);
}
else
{
ColorspaceCopyBuffer32<false, false>((u32 *)_gfx3d_savestateBuffer, (u32 *)CurrentRenderer->GetFramebuffer(), GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT);
}
}
else // Framebuffer is at a custom size
{
if (CurrentRenderer->GetColorFormat() == NDSColorFormat_BGR666_Rev)
{
ColorspaceConvertBuffer8888To6665<false, false>((u32 *)_gfx3d_savestateBuffer, (u32 *)_gfx3d_savestateBuffer, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT);
}
const FragmentColor *__restrict src = _gfx3d_savestateBuffer;
FragmentColor *__restrict dst = CurrentRenderer->GetFramebuffer();
for (size_t l = 0; l < GPU_FRAMEBUFFER_NATIVE_HEIGHT; l++)
{
const GPUEngineLineInfo &lineInfo = GPU->GetLineInfoAtIndex(l);
CopyLineExpandHinted<0xFFFF, false, true, 4>(lineInfo, src, dst);
src += GPU_FRAMEBUFFER_NATIVE_WIDTH;
dst += lineInfo.pixelCount;
}
}
break;
}
default:
// Do nothing. Loading the 3D framebuffer is unsupported on this 3D renderer.
break;
}
}
void gfx3d_parseCurrentDISP3DCNT() void gfx3d_parseCurrentDISP3DCNT()
{ {
const IOREG_DISP3DCNT &DISP3DCNT = gfx3d.state.savedDISP3DCNT; const IOREG_DISP3DCNT &DISP3DCNT = gfx3d.state.savedDISP3DCNT;

View File

@ -636,9 +636,10 @@ void gfx3d_glGetLightColor(const size_t index, u32 &dst);
struct SFORMAT; struct SFORMAT;
extern SFORMAT SF_GFX3D[]; extern SFORMAT SF_GFX3D[];
void gfx3d_Update3DFramebuffers(FragmentColor *framebufferMain, u16 *framebuffer16); void gfx3d_PrepareSaveStateBufferWrite();
void gfx3d_savestate(EMUFILE &os); void gfx3d_savestate(EMUFILE &os);
bool gfx3d_loadstate(EMUFILE &is, int size); bool gfx3d_loadstate(EMUFILE &is, int size);
void gfx3d_FinishLoadStateBufferRead();
void gfx3d_ClearStack(); void gfx3d_ClearStack();

View File

@ -1061,6 +1061,7 @@ static void writechunks(EMUFILE &os)
save_time = tm.get_Ticks(); save_time = tm.get_Ticks();
gfx3d_PrepareSaveStateBufferWrite();
wifiHandler->PrepareSaveStateWrite(); wifiHandler->PrepareSaveStateWrite();
savestate_WriteChunk(os,1,SF_ARM9); savestate_WriteChunk(os,1,SF_ARM9);
@ -1184,7 +1185,13 @@ static bool ReadStateChunks(EMUFILE &is, s32 totalsize)
} }
if (chunkError) if (chunkError)
{
msgbox->warn("There was an error loading the savestate. Your game session is probably corrupt now."); msgbox->warn("There was an error loading the savestate. Your game session is probably corrupt now.");
}
else
{
gfx3d_FinishLoadStateBufferRead();
}
if (haveInfo) if (haveInfo)
{ {