SRAM things (#970)

* Allow SRAMManager to save to/load from a buffer.

* Don't delete what doesn't exist. Don't create a thread that will do absolutely nothing.

* Update SRAMManager's SecondaryBuffer when loading a savestate.
This commit is contained in:
SuuperW
2021-02-22 19:46:02 -06:00
committed by GitHub
parent 58dd1ec580
commit 94dcc9523e
3 changed files with 58 additions and 19 deletions

View File

@ -111,6 +111,10 @@ void DoSavestate(Savestate* file)
file->Var8(&StatusReg); file->Var8(&StatusReg);
file->Var32(&Addr); file->Var32(&Addr);
// SRAMManager might now have an old buffer (or one from the future or alternate timeline!)
if (!file->Saving)
NDSCart_SRAMManager::RequestFlush();
} }
void LoadSave(const char* path, u32 type) void LoadSave(const char* path, u32 type)
@ -145,6 +149,7 @@ void LoadSave(const char* path, u32 type)
} }
} }
SRAMFileDirty = false;
NDSCart_SRAMManager::Setup(path, SRAM, SRAMLength); NDSCart_SRAMManager::Setup(path, SRAM, SRAMLength);
switch (SRAMLength) switch (SRAMLength)

View File

@ -45,13 +45,9 @@ namespace NDSCart_SRAMManager
u32 FlushVersion; u32 FlushVersion;
void FlushThreadFunc(); void FlushThreadFunc();
void FlushSecondaryBufferToFile();
bool Init() bool Init()
{ {
FlushThread = Platform::Thread_Create(FlushThreadFunc);
FlushThreadRunning = true;
SecondaryBufferLock = Platform::Mutex_Create(); SecondaryBufferLock = Platform::Mutex_Create();
return true; return true;
@ -64,10 +60,11 @@ namespace NDSCart_SRAMManager
FlushThreadRunning = false; FlushThreadRunning = false;
Platform::Thread_Wait(FlushThread); Platform::Thread_Wait(FlushThread);
Platform::Thread_Free(FlushThread); Platform::Thread_Free(FlushThread);
FlushSecondaryBufferToFile(); FlushSecondaryBuffer();
} }
delete SecondaryBuffer; if (SecondaryBuffer) delete SecondaryBuffer;
SecondaryBuffer = NULL;
Platform::Mutex_Free(SecondaryBufferLock); Platform::Mutex_Free(SecondaryBufferLock);
} }
@ -75,7 +72,7 @@ namespace NDSCart_SRAMManager
void Setup(const char* path, u8* buffer, u32 length) void Setup(const char* path, u8* buffer, u32 length)
{ {
// Flush SRAM in case there is unflushed data from previous state. // Flush SRAM in case there is unflushed data from previous state.
FlushSecondaryBufferToFile(); FlushSecondaryBuffer();
Platform::Mutex_Lock(SecondaryBufferLock); Platform::Mutex_Lock(SecondaryBufferLock);
@ -85,7 +82,7 @@ namespace NDSCart_SRAMManager
Buffer = buffer; Buffer = buffer;
Length = length; Length = length;
delete SecondaryBuffer; // Delete secondary buffer, there might be previous state. if(SecondaryBuffer) delete SecondaryBuffer; // Delete secondary buffer, there might be previous state.
SecondaryBuffer = new u8[length]; SecondaryBuffer = new u8[length];
SecondaryBufferLength = length; SecondaryBufferLength = length;
@ -95,6 +92,12 @@ namespace NDSCart_SRAMManager
TimeAtLastFlushRequest = 0; TimeAtLastFlushRequest = 0;
Platform::Mutex_Unlock(SecondaryBufferLock); Platform::Mutex_Unlock(SecondaryBufferLock);
if (path[0] != '\0')
{
FlushThread = Platform::Thread_Create(FlushThreadFunc);
FlushThreadRunning = true;
}
} }
void RequestFlush() void RequestFlush()
@ -121,27 +124,52 @@ namespace NDSCart_SRAMManager
continue; continue;
} }
FlushSecondaryBufferToFile(); FlushSecondaryBuffer();
} }
} }
void FlushSecondaryBufferToFile() void FlushSecondaryBuffer(u8* dst, s32 dstLength)
{ {
if (FlushVersion == PreviousFlushVersion) // When flushing to a file, there's no point in re-writing the exact same data.
{ if (!dst && !NeedsFlush()) return;
return; // When flushing to memory, we don't know if dst already has any data so we only check that we CAN flush.
} if (dst && dstLength < SecondaryBufferLength) return;
Platform::Mutex_Lock(SecondaryBufferLock); Platform::Mutex_Lock(SecondaryBufferLock);
FILE* f = Platform::OpenFile(Path, "wb"); if (dst)
if (f)
{ {
printf("NDS SRAM: Written\n"); memcpy(dst, SecondaryBuffer, SecondaryBufferLength);
fwrite(SecondaryBuffer, SecondaryBufferLength, 1, f); }
fclose(f); else
{
FILE* f = Platform::OpenFile(Path, "wb");
if (f)
{
printf("NDS SRAM: Written\n");
fwrite(SecondaryBuffer, SecondaryBufferLength, 1, f);
fclose(f);
}
} }
PreviousFlushVersion = FlushVersion; PreviousFlushVersion = FlushVersion;
TimeAtLastFlushRequest = 0; TimeAtLastFlushRequest = 0;
Platform::Mutex_Unlock(SecondaryBufferLock); Platform::Mutex_Unlock(SecondaryBufferLock);
} }
bool NeedsFlush()
{
return FlushVersion != PreviousFlushVersion;
}
void UpdateBuffer(u8* src, s32 srcLength)
{
if (!src || srcLength != Length) return;
// should we create a lock for the primary buffer? this method is not intended to be called from a secondary thread in the way Flush is
memcpy(Buffer, src, srcLength);
Platform::Mutex_Lock(SecondaryBufferLock);
memcpy(SecondaryBuffer, src, srcLength);
Platform::Mutex_Unlock(SecondaryBufferLock);
PreviousFlushVersion = FlushVersion;
}
} }

View File

@ -23,11 +23,17 @@
namespace NDSCart_SRAMManager namespace NDSCart_SRAMManager
{ {
extern u32 SecondaryBufferLength;
bool Init(); bool Init();
void DeInit(); void DeInit();
void Setup(const char* path, u8* buffer, u32 length); void Setup(const char* path, u8* buffer, u32 length);
void RequestFlush(); void RequestFlush();
bool NeedsFlush();
void FlushSecondaryBuffer(u8* dst = NULL, s32 dstLength = 0);
void UpdateBuffer(u8* src, s32 srcLength);
} }
#endif // NDSCART_SRAMMANAGER_H #endif // NDSCART_SRAMMANAGER_H