Cocoa Port:

- Throttle execution speed using mach_wait_until() instead of usleep(). This improves execution timing, and reduces screen tearing when running the video at >= 60FPS.
- Improve thread safety when changing the execution speed.
- Do some miscellaneous minor optimizations to the execution loop and frame skip.
This commit is contained in:
rogerman 2012-03-13 01:59:32 +00:00
parent 7ae952f366
commit f6f1678eca
2 changed files with 20 additions and 20 deletions

View File

@ -120,5 +120,5 @@ typedef struct
@end @end
void* RunCoreThread(void *arg); static void* RunCoreThread(void *arg);
void CoreFrameSkip(uint64_t timeBudgetMachAbsoluteTime, uint64_t frameStartMachAbsoluteTime, unsigned int *outFramesToSkip); static void CoreFrameSkip(uint64_t timeBudgetMachAbsoluteTime, uint64_t frameStartMachAbsoluteTime, unsigned int *outFramesToSkip);

View File

@ -642,23 +642,25 @@ static BOOL isCoreStarted = NO;
@end @end
void* RunCoreThread(void *arg) static void* RunCoreThread(void *arg)
{ {
CoreThreadParam *param = (CoreThreadParam *)arg; CoreThreadParam *param = (CoreThreadParam *)arg;
CocoaDSCore *cdsCore = (CocoaDSCore *)param->cdsCore; CocoaDSCore *cdsCore = (CocoaDSCore *)param->cdsCore;
NSMutableArray *cdsOutputList = [cdsCore cdsOutputList]; NSMutableArray *cdsOutputList = [cdsCore cdsOutputList];
uint64_t startTime = 0; uint64_t startTime = 0;
uint64_t elapsedMachAbsTime; uint64_t timeBudget = 0; // Need local variable to ensure that param->timeBudgetMachAbsTime is thread-safe.
do do
{ {
startTime = mach_absolute_time(); startTime = mach_absolute_time();
pthread_mutex_lock(&param->mutexThreadExecute); pthread_mutex_lock(&param->mutexThreadExecute);
timeBudget = param->timeBudgetMachAbsTime;
while (!(param->state == CORESTATE_EXECUTE && execute && !param->exitThread)) while (!(param->state == CORESTATE_EXECUTE && execute && !param->exitThread))
{ {
pthread_cond_wait(&param->condThreadExecute, &param->mutexThreadExecute); pthread_cond_wait(&param->condThreadExecute, &param->mutexThreadExecute);
startTime = mach_absolute_time(); startTime = mach_absolute_time();
timeBudget = param->timeBudgetMachAbsTime;
} }
if (param->exitThread) if (param->exitThread)
@ -708,20 +710,15 @@ void* RunCoreThread(void *arg)
// we owe on timeBudget. // we owe on timeBudget.
if (param->isFrameSkipEnabled) if (param->isFrameSkipEnabled)
{ {
CoreFrameSkip(param->timeBudgetMachAbsTime, startTime, &param->framesToSkip); CoreFrameSkip(timeBudget, startTime, &param->framesToSkip);
} }
// If there is any time left in the loop, go ahead and pad it.
elapsedMachAbsTime = mach_absolute_time() - startTime;
pthread_mutex_unlock(&param->mutexThreadExecute); pthread_mutex_unlock(&param->mutexThreadExecute);
if(param->timeBudgetMachAbsTime > elapsedMachAbsTime) // If there is any time left in the loop, go ahead and pad it.
if(timeBudget > (mach_absolute_time() - startTime))
{ {
uint64_t padMachAbsTime = param->timeBudgetMachAbsTime - elapsedMachAbsTime; mach_wait_until(startTime + timeBudget);
Nanoseconds padNanoseconds = AbsoluteToNanoseconds(*(AbsoluteTime *)&padMachAbsTime);
useconds_t padMicroseconds = (useconds_t)(*(uint64_t *)&padNanoseconds / 1000);
usleep(padMicroseconds);
} }
} while (!param->exitThread); } while (!param->exitThread);
@ -729,10 +726,8 @@ void* RunCoreThread(void *arg)
return nil; return nil;
} }
void CoreFrameSkip(uint64_t timeBudgetMachAbsTime, uint64_t frameStartMachAbsTime, unsigned int *outFramesToSkip) static void CoreFrameSkip(uint64_t timeBudgetMachAbsTime, uint64_t frameStartMachAbsTime, unsigned int *outFramesToSkip)
{ {
static unsigned int lastSetFrameSkip = 0;
if (*outFramesToSkip > 0) if (*outFramesToSkip > 0)
{ {
NDS_SkipNextFrame(); NDS_SkipNextFrame();
@ -740,13 +735,14 @@ void CoreFrameSkip(uint64_t timeBudgetMachAbsTime, uint64_t frameStartMachAbsTim
} }
else else
{ {
unsigned int framesToSkip = 0;
// Calculate the time remaining. // Calculate the time remaining.
uint64_t elapsed = mach_absolute_time() - frameStartMachAbsTime; uint64_t elapsed = mach_absolute_time() - frameStartMachAbsTime;
if (elapsed > timeBudgetMachAbsTime) if (elapsed > timeBudgetMachAbsTime)
{ {
static unsigned int lastSetFrameSkip = 0;
unsigned int framesToSkip = 0;
if (timeBudgetMachAbsTime > 0) if (timeBudgetMachAbsTime > 0)
{ {
framesToSkip = (unsigned int)( (((double)(elapsed - timeBudgetMachAbsTime) * FRAME_SKIP_AGGRESSIVENESS) / (double)timeBudgetMachAbsTime) + FRAME_SKIP_BIAS ); framesToSkip = (unsigned int)( (((double)(elapsed - timeBudgetMachAbsTime) * FRAME_SKIP_AGGRESSIVENESS) / (double)timeBudgetMachAbsTime) + FRAME_SKIP_BIAS );
@ -770,8 +766,12 @@ void CoreFrameSkip(uint64_t timeBudgetMachAbsTime, uint64_t frameStartMachAbsTim
framesToSkip = (unsigned int)MAX_FRAME_SKIP; framesToSkip = (unsigned int)MAX_FRAME_SKIP;
lastSetFrameSkip = framesToSkip; lastSetFrameSkip = framesToSkip;
} }
*outFramesToSkip = framesToSkip;
}
else
{
*outFramesToSkip = 0;
} }
*outFramesToSkip = framesToSkip;
} }
} }