From d2183af37125cfad26766cf1afc64ad9c3678bf1 Mon Sep 17 00:00:00 2001 From: OV2 Date: Tue, 7 Aug 2018 18:36:43 +0200 Subject: [PATCH] libretro: add fast snapshot support --- libretro/libretro.cpp | 14 +++++ ppu.cpp | 14 +++++ ppu.h | 1 + snapshot.cpp | 135 +++++++++++++++++++++++++++++++++++++----- snes9x.h | 3 +- 5 files changed, 150 insertions(+), 17 deletions(-) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index f7e0b251..2dc6af1d 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -1372,6 +1372,13 @@ size_t retro_serialize_size() bool retro_serialize(void *data, size_t size) { + int result = -1; + bool okay = false; + okay = environ_cb(RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE, &result); + if (okay) + { + Settings.FastSavestates = 0 != (result & 4); + } if (S9xFreezeGameMem((uint8_t*)data,size) == FALSE) return false; @@ -1380,6 +1387,13 @@ bool retro_serialize(void *data, size_t size) bool retro_unserialize(const void* data, size_t size) { + int result = -1; + bool okay = false; + okay = environ_cb(RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE, &result); + if (okay) + { + Settings.FastSavestates = 0 != (result & 4); + } if (S9xUnfreezeGameMem((const uint8_t*)data,size) != SUCCESS) return false; diff --git a/ppu.cpp b/ppu.cpp index d8c0bd72..deed5cf4 100644 --- a/ppu.cpp +++ b/ppu.cpp @@ -1937,6 +1937,20 @@ void S9xResetPPU (void) PPU.M7byte = 0; } +void S9xResetPPUFast (void) +{ + PPU.RecomputeClipWindows = TRUE; + IPPU.ColorsChanged = TRUE; + IPPU.OBJChanged = TRUE; + memset(IPPU.TileCached[TILE_2BIT], 0, MAX_2BIT_TILES); + memset(IPPU.TileCached[TILE_4BIT], 0, MAX_4BIT_TILES); + memset(IPPU.TileCached[TILE_8BIT], 0, MAX_8BIT_TILES); + memset(IPPU.TileCached[TILE_2BIT_EVEN], 0, MAX_2BIT_TILES); + memset(IPPU.TileCached[TILE_2BIT_ODD], 0, MAX_2BIT_TILES); + memset(IPPU.TileCached[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES); + memset(IPPU.TileCached[TILE_4BIT_ODD], 0, MAX_4BIT_TILES); +} + void S9xSoftResetPPU (void) { S9xControlsSoftReset(); diff --git a/ppu.h b/ppu.h index 6346d325..2ad0aa15 100644 --- a/ppu.h +++ b/ppu.h @@ -384,6 +384,7 @@ extern struct SPPU PPU; extern struct InternalPPU IPPU; void S9xResetPPU (void); +void S9xResetPPUFast (void); void S9xSoftResetPPU (void); void S9xSetPPU (uint8, uint16); uint8 S9xGetPPU (uint16); diff --git a/snapshot.cpp b/snapshot.cpp index 468cf781..9d5a0c22 100644 --- a/snapshot.cpp +++ b/snapshot.cpp @@ -1181,6 +1181,8 @@ static int UnfreezeStructCopy (STREAM, const char *, uint8 **, FreezeData *, int static void UnfreezeStructFromCopy (void *, FreezeData *, int, uint8 *, int); static void FreezeBlock (STREAM, const char *, uint8 *, int); static void FreezeStruct (STREAM, const char *, void *, FreezeData *, int); +static bool CheckBlockName(STREAM stream, const char *name, int &len); +static void SkipBlockWithName(STREAM stream, const char *name); void S9xResetSaveTimer (bool8 dontsave) @@ -1469,6 +1471,8 @@ void S9xFreezeToStream (STREAM stream) int S9xUnfreezeFromStream (STREAM stream) { + const bool8 fast = Settings.FastSavestates; + int result = SUCCESS; int version, len; char buffer[PATH_MAX + 1]; @@ -1535,19 +1539,31 @@ int S9xUnfreezeFromStream (STREAM stream) if (result != SUCCESS) break; - result = UnfreezeBlockCopy (stream, "VRA", &local_vram, 0x10000); + if (fast) + result = UnfreezeBlock(stream, "VRA", Memory.VRAM, 0x10000); + else + result = UnfreezeBlockCopy(stream, "VRA", &local_vram, 0x10000); if (result != SUCCESS) break; - result = UnfreezeBlockCopy (stream, "RAM", &local_ram, 0x20000); + if (fast) + result = UnfreezeBlock(stream, "RAM", Memory.RAM, 0x20000); + else + result = UnfreezeBlockCopy(stream, "RAM", &local_ram, 0x20000); if (result != SUCCESS) break; - result = UnfreezeBlockCopy (stream, "SRA", &local_sram, 0x20000); + if (fast) + result = UnfreezeBlock(stream, "SRA", Memory.SRAM, 0x20000); + else + result = UnfreezeBlockCopy (stream, "SRA", &local_sram, 0x20000); if (result != SUCCESS) break; - result = UnfreezeBlockCopy (stream, "FIL", &local_fillram, 0x8000); + if (fast) + result = UnfreezeBlock(stream, "FIL", Memory.FillRAM, 0x8000); + else + result = UnfreezeBlockCopy(stream, "FIL", &local_fillram, 0x8000); if (result != SUCCESS) break; @@ -1587,9 +1603,19 @@ int S9xUnfreezeFromStream (STREAM stream) if (result != SUCCESS && Settings.DSP == 4) break; - result = UnfreezeBlockCopy (stream, "CX4", &local_cx4_data, 8192); - if (result != SUCCESS && Settings.C4) - break; + if (Settings.C4) + { + if (fast) + result = UnfreezeBlock(stream, "CX4", Memory.C4RAM, 8192); + else + result = UnfreezeBlockCopy(stream, "CX4", &local_cx4_data, 8192); + if (result != SUCCESS) + break; + } + else + { + SkipBlockWithName(stream, "CX4"); + } result = UnfreezeStructCopy(stream, "ST0", &local_st010, SnapST010, COUNT(SnapST010), version); if (result != SUCCESS && Settings.SETA == ST_010) @@ -1599,9 +1625,19 @@ int S9xUnfreezeFromStream (STREAM stream) if (result != SUCCESS && Settings.OBC1) break; - result = UnfreezeBlockCopy (stream, "OBM", &local_obc1_data, 8192); - if (result != SUCCESS && Settings.OBC1) - break; + if (Settings.OBC1) + { + if (fast) + result = UnfreezeBlock(stream, "OBM", Memory.OBC1RAM, 8192); + else + result = UnfreezeBlockCopy(stream, "OBM", &local_obc1_data, 8192); + if (result != SUCCESS) + break; + } + else + { + SkipBlockWithName(stream, "OBM"); + } result = UnfreezeStructCopy(stream, "S71", &local_spc7110, SnapSPC7110Snap, COUNT(SnapSPC7110Snap), version); if (result != SUCCESS && Settings.SPC7110) @@ -1664,7 +1700,15 @@ int S9xUnfreezeFromStream (STREAM stream) uint32 old_flags = CPU.Flags; uint32 sa1_old_flags = SA1.Flags; - S9xReset(); + if (fast) + { + S9xResetPPUFast(); + } + else + { + //Do not call this if you have written directly to "Memory." arrays + S9xReset(); + } UnfreezeStructFromCopy(&CPU, SnapCPU, COUNT(SnapCPU), local_cpu, version); @@ -1675,13 +1719,17 @@ int S9xUnfreezeFromStream (STREAM stream) struct SDMASnapshot dma_snap; UnfreezeStructFromCopy(&dma_snap, SnapDMA, COUNT(SnapDMA), local_dma, version); - memcpy(Memory.VRAM, local_vram, 0x10000); + if (local_vram) + memcpy(Memory.VRAM, local_vram, 0x10000); - memcpy(Memory.RAM, local_ram, 0x20000); + if (local_ram) + memcpy(Memory.RAM, local_ram, 0x20000); - memcpy(Memory.SRAM, local_sram, 0x20000); + if (local_sram) + memcpy(Memory.SRAM, local_sram, 0x20000); - memcpy(Memory.FillRAM, local_fillram, 0x8000); + if (local_fillram) + memcpy(Memory.FillRAM, local_fillram, 0x8000); if(version < SNAPSHOT_VERSION_BAPU) { printf("Using Blargg APU snapshot loading (snapshot version %d, current is %d)\n...", version, SNAPSHOT_VERSION); @@ -2092,6 +2140,51 @@ static void FreezeBlock (STREAM stream, const char *name, uint8 *block, int size WRITE_STREAM(block, size, stream); } +static bool CheckBlockName(STREAM stream, const char *name, int &len) +{ + char buffer[16]; + len = 0; + long rewind = FIND_STREAM(stream); + + size_t l = READ_STREAM(buffer, 11, stream); + buffer[l] = 0; + REVERT_STREAM(stream, FIND_STREAM(stream) - l, 0); + + if (buffer[4] == '-') + { + len = (((unsigned char)buffer[6]) << 24) + | (((unsigned char)buffer[7]) << 16) + | (((unsigned char)buffer[8]) << 8) + | (((unsigned char)buffer[9]) << 0); + } + else + len = atoi(buffer + 4); + + if (l != 11 || strncmp(buffer, name, 3) != 0 || buffer[3] != ':') + { + return false; + } + + if (len <= 0) + { + return false; + } + + return true; +} + +static void SkipBlockWithName(STREAM stream, const char *name) +{ + int len; + bool matchesName = CheckBlockName(stream, name, len); + if (matchesName) + { + long rewind = FIND_STREAM(stream); + rewind += len + 11; + REVERT_STREAM(stream, rewind, 0); + } +} + static int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int size) { char buffer[20]; @@ -2130,7 +2223,10 @@ static int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int siz len = size; } - memset(block, 0, size); + if (!Settings.FastSavestates) + { + memset(block, 0, size); + } if (READ_STREAM(block, len, stream) != (unsigned int) len) { @@ -2157,6 +2253,13 @@ static int UnfreezeBlockCopy (STREAM stream, const char *name, uint8 **block, in { int result; + //check name first to avoid memory allocation + int blockLength; + if (!CheckBlockName(stream, name, blockLength)) + { + return 0; + } + *block = new uint8[size]; result = UnfreezeBlock(stream, name, *block, size); diff --git a/snes9x.h b/snes9x.h index 2dd3be55..61fdbc4a 100644 --- a/snes9x.h +++ b/snes9x.h @@ -476,7 +476,8 @@ struct SSettings bool8 TakeScreenshot; int8 StretchScreenshots; bool8 SnapshotScreenshots; - char InitialSnapshotFilename[PATH_MAX + 1]; + char InitialSnapshotFilename[PATH_MAX + 1]; + bool8 FastSavestates; bool8 ApplyCheats; bool8 NoPatch;