Merge pull request #247 from mjbudd77/master
Frame Timing and Thread Scheduling Enhancements for Qt GUI
This commit is contained in:
commit
3ccbc61aa1
|
@ -430,6 +430,7 @@ set(SRC_DRIVERS_SDL
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/InputConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GamePadConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HotKeyConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TimingConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/PaletteConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GuiConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MoviePlay.cpp
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
// GameApp.cpp
|
||||
//
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
@ -27,6 +36,7 @@
|
|||
#include "Qt/GuiConf.h"
|
||||
#include "Qt/MoviePlay.h"
|
||||
#include "Qt/MovieOptions.h"
|
||||
#include "Qt/TimingConf.h"
|
||||
#include "Qt/LuaControl.h"
|
||||
#include "Qt/CheatsConf.h"
|
||||
#include "Qt/GameGenie.h"
|
||||
|
@ -50,6 +60,7 @@
|
|||
consoleWin_t::consoleWin_t(QWidget *parent)
|
||||
: QMainWindow( parent )
|
||||
{
|
||||
int opt;
|
||||
int use_SDL_video = false;
|
||||
int setFullScreen = false;
|
||||
|
||||
|
@ -95,11 +106,24 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
|||
connect( gameTimer, &QTimer::timeout, this, &consoleWin_t::updatePeriodic );
|
||||
|
||||
gameTimer->setTimerType( Qt::PreciseTimer );
|
||||
//gameTimer->start( 16 ); // 60hz
|
||||
gameTimer->start( 8 ); // 120hz
|
||||
|
||||
emulatorThread->start();
|
||||
|
||||
g_config->getOption( "SDL.SetSchedParam", &opt );
|
||||
|
||||
if ( opt )
|
||||
{
|
||||
int policy, prio, nice;
|
||||
|
||||
g_config->getOption( "SDL.GuiSchedPolicy", &policy );
|
||||
g_config->getOption( "SDL.GuiSchedPrioRt", &prio );
|
||||
g_config->getOption( "SDL.GuiSchedNice" , &nice );
|
||||
|
||||
setNicePriority( nice );
|
||||
|
||||
setSchedParam( policy, prio );
|
||||
}
|
||||
}
|
||||
|
||||
consoleWin_t::~consoleWin_t(void)
|
||||
|
@ -404,6 +428,14 @@ void consoleWin_t::createMainMenu(void)
|
|||
|
||||
optMenu->addAction(guiConfig);
|
||||
|
||||
// Options -> Timing Config
|
||||
timingConfig = new QAction(tr("Timing Config"), this);
|
||||
//timingConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
|
||||
timingConfig->setStatusTip(tr("Timing Configure"));
|
||||
connect(timingConfig, SIGNAL(triggered()), this, SLOT(openTimingConfWin(void)) );
|
||||
|
||||
optMenu->addAction(timingConfig);
|
||||
|
||||
// Options -> Movie Options
|
||||
movieConfig = new QAction(tr("Movie Options"), this);
|
||||
//movieConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
|
||||
|
@ -1252,6 +1284,17 @@ void consoleWin_t::openGuiConfWin(void)
|
|||
guiConfWin->show();
|
||||
}
|
||||
|
||||
void consoleWin_t::openTimingConfWin(void)
|
||||
{
|
||||
TimingConfDialog_t *tmConfWin;
|
||||
|
||||
//printf("Open Timing Config Window\n");
|
||||
|
||||
tmConfWin = new TimingConfDialog_t(this);
|
||||
|
||||
tmConfWin->show();
|
||||
}
|
||||
|
||||
void consoleWin_t::openMovieOptWin(void)
|
||||
{
|
||||
MovieOptionsDialog_t *win;
|
||||
|
@ -1770,6 +1813,159 @@ void consoleWin_t::aboutQt(void)
|
|||
return;
|
||||
}
|
||||
|
||||
int consoleWin_t::setNicePriority( int value )
|
||||
{
|
||||
int ret = 0;
|
||||
#if defined(__linux__)
|
||||
|
||||
if ( value < -20 )
|
||||
{
|
||||
value = -20;
|
||||
}
|
||||
else if ( value > 19 )
|
||||
{
|
||||
value = 19;
|
||||
}
|
||||
|
||||
if ( ::setpriority( PRIO_PROCESS, getpid(), value ) )
|
||||
{
|
||||
perror("Emulator thread setpriority error: ");
|
||||
ret = -1;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
if ( value < -20 )
|
||||
{
|
||||
value = -20;
|
||||
}
|
||||
else if ( value > 20 )
|
||||
{
|
||||
value = 20;
|
||||
}
|
||||
|
||||
if ( ::setpriority( PRIO_PROCESS, getpid(), value ) )
|
||||
{
|
||||
perror("Emulator thread setpriority error: ");
|
||||
ret = -1;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int consoleWin_t::getNicePriority(void)
|
||||
{
|
||||
return ::getpriority( PRIO_PROCESS, getpid() );
|
||||
}
|
||||
|
||||
int consoleWin_t::getMinSchedPriority(void)
|
||||
{
|
||||
int policy, prio;
|
||||
|
||||
if ( getSchedParam( policy, prio ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return sched_get_priority_min( policy );
|
||||
}
|
||||
|
||||
int consoleWin_t::getMaxSchedPriority(void)
|
||||
{
|
||||
int policy, prio;
|
||||
|
||||
if ( getSchedParam( policy, prio ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return sched_get_priority_max( policy );
|
||||
}
|
||||
|
||||
int consoleWin_t::getSchedParam( int &policy, int &priority )
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#if defined(__linux__)
|
||||
struct sched_param p;
|
||||
|
||||
policy = sched_getscheduler( getpid() );
|
||||
|
||||
if ( sched_getparam( getpid(), &p ) )
|
||||
{
|
||||
perror("GUI thread sched_getparam error: ");
|
||||
ret = -1;
|
||||
priority = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
priority = p.sched_priority;
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
struct sched_param p;
|
||||
|
||||
if ( pthread_getschedparam( pthread_self(), &policy, &p ) )
|
||||
{
|
||||
perror("GUI thread pthread_getschedparam error: ");
|
||||
ret = -1;
|
||||
priority = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
priority = p.sched_priority;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int consoleWin_t::setSchedParam( int policy, int priority )
|
||||
{
|
||||
int ret = 0;
|
||||
#if defined(__linux__)
|
||||
struct sched_param p;
|
||||
int minPrio, maxPrio;
|
||||
|
||||
minPrio = sched_get_priority_min( policy );
|
||||
maxPrio = sched_get_priority_max( policy );
|
||||
|
||||
if ( priority < minPrio )
|
||||
{
|
||||
priority = minPrio;
|
||||
}
|
||||
else if ( priority > maxPrio )
|
||||
{
|
||||
priority = maxPrio;
|
||||
}
|
||||
p.sched_priority = priority;
|
||||
|
||||
if ( sched_setscheduler( getpid(), policy, &p ) )
|
||||
{
|
||||
perror("GUI thread sched_setscheduler error");
|
||||
ret = -1;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
struct sched_param p;
|
||||
int minPrio, maxPrio;
|
||||
|
||||
minPrio = sched_get_priority_min( policy );
|
||||
maxPrio = sched_get_priority_max( policy );
|
||||
|
||||
if ( priority < minPrio )
|
||||
{
|
||||
priority = minPrio;
|
||||
}
|
||||
else if ( priority > maxPrio )
|
||||
{
|
||||
priority = maxPrio;
|
||||
}
|
||||
p.sched_priority = priority;
|
||||
|
||||
if ( ::pthread_setschedparam( pthread_self(), policy, &p ) != 0 )
|
||||
{
|
||||
perror("GUI thread pthread_setschedparam error: ");
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void consoleWin_t::syncActionConfig( QAction *act, const char *property )
|
||||
{
|
||||
if ( act->isCheckable() )
|
||||
|
@ -1821,11 +2017,205 @@ void consoleWin_t::updatePeriodic(void)
|
|||
return;
|
||||
}
|
||||
|
||||
emulatorThread_t::emulatorThread_t(void)
|
||||
{
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
pself = 0;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
#ifndef SYS_gettid
|
||||
#error "SYS_gettid unavailable on this system"
|
||||
#endif
|
||||
|
||||
#define gettid() ((pid_t)syscall(SYS_gettid))
|
||||
#endif
|
||||
|
||||
|
||||
void emulatorThread_t::init(void)
|
||||
{
|
||||
int opt;
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
if ( pthread_self() == (pthread_t)QThread::currentThreadId() )
|
||||
{
|
||||
pself = pthread_self();
|
||||
//printf("EMU is using PThread: %p\n", (void*)pself);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
pid = gettid();
|
||||
#elif defined(__APPLE__)
|
||||
pid = getpid();
|
||||
#endif
|
||||
|
||||
g_config->getOption( "SDL.SetSchedParam", &opt );
|
||||
|
||||
if ( opt )
|
||||
{
|
||||
int policy, prio, nice;
|
||||
|
||||
g_config->getOption( "SDL.EmuSchedPolicy", &policy );
|
||||
g_config->getOption( "SDL.EmuSchedPrioRt", &prio );
|
||||
g_config->getOption( "SDL.EmuSchedNice" , &nice );
|
||||
|
||||
setNicePriority( nice );
|
||||
|
||||
setSchedParam( policy, prio );
|
||||
}
|
||||
}
|
||||
|
||||
void emulatorThread_t::setPriority( QThread::Priority priority_req )
|
||||
{
|
||||
//printf("New Priority: %i \n", priority_req );
|
||||
//printf("Old Priority: %i \n", priority() );
|
||||
|
||||
QThread::setPriority( priority_req );
|
||||
|
||||
//printf("Set Priority: %i \n", priority() );
|
||||
}
|
||||
|
||||
int emulatorThread_t::setNicePriority( int value )
|
||||
{
|
||||
int ret = 0;
|
||||
#if defined(__linux__)
|
||||
|
||||
if ( value < -20 )
|
||||
{
|
||||
value = -20;
|
||||
}
|
||||
else if ( value > 19 )
|
||||
{
|
||||
value = 19;
|
||||
}
|
||||
|
||||
if ( ::setpriority( PRIO_PROCESS, pid, value ) )
|
||||
{
|
||||
perror("Emulator thread setpriority error: ");
|
||||
ret = -1;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
if ( value < -20 )
|
||||
{
|
||||
value = -20;
|
||||
}
|
||||
else if ( value > 20 )
|
||||
{
|
||||
value = 20;
|
||||
}
|
||||
|
||||
if ( ::setpriority( PRIO_PROCESS, pid, value ) )
|
||||
{
|
||||
perror("Emulator thread setpriority error: ");
|
||||
ret = -1;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int emulatorThread_t::getNicePriority(void)
|
||||
{
|
||||
return ::getpriority( PRIO_PROCESS, pid );
|
||||
}
|
||||
|
||||
int emulatorThread_t::getMinSchedPriority(void)
|
||||
{
|
||||
int policy, prio;
|
||||
|
||||
if ( getSchedParam( policy, prio ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return sched_get_priority_min( policy );
|
||||
}
|
||||
|
||||
int emulatorThread_t::getMaxSchedPriority(void)
|
||||
{
|
||||
int policy, prio;
|
||||
|
||||
if ( getSchedParam( policy, prio ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return sched_get_priority_max( policy );
|
||||
}
|
||||
|
||||
int emulatorThread_t::getSchedParam( int &policy, int &priority )
|
||||
{
|
||||
struct sched_param p;
|
||||
|
||||
if ( pthread_getschedparam( pself, &policy, &p ) )
|
||||
{
|
||||
perror("Emulator thread pthread_getschedparam error: ");
|
||||
return -1;
|
||||
}
|
||||
priority = p.sched_priority;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int emulatorThread_t::setSchedParam( int policy, int priority )
|
||||
{
|
||||
int ret = 0;
|
||||
#if defined(__linux__)
|
||||
struct sched_param p;
|
||||
int minPrio, maxPrio;
|
||||
|
||||
minPrio = sched_get_priority_min( policy );
|
||||
maxPrio = sched_get_priority_max( policy );
|
||||
|
||||
if ( priority < minPrio )
|
||||
{
|
||||
priority = minPrio;
|
||||
}
|
||||
else if ( priority > maxPrio )
|
||||
{
|
||||
priority = maxPrio;
|
||||
}
|
||||
p.sched_priority = priority;
|
||||
|
||||
if ( ::pthread_setschedparam( pself, policy, &p ) != 0 )
|
||||
{
|
||||
perror("Emulator thread pthread_setschedparam error: ");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
struct sched_param p;
|
||||
int minPrio, maxPrio;
|
||||
|
||||
minPrio = sched_get_priority_min( policy );
|
||||
maxPrio = sched_get_priority_max( policy );
|
||||
|
||||
if ( priority < minPrio )
|
||||
{
|
||||
priority = minPrio;
|
||||
}
|
||||
else if ( priority > maxPrio )
|
||||
{
|
||||
priority = maxPrio;
|
||||
}
|
||||
p.sched_priority = priority;
|
||||
|
||||
if ( ::pthread_setschedparam( pself, policy, &p ) != 0 )
|
||||
{
|
||||
perror("Emulator thread pthread_setschedparam error: ");
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void emulatorThread_t::run(void)
|
||||
{
|
||||
printf("Emulator Start\n");
|
||||
nes_shm->runEmulator = 1;
|
||||
|
||||
init();
|
||||
|
||||
while ( nes_shm->runEmulator )
|
||||
{
|
||||
fceuWrapperUpdate();
|
||||
|
|
|
@ -28,10 +28,32 @@ class emulatorThread_t : public QThread
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
//public slots:
|
||||
protected:
|
||||
void run( void ) override;
|
||||
|
||||
public:
|
||||
emulatorThread_t(void);
|
||||
|
||||
void setPriority( QThread::Priority priority );
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
int setSchedParam( int policy, int priority );
|
||||
int getSchedParam( int &policy, int &priority );
|
||||
int setNicePriority( int value );
|
||||
int getNicePriority( void );
|
||||
int getMinSchedPriority(void);
|
||||
int getMaxSchedPriority(void);
|
||||
#endif
|
||||
private:
|
||||
void init(void);
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
pthread_t pself;
|
||||
int pid;
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
void finished();
|
||||
};
|
||||
|
||||
class consoleWin_t : public QMainWindow
|
||||
|
@ -53,6 +75,17 @@ class consoleWin_t : public QMainWindow
|
|||
|
||||
int showListSelectDialog( const char *title, std::vector <std::string> &l );
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
int setSchedParam( int policy, int priority );
|
||||
int getSchedParam( int &policy, int &priority );
|
||||
int setNicePriority( int value );
|
||||
int getNicePriority( void );
|
||||
int getMinSchedPriority(void);
|
||||
int getMaxSchedPriority(void);
|
||||
#endif
|
||||
|
||||
emulatorThread_t *emulatorThread;
|
||||
|
||||
protected:
|
||||
QMenu *fileMenu;
|
||||
QMenu *optMenu;
|
||||
|
@ -78,6 +111,7 @@ class consoleWin_t : public QMainWindow
|
|||
QAction *hotkeyConfig;
|
||||
QAction *paletteConfig;
|
||||
QAction *guiConfig;
|
||||
QAction *timingConfig;
|
||||
QAction *movieConfig;
|
||||
QAction *autoResume;
|
||||
QAction *fullscreen;
|
||||
|
@ -112,8 +146,6 @@ class consoleWin_t : public QMainWindow
|
|||
|
||||
QTimer *gameTimer;
|
||||
|
||||
emulatorThread_t *emulatorThread;
|
||||
|
||||
std::string errorMsg;
|
||||
bool errorMsgValid;
|
||||
|
||||
|
@ -148,6 +180,7 @@ class consoleWin_t : public QMainWindow
|
|||
void openHotkeyConfWin(void);
|
||||
void openPaletteConfWin(void);
|
||||
void openGuiConfWin(void);
|
||||
void openTimingConfWin(void);
|
||||
void openMovieOptWin(void);
|
||||
void openCodeDataLogger(void);
|
||||
void openTraceLogger(void);
|
||||
|
|
|
@ -0,0 +1,534 @@
|
|||
// TimingConf.cpp
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <SDL.h>
|
||||
#include <QHeaderView>
|
||||
#include <QCloseEvent>
|
||||
|
||||
#include "Qt/main.h"
|
||||
#include "Qt/dface.h"
|
||||
#include "Qt/input.h"
|
||||
#include "Qt/config.h"
|
||||
#include "Qt/keyscan.h"
|
||||
#include "Qt/throttle.h"
|
||||
#include "Qt/fceuWrapper.h"
|
||||
#include "Qt/ConsoleWindow.h"
|
||||
#include "Qt/TimingConf.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool hasNicePermissions( int val )
|
||||
{
|
||||
int usrID;
|
||||
bool usrRoot;
|
||||
|
||||
usrID = geteuid();
|
||||
|
||||
usrRoot = (usrID == 0);
|
||||
|
||||
if ( usrRoot )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#ifdef __linux__
|
||||
struct rlimit r;
|
||||
|
||||
if ( getrlimit( RLIMIT_NICE, &r ) == 0 )
|
||||
{
|
||||
int ncur = 20 - r.rlim_cur;
|
||||
|
||||
if ( val >= ncur )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//printf("RLim Cur: %lu \n", r.rlim_cur );
|
||||
//printf("RLim Max: %lu \n", r.rlim_max );
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
TimingConfDialog_t::TimingConfDialog_t(QWidget *parent)
|
||||
: QDialog( parent )
|
||||
{
|
||||
int opt;
|
||||
QVBoxLayout *mainLayout;
|
||||
QHBoxLayout *hbox;
|
||||
QGridLayout *grid;
|
||||
QGroupBox *emuPrioBox, *guiPrioBox;
|
||||
|
||||
setWindowTitle("Timing Configuration");
|
||||
|
||||
mainLayout = new QVBoxLayout();
|
||||
|
||||
emuPrioCtlEna = new QCheckBox( tr("Set Scheduling Parameters at Startup") );
|
||||
|
||||
emuPrioBox = new QGroupBox( tr("EMU Thread Scheduling Parameters") );
|
||||
guiPrioBox = new QGroupBox( tr("GUI Thread Scheduling Parameters") );
|
||||
grid = new QGridLayout();
|
||||
emuPrioBox->setLayout( grid );
|
||||
|
||||
emuSchedPolicyBox = new QComboBox();
|
||||
emuSchedPrioSlider = new QSlider( Qt::Horizontal );
|
||||
emuSchedNiceSlider = new QSlider( Qt::Horizontal );
|
||||
emuSchedPrioLabel = new QLabel( tr("Priority (RT)") );
|
||||
emuSchedNiceLabel = new QLabel( tr("Priority (Nice)") );
|
||||
|
||||
emuSchedPolicyBox->addItem( tr("SCHED_OTHER") , SCHED_OTHER );
|
||||
emuSchedPolicyBox->addItem( tr("SCHED_FIFO") , SCHED_FIFO );
|
||||
emuSchedPolicyBox->addItem( tr("SCHED_RR") , SCHED_RR );
|
||||
|
||||
grid->addWidget( new QLabel( tr("Policy") ), 0, 0 );
|
||||
grid->addWidget( emuSchedPolicyBox, 0, 1 );
|
||||
grid->addWidget( emuSchedPrioLabel, 1, 0 );
|
||||
grid->addWidget( emuSchedPrioSlider, 1, 1 );
|
||||
grid->addWidget( emuSchedNiceLabel, 2, 0 );
|
||||
grid->addWidget( emuSchedNiceSlider, 2, 1 );
|
||||
|
||||
mainLayout->addWidget( emuPrioCtlEna );
|
||||
mainLayout->addWidget( emuPrioBox );
|
||||
|
||||
grid = new QGridLayout();
|
||||
guiPrioBox->setLayout( grid );
|
||||
|
||||
guiSchedPolicyBox = new QComboBox();
|
||||
guiSchedPrioSlider = new QSlider( Qt::Horizontal );
|
||||
guiSchedNiceSlider = new QSlider( Qt::Horizontal );
|
||||
guiSchedPrioLabel = new QLabel( tr("Priority (RT)") );
|
||||
guiSchedNiceLabel = new QLabel( tr("Priority (Nice)") );
|
||||
|
||||
guiSchedPolicyBox->addItem( tr("SCHED_OTHER") , SCHED_OTHER );
|
||||
guiSchedPolicyBox->addItem( tr("SCHED_FIFO") , SCHED_FIFO );
|
||||
guiSchedPolicyBox->addItem( tr("SCHED_RR") , SCHED_RR );
|
||||
|
||||
grid->addWidget( new QLabel( tr("Policy") ), 0, 0 );
|
||||
grid->addWidget( guiSchedPolicyBox, 0, 1 );
|
||||
grid->addWidget( guiSchedPrioLabel, 1, 0 );
|
||||
grid->addWidget( guiSchedPrioSlider, 1, 1 );
|
||||
grid->addWidget( guiSchedNiceLabel, 2, 0 );
|
||||
grid->addWidget( guiSchedNiceSlider, 2, 1 );
|
||||
|
||||
mainLayout->addWidget( guiPrioBox );
|
||||
|
||||
hbox = new QHBoxLayout();
|
||||
timingDevSelBox = new QComboBox();
|
||||
timingDevSelBox->addItem( tr("NanoSleep") , 0 );
|
||||
|
||||
#ifdef __linux__
|
||||
timingDevSelBox->addItem( tr("Timer FD") , 1 );
|
||||
#endif
|
||||
hbox->addWidget( new QLabel( tr("Timing Mechanism:") ) );
|
||||
hbox->addWidget( timingDevSelBox );
|
||||
mainLayout->addLayout( hbox );
|
||||
|
||||
setLayout( mainLayout );
|
||||
|
||||
g_config->getOption( "SDL.SetSchedParam", &opt );
|
||||
|
||||
emuPrioCtlEna->setChecked( opt );
|
||||
|
||||
updatePolicyBox();
|
||||
updateSliderLimits();
|
||||
updateSliderValues();
|
||||
updateTimingMech();
|
||||
|
||||
connect( emuSchedPolicyBox , SIGNAL(activated(int)) , this, SLOT(emuSchedPolicyChange(int)) );
|
||||
connect( emuSchedNiceSlider , SIGNAL(valueChanged(int)), this, SLOT(emuSchedNiceChange(int)) );
|
||||
connect( emuSchedPrioSlider , SIGNAL(valueChanged(int)), this, SLOT(emuSchedPrioChange(int)) );
|
||||
connect( guiSchedPolicyBox , SIGNAL(activated(int)) , this, SLOT(guiSchedPolicyChange(int)) );
|
||||
connect( guiSchedNiceSlider , SIGNAL(valueChanged(int)), this, SLOT(guiSchedNiceChange(int)) );
|
||||
connect( guiSchedPrioSlider , SIGNAL(valueChanged(int)), this, SLOT(guiSchedPrioChange(int)) );
|
||||
connect( emuPrioCtlEna , SIGNAL(stateChanged(int)), this, SLOT(emuSchedCtlChange(int)) );
|
||||
connect( timingDevSelBox , SIGNAL(activated(int)) , this, SLOT(emuTimingMechChange(int)) );
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
TimingConfDialog_t::~TimingConfDialog_t(void)
|
||||
{
|
||||
printf("Destroy Timing Config Window\n");
|
||||
saveValues();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
printf("Timing Close Window Event\n");
|
||||
done(0);
|
||||
deleteLater();
|
||||
event->accept();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::closeWindow(void)
|
||||
{
|
||||
//printf("Close Window\n");
|
||||
done(0);
|
||||
deleteLater();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::emuSchedCtlChange( int state )
|
||||
{
|
||||
g_config->setOption( "SDL.SetSchedParam", (state != Qt::Unchecked) );
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::saveValues(void)
|
||||
{
|
||||
int policy, prio, nice;
|
||||
|
||||
if ( consoleWindow == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
nice = consoleWindow->emulatorThread->getNicePriority();
|
||||
|
||||
consoleWindow->emulatorThread->getSchedParam( policy, prio );
|
||||
|
||||
g_config->setOption( "SDL.EmuSchedPolicy", policy );
|
||||
g_config->setOption( "SDL.EmuSchedPrioRt", prio );
|
||||
g_config->setOption( "SDL.EmuSchedNice" , nice );
|
||||
|
||||
//printf("EMU Sched: %i %i %i\n", policy, prio, nice );
|
||||
|
||||
nice = consoleWindow->getNicePriority();
|
||||
|
||||
consoleWindow->getSchedParam( policy, prio );
|
||||
|
||||
g_config->setOption( "SDL.GuiSchedPolicy", policy );
|
||||
g_config->setOption( "SDL.GuiSchedPrioRt", prio );
|
||||
g_config->setOption( "SDL.GuiSchedNice" , nice );
|
||||
|
||||
//printf("GUI Sched: %i %i %i\n", policy, prio, nice );
|
||||
|
||||
g_config->save();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::emuSchedNiceChange(int val)
|
||||
{
|
||||
if ( consoleWindow == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
fceuWrapperLock();
|
||||
if ( consoleWindow->emulatorThread->setNicePriority( -val ) )
|
||||
{
|
||||
char msg[1024];
|
||||
|
||||
sprintf( msg, "Error: system call setPriority Failed\nReason: %s\n", strerror(errno) );
|
||||
#ifdef __linux__
|
||||
strcat( msg, "Ensure that your system has the proper resource permissions set in the file:\n\n");
|
||||
strcat( msg, " /etc/security/limits.conf \n\n");
|
||||
strcat( msg, "Adding the following lines to that file and rebooting will usually fix the issue:\n\n");
|
||||
strcat( msg, "* - priority 99 \n");
|
||||
strcat( msg, "* - rtprio 99 \n");
|
||||
strcat( msg, "* - nice -20 \n");
|
||||
#endif
|
||||
printf("%s\n", msg );
|
||||
consoleWindow->QueueErrorMsgWindow( msg );
|
||||
updateSliderValues();
|
||||
}
|
||||
fceuWrapperUnLock();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::emuSchedPrioChange(int val)
|
||||
{
|
||||
int policy, prio;
|
||||
|
||||
if ( consoleWindow == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
fceuWrapperLock();
|
||||
consoleWindow->emulatorThread->getSchedParam( policy, prio );
|
||||
|
||||
if ( consoleWindow->emulatorThread->setSchedParam( policy, val ) )
|
||||
{
|
||||
char msg[1024];
|
||||
|
||||
sprintf( msg, "Error: system call pthread_setschedparam Failed\nReason: %s\n", strerror(errno) );
|
||||
#ifdef __linux__
|
||||
strcat( msg, "Ensure that your system has the proper resource permissions set in the file:\n\n");
|
||||
strcat( msg, " /etc/security/limits.conf \n\n");
|
||||
strcat( msg, "Adding the following lines to that file and rebooting will usually fix the issue:\n\n");
|
||||
strcat( msg, "* - priority 99 \n");
|
||||
strcat( msg, "* - rtprio 99 \n");
|
||||
strcat( msg, "* - nice -20 \n");
|
||||
#endif
|
||||
printf("%s\n", msg );
|
||||
consoleWindow->QueueErrorMsgWindow( msg );
|
||||
updateSliderValues();
|
||||
}
|
||||
fceuWrapperUnLock();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::emuSchedPolicyChange( int index )
|
||||
{
|
||||
int policy, prio;
|
||||
|
||||
if ( consoleWindow == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
fceuWrapperLock();
|
||||
consoleWindow->emulatorThread->getSchedParam( policy, prio );
|
||||
|
||||
policy = emuSchedPolicyBox->itemData( index ).toInt();
|
||||
|
||||
if ( consoleWindow->emulatorThread->setSchedParam( policy, prio ) )
|
||||
{
|
||||
char msg[1024];
|
||||
|
||||
sprintf( msg, "Error: system call pthread_setschedparam Failed\nReason: %s\n", strerror(errno) );
|
||||
#ifdef __linux__
|
||||
strcat( msg, "Ensure that your system has the proper resource permissions set in the file:\n\n");
|
||||
strcat( msg, " /etc/security/limits.conf \n\n");
|
||||
strcat( msg, "Adding the following lines to that file and rebooting will usually fix the issue:\n\n");
|
||||
strcat( msg, "* - priority 99 \n");
|
||||
strcat( msg, "* - rtprio 99 \n");
|
||||
strcat( msg, "* - nice -20 \n");
|
||||
#endif
|
||||
printf("%s\n", msg );
|
||||
consoleWindow->QueueErrorMsgWindow( msg );
|
||||
}
|
||||
|
||||
updatePolicyBox();
|
||||
updateSliderLimits();
|
||||
updateSliderValues();
|
||||
fceuWrapperUnLock();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::guiSchedNiceChange(int val)
|
||||
{
|
||||
if ( consoleWindow == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
fceuWrapperLock();
|
||||
if ( consoleWindow->setNicePriority( -val ) )
|
||||
{
|
||||
char msg[1024];
|
||||
|
||||
sprintf( msg, "Error: system call setPriority Failed\nReason: %s\n", strerror(errno) );
|
||||
#ifdef __linux__
|
||||
strcat( msg, "Ensure that your system has the proper resource permissions set in the file:\n\n");
|
||||
strcat( msg, " /etc/security/limits.conf \n\n");
|
||||
strcat( msg, "Adding the following lines to that file and rebooting will usually fix the issue:\n\n");
|
||||
strcat( msg, "* - priority 99 \n");
|
||||
strcat( msg, "* - rtprio 99 \n");
|
||||
strcat( msg, "* - nice -20 \n");
|
||||
#endif
|
||||
printf("%s\n", msg );
|
||||
consoleWindow->QueueErrorMsgWindow( msg );
|
||||
updateSliderValues();
|
||||
}
|
||||
fceuWrapperUnLock();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::guiSchedPrioChange(int val)
|
||||
{
|
||||
int policy, prio;
|
||||
|
||||
if ( consoleWindow == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
fceuWrapperLock();
|
||||
consoleWindow->getSchedParam( policy, prio );
|
||||
|
||||
if ( consoleWindow->setSchedParam( policy, val ) )
|
||||
{
|
||||
char msg[1024];
|
||||
|
||||
sprintf( msg, "Error: system call pthread_setschedparam Failed\nReason: %s\n", strerror(errno) );
|
||||
#ifdef __linux__
|
||||
strcat( msg, "Ensure that your system has the proper resource permissions set in the file:\n\n");
|
||||
strcat( msg, " /etc/security/limits.conf \n\n");
|
||||
strcat( msg, "Adding the following lines to that file and rebooting will usually fix the issue:\n\n");
|
||||
strcat( msg, "* - priority 99 \n");
|
||||
strcat( msg, "* - rtprio 99 \n");
|
||||
strcat( msg, "* - nice -20 \n");
|
||||
#endif
|
||||
printf("%s\n", msg );
|
||||
consoleWindow->QueueErrorMsgWindow( msg );
|
||||
updateSliderValues();
|
||||
}
|
||||
fceuWrapperUnLock();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::guiSchedPolicyChange( int index )
|
||||
{
|
||||
int policy, prio;
|
||||
|
||||
if ( consoleWindow == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
fceuWrapperLock();
|
||||
consoleWindow->getSchedParam( policy, prio );
|
||||
|
||||
policy = guiSchedPolicyBox->itemData( index ).toInt();
|
||||
|
||||
if ( consoleWindow->setSchedParam( policy, prio ) )
|
||||
{
|
||||
char msg[1024];
|
||||
|
||||
sprintf( msg, "Error: system call pthread_setschedparam Failed\nReason: %s\n", strerror(errno) );
|
||||
#ifdef __linux__
|
||||
strcat( msg, "Ensure that your system has the proper resource permissions set in the file:\n\n");
|
||||
strcat( msg, " /etc/security/limits.conf \n\n");
|
||||
strcat( msg, "Adding the following lines to that file and rebooting will usually fix the issue:\n\n");
|
||||
strcat( msg, "* - priority 99 \n");
|
||||
strcat( msg, "* - rtprio 99 \n");
|
||||
strcat( msg, "* - nice -20 \n");
|
||||
#endif
|
||||
printf("%s\n", msg );
|
||||
consoleWindow->QueueErrorMsgWindow( msg );
|
||||
}
|
||||
|
||||
updatePolicyBox();
|
||||
updateSliderLimits();
|
||||
updateSliderValues();
|
||||
fceuWrapperUnLock();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::updatePolicyBox(void)
|
||||
{
|
||||
int policy, prio;
|
||||
|
||||
if ( consoleWindow == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
consoleWindow->emulatorThread->getSchedParam( policy, prio );
|
||||
|
||||
for (int j=0; j<emuSchedPolicyBox->count(); j++)
|
||||
{
|
||||
if ( emuSchedPolicyBox->itemData(j).toInt() == policy )
|
||||
{
|
||||
//printf("Found Policy %i %i\n", j , policy );
|
||||
emuSchedPolicyBox->setCurrentIndex( j );
|
||||
}
|
||||
}
|
||||
|
||||
consoleWindow->getSchedParam( policy, prio );
|
||||
|
||||
for (int j=0; j<guiSchedPolicyBox->count(); j++)
|
||||
{
|
||||
if ( guiSchedPolicyBox->itemData(j).toInt() == policy )
|
||||
{
|
||||
//printf("Found Policy %i %i\n", j , policy );
|
||||
guiSchedPolicyBox->setCurrentIndex( j );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::updateSliderValues(void)
|
||||
{
|
||||
int policy, prio;
|
||||
bool hasNicePerms;
|
||||
|
||||
if ( consoleWindow == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
consoleWindow->emulatorThread->getSchedParam( policy, prio );
|
||||
|
||||
emuSchedNiceSlider->setValue( -consoleWindow->emulatorThread->getNicePriority() );
|
||||
emuSchedPrioSlider->setValue( prio );
|
||||
|
||||
if ( (policy == SCHED_RR) || (policy == SCHED_FIFO) )
|
||||
{
|
||||
emuSchedPrioLabel->setEnabled(true);
|
||||
emuSchedPrioSlider->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
emuSchedPrioLabel->setEnabled(false);
|
||||
emuSchedPrioSlider->setEnabled(false);
|
||||
}
|
||||
hasNicePerms = hasNicePermissions( consoleWindow->emulatorThread->getNicePriority() );
|
||||
|
||||
emuSchedNiceLabel->setEnabled( hasNicePerms );
|
||||
emuSchedNiceSlider->setEnabled( hasNicePerms );
|
||||
|
||||
consoleWindow->getSchedParam( policy, prio );
|
||||
|
||||
guiSchedNiceSlider->setValue( -consoleWindow->getNicePriority() );
|
||||
guiSchedPrioSlider->setValue( prio );
|
||||
|
||||
if ( (policy == SCHED_RR) || (policy == SCHED_FIFO) )
|
||||
{
|
||||
guiSchedPrioLabel->setEnabled(true);
|
||||
guiSchedPrioSlider->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
guiSchedPrioLabel->setEnabled(false);
|
||||
guiSchedPrioSlider->setEnabled(false);
|
||||
}
|
||||
hasNicePerms = hasNicePermissions( consoleWindow->getNicePriority() );
|
||||
|
||||
guiSchedNiceLabel->setEnabled( hasNicePerms );
|
||||
guiSchedNiceSlider->setEnabled( hasNicePerms );
|
||||
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::updateSliderLimits(void)
|
||||
{
|
||||
if ( consoleWindow == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
emuSchedNiceSlider->setMinimum( -20 );
|
||||
emuSchedNiceSlider->setMaximum( 20 );
|
||||
emuSchedPrioSlider->setMinimum( consoleWindow->emulatorThread->getMinSchedPriority() );
|
||||
emuSchedPrioSlider->setMaximum( consoleWindow->emulatorThread->getMaxSchedPriority() );
|
||||
|
||||
guiSchedNiceSlider->setMinimum( -20 );
|
||||
guiSchedNiceSlider->setMaximum( 20 );
|
||||
guiSchedPrioSlider->setMinimum( consoleWindow->getMinSchedPriority() );
|
||||
guiSchedPrioSlider->setMaximum( consoleWindow->getMaxSchedPriority() );
|
||||
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::emuTimingMechChange( int index )
|
||||
{
|
||||
int mode;
|
||||
|
||||
if ( consoleWindow == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
fceuWrapperLock();
|
||||
|
||||
mode = timingDevSelBox->itemData( index ).toInt();
|
||||
|
||||
setTimingMode( mode );
|
||||
|
||||
RefreshThrottleFPS();
|
||||
|
||||
g_config->setOption("SDL.EmuTimingMech", mode);
|
||||
|
||||
fceuWrapperUnLock();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void TimingConfDialog_t::updateTimingMech(void)
|
||||
{
|
||||
int mode = getTimingMode();
|
||||
|
||||
for (int j=0; j<timingDevSelBox->count(); j++)
|
||||
{
|
||||
if ( timingDevSelBox->itemData(j).toInt() == mode )
|
||||
{
|
||||
timingDevSelBox->setCurrentIndex( j );
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
|
@ -0,0 +1,65 @@
|
|||
// TimingConf.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QSlider>
|
||||
#include <QFrame>
|
||||
#include <QGroupBox>
|
||||
#include <QTreeView>
|
||||
#include <QTreeWidget>
|
||||
|
||||
#include "Qt/main.h"
|
||||
|
||||
class TimingConfDialog_t : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TimingConfDialog_t(QWidget *parent = 0);
|
||||
~TimingConfDialog_t(void);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
QCheckBox *emuPrioCtlEna;
|
||||
QComboBox *emuSchedPolicyBox;
|
||||
QSlider *emuSchedPrioSlider;
|
||||
QSlider *emuSchedNiceSlider;
|
||||
QLabel *emuSchedPrioLabel;
|
||||
QLabel *emuSchedNiceLabel;
|
||||
QComboBox *guiSchedPolicyBox;
|
||||
QSlider *guiSchedPrioSlider;
|
||||
QSlider *guiSchedNiceSlider;
|
||||
QLabel *guiSchedPrioLabel;
|
||||
QLabel *guiSchedNiceLabel;
|
||||
QComboBox *timingDevSelBox;
|
||||
|
||||
private:
|
||||
void updatePolicyBox(void);
|
||||
void updateSliderLimits(void);
|
||||
void updateSliderValues(void);
|
||||
void updateTimingMech(void);
|
||||
void saveValues(void);
|
||||
|
||||
public slots:
|
||||
void closeWindow(void);
|
||||
private slots:
|
||||
void emuSchedCtlChange( int state );
|
||||
void emuSchedNiceChange( int val );
|
||||
void emuSchedPrioChange( int val );
|
||||
void emuSchedPolicyChange( int index );
|
||||
void guiSchedNiceChange( int val );
|
||||
void guiSchedPrioChange( int val );
|
||||
void guiSchedPolicyChange( int index );
|
||||
void emuTimingMechChange( int index );
|
||||
|
||||
};
|
|
@ -315,6 +315,15 @@ InitConfig()
|
|||
config->addOption("_useNativeFileDialog", "SDL.UseNativeFileDialog", false);
|
||||
config->addOption("_useNativeMenuBar" , "SDL.UseNativeMenuBar", false);
|
||||
|
||||
config->addOption("_setSchedParam" , "SDL.SetSchedParam" , 0);
|
||||
config->addOption("_emuSchedPolicy" , "SDL.EmuSchedPolicy", 0);
|
||||
config->addOption("_emuSchedNice" , "SDL.EmuSchedNice" , 0);
|
||||
config->addOption("_emuSchedPrioRt" , "SDL.EmuSchedPrioRt", 40);
|
||||
config->addOption("_guiSchedPolicy" , "SDL.GuiSchedPolicy", 0);
|
||||
config->addOption("_guiSchedNice" , "SDL.GuiSchedNice" , 0);
|
||||
config->addOption("_guiSchedPrioRt" , "SDL.GuiSchedPrioRt", 40);
|
||||
config->addOption("_emuTimingMech" , "SDL.EmuTimingMech" , 0);
|
||||
|
||||
// fcm -> fm2 conversion
|
||||
config->addOption("fcmconvert", "SDL.FCMConvert", "");
|
||||
|
||||
|
|
|
@ -737,6 +737,15 @@ int fceuWrapperInit( int argc, char *argv[] )
|
|||
g_config->getOption("SDL.SubtitleDisplay", &id);
|
||||
movieSubtitles = id ? true : false;
|
||||
}
|
||||
|
||||
// Emulation Timing Mechanism
|
||||
{
|
||||
int timingMode;
|
||||
|
||||
g_config->getOption("SDL.EmuTimingMech", &timingMode);
|
||||
|
||||
setTimingMode( timingMode );
|
||||
}
|
||||
|
||||
// load the hotkeys from the config life
|
||||
setHotKeys();
|
||||
|
@ -958,13 +967,6 @@ FCEUD_Update(uint8 *XBuf,
|
|||
}
|
||||
else
|
||||
{
|
||||
//if (!NoWaiting && (!(eoptions&EO_NOTHROTTLE) || FCEUI_EmulationPaused()))
|
||||
//{
|
||||
// while (SpeedThrottle())
|
||||
// {
|
||||
// FCEUD_UpdateInput();
|
||||
// }
|
||||
//}
|
||||
if (XBuf && (inited&4))
|
||||
{
|
||||
BlitScreen(XBuf); blitDone = 1;
|
||||
|
|
|
@ -4,16 +4,112 @@
|
|||
#include "Qt/sdl.h"
|
||||
#include "Qt/throttle.h"
|
||||
|
||||
#if defined(__linux) || defined(__APPLE__)
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/timerfd.h>
|
||||
#endif
|
||||
|
||||
static const double Slowest = 0.015625; // 1/64x speed (around 1 fps on NTSC)
|
||||
static const double Fastest = 32; // 32x speed (around 1920 fps on NTSC)
|
||||
static const double Normal = 1.0; // 1x speed (around 60 fps on NTSC)
|
||||
|
||||
static uint64 Lasttime, Nexttime;
|
||||
static uint32 frameLateCounter = 0;
|
||||
static double Lasttime=0, Nexttime=0, Latetime=0;
|
||||
static double desired_frametime = (1.0 / 60.099823);
|
||||
static double frameDeltaMin = 99999.0;
|
||||
static double frameDeltaMax = 0.0;
|
||||
static bool keepFrameTimeStats = false;
|
||||
static int InFrame = 0;
|
||||
double g_fpsScale = Normal; // used by sdl.cpp
|
||||
bool MaxSpeed = false;
|
||||
|
||||
double getHighPrecTimeStamp(void)
|
||||
{
|
||||
#if defined(__linux) || defined(__APPLE__)
|
||||
struct timespec ts;
|
||||
double t;
|
||||
|
||||
clock_gettime( CLOCK_REALTIME, &ts );
|
||||
|
||||
t = (double)ts.tv_sec + (double)(ts.tv_nsec * 1.0e-9);
|
||||
#else
|
||||
double t;
|
||||
|
||||
t = (double)SDL_GetTicks();
|
||||
|
||||
t = t * 1e-3;
|
||||
#endif
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static char useTimerFD = 0;
|
||||
static int timerfd = -1;
|
||||
|
||||
static void setTimer( double hz )
|
||||
{
|
||||
struct itimerspec ispec;
|
||||
|
||||
if ( !useTimerFD )
|
||||
{
|
||||
if ( timerfd != -1 )
|
||||
{
|
||||
::close( timerfd ); timerfd = -1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( timerfd == -1 )
|
||||
{
|
||||
timerfd = timerfd_create( CLOCK_REALTIME, 0 );
|
||||
|
||||
if ( timerfd == -1 )
|
||||
{
|
||||
perror("timerfd_create failed: ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
ispec.it_interval.tv_sec = 0;
|
||||
ispec.it_interval.tv_nsec = (long)( 1.0e9 / hz );
|
||||
ispec.it_value.tv_sec = ispec.it_interval.tv_sec;
|
||||
ispec.it_value.tv_nsec = ispec.it_interval.tv_nsec;
|
||||
|
||||
if ( timerfd_settime( timerfd, 0, &ispec, NULL ) == -1 )
|
||||
{
|
||||
perror("timerfd_settime failed: ");
|
||||
}
|
||||
|
||||
//printf("Timer Set: %li ns\n", ispec.it_value.tv_nsec );
|
||||
|
||||
Lasttime = getHighPrecTimeStamp();
|
||||
Nexttime = Lasttime + desired_frametime;
|
||||
Latetime = Nexttime + desired_frametime;
|
||||
}
|
||||
#endif
|
||||
|
||||
int getTimingMode(void)
|
||||
{
|
||||
#ifdef __linux__
|
||||
if ( useTimerFD )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setTimingMode( int mode )
|
||||
{
|
||||
#ifdef __linux__
|
||||
useTimerFD = (mode == 1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LOGMUL = exp(log(2) / 3)
|
||||
*
|
||||
* This gives us a value such that if we do x*=LOGMUL three times,
|
||||
|
@ -28,7 +124,7 @@ bool MaxSpeed = false;
|
|||
* Refreshes the FPS throttling variables.
|
||||
*/
|
||||
void
|
||||
RefreshThrottleFPS()
|
||||
RefreshThrottleFPS(void)
|
||||
{
|
||||
double hz;
|
||||
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
|
||||
|
@ -47,37 +143,67 @@ RefreshThrottleFPS()
|
|||
Lasttime=0;
|
||||
Nexttime=0;
|
||||
InFrame=0;
|
||||
|
||||
#ifdef __linux__
|
||||
setTimer( hz * g_fpsScale );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int highPrecSleep( double timeSeconds )
|
||||
{
|
||||
int ret = 0;
|
||||
#if defined(__linux) || defined(__APPLE__)
|
||||
struct timespec req, rem;
|
||||
|
||||
req.tv_sec = (long)timeSeconds;
|
||||
req.tv_nsec = (long)((timeSeconds - (double)req.tv_sec) * 1e9);
|
||||
|
||||
ret = nanosleep( &req, &rem );
|
||||
#else
|
||||
SDL_Delay( (long)(time_left * 1e3) );
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform FPS speed throttling by delaying until the next time slot.
|
||||
*/
|
||||
int
|
||||
SpeedThrottle()
|
||||
SpeedThrottle(void)
|
||||
{
|
||||
if (g_fpsScale >= 32)
|
||||
{
|
||||
return 0; /* Done waiting */
|
||||
}
|
||||
uint64 time_left;
|
||||
uint64 cur_time;
|
||||
double time_left;
|
||||
double cur_time;
|
||||
double frame_time = desired_frametime;
|
||||
double quarterFrame = 0.250 * frame_time;
|
||||
|
||||
if (!Lasttime)
|
||||
cur_time = getHighPrecTimeStamp();
|
||||
|
||||
if (Lasttime < 1.0)
|
||||
{
|
||||
Lasttime = SDL_GetTicks();
|
||||
Lasttime = cur_time;
|
||||
Latetime = Lasttime + frame_time;
|
||||
}
|
||||
|
||||
if (!InFrame)
|
||||
{
|
||||
InFrame = 1;
|
||||
Nexttime = Lasttime + desired_frametime * 1000;
|
||||
Nexttime = Lasttime + frame_time;
|
||||
Latetime = Nexttime + frame_time;
|
||||
}
|
||||
|
||||
cur_time = SDL_GetTicks();
|
||||
if(cur_time >= Nexttime)
|
||||
if (cur_time >= Nexttime)
|
||||
{
|
||||
time_left = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
time_left = Nexttime - cur_time;
|
||||
}
|
||||
|
||||
if (time_left > 50)
|
||||
{
|
||||
|
@ -93,16 +219,81 @@ SpeedThrottle()
|
|||
//fprintf(stderr, "attempting to sleep %Ld ms, frame complete=%s\n",
|
||||
// time_left, InFrame?"no":"yes");
|
||||
|
||||
#ifdef __linux__
|
||||
if ( timerfd != -1 )
|
||||
{
|
||||
uint64_t val;
|
||||
|
||||
if ( read( timerfd, &val, sizeof(val) ) > 0 )
|
||||
{
|
||||
if ( val > 1 )
|
||||
{
|
||||
frameLateCounter += (val - 1);
|
||||
//printf("Late Frame: %u \n", frameLateCounter);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( time_left > 0 )
|
||||
{
|
||||
highPrecSleep( time_left );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( cur_time >= Latetime )
|
||||
{
|
||||
frameLateCounter++;
|
||||
//printf("Late Frame: %u - %llu ms\n", frameLateCounter, cur_time - Latetime);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if ( time_left > 0 )
|
||||
{
|
||||
SDL_Delay(time_left);
|
||||
highPrecSleep( time_left );
|
||||
}
|
||||
|
||||
if (!InFrame)
|
||||
else
|
||||
{
|
||||
Lasttime = SDL_GetTicks();
|
||||
if ( cur_time >= Latetime )
|
||||
{
|
||||
frameLateCounter++;
|
||||
//printf("Late Frame: %u - %llu ms\n", frameLateCounter, cur_time - Latetime);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
cur_time = getHighPrecTimeStamp();
|
||||
|
||||
if ( cur_time >= (Nexttime - quarterFrame) )
|
||||
{
|
||||
if ( keepFrameTimeStats )
|
||||
{
|
||||
double frameDelta;
|
||||
|
||||
frameDelta = (cur_time - Lasttime);
|
||||
|
||||
if ( frameDelta < frameDeltaMin )
|
||||
{
|
||||
frameDeltaMin = frameDelta;
|
||||
}
|
||||
if ( frameDelta > frameDeltaMax )
|
||||
{
|
||||
frameDeltaMax = frameDelta;
|
||||
}
|
||||
//printf("Frame Delta: %f us min:%f max:%f \n", frameDelta * 1e6, frameDeltaMin * 1e6, frameDeltaMax * 1e6 );
|
||||
//printf("Frame Sleep Time: %f Target Error: %f us\n", time_left * 1e6, (cur_time - Nexttime) * 1e6 );
|
||||
}
|
||||
Lasttime = Nexttime;
|
||||
Nexttime = Lasttime + frame_time;
|
||||
Latetime = Nexttime + frame_time;
|
||||
|
||||
if ( cur_time >= Nexttime )
|
||||
{
|
||||
Lasttime = cur_time;
|
||||
Nexttime = Lasttime + frame_time;
|
||||
Latetime = Nexttime + frame_time;
|
||||
}
|
||||
return 0; /* Done waiting */
|
||||
}
|
||||
|
||||
return 1; /* Must still wait some more */
|
||||
}
|
||||
|
||||
|
@ -113,7 +304,7 @@ void IncreaseEmulationSpeed(void)
|
|||
{
|
||||
g_fpsScale *= LOGMUL;
|
||||
|
||||
if(g_fpsScale > Fastest) g_fpsScale = Fastest;
|
||||
if (g_fpsScale > Fastest) g_fpsScale = Fastest;
|
||||
|
||||
RefreshThrottleFPS();
|
||||
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
void RefreshThrottleFPS();
|
||||
// throttle.h
|
||||
int SpeedThrottle(void);
|
||||
void RefreshThrottleFPS(void);
|
||||
int getTimingMode(void);
|
||||
int setTimingMode(int mode);
|
||||
|
|
Loading…
Reference in New Issue