From 03554f8722f689b85dad9e456251231e21e0ed3b Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sun, 15 Jul 2012 09:40:34 +0300 Subject: [PATCH] Fix savestate-related bugs - Properly save and restore the framebuffer. Avoids display glitches one frame after loading. - Save and restore the base class of channel 4 LFSR (to avoid desyncs). --- ...ake-libgambatte-rerecording-friendly.patch | 15 ++++++----- src/core/gambatte.cpp | 27 ++++++++++--------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/libgambatte-patches/svn320/0001-Changes-to-make-libgambatte-rerecording-friendly.patch b/libgambatte-patches/svn320/0001-Changes-to-make-libgambatte-rerecording-friendly.patch index 5b1ec0d5..1a174790 100644 --- a/libgambatte-patches/svn320/0001-Changes-to-make-libgambatte-rerecording-friendly.patch +++ b/libgambatte-patches/svn320/0001-Changes-to-make-libgambatte-rerecording-friendly.patch @@ -1,4 +1,4 @@ -From 58e7bcf988a64733c22337e21b74b31d2de7b64b Mon Sep 17 00:00:00 2001 +From 0c061244bc907dc3f3202f62b771759105825b1f Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Thu, 12 Jul 2012 20:49:57 +0300 Subject: [PATCH] Changes to make libgambatte rerecording-friendly @@ -41,7 +41,7 @@ Subject: [PATCH] Changes to make libgambatte rerecording-friendly libgambatte/src/sound/channel3.cpp | 41 +++- libgambatte/src/sound/channel3.h | 27 ++- libgambatte/src/sound/channel4.cpp | 59 ++++-- - libgambatte/src/sound/channel4.h | 39 +++-- + libgambatte/src/sound/channel4.h | 40 +++-- libgambatte/src/sound/duty_unit.cpp | 34 +++- libgambatte/src/sound/duty_unit.h | 29 ++- libgambatte/src/sound/envelope_unit.cpp | 19 ++- @@ -66,7 +66,7 @@ Subject: [PATCH] Changes to make libgambatte rerecording-friendly libgambatte/src/video/ppu.h | 84 ++++++--- libgambatte/src/video/sprite_mapper.cpp | 17 +- libgambatte/src/video/sprite_mapper.h | 53 ++++-- - 62 files changed, 2150 insertions(+), 603 deletions(-) + 62 files changed, 2151 insertions(+), 603 deletions(-) create mode 100644 Makefile create mode 100644 libgambatte/Makefile create mode 100644 libgambatte/src/loadsave.cpp @@ -3504,7 +3504,7 @@ index 35c3c00..9d89db7 100644 + } diff --git a/libgambatte/src/sound/channel4.h b/libgambatte/src/sound/channel4.h -index 00b0b5a..cb923b8 100644 +index 00b0b5a..d52d9f7 100644 --- a/libgambatte/src/sound/channel4.h +++ b/libgambatte/src/sound/channel4.h @@ -24,6 +24,11 @@ @@ -3519,7 +3519,7 @@ index 00b0b5a..cb923b8 100644 namespace gambatte { -@@ -31,26 +36,32 @@ struct SaveState; +@@ -31,26 +36,33 @@ struct SaveState; class Channel4 { class Lfsr : public SoundUnit { @@ -3552,6 +3552,7 @@ index 00b0b5a..cb923b8 100644 - void reviveCounter(unsigned long cc); + void reviveCounter(unsigned cc); + void loadOrSave(loadsave& state) { ++ loadOrSave2(state); + state(backupCounter); + state(reg); + state(nr3); @@ -3560,7 +3561,7 @@ index 00b0b5a..cb923b8 100644 }; class Ch4MasterDisabler : public MasterDisabler { -@@ -70,9 +81,9 @@ class Channel4 { +@@ -70,9 +82,9 @@ class Channel4 { SoundUnit *nextEventUnit; @@ -3573,7 +3574,7 @@ index 00b0b5a..cb923b8 100644 unsigned char nr4; bool master; -@@ -86,15 +97,17 @@ public: +@@ -86,15 +98,17 @@ public: void setNr3(unsigned data) { lfsr.nr3Change(data, cycleCounter); /*setEvent();*/ } void setNr4(unsigned data); diff --git a/src/core/gambatte.cpp b/src/core/gambatte.cpp index 51a1b4db..5bc7d72a 100644 --- a/src/core/gambatte.cpp +++ b/src/core/gambatte.cpp @@ -13,6 +13,7 @@ #include "core/window.hpp" #include "library/pixfmt-rgb32.hpp" #include "library/string.hpp" +#include "library/serialization.hpp" #include "library/minmax.hpp" #include "library/framebuffer.hpp" #define HAVE_CSTDINT @@ -53,6 +54,7 @@ namespace gambatte::GB* instance; unsigned frame_overflow = 0; std::vector romdata; + uint32_t primary_framebuffer[160*144]; time_t walltime_fn() { @@ -95,6 +97,7 @@ namespace new(instance) gambatte::GB; instance->setInputGetter(&getinput); instance->set_walltime_fn(walltime_fn); + memset(primary_framebuffer, 0, sizeof(primary_framebuffer)); frame_overflow = 0; rtc_fixed = true; @@ -296,13 +299,9 @@ void core_emulate_frame() static uint32_t accumulator_r = 0; static unsigned accumulator_s = 0; uint32_t samplebuffer[SAMPLES_PER_FRAME + 2064]; - uint32_t videobuf[160*144]; - static uint32_t old_videobuf[160*144]; while(true) { unsigned samples_emitted = SAMPLES_PER_FRAME - frame_overflow; - long ret = instance->runFor(videobuf, 160, samplebuffer, samples_emitted); - if(ret >= 0) - memcpy(old_videobuf, videobuf, sizeof(old_videobuf)); + long ret = instance->runFor(primary_framebuffer, 160, samplebuffer, samples_emitted); for(unsigned i = 0; i < samples_emitted; i++) { uint32_t l = (int32_t)(int16_t)(samplebuffer[i]) + 32768; uint32_t r = (int32_t)(int16_t)(samplebuffer[i] >> 16) + 32768; @@ -327,7 +326,7 @@ void core_emulate_frame() } framebuffer_info inf; inf.type = &_pixel_format_rgb32; - inf.mem = const_cast(reinterpret_cast(old_videobuf)); + inf.mem = const_cast(reinterpret_cast(primary_framebuffer)); inf.physwidth = 160; inf.physheight = 144; inf.physstride = 640; @@ -458,23 +457,27 @@ function_ptr_command<> cmp_save2("do-cmp-save", "", "\n", []() throw(std::bad_al void core_serialize(std::vector& out) { instance->saveState(out); + size_t osize = out.size(); + out.resize(osize + 4 * sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0])); + for(size_t i = 0; i < sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]); i++) + write32ube(&out[osize + 4 * i], primary_framebuffer[i]); out.push_back(frame_overflow >> 8); out.push_back(frame_overflow); } void core_unserialize(const char* in, size_t insize) { + size_t foffset = insize - 2 - 4 * sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]); std::vector tmp; - tmp.resize(insize - 2); - memcpy(&tmp[0], in, insize - 2); + tmp.resize(foffset); + memcpy(&tmp[0], in, foffset); instance->loadState(tmp); + for(size_t i = 0; i < sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]); i++) + primary_framebuffer[i] = read32ube(&in[foffset + 4 * i]); + unsigned x1 = (unsigned char)in[insize - 2]; unsigned x2 = (unsigned char)in[insize - 1]; frame_overflow = x1 * 256 + x2; - std::vector cmpx; - core_serialize(cmpx); - if(cmpx.size() != insize || memcmp(&cmpx[0], in, insize)) - throw std::runtime_error("Loading and resaving won't roundtrip"); } std::pair get_scale_factors(uint32_t width, uint32_t height)