我在OSX上制作一个简单的图形应用程序。我刚开始通过检查帧之间系统时间的差异来监视帧速率。它似乎每隔几帧悬挂一下。
该应用程序在NSTimer对象上运行,目前设置为200 fps(5毫秒帧)。为了确保它不仅仅是我的主代码很慢,我注释掉了整个主循环,除了[self.context flushBuffer]; (当然还有帧率采样代码)。即使重复这一次调用,也会导致它一次挂起几帧。以下是我的控制台输出示例:
4
5
6
10
5
5
5
4
6
10
5
5
5
5
5
5
20
4
5
6
20
5
5
5
这是每次循环迭代之间的时间(以毫秒为单位)。在200帧/秒时,每帧应该约为5毫秒,但它会反复挂起10,15甚至20毫秒。正如你在-initOpenGL函数中看到的那样,Vsyncing被禁用了。
-(void)initOpenGL{
NSOpenGLPixelFormatAttribute attributes[] = {NSOpenGLPFADoubleBuffer, 0};
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes: attributes];
self.context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
[self.context setView:[self.window contentView]];
[self.context makeCurrentContext];
//Disable Vsync
int temp = 0;
[self.context setValues: &temp forParameter: NSOpenGLCPSwapInterval];
glViewport(0, 0, windowWidth, windowHeight);
glMatrixMode(GL_PROJECTION);
glOrtho(0, windowWidth, 0, windowHeight, -1, 100);
//Flip all textures right side up
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glScalef(1.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_SCISSOR_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
编辑,新信息:我可以确认这与双缓冲与单一有关。当我初始化没有DoubleBuffer属性的NSOpenGLPixelFormat时,它以200 fps完美运行。鉴于该属性,我继续得到口吃。
答案 0 :(得分:5)
在不知道实际渲染代码(没有发布)的情况下,一个非常可能的原因是首先使用NSTimer
进行帧速率控制并不是一个好主意。请参阅文档(重点添加):
计时器不是实时机制;只有当添加了计时器的其中一个运行循环模式正在运行并且能够检查计时器的触发时间是否已经过去时,它才会触发。由于典型的运行循环管理各种输入源,计时器的时间间隔的有效分辨率限制为 50-100毫秒。
因此,期望在5毫秒之内使用计时器从根本上是有缺陷的。
除此之外,可能还有其他影响(进程调度,纹理上传和OpenGL中的停顿等),这会使帧时间不是100%不变。虽然这些引起的抖动通常会小得多。
答案 1 :(得分:2)
如果您想在OSX上实现良好的同步,那么您应该使用CoreVideo DisplayLink。这是一个在每个屏幕垂直刷新时调用的回调,所以如果你的屏幕是60 FPS,这个回调将被调用(在一个单独的线程中,小心使用OpenGL线程)每秒60次,这就是触发OpenGL刷新的内容