diff --git a/src/debugger/TIADebug.cxx b/src/debugger/TIADebug.cxx index 6a6dd008d..ede1ec411 100644 --- a/src/debugger/TIADebug.cxx +++ b/src/debugger/TIADebug.cxx @@ -48,7 +48,7 @@ const DebuggerState& TIADebug::getState() myState.coluRegs.push_back(coluBK()); // Debug Colors - int mode = myTIA.myFrameManager.layout() == FrameLayout::ntsc ? 0 : 1; + int mode = myTIA.frameLayout() == FrameLayout::ntsc ? 0 : 1; myState.fixedCols.clear(); myState.fixedCols.push_back(myTIA.myFixedColorPalette[mode][TIA::P0]); myState.fixedCols.push_back(myTIA.myFixedColorPalette[mode][TIA::P1]); @@ -721,7 +721,7 @@ int TIADebug::scanlines() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::scanlinesLastFrame() const { - return myTIA.myFrameManager.scanlinesLastFrame(); + return myTIA.scanlinesLastFrame(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -801,7 +801,7 @@ string TIADebug::debugColors() const { ostringstream buf; - int mode = myTIA.myFrameManager.layout() == FrameLayout::ntsc ? 0 : 1; + int mode = myTIA.frameLayout() == FrameLayout::ntsc ? 0 : 1; buf << " Red " << colorSwatch(myTIA.myFixedColorPalette[mode][TIA::P0]) << " Player 0\n" << " Orange " << colorSwatch(myTIA.myFixedColorPalette[mode][TIA::M0]) diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index ef275831a..3fec0c07c 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -22,6 +22,7 @@ #include "Paddles.hxx" #include "DelayQueueIteratorImpl.hxx" #include "TIAConstants.hxx" +#include "frame-manager/FrameManager.hxx" #ifdef DEBUGGER_SUPPORT #include "CartDebug.hxx" @@ -77,7 +78,9 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings) mySpriteEnabledBits(0xFF), myCollisionsEnabledBits(0xFF) { - myFrameManager.setHandlers( + myFrameManager = new FrameManager(); + + myFrameManager->setHandlers( [this] () { onFrameStart(); }, @@ -99,12 +102,17 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings) myMissile1.setTIA(this); myBall.setTIA(this); - myFrameManager.enableJitter(mySettings.getBool("tv.jitter")); - myFrameManager.setJitterFactor(mySettings.getInt("tv.jitter_recovery")); + myFrameManager->enableJitter(mySettings.getBool("tv.jitter")); + myFrameManager->setJitterFactor(mySettings.getInt("tv.jitter_recovery")); reset(); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +TIA::~TIA() { + delete myFrameManager; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::reset() { @@ -144,7 +152,7 @@ void TIA::reset() mySound.reset(); myDelayQueue.reset(); - myFrameManager.reset(); + myFrameManager->reset(); myCyclesAtFrameStart = 0; @@ -206,7 +214,7 @@ bool TIA::save(Serializer& out) const if(!mySound.save(out)) return false; if(!myDelayQueue.save(out)) return false; - if(!myFrameManager.save(out)) return false; + if(!myFrameManager->save(out)) return false; if(!myBackground.save(out)) return false; if(!myPlayfield.save(out)) return false; @@ -277,7 +285,7 @@ bool TIA::load(Serializer& in) if(!mySound.load(in)) return false; if(!myDelayQueue.load(in)) return false; - if(!myFrameManager.load(in)) return false; + if(!myFrameManager->load(in)) return false; if(!myBackground.load(in)) return false; if(!myPlayfield.load(in)) return false; @@ -482,7 +490,7 @@ bool TIA::poke(uInt16 address, uInt8 value) break; case VSYNC: - myFrameManager.setVsync(value & 0x02); + myFrameManager->setVsync(value & 0x02); myShadowRegisters[address] = value; break; @@ -796,7 +804,7 @@ bool TIA::enableColorLoss(bool enabled) if(enabled) { myColorLossEnabled = true; - myColorLossActive = myFrameManager.scanlinesLastFrame() & 0x1; + myColorLossActive = myFrameManager->scanlinesLastFrame() & 0x1; } else { @@ -820,7 +828,7 @@ bool TIA::electronBeamPos(uInt32& x, uInt32& y) const uInt8 clocks = clocksThisLine(); x = (clocks < 68) ? 0 : clocks - 68; - y = myFrameManager.getY(); + y = myFrameManager->getY(); return isRendering(); } @@ -906,7 +914,7 @@ bool TIA::toggleCollisions() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::enableFixedColors(bool enable) { - int layout = myFrameManager.layout() == FrameLayout::pal ? 1 : 0; + int layout = myFrameManager->layout() == FrameLayout::pal ? 1 : 0; myMissile0.setDebugColor(myFixedColorPalette[layout][FixedObject::M0]); myMissile1.setDebugColor(myFixedColorPalette[layout][FixedObject::M1]); myPlayer0.setDebugColor(myFixedColorPalette[layout][FixedObject::P0]); @@ -991,22 +999,22 @@ bool TIA::toggleJitter(uInt8 mode) { switch (mode) { case 0: - myFrameManager.enableJitter(false); + myFrameManager->enableJitter(false); break; case 1: - myFrameManager.enableJitter(true); + myFrameManager->enableJitter(true); break; case 2: - myFrameManager.enableJitter(!myFrameManager.jitterEnabled()); + myFrameManager->enableJitter(!myFrameManager->jitterEnabled()); break; default: throw runtime_error("invalid argument for toggleJitter"); } - return myFrameManager.jitterEnabled(); + return myFrameManager->jitterEnabled(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1081,9 +1089,9 @@ void TIA::onFrameStart() { // Only activate it when necessary, since changing colours in // the graphical object forces the TIA cached line to be flushed - if (myFrameManager.scanlineCountTransitioned()) + if (myFrameManager->scanlineCountTransitioned()) { - myColorLossActive = myFrameManager.scanlinesLastFrame() & 0x1; + myColorLossActive = myFrameManager->scanlinesLastFrame() & 0x1; myMissile0.applyColorLoss(); myMissile1.applyColorLoss(); @@ -1112,13 +1120,13 @@ void TIA::onFrameComplete() memset(myFramebuffer, 0, myXAtRenderingStart); // Blank out any extra lines not drawn this frame - const uInt32 missingScanlines = myFrameManager.missingScanlines(); + const Int32 missingScanlines = myFrameManager->missingScanlines(); if (missingScanlines > 0) - memset(myFramebuffer + 160 * myFrameManager.getY(), 0, missingScanlines * 160); + memset(myFramebuffer + 160 * myFrameManager->getY(), 0, missingScanlines * 160); // Recalculate framerate, attempting to auto-correct for scanline 'jumps' if(myAutoFrameEnabled) - myConsole.setFramerate(myFrameManager.frameRate()); + myConsole.setFramerate(myFrameManager->frameRate()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1148,7 +1156,7 @@ void TIA::cycle(uInt32 colorClocks) else tickHframe(); - if (myCollisionUpdateRequired && !myFrameManager.vblank()) updateCollision(); + if (myCollisionUpdateRequired && !myFrameManager->vblank()) updateCollision(); } if (++myHctr >= 228) @@ -1202,7 +1210,7 @@ void TIA::tickHblank() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::tickHframe() { - const uInt32 y = myFrameManager.getY(); + const uInt32 y = myFrameManager->getY(); const uInt32 x = myHctr - 68 - myHctrDelta; myCollisionUpdateRequired = true; @@ -1214,7 +1222,7 @@ void TIA::tickHframe() myPlayer1.tick(); myBall.tick(); - if (myFrameManager.isRendering()) + if (myFrameManager->isRendering()) renderPixel(x, y); } @@ -1224,8 +1232,8 @@ void TIA::applyRsync() const uInt32 x = myHctr > 68 ? myHctr - 68 : 0; myHctrDelta = 225 - myHctr; - if (myFrameManager.isRendering()) - memset(myFramebuffer + myFrameManager.getY() * 160 + x, 0, 160 - x); + if (myFrameManager->isRendering()) + memset(myFramebuffer + myFrameManager->getY() * 160 + x, 0, 160 - x); myHctr = 225; } @@ -1244,9 +1252,9 @@ void TIA::nextLine() myHstate = HState::blank; myHctrDelta = 0; - myFrameManager.nextLine(); + myFrameManager->nextLine(); - if (myFrameManager.isRendering() && myFrameManager.getY() == 0) flushLineCache(); + if (myFrameManager->isRendering() && myFrameManager->getY() == 0) flushLineCache(); mySystem->m6502().clearHaltRequest(); } @@ -1254,9 +1262,9 @@ void TIA::nextLine() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::cloneLastLine() { - const auto y = myFrameManager.getY(); + const auto y = myFrameManager->getY(); - if (!myFrameManager.isRendering() || y == 0) return; + if (!myFrameManager->isRendering() || y == 0) return; uInt8* buffer = myFramebuffer; @@ -1283,7 +1291,7 @@ void TIA::renderPixel(uInt32 x, uInt32 y) uInt8 color = 0; - if (!myFrameManager.vblank()) + if (!myFrameManager->vblank()) { switch (myPriority) { @@ -1356,8 +1364,8 @@ void TIA::flushLineCache() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::clearHmoveComb() { - if (myFrameManager.isRendering() && myHstate == HState::blank) - memset(myFramebuffer + myFrameManager.getY() * 160, myColorHBlank, 8); + if (myFrameManager->isRendering() && myHstate == HState::blank) + memset(myFramebuffer + myFrameManager->getY() * 160, myColorHBlank, 8); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1370,7 +1378,7 @@ void TIA::delayedWrite(uInt8 address, uInt8 value) { case VBLANK: flushLineCache(); - myFrameManager.setVblank(value & 0x02); + myFrameManager->setVblank(value & 0x02); break; case HMOVE: diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index c58c1f375..e06e81421 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -28,7 +28,7 @@ #include "TIAConstants.hxx" #include "DelayQueue.hxx" #include "DelayQueueIterator.hxx" -#include "frame-manager/FrameManager.hxx" +#include "frame-manager/AbstractFrameManager.hxx" #include "FrameLayout.hxx" #include "Background.hxx" #include "Playfield.hxx" @@ -101,7 +101,7 @@ class TIA : public Device @param settings The settings object for this TIA device */ TIA(Console& console, Sound& sound, Settings& settings); - virtual ~TIA() = default; + virtual ~TIA(); public: /** @@ -193,21 +193,21 @@ class TIA : public Device Answers dimensional info about the framebuffer. */ uInt32 width() const { return 160; } - uInt32 height() const { return myFrameManager.height(); } - uInt32 ystart() const { return myFrameManager.ystart(); } - bool ystartIsAuto(uInt32 line) const { return myFrameManager.ystartIsAuto(line); } + uInt32 height() const { return myFrameManager->height(); } + uInt32 ystart() const { return myFrameManager->ystart(); } + bool ystartIsAuto(uInt32 line) const { return myFrameManager->ystartIsAuto(line); } /** Changes the current Height/YStart properties. Note that calls to these method(s) must be eventually followed by ::frameReset() for the changes to take effect. */ - void setHeight(uInt32 height) { myFrameManager.setFixedHeight(height); } - void setYStart(uInt32 ystart) { myFrameManager.setYstart(ystart); } + void setHeight(uInt32 height) { myFrameManager->setFixedHeight(height); } + void setYStart(uInt32 ystart) { myFrameManager->setYstart(ystart); } - void autodetectLayout(bool toggle) { myFrameManager.autodetectLayout(toggle); } - void setLayout(FrameLayout layout) { myFrameManager.setLayout(layout); } - FrameLayout frameLayout() const { return myFrameManager.layout(); } + void autodetectLayout(bool toggle) { myFrameManager->autodetectLayout(toggle); } + void setLayout(FrameLayout layout) { myFrameManager->setLayout(layout); } + FrameLayout frameLayout() const { return myFrameManager->layout(); } /** Answers the timing of the console currently in use. @@ -250,7 +250,7 @@ class TIA : public Device @return The total number of scanlines generated */ - uInt32 scanlines() const { return myFrameManager.scanlines(); } + uInt32 scanlines() const { return myFrameManager->scanlines(); } /** Answers the total number of scanlines the TIA generated in the @@ -258,7 +258,7 @@ class TIA : public Device @return The total number of scanlines generated in the last frame. */ - uInt32 scanlinesLastFrame() const { return myFrameManager.scanlinesLastFrame(); } + uInt32 scanlinesLastFrame() const { return myFrameManager->scanlinesLastFrame(); } /** Answers the total system cycles from the start of the emulation. @@ -268,7 +268,7 @@ class TIA : public Device /** Answers the frame count from the start of the emulation. */ - uInt32 frameCount() const { return myFrameManager.frameCount(); } + uInt32 frameCount() const { return myFrameManager->frameCount(); } /** Answers the system cycles from the start of the current frame. @@ -283,7 +283,7 @@ class TIA : public Device @return If the frame is in rendering mode */ - bool isRendering() const { return myFrameManager.isRendering(); } + bool isRendering() const { return myFrameManager->isRendering(); } /** Answers the current position of the virtual 'electron beam' used @@ -360,7 +360,7 @@ class TIA : public Device @return Whether the mode was enabled or disabled */ bool toggleJitter(uInt8 mode = 2); - void setJitterRecoveryFactor(Int32 factor) { myFrameManager.setJitterFactor(factor); } + void setJitterRecoveryFactor(Int32 factor) { myFrameManager->setJitterFactor(factor); } /** This method should be called to update the TIA with a new scanline. @@ -593,7 +593,7 @@ class TIA : public Device * The frame manager is responsible for detecting frame boundaries and the visible * region of each frame. */ - FrameManager myFrameManager; + AbstractFrameManager *myFrameManager; /** * The various TIA objects. diff --git a/src/emucore/tia/frame-manager/AbstractFrameManager.cxx b/src/emucore/tia/frame-manager/AbstractFrameManager.cxx index 0fdd50c58..3e82cee2a 100644 --- a/src/emucore/tia/frame-manager/AbstractFrameManager.cxx +++ b/src/emucore/tia/frame-manager/AbstractFrameManager.cxx @@ -18,8 +18,13 @@ #include "AbstractFrameManager.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AbstractFrameManager::AbstractFrameManager() +AbstractFrameManager::AbstractFrameManager() : + myLayout(FrameLayout::pal), + myOnFrameStart(0), + myOnFrameComplete(0), + myOnRenderingStart(0) { + layout(FrameLayout::ntsc); reset(); } @@ -33,11 +38,8 @@ void AbstractFrameManager::reset() myCurrentFrameFinalLines = 0; myPreviousFrameFinalLines = 0; myTotalFrames = 0; - myLayout = FrameLayout::ntsc; myFrameRate = 0; - myOnFrameComplete = 0; - myOnFrameStart = 0; - myOnRenderingStart = 0; + myFrameRate = 60.0; onReset(); } @@ -96,6 +98,9 @@ void AbstractFrameManager::notifyFrameComplete() myTotalFrames++; if (myOnFrameComplete) myOnFrameComplete(); + + myFrameRate = (layout() == FrameLayout::pal ? 15600.0 : 15720.0) / + myCurrentFrameFinalLines; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -104,6 +109,16 @@ void AbstractFrameManager::notifyRenderingStart() if (myOnRenderingStart) myOnRenderingStart(); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void AbstractFrameManager::layout(FrameLayout layout) +{ + if (layout == myLayout) return; + + myLayout = layout; + + onLayoutChange(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool AbstractFrameManager::save(Serializer& out) const { diff --git a/src/emucore/tia/frame-manager/AbstractFrameManager.hxx b/src/emucore/tia/frame-manager/AbstractFrameManager.hxx index 54fc57c70..18a2e2d70 100644 --- a/src/emucore/tia/frame-manager/AbstractFrameManager.hxx +++ b/src/emucore/tia/frame-manager/AbstractFrameManager.hxx @@ -67,6 +67,10 @@ class AbstractFrameManager : public Serializable float frameRate() const { return myFrameRate; } + bool save(Serializer& out) const override; + + bool load(Serializer& in) override; + public: virtual void setJitterFactor(uInt8 factor) {} @@ -75,10 +79,6 @@ class AbstractFrameManager : public Serializable virtual void enableJitter(bool enabled) {}; - bool save(Serializer& out) const override; - - bool load(Serializer& in) override; - public: virtual uInt32 height() const = 0; @@ -89,11 +89,11 @@ class AbstractFrameManager : public Serializable virtual uInt32 scanlines() const = 0; - virtual uInt32 missingScanlines() const = 0; + virtual Int32 missingScanlines() const = 0; virtual void setYstart(uInt32 ystart) = 0; - virtual uInt32 ystart() = 0; + virtual uInt32 ystart() const = 0; // TODO: this looks pretty weird --- does this actually work? virtual bool ystartIsAuto(uInt32 line) const = 0; @@ -101,6 +101,7 @@ class AbstractFrameManager : public Serializable // TODO: this has to go virtual void autodetectLayout(bool toggle) = 0; + // TODO: this collides with layout(...). Refactor after all is done. virtual void setLayout(FrameLayout mode) = 0; protected: @@ -113,6 +114,8 @@ class AbstractFrameManager : public Serializable virtual void onReset() {} + virtual void onLayoutChange() {} + virtual bool onSave(Serializer& out) const { throw runtime_error("cannot be serialized"); } virtual bool onLoad(Serializer& in) { throw runtime_error("cannot be serialized"); } @@ -125,6 +128,8 @@ class AbstractFrameManager : public Serializable void notifyRenderingStart(); + void layout(FrameLayout layout); + protected: bool myIsRendering; @@ -141,12 +146,12 @@ class AbstractFrameManager : public Serializable uInt32 myTotalFrames; - FrameLayout myLayout; - float myFrameRate; private: + FrameLayout myLayout; + callback myOnFrameStart; callback myOnFrameComplete; callback myOnRenderingStart; diff --git a/src/emucore/tia/frame-manager/FrameManager.cxx b/src/emucore/tia/frame-manager/FrameManager.cxx index cc10cb3c2..27e833fdb 100644 --- a/src/emucore/tia/frame-manager/FrameManager.cxx +++ b/src/emucore/tia/frame-manager/FrameManager.cxx @@ -50,39 +50,19 @@ inline static uInt32 vsyncLimit(bool autodetect) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FrameManager::FrameManager() - : myLayout(FrameLayout::pal), - myAutodetectLayout(true), - myHeight(0), - myFixedHeight(0), - myJitterEnabled(false) +FrameManager::FrameManager() : + myHeight(0) { - updateLayout(FrameLayout::ntsc); - reset(); + onLayoutChange(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameManager::setHandlers( - FrameManager::callback frameStartCallback, - FrameManager::callback frameCompleteCallback, - FrameManager::callback renderingStartCallback -) -{ - myOnFrameStart = frameStartCallback; - myOnFrameComplete = frameCompleteCallback; - myOnRenderingStart = renderingStartCallback; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameManager::reset() +void FrameManager::onReset() { myVblankManager.reset(); myState = State::waitForVsyncStart; - myCurrentFrameTotalLines = myCurrentFrameFinalLines = 0; - myFrameRate = 60.0; myLineInState = 0; - myVsync = false; myTotalFrames = 0; myFramesInMode = 0; myModeConfirmed = false; @@ -98,11 +78,9 @@ void FrameManager::reset() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameManager::nextLine() +void FrameManager::onNextLine() { State previousState = myState; - - myCurrentFrameTotalLines++; myLineInState++; switch (myState) @@ -142,25 +120,22 @@ void FrameManager::nextLine() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 FrameManager::missingScanlines() const +Int32 FrameManager::missingScanlines() const { if (myLastY == ystart() + myY) return 0; - else + else { return myHeight - myY; + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameManager::setVsync(bool vsync) +void FrameManager::onSetVsync() { - if (vsync == myVsync) return; - #ifdef TIA_FRAMEMANAGER_DEBUG_LOG - (cout << "vsync " << myVsync << " -> " << vsync << ": state " << int(myState) << " @ " << myLineInState << "\n").flush(); + (cout << "vsync " << !myVsync << " -> " << myVsync << ": state " << int(myState) << " @ " << myLineInState << "\n").flush(); #endif - myVsync = vsync; - switch (myState) { case State::waitForVsyncStart: @@ -200,6 +175,8 @@ void FrameManager::setState(FrameManager::State state) myStableFrames >= Metrics::minStableFrames || myStabilizationFrames >= Metrics::maxStabilizationFrames; + updateIsRendering(); + myStabilizationFrames++; if (myVblankManager.isStable()) @@ -209,7 +186,7 @@ void FrameManager::setState(FrameManager::State state) } if (myFramePending) finalizeFrame(); - if (myOnFrameStart) myOnFrameStart(); + notifyFrameStart(); myVblankManager.start(); myFramePending = true; @@ -218,7 +195,7 @@ void FrameManager::setState(FrameManager::State state) break; case State::frame: - if (myOnRenderingStart) myOnRenderingStart(); + notifyRenderingStart(); myVsyncLines = 0; myY = 0; break; @@ -226,6 +203,8 @@ void FrameManager::setState(FrameManager::State state) default: break; } + + updateIsRendering(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -246,21 +225,13 @@ void FrameManager::finalizeFrame() else myStableFrameHeightCountdown = 0; } - myPreviousFrameFinalLines = myCurrentFrameFinalLines; - myCurrentFrameFinalLines = myCurrentFrameTotalLines; - myCurrentFrameTotalLines = 0; - myTotalFrames++; - - if (myOnFrameComplete) myOnFrameComplete(); + notifyFrameComplete(); #ifdef TIA_FRAMEMANAGER_DEBUG_LOG (cout << "frame complete @ " << myLineInState << " (" << myCurrentFrameFinalLines << " total)" << "\n").flush(); #endif // TIA_FRAMEMANAGER_DEBUG_LOG if (myAutodetectLayout) updateAutodetectedLayout(); - - myFrameRate = (myLayout == FrameLayout::pal ? 15600.0 : 15720.0) / - myCurrentFrameFinalLines; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -282,26 +253,26 @@ void FrameManager::updateAutodetectedLayout() return; } - const FrameLayout oldLayout = myLayout; + const FrameLayout oldLayout = layout(); const uInt32 deltaNTSC = abs(Int32(myCurrentFrameFinalLines) - Int32(frameLinesNTSC)), deltaPAL = abs(Int32(myCurrentFrameFinalLines) - Int32(frameLinesPAL)); if (std::min(deltaNTSC, deltaPAL) <= Metrics::tvModeDetectionTolerance) - updateLayout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal); + layout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal); else if (!myModeConfirmed) { if ( (myCurrentFrameFinalLines < frameLinesPAL) && (myCurrentFrameFinalLines > frameLinesNTSC) && (myCurrentFrameFinalLines % 2) ) - updateLayout(FrameLayout::ntsc); + layout(FrameLayout::ntsc); else - updateLayout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal); + layout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal); } - if (oldLayout == myLayout) + if (oldLayout == layout()) myFramesInMode++; else myFramesInMode = 0; @@ -311,17 +282,13 @@ void FrameManager::updateAutodetectedLayout() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameManager::updateLayout(FrameLayout layout) +void FrameManager::onLayoutChange() { - if (layout == myLayout) return; - #ifdef TIA_FRAMEMANAGER_DEBUG_LOG - (cout << "TV mode switched to " << int(layout) << "\n").flush(); + (cout << "TV mode switched to " << int(layout()) << "\n").flush(); #endif // TIA_FRAMEMANAGER_DEBUG_LOG - myLayout = layout; - - switch (myLayout) + switch (layout()) { case FrameLayout::ntsc: myVblankLines = Metrics::vblankNTSC; @@ -347,18 +314,18 @@ void FrameManager::updateLayout(FrameLayout layout) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameManager::setVblank(bool vblank) +void FrameManager::onSetVblank() { #ifdef TIA_FRAMEMANAGER_DEBUG_LOG - (cout << "vblank change " << myVblankManager.vblank() << " -> " << vblank << "@" << myLineInState << "\n").flush(); + (cout << "vblank change " << !myVblank << " -> " << myVblank << "@" << myLineInState << "\n").flush(); #endif // TIA_FRAMEMANAGER_DEBUG_LOG if (myState == State::waitForFrameStart) { - if (myVblankManager.setVblankDuringVblank(vblank, myTotalFrames <= Metrics::initialGarbageFrames)) { + if (myVblankManager.setVblankDuringVblank(myVblank, myTotalFrames <= Metrics::initialGarbageFrames)) { setState(State::frame); } } else - myVblankManager.setVblank(vblank); + myVblankManager.setVblank(myVblank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -377,106 +344,76 @@ void FrameManager::enableJitter(bool enabled) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameManager::save(Serializer& out) const +void FrameManager::updateIsRendering() { + myIsRendering = myState == State::frame && myHasStabilized; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FrameManager::onSave(Serializer& out) const { - try - { - out.putString(name()); + if (!myVblankManager.save(out)) return false; - if (!myVblankManager.save(out)) return false; + out.putBool(myAutodetectLayout); + out.putInt(uInt32(myState)); + out.putInt(myLineInState); + out.putInt(myVsyncLines); + out.putInt(myY); + out.putInt(myLastY); + out.putBool(myFramePending); - out.putInt(uInt32(myLayout)); - out.putBool(myAutodetectLayout); - out.putInt(uInt32(myState)); - out.putInt(myLineInState); - out.putInt(myCurrentFrameTotalLines); - out.putInt(myCurrentFrameFinalLines); - out.putInt(myPreviousFrameFinalLines); - out.putInt(myVsyncLines); - out.putDouble(myFrameRate); - out.putInt(myY); out.putInt(myLastY); - out.putBool(myFramePending); + out.putInt(myFramesInMode); + out.putBool(myModeConfirmed); - out.putInt(myTotalFrames); - out.putInt(myFramesInMode); - out.putBool(myModeConfirmed); + out.putInt(myStableFrames); + out.putInt(myStabilizationFrames); + out.putBool(myHasStabilized); - out.putInt(myStableFrames); - out.putInt(myStabilizationFrames); - out.putBool(myHasStabilized); + out.putInt(myVblankLines); + out.putInt(myKernelLines); + out.putInt(myOverscanLines); + out.putInt(myFrameLines); + out.putInt(myHeight); + out.putInt(myFixedHeight); - out.putBool(myVsync); + out.putBool(myJitterEnabled); - out.putInt(myVblankLines); - out.putInt(myKernelLines); - out.putInt(myOverscanLines); - out.putInt(myFrameLines); - out.putInt(myHeight); - out.putInt(myFixedHeight); - - out.putBool(myJitterEnabled); - - out.putInt(myStableFrameLines); - out.putInt(myStableFrameHeightCountdown); - } - catch(...) - { - cerr << "ERROR: TIA_FrameManager::save" << endl; - return false; - } + out.putInt(myStableFrameLines); + out.putInt(myStableFrameHeightCountdown); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameManager::load(Serializer& in) +bool FrameManager::onLoad(Serializer& in) { - try - { - if(in.getString() != name()) - return false; + if (!myVblankManager.load(in)) return false; - if (!myVblankManager.load(in)) return false; + myAutodetectLayout = in.getBool(); + myState = State(in.getInt()); + myLineInState = in.getInt(); + myVsyncLines = in.getInt(); + myY = in.getInt(); + myLastY = in.getInt(); + myFramePending = in.getBool(); - myLayout = FrameLayout(in.getInt()); - myAutodetectLayout = in.getBool(); - myState = State(in.getInt()); - myLineInState = in.getInt(); - myCurrentFrameTotalLines = in.getInt(); - myCurrentFrameFinalLines = in.getInt(); - myPreviousFrameFinalLines = in.getInt(); - myVsyncLines = in.getInt(); - myFrameRate = float(in.getDouble()); - myY = in.getInt(); myLastY = in.getInt(); - myFramePending = in.getBool(); + myFramesInMode = in.getInt(); + myModeConfirmed = in.getBool(); - myTotalFrames = in.getInt(); - myFramesInMode = in.getInt(); - myModeConfirmed = in.getBool(); + myStableFrames = in.getInt(); + myStabilizationFrames = in.getInt(); + myHasStabilized = in.getBool(); - myStableFrames = in.getInt(); - myStabilizationFrames = in.getInt(); - myHasStabilized = in.getBool(); + myVblankLines = in.getInt(); + myKernelLines = in.getInt(); + myOverscanLines = in.getInt(); + myFrameLines = in.getInt(); + myHeight = in.getInt(); + myFixedHeight = in.getInt(); - myVsync = in.getBool(); + myJitterEnabled = in.getBool(); - myVblankLines = in.getInt(); - myKernelLines = in.getInt(); - myOverscanLines = in.getInt(); - myFrameLines = in.getInt(); - myHeight = in.getInt(); - myFixedHeight = in.getInt(); - - myJitterEnabled = in.getBool(); - - myStableFrameLines = in.getInt(); - myStableFrameHeightCountdown = in.getInt(); - } - catch(...) - { - cerr << "ERROR: TIA_FrameManager::load" << endl; - return false; - } + myStableFrameLines = in.getInt(); + myStableFrameHeightCountdown = in.getInt(); return true; } diff --git a/src/emucore/tia/frame-manager/FrameManager.hxx b/src/emucore/tia/frame-manager/FrameManager.hxx index 733448919..0c3561914 100644 --- a/src/emucore/tia/frame-manager/FrameManager.hxx +++ b/src/emucore/tia/frame-manager/FrameManager.hxx @@ -18,88 +18,60 @@ #ifndef TIA_FRAME_MANAGER #define TIA_FRAME_MANAGER -#include - +#include "AbstractFrameManager.hxx" #include "VblankManager.hxx" -#include "Serializable.hxx" -#include "FrameLayout.hxx" #include "TIAConstants.hxx" #include "bspf.hxx" -class FrameManager : public Serializable -{ - public: - - using callback = std::function; - +class FrameManager: public AbstractFrameManager { public: FrameManager(); public: - void setHandlers( - callback frameStartCallback, - callback frameCompletionCallback, - callback renderingStartCallback - ); + void setJitterFactor(uInt8 factor) override { myVblankManager.setJitterFactor(factor); } - void reset(); + bool jitterEnabled() const override { return myJitterEnabled; } - void nextLine(); + void enableJitter(bool enabled) override; - void setVblank(bool vblank); + uInt32 height() const override { return myHeight; }; - void setVsync(bool vsync); + void setFixedHeight(uInt32 height) override; - bool isRendering() const { return myState == State::frame && myHasStabilized; } + uInt32 getY() const override { return myY; } - FrameLayout layout() const { return myLayout; } + uInt32 scanlines() const override { return myCurrentFrameTotalLines; } - bool vblank() const { return myVblankManager.vblank(); } + Int32 missingScanlines() const override; - bool vsync() const { return myVsync; } + void setYstart(uInt32 ystart) override { myVblankManager.setYstart(ystart); } - uInt32 height() const { return myHeight; } + uInt32 ystart() const override { return myVblankManager.ystart(); } - void setFixedHeight(uInt32 height); + bool ystartIsAuto(uInt32 line) const override { return myVblankManager.ystartIsAuto(line); }; - uInt32 getY() const { return myY; } + void autodetectLayout(bool toggle) override { myAutodetectLayout = toggle; } - uInt32 scanlines() const { return myCurrentFrameTotalLines; } + void setLayout(FrameLayout mode) override { if (!myAutodetectLayout) layout(mode); } - uInt32 scanlinesLastFrame() const { return myCurrentFrameFinalLines; } + void onSetVblank() override; - uInt32 missingScanlines() const; + void onSetVsync() override; - bool scanlineCountTransitioned() const { - return (myPreviousFrameFinalLines & 0x1) != (myCurrentFrameFinalLines & 0x1); - } + void onNextLine() override; - uInt32 frameCount() const { return myTotalFrames; } + void onReset() override; - float frameRate() const { return myFrameRate; } + void onLayoutChange() override; - void setYstart(uInt32 ystart) { myVblankManager.setYstart(ystart); } + bool onSave(Serializer& out) const override; - uInt32 ystart() const { return myVblankManager.ystart(); } - bool ystartIsAuto(uInt32 line) const { return myVblankManager.ystartIsAuto(line); } + bool onLoad(Serializer& in) override; - void autodetectLayout(bool toggle) { myAutodetectLayout = toggle; } - - void setLayout(FrameLayout mode) { if (!myAutodetectLayout) updateLayout(mode); } - - /** - Serializable methods (see that class for more information). - */ - bool save(Serializer& out) const override; - bool load(Serializer& in) override; string name() const override { return "TIA_FrameManager"; } - void setJitterFactor(uInt8 factor) { myVblankManager.setJitterFactor(factor); } - bool jitterEnabled() const { return myJitterEnabled; } - void enableJitter(bool enabled); - private: enum State { @@ -109,17 +81,8 @@ class FrameManager : public Serializable frame }; - enum VblankMode { - locked, - floating, - final, - fixed - }; - private: - void updateLayout(FrameLayout mode); - void updateAutodetectedLayout(); void setState(State state); @@ -130,27 +93,19 @@ class FrameManager : public Serializable void handleJitter(Int32 scanlineDifference); - private: + void updateIsRendering(); - callback myOnFrameStart; - callback myOnFrameComplete; - callback myOnRenderingStart; + private: VblankManager myVblankManager; - FrameLayout myLayout; bool myAutodetectLayout; State myState; uInt32 myLineInState; - uInt32 myCurrentFrameTotalLines; - uInt32 myCurrentFrameFinalLines; - uInt32 myPreviousFrameFinalLines; uInt32 myVsyncLines; - float myFrameRate; uInt32 myY, myLastY; bool myFramePending; - uInt32 myTotalFrames; uInt32 myFramesInMode; bool myModeConfirmed; @@ -158,8 +113,6 @@ class FrameManager : public Serializable uInt32 myStabilizationFrames; bool myHasStabilized; - bool myVsync; - uInt32 myVblankLines; uInt32 myKernelLines; uInt32 myOverscanLines; @@ -173,6 +126,7 @@ class FrameManager : public Serializable uInt8 myStableFrameHeightCountdown; private: + FrameManager(const FrameManager&) = delete; FrameManager(FrameManager&&) = delete; FrameManager& operator=(const FrameManager&) = delete;