diff --git a/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx b/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx index 1be30623d..e3117ffd8 100644 --- a/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx +++ b/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx @@ -98,6 +98,13 @@ class FrameLayoutDetector: public AbstractFrameManager { */ uInt32 myLinesWaitingForVsyncToStart; + private: + + FrameLayoutDetector(const FrameLayoutDetector&) = delete; + FrameLayoutDetector(FrameLayoutDetector&&) = delete; + FrameLayoutDetector& operator=(const FrameLayoutDetector&) = delete; + FrameLayoutDetector& operator=(FrameLayoutDetector&&) = delete; + }; #endif // TIA_FRAME_LAYOUT_DETECTOR diff --git a/src/emucore/tia/frame-manager/FrameManager.cxx b/src/emucore/tia/frame-manager/FrameManager.cxx index 5e1ade34c..40629f152 100644 --- a/src/emucore/tia/frame-manager/FrameManager.cxx +++ b/src/emucore/tia/frame-manager/FrameManager.cxx @@ -58,11 +58,15 @@ void FrameManager::onReset() myStableFrameLines = -1; myStableFrameHeightCountdown = 0; + + myJitterEmulation.reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameManager::onNextLine() { + Int32 jitter; + State previousState = myState; myLineInState++; @@ -83,7 +87,10 @@ void FrameManager::onNextLine() break; case State::waitForFrameStart: - if (myLineInState >= myYStart) setState(State::frame); + jitter = + (myJitterEnabled && myTotalFrames > Metrics::initialGarbageFrames) ? myJitterEmulation.jitter() : 0; + + if (myLineInState >= (myYStart + jitter)) setState(State::frame); break; case State::frame: @@ -111,6 +118,13 @@ Int32 FrameManager::missingScanlines() const } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FrameManager::setYstart(uInt32 ystart) +{ + myYStart = ystart; + myJitterEmulation.setYStart(ystart); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameManager::onSetVsync() { @@ -128,7 +142,8 @@ void FrameManager::setState(FrameManager::State state) switch (myState) { case State::waitForFrameStart: - finalizeFrame(); + notifyFrameComplete(); + myJitterEmulation.frameComplete(myCurrentFrameFinalLines); notifyFrameStart(); myVsyncLines = 0; @@ -146,45 +161,6 @@ void FrameManager::setState(FrameManager::State state) updateIsRendering(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameManager::finalizeFrame() -{ - if (myCurrentFrameTotalLines != (uInt32)myStableFrameLines) { - if (myCurrentFrameTotalLines == myCurrentFrameFinalLines) { - - if (++myStableFrameHeightCountdown >= Metrics::framesForStableHeight) { - if (myStableFrameLines >= 0) { - handleJitter(myCurrentFrameTotalLines - myStableFrameLines); - } - - myStableFrameLines = myCurrentFrameTotalLines; - } - - } - else myStableFrameHeightCountdown = 0; - } - - notifyFrameComplete(); - -#ifdef TIA_FRAMEMANAGER_DEBUG_LOG - (cout << "frame complete @ " << myLineInState << " (" << myCurrentFrameFinalLines << " total)" << "\n").flush(); -#endif // TIA_FRAMEMANAGER_DEBUG_LOG -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameManager::handleJitter(Int32 scanlineDifference) -{ - /* - if ( - (uInt32)abs(scanlineDifference) < Metrics::minDeltaForJitter || - !myJitterEnabled || - myTotalFrames < Metrics::initialGarbageFrames - ) return; - - myVblankManager.setJitter(scanlineDifference); - */ -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // TODO: kill this with fire once frame manager refactoring is complete void FrameManager::onLayoutChange() @@ -219,16 +195,6 @@ void FrameManager::setFixedHeight(uInt32 height) myHeight = myFixedHeight > 0 ? myFixedHeight : (myKernelLines + Metrics::visibleOverscan); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameManager::enableJitter(bool enabled) -{ - /* - myJitterEnabled = enabled; - - if (!enabled) myVblankManager.setJitter(0); - */ -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameManager::updateIsRendering() { myIsRendering = myState == State::frame; @@ -237,6 +203,8 @@ void FrameManager::updateIsRendering() { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameManager::onSave(Serializer& out) const { + if (!myJitterEmulation.save(out)) return false; + out.putInt(uInt32(myState)); out.putInt(myLineInState); out.putInt(myVsyncLines); @@ -261,6 +229,8 @@ bool FrameManager::onSave(Serializer& out) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameManager::onLoad(Serializer& in) { + if (!myJitterEmulation.load(in)) return false; + myState = State(in.getInt()); myLineInState = in.getInt(); myVsyncLines = in.getInt(); diff --git a/src/emucore/tia/frame-manager/FrameManager.hxx b/src/emucore/tia/frame-manager/FrameManager.hxx index d30cd4f20..d3167cbba 100644 --- a/src/emucore/tia/frame-manager/FrameManager.hxx +++ b/src/emucore/tia/frame-manager/FrameManager.hxx @@ -21,6 +21,7 @@ #include "AbstractFrameManager.hxx" #include "TIAConstants.hxx" #include "bspf.hxx" +#include "JitterEmulation.hxx" class FrameManager: public AbstractFrameManager { public: @@ -29,11 +30,11 @@ class FrameManager: public AbstractFrameManager { public: - void setJitterFactor(uInt8 factor) override { } + void setJitterFactor(uInt8 factor) override { myJitterEmulation.setJitterFactor(factor); } bool jitterEnabled() const override { return myJitterEnabled; } - void enableJitter(bool enabled) override; + void enableJitter(bool enabled) override { myJitterEnabled = enabled; } uInt32 height() const override { return myHeight; }; @@ -45,7 +46,7 @@ class FrameManager: public AbstractFrameManager { Int32 missingScanlines() const override; - void setYstart(uInt32 ystart) override { myYStart = ystart; } + void setYstart(uInt32 ystart) override; uInt32 ystart() const override { return myYStart; } @@ -80,12 +81,6 @@ class FrameManager: public AbstractFrameManager { void setState(State state); - void finalizeFrame(); - - void nextLineInVsync(); - - void handleJitter(Int32 scanlineDifference); - void updateIsRendering(); private: @@ -108,6 +103,8 @@ class FrameManager: public AbstractFrameManager { Int32 myStableFrameLines; uInt8 myStableFrameHeightCountdown; + JitterEmulation myJitterEmulation; + private: FrameManager(const FrameManager&) = delete; diff --git a/src/emucore/tia/frame-manager/JitterEmulation.cxx b/src/emucore/tia/frame-manager/JitterEmulation.cxx new file mode 100644 index 000000000..6a7349602 --- /dev/null +++ b/src/emucore/tia/frame-manager/JitterEmulation.cxx @@ -0,0 +1,122 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include "JitterEmulation.hxx" + +enum Metrics: uInt32 { + framesForStableHeight = 2, + minDeltaForJitter = 3, + maxJitter = 50 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +JitterEmulation::JitterEmulation() : + myYStart(0) +{} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JitterEmulation::reset() +{ + myLastFrameScanlines = 0; + myStableFrameFinalLines = 0; + myStableFrames = 0; + myStabilizationCounter = 0; + myJitter = 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JitterEmulation::frameComplete(uInt32 scanlineCount) +{ + if (scanlineCount != myStableFrameFinalLines) { + if (scanlineCount == myLastFrameScanlines) { + + if (++myStabilizationCounter >= Metrics::framesForStableHeight) { + if (myStableFrameFinalLines > 0) updateJitter(scanlineCount - myStableFrameFinalLines); + + myStableFrameFinalLines = scanlineCount; + } + + } + else myStabilizationCounter = 0; + } + + myLastFrameScanlines = scanlineCount; + + if (myJitter > 0) myJitter = std::max(myJitter - myJitterFactor, 0); + if (myJitter < 0) myJitter = std::min(myJitter + myJitterFactor, 0); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JitterEmulation::updateJitter(Int32 scanlineDifference) +{ + if ((uInt32)abs(scanlineDifference) < Metrics::minDeltaForJitter) return; + + Int32 jitter = std::min(jitter, Metrics::maxJitter); + jitter = std::max(jitter, -myYStart); + + if (jitter > 0) jitter += myJitterFactor; + if (jitter < 0) jitter -= myJitterFactor; + + if (abs(jitter) > abs(myJitter)) myJitter = jitter; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool JitterEmulation::save(Serializer& out) const +{ + try { + out.putString(name()); + + out.putInt(myLastFrameScanlines); + out.putInt(myStableFrameFinalLines); + out.putInt(myStableFrames); + out.putInt(myStabilizationCounter); + out.putInt(myJitter); + out.putInt(myJitterFactor); + out.putInt(myYStart); + } + catch(...) { + cerr << "ERROR: JitterEmulation::save" << std::endl; + + return false; + } + + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool JitterEmulation::load(Serializer& in) +{ + try { + if (in.getString() != name()) return false; + + myLastFrameScanlines = in.getInt(); + myStableFrameFinalLines = in.getInt(); + myStableFrames = in.getInt(); + myStabilizationCounter = in.getInt(); + myJitter = in.getInt(); + myJitterFactor = in.getInt(); + myYStart = in.getInt(); + } + catch (...) + { + cerr << "ERROR: JitterEmulation::load" << std::endl; + + return false; + } + + return true; +} diff --git a/src/emucore/tia/frame-manager/JitterEmulation.hxx b/src/emucore/tia/frame-manager/JitterEmulation.hxx new file mode 100644 index 000000000..6e67eb62c --- /dev/null +++ b/src/emucore/tia/frame-manager/JitterEmulation.hxx @@ -0,0 +1,81 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef TIA_JITTER_EMULATION +#define TIA_JITTER_EMULATION + +#include "bspf.hxx" +#include "Serializable.hxx" + +class JitterEmulation: public Serializable { + public: + + JitterEmulation(); + + public: + + void reset(); + + void frameComplete(uInt32 scanlineCount); + + void setJitterFactor(Int32 factor) { myJitterFactor = factor; } + + Int32 jitter() const { return myJitter; } + + void setYStart(uInt32 ystart) { myYStart = ystart; } + + /** + * Save state. + */ + bool save(Serializer& out) const override; + + /** + * Restore state. + */ + bool load(Serializer& in) override; + + string name() const override { return "JitterEmulation"; } + + private: + + void updateJitter(Int32 scanlineDifference); + + private: + + uInt32 myLastFrameScanlines; + + uInt32 myStableFrameFinalLines; + + uInt32 myStableFrames; + + uInt32 myStabilizationCounter; + + Int32 myJitter; + + Int32 myJitterFactor; + + uInt32 myYStart; + + private: + + JitterEmulation(const JitterEmulation&) = delete; + JitterEmulation(JitterEmulation&&) = delete; + JitterEmulation& operator=(const JitterEmulation&) = delete; + JitterEmulation& operator=(JitterEmulation&&) = delete; +}; + +#endif // TIA_JITTER_EMULATION diff --git a/src/emucore/tia/frame-manager/module.mk b/src/emucore/tia/frame-manager/module.mk index 7999f5d00..9bd6093c2 100644 --- a/src/emucore/tia/frame-manager/module.mk +++ b/src/emucore/tia/frame-manager/module.mk @@ -2,10 +2,10 @@ MODULE := src/emucore/tia/frame-manager MODULE_OBJS := \ src/emucore/tia/frame-manager/FrameManager.o \ - src/emucore/tia/frame-manager/VblankManager.o \ src/emucore/tia/frame-manager/AbstractFrameManager.o \ src/emucore/tia/frame-manager/FrameLayoutDetector.o \ - src/emucore/tia/frame-manager/YStartDetector.o + src/emucore/tia/frame-manager/YStartDetector.o \ + src/emucore/tia/frame-manager/JitterEmulation.o MODULE_DIRS += \ src/emucore/tia/frame-manager