savestate position in list display in message added

compressStates loop fixed and slightly optimized
fixed minimal size value in Settings
This commit is contained in:
thrust26 2017-12-13 12:31:18 +01:00
parent 47b4007bcb
commit 20eb97ce14
4 changed files with 44 additions and 36 deletions

View File

@ -72,6 +72,19 @@ class LinkedObjectPool
*/ */
T& current() const { return *myCurrent; } T& current() const { return *myCurrent; }
/**
Returns current's position in the list
SLOW, but only required for messages
*/
uInt32 currentIdx() const {
iter it = myCurrent;
uInt32 idx = 1;
while(it-- != myList.begin()) idx++;
return idx;
}
/** /**
Does the 'current' iterator point to a valid node in the active list? Does the 'current' iterator point to a valid node in the active list?
This must be called before 'current()' is called. This must be called before 'current()' is called.

View File

@ -56,13 +56,13 @@ void RewindManager::setup()
// calc interval growth factor // calc interval growth factor
const double MAX_FACTOR = 1E8; const double MAX_FACTOR = 1E8;
double minFactor = 1, maxFactor = MAX_FACTOR; double minFactor = 0, maxFactor = MAX_FACTOR;
while(true) while(true)
{ {
double interval = myInterval; double interval = myInterval;
double cycleSum = interval * myUncompressed; double cycleSum = interval * myUncompressed;
// calculate next factor // calculate nextCycles factor
myFactor = (minFactor + maxFactor) / 2; myFactor = (minFactor + maxFactor) / 2;
// horizon not reachable? // horizon not reachable?
if(myFactor == MAX_FACTOR) if(myFactor == MAX_FACTOR)
@ -91,11 +91,11 @@ void RewindManager::setup()
bool RewindManager::addState(const string& message, bool continuous) bool RewindManager::addState(const string& message, bool continuous)
{ {
// only check for continuous rewind states, ignore for debugger // only check for continuous rewind states, ignore for debugger
if(continuous) if(continuous && myStateList.currentIsValid())
{ {
// check if the current state has the right interval from the last state // check if the current state has the right interval from the last state
RewindState& lastState = myStateList.current(); RewindState& lastState = myStateList.current();
if(myOSystem.console().tia().cycles() - lastState.cycle < myInterval) if(myOSystem.console().tia().cycles() - lastState.cycles < myInterval)
return false; return false;
} }
@ -116,7 +116,7 @@ bool RewindManager::addState(const string& message, bool continuous)
if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s)) if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s))
{ {
state.message = message; state.message = message;
state.cycle = myOSystem.console().tia().cycles(); state.cycles = myOSystem.console().tia().cycles();
//state.count = count++; //state.count = count++;
//cerr << "add " << state.count << endl; //cerr << "add " << state.count << endl;
return true; return true;
@ -157,7 +157,7 @@ bool RewindManager::unwindState()
{ {
if(!atLast()) if(!atLast())
{ {
// Set internal current iterator to next state (forward in time), // Set internal current iterator to nextCycles state (forward in time),
// since we've now processed this state // since we've now processed this state
myStateList.moveToNext(); myStateList.moveToNext();
@ -181,41 +181,35 @@ bool RewindManager::unwindState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RewindManager::compressStates() void RewindManager::compressStates()
{ {
//bool debugMode = myOSystem.eventHandler().state() == EventHandler::S_DEBUGGER; uInt64 currentCycles = myOSystem.console().tia().cycles();
double expectedCycles = myInterval * (1*0 + myFactor);
uInt64 currentCycle = myOSystem.console().tia().cycles(); double maxError = 0;
uInt64 lastCycle = currentCycle;
double expectedCycles = myInterval; // == cycles of 1 frame, TODO: use actual number of scanlines
double maxDelta = 0;
uInt32 removeIdx = 0; uInt32 removeIdx = 0;
uInt32 idx = myStateList.size() - 2;
uInt32 idx = myStateList.size() - 1; //cerr << "idx: " << idx << endl;
//cerr << "idx: " << idx << endl; // iterate from last but one to first but one
for(auto it = myStateList.last(); it != myStateList.first(); --it) for(auto it = myStateList.previous(myStateList.last()); it != myStateList.first(); --it)
{ {
if(idx < mySize - myUncompressed) if(idx < mySize - myUncompressed)
{ {
//cerr << *it << endl << endl; // debug code //cerr << *it << endl << endl; // debug code
expectedCycles *= myFactor; expectedCycles *= myFactor;
double expected = expectedCycles * (1 + myFactor); uInt64 prevCycles = myStateList.previous(it)->cycles;
uInt64 prev = myStateList.previous(it)->cycle; uInt64 nextCycles = myStateList.next(it)->cycles;
uInt64 next = myStateList.next(it)->cycle; double error = expectedCycles / (nextCycles - prevCycles);
if(next != lastCycle) //cerr << "prevCycles: " << prevCycles << ", nextCycles: " << nextCycles << ", error: " << error << endl;
lastCycle++;
double delta = expected / (next - prev);
//cerr << "prev: " << prev << ", next: " << next << ", delta: " << delta << endl;
if(delta > maxDelta) if(error > maxError)
{ {
maxDelta = delta; maxError = error;
removeIdx = idx; removeIdx = idx;
} }
} }
lastCycle = it->cycle;
--idx; --idx;
} }
if (maxDelta < 1) if (maxError < 1)
{ {
// the horizon is getting too big (can happen after changing settings) // the horizon is getting too big (can happen after changing settings)
myStateList.remove(1); // remove oldest but one myStateList.remove(1); // remove oldest but one
@ -231,7 +225,7 @@ void RewindManager::compressStates()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string RewindManager::getMessage(RewindState& state, RewindState& lastState) string RewindManager::getMessage(RewindState& state, RewindState& lastState)
{ {
Int64 diff = myOSystem.console().tia().cycles() - state.cycle; Int64 diff = myOSystem.console().tia().cycles() - state.cycles;
stringstream message; stringstream message;
message << (diff >= 0 ? "Rewind" : "Unwind") << " " << getUnitString(diff); message << (diff >= 0 ? "Rewind" : "Unwind") << " " << getUnitString(diff);
@ -239,6 +233,7 @@ string RewindManager::getMessage(RewindState& state, RewindState& lastState)
// add optional message (TODO: when smart removal works, we have to do something smart with this part too) // add optional message (TODO: when smart removal works, we have to do something smart with this part too)
if(!lastState.message.empty()) if(!lastState.message.empty())
message << " (" << lastState.message << ")"; message << " (" << lastState.message << ")";
message << " [" << myStateList.currentIdx() << "/" << myStateList.size() << "]";
return message.str(); return message.str();
} }
@ -263,7 +258,7 @@ string RewindManager::getUnitString(Int64 cycles)
for(i = 0; i < NUM_UNITS - 1; ++i) for(i = 0; i < NUM_UNITS - 1; ++i)
{ {
// use the lower unit up to twice the next unit, except for an exact match of the next unit // use the lower unit up to twice the nextCycles unit, except for an exact match of the nextCycles unit
// TODO: does the latter make sense, e.g. for ROMs with changing scanlines? // TODO: does the latter make sense, e.g. for ROMs with changing scanlines?
if(cycles < UNIT_CYCLES[i + 1] * 2 && cycles % UNIT_CYCLES[i + 1] != 0) if(cycles < UNIT_CYCLES[i + 1] * 2 && cycles % UNIT_CYCLES[i + 1] != 0)
break; break;

View File

@ -148,7 +148,7 @@ class RewindManager
struct RewindState { struct RewindState {
Serializer data; Serializer data;
string message; string message;
uInt64 cycle; uInt64 cycles;
//int count; // TODO - remove this //int count; // TODO - remove this
// We do nothing on object instantiation or copy // We do nothing on object instantiation or copy
@ -158,7 +158,7 @@ class RewindManager
// Output object info; used for debugging only // Output object info; used for debugging only
friend ostream& operator<<(ostream& os, const RewindState& s) { friend ostream& operator<<(ostream& os, const RewindState& s) {
return os << "msg: " << s.message << " cycle: " << s.cycle; // << " count: " << s.count; return os << "msg: " << s.message << " cycle: " << s.cycles; // << " count: " << s.count;
} }
}; };

View File

@ -320,10 +320,10 @@ void Settings::validate()
if(i < 1 || i > 20) setInternal("dev.tv.jitter_recovery", "2"); if(i < 1 || i > 20) setInternal("dev.tv.jitter_recovery", "2");
int size = getInt("dev.rewind.size"); int size = getInt("dev.rewind.size");
if(size < 100 || size > 1000) if(size < 20 || size > 1000)
{ {
setInternal("dev.rewind.size", 100); setInternal("dev.rewind.size", 20);
size = 100; size = 20;
} }
i = getInt("dev.rewind.uncompressed"); i = getInt("dev.rewind.uncompressed");
@ -339,10 +339,10 @@ void Settings::validate()
if(i < 1 || i > 20) setInternal("plr.tv.jitter_recovery", "10"); if(i < 1 || i > 20) setInternal("plr.tv.jitter_recovery", "10");
size = getInt("plr.rewind.size"); size = getInt("plr.rewind.size");
if(size < 100 || size > 1000) if(size < 20 || size > 1000)
{ {
setInternal("plr.rewind.size", 100); setInternal("plr.rewind.size", 20);
size = 100; size = 20;
} }
i = getInt("plr.rewind.uncompressed"); i = getInt("plr.rewind.uncompressed");