mirror of https://github.com/stella-emu/stella.git
Add measured FPS to OSD, squash a bunch of minor bugs.
This commit is contained in:
parent
de24815771
commit
3a5572d3b9
|
@ -17,7 +17,8 @@ MODULE_OBJS := \
|
||||||
src/common/StateManager.o \
|
src/common/StateManager.o \
|
||||||
src/common/ZipHandler.o \
|
src/common/ZipHandler.o \
|
||||||
src/common/AudioQueue.o \
|
src/common/AudioQueue.o \
|
||||||
src/common/AudioSettings.o
|
src/common/AudioSettings.o \
|
||||||
|
src/common/FpsMeter.o
|
||||||
|
|
||||||
MODULE_DIRS += \
|
MODULE_DIRS += \
|
||||||
src/common
|
src/common
|
||||||
|
|
|
@ -157,6 +157,8 @@ void Debugger::quit(bool exitrom)
|
||||||
myOSystem.eventHandler().handleEvent(Event::LauncherMode, 1);
|
myOSystem.eventHandler().handleEvent(Event::LauncherMode, 1);
|
||||||
else
|
else
|
||||||
myOSystem.eventHandler().leaveDebugMode();
|
myOSystem.eventHandler().leaveDebugMode();
|
||||||
|
|
||||||
|
myOSystem.console().tia().clearPendingFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -148,7 +148,6 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
|
||||||
// Note that this can be overridden if a format is forced
|
// Note that this can be overridden if a format is forced
|
||||||
// For example, if a PAL ROM is forced to be NTSC, it will use NTSC-like
|
// For example, if a PAL ROM is forced to be NTSC, it will use NTSC-like
|
||||||
// properties (60Hz, 262 scanlines, etc), but likely result in flicker
|
// properties (60Hz, 262 scanlines, etc), but likely result in flicker
|
||||||
setTIAProperties();
|
|
||||||
if(myDisplayFormat == "NTSC")
|
if(myDisplayFormat == "NTSC")
|
||||||
{
|
{
|
||||||
myCurrentFormat = 1;
|
myCurrentFormat = 1;
|
||||||
|
@ -180,6 +179,8 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
|
||||||
myConsoleTiming = ConsoleTiming::secam;
|
myConsoleTiming = ConsoleTiming::secam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTIAProperties();
|
||||||
|
|
||||||
bool joyallow4 = myOSystem.settings().getBool("joyallow4");
|
bool joyallow4 = myOSystem.settings().getBool("joyallow4");
|
||||||
myOSystem.eventHandler().allowAllDirections(joyallow4);
|
myOSystem.eventHandler().allowAllDirections(joyallow4);
|
||||||
|
|
||||||
|
@ -387,6 +388,7 @@ void Console::setFormat(uInt32 format)
|
||||||
myTIA->frameReset();
|
myTIA->frameReset();
|
||||||
initializeVideo(); // takes care of refreshing the screen
|
initializeVideo(); // takes care of refreshing the screen
|
||||||
initializeAudio(); // ensure that audio synthesis is set up to match emulation speed
|
initializeAudio(); // ensure that audio synthesis is set up to match emulation speed
|
||||||
|
myOSystem.resetFps(); // Reset FPS measurement
|
||||||
}
|
}
|
||||||
|
|
||||||
myOSystem.frameBuffer().showMessage(message);
|
myOSystem.frameBuffer().showMessage(message);
|
||||||
|
@ -975,7 +977,8 @@ void Console::generateColorLossPalette()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
float Console::getFramerate() const
|
float Console::getFramerate() const
|
||||||
{
|
{
|
||||||
return myTIA->frameBufferFrameRate();
|
return
|
||||||
|
static_cast<float>(myEmulationTiming.linesPerSecond()) / myTIA->frameBufferScanlinesLastFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -134,6 +134,12 @@ uInt32 EmulationTiming::cyclesPerSecond() const
|
||||||
return myCyclesPerSecond;
|
return myCyclesPerSecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
uInt32 EmulationTiming::linesPerSecond() const
|
||||||
|
{
|
||||||
|
return myLinesPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt32 EmulationTiming::audioFragmentSize() const
|
uInt32 EmulationTiming::audioFragmentSize() const
|
||||||
{
|
{
|
||||||
|
@ -181,7 +187,7 @@ void EmulationTiming::recalculate()
|
||||||
|
|
||||||
case ConsoleTiming::pal:
|
case ConsoleTiming::pal:
|
||||||
case ConsoleTiming::secam:
|
case ConsoleTiming::secam:
|
||||||
myCyclesPerSecond = uInt32(round(mySpeedFactor * 312 * 76 * 50) / 38);
|
myAudioSampleRate = uInt32(round(mySpeedFactor * 312 * 76 * 50) / 38);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -204,4 +210,6 @@ void EmulationTiming::recalculate()
|
||||||
myPrebufferFragmentCount,
|
myPrebufferFragmentCount,
|
||||||
discreteDivCeil(myMaxCyclesPerTimeslice * myAudioSampleRate, myAudioFragmentSize * myCyclesPerSecond)
|
discreteDivCeil(myMaxCyclesPerTimeslice * myAudioSampleRate, myAudioFragmentSize * myCyclesPerSecond)
|
||||||
) + myAudioQueueExtraFragments;
|
) + myAudioQueueExtraFragments;
|
||||||
|
|
||||||
|
myLinesPerSecond = myCyclesPerSecond / 76;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,8 @@ class EmulationTiming {
|
||||||
|
|
||||||
uInt32 cyclesPerFrame() const;
|
uInt32 cyclesPerFrame() const;
|
||||||
|
|
||||||
|
uInt32 linesPerSecond() const;
|
||||||
|
|
||||||
uInt32 cyclesPerSecond() const;
|
uInt32 cyclesPerSecond() const;
|
||||||
|
|
||||||
uInt32 audioFragmentSize() const;
|
uInt32 audioFragmentSize() const;
|
||||||
|
@ -82,6 +84,7 @@ class EmulationTiming {
|
||||||
uInt32 myAudioSampleRate;
|
uInt32 myAudioSampleRate;
|
||||||
uInt32 myAudioQueueCapacity;
|
uInt32 myAudioQueueCapacity;
|
||||||
uInt32 myPrebufferFragmentCount;
|
uInt32 myPrebufferFragmentCount;
|
||||||
|
uInt32 myLinesPerSecond;
|
||||||
|
|
||||||
float mySpeedFactor;
|
float mySpeedFactor;
|
||||||
|
|
||||||
|
|
|
@ -229,8 +229,8 @@ FBInitStatus FrameBuffer::createDisplay(const string& title,
|
||||||
|
|
||||||
// Create surfaces for TIA statistics and general messages
|
// Create surfaces for TIA statistics and general messages
|
||||||
myStatsMsg.color = kColorInfo;
|
myStatsMsg.color = kColorInfo;
|
||||||
myStatsMsg.w = font().getMaxCharWidth() * 30 + 3;
|
myStatsMsg.w = font().getMaxCharWidth() * 40 + 3;
|
||||||
myStatsMsg.h = (font().getFontHeight() + 2) * 2;
|
myStatsMsg.h = (font().getFontHeight() + 2) * 3;
|
||||||
|
|
||||||
if(!myStatsMsg.surface)
|
if(!myStatsMsg.surface)
|
||||||
{
|
{
|
||||||
|
@ -361,7 +361,7 @@ void FrameBuffer::update(bool force)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void FrameBuffer::updateInEmulationMode()
|
void FrameBuffer::updateInEmulationMode(float framesPerSecond)
|
||||||
{
|
{
|
||||||
// Update method that is specifically tailored to emulation mode
|
// Update method that is specifically tailored to emulation mode
|
||||||
// Typically called from a thread, so it needs to be separate from
|
// Typically called from a thread, so it needs to be separate from
|
||||||
|
@ -374,7 +374,7 @@ void FrameBuffer::updateInEmulationMode()
|
||||||
|
|
||||||
// Show frame statistics
|
// Show frame statistics
|
||||||
if(myStatsMsg.enabled)
|
if(myStatsMsg.enabled)
|
||||||
drawFrameStats();
|
drawFrameStats(framesPerSecond);
|
||||||
|
|
||||||
myLastScanlines = myOSystem.console().tia().frameBufferScanlinesLastFrame();
|
myLastScanlines = myOSystem.console().tia().frameBufferScanlinesLastFrame();
|
||||||
myPausedCount = 0;
|
myPausedCount = 0;
|
||||||
|
@ -410,39 +410,50 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position,
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void FrameBuffer::drawFrameStats()
|
void FrameBuffer::drawFrameStats(float framesPerSecond)
|
||||||
{
|
{
|
||||||
const ConsoleInfo& info = myOSystem.console().about();
|
const ConsoleInfo& info = myOSystem.console().about();
|
||||||
char msg[30];
|
|
||||||
uInt32 color;
|
uInt32 color;
|
||||||
const int XPOS = 2, YPOS = 0;
|
int xPos = 2, yPos = 0;
|
||||||
int xPos = XPOS;
|
const int dy = font().getFontHeight() + 2;
|
||||||
|
|
||||||
|
ostringstream ss;
|
||||||
|
|
||||||
myStatsMsg.surface->invalidate();
|
myStatsMsg.surface->invalidate();
|
||||||
|
|
||||||
// draw scanlines
|
// draw scanlines
|
||||||
color = myOSystem.console().tia().frameBufferScanlinesLastFrame() != myLastScanlines ?
|
color = myOSystem.console().tia().frameBufferScanlinesLastFrame() != myLastScanlines ?
|
||||||
uInt32(kDbgColorRed) : myStatsMsg.color;
|
uInt32(kDbgColorRed) : myStatsMsg.color;
|
||||||
std::snprintf(msg, 30, "%3u", myOSystem.console().tia().frameBufferScanlinesLastFrame());
|
|
||||||
myStatsMsg.surface->drawString(font(), msg, xPos, YPOS,
|
ss
|
||||||
|
<< myOSystem.console().tia().frameBufferScanlinesLastFrame()
|
||||||
|
<< " / "
|
||||||
|
<< std::fixed << std::setprecision(1) << myOSystem.console().getFramerate()
|
||||||
|
<< "Hz => "
|
||||||
|
<< info.DisplayFormat;
|
||||||
|
|
||||||
|
myStatsMsg.surface->drawString(font(), ss.str(), xPos, yPos,
|
||||||
myStatsMsg.w, color, TextAlign::Left, 0, true, kBGColor);
|
myStatsMsg.w, color, TextAlign::Left, 0, true, kBGColor);
|
||||||
xPos += font().getStringWidth(msg);
|
|
||||||
|
|
||||||
// draw frequency
|
yPos += dy;
|
||||||
std::snprintf(msg, 30, " => %s", info.DisplayFormat.c_str());
|
ss.str("");
|
||||||
myStatsMsg.surface->drawString(font(), msg, xPos, YPOS,
|
|
||||||
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
|
|
||||||
xPos += font().getStringWidth(msg);
|
|
||||||
|
|
||||||
std::snprintf(msg, 30, " @ %5.2ffps", myOSystem.console().getFramerate());
|
ss
|
||||||
|
<< std::fixed << std::setprecision(1) << framesPerSecond
|
||||||
|
<< "fps @ "
|
||||||
|
<< std::fixed << std::setprecision(2) << 100 * myOSystem.settings().getFloat("speed")
|
||||||
|
<< "% speed";
|
||||||
|
|
||||||
myStatsMsg.surface->drawString(font(), msg, xPos, YPOS,
|
myStatsMsg.surface->drawString(font(), ss.str(), xPos, yPos,
|
||||||
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
|
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
|
||||||
|
|
||||||
// draw bankswitching type
|
yPos += dy;
|
||||||
string bsinfo = info.BankSwitch +
|
ss.str("");
|
||||||
(myOSystem.settings().getBool("dev.settings") ? "| Developer" : "");
|
|
||||||
myStatsMsg.surface->drawString(font(), bsinfo, XPOS, YPOS + font().getFontHeight(),
|
ss << info.BankSwitch;
|
||||||
|
if (myOSystem.settings().getBool("dev.settings")) ss << "| Developer";
|
||||||
|
|
||||||
|
myStatsMsg.surface->drawString(font(), ss.str(), xPos, yPos,
|
||||||
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
|
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
|
||||||
|
|
||||||
myStatsMsg.surface->setDstPos(myImageRect.x() + 10, myImageRect.y() + 8);
|
myStatsMsg.surface->setDstPos(myImageRect.x() + 10, myImageRect.y() + 8);
|
||||||
|
|
|
@ -120,7 +120,7 @@ class FrameBuffer
|
||||||
/**
|
/**
|
||||||
There is a dedicated update method for emulation mode.
|
There is a dedicated update method for emulation mode.
|
||||||
*/
|
*/
|
||||||
void updateInEmulationMode();
|
void updateInEmulationMode(float framesPerSecond);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Shows a message onscreen.
|
Shows a message onscreen.
|
||||||
|
@ -471,7 +471,7 @@ class FrameBuffer
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Draws the frame stats overlay
|
// Draws the frame stats overlay
|
||||||
void drawFrameStats();
|
void drawFrameStats(float framesPerSecond);
|
||||||
|
|
||||||
// Indicates the number of times the framebuffer was initialized
|
// Indicates the number of times the framebuffer was initialized
|
||||||
uInt32 myInitializedCount;
|
uInt32 myInitializedCount;
|
||||||
|
|
|
@ -30,14 +30,13 @@
|
||||||
#include "CheatManager.hxx"
|
#include "CheatManager.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
#include "FSNode.hxx"
|
#include "FSNode.hxx"
|
||||||
#include "MD5.hxx"
|
#include "MD5.hxx"
|
||||||
#include "Cart.hxx"
|
#include "Cart.hxx"
|
||||||
#include "CartDetector.hxx"
|
#include "CartDetector.hxx"
|
||||||
#include "FrameBuffer.hxx"
|
#include "FrameBuffer.hxx"
|
||||||
#include "TIASurface.hxx"
|
#include "TIASurface.hxx"
|
||||||
|
#include "TIAConstants.hxx"
|
||||||
#include "Settings.hxx"
|
#include "Settings.hxx"
|
||||||
#include "PropsSet.hxx"
|
#include "PropsSet.hxx"
|
||||||
#include "EventHandler.hxx"
|
#include "EventHandler.hxx"
|
||||||
|
@ -60,10 +59,15 @@
|
||||||
|
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr uInt32 FPS_METER_QUEUE_SIZE = 100;
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
OSystem::OSystem()
|
OSystem::OSystem()
|
||||||
: myLauncherUsed(false),
|
: myLauncherUsed(false),
|
||||||
myQuitLoop(false)
|
myQuitLoop(false),
|
||||||
|
myFpsMeter(FPS_METER_QUEUE_SIZE)
|
||||||
{
|
{
|
||||||
// Get built-in features
|
// Get built-in features
|
||||||
#ifdef SOUND_SUPPORT
|
#ifdef SOUND_SUPPORT
|
||||||
|
@ -481,6 +485,12 @@ void OSystem::logMessage(const string& message, uInt8 level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void OSystem::resetFps()
|
||||||
|
{
|
||||||
|
myFpsMeter.reset();
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
unique_ptr<Console> OSystem::openConsole(const FilesystemNode& romfile, string& md5)
|
unique_ptr<Console> OSystem::openConsole(const FilesystemNode& romfile, string& md5)
|
||||||
{
|
{
|
||||||
|
@ -651,7 +661,10 @@ double OSystem::dispatchEmulation(EmulationWorker& emulationWorker)
|
||||||
bool framePending = tia.newFramePending();
|
bool framePending = tia.newFramePending();
|
||||||
// ... and copy it to the frame buffer. It is important to do this before
|
// ... and copy it to the frame buffer. It is important to do this before
|
||||||
// the worker is started to avoid racing.
|
// the worker is started to avoid racing.
|
||||||
if (framePending) tia.renderToFrameBuffer();
|
if (framePending) {
|
||||||
|
myFpsMeter.render(tia.framesSinceLastRender());
|
||||||
|
tia.renderToFrameBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
// Start emulation on a dedicated thread. It will do its own scheduling to sync 6507 and real time
|
// Start emulation on a dedicated thread. It will do its own scheduling to sync 6507 and real time
|
||||||
// and will run until we stop the worker.
|
// and will run until we stop the worker.
|
||||||
|
@ -665,7 +678,7 @@ double OSystem::dispatchEmulation(EmulationWorker& emulationWorker)
|
||||||
|
|
||||||
// Render the frame. This may block, but emulation will continue to run on the worker, so the
|
// Render the frame. This may block, but emulation will continue to run on the worker, so the
|
||||||
// audio pipeline is kept fed :)
|
// audio pipeline is kept fed :)
|
||||||
if (framePending) myFrameBuffer->updateInEmulationMode();
|
if (framePending) myFrameBuffer->updateInEmulationMode(myFpsMeter.fps());
|
||||||
|
|
||||||
// Stop the worker and wait until it has finished
|
// Stop the worker and wait until it has finished
|
||||||
uInt64 totalCycles = emulationWorker.stop();
|
uInt64 totalCycles = emulationWorker.stop();
|
||||||
|
@ -691,11 +704,20 @@ void OSystem::mainLoop()
|
||||||
// The emulation worker
|
// The emulation worker
|
||||||
EmulationWorker emulationWorker;
|
EmulationWorker emulationWorker;
|
||||||
|
|
||||||
|
myFpsMeter.reset(TIAConstants::initialGarbageFrames);
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
|
bool wasEmulation = myEventHandler->state() == EventHandlerState::EMULATION;
|
||||||
|
|
||||||
myEventHandler->poll(getTicks());
|
myEventHandler->poll(getTicks());
|
||||||
if(myQuitLoop) break; // Exit if the user wants to quit
|
if(myQuitLoop) break; // Exit if the user wants to quit
|
||||||
|
|
||||||
|
if (!wasEmulation && myEventHandler->state() == EventHandlerState::EMULATION) {
|
||||||
|
myFpsMeter.reset();
|
||||||
|
virtualTime = high_resolution_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
double timesliceSeconds;
|
double timesliceSeconds;
|
||||||
|
|
||||||
if (myEventHandler->state() == EventHandlerState::EMULATION)
|
if (myEventHandler->state() == EventHandlerState::EMULATION)
|
||||||
|
|
|
@ -40,9 +40,12 @@ class StateManager;
|
||||||
class VideoDialog;
|
class VideoDialog;
|
||||||
class EmulationWorker;
|
class EmulationWorker;
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#include "FSNode.hxx"
|
#include "FSNode.hxx"
|
||||||
#include "FrameBufferConstants.hxx"
|
#include "FrameBufferConstants.hxx"
|
||||||
#include "EventHandlerConstants.hxx"
|
#include "EventHandlerConstants.hxx"
|
||||||
|
#include "FpsMeter.hxx"
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
#include "AudioSettings.hxx"
|
#include "AudioSettings.hxx"
|
||||||
|
|
||||||
|
@ -367,6 +370,11 @@ class OSystem
|
||||||
*/
|
*/
|
||||||
const string& logMessages() const { return myLogMessages; }
|
const string& logMessages() const { return myLogMessages; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
Reset FPS measurement.
|
||||||
|
*/
|
||||||
|
void resetFps();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// The following methods are system-specific and can be overrided in
|
// The following methods are system-specific and can be overrided in
|
||||||
|
@ -510,6 +518,8 @@ class OSystem
|
||||||
string myFeatures;
|
string myFeatures;
|
||||||
string myBuildInfo;
|
string myBuildInfo;
|
||||||
|
|
||||||
|
FpsMeter myFpsMeter;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
Creates the various framebuffers/renderers available in this system.
|
Creates the various framebuffers/renderers available in this system.
|
||||||
|
|
|
@ -181,10 +181,9 @@ void TIA::reset()
|
||||||
frameReset(); // Recalculate the size of the display
|
frameReset(); // Recalculate the size of the display
|
||||||
}
|
}
|
||||||
|
|
||||||
myFrontBufferFrameRate = myFrameBufferFrameRate = 0;
|
|
||||||
myFrontBufferScanlines = myFrameBufferScanlines = 0;
|
myFrontBufferScanlines = myFrameBufferScanlines = 0;
|
||||||
|
|
||||||
myNewFramePending = false;
|
myFramesSinceLastRender = 0;
|
||||||
|
|
||||||
// Must be done last, after all other items have reset
|
// Must be done last, after all other items have reset
|
||||||
enableFixedColors(mySettings.getBool(mySettings.getBool("dev.settings") ? "dev.debugcolors" : "plr.debugcolors"));
|
enableFixedColors(mySettings.getBool(mySettings.getBool("dev.settings") ? "dev.debugcolors" : "plr.debugcolors"));
|
||||||
|
@ -293,8 +292,6 @@ bool TIA::save(Serializer& out) const
|
||||||
|
|
||||||
out.putInt(myFrameBufferScanlines);
|
out.putInt(myFrameBufferScanlines);
|
||||||
out.putInt(myFrontBufferScanlines);
|
out.putInt(myFrontBufferScanlines);
|
||||||
out.putDouble(myFrameBufferFrameRate);
|
|
||||||
out.putDouble(myFrontBufferFrameRate);
|
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -366,8 +363,6 @@ bool TIA::load(Serializer& in)
|
||||||
|
|
||||||
myFrameBufferScanlines = in.getInt();
|
myFrameBufferScanlines = in.getInt();
|
||||||
myFrontBufferScanlines = in.getInt();
|
myFrontBufferScanlines = in.getInt();
|
||||||
myFrameBufferFrameRate = in.getDouble();
|
|
||||||
myFrontBufferFrameRate = in.getDouble();
|
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -799,7 +794,7 @@ bool TIA::saveDisplay(Serializer& out) const
|
||||||
out.putByteArray(myFramebuffer, 160* TIAConstants::frameBufferHeight);
|
out.putByteArray(myFramebuffer, 160* TIAConstants::frameBufferHeight);
|
||||||
out.putByteArray(myBackBuffer, 160 * TIAConstants::frameBufferHeight);
|
out.putByteArray(myBackBuffer, 160 * TIAConstants::frameBufferHeight);
|
||||||
out.putByteArray(myFrontBuffer, 160 * TIAConstants::frameBufferHeight);
|
out.putByteArray(myFrontBuffer, 160 * TIAConstants::frameBufferHeight);
|
||||||
out.putBool(myNewFramePending);
|
out.putInt(myFramesSinceLastRender);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -819,7 +814,7 @@ bool TIA::loadDisplay(Serializer& in)
|
||||||
in.getByteArray(myFramebuffer, 160 * TIAConstants::frameBufferHeight);
|
in.getByteArray(myFramebuffer, 160 * TIAConstants::frameBufferHeight);
|
||||||
in.getByteArray(myBackBuffer, 160 * TIAConstants::frameBufferHeight);
|
in.getByteArray(myBackBuffer, 160 * TIAConstants::frameBufferHeight);
|
||||||
in.getByteArray(myFrontBuffer, 160 * TIAConstants::frameBufferHeight);
|
in.getByteArray(myFrontBuffer, 160 * TIAConstants::frameBufferHeight);
|
||||||
myNewFramePending = in.getBool();
|
myFramesSinceLastRender = in.getInt();
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -841,11 +836,12 @@ void TIA::update(DispatchResult& result, uInt64 maxCycles)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void TIA::renderToFrameBuffer()
|
void TIA::renderToFrameBuffer()
|
||||||
{
|
{
|
||||||
if (!myNewFramePending) return;
|
if (myFramesSinceLastRender == 0) return;
|
||||||
|
|
||||||
|
myFramesSinceLastRender = 0;
|
||||||
|
|
||||||
memcpy(myFramebuffer, myFrontBuffer, 160 * TIAConstants::frameBufferHeight);
|
memcpy(myFramebuffer, myFrontBuffer, 160 * TIAConstants::frameBufferHeight);
|
||||||
|
|
||||||
myFrameBufferFrameRate = myFrontBufferFrameRate;
|
|
||||||
myFrameBufferScanlines = myFrontBufferScanlines;
|
myFrameBufferScanlines = myFrontBufferScanlines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1198,10 +1194,9 @@ void TIA::onFrameComplete()
|
||||||
|
|
||||||
memcpy(myFrontBuffer, myBackBuffer, 160 * TIAConstants::frameBufferHeight);
|
memcpy(myFrontBuffer, myBackBuffer, 160 * TIAConstants::frameBufferHeight);
|
||||||
|
|
||||||
myFrontBufferFrameRate = frameRate();
|
|
||||||
myFrontBufferScanlines = scanlinesLastFrame();
|
myFrontBufferScanlines = scanlinesLastFrame();
|
||||||
|
|
||||||
myNewFramePending = true;
|
myFramesSinceLastRender++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -207,7 +207,17 @@ class TIA : public Device
|
||||||
/**
|
/**
|
||||||
Did we generate a new frame?
|
Did we generate a new frame?
|
||||||
*/
|
*/
|
||||||
bool newFramePending() { return myNewFramePending; }
|
bool newFramePending() { return myFramesSinceLastRender > 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear any pending frames.
|
||||||
|
*/
|
||||||
|
void clearPendingFrame() { myFramesSinceLastRender = 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
The number of frames since we did last render to the front buffer.
|
||||||
|
*/
|
||||||
|
uInt32 framesSinceLastRender() { return myFramesSinceLastRender; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Render the pending frame to the framebuffer and clear the flag.
|
Render the pending frame to the framebuffer and clear the flag.
|
||||||
|
@ -248,13 +258,6 @@ class TIA : public Device
|
||||||
*/
|
*/
|
||||||
ConsoleTiming consoleTiming() const { return myConsole.timing(); }
|
ConsoleTiming consoleTiming() const { return myConsole.timing(); }
|
||||||
|
|
||||||
float frameRate() const { return myFrameManager ? myFrameManager->frameRate() : 0; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
The same, but for the frame in the frame buffer.
|
|
||||||
*/
|
|
||||||
float frameBufferFrameRate() const { return myFrameBufferFrameRate; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Enables/disables color-loss for PAL modes only.
|
Enables/disables color-loss for PAL modes only.
|
||||||
|
|
||||||
|
@ -694,10 +697,9 @@ class TIA : public Device
|
||||||
// We snapshot frame statistics when the back buffer is copied to the front buffer
|
// We snapshot frame statistics when the back buffer is copied to the front buffer
|
||||||
// and when the front buffer is copied to the frame buffer
|
// and when the front buffer is copied to the frame buffer
|
||||||
uInt32 myFrontBufferScanlines, myFrameBufferScanlines;
|
uInt32 myFrontBufferScanlines, myFrameBufferScanlines;
|
||||||
float myFrontBufferFrameRate, myFrameBufferFrameRate;
|
|
||||||
|
|
||||||
// Did we emit a frame?
|
// Frames since the last time a frame was rendered to the render buffer
|
||||||
bool myNewFramePending;
|
uInt32 myFramesSinceLastRender;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setting this to true injects random values into undefined reads.
|
* Setting this to true injects random values into undefined reads.
|
||||||
|
|
|
@ -37,8 +37,6 @@ void AbstractFrameManager::reset()
|
||||||
myCurrentFrameFinalLines = 0;
|
myCurrentFrameFinalLines = 0;
|
||||||
myPreviousFrameFinalLines = 0;
|
myPreviousFrameFinalLines = 0;
|
||||||
myTotalFrames = 0;
|
myTotalFrames = 0;
|
||||||
myFrameRate = 0;
|
|
||||||
myFrameRate = 60.0;
|
|
||||||
|
|
||||||
onReset();
|
onReset();
|
||||||
}
|
}
|
||||||
|
@ -101,9 +99,6 @@ void AbstractFrameManager::notifyFrameComplete()
|
||||||
myTotalFrames++;
|
myTotalFrames++;
|
||||||
|
|
||||||
if (myOnFrameComplete) myOnFrameComplete();
|
if (myOnFrameComplete) myOnFrameComplete();
|
||||||
|
|
||||||
myFrameRate = (layout() == FrameLayout::pal ? 15600.0 : 15720.0) /
|
|
||||||
myCurrentFrameFinalLines;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -130,7 +125,6 @@ bool AbstractFrameManager::save(Serializer& out) const
|
||||||
out.putInt(myPreviousFrameFinalLines);
|
out.putInt(myPreviousFrameFinalLines);
|
||||||
out.putInt(myTotalFrames);
|
out.putInt(myTotalFrames);
|
||||||
out.putInt(uInt32(myLayout));
|
out.putInt(uInt32(myLayout));
|
||||||
out.putDouble(myFrameRate);
|
|
||||||
|
|
||||||
return onSave(out);
|
return onSave(out);
|
||||||
}
|
}
|
||||||
|
@ -155,7 +149,6 @@ bool AbstractFrameManager::load(Serializer& in)
|
||||||
myPreviousFrameFinalLines = in.getInt();
|
myPreviousFrameFinalLines = in.getInt();
|
||||||
myTotalFrames = in.getInt();
|
myTotalFrames = in.getInt();
|
||||||
myLayout = FrameLayout(in.getInt());
|
myLayout = FrameLayout(in.getInt());
|
||||||
myFrameRate = float(in.getDouble());
|
|
||||||
|
|
||||||
return onLoad(in);
|
return onLoad(in);
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,13 +107,6 @@ class AbstractFrameManager : public Serializable
|
||||||
*/
|
*/
|
||||||
FrameLayout layout() const { return myLayout; }
|
FrameLayout layout() const { return myLayout; }
|
||||||
|
|
||||||
/**
|
|
||||||
* The current frame rate. This is calculated dynamically from the number of
|
|
||||||
* scanlines in the last frames and used to control sleep time in the
|
|
||||||
* dispatch loop.
|
|
||||||
*/
|
|
||||||
float frameRate() const { return myFrameRate; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save state.
|
* Save state.
|
||||||
*/
|
*/
|
||||||
|
@ -289,11 +282,6 @@ class AbstractFrameManager : public Serializable
|
||||||
*/
|
*/
|
||||||
uInt32 myTotalFrames;
|
uInt32 myTotalFrames;
|
||||||
|
|
||||||
/**
|
|
||||||
* Frame rate (see above.)
|
|
||||||
*/
|
|
||||||
float myFrameRate;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue