有效的帧限制

时间:2013-09-15 06:11:47

标签: c++ sleep

我有一个模拟,我试图转换为“实时”。我说“实时”,因为如果需要它可以在性能下降(观察者/客户也减慢了时间)。但是,如果有少量对象,我想限制性能,使其以稳定的帧速率运行(在这种情况下约为100 FPS)。

我分别为linux和windows试过了sleep()Sleep()但它似乎不够准确,因为FPS 真的下降到了我的一小部分把目标放在。我认为这种情况在游戏中很常见,特别是在线游戏,但我无法找到有关该主题的任何有用的材料。框架限制的首选方式是什么?是否有睡眠方法可以保证它不会放弃比指定时间更多的时间?

注意:我在两个不同的群集(Linux和Windows)上运行它,所有节点只有内置视频。所以我必须在两个平台上实现限制,它不应该是基于视频卡的(如果有这样的话)。我还需要在一个线程/节点上实现限制,因为节点之间已经存在同步,如果一个线程被适当限制,其他节点将自动受限。

编辑:一些伪代码,显示我如何实现当前限制器:

while (ProcessControlMessages())
{
    uint64 tStart;
    SimulateFrame();
    uint64 newT =_context.GetTimeMs64();
    if (newT - tStart < DESIRED_FRAME_RATE_DURATION)
        this_thread::sleep_for(chrono::milliseconds(DESIRED_FRAME_RATE_DURATION - (newT - tStart)));
}

我还在考虑是否可以对每N帧进行限制,其中N是所需帧速率的一部分。我会试一试并报告。

2 个答案:

答案 0 :(得分:2)

对于游戏,帧限制器通常不足。相反,更新游戏状态的方法(在您的情况下为SimulateFrame())保持帧速率独立。例如。如果要移动对象,则实际偏移量是对象的速度乘以最后一帧的持续时间。同样,您可以对所有类型的计算执行此操作。

这种方法的优点是用户在保持实时性的同时获得最大帧速率。但是,您应该注意帧持续时间不会太小(<1 ms)。这可能导致计算不准确。在这种情况下,具有固定持续时间的小sleep可能有所帮助。

这就是游戏通常如何处理这个问题。你必须检查你的模拟是否适合这种技术。

答案 1 :(得分:1)

不要让每个帧试图长时间睡眠成为一个完整的帧,让他们睡觉以试图平均。保持全局/线程拥有的时间计数。对于每个帧都有一个&#34;期望的最早结束时间,&#34;从先前期望的最早结束时间计算,而不是从当前时间计算

tGoalEndTime = _context.GetTimeMS64() + DESIRED_FRAME_RATE_DURATION;
while (ProcessControlMessages())
{
    SimulateFrame();
    uint64 end =_context.GetTimeMs64();
    if (end < tGoalEndTime) {
        this_thread::sleep_for(chrono::milliseconds(tGoalEndTime - end)));
        tGoalEndTime += DESIRED_FRAME_RATE_DURATION;
    } else {
        tGoalEndTime = end; // we ran over, pretend we didn't and keep going
}

注意:这会使用您的示例sleep_for,因为我想显示实现它的最小更改次数。 sleep_until在这里效果更好。

诀窍是,任何睡眠时间过长的帧都会导致接下来的几帧急于赶上。

注意:在现代消费类操作系统上,您无法在2ms内(100fps上20%抖动)获得任何时序。大多数消费者操作系统上的线程量大约为100毫秒,所以在你睡觉的那一刻,你可以在轮到你之前睡多个量子。 sleep_until 可能使用特定于操作系统的技术来减少抖动,但您无法依赖它。