mirror of https://github.com/stella-emu/stella.git
Simplify FrameManager state machine, smarter ystart / vblank detection.
This commit is contained in:
parent
f0828c597d
commit
12fe183890
|
@ -22,8 +22,8 @@
|
||||||
#include "FrameManager.hxx"
|
#include "FrameManager.hxx"
|
||||||
|
|
||||||
enum Metrics: uInt32 {
|
enum Metrics: uInt32 {
|
||||||
vblankNTSC = 40,
|
vblankNTSC = 37,
|
||||||
vblankPAL = 48,
|
vblankPAL = 45,
|
||||||
kernelNTSC = 192,
|
kernelNTSC = 192,
|
||||||
kernelPAL = 228,
|
kernelPAL = 228,
|
||||||
overscanNTSC = 30,
|
overscanNTSC = 30,
|
||||||
|
@ -31,10 +31,11 @@ enum Metrics: uInt32 {
|
||||||
vsync = 3,
|
vsync = 3,
|
||||||
visibleOverscan = 20,
|
visibleOverscan = 20,
|
||||||
maxUnderscan = 10,
|
maxUnderscan = 10,
|
||||||
maxFramesWithoutVsync = 50,
|
|
||||||
tvModeDetectionTolerance = 20,
|
tvModeDetectionTolerance = 20,
|
||||||
modeDetectionInitialFrameskip = 5,
|
initialGarbageFrames = 10,
|
||||||
framesForModeConfirmation = 5
|
framesForModeConfirmation = 5,
|
||||||
|
maxVblankViolations = 2,
|
||||||
|
minStableVblankFrames = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr uInt32
|
static constexpr uInt32
|
||||||
|
@ -70,6 +71,11 @@ void FrameManager::reset()
|
||||||
myTotalFrames = 0;
|
myTotalFrames = 0;
|
||||||
myFramesInMode = 0;
|
myFramesInMode = 0;
|
||||||
myModeConfirmed = false;
|
myModeConfirmed = false;
|
||||||
|
myVblankMode = VblankMode::floating;
|
||||||
|
myLastVblankLines = 0;
|
||||||
|
myVblankViolations = 0;
|
||||||
|
myStableVblankFrames = 0;
|
||||||
|
myVblankViolated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -85,8 +91,7 @@ void FrameManager::nextLine()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::waitForFrameStart:
|
case State::waitForFrameStart:
|
||||||
if (myLineInState >= (myVblank ? myVblankLines : myVblankLines - Metrics::maxUnderscan))
|
nextLineInVsync();
|
||||||
setState(State::frame);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::frame:
|
case State::frame:
|
||||||
|
@ -100,6 +105,54 @@ void FrameManager::nextLine()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void FrameManager::nextLineInVsync()
|
||||||
|
{
|
||||||
|
bool shouldTransition = myLineInState >= (myVblank ? myVblankLines : myVblankLines - Metrics::maxUnderscan);
|
||||||
|
|
||||||
|
switch (myVblankMode) {
|
||||||
|
case VblankMode::floating:
|
||||||
|
|
||||||
|
if (shouldTransition) {
|
||||||
|
if (myTotalFrames > initialGarbageFrames && myLineInState == myLastVblankLines)
|
||||||
|
myStableVblankFrames++;
|
||||||
|
else
|
||||||
|
myStableVblankFrames = 0;
|
||||||
|
|
||||||
|
myLastVblankLines = myLineInState;
|
||||||
|
|
||||||
|
setState(State::frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myStableVblankFrames >= Metrics::minStableVblankFrames) {
|
||||||
|
myVblankMode = VblankMode::locked;
|
||||||
|
myVblankViolations = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VblankMode::locked:
|
||||||
|
|
||||||
|
if (myLineInState == myLastVblankLines) {
|
||||||
|
if (shouldTransition && !myVblankViolated)
|
||||||
|
myVblankViolations = 0;
|
||||||
|
else {
|
||||||
|
if (!myVblankViolated) myVblankViolations++;
|
||||||
|
myVblankViolated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(State::frame);
|
||||||
|
} else if (shouldTransition){
|
||||||
|
if (!myVblankViolated) myVblankViolations++;
|
||||||
|
myVblankViolated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myVblankViolations > Metrics::maxVblankViolations)
|
||||||
|
myVblankMode = VblankMode::floating;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void FrameManager::setVblank(bool vblank)
|
void FrameManager::setVblank(bool vblank)
|
||||||
{
|
{
|
||||||
|
@ -123,9 +176,8 @@ void FrameManager::setVsync(bool vsync)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::waitForVsyncEnd:
|
case State::waitForVsyncEnd:
|
||||||
if (!myVsync) {
|
if (!myVsync)
|
||||||
setState(State::waitForFrameStart);
|
setState(State::waitForFrameStart);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::frame:
|
case State::frame:
|
||||||
|
@ -210,7 +262,18 @@ void FrameManager::setState(FrameManager::State state)
|
||||||
myState = state;
|
myState = state;
|
||||||
myLineInState = 0;
|
myLineInState = 0;
|
||||||
|
|
||||||
if (myState == State::frame && myOnFrameStart) myOnFrameStart();
|
switch (myState) {
|
||||||
|
case State::waitForFrameStart:
|
||||||
|
myVblankViolated = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State::frame:
|
||||||
|
if (myOnFrameStart) myOnFrameStart();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -230,7 +293,7 @@ void FrameManager::finalizeFrame(FrameManager::State state)
|
||||||
|
|
||||||
myTotalFrames++;
|
myTotalFrames++;
|
||||||
|
|
||||||
if (myTotalFrames <= Metrics::modeDetectionInitialFrameskip) {
|
if (myTotalFrames <= Metrics::initialGarbageFrames) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,11 @@ class FrameManager : public Serializable
|
||||||
frame
|
frame
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum VblankMode {
|
||||||
|
locked,
|
||||||
|
floating
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void setTvMode(TvMode mode);
|
void setTvMode(TvMode mode);
|
||||||
|
@ -87,6 +92,8 @@ class FrameManager : public Serializable
|
||||||
|
|
||||||
void finalizeFrame(State state = State::waitForVsyncStart);
|
void finalizeFrame(State state = State::waitForVsyncStart);
|
||||||
|
|
||||||
|
void nextLineInVsync();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
callback myOnFrameStart;
|
callback myOnFrameStart;
|
||||||
|
@ -110,6 +117,12 @@ class FrameManager : public Serializable
|
||||||
uInt32 myOverscanLines;
|
uInt32 myOverscanLines;
|
||||||
uInt32 myFrameLines;
|
uInt32 myFrameLines;
|
||||||
|
|
||||||
|
VblankMode myVblankMode;
|
||||||
|
uInt32 myLastVblankLines;
|
||||||
|
uInt8 myVblankViolations;
|
||||||
|
uInt8 myStableVblankFrames;
|
||||||
|
bool myVblankViolated;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FrameManager(const FrameManager&) = delete;
|
FrameManager(const FrameManager&) = delete;
|
||||||
FrameManager(FrameManager&&) = delete;
|
FrameManager(FrameManager&&) = delete;
|
||||||
|
|
Loading…
Reference in New Issue