Pergunta

I'm making a simple graphical app on OSX. I just started monitoring the frame rate by checking the difference in system time between frames. It seems to be hanging a bit every few frames.

The app runs on an NSTimer object, currently set to 200 fps (5 ms frames). To make sure it wasn't just my main code being slow, I commented out the entire main loop, except for [self.context flushBuffer]; (and of course the frame-rate sampling code). Even repeating this single call is causing it to hang for several frames at a time. Here is an example of my console output:

4
5
6
10
5
5
5
4
6
10
5
5
5
5
5
5
20
4
5
6
20
5
5
5

This is the time in milliseconds between each loop iteration. At 200 fps, it should be about 5 ms for each frame, but it repeatedly hangs for 10, 15, or even 20 ms. Vsyncing is disabled, as you can see in my -initOpenGL function.

-(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);
    }

Edit, new information: I can confirm that this has something to do with double-buffering vs single. When I initialize the NSOpenGLPixelFormat without the DoubleBuffer attribute, it runs perfectly at 200 fps. Whereas with that attribute, I continue to get the stuttering.

Foi útil?

Solução

Without knowing the actual rendering code (which wasn't posted), one very possible cause is that using a NSTimer for frame rate control in the first place isn't such a great idea. Refer to the documentation (emphasis added):

A timer is not a real-time mechanism; it fires only when one of the run loop modes to which the timer has been added is running and able to check if the timer’s firing time has passed. Because of the various input sources a typical run loop manages, the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds.

Thus, the expectation to use a timer for something like 5 milliseconds is fundamentally flawed.

In addition to that, there may be other effects (process scheduling, texture uploads and stalls in OpenGL, etc.) that will make frame times not 100% constant. Though the jitter caused by these will usually be on a much smaller scale.

Outras dicas

If you want a good synchro on OSX, you should a CoreVideo DisplayLink. It is a callback called at each screen vertical refresh, so if your screen is at 60 FPS, this callback will be called (in a separated thread, be carefull with OpenGL threading) 60 times per second, and that's what should trigger an OpenGL refresh.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top