From e2301dfd5ed2c8432b8d2ff2b21470f1b811fed9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 Dec 2017 19:15:09 +0100 Subject: [PATCH] fine tuning on interval factor and state compression rewind now displayed immediately (instead of "Paused") two initial rewinds in continuous rewind mode fixed Horizon widget disabled when Uncompressed size == Buffer size fixed minimum Interval --- docs/index.html | 7 +++++-- src/common/RewindManager.cxx | 38 ++++++++++++++++++++++-------------- src/common/RewindManager.hxx | 3 ++- src/common/StateManager.cxx | 2 +- src/emucore/EventHandler.cxx | 10 ++++++---- src/emucore/FrameBuffer.cxx | 8 +++++++- src/emucore/FrameBuffer.hxx | 5 +++++ src/emucore/Settings.cxx | 4 ++-- src/gui/DeveloperDialog.cxx | 2 ++ 9 files changed, 53 insertions(+), 26 deletions(-) diff --git a/docs/index.html b/docs/index.html index d7d340e30..8bb086b80 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3107,9 +3107,12 @@ Defines the horizon of the rewind buffer. A large horizon allows going back further in time. To reach the horizon, save states - will be compressed. This means that more and more intermediate + will be compressed (*). This means that more and more intermediate states will be removed and the interval between save states - becomes larger the further they are back in time. + becomes larger the further they are back in time. The very first + save state will not be removed.
+ (*) Compresion only works if 'Uncompressed size' is smaller than + 'Buffer size'. -plr.rewind.horizon
-dev.rewind.horizon diff --git a/src/common/RewindManager.cxx b/src/common/RewindManager.cxx index 4a2d85ab9..f2314645c 100644 --- a/src/common/RewindManager.cxx +++ b/src/common/RewindManager.cxx @@ -36,6 +36,8 @@ RewindManager::RewindManager(OSystem& system, StateManager& statemgr) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RewindManager::setup() { + myLastContinuousAdd = false; + string prefix = myOSystem.settings().getBool("dev.settings") ? "dev." : "plr."; mySize = myOSystem.settings().getInt(prefix + "rewind.size"); @@ -55,20 +57,22 @@ void RewindManager::setup() myHorizon = HORIZON_CYCLES[i]; // calc interval growth factor + // this factor defines the backward horizon const double MAX_FACTOR = 1E8; double minFactor = 0, maxFactor = MAX_FACTOR; + myFactor = 1; - while(true) + while(myUncompressed < mySize) { double interval = myInterval; - double cycleSum = interval * myUncompressed; + double cycleSum = interval * (myUncompressed + 1); // calculate nextCycles factor myFactor = (minFactor + maxFactor) / 2; // horizon not reachable? if(myFactor == MAX_FACTOR) break; - // sum up interval cycles - for(uInt32 i = myUncompressed; i < mySize; ++i) + // sum up interval cycles (first and last state are not compressed) + for(uInt32 i = myUncompressed + 1; i < mySize - 1; ++i) { interval *= myFactor; cycleSum += interval; @@ -119,6 +123,7 @@ bool RewindManager::addState(const string& message, bool continuous) state.cycles = myOSystem.console().tia().cycles(); //state.count = count++; //cerr << "add " << state.count << endl; + myLastContinuousAdd = continuous; return true; } return false; @@ -129,15 +134,17 @@ bool RewindManager::rewindState() { if(!atFirst()) { - RewindState& lastState = myStateList.current(); - + if (!myLastContinuousAdd) // Set internal current iterator to previous state (back in time), // since we will now processed this state - myStateList.moveToPrevious(); + myStateList.moveToPrevious(); + myLastContinuousAdd = false; + + //RewindState& lastState = myStateList.current(); RewindState& state = myStateList.current(); Serializer& s = state.data; - string message = getMessage(state, lastState); + string message = getMessage(state); //cerr << "rewind " << state.count << endl; s.rewind(); // rewind Serializer internal buffers @@ -163,7 +170,7 @@ bool RewindManager::unwindState() RewindState& state = myStateList.current(); Serializer& s = state.data; - string message = getMessage(state, state); + string message = getMessage(state); //cerr << "unwind " << state.count << endl; s.rewind(); // rewind Serializer internal buffers @@ -182,8 +189,8 @@ bool RewindManager::unwindState() void RewindManager::compressStates() { uInt64 currentCycles = myOSystem.console().tia().cycles(); - double expectedCycles = myInterval * (1*0 + myFactor); - double maxError = 0; + double expectedCycles = myInterval * myFactor * (1 + myFactor); + double maxError = 1; uInt32 removeIdx = 0; uInt32 idx = myStateList.size() - 2; @@ -223,17 +230,18 @@ void RewindManager::compressStates() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string RewindManager::getMessage(RewindState& state, RewindState& lastState) +string RewindManager::getMessage(RewindState& state) { Int64 diff = myOSystem.console().tia().cycles() - state.cycles; stringstream message; message << (diff >= 0 ? "Rewind" : "Unwind") << " " << getUnitString(diff); - // add optional message (TODO: when smart removal works, we have to do something smart with this part too) - if(!lastState.message.empty()) - message << " (" << lastState.message << ")"; message << " [" << myStateList.currentIdx() << "/" << myStateList.size() << "]"; + // add optional message + if(!state.message.empty()) + message << " (" << state.message << ")"; + return message.str(); } diff --git a/src/common/RewindManager.hxx b/src/common/RewindManager.hxx index 53fef1b7d..f4e67debb 100644 --- a/src/common/RewindManager.hxx +++ b/src/common/RewindManager.hxx @@ -144,6 +144,7 @@ class RewindManager uInt32 myInterval; uInt64 myHorizon; double myFactor; + bool myLastContinuousAdd; struct RewindState { Serializer data; @@ -168,7 +169,7 @@ class RewindManager void compressStates(); - string getMessage(RewindState& state, RewindState& lastState); + string getMessage(RewindState& state); private: // Following constructors and assignment operators not supported diff --git a/src/common/StateManager.cxx b/src/common/StateManager.cxx index a279e23f6..d31c56aaf 100644 --- a/src/common/StateManager.cxx +++ b/src/common/StateManager.cxx @@ -161,7 +161,7 @@ void StateManager::update() switch(myActiveMode) { case Mode::Rewind: - myRewindManager->addState("1 frame", true); + myRewindManager->addState("continuous rewind", true); break; #if 0 diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 943b3f883..ac3957a8d 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -299,13 +299,15 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state) switch(key) { case KBDK_LEFT: // Alt-left rewinds states - if(myOSystem.state().rewindState() && myState != S_PAUSE) - setEventState(S_PAUSE); + myOSystem.frameBuffer().resetPauseDelay(); + setEventState(S_PAUSE); + myOSystem.state().rewindState(); break; case KBDK_RIGHT: // Alt-right unwinds states - if(myOSystem.state().unwindState() && myState != S_PAUSE) - setEventState(S_PAUSE); + myOSystem.frameBuffer().resetPauseDelay(); + setEventState(S_PAUSE); + myOSystem.state().unwindState(); break; default: diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 5b635c52a..ed1da3185 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -301,7 +301,7 @@ void FrameBuffer::update() // Show a pause message immediately and then every 7 seconds if (myPausedCount-- <= 0) { - myPausedCount = uInt32(7 * myOSystem.frameRate()); + resetPauseDelay(); showMessage("Paused", kMiddleCenter); } break; // S_PAUSE @@ -471,6 +471,12 @@ inline void FrameBuffer::drawMessage() myMsg.enabled = false; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FrameBuffer::resetPauseDelay() +{ + myPausedCount = uInt32(7 * myOSystem.frameRate()); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - shared_ptr FrameBuffer::allocateSurface(int w, int h, const uInt32* data) { diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 12f0e038d..7114ca4b0 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -144,6 +144,11 @@ class FrameBuffer */ void enableMessages(bool enable); + /** + Reset 'Paused' display delay counter + */ + void resetPauseDelay(); + /** Allocate a new surface. The FrameBuffer class takes all responsibility for freeing this surface (ie, other classes must not delete it directly). diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 6a312e01a..4943d5003 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -329,11 +329,11 @@ void Settings::validate() i = getInt("dev.rewind.uncompressed"); if(i < 0 || i > size) setInternal("dev.rewind.uncompressed", size); - i = getInt("dev.rewind.interval"); + /*i = getInt("dev.rewind.interval"); if(i < 0 || i > 5) setInternal("dev.rewind.interval", 0); i = getInt("dev.rewind.horizon"); - if(i < 0 || i > 6) setInternal("dev.rewind.horizon", 1); + if(i < 0 || i > 6) setInternal("dev.rewind.horizon", 1);*/ i = getInt("plr.tv.jitter_recovery"); if(i < 1 || i > 20) setInternal("plr.tv.jitter_recovery", "10"); diff --git a/src/gui/DeveloperDialog.cxx b/src/gui/DeveloperDialog.cxx index 88b6ca927..fc48e4f39 100644 --- a/src/gui/DeveloperDialog.cxx +++ b/src/gui/DeveloperDialog.cxx @@ -999,6 +999,7 @@ void DeveloperDialog::handleSize() myUncompressedWidget->setValue(size); myStateIntervalWidget->setSelectedIndex(interval); myStateHorizonWidget->setSelectedIndex(i); + myStateHorizonWidget->setEnabled(size > uncompressed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1011,6 +1012,7 @@ void DeveloperDialog::handleUncompressed() if(size < uncompressed) myStateSizeWidget->setValue(uncompressed); + myStateHorizonWidget->setEnabled(size > uncompressed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -