不知道有没有标准的方法,但这是我用过的方法。
简而言之,为你的帧率确定一个间隔周期,并根据这个间隔提前一个虚拟时钟。每一帧,确定完成“工作”所需的时间。从帧间隔中减去工作时间可以告诉您需要多长时间才能达到下一个间隔。
这本身将提供“每秒滴答 N 次不倾斜”。它是自我纠正的,所以如果你偶尔落后,它会在工作量较轻的时候加速,直到赶上。
如果要调整帧速率以匹配工作负载,只需检查空闲时间并相应地调整间隔。
代码是一个演示这一点的小程序。它运行在 Linux 上,我不知道 OS X。我选择了 1/2 秒的间隔,因为你可以观察它的运行情况,看看时间是否流畅。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
/* frame interval is in microseconds */
#define INTERVAL 500000
/* use a variable so it is adjustable */
int interval = INTERVAL;
int ideal = 0;
struct timeval start; /* start time */
void init_time()
{
gettimeofday(&start, 0);
wait((1000000 - start.tv_usec));
gettimeofday(&start, 0);
ideal = start.tv_usec; /* initialize ideal time */
}
int get_time()
{
struct timeval tv;
gettimeofday(&tv, 0);
tv.tv_sec -= start.tv_sec; /* normalize to start time */
int usec = (tv.tv_sec * 1000000) + (tv.tv_usec);
return usec;
}
int wait(int usec)
{
struct timespec ts = { 0, usec * 1000 };
if (nanosleep(&ts, 0) != 0) {
printf("ERROR: nanosleep interrupted\n");
}
}
void dowork()
{
wait((rand() % 5) * 100000); /* simulated workload */
}
void frame()
{
dowork(); /* do your per-frame work here */
int actual = get_time();
int work_time = actual - ideal; /* elapsed time in dowork() */
int idle_time = interval - work_time; /* idle delay to next frame */
#ifdef ENABLE_VARIABLE
if (idle_time < 0) {
/* OPTIONAL: slow frame rate 10% if falling behind */
interval -= idle_time;
} else if (interval > INTERVAL) {
/* OPTIONAL: if we slowed down, but now we have idle time, increase
* rate 10% until we get to our original target rate */
interval -= (interval - INTERVAL)/10;
}
#endif
if (idle_time > 0) {
/* sleep for the idle period */
wait(idle_time);
}
printf("FRAME: time %10d (work %10d, idle %10d)\n",
ideal, work_time, idle_time);
ideal = ideal + interval;
}
void main()
{
int i;
init_time();
/* simulate 50 frames */
for (i=0; i<50; i++)
frame();
}