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).
This commit is contained in:
Ilari Liusvaara 2012-07-15 09:40:34 +03:00
parent c10621e3b3
commit 03554f8722
2 changed files with 23 additions and 19 deletions

View file

@ -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 <ilari.liusvaara@elisanet.fi>
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);

View file

@ -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<unsigned char> 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<char*>(reinterpret_cast<const char*>(old_videobuf));
inf.mem = const_cast<char*>(reinterpret_cast<const char*>(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<char>& 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<char> 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<char> 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<uint32_t, uint32_t> get_scale_factors(uint32_t width, uint32_t height)