OpenGL VSync / NSTimer issues on macOS


I'm trying to set up a simple OpenGL game on macOS, using an NSTimer to set up a run loop as explained here. The idea is to create a repeating timer with a very small (~1ms) time interval and rely on vsync to regulate the frame rate.

I'm setting my NSOpenGLContext swap interval to a value of 1, which should enable vsync. I was under the impression that this would cause NSOpenGLContext.flushbuffer to block, but this doesn't seem to be the case. My render code is firing off much more frequently than 60 times per second.

The document I linked has been marked as retired, but all the official documentation I've read suggests that it's possible to throttle an NSTimer loop to the display's refresh rate somehow. I haven't been able to get this working though, and I'm wondering if this approach is no longer viable.

Am I missing something? In a modern project, is it better just to go with a CVDisplayLink?

Show source
| osx   | swift   | graphics   | opengl   2017-01-07 05:01 1 Answers

Answers ( 1 )

  1. 2017-01-07 05:01

    My understanding is that it's unlikely that an NSTimer will fire more frequently than about 10-20 times per second, and with timer coalescing you aren't likely to get guaranteed fire times appropriate for this type of application. For example, one answer to this question points out that the docs say:

    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. If a timer’s firing time occurs during a long callout or while the run loop is in a mode that is not monitoring the timer, the timer does not fire until the next time the run loop checks the timer. Therefore, the actual time at which the timer fires potentially can be a significant period of time after the scheduled firing time.

    CVDisplayLink is definitely the preferred solution. It's quite simple to use, too.

    And to answer your other question, yes something has changed. The OS has changed how timers are handled to help improve energy performance. I worked on an app that used the method you're suggesting up until about OS 10.9 or 10.10. Once that came out we had to rethink our strategy because timers worked differently.

◀ Go back