Objective c 呈现Renderbuffer时,是什么导致执行时间波动?(OpenGL)
情况就是这样:Objective c 呈现Renderbuffer时,是什么导致执行时间波动?(OpenGL),objective-c,opengl-es,timing,Objective C,Opengl Es,Timing,情况就是这样: 根据建议,由于使用了usleep,drawGL函数将在帧的精确末尾调用。这已经保持了稳定的帧速率 renderbuffer的实际演示使用drawGL()进行。测量执行此操作所需的时间,会给我波动的执行时间,导致动画中出现口吃。此计时器使用马赫绝对时间,因此非常精确 在帧的末尾,我测量时差。是的,它的平均值为1毫秒,但它的偏差很大,从0.8毫秒到1.2毫秒不等,峰值可达2毫秒以上 例如: 我的理解是,一旦创建了帧缓冲区,无论帧的复杂程度如何,呈现renderbuffer都应该付
- 根据建议,由于使用了
,drawGL函数将在帧的精确末尾调用。这已经保持了稳定的帧速率usleep
- renderbuffer的实际演示使用
进行。测量执行此操作所需的时间,会给我波动的执行时间,导致动画中出现口吃。此计时器使用马赫绝对时间,因此非常精确drawGL()
- 在帧的末尾,我测量
。是的,它的平均值为1毫秒,但它的偏差很大,从0.8毫秒到1.2毫秒不等,峰值可达2毫秒以上时差
顺便说一下,这是iPhone应用程序的一个例子。所以我们在这里讨论的是OpenGL ES,尽管我不认为这是一个特定于平台的问题。如果是,那么发生了什么?这不应该发生吗?同样,如果是这样的话,我怎样才能防止这种情况发生呢?您遇到的偏差可能是由许多因素造成的,包括操作系统调度程序启动并将cpu分配给另一个进程或类似问题。事实上,正常人看不出1毫秒和2毫秒的渲染时间有什么区别。电影以每秒25帧的速度运行,这意味着每一帧的显示时间约为40毫秒,人眼看起来很流畅 对于动画口吃,您应该检查如何保持恒定的动画速度。我见过的最常见的方法大致如下:
while(loop)
{
lastFrameTime; // time it took for last frame to render
timeSinceLastUpdate+= lastFrameTime;
if(timeSinceLastUpdate > (1 second / DESIRED_UPDATES_PER_SECOND))
{
updateAnimation(timeSinceLastUpdate);
timeSinceLastUpdate = 0;
}
// do the drawing
presentScene();
}
或者,您可以将lastFrameTime传递给每一帧更新动画,并在动画状态之间进行插值。结果将更加流畅
如果您已经在使用类似于上面的内容,那么可能应该在渲染循环的其他部分查找罪魁祸首。在Direct3D中,代价高昂的事情是调用绘制原语和更改渲染状态,因此您可能需要查看OpenGL的类似情况。出于许多原因,最好不要依赖高恒定帧速率,最重要的是操作系统可能会在后台做一些减慢速度的事情。最好对计时器进行采样并计算出每帧经过了多少时间,这样可以确保动画流畅。即使计时器返回的是小数0.8->2.0,计时器是否可能不精确到亚毫秒级?我最喜欢的OpenGL表达式:“特定于实现”。我认为它在这里非常适用。快速搜索马赫绝对时间可在本文中找到: 看起来iPhone上计时器的精度只有166.67纳秒(甚至更糟)。 虽然这可能解释了巨大的差异,但根本不能解释存在差异 三个主要原因可能是:
- renderbuffer演示期间的不同执行路径。1ms内可能会发生很多事情,仅仅因为使用相同的参数调用相同的函数并不意味着执行完全相同的指令。如果涉及到其他硬件,尤其如此
- 中断/其他进程时,总有其他事情会分散CPU的注意力。据我所知,iPhone操作系统不是实时操作系统,因此无法保证任何操作都能在一定的时间限制内完成(即使是实时操作系统也会有时间变化)
- 如果GPU仍在处理任何其他OpenGL调用,则可能会延迟presentRenderbuffer。这是最容易测试的,只需在获取开始时间之前调用glFinish()
while(loop)
{
lastFrameTime; // time it took for last frame to render
timeSinceLastUpdate+= lastFrameTime;
if(timeSinceLastUpdate > (1 second / DESIRED_UPDATES_PER_SECOND))
{
updateAnimation(timeSinceLastUpdate);
timeSinceLastUpdate = 0;
}
// do the drawing
presentScene();
}