Added an integer frame rate option to Qt GUI better sync with video.
This commit is contained in:
parent
6b65d1264d
commit
c978c1631a
|
@ -26,6 +26,7 @@
|
|||
#include "Qt/main.h"
|
||||
#include "Qt/dface.h"
|
||||
#include "Qt/config.h"
|
||||
#include "Qt/throttle.h"
|
||||
#include "Qt/fceuWrapper.h"
|
||||
#include "Qt/ConsoleWindow.h"
|
||||
#include "Qt/ConsoleUtilities.h"
|
||||
|
@ -148,6 +149,9 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
|
|||
// Enable New PPU Checkbox
|
||||
frmskipcbx = new QCheckBox( tr("Enable Frameskip") );
|
||||
|
||||
// Use Integer Frame Rate Checkbox
|
||||
intFrameRateCbx = new QCheckBox( tr("Use Integer Frame Rate") );
|
||||
|
||||
// Disable Sprite Limit Checkbox
|
||||
sprtLimCbx = new QCheckBox( tr("Disable Sprite Limit") );
|
||||
|
||||
|
@ -166,12 +170,13 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
|
|||
// Draw Input Aids
|
||||
drawInputAidsCbx = new QCheckBox( tr("Draw Input Aids") );
|
||||
|
||||
setCheckBoxFromProperty( autoRegion , "SDL.AutoDetectPAL");
|
||||
setCheckBoxFromProperty( new_PPU_ena , "SDL.NewPPU");
|
||||
setCheckBoxFromProperty( frmskipcbx , "SDL.Frameskip");
|
||||
setCheckBoxFromProperty( sprtLimCbx , "SDL.DisableSpriteLimit");
|
||||
setCheckBoxFromProperty( clipSidesCbx , "SDL.ClipSides");
|
||||
setCheckBoxFromProperty( showFPS_cbx , "SDL.ShowFPS");
|
||||
setCheckBoxFromProperty( autoRegion , "SDL.AutoDetectPAL");
|
||||
setCheckBoxFromProperty( new_PPU_ena , "SDL.NewPPU");
|
||||
setCheckBoxFromProperty( frmskipcbx , "SDL.Frameskip");
|
||||
setCheckBoxFromProperty( intFrameRateCbx , "SDL.IntFrameRate");
|
||||
setCheckBoxFromProperty( sprtLimCbx , "SDL.DisableSpriteLimit");
|
||||
setCheckBoxFromProperty( clipSidesCbx , "SDL.ClipSides");
|
||||
setCheckBoxFromProperty( showFPS_cbx , "SDL.ShowFPS");
|
||||
setCheckBoxFromProperty( drawInputAidsCbx, "SDL.DrawInputAids" );
|
||||
|
||||
if ( consoleWindow )
|
||||
|
@ -191,6 +196,7 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
|
|||
connect(new_PPU_ena , SIGNAL(clicked(bool)) , this, SLOT(use_new_PPU_changed(bool)) );
|
||||
connect(autoRegion , SIGNAL(stateChanged(int)), this, SLOT(autoRegionChanged(int)) );
|
||||
connect(frmskipcbx , SIGNAL(stateChanged(int)), this, SLOT(frameskip_changed(int)) );
|
||||
connect(intFrameRateCbx , SIGNAL(stateChanged(int)), this, SLOT(intFrameRate_changed(int)) );
|
||||
connect(sprtLimCbx , SIGNAL(stateChanged(int)), this, SLOT(useSpriteLimitChanged(int)) );
|
||||
connect(clipSidesCbx , SIGNAL(stateChanged(int)), this, SLOT(clipSidesChanged(int)) );
|
||||
connect(showFPS_cbx , SIGNAL(stateChanged(int)), this, SLOT(showFPSChanged(int)) );
|
||||
|
@ -201,6 +207,7 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
|
|||
vbox1->addWidget( autoRegion );
|
||||
vbox1->addWidget( new_PPU_ena );
|
||||
vbox1->addWidget( frmskipcbx );
|
||||
vbox1->addWidget( intFrameRateCbx );
|
||||
vbox1->addWidget( sprtLimCbx );
|
||||
vbox1->addWidget( drawInputAidsCbx );
|
||||
vbox1->addWidget( showFPS_cbx );
|
||||
|
@ -689,6 +696,18 @@ void ConsoleVideoConfDialog_t::frameskip_changed( int value )
|
|||
fceuWrapperUnLock();
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void ConsoleVideoConfDialog_t::intFrameRate_changed( int value )
|
||||
{
|
||||
//printf("Value:%i \n", value );
|
||||
useIntFrameRate = (value != Qt::Unchecked);
|
||||
g_config->setOption("SDL.IntFrameRate", useIntFrameRate );
|
||||
g_config->save ();
|
||||
|
||||
fceuWrapperLock();
|
||||
RefreshThrottleFPS();
|
||||
fceuWrapperUnLock();
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void ConsoleVideoConfDialog_t::useSpriteLimitChanged( int value )
|
||||
{
|
||||
//printf("Value:%i \n", value );
|
||||
|
|
|
@ -47,6 +47,7 @@ class ConsoleVideoConfDialog_t : public QDialog
|
|||
QCheckBox *aspectCbx;
|
||||
QCheckBox *cursorVisCbx;
|
||||
QCheckBox *drawInputAidsCbx;
|
||||
QCheckBox *intFrameRateCbx;
|
||||
QDoubleSpinBox *xScaleBox;
|
||||
QDoubleSpinBox *yScaleBox;
|
||||
QLabel *aspectSelectLabel;
|
||||
|
@ -78,6 +79,7 @@ class ConsoleVideoConfDialog_t : public QDialog
|
|||
void aspectEnableChanged( int value );
|
||||
void use_new_PPU_changed( bool value );
|
||||
void frameskip_changed( int value );
|
||||
void intFrameRate_changed( int value );
|
||||
void useSpriteLimitChanged( int value );
|
||||
void clipSidesChanged( int value );
|
||||
void showFPSChanged( int value );
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#endif
|
||||
|
||||
#include "Qt/nes_shm.h"
|
||||
#include "Qt/throttle.h"
|
||||
#include "Qt/fceuWrapper.h"
|
||||
#include "Qt/ConsoleViewerGL.h"
|
||||
|
||||
|
@ -100,6 +101,8 @@ ConsoleViewGL_t::ConsoleViewGL_t(QWidget *parent)
|
|||
|
||||
g_config->getOption ("SDL.ForceAspect", &forceAspect);
|
||||
}
|
||||
|
||||
connect( this, SIGNAL(frameSwapped(void)), this, SLOT(renderFinished(void)) );
|
||||
}
|
||||
|
||||
ConsoleViewGL_t::~ConsoleViewGL_t(void)
|
||||
|
@ -496,6 +499,11 @@ void ConsoleViewGL_t::getNormalizedCursorPos( double &x, double &y )
|
|||
//printf("Normalized Cursor (%f,%f) \n", x, y );
|
||||
}
|
||||
|
||||
void ConsoleViewGL_t::renderFinished(void)
|
||||
{
|
||||
videoBufferSwapMark();
|
||||
}
|
||||
|
||||
void ConsoleViewGL_t::paintGL(void)
|
||||
{
|
||||
int texture_width = nes_shm->video.ncol;
|
||||
|
|
|
@ -80,5 +80,6 @@ class ConsoleViewGL_t : public QOpenGLWidget, protected QOpenGLFunctions
|
|||
|
||||
private slots:
|
||||
void cleanupGL(void);
|
||||
void renderFinished(void);
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
//#include <unistd.h>
|
||||
|
||||
#include "Qt/nes_shm.h"
|
||||
#include "Qt/throttle.h"
|
||||
#include "Qt/fceuWrapper.h"
|
||||
#include "Qt/ConsoleViewerSDL.h"
|
||||
|
||||
|
@ -650,5 +651,7 @@ void ConsoleViewSDL_t::render(void)
|
|||
|
||||
SDL_RenderPresent(sdlRenderer);
|
||||
|
||||
videoBufferSwapMark();
|
||||
|
||||
nes_shm->render_count++;
|
||||
}
|
||||
|
|
|
@ -152,6 +152,7 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
|||
emulatorThread = new emulatorThread_t(this);
|
||||
|
||||
connect(emulatorThread, &QThread::finished, emulatorThread, &QObject::deleteLater);
|
||||
connect(emulatorThread, SIGNAL(frameFinished(void)), this, SLOT(emuFrameFinish(void)) );
|
||||
|
||||
connect( gameTimer, &QTimer::timeout, this, &consoleWin_t::updatePeriodic );
|
||||
|
||||
|
@ -3974,15 +3975,8 @@ void consoleWin_t::loadMostRecentROM(void)
|
|||
fceuWrapperUnLock();
|
||||
}
|
||||
|
||||
void consoleWin_t::updatePeriodic(void)
|
||||
void consoleWin_t::transferVideoBuffer(void)
|
||||
{
|
||||
// Process all events before attempting to render viewport
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
// Update Input Devices
|
||||
FCEUD_UpdateInput();
|
||||
|
||||
// RePaint Game Viewport
|
||||
if ( nes_shm->blitUpdated )
|
||||
{
|
||||
nes_shm->blitUpdated = 0;
|
||||
|
@ -3992,12 +3986,31 @@ void consoleWin_t::updatePeriodic(void)
|
|||
viewport_SDL->transfer2LocalBuffer();
|
||||
viewport_SDL->render();
|
||||
}
|
||||
else
|
||||
else if ( viewport_GL )
|
||||
{
|
||||
viewport_GL->transfer2LocalBuffer();
|
||||
viewport_GL->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void consoleWin_t::emuFrameFinish(void)
|
||||
{
|
||||
//printf("EMU Frame Finish\n");
|
||||
|
||||
transferVideoBuffer();
|
||||
}
|
||||
|
||||
void consoleWin_t::updatePeriodic(void)
|
||||
{
|
||||
// Process all events before attempting to render viewport
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
// Update Input Devices
|
||||
FCEUD_UpdateInput();
|
||||
|
||||
// RePaint Game Viewport
|
||||
transferVideoBuffer();
|
||||
|
||||
// Low Rate Updates
|
||||
if ( (updateCounter % 30) == 0 )
|
||||
|
@ -4271,6 +4284,11 @@ void emulatorThread_t::run(void)
|
|||
emit finished();
|
||||
}
|
||||
|
||||
void emulatorThread_t::signalFrameFinished(void)
|
||||
{
|
||||
emit frameFinished();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Custom QMenuBar for Console
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -51,6 +51,7 @@ class emulatorThread_t : public QThread
|
|||
int getMinSchedPriority(void);
|
||||
int getMaxSchedPriority(void);
|
||||
#endif
|
||||
void signalFrameFinished(void);
|
||||
private:
|
||||
void init(void);
|
||||
|
||||
|
@ -60,7 +61,8 @@ class emulatorThread_t : public QThread
|
|||
#endif
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
void finished(void);
|
||||
void frameFinished(void);
|
||||
};
|
||||
|
||||
class consoleMenuBar : public QMenuBar
|
||||
|
@ -280,6 +282,7 @@ class consoleWin_t : public QMainWindow
|
|||
void changeState(int slot);
|
||||
void saveState(int slot);
|
||||
void loadState(int slot);
|
||||
void transferVideoBuffer(void);
|
||||
void syncAutoFirePatternMenu(void);
|
||||
|
||||
public slots:
|
||||
|
@ -413,6 +416,7 @@ class consoleWin_t : public QMainWindow
|
|||
void wavRecordAsStart(void);
|
||||
void wavRecordStop(void);
|
||||
void winScreenChanged( QScreen *scr );
|
||||
void emuFrameFinish(void);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
|
|||
frameTimeWorkPct = new QTreeWidgetItem();
|
||||
frameTimeIdlePct = new QTreeWidgetItem();
|
||||
frameLateCount = new QTreeWidgetItem();
|
||||
videoTimeAbs = new QTreeWidgetItem();
|
||||
|
||||
tree->addTopLevelItem(frameTimeAbs);
|
||||
tree->addTopLevelItem(frameTimeDel);
|
||||
|
@ -93,6 +94,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
|
|||
tree->addTopLevelItem(frameTimeIdle);
|
||||
tree->addTopLevelItem(frameTimeWorkPct);
|
||||
tree->addTopLevelItem(frameTimeIdlePct);
|
||||
tree->addTopLevelItem(videoTimeAbs);
|
||||
tree->addTopLevelItem(frameLateCount);
|
||||
|
||||
frameTimeAbs->setFlags(Qt::ItemIsEnabled | Qt::ItemNeverHasChildren);
|
||||
|
@ -105,6 +107,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
|
|||
frameTimeWorkPct->setText(0, tr("Frame Work %"));
|
||||
frameTimeIdlePct->setText(0, tr("Frame Idle %"));
|
||||
frameLateCount->setText(0, tr("Frame Late Count"));
|
||||
videoTimeAbs->setText(0, tr("Video Period ms"));
|
||||
|
||||
frameTimeAbs->setTextAlignment(0, Qt::AlignLeft);
|
||||
frameTimeDel->setTextAlignment(0, Qt::AlignLeft);
|
||||
|
@ -113,6 +116,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
|
|||
frameTimeWorkPct->setTextAlignment(0, Qt::AlignLeft);
|
||||
frameTimeIdlePct->setTextAlignment(0, Qt::AlignLeft);
|
||||
frameLateCount->setTextAlignment(0, Qt::AlignLeft);
|
||||
videoTimeAbs->setTextAlignment(0, Qt::AlignLeft);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
|
@ -123,6 +127,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
|
|||
frameTimeWorkPct->setTextAlignment(i + 1, Qt::AlignCenter);
|
||||
frameTimeIdlePct->setTextAlignment(i + 1, Qt::AlignCenter);
|
||||
frameLateCount->setTextAlignment(i + 1, Qt::AlignCenter);
|
||||
videoTimeAbs->setTextAlignment(i + 1, Qt::AlignCenter);
|
||||
}
|
||||
|
||||
hbox = new QHBoxLayout();
|
||||
|
@ -268,6 +273,19 @@ void FrameTimingDialog_t::updateTimingStats(void)
|
|||
sprintf(stmp, "%.1f", 100.0 * stats.frameTimeIdle.max / stats.frameTimeAbs.tgt);
|
||||
frameTimeIdlePct->setText(4, tr(stmp));
|
||||
|
||||
// Video
|
||||
sprintf(stmp, "%.3f", stats.videoTimeDel.tgt * 1e3);
|
||||
videoTimeAbs->setText(1, tr(stmp));
|
||||
|
||||
sprintf(stmp, "%.3f", stats.videoTimeDel.cur * 1e3);
|
||||
videoTimeAbs->setText(2, tr(stmp));
|
||||
|
||||
sprintf(stmp, "%.3f", stats.videoTimeDel.min * 1e3);
|
||||
videoTimeAbs->setText(3, tr(stmp));
|
||||
|
||||
sprintf(stmp, "%.3f", stats.videoTimeDel.max * 1e3);
|
||||
videoTimeAbs->setText(4, tr(stmp));
|
||||
|
||||
// Late Count
|
||||
sprintf(stmp, "%u", stats.lateCount);
|
||||
frameLateCount->setText(1, tr("0"));
|
||||
|
|
|
@ -39,6 +39,7 @@ protected:
|
|||
QTreeWidgetItem *frameTimeIdle;
|
||||
QTreeWidgetItem *frameTimeIdlePct;
|
||||
QTreeWidgetItem *frameLateCount;
|
||||
QTreeWidgetItem *videoTimeAbs;
|
||||
QGroupBox *statFrame;
|
||||
|
||||
QTreeWidget *tree;
|
||||
|
|
|
@ -490,6 +490,7 @@ InitConfig()
|
|||
config->addOption("pal", "SDL.PAL", 0);
|
||||
config->addOption("autoPal", "SDL.AutoDetectPAL", 1);
|
||||
config->addOption("frameskip", "SDL.Frameskip", 0);
|
||||
config->addOption("intFrameRate", "SDL.IntFrameRate", 0);
|
||||
config->addOption("clipsides", "SDL.ClipSides", 0);
|
||||
config->addOption("nospritelim", "SDL.DisableSpriteLimit", 1);
|
||||
config->addOption("swapduty", "SDL.SwapDuty", 0);
|
||||
|
@ -922,6 +923,7 @@ UpdateEMUCore(Config *config)
|
|||
config->getOption("SDL.Hue", &ntschue);
|
||||
FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue);
|
||||
|
||||
config->getOption("SDL.IntFrameRate" , &useIntFrameRate);
|
||||
config->getOption("SDL.ForceGrayScale", &force_grayscale);
|
||||
config->getOption("SDL.DeempBitSwap" , &paldeemphswap);
|
||||
config->getOption("SDL.PalNotch" , &palnotch);
|
||||
|
|
|
@ -1242,6 +1242,10 @@ int fceuWrapperUpdate( void )
|
|||
|
||||
hexEditorUpdateMemoryValues();
|
||||
|
||||
if ( consoleWindow )
|
||||
{
|
||||
consoleWindow->emulatorThread->signalFrameFinished();
|
||||
}
|
||||
fceuWrapperUnLock();
|
||||
|
||||
emulatorHasMutux = 0;
|
||||
|
|
|
@ -44,10 +44,15 @@ static double frameDeltaMax = 0.0;
|
|||
static double frameIdleCur = 0.0;
|
||||
static double frameIdleMin = 1.0;
|
||||
static double frameIdleMax = 0.0;
|
||||
static double videoLastTs = 0.0;
|
||||
static double videoPeriodCur = 0.0;
|
||||
static double videoPeriodMin = 1.0;
|
||||
static double videoPeriodMax = 0.0;
|
||||
static bool keepFrameTimeStats = false;
|
||||
static int InFrame = 0;
|
||||
double g_fpsScale = Normal; // used by sdl.cpp
|
||||
bool MaxSpeed = false;
|
||||
bool useIntFrameRate = false;
|
||||
|
||||
double getHighPrecTimeStamp(void)
|
||||
{
|
||||
|
@ -176,9 +181,34 @@ int getFrameTimingStats( struct frameTimingStat_t *stats )
|
|||
stats->frameTimeWork.max = 0;
|
||||
}
|
||||
|
||||
stats->videoTimeDel.tgt = desired_frametime;
|
||||
stats->videoTimeDel.cur = videoPeriodCur;
|
||||
stats->videoTimeDel.min = videoPeriodMin;
|
||||
stats->videoTimeDel.max = videoPeriodMax;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void videoBufferSwapMark(void)
|
||||
{
|
||||
if ( keepFrameTimeStats )
|
||||
{
|
||||
double ts = getHighPrecTimeStamp();
|
||||
|
||||
videoPeriodCur = ts - videoLastTs;
|
||||
|
||||
if ( videoPeriodCur < videoPeriodMin )
|
||||
{
|
||||
videoPeriodMin = videoPeriodCur;
|
||||
}
|
||||
if ( videoPeriodCur > videoPeriodMax )
|
||||
{
|
||||
videoPeriodMax = videoPeriodCur;
|
||||
}
|
||||
videoLastTs = ts;
|
||||
}
|
||||
}
|
||||
|
||||
void resetFrameTiming(void)
|
||||
{
|
||||
frameLateCounter = 0;
|
||||
|
@ -186,6 +216,8 @@ void resetFrameTiming(void)
|
|||
frameDeltaMin = 1.0;
|
||||
frameIdleMax = 0.0;
|
||||
frameIdleMin = 1.0;
|
||||
videoPeriodMin = 1.0;
|
||||
videoPeriodMax = 0.0;
|
||||
}
|
||||
|
||||
/* LOGMUL = exp(log(2) / 3)
|
||||
|
@ -204,19 +236,23 @@ void resetFrameTiming(void)
|
|||
void
|
||||
RefreshThrottleFPS(void)
|
||||
{
|
||||
double hz;
|
||||
double hz;
|
||||
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
|
||||
int32_t T;
|
||||
|
||||
hz = ( ((double)fps) / 16777216.0 );
|
||||
hz = ( ((double)fps) / 16777216.0 );
|
||||
|
||||
if ( useIntFrameRate )
|
||||
{
|
||||
hz = (double)( (int)(hz) );
|
||||
}
|
||||
desired_frametime = 1.0 / ( hz * g_fpsScale );
|
||||
|
||||
T = (int32_t)( desired_frametime * 1000.0 );
|
||||
|
||||
if ( T < 0 ) T = 1;
|
||||
|
||||
//printf("FrameTime: %llu %llu %f %lf \n", fps, fps >> 24, hz, desired_frametime );
|
||||
//printf("FrameTime: %llu %llu %f %lf \n", fps, fps >> 24, hz, desired_frametime );
|
||||
|
||||
Lasttime=0;
|
||||
Nexttime=0;
|
||||
|
|
|
@ -36,6 +36,13 @@ struct frameTimingStat_t
|
|||
double max;
|
||||
} frameTimeIdle;
|
||||
|
||||
struct {
|
||||
double tgt;
|
||||
double cur;
|
||||
double min;
|
||||
double max;
|
||||
} videoTimeDel;
|
||||
|
||||
unsigned int lateCount;
|
||||
|
||||
bool enabled;
|
||||
|
@ -44,3 +51,7 @@ struct frameTimingStat_t
|
|||
void resetFrameTiming(void);
|
||||
void setFrameTimingEnable( bool enable );
|
||||
int getFrameTimingStats( struct frameTimingStat_t *stats );
|
||||
void videoBufferSwapMark(void);
|
||||
double getHighPrecTimeStamp(void);
|
||||
|
||||
extern bool useIntFrameRate;
|
||||
|
|
Loading…
Reference in New Issue