Limit the number of lines FrameManager waits for frame with large scanlines, refactoring.

This commit is contained in:
Christian Speckner 2017-01-10 23:59:36 +01:00
parent a6725f2436
commit aba48e85cf
5 changed files with 120 additions and 118 deletions

View File

@ -118,7 +118,7 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
myOSystem.settings().setValue("fastscbios", true);
mySystem->reset(true); // autodetect in reset enabled
myTIA->autodetectTvMode(true);
for(int i = 0; i < 60; ++i)
for(int i = 0; i < 80; ++i)
myTIA->update();
myDisplayFormat = myTIA->tvMode() == TvMode::pal ? "PAL" : "NTSC";
if(myProperties.get(Display_Format) == "AUTO")

View File

@ -29,10 +29,11 @@ enum Metrics: uInt32 {
overscanNTSC = 30,
overscanPAL = 36,
vsync = 3,
vsyncLimit = 30,
visibleOverscan = 20,
maxUnderscan = 10,
tvModeDetectionTolerance = 20,
initialGarbageFrames = 10,
initialGarbageFrames = 20,
framesForModeConfirmation = 5,
maxVblankViolations = 2,
minStableVblankFrames = 1
@ -71,7 +72,6 @@ void FrameManager::reset()
myCurrentFrameTotalLines = myCurrentFrameFinalLines = 0;
myFrameRate = 60.0;
myLineInState = 0;
myMaxVisibleFrameLines = 0;
myVsync = false;
myVblank = false;
myTotalFrames = 0;
@ -81,6 +81,7 @@ void FrameManager::reset()
myVblankViolations = 0;
myStableVblankFrames = 0;
myVblankViolated = false;
myVsyncLines = 0;
if (myVblankMode != VblankMode::fixed) myVblankMode = VblankMode::floating;
}
@ -94,7 +95,17 @@ void FrameManager::nextLine()
switch (myState)
{
case State::waitForVsyncStart:
if (Int32(myLineInState) > Int32(myFrameLines - myCurrentFrameFinalLines) || !myCurrentFrameFinalLines)
myVsyncLines++;
if (myVsyncLines > Metrics::vsyncLimit) setState(State::waitForFrameStart);
break;
case State::waitForVsyncEnd:
if (++myVsyncLines > Metrics::vsyncLimit)
setState(State::waitForFrameStart);
break;
case State::waitForFrameStart:
@ -164,27 +175,6 @@ void FrameManager::nextLineInVsync()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setYstart(uInt32 ystart)
{
if (ystart == myYstart) return;
myYstart = ystart;
myVblankMode = ystart ? VblankMode::fixed : VblankMode::floating;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameManager::ystart() const {
return myYstart;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setVblank(bool vblank)
{
myVblank = vblank;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setVsync(bool vsync)
{
@ -220,90 +210,6 @@ void FrameManager::setVsync(bool vsync)
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameManager::isRendering() const
{
return myState == State::frame;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TvMode FrameManager::tvMode() const
{
return myMode;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameManager::height() const
{
return myFixedHeight > 0 ? myFixedHeight : (myKernelLines + Metrics::visibleOverscan);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setFixedHeight(uInt32 height)
{
myFixedHeight = height;
(cout << myFixedHeight << "\n").flush();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameManager::currentLine() const
{
return myState == State::frame ? myLineInState : 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameManager::scanlines() const
{
return myState == State::frame ? myCurrentFrameTotalLines : myCurrentFrameFinalLines;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameManager::maxVisibleFrameLines() const
{
return myMaxVisibleFrameLines;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setTvMode(TvMode mode)
{
if (!myAutodetectTvMode) updateTvMode(mode);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::autodetectTvMode(bool toggle)
{
myAutodetectTvMode = toggle;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::updateTvMode(TvMode mode)
{
if (mode == myMode) return;
myMode = mode;
switch (myMode)
{
case TvMode::ntsc:
myVblankLines = Metrics::vblankNTSC;
myKernelLines = Metrics::kernelNTSC;
myOverscanLines = Metrics::overscanNTSC;
break;
case TvMode::pal:
myVblankLines = Metrics::vblankPAL;
myKernelLines = Metrics::kernelPAL;
myOverscanLines = Metrics::overscanPAL;
break;
default:
throw runtime_error("frame manager: invalid TV mode");
}
myFrameLines = Metrics::vsync + myVblankLines + myKernelLines + myOverscanLines;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setState(FrameManager::State state)
{
@ -318,10 +224,12 @@ void FrameManager::setState(FrameManager::State state)
switch (myState) {
case State::waitForFrameStart:
myVsyncLines = 0;
myVblankViolated = false;
break;
case State::frame:
myVsyncLines = 0;
if (myOnFrameStart) myOnFrameStart();
break;
@ -337,15 +245,12 @@ void FrameManager::finalizeFrame(FrameManager::State state)
myCurrentFrameTotalLines = 0;
myTotalFrames++;
if (myTotalFrames > Metrics::initialGarbageFrames)
myMaxVisibleFrameLines = std::max(myMaxVisibleFrameLines, myLineInState);
if (myOnFrameComplete) {
myOnFrameComplete();
}
#ifdef TIA_FRAMEMANAGER_DEBUG_LOG
(cout << "frame complete @ " << myLineInState << " (" << myCurrentFrameTotalLines << " total)" << "\n").flush();
(cout << "frame complete @ " << myLineInState << " (" << myCurrentFrameFinalLines << " total)" << "\n").flush();
#endif // TIA_FRAMEMANAGER_DEBUG_LOG
setState(state);
@ -391,6 +296,103 @@ void FrameManager::updateAutodetectedTvMode()
myModeConfirmed = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::updateTvMode(TvMode mode)
{
if (mode == myMode) return;
myMode = mode;
switch (myMode)
{
case TvMode::ntsc:
myVblankLines = Metrics::vblankNTSC;
myKernelLines = Metrics::kernelNTSC;
myOverscanLines = Metrics::overscanNTSC;
break;
case TvMode::pal:
myVblankLines = Metrics::vblankPAL;
myKernelLines = Metrics::kernelPAL;
myOverscanLines = Metrics::overscanPAL;
break;
default:
throw runtime_error("frame manager: invalid TV mode");
}
myFrameLines = Metrics::vsync + myVblankLines + myKernelLines + myOverscanLines;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setYstart(uInt32 ystart)
{
if (ystart == myYstart) return;
myYstart = ystart;
myVblankMode = ystart ? VblankMode::fixed : VblankMode::floating;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameManager::ystart() const {
return myYstart;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setVblank(bool vblank)
{
myVblank = vblank;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameManager::isRendering() const
{
return myState == State::frame;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TvMode FrameManager::tvMode() const
{
return myMode;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameManager::height() const
{
return myFixedHeight > 0 ? myFixedHeight : (myKernelLines + Metrics::visibleOverscan);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setFixedHeight(uInt32 height)
{
myFixedHeight = height;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameManager::currentLine() const
{
return myState == State::frame ? myLineInState : 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameManager::scanlines() const
{
return myState == State::frame ? myCurrentFrameTotalLines : myCurrentFrameFinalLines;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setTvMode(TvMode mode)
{
if (!myAutodetectTvMode) updateTvMode(mode);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::autodetectTvMode(bool toggle)
{
myAutodetectTvMode = toggle;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// TODO: implement this once the class is finalized
bool FrameManager::save(Serializer& out) const

View File

@ -61,8 +61,6 @@ class FrameManager : public Serializable
uInt32 scanlines() const;
uInt32 maxVisibleFrameLines() const;
uInt32 frameCount() const { return myTotalFrames; }
float frameRate() const { return myFrameRate; }
@ -124,7 +122,7 @@ class FrameManager : public Serializable
uInt32 myLineInState;
uInt32 myCurrentFrameTotalLines;
uInt32 myCurrentFrameFinalLines;
uInt32 myMaxVisibleFrameLines;
uInt32 myVsyncLines;
float myFrameRate;
uInt32 myTotalFrames;

View File

@ -115,6 +115,7 @@ void TIA::reset()
myLastCycle = 0;
mySubClock = 0;
myXDelta = 0;
myLastFrameHeight = 0;
myBackground.reset();
myPlayfield.reset();
@ -146,8 +147,6 @@ void TIA::frameReset()
clearBuffers();
myAutoFrameEnabled = (mySettings.getInt("framerate") <= 0);
// TODO - make use of ystart and height, maybe move to FrameManager
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -926,11 +925,13 @@ void TIA::onFrameComplete()
mySystem->m6502().stop();
mySystem->resetCycles();
Int32 missingScanlines = myFrameManager.maxVisibleFrameLines() - myFrameManager.currentLine();
Int32 missingScanlines = myLastFrameHeight - myFrameManager.currentLine();
if (missingScanlines > 0)
memset(myCurrentFrameBuffer.get() + 160 * myFrameManager.currentLine(), 0, missingScanlines * 160);
myLastFrameHeight = myFrameManager.currentLine();
// Recalculate framerate, attempting to auto-correct for scanline 'jumps'
if(myAutoFrameEnabled)
myConsole.setFramerate(myFrameManager.frameRate());

View File

@ -443,6 +443,7 @@ class TIA : public Device
// Pointer to the current and previous frame buffers
BytePtr myCurrentFrameBuffer;
BytePtr myPreviousFrameBuffer;
uInt32 myLastFrameHeight;
Background myBackground;
Playfield myPlayfield;