diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 74382718..82db5765 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index e7bc92f4..1078b838 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -36,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" @@ -415,6 +416,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"))); @@ -1263,6 +1272,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; @@ -1924,105 +1944,8 @@ emulatorThread_t::emulatorThread_t(void) #endif -void emulatorThread_t::setPriority( QThread::Priority priority_req ) +void emulatorThread_t::init(void) { - printf("New Priority: %i \n", priority_req ); - printf("Old Priority: %i \n", priority() ); - - //QThread::setPriority( priority_req ); - - printf("Set Priority: %i \n", priority() ); - -#if defined(__linux__) - struct sched_param p; - int oldPolicy, newPolicy, minPrio, maxPrio; - - newPolicy = SCHED_FIFO; - - minPrio = sched_get_priority_min( SCHED_FIFO ); - maxPrio = sched_get_priority_max( SCHED_FIFO ); - - pthread_getschedparam( pself, &oldPolicy, &p ); - - printf("pthread_getschedparam(): %i, %i \n", oldPolicy, p.sched_priority ); - - p.sched_priority = maxPrio; - - if ( ::pthread_setschedparam( pself, newPolicy, &p ) != 0 ) - { - perror("Emulator thread pthread_setschedparam error: "); - } - - if ( ::setpriority( PRIO_PROCESS, gettid(), -20 ) ) - { - perror("Emulator thread setpriority error: "); - } - printf("sched_getscheduler(): %i \n", sched_getscheduler( getpid() ) ); - printf("sched_get_priority_min(SCHED_FIFO): %i \n", minPrio ); - printf("sched_get_priority_max(SCHED_FIFO): %i \n", maxPrio ); - - printf("setpriority(): %i \n", ::getpriority( PRIO_PROCESS, getpid() ) ); - - //if ( sched_setscheduler( getpid(), SCHED_FIFO, &p ) ) - //{ - // perror("Emulator thread sched_setscheduler error:"); - //} - printf("sched_getscheduler(): %i \n", sched_getscheduler( getpid() ) ); - - pthread_getschedparam( pself, &oldPolicy, &p ); - - printf("pthread_getschedparam(): %i, %i \n", oldPolicy, p.sched_priority ); -#elif defined(__APPLE__) - struct sched_param p; - int oldPolicy, newPolicy, minPrio, maxPrio; - - newPolicy = SCHED_FIFO; - - if ( ::setpriority( PRIO_PROCESS, getpid(), -20 ) ) - { - perror("Emulator thread setpriority error: "); - } - printf("EMU setpriority(): %i \n", ::getpriority( PRIO_PROCESS, getpid() ) ); - - minPrio = sched_get_priority_min( SCHED_FIFO ); - maxPrio = sched_get_priority_max( SCHED_FIFO ); - - printf("sched_get_priority_min(SCHED_FIFO): %i \n", minPrio ); - printf("sched_get_priority_max(SCHED_FIFO): %i \n", maxPrio ); - - pthread_getschedparam( pself, &oldPolicy, &p ); - - printf("EMU pthread_getschedparam(): %i, %i \n", oldPolicy, p.sched_priority ); - - //for (int i=0; i<7; i++) - //{ - // QThread::setPriority( (QThread::Priority)i); - - // pthread_getschedparam( pself, &oldPolicy, &p ); - - // printf("%i: EMU pthread_getschedparam(): %i, %i \n", i, oldPolicy, p.sched_priority ); - //} - - p.sched_priority = maxPrio; - - if ( ::pthread_setschedparam( pself, newPolicy, &p ) != 0 ) - { - perror("Emulator thread pthread_setschedparam error: "); - } - - pthread_getschedparam( pself, &oldPolicy, &p ); - - printf("EMU pthread_getschedparam(): %i, %i \n", oldPolicy, p.sched_priority ); - - -#endif -} - -void emulatorThread_t::run(void) -{ - printf("Emulator Start\n"); - nes_shm->runEmulator = 1; - #if defined(__linux__) || defined(__APPLE__) if ( pthread_self() == (pthread_t)QThread::currentThreadId() ) { @@ -2031,7 +1954,160 @@ void emulatorThread_t::run(void) } #endif - setPriority( QThread::TimeCriticalPriority ); + #if defined(__linux__) + pid = gettid(); + #elif defined(__APPLE__) + pid = getpid(); + #endif +} + +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; + } + 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(); + + //setPriority( QThread::TimeCriticalPriority ); while ( nes_shm->runEmulator ) { diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index e7494bc8..88b9e631 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -36,9 +36,20 @@ class emulatorThread_t : public QThread 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: @@ -66,6 +77,8 @@ class consoleWin_t : public QMainWindow void setPriority( QThread::Priority priority_req ); + emulatorThread_t *emulatorThread; + protected: QMenu *fileMenu; QMenu *optMenu; @@ -91,6 +104,7 @@ class consoleWin_t : public QMainWindow QAction *hotkeyConfig; QAction *paletteConfig; QAction *guiConfig; + QAction *timingConfig; QAction *movieConfig; QAction *autoResume; QAction *fullscreen; @@ -125,8 +139,6 @@ class consoleWin_t : public QMainWindow QTimer *gameTimer; - emulatorThread_t *emulatorThread; - std::string errorMsg; bool errorMsgValid; @@ -161,6 +173,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); diff --git a/src/drivers/Qt/TimingConf.cpp b/src/drivers/Qt/TimingConf.cpp new file mode 100644 index 00000000..96cdaa9a --- /dev/null +++ b/src/drivers/Qt/TimingConf.cpp @@ -0,0 +1,196 @@ +// TimingConf.cpp +// +#include +#include +#include +#include + +#include +#include +#include + +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" +#include "Qt/ConsoleWindow.h" +#include "Qt/TimingConf.h" + +//---------------------------------------------------------------------------- +TimingConfDialog_t::TimingConfDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QVBoxLayout *mainLayout, *vbox; + QHBoxLayout *hbox; + QGridLayout *grid; + QGroupBox *emuPrioBox; + + setWindowTitle("Timing Configuration"); + + mainLayout = new QVBoxLayout(); + + emuPrioCtlEna = new QCheckBox( tr("Set Scheduling Parameters at Startup") ); + + emuPrioBox = new QGroupBox( tr("EMU 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)") ); + + 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( new QLabel( tr("Priority (Nice)") ), 2, 0 ); + grid->addWidget( emuSchedNiceSlider, 2, 1 ); + + mainLayout->addWidget( emuPrioCtlEna ); + mainLayout->addWidget( emuPrioBox ); + + setLayout( mainLayout ); + + updatePolicyBox(); + updateSliderLimits(); + updateSliderValues(); + + 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)) ); +} +//---------------------------------------------------------------------------- +TimingConfDialog_t::~TimingConfDialog_t(void) +{ + printf("Destroy Timing Config Window\n"); +} +//---------------------------------------------------------------------------- +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::emuSchedNiceChange(int val) +{ + if ( consoleWindow == NULL ) + { + return; + } + if ( consoleWindow->emulatorThread->setNicePriority( -val ) ) + { + printf("Set Nice Failed\n"); + } +} +//---------------------------------------------------------------------------- +void TimingConfDialog_t::emuSchedPrioChange(int val) +{ + int policy, prio; + + if ( consoleWindow == NULL ) + { + return; + } + consoleWindow->emulatorThread->getSchedParam( policy, prio ); + + if ( consoleWindow->emulatorThread->setSchedParam( policy, val ) ) + { + printf("Set setSchedParam Failed\n"); + } +} +//---------------------------------------------------------------------------- +void TimingConfDialog_t::emuSchedPolicyChange( int index ) +{ + int policy, prio; + + if ( consoleWindow == NULL ) + { + return; + } + consoleWindow->emulatorThread->getSchedParam( policy, prio ); + + policy = emuSchedPolicyBox->itemData( index ).toInt(); + + consoleWindow->emulatorThread->setSchedParam( policy, prio ); + + updatePolicyBox(); + updateSliderLimits(); + updateSliderValues(); +} +//---------------------------------------------------------------------------- +void TimingConfDialog_t::updatePolicyBox(void) +{ + int policy, prio; + + if ( consoleWindow == NULL ) + { + return; + } + consoleWindow->emulatorThread->getSchedParam( policy, prio ); + + for (int j=0; jcount(); j++) + { + if ( emuSchedPolicyBox->itemData(j).toInt() == policy ) + { + //printf("Found Policy %i %i\n", j , policy ); + emuSchedPolicyBox->setCurrentIndex( j ); + } + } + +} +//---------------------------------------------------------------------------- +void TimingConfDialog_t::updateSliderValues(void) +{ + int policy, prio; + + 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); + } +} +//---------------------------------------------------------------------------- +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() ); + +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/TimingConf.h b/src/drivers/Qt/TimingConf.h new file mode 100644 index 00000000..d6d8a23b --- /dev/null +++ b/src/drivers/Qt/TimingConf.h @@ -0,0 +1,51 @@ +// TimingConf.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + + private: + void updatePolicyBox(void); + void updateSliderLimits(void); + void updateSliderValues(void); + + public slots: + void closeWindow(void); + private slots: + void emuSchedNiceChange( int val ); + void emuSchedPrioChange( int val ); + void emuSchedPolicyChange( int index ); + +};