2

我正在 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 fps 时,每帧应该是 5 毫秒左右,但它会反复挂起 10、15 甚至 20 毫秒。正如您在我的 -initOpenGL 函数中所见,垂直同步已禁用。

-(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 的速度完美运行。而有了这个属性,我继续口吃。

4

2 回答 2

5

在不知道实际渲染代码(未发布)的情况下,一个很可能的原因是首先使用NSTimerfor 帧速率控制并不是一个好主意。请参阅文档(已添加重点):

计时器不是实时机制;它仅在已添加计时器的运行循环模式之一正在运行并且能够检查计时器的触发时间是否已过时触发。由于典型的运行循环管理的各种输入源,计时器的时间间隔的有效分辨率被限制在50-100 毫秒的数量级。

因此,期望使用 5 毫秒的计时器从根本上是有缺陷的。

除此之外,可能还有其他影响(进程调度、纹理上传和 OpenGL 中的停顿等)会使帧时间不是 100% 恒定。尽管由这些引起的抖动通常会小得多。

于 2013-03-13T17:43:58.157 回答
2

如果您想在 OSX 上获得良好的同步,您应该使用 CoreVideo DisplayLink。它是在每次屏幕垂直刷新时调用的回调,因此如果您的屏幕为 60 FPS,则此回调将每秒调用 60 次(在单独的线程中,请注意 OpenGL 线程),这就是应该触发 OpenGL 刷新的原因.

于 2015-07-24T09:15:40.833 回答