mirror of https://github.com/stella-emu/stella.git
Refactor FrameManager to extend AbstractFrameManager.
This commit is contained in:
parent
d52562975d
commit
a400238c19
|
@ -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])
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,27 +344,23 @@ void FrameManager::enableJitter(bool enabled)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameManager::save(Serializer& out) const
|
||||
{
|
||||
try
|
||||
{
|
||||
out.putString(name());
|
||||
void FrameManager::updateIsRendering() {
|
||||
myIsRendering = myState == State::frame && myHasStabilized;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameManager::onSave(Serializer& out) const
|
||||
{
|
||||
if (!myVblankManager.save(out)) return false;
|
||||
|
||||
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.putInt(myY);
|
||||
out.putInt(myLastY);
|
||||
out.putBool(myFramePending);
|
||||
|
||||
out.putInt(myTotalFrames);
|
||||
out.putInt(myFramesInMode);
|
||||
out.putBool(myModeConfirmed);
|
||||
|
||||
|
@ -405,8 +368,6 @@ bool FrameManager::save(Serializer& out) const
|
|||
out.putInt(myStabilizationFrames);
|
||||
out.putBool(myHasStabilized);
|
||||
|
||||
out.putBool(myVsync);
|
||||
|
||||
out.putInt(myVblankLines);
|
||||
out.putInt(myKernelLines);
|
||||
out.putInt(myOverscanLines);
|
||||
|
@ -418,39 +379,23 @@ bool FrameManager::save(Serializer& out) const
|
|||
|
||||
out.putInt(myStableFrameLines);
|
||||
out.putInt(myStableFrameHeightCountdown);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "ERROR: TIA_FrameManager::save" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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();
|
||||
myY = in.getInt();
|
||||
myLastY = in.getInt();
|
||||
myFramePending = in.getBool();
|
||||
|
||||
myTotalFrames = in.getInt();
|
||||
myFramesInMode = in.getInt();
|
||||
myModeConfirmed = in.getBool();
|
||||
|
||||
|
@ -458,8 +403,6 @@ bool FrameManager::load(Serializer& in)
|
|||
myStabilizationFrames = in.getInt();
|
||||
myHasStabilized = in.getBool();
|
||||
|
||||
myVsync = in.getBool();
|
||||
|
||||
myVblankLines = in.getInt();
|
||||
myKernelLines = in.getInt();
|
||||
myOverscanLines = in.getInt();
|
||||
|
@ -471,12 +414,6 @@ bool FrameManager::load(Serializer& in)
|
|||
|
||||
myStableFrameLines = in.getInt();
|
||||
myStableFrameHeightCountdown = in.getInt();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "ERROR: TIA_FrameManager::load" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue