diff --git a/src/drivers/Qt/sdl-throttle.cpp b/src/drivers/Qt/sdl-throttle.cpp index 5603eb6c..800ad121 100644 --- a/src/drivers/Qt/sdl-throttle.cpp +++ b/src/drivers/Qt/sdl-throttle.cpp @@ -37,7 +37,8 @@ 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 uint32 frameLateCounter = 0; -static double Lasttime=0, Nexttime=0, Latetime=0; +static FCEU::timeStampRecord Lasttime, Nexttime, Latetime; +static FCEU::timeStampRecord DesiredFrameTime, HalfFrameTime, QuarterFrameTime, DoubleFrameTime; static double desired_frametime = (1.0 / 60.099823); static double desired_frameRate = (60.099823); static double baseframeRate = (60.099823); @@ -119,9 +120,9 @@ static void setTimer( double hz ) //printf("Timer Set: %li ns\n", ispec.it_value.tv_nsec ); - Lasttime = getHighPrecTimeStamp(); - Nexttime = Lasttime + desired_frametime; - Latetime = Nexttime + (desired_frametime*0.50); + Lasttime.readNew(); + Nexttime = Lasttime + DesiredFrameTime; + Latetime = Nexttime + HalfFrameTime; } #endif @@ -270,10 +271,17 @@ RefreshThrottleFPS(void) if ( T < 0 ) T = 1; + DesiredFrameTime.fromSeconds( desired_frametime ); + HalfFrameTime = DesiredFrameTime / 2; + QuarterFrameTime = DesiredFrameTime / 4; + DoubleFrameTime = DesiredFrameTime * 2; + + //printf("FrameTime: %f %f %f %f \n", DesiredFrameTime.toSeconds(), + // HalfFrameTime.toSeconds(), QuarterFrameTime.toSeconds(), DoubleFrameTime.toSeconds() ); //printf("FrameTime: %llu %llu %f %lf \n", fps, fps >> 24, hz, desired_frametime ); - Lasttime=0; - Nexttime=0; + Lasttime.zero(); + Nexttime.zero(); InFrame=0; #ifdef __linux__ @@ -297,18 +305,17 @@ double getFrameRateAdjustmentRatio(void) return frmRateAdjRatio; } -int highPrecSleep( double timeSeconds ) +static int highPrecSleep( FCEU::timeStampRecord &ts ) { int ret = 0; #if defined(__linux__) || defined(__APPLE__) || defined(__unix__) struct timespec req, rem; - req.tv_sec = (long)timeSeconds; - req.tv_nsec = (long)((timeSeconds - (double)req.tv_sec) * 1e9); + req = ts.toTimeSpec(); ret = nanosleep( &req, &rem ); #else - SDL_Delay( (long)(timeSeconds * 1e3) ); + SDL_Delay( ts.toMilliSeconds() ); #endif return ret; } @@ -323,39 +330,37 @@ SpeedThrottle(void) { return 0; /* Done waiting */ } - double time_left; - double cur_time, idleStart; - double frame_time = desired_frametime; - double halfFrame = 0.500 * frame_time; - double quarterFrame = 0.250 * frame_time; + FCEU::timeStampRecord cur_time, idleStart, time_left; - idleStart = cur_time = getHighPrecTimeStamp(); + cur_time.readNew(); + idleStart = cur_time; - if (Lasttime < 1.0) + if (Lasttime.isZero()) { + //printf("Lasttime Reset\n"); Lasttime = cur_time; - Latetime = Lasttime + 2.0*frame_time; + Latetime = Lasttime + DoubleFrameTime; } if (!InFrame) { InFrame = 1; - Nexttime = Lasttime + frame_time; - Latetime = Nexttime + halfFrame; + Nexttime = Lasttime + DesiredFrameTime; + Latetime = Nexttime + HalfFrameTime; } if (cur_time >= Nexttime) { - time_left = 0; + time_left.zero(); } else { time_left = Nexttime - cur_time; } - if (time_left > 50) + if (time_left.toMilliSeconds() > 50) { - time_left = 50; + time_left.fromMilliSeconds(50); /* In order to keep input responsive, don't wait too long at once */ /* 50 ms wait gives us a 20 Hz responsetime which is nice. */ } @@ -381,7 +386,7 @@ SpeedThrottle(void) } } } - else if ( time_left > 0 ) + else if ( !time_left.isZero() ) { highPrecSleep( time_left ); } @@ -394,7 +399,7 @@ SpeedThrottle(void) } } #else - if ( time_left > 0 ) + if ( !time_left.isZero() ) { highPrecSleep( time_left ); } @@ -408,14 +413,15 @@ SpeedThrottle(void) } #endif - cur_time = getHighPrecTimeStamp(); + cur_time.readNew(); - if ( cur_time >= (Nexttime - quarterFrame) ) + if ( cur_time >= (Nexttime - QuarterFrameTime) ) { if ( keepFrameTimeStats ) { + FCEU::timeStampRecord diffTime = (cur_time - Lasttime); - frameDeltaCur = (cur_time - Lasttime); + frameDeltaCur = diffTime.toSeconds(); if ( frameDeltaCur < frameDeltaMin ) { @@ -426,7 +432,9 @@ SpeedThrottle(void) frameDeltaMax = frameDeltaCur; } - frameIdleCur = (cur_time - idleStart); + diffTime = (cur_time - idleStart); + + frameIdleCur = diffTime.toSeconds(); if ( frameIdleCur < frameIdleMin ) { @@ -440,14 +448,14 @@ SpeedThrottle(void) //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 + halfFrame; + Nexttime = Lasttime + DesiredFrameTime; + Latetime = Nexttime + HalfFrameTime; if ( cur_time >= Nexttime ) { Lasttime = cur_time; - Nexttime = Lasttime + frame_time; - Latetime = Nexttime + halfFrame; + Nexttime = Lasttime + DesiredFrameTime; + Latetime = Nexttime + HalfFrameTime; } return 0; /* Done waiting */ } diff --git a/src/utils/timeStamp.cpp b/src/utils/timeStamp.cpp index e8eff27b..b746fc5e 100644 --- a/src/utils/timeStamp.cpp +++ b/src/utils/timeStamp.cpp @@ -29,7 +29,7 @@ static uint64_t rdtsc() namespace FCEU { -uint64_t timeStampRecord::tscFreq = 0; +uint64_t timeStampRecord::_tscFreq = 0; #if defined(WIN32) uint64_t timeStampRecord::qpcFreq = 0; #endif @@ -63,16 +63,15 @@ static timeStampModule module; bool timeStampModuleInitialized(void) { - bool initialized = false; #if defined(WIN32) - initialized = timeStampRecord::qpcFreq != 0; + bool initialized = timeStampRecord::qpcFreq != 0; #else - initialized = true; + bool initialized = true; #endif return initialized; } -void timeStampModuleCalibrate(int numSamples) +void timeStampRecord::tscCalibrate(int numSamples) { timeStampRecord t1, t2, td; uint64_t td_sum = 0; @@ -102,10 +101,10 @@ void timeStampModuleCalibrate(int numSamples) td_avg = static_cast(td_sum); - timeStampRecord::tscFreq = static_cast( td_avg / td.toSeconds() ); + timeStampRecord::_tscFreq = static_cast( td_avg / td.toSeconds() ); printf("%i Calibration: %f sec TSC:%llu TSC Freq: %f MHz\n", i, td.toSeconds(), - static_cast(td.tsc), static_cast(timeStampRecord::tscFreq) * 1.0e-6 ); + static_cast(td.tsc), static_cast(timeStampRecord::_tscFreq) * 1.0e-6 ); } } diff --git a/src/utils/timeStamp.h b/src/utils/timeStamp.h index 497c1ab5..0ac67c42 100644 --- a/src/utils/timeStamp.h +++ b/src/utils/timeStamp.h @@ -9,11 +9,10 @@ namespace FCEU { - struct timeStampRecord + class timeStampRecord { + public: #if defined(__linux__) || defined(__APPLE__) || defined(__unix__) - struct timespec ts; - uint64_t tsc; timeStampRecord(void) { @@ -37,7 +36,7 @@ namespace FCEU if (ts.tv_nsec >= 1000000000) { ts.tv_nsec -= 1000000000; - ts.tv_sec++; + ts.tv_sec++; } tsc += op.tsc; return *this; @@ -53,7 +52,7 @@ namespace FCEU if (res.ts.tv_nsec >= 1000000000) { res.ts.tv_nsec -= 1000000000; - res.ts.tv_sec++; + res.ts.tv_sec++; } res.tsc = tsc + op.tsc; return res; @@ -76,30 +75,84 @@ namespace FCEU return res; } + timeStampRecord operator * (const unsigned int multiplier) + { + timeStampRecord res; + + res.ts.tv_sec = ts.tv_sec * multiplier; + res.ts.tv_nsec = ts.tv_nsec * multiplier; + + if (res.ts.tv_nsec >= 1000000000) + { + res.ts.tv_nsec -= 1000000000; + res.ts.tv_sec++; + } + res.tsc = tsc * multiplier; + + return res; + } + + timeStampRecord operator / (const unsigned int divisor) + { + timeStampRecord res; + + res.ts.tv_sec = ts.tv_sec / divisor; + res.ts.tv_nsec = ts.tv_nsec / divisor; + res.tsc = tsc / divisor; + + return res; + } + bool operator > (const timeStampRecord& op) { - bool res = false; + bool res; if (ts.tv_sec == op.ts.tv_sec) { res = (ts.tv_nsec > op.ts.tv_nsec); } - else if (ts.tv_sec > op.ts.tv_sec) + else { - res = true; + res = (ts.tv_sec > op.ts.tv_sec); + } + return res; + } + bool operator >= (const timeStampRecord& op) + { + bool res; + if (ts.tv_sec == op.ts.tv_sec) + { + res = (ts.tv_nsec >= op.ts.tv_nsec); + } + else + { + res = (ts.tv_sec >= op.ts.tv_sec); } return res; } bool operator < (const timeStampRecord& op) { - bool res = false; + bool res; if (ts.tv_sec == op.ts.tv_sec) { res = (ts.tv_nsec < op.ts.tv_nsec); } - else if (ts.tv_sec < op.ts.tv_sec) + else { - res = true; + res = (ts.tv_sec < op.ts.tv_sec); + } + return res; + } + bool operator <= (const timeStampRecord& op) + { + bool res; + if (ts.tv_sec == op.ts.tv_sec) + { + res = (ts.tv_nsec <= op.ts.tv_nsec); + } + else + { + res = (ts.tv_sec <= op.ts.tv_sec); } return res; } @@ -111,6 +164,11 @@ namespace FCEU tsc = 0; } + bool isZero(void) + { + return (ts.tv_sec == 0) && (ts.tv_nsec == 0); + } + void fromSeconds(unsigned int sec) { ts.tv_sec = sec; @@ -118,12 +176,33 @@ namespace FCEU tsc = 0; } + void fromSeconds(double sec) + { + double ns; + ts.tv_sec = static_cast(sec); + ns = (sec - static_cast(ts.tv_sec)) * 1.0e9; + ts.tv_nsec = static_cast(ns); + tsc = 0; + } + double toSeconds(void) { double sec = static_cast(ts.tv_sec) + ( static_cast(ts.tv_nsec) * 1.0e-9 ); return sec; } + void fromMilliSeconds(uint64_t ms) + { + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms * 1000000) - (ts.tv_sec * 1000000000); + } + + uint64_t toMilliSeconds(void) + { + uint64_t ms = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000 ); + return ms; + } + uint64_t toCounts(void) { return (ts.tv_sec * 1000000000) + ts.tv_nsec; @@ -133,9 +212,12 @@ namespace FCEU { return 1000000000; } + + struct timespec toTimeSpec(void) + { + return ts; + } #else // WIN32 - uint64_t ts; - uint64_t tsc; timeStampRecord(void) { @@ -176,15 +258,43 @@ namespace FCEU return res; } + timeStampRecord operator * (const unsigned int multiplier) + { + timeStampRecord res; + + res.ts = ts * multiplier; + res.tsc = tsc * multiplier; + + return res; + } + + timeStampRecord operator / (const unsigned int divisor) + { + timeStampRecord res; + + res.ts = ts / divisor; + res.tsc = tsc / divisor; + + return res; + } + bool operator > (const timeStampRecord& op) { return ts > op.ts; } + bool operator >= (const timeStampRecord& op) + { + return ts >= op.ts; + } bool operator < (const timeStampRecord& op) { return ts < op.ts; } + bool operator <= (const timeStampRecord& op) + { + return ts <= op.ts; + } void zero(void) { @@ -192,18 +302,41 @@ namespace FCEU tsc = 0; } + bool isZero(void) + { + return (ts == 0); + } + + void fromSeconds(unsigned int sec) { ts = sec * qpcFreq; tsc = 0; } + void fromSeconds(double sec) + { + ts = static_cast(sec * static_cast(qpcFreq)); + tsc = 0; + } + double toSeconds(void) { double sec = static_cast(ts) / static_cast(qpcFreq); return sec; } + void fromMilliSeconds(uint64_t ms) + { + ts = (ms * qpcFreq) / 1000; + } + + uint64_t toMilliSeconds(void) + { + uint64_t ms = (ts * 1000) / qpcFreq; + return ms; + } + uint64_t toCounts(void) { return ts; @@ -213,19 +346,33 @@ namespace FCEU { return qpcFreq; } - static uint64_t qpcFreq; #endif - static uint64_t tscFreq; + uint64_t getTSC(void){ return tsc; }; + + static uint64_t tscFreq(void) + { + return _tscFreq; + } static bool tscValid(void){ return tscFreq != 0; }; + // Call this function to calibrate the estimated TSC frequency + static void tscCalibrate(int numSamples = 0); + void readNew(void); + + private: +#if defined(__linux__) || defined(__APPLE__) || defined(__unix__) + struct timespec ts; +#else // Win32 + uint64_t ts; + static uint64_t qpcFreq; +#endif + uint64_t tsc; + static uint64_t _tscFreq; }; bool timeStampModuleInitialized(void); - // Call this function to calibrate the estimated TSC frequency - void timeStampModuleCalibrate(int numSamples = 1); - } // namespace FCEU