背景介绍
帧率统计常用于游戏限帧,视频音画同步等地方。是时间类组件的重要部分。
基本思路
1.2幂长度的环形缓存区能便于计算。 2.每帧采样并计算帧间间隔填入缓存区。 3.每帧都利用统计的帧缓冲计算平均帧率。
使用这种方式,每一帧都能得到正确的平均帧率,仅计算进出缓冲的时间间隔效率高。
1.最终使用案例
https://bitbucket.org/mm_longcheng/mm-core/src/dev/mm/src/core/mmFrameStats.h
static void MyTestFrameStats(void)
{
int i;
struct mmFrameStats stats;
mmFrameStats_Init(&stats);
// 可选,设置初始帧率
mmFrameStats_SetAverage(&stats, 60.0);
for (i = 0; i < 60; i++)
{
// 休眠一段时间
mmMSleep(16);
// 更新帧率统计
mmFrameStats_Update(&stats);
}
mmFrameStats_Destroy(&stats);
}
2.前置数据结构组件
// 每秒的毫秒数
#define MM_USEC_PER_SEC 1000000
// 秒表,用来计时
struct mmClock;
3.主要数据结构
enum
{
// [0x00, 0xFF] 0x40 = 64 .
// Very close to the commonly used 60 frame rate.
mmFrameStatsCacheSize = 0x40,
mmFrameStatsCacheMask = mmFrameStatsCacheSize - 1,
mmFrameStatsCacheTime = mmFrameStatsCacheSize * MM_USEC_PER_SEC,
};
// Frame rate statistics based on circular queues
struct mmFrameStats
{
// time clock.
struct mmClock clock;
// frame number, reset api can assign 0.
mmUInt64_t number;
// average fps.
double average;
// current frame interval.
double interval;
// frame interval total.
double total;
// frame interval cache.
double cache[mmFrameStatsCacheSize];
// cache index.
mmUInt8_t index;
};
4.主要处理函数
MM_EXPORT_DLL void mmFrameStats_UpdateInterval(struct mmFrameStats* p, double interval)
{
// cache the last frame interval.
p->interval = interval;
// accumulate the frame number.
p->number++;
// sub the index cache interval.
p->total -= p->cache[p->index];
// insert to back current interval.
p->cache[p->index] = interval;
// add the current interval.
p->total += interval;
// index++
p->index++;
// index %= CacheSize
p->index &= mmFrameStatsCacheMask;
// fps value update.
// if total == 0.0 the fps_avge will be +inf, but it's correct.
p->average = ((double)mmFrameStatsCacheTime) / p->total;
}
5.原理
更新时间时,我们仅减掉出队的间隔时间,加上进队的间隔时间,然后求平均,能避免遍历反复累加全体时间缓冲。利用2幂的特性,我们使用位操作可以快速回环索引,避免求余操作。
|