Reimplement jitter; fixes #11.

This commit is contained in:
Christian Speckner 2017-05-09 00:10:14 +02:00
parent 1cb83f4a68
commit 362f7c2888
6 changed files with 93 additions and 12 deletions

View File

@ -57,7 +57,8 @@ FrameManager::FrameManager()
: myLayout(FrameLayout::pal), : myLayout(FrameLayout::pal),
myAutodetectLayout(true), myAutodetectLayout(true),
myHeight(0), myHeight(0),
myFixedHeight(0) myFixedHeight(0),
myJitterEnabled(false)
{ {
updateLayout(FrameLayout::ntsc); updateLayout(FrameLayout::ntsc);
reset(); reset();
@ -210,6 +211,8 @@ void FrameManager::setState(FrameManager::State state)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::finalizeFrame() void FrameManager::finalizeFrame()
{ {
handleJitter(myCurrentFrameTotalLines - myCurrentFrameFinalLines);
myCurrentFrameFinalLines = myCurrentFrameTotalLines; myCurrentFrameFinalLines = myCurrentFrameTotalLines;
myCurrentFrameTotalLines = 0; myCurrentFrameTotalLines = 0;
myTotalFrames++; myTotalFrames++;
@ -226,6 +229,14 @@ void FrameManager::finalizeFrame()
myCurrentFrameFinalLines; myCurrentFrameFinalLines;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::handleJitter(Int32 scanlineDifference)
{
if (scanlineDifference == 0 || !myJitterEnabled || myTotalFrames < Metrics::initialGarbageFrames) return;
myVblankManager.setJitter(scanlineDifference);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::updateAutodetectedLayout() void FrameManager::updateAutodetectedLayout()
{ {
@ -315,6 +326,14 @@ void FrameManager::setFixedHeight(uInt32 height)
myHeight = myFixedHeight > 0 ? myFixedHeight : (myKernelLines + Metrics::visibleOverscan); myHeight = myFixedHeight > 0 ? myFixedHeight : (myKernelLines + Metrics::visibleOverscan);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::enableJitter(bool enabled)
{
myJitterEnabled = enabled;
if (!enabled) myVblankManager.setJitter(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameManager::save(Serializer& out) const bool FrameManager::save(Serializer& out) const
{ {
@ -347,6 +366,8 @@ bool FrameManager::save(Serializer& out) const
out.putInt(myFrameLines); out.putInt(myFrameLines);
out.putInt(myHeight); out.putInt(myHeight);
out.putInt(myFixedHeight); out.putInt(myFixedHeight);
out.putBool(myJitterEnabled);
} }
catch(...) catch(...)
{ {
@ -390,6 +411,8 @@ bool FrameManager::load(Serializer& in)
myFrameLines = in.getInt(); myFrameLines = in.getInt();
myHeight = in.getInt(); myHeight = in.getInt();
myFixedHeight = in.getInt(); myFixedHeight = in.getInt();
myJitterEnabled = in.getBool();
} }
catch(...) catch(...)
{ {

View File

@ -89,6 +89,10 @@ class FrameManager : public Serializable
bool load(Serializer& in) override; bool load(Serializer& in) override;
string name() const override { return "TIA_FrameManager"; } string name() const override { return "TIA_FrameManager"; }
void setJitterFactor(uInt8 factor) { myVblankManager.setJitterFactor(factor); }
bool jitterEnabled() const { return myJitterEnabled; }
void enableJitter(bool enabled);
public: public:
static constexpr uInt32 frameBufferHeight = 320; static constexpr uInt32 frameBufferHeight = 320;
static constexpr uInt32 minYStart = 1, maxYStart = 64; static constexpr uInt32 minYStart = 1, maxYStart = 64;
@ -122,6 +126,8 @@ class FrameManager : public Serializable
void nextLineInVsync(); void nextLineInVsync();
void handleJitter(Int32 scanlineDifference);
private: private:
callback myOnFrameStart; callback myOnFrameStart;
@ -153,6 +159,8 @@ class FrameManager : public Serializable
uInt32 myHeight; uInt32 myHeight;
uInt32 myFixedHeight; uInt32 myFixedHeight;
bool myJitterEnabled;
private: private:
FrameManager(const FrameManager&) = delete; FrameManager(const FrameManager&) = delete;
FrameManager(FrameManager&&) = delete; FrameManager(FrameManager&&) = delete;

View File

@ -98,6 +98,9 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
myMissile1.setTIA(this); myMissile1.setTIA(this);
myBall.setTIA(this); myBall.setTIA(this);
myFrameManager.enableJitter(mySettings.getBool("tv.jitter"));
myFrameManager.setJitterFactor(mySettings.getInt("tv.jitter_recovery"));
reset(); reset();
} }
@ -896,13 +899,24 @@ bool TIA::driveUnusedPinsRandom(uInt8 mode)
// TODO: stub // TODO: stub
bool TIA::toggleJitter(uInt8 mode) bool TIA::toggleJitter(uInt8 mode)
{ {
return false; switch (mode) {
} case 0:
myFrameManager.enableJitter(false);
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case 1:
// TODO: stub myFrameManager.enableJitter(true);
void TIA::setJitterRecoveryFactor(Int32 f) break;
{
case 2:
myFrameManager.enableJitter(!myFrameManager.jitterEnabled());
break;
default:
throw runtime_error("invalid argument for toggleJitter");
}
return myFrameManager.jitterEnabled();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -294,7 +294,7 @@ class TIA : public Device
@return Whether the mode was enabled or disabled @return Whether the mode was enabled or disabled
*/ */
bool toggleJitter(uInt8 mode = 2); bool toggleJitter(uInt8 mode = 2);
void setJitterRecoveryFactor(Int32 f); void setJitterRecoveryFactor(Int32 factor) { myFrameManager.setJitterFactor(factor); }
// Clear both internal TIA buffers to black (palette color 0) // Clear both internal TIA buffers to black (palette color 0)
void clearBuffers(); void clearBuffers();

View File

@ -17,20 +17,25 @@
// #define TIA_VBLANK_MANAGER_DEBUG_LOG // #define TIA_VBLANK_MANAGER_DEBUG_LOG
#include <algorithm>
#include "VblankManager.hxx" #include "VblankManager.hxx"
enum Metrics: uInt32 { enum Metrics: uInt32 {
maxUnderscan = 10, maxUnderscan = 10,
maxVblankViolations = 2, maxVblankViolations = 2,
minStableVblankFrames = 1, minStableVblankFrames = 1,
framesUntilFinal = 30 framesUntilFinal = 30,
maxJitter = 50
}; };
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VblankManager::VblankManager() VblankManager::VblankManager()
: myVblankLines(0), : myVblankLines(0),
myYstart(0), myYstart(0),
myMode(VblankMode::floating) myMode(VblankMode::floating),
myJitter(0),
myJitterFactor(2)
{ {
reset(); reset();
} }
@ -45,10 +50,24 @@ void VblankManager::reset()
myVblankViolated = false; myVblankViolated = false;
myLastVblankLines = 0; myLastVblankLines = 0;
myIsRunning = false; myIsRunning = false;
myJitter = 0;
if (myMode != VblankMode::fixed) setVblankMode(VblankMode::floating); if (myMode != VblankMode::fixed) setVblankMode(VblankMode::floating);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void VblankManager::setJitter(Int32 jitter) {
jitter = std::min<Int32>(jitter, Metrics::maxJitter);
if (myMode == VblankMode::final) jitter = std::max<Int32>(jitter, -myLastVblankLines);
if (myMode == VblankMode::fixed) jitter = std::max<Int32>(jitter, -myYstart);
if (jitter > 0) jitter += myJitterFactor;
if (jitter < 0) jitter -= myJitterFactor;
if (abs(jitter) > abs(myJitter)) myJitter = jitter;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void VblankManager::start() void VblankManager::start()
{ {
@ -58,6 +77,9 @@ void VblankManager::start()
if (myMode == VblankMode::locked && ++myFramesInLockedMode > Metrics::framesUntilFinal) if (myMode == VblankMode::locked && ++myFramesInLockedMode > Metrics::framesUntilFinal)
setVblankMode(VblankMode::final); setVblankMode(VblankMode::final);
if (myJitter > 0) myJitter = std::max(myJitter - myJitterFactor, 0);
if (myJitter < 0) myJitter = std::min(myJitter + myJitterFactor, 0);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -156,11 +178,13 @@ bool VblankManager::shouldTransition(bool isGarbageFrame)
break; break;
case VblankMode::fixed: case VblankMode::fixed:
transition = myCurrentLine >= myYstart; transition = (Int32)myCurrentLine >=
std::max<Int32>(myYstart + std::min<Int32>(myJitter, Metrics::maxJitter), 0);
break; break;
case VblankMode::final: case VblankMode::final:
transition = myCurrentLine >= myLastVblankLines; transition = (Int32)myCurrentLine >=
std::max<Int32>(myLastVblankLines + std::min<Int32>(myJitter, Metrics::maxJitter), 0);
break; break;
} }
@ -203,6 +227,9 @@ bool VblankManager::save(Serializer& out) const
out.putBool(myVblankViolated); out.putBool(myVblankViolated);
out.putByte(myFramesInLockedMode); out.putByte(myFramesInLockedMode);
out.putInt(myJitter);
out.putByte(myJitterFactor);
out.putBool(myIsRunning); out.putBool(myIsRunning);
} }
catch(...) catch(...)
@ -234,6 +261,9 @@ bool VblankManager::load(Serializer& in)
myVblankViolated = in.getBool(); myVblankViolated = in.getBool();
myFramesInLockedMode = in.getByte(); myFramesInLockedMode = in.getByte();
myJitter = in.getInt();
myJitterFactor = in.getByte();
myIsRunning = in.getBool(); myIsRunning = in.getBool();
} }
catch(...) catch(...)

View File

@ -49,6 +49,9 @@ class VblankManager : public Serializable
uInt32 currentLine() const { return myCurrentLine; }; uInt32 currentLine() const { return myCurrentLine; };
void setJitter(Int32 jitter);
void setJitterFactor(uInt8 jitterFactor) { myJitterFactor = jitterFactor; }
/** /**
Serializable methods (see that class for more information). Serializable methods (see that class for more information).
*/ */
@ -85,6 +88,9 @@ class VblankManager : public Serializable
bool myVblankViolated; bool myVblankViolated;
uInt8 myFramesInLockedMode; uInt8 myFramesInLockedMode;
Int32 myJitter;
uInt8 myJitterFactor;
bool myIsRunning; bool myIsRunning;
private: private: