mirror of https://github.com/stella-emu/stella.git
Ystart is sleeping with the fishes.
This commit is contained in:
parent
356f06598d
commit
ec35026329
|
@ -30,5 +30,4 @@ src/windows/Stella.vcxproj.user
|
|||
src/**/*.psess
|
||||
src/**/*.vspx
|
||||
src/**/**.pdb
|
||||
|
||||
|
||||
Stella.xcscheme
|
||||
|
|
|
@ -120,7 +120,7 @@ void TiaOutputWidget::handleMouseDown(int x, int y, MouseButton b, int clickCoun
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TiaOutputWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||
{
|
||||
uInt32 ystart = instance().console().tia().ystart();
|
||||
uInt32 startLine = instance().console().tia().startLine();
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
|
@ -131,7 +131,7 @@ void TiaOutputWidget::handleCommand(CommandSender* sender, int cmd, int data, in
|
|||
if(rmb == "scanline")
|
||||
{
|
||||
ostringstream command;
|
||||
int lines = myClickY + ystart - instance().console().tia().scanlines();
|
||||
int lines = myClickY + startLine - instance().console().tia().scanlines();
|
||||
|
||||
if(lines < 0)
|
||||
lines += instance().console().tia().scanlinesLastFrame();
|
||||
|
@ -145,7 +145,7 @@ void TiaOutputWidget::handleCommand(CommandSender* sender, int cmd, int data, in
|
|||
else if(rmb == "bp")
|
||||
{
|
||||
ostringstream command;
|
||||
int scanline = myClickY + ystart;
|
||||
int scanline = myClickY + startLine;
|
||||
command << "breakif _scan==#" << scanline;
|
||||
string message = instance().debugger().parser().run(command.str());
|
||||
instance().frameBuffer().showMessage(message);
|
||||
|
|
|
@ -249,13 +249,13 @@ void TiaZoomWidget::handleCommand(CommandSender* sender, int cmd, int data, int
|
|||
{
|
||||
case ContextMenu::kItemSelectedCmd:
|
||||
{
|
||||
uInt32 ystart = instance().console().tia().ystart();
|
||||
uInt32 startLine = instance().console().tia().startLine();
|
||||
const string& rmb = myMenu->getSelectedTag().toString();
|
||||
|
||||
if(rmb == "scanline")
|
||||
{
|
||||
ostringstream command;
|
||||
int lines = myClickY / myZoomLevel + myOffY + ystart - instance().console().tia().scanlines();
|
||||
int lines = myClickY / myZoomLevel + myOffY + startLine - instance().console().tia().scanlines();
|
||||
|
||||
if (lines < 0)
|
||||
lines += instance().console().tia().scanlinesLastFrame();
|
||||
|
@ -269,7 +269,7 @@ void TiaZoomWidget::handleCommand(CommandSender* sender, int cmd, int data, int
|
|||
else if(rmb == "bp")
|
||||
{
|
||||
ostringstream command;
|
||||
int scanline = myClickY / myZoomLevel + myOffY + ystart;
|
||||
int scanline = myClickY / myZoomLevel + myOffY + startLine;
|
||||
command << "breakif _scan==#" << scanline;
|
||||
string message = instance().debugger().parser().run(command.str());
|
||||
instance().frameBuffer().showMessage(message);
|
||||
|
|
|
@ -60,7 +60,6 @@
|
|||
#include "AudioSettings.hxx"
|
||||
#include "frame-manager/FrameManager.hxx"
|
||||
#include "frame-manager/FrameLayoutDetector.hxx"
|
||||
#include "frame-manager/YStartDetector.hxx"
|
||||
|
||||
#ifdef CHEATCODE_SUPPORT
|
||||
#include "CheatManager.hxx"
|
||||
|
@ -71,10 +70,6 @@
|
|||
|
||||
#include "Console.hxx"
|
||||
|
||||
namespace {
|
||||
constexpr uInt8 YSTART_EXTRA = 2;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
|
||||
const Properties& props, AudioSettings& audioSettings)
|
||||
|
@ -84,8 +79,6 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
|
|||
myCart(std::move(cart)),
|
||||
myDisplayFormat(""), // Unknown TV format @ start
|
||||
myCurrentFormat(0), // Unknown format @ start,
|
||||
myAutodetectedYstart(0),
|
||||
myYStartAutodetected(false),
|
||||
myFormatAutodetected(false),
|
||||
myUserPaletteDefined(false),
|
||||
myConsoleTiming(ConsoleTiming::ntsc),
|
||||
|
@ -151,10 +144,6 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
|
|||
}
|
||||
}
|
||||
|
||||
if (atoi(myProperties.get(PropType::Display_VCenter).c_str()) == 0) {
|
||||
autodetectYStart();
|
||||
}
|
||||
|
||||
myConsoleInfo.DisplayFormat = myDisplayFormat + autodetected;
|
||||
|
||||
// Set up the correct properties used when toggling format
|
||||
|
@ -265,49 +254,6 @@ void Console::redetectFrameLayout()
|
|||
save(s);
|
||||
|
||||
autodetectFrameLayout(false);
|
||||
if (myYStartAutodetected) autodetectYStart();
|
||||
|
||||
load(s);
|
||||
initializeAudio();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Console::autodetectYStart(bool reset)
|
||||
{
|
||||
// We turn off the SuperCharger progress bars, otherwise the SC BIOS
|
||||
// will take over 250 frames!
|
||||
// The 'fastscbios' option must be changed before the system is reset
|
||||
bool fastscbios = myOSystem.settings().getBool("fastscbios");
|
||||
myOSystem.settings().setValue("fastscbios", true);
|
||||
|
||||
YStartDetector ystartDetector;
|
||||
ystartDetector.setLayout(myDisplayFormat == "PAL" ? FrameLayout::pal : FrameLayout::ntsc);
|
||||
myTIA->setFrameManager(&ystartDetector);
|
||||
|
||||
if (reset) {
|
||||
mySystem->reset(true);
|
||||
myRiot->update();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 80; i++) myTIA->update();
|
||||
|
||||
myTIA->setFrameManager(myFrameManager.get());
|
||||
|
||||
myAutodetectedYstart = ystartDetector.detectedYStart() - YSTART_EXTRA;
|
||||
|
||||
// Don't forget to reset the SC progress bars again
|
||||
myOSystem.settings().setValue("fastscbios", fastscbios);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Console::redetectYStart()
|
||||
{
|
||||
Serializer s;
|
||||
|
||||
myOSystem.sound().close();
|
||||
save(s);
|
||||
|
||||
autodetectYStart(false);
|
||||
|
||||
load(s);
|
||||
initializeAudio();
|
||||
|
@ -696,75 +642,57 @@ void Console::fry() const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Console::changeVerticalCenter(int direction)
|
||||
{
|
||||
uInt32 ystart = myTIA->ystart();
|
||||
Int32 vcenter = myTIA->vcenter();
|
||||
|
||||
if(direction == +1) // increase YStart
|
||||
if(direction == +1) // increase vcenter
|
||||
{
|
||||
if(ystart >= TIAConstants::maxYStart)
|
||||
if(vcenter >= TIAConstants::maxVcenter)
|
||||
{
|
||||
myOSystem.frameBuffer().showMessage("V-Center at minimum");
|
||||
return;
|
||||
}
|
||||
|
||||
++ystart;
|
||||
myYStartAutodetected = false;
|
||||
++vcenter;
|
||||
}
|
||||
else if(direction == -1) // decrease YStart
|
||||
else if(direction == -1) // decrease vcenter
|
||||
{
|
||||
if (ystart <= TIAConstants::minYStart)
|
||||
if (vcenter <= TIAConstants::minVcenter)
|
||||
{
|
||||
myOSystem.frameBuffer().showMessage("V-Center at maximum");
|
||||
return;
|
||||
}
|
||||
|
||||
--ystart;
|
||||
myYStartAutodetected = false;
|
||||
--vcenter;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
ostringstream ss;
|
||||
ss << ystart;
|
||||
ss << vcenter;
|
||||
|
||||
myProperties.set(PropType::Display_VCenter, ss.str());
|
||||
if (ystart != myTIA->ystart()) myTIA->setYStart(ystart);
|
||||
if (vcenter != myTIA->vcenter()) myTIA->setVcenter(vcenter);
|
||||
|
||||
// use vertical center instead of y-start for display
|
||||
int vCenter = TIAConstants::defaultYStart - ystart;
|
||||
ss.str("");
|
||||
ss << "V-Center " << vCenter;
|
||||
ss << "V-Center " << vcenter;
|
||||
|
||||
myOSystem.frameBuffer().showMessage(ss.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Console::updateYStart(uInt32 ystart)
|
||||
void Console::updateVcenter(Int32 vcenter)
|
||||
{
|
||||
if (ystart > TIAConstants::maxYStart) return;
|
||||
if (vcenter > TIAConstants::maxVcenter | vcenter < TIAConstants::minVcenter) return;
|
||||
|
||||
if (ystart == 0) {
|
||||
if (myYStartAutodetected) return;
|
||||
|
||||
redetectYStart();
|
||||
myYStartAutodetected = true;
|
||||
ystart = myAutodetectedYstart;
|
||||
} else
|
||||
myYStartAutodetected = false;
|
||||
|
||||
if (ystart != myTIA->ystart()) myTIA->setYStart(ystart);
|
||||
if (vcenter != myTIA->vcenter()) myTIA->setVcenter(vcenter);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Console::setTIAProperties()
|
||||
{
|
||||
// FIXME - ystart is probably disappearing soon, or at least autodetection is
|
||||
uInt32 ystart = atoi(myProperties.get(PropType::Display_VCenter).c_str());
|
||||
if(ystart != 0)
|
||||
ystart = BSPF::clamp(ystart, 0u, TIAConstants::maxYStart);
|
||||
else {
|
||||
ystart = myAutodetectedYstart;
|
||||
myYStartAutodetected = true;
|
||||
}
|
||||
Int32 vcenter = BSPF::clamp(
|
||||
static_cast<Int32>(atoi(myProperties.get(PropType::Display_VCenter).c_str())), TIAConstants::minVcenter, TIAConstants::maxVcenter
|
||||
);
|
||||
|
||||
if(myDisplayFormat == "NTSC" || myDisplayFormat == "PAL60" ||
|
||||
myDisplayFormat == "SECAM60")
|
||||
|
@ -778,7 +706,7 @@ void Console::setTIAProperties()
|
|||
myTIA->setLayout(FrameLayout::pal);
|
||||
}
|
||||
|
||||
myTIA->setYStart(ystart);
|
||||
myTIA->setVcenter(vcenter);
|
||||
|
||||
myEmulationTiming.updateFrameLayout(myTIA->frameLayout());
|
||||
myEmulationTiming.updateConsoleTiming(myConsoleTiming);
|
||||
|
|
|
@ -306,9 +306,9 @@ class Console : public Serializable, public ConsoleIO
|
|||
void toggleJitter() const;
|
||||
|
||||
/**
|
||||
* Update yatart and run autodetection if necessary.
|
||||
* Update vcenter
|
||||
*/
|
||||
void updateYStart(uInt32 ystart);
|
||||
void updateVcenter(Int32 vcenter);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -316,23 +316,13 @@ class Console : public Serializable, public ConsoleIO
|
|||
*/
|
||||
void autodetectFrameLayout(bool reset = true);
|
||||
|
||||
/**
|
||||
* Dryrun the emulation and detect ystart (the first visible scanline).
|
||||
*/
|
||||
void autodetectYStart(bool reset = true);
|
||||
|
||||
/**
|
||||
* Rerun frame layout autodetection
|
||||
*/
|
||||
void redetectFrameLayout();
|
||||
|
||||
/**
|
||||
* Rerun ystart autodetection.
|
||||
*/
|
||||
void redetectYStart();
|
||||
|
||||
/**
|
||||
Sets various properties of the TIA (YStart, Height, etc) based on
|
||||
Sets various properties of the TIA (vcenter, Height, etc) based on
|
||||
the current display format.
|
||||
*/
|
||||
void setTIAProperties();
|
||||
|
@ -411,12 +401,6 @@ class Console : public Serializable, public ConsoleIO
|
|||
// Display format currently in use
|
||||
uInt32 myCurrentFormat;
|
||||
|
||||
// Autodetected ystart.
|
||||
uInt32 myAutodetectedYstart;
|
||||
|
||||
// Is ystart currently autodetected?
|
||||
bool myYStartAutodetected;
|
||||
|
||||
// Is the TV format autodetected?
|
||||
bool myFormatAutodetected;
|
||||
|
||||
|
|
|
@ -587,7 +587,7 @@ unique_ptr<Console> OSystem::openConsole(const FilesystemNode& romfile, string&
|
|||
CMDLINE_PROPS_UPDATE("rd", PropType::Console_RightDiff);
|
||||
CMDLINE_PROPS_UPDATE("tv", PropType::Console_TVType);
|
||||
CMDLINE_PROPS_UPDATE("format", PropType::Display_Format);
|
||||
CMDLINE_PROPS_UPDATE("ystart", PropType::Display_VCenter); // TODO (SA): change option
|
||||
CMDLINE_PROPS_UPDATE("vcenter", PropType::Display_VCenter); // TODO (SA): change option
|
||||
CMDLINE_PROPS_UPDATE("pp", PropType::Display_Phosphor);
|
||||
CMDLINE_PROPS_UPDATE("ppblend", PropType::Display_PPBlend);
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "TIA.hxx"
|
||||
#include "ConsoleTiming.hxx"
|
||||
#include "FrameManager.hxx"
|
||||
#include "YStartDetector.hxx"
|
||||
#include "FrameLayoutDetector.hxx"
|
||||
#include "EmulationTiming.hxx"
|
||||
#include "ConsoleTiming.hxx"
|
||||
|
@ -159,20 +158,9 @@ bool ProfilingRunner::runOne(const ProfilingRun run)
|
|||
|
||||
(cout << endl).flush();
|
||||
|
||||
YStartDetector ystartDetector;
|
||||
tia.setFrameManager(&ystartDetector);
|
||||
system.reset();
|
||||
|
||||
(cout << "detecting ystart... ").flush();
|
||||
for (int i = 0; i < 80; i++) tia.update();
|
||||
|
||||
uInt32 yStart = ystartDetector.detectedYStart();
|
||||
(cout << yStart << endl).flush();
|
||||
|
||||
FrameManager frameManager;
|
||||
tia.setFrameManager(&frameManager);
|
||||
tia.setLayout(frameLayout);
|
||||
tia.setYStart(yStart);
|
||||
|
||||
system.reset();
|
||||
|
||||
|
|
|
@ -553,7 +553,7 @@ void Settings::usage() const
|
|||
<< " -bc <arg> Same as using both -lc and -rc\n"
|
||||
<< " -cp <arg> Sets the 'Controller.SwapPaddles' property\n"
|
||||
<< " -format <arg> Sets the 'Display.Format' property\n"
|
||||
<< " -ystart <arg> Sets the 'Display.YStart' property\n"
|
||||
<< " -vcenter <arg> Sets the 'Display.vcenter' property\n"
|
||||
<< " -pp <arg> Sets the 'Display.Phosphor' property\n"
|
||||
<< " -ppblend <arg> Sets the 'Display.PPBlend' property\n"
|
||||
<< endl
|
||||
|
|
|
@ -249,12 +249,13 @@ class TIA : public Device
|
|||
*/
|
||||
uInt32 width() const { return TIAConstants::H_PIXEL; }
|
||||
uInt32 height() const { return myFrameManager->height(); }
|
||||
uInt32 ystart() const { return myFrameManager->ystart(); }
|
||||
Int32 vcenter() const { return myFrameManager->vcenter(); }
|
||||
uInt32 startLine() const { return myFrameManager->startLine(); }
|
||||
|
||||
/**
|
||||
Changes the current YStart property.
|
||||
Changes the current vcenter property.
|
||||
*/
|
||||
void setYStart(uInt32 ystart) { myFrameManager->setYstart(ystart); }
|
||||
void setVcenter(Int32 vcenter) { myFrameManager->setVcenter(vcenter); }
|
||||
|
||||
void setLayout(FrameLayout layout) { myFrameManager->setLayout(layout); }
|
||||
FrameLayout frameLayout() const { return myFrameManager->layout(); }
|
||||
|
|
|
@ -24,9 +24,8 @@ namespace TIAConstants {
|
|||
|
||||
static constexpr uInt32 frameBufferWidth = 160;
|
||||
static constexpr uInt32 frameBufferHeight = 320;
|
||||
static constexpr uInt32 defaultYStart = 34; // TODO: PAL-50 might need a different value here
|
||||
static constexpr uInt32 minYStart = defaultYStart - 15; // limit to reasonable values
|
||||
static constexpr uInt32 maxYStart = defaultYStart + 15; // limit to reasonable values
|
||||
static constexpr Int32 maxVcenter = 20; // limit to reasonable values
|
||||
static constexpr Int32 minVcenter = -20; // limit to reasonable values
|
||||
static constexpr uInt32 viewableWidth = 320;
|
||||
static constexpr uInt32 viewableHeight = 240;
|
||||
static constexpr uInt32 initialGarbageFrames = 10;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "Serializable.hxx"
|
||||
#include "FrameLayout.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
class AbstractFrameManager : public Serializable
|
||||
{
|
||||
|
@ -160,14 +161,19 @@ class AbstractFrameManager : public Serializable
|
|||
virtual uInt32 scanlines() const { return 0; }
|
||||
|
||||
/**
|
||||
* Configure the ystart value.
|
||||
* Configure the vcenter value.
|
||||
*/
|
||||
virtual void setYstart(uInt32 ystart) {}
|
||||
virtual void setVcenter(Int32 vcenter) {}
|
||||
|
||||
/**
|
||||
* The configured ystart value.
|
||||
* The configured vcenter value.
|
||||
*/
|
||||
virtual uInt32 ystart() const { return 0; }
|
||||
virtual Int32 vcenter() const { return 0; }
|
||||
|
||||
/**
|
||||
* The corresponding start line.
|
||||
*/
|
||||
virtual uInt32 startLine() const { return 0; }
|
||||
|
||||
/**
|
||||
* Set the frame layout. This may be a noop (on the autodetection manager).
|
||||
|
|
|
@ -31,7 +31,9 @@ enum Metrics: uInt32 {
|
|||
vsync = 3,
|
||||
maxLinesVsync = 50,
|
||||
visibleOverscan = 20,
|
||||
initialGarbageFrames = TIAConstants::initialGarbageFrames
|
||||
initialGarbageFrames = TIAConstants::initialGarbageFrames,
|
||||
ystartNTSC = 34,
|
||||
ystartPAL = 39
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -46,9 +48,11 @@ FrameManager::FrameManager()
|
|||
myFrameLines(0),
|
||||
myHeight(0),
|
||||
myYStart(0),
|
||||
myVcenter(0),
|
||||
myJitterEnabled(false)
|
||||
{
|
||||
reset();
|
||||
updateYStart();
|
||||
onLayoutChange();
|
||||
}
|
||||
|
||||
|
@ -98,7 +102,7 @@ void FrameManager::onNextLine()
|
|||
case State::frame:
|
||||
if (myLineInState >= myHeight)
|
||||
{
|
||||
myLastY = ystart() + myY; // Last line drawn in this frame
|
||||
myLastY = myYStart + myY; // Last line drawn in this frame
|
||||
setState(State::waitForVsyncStart);
|
||||
}
|
||||
break;
|
||||
|
@ -121,10 +125,10 @@ Int32 FrameManager::missingScanlines() const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameManager::setYstart(uInt32 ystart)
|
||||
void FrameManager::setVcenter(Int32 vcenter)
|
||||
{
|
||||
myYStart = ystart;
|
||||
myJitterEmulation.setYStart(ystart);
|
||||
myVcenter = vcenter;
|
||||
updateYStart();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -241,3 +245,9 @@ bool FrameManager::onLoad(Serializer& in)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameManager::updateYStart() {
|
||||
myYStart = (layout() == FrameLayout::ntsc ? Metrics::ystartNTSC : Metrics::ystartPAL) - myVcenter;
|
||||
myJitterEmulation.setYStart(myYStart);
|
||||
}
|
||||
|
|
|
@ -44,9 +44,11 @@ class FrameManager: public AbstractFrameManager {
|
|||
|
||||
Int32 missingScanlines() const override;
|
||||
|
||||
void setYstart(uInt32 ystart) override;
|
||||
void setVcenter(Int32 vcenter) override;
|
||||
|
||||
uInt32 ystart() const override { return myYStart; }
|
||||
Int32 vcenter() const override { return myVcenter; }
|
||||
|
||||
uInt32 startLine() const override { return myYStart; }
|
||||
|
||||
void setLayout(FrameLayout mode) override { layout(mode); }
|
||||
|
||||
|
@ -77,6 +79,8 @@ class FrameManager: public AbstractFrameManager {
|
|||
|
||||
void updateIsRendering();
|
||||
|
||||
void updateYStart();
|
||||
|
||||
private:
|
||||
|
||||
State myState;
|
||||
|
@ -90,6 +94,7 @@ class FrameManager: public AbstractFrameManager {
|
|||
uInt32 myFrameLines;
|
||||
uInt32 myHeight;
|
||||
uInt32 myYStart;
|
||||
Int32 myVcenter;
|
||||
|
||||
bool myJitterEnabled;
|
||||
|
||||
|
|
|
@ -1,230 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "YStartDetector.hxx"
|
||||
#include "TIAConstants.hxx"
|
||||
|
||||
/**
|
||||
* Misc. numeric constants used in the algorithm.
|
||||
*/
|
||||
enum Metrics: uInt32 {
|
||||
// ideal world frame sizes
|
||||
frameLinesNTSC = 262,
|
||||
frameLinesPAL = 312,
|
||||
|
||||
// the ideal vblank zone
|
||||
vblankNTSC = 37,
|
||||
vblankPAL = 45,
|
||||
|
||||
// number of scanlines to wait for vsync to start (exceeding after the ideal frame size) and stop
|
||||
waitForVsync = 50,
|
||||
|
||||
// max lines underscan
|
||||
maxUnderscan = 10,
|
||||
|
||||
// max lines deviations from detected ystart before we switch back to floating
|
||||
maxVblankViolations = 2,
|
||||
|
||||
// switch to fixed mode after this number of stable frames (+1)
|
||||
minStableVblankFrames = 1,
|
||||
|
||||
// no transitions to fixed mode will happend during those
|
||||
initialGarbageFrames = TIAConstants::initialGarbageFrames
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
YStartDetector::YStartDetector()
|
||||
: myState(State::waitForVsyncStart),
|
||||
myVblankMode(VblankMode::floating),
|
||||
myLinesWaitingForVsyncToStart(0),
|
||||
myCurrentVblankLines(0),
|
||||
myLastVblankLines(0),
|
||||
myVblankViolations(0),
|
||||
myStableVblankFrames(0),
|
||||
myVblankViolated(false)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 YStartDetector::detectedYStart() const
|
||||
{
|
||||
return myLastVblankLines;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void YStartDetector::onReset()
|
||||
{
|
||||
myState = State::waitForVsyncStart;
|
||||
myVblankMode = VblankMode::floating;
|
||||
myLinesWaitingForVsyncToStart = 0;
|
||||
myCurrentVblankLines = 0;
|
||||
myLastVblankLines = 0;
|
||||
myVblankViolations = 0;
|
||||
myStableVblankFrames = 0;
|
||||
myVblankViolated = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void YStartDetector::onSetVsync()
|
||||
{
|
||||
if (myVsync)
|
||||
setState(State::waitForVsyncEnd);
|
||||
else
|
||||
setState(State::waitForFrameStart);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void YStartDetector::onNextLine()
|
||||
{
|
||||
const uInt32 frameLines = layout() == FrameLayout::ntsc ? Metrics::frameLinesNTSC : Metrics::frameLinesPAL;
|
||||
|
||||
switch (myState) {
|
||||
case State::waitForVsyncStart:
|
||||
// We start counting the number of "lines spent while waiting for vsync start" from
|
||||
// the "ideal" frame size (corrected by the three scanlines spent in vsync).
|
||||
if (myCurrentFrameTotalLines > frameLines - 3 || myTotalFrames == 0)
|
||||
++myLinesWaitingForVsyncToStart;
|
||||
|
||||
if (myLinesWaitingForVsyncToStart > Metrics::waitForVsync) setState(State::waitForVsyncEnd);
|
||||
|
||||
break;
|
||||
|
||||
case State::waitForVsyncEnd:
|
||||
if (++myLinesWaitingForVsyncToStart > Metrics::waitForVsync) setState(State::waitForFrameStart);
|
||||
|
||||
break;
|
||||
|
||||
case State::waitForFrameStart:
|
||||
if (shouldTransitionToFrame()) setState(State::waitForVsyncStart);
|
||||
else ++myCurrentVblankLines;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error("cannot happen");
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool YStartDetector::shouldTransitionToFrame()
|
||||
{
|
||||
uInt32 vblankLines = layout() == FrameLayout::pal ? Metrics::vblankPAL : Metrics::vblankNTSC;
|
||||
|
||||
// Are we free to transition as per vblank cycle?
|
||||
bool shouldTransition = myCurrentVblankLines + 1 >= (myVblank ? vblankLines : vblankLines - Metrics::maxUnderscan);
|
||||
|
||||
// Do we **actually** transition? This depends on what mode we are in.
|
||||
bool transition = false;
|
||||
|
||||
switch (myVblankMode) {
|
||||
// Floating mode: we still are looking for a stable frame start
|
||||
case VblankMode::floating:
|
||||
|
||||
// Are we free to transition?
|
||||
if (shouldTransition) {
|
||||
// Is this same scanline in which the transition ocurred last frame?
|
||||
if (myTotalFrames > Metrics::initialGarbageFrames && myCurrentVblankLines == myLastVblankLines)
|
||||
// Yes? -> Increase the number of stable frames
|
||||
++myStableVblankFrames;
|
||||
else
|
||||
// No? -> Frame start shifted again, set the number of consecutive stable frames to zero
|
||||
myStableVblankFrames = 0;
|
||||
|
||||
// Save the transition point for checking on it next frame
|
||||
myLastVblankLines = myCurrentVblankLines;
|
||||
|
||||
// In floating mode, we transition whenever we can.
|
||||
transition = true;
|
||||
}
|
||||
|
||||
// Transition to locked mode if we saw enough stable frames in a row.
|
||||
if (myStableVblankFrames >= Metrics::minStableVblankFrames) {
|
||||
myVblankMode = VblankMode::locked;
|
||||
myVblankViolations = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Locked mode: always transition at the same point, but check whether this is actually the
|
||||
// detected transition point and revert state if applicable
|
||||
case VblankMode::locked:
|
||||
|
||||
// Have we reached the transition point?
|
||||
if (myCurrentVblankLines == myLastVblankLines) {
|
||||
|
||||
// Are we free to transition per the algorithm and didn't observe an violation before?
|
||||
// (aka did the algorithm tell us to transition before reaching the actual line)
|
||||
if (shouldTransition && !myVblankViolated)
|
||||
// Reset the number of irregular frames (if any)
|
||||
myVblankViolations = 0;
|
||||
else {
|
||||
// Record a violation if it wasn't recorded before
|
||||
if (!myVblankViolated) ++myVblankViolations;
|
||||
myVblankViolated = true;
|
||||
}
|
||||
|
||||
// transition
|
||||
transition = true;
|
||||
// The algorithm tells us to transition although we haven't reached the trip line before
|
||||
} else if (shouldTransition) {
|
||||
// Record a violation if it wasn't recorded before
|
||||
if (!myVblankViolated) ++myVblankViolations;
|
||||
myVblankViolated = true;
|
||||
}
|
||||
|
||||
// Revert to floating mode if there were too many irregular frames in a row
|
||||
if (myVblankViolations > Metrics::maxVblankViolations) {
|
||||
myVblankMode = VblankMode::floating;
|
||||
myStableVblankFrames = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error("cannot happen");
|
||||
}
|
||||
|
||||
return transition;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void YStartDetector::setState(State state)
|
||||
{
|
||||
if (state == myState) return;
|
||||
|
||||
myState = state;
|
||||
myLinesWaitingForVsyncToStart = 0;
|
||||
|
||||
switch (state) {
|
||||
case State::waitForVsyncEnd:
|
||||
break;
|
||||
|
||||
case State::waitForVsyncStart:
|
||||
notifyFrameComplete();
|
||||
notifyFrameStart();
|
||||
break;
|
||||
|
||||
case State::waitForFrameStart:
|
||||
myVblankViolated = false;
|
||||
myCurrentVblankLines = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new runtime_error("cannot happen");
|
||||
}
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef TIA_YSTART_DETECTOR
|
||||
#define TIA_YSTART_DETECTOR
|
||||
|
||||
#include "AbstractFrameManager.hxx"
|
||||
|
||||
/**
|
||||
* This frame manager detects ystart from the first line with vblank = off.
|
||||
*/
|
||||
|
||||
class YStartDetector: public AbstractFrameManager {
|
||||
|
||||
public:
|
||||
|
||||
YStartDetector();
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Getter for the detected ystart value
|
||||
*/
|
||||
uInt32 detectedYStart() const;
|
||||
|
||||
/**
|
||||
* We require frame layout to be set from outside.
|
||||
*/
|
||||
void setLayout(FrameLayout layout) override { this->layout(layout); }
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* We need to track vsync changes.
|
||||
*/
|
||||
void onSetVsync() override;
|
||||
|
||||
/**
|
||||
* Reset hook.
|
||||
*/
|
||||
void onReset() override;
|
||||
|
||||
/**
|
||||
* The workhorse.
|
||||
*/
|
||||
void onNextLine() override;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Our various states.
|
||||
*/
|
||||
enum class State {
|
||||
// Wait for vsync on
|
||||
waitForVsyncStart,
|
||||
|
||||
// Wait for vsync off
|
||||
waitForVsyncEnd,
|
||||
|
||||
// Wait for the visible frame to start
|
||||
waitForFrameStart
|
||||
};
|
||||
|
||||
/**
|
||||
* Have we settled on a frame start?
|
||||
*/
|
||||
enum class VblankMode {
|
||||
// We have settled on a frame start and have some hysteresis before we return to floating
|
||||
locked,
|
||||
|
||||
// We are actively looking for the frame to start
|
||||
floating
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Side effects for state transitions.
|
||||
*/
|
||||
void setState(State state);
|
||||
|
||||
/**
|
||||
* Perform detection and decide whether the frame starts now.
|
||||
*/
|
||||
bool shouldTransitionToFrame();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* State.
|
||||
*/
|
||||
State myState;
|
||||
|
||||
/**
|
||||
* locked / floating
|
||||
*/
|
||||
VblankMode myVblankMode;
|
||||
|
||||
/**
|
||||
* Counts the scanlines that we wait for vsync to start.
|
||||
*/
|
||||
uInt32 myLinesWaitingForVsyncToStart;
|
||||
|
||||
/**
|
||||
* The number of lines we are currently waiting for the frame to start (and vblank to end).
|
||||
*/
|
||||
uInt32 myCurrentVblankLines;
|
||||
|
||||
/**
|
||||
* The number of vblank lines on the last frame.
|
||||
*/
|
||||
uInt32 myLastVblankLines;
|
||||
|
||||
/**
|
||||
* Count "vblank violations" in fixed mode (the number of consecutive frames where ystart
|
||||
* differs from the previously detected value). Once a trip point is reached, we transition
|
||||
* back to floating mode.
|
||||
*/
|
||||
uInt32 myVblankViolations;
|
||||
|
||||
/**
|
||||
* The number of frames in floating mode with stable ystart. Once a trip point is reacted,
|
||||
* we transition to fixed mode
|
||||
*/
|
||||
uInt32 myStableVblankFrames;
|
||||
|
||||
/**
|
||||
* Tracks deviations from the determined ystart value during a fixed mode frame in order to
|
||||
* avoid double counting.
|
||||
*/
|
||||
bool myVblankViolated;
|
||||
|
||||
private:
|
||||
|
||||
YStartDetector(const YStartDetector&) = delete;
|
||||
YStartDetector(YStartDetector&&) = delete;
|
||||
YStartDetector& operator=(const YStartDetector&) = delete;
|
||||
YStartDetector& operator=(YStartDetector&&) = delete;
|
||||
};
|
||||
|
||||
#endif // TIA_YSTART_DETECTOR
|
|
@ -4,7 +4,6 @@ MODULE_OBJS := \
|
|||
src/emucore/tia/frame-manager/FrameManager.o \
|
||||
src/emucore/tia/frame-manager/AbstractFrameManager.o \
|
||||
src/emucore/tia/frame-manager/FrameLayoutDetector.o \
|
||||
src/emucore/tia/frame-manager/YStartDetector.o \
|
||||
src/emucore/tia/frame-manager/JitterEmulation.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
|
|
|
@ -138,9 +138,9 @@ GameInfoDialog::GameInfoDialog(
|
|||
t = new StaticTextWidget(myTab, font, HBORDER, ypos + 1, "V-Center ");
|
||||
myVCenter = new SliderWidget(myTab, font, t->getRight() + 2, ypos,
|
||||
"", 0, kVCenterChanged, 7 * fontWidth, "px");
|
||||
// TODO (SA):check relationship of ystart and vcenter
|
||||
myVCenter->setMinValue(TIAConstants::minYStart - TIAConstants::defaultYStart);
|
||||
myVCenter->setMaxValue(TIAConstants::maxYStart - TIAConstants::defaultYStart);
|
||||
|
||||
myVCenter->setMinValue(TIAConstants::minVcenter);
|
||||
myVCenter->setMaxValue(TIAConstants::maxVcenter);
|
||||
myVCenter->setTickmarkIntervals(4);
|
||||
wid.push_back(myVCenter);
|
||||
|
||||
|
@ -458,20 +458,10 @@ void GameInfoDialog::loadEmulationProperties(const Properties& props)
|
|||
myPPBlend->setValue(atoi(blend.c_str()));
|
||||
|
||||
// set vertical center
|
||||
int vCenter = atoi(props.get(PropType::Display_VCenter).c_str());
|
||||
if (vCenter)
|
||||
{
|
||||
// convert y-start into v-center
|
||||
// TODO (SA): fix this
|
||||
vCenter = TIAConstants::defaultYStart - vCenter;
|
||||
myVCenter->setValueLabel(vCenter);
|
||||
}
|
||||
else
|
||||
{
|
||||
myVCenter->setValueLabel("default");
|
||||
}
|
||||
myVCenter->setValue(vCenter);
|
||||
myVCenter->setValueUnit(vCenter ? "px" : "");
|
||||
Int32 vcenter = atoi(props.get(PropType::Display_VCenter).c_str());
|
||||
myVCenter->setValueLabel(vcenter);
|
||||
myVCenter->setValue(vcenter);
|
||||
myVCenter->setValueUnit(vcenter ? "px" : "");
|
||||
|
||||
mySound->setState(props.get(PropType::Cart_Sound) == "STEREO");
|
||||
// if stereo is always enabled, disable game specific stereo setting
|
||||
|
@ -548,11 +538,9 @@ void GameInfoDialog::saveConfig()
|
|||
myGameProperties.set(PropType::Display_Phosphor, myPhosphor->getState() ? "YES" : "NO");
|
||||
myGameProperties.set(PropType::Display_PPBlend, myPPBlend->getValueLabel() == "Off" ? "0" :
|
||||
myPPBlend->getValueLabel());
|
||||
int vCenter = myVCenter->getValue();
|
||||
if (vCenter)
|
||||
// convert v-center into y-start TODO (SA): fix this
|
||||
vCenter = TIAConstants::defaultYStart - vCenter;
|
||||
myGameProperties.set(PropType::Display_VCenter, std::to_string(vCenter));
|
||||
Int32 vcenter = myVCenter->getValue();
|
||||
|
||||
myGameProperties.set(PropType::Display_VCenter, std::to_string(vcenter));
|
||||
myGameProperties.set(PropType::Cart_Sound, mySound->getState() ? "STEREO" : "MONO");
|
||||
|
||||
// Console properties
|
||||
|
@ -595,7 +583,7 @@ void GameInfoDialog::saveConfig()
|
|||
// update 'Emulation' tab settings immediately
|
||||
instance().console().setFormat(myFormat->getSelected());
|
||||
instance().frameBuffer().tiaSurface().enablePhosphor(myPhosphor->getState(), myPPBlend->getValue());
|
||||
instance().console().updateYStart(vCenter);
|
||||
instance().console().updateVcenter(vcenter);
|
||||
instance().console().initializeAudio();
|
||||
|
||||
// update 'Console' tab settings immediately
|
||||
|
|
Loading…
Reference in New Issue