diff --git a/src/emucore/tia/frame-manager/FrameLayoutDetector.cxx b/src/emucore/tia/frame-manager/FrameLayoutDetector.cxx index 9538201c6..fc7a92651 100644 --- a/src/emucore/tia/frame-manager/FrameLayoutDetector.cxx +++ b/src/emucore/tia/frame-manager/FrameLayoutDetector.cxx @@ -22,10 +22,17 @@ * Misc. numeric constants used in the algorithm. */ enum Metrics: uInt32 { + // ideal frame heights frameLinesNTSC = 262, frameLinesPAL = 312, + + // number of scanlines to wait for vsync to start and stop (exceeding ideal frame height) waitForVsync = 100, + + // tolerance window around ideal frame size for TV mode detection tvModeDetectionTolerance = 20, + + // these frames will not be considered for detection initialGarbageFrames = TIAConstants::initialGarbageFrames }; diff --git a/src/emucore/tia/frame-manager/YStartDetector.cxx b/src/emucore/tia/frame-manager/YStartDetector.cxx index ef266e94f..cb5d3cce3 100644 --- a/src/emucore/tia/frame-manager/YStartDetector.cxx +++ b/src/emucore/tia/frame-manager/YStartDetector.cxx @@ -22,15 +22,27 @@ * Misc. numeric constants used in the algorithm. */ enum Metrics: uInt32 { + // ideal world frame sizes frameLinesNTSC = 262, frameLinesPAL = 312, + + // the ideal vblank zone vblankNTSC = 37, vblankPAL = 45, + + // number of scanlines to wait for vsync to start (exceeding after the ideal frame size) and stop waitForVsync = 50, - tvModeDetectionTolerance = 20, + + // max lines underscan maxUnderscan = 10, + + // max lines deviations from detected ystart before we switch back to floating maxVblankViolations = 2, + + // switch to fixed mode after this number of stable frames (+1) minStableVblankFrames = 1, + + // no transitions to fixed mode will happend during those initialGarbageFrames = TIAConstants::initialGarbageFrames }; diff --git a/src/emucore/tia/frame-manager/YStartDetector.hxx b/src/emucore/tia/frame-manager/YStartDetector.hxx index b02ce3de2..1fc5d596c 100644 --- a/src/emucore/tia/frame-manager/YStartDetector.hxx +++ b/src/emucore/tia/frame-manager/YStartDetector.hxx @@ -32,50 +32,116 @@ class YStartDetector: public AbstractFrameManager { public: + /** + * Getter for the detected ystart value + */ uInt32 detectedYStart() const; + /** + * We require frame layout to be set from outside. + */ void setLayout(FrameLayout layout) override { this->layout(layout); } protected: + /** + * We need to track vsync changes. + */ void onSetVsync() override; + /** + * Reset hook. + */ void onReset() override; + /** + * The workhorse. + */ void onNextLine() override; private: + /** + * Our various states. + */ enum State { + // Wait for vsync on waitForVsyncStart, + + // Wait for vsync off waitForVsyncEnd, + + // Wait for the visible frame to start waitForFrameStart }; + /** + * Have we settled on a frame start? + */ enum VblankMode { + // We have settled on a frame start and have some hysteresis before we return to floating locked, + + // We are actively looking for the frame to start floating }; private: + /** + * Side effects for state transitions. + */ void setState(State state); + /** + * Perform detection and decide whether the frame starts now. + */ bool shouldTransitionToFrame(); private: + /** + * State. + */ State myState; + /** + * locked / floating + */ VblankMode myVblankMode; + /** + * Counts the scanlines that we wait for vsync to start. + */ uInt32 myLinesWaitingForVsyncToStart; + /** + * The number of lines we are currently waiting for the frame to start (and vblank to end). + */ uInt32 myCurrentVblankLines; + + /** + * The number of vblank lines on the last frame. + */ uInt32 myLastVblankLines; + + /** + * Count "vblank violations" in fixed mode (the number of consecutive frames where ystart + * differs from the previously detected value). Once a trip point is reached, we transition + * back to floating mode. + */ uInt32 myVblankViolations; + + /** + * The number of frames in floating mode with stable ystart. Once a trip point is reacted, + * we transition to fixed mode + */ uInt32 myStableVblankFrames; + /** + * Tracks deviations from the determined ystart value during a fixed mode frame in order to + * avoid double counting. + */ bool myVblankViolated; private: