Refactor FrameManager to extend AbstractFrameManager.

This commit is contained in:
Christian Speckner 2017-10-07 01:41:47 +02:00
parent d52562975d
commit a400238c19
7 changed files with 197 additions and 278 deletions

View File

@ -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])

View File

@ -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:

View File

@ -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.

View File

@ -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
{

View File

@ -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;

View File

@ -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;
}

View File

@ -18,88 +18,60 @@
#ifndef TIA_FRAME_MANAGER
#define TIA_FRAME_MANAGER
#include <functional>
#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<void()>;
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;