mirror of https://github.com/stella-emu/stella.git
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:
parent
47b4007bcb
commit
20eb97ce14
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
for(auto it = myStateList.last(); it != myStateList.first(); --it)
|
// iterate from last but one to first but one
|
||||||
|
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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
Loading…
Reference in New Issue