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:
parent
7ae952f366
commit
f6f1678eca
|
@ -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);
|
||||||
|
|
|
@ -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(¶m->mutexThreadExecute);
|
pthread_mutex_lock(¶m->mutexThreadExecute);
|
||||||
|
timeBudget = param->timeBudgetMachAbsTime;
|
||||||
|
|
||||||
while (!(param->state == CORESTATE_EXECUTE && execute && !param->exitThread))
|
while (!(param->state == CORESTATE_EXECUTE && execute && !param->exitThread))
|
||||||
{
|
{
|
||||||
pthread_cond_wait(¶m->condThreadExecute, ¶m->mutexThreadExecute);
|
pthread_cond_wait(¶m->condThreadExecute, ¶m->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, ¶m->framesToSkip);
|
CoreFrameSkip(timeBudget, startTime, ¶m->framesToSkip);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is any time left in the loop, go ahead and pad it.
|
|
||||||
elapsedMachAbsTime = mach_absolute_time() - startTime;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(¶m->mutexThreadExecute);
|
pthread_mutex_unlock(¶m->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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue