Skip to content

Commit

Permalink
Change macOS OpenGL timing to use CVDisplayLink
Browse files Browse the repository at this point in the history
When building with SOKOL_GLCORE33 on Mac, this commit adds the CoreVideo
to the list of required frameworks: -framework CoreVideo

This replaces the NSTimer with CVDisplayLink for driving the timing of
rendering frames with OpenGL on macOS. CVDisplayLink can be used to
receive a callback on a separate high-priority thread synchronized with
the timing of a display device.

Because sokol_app.h expects the rendering code to run on the main
thread, we use: NSObject performSelectorOnMainThread: to trigger our
code on the main thread.

Without vertical sync enabled, this will cause tearing. Maybe because
both the rendering time of a frame can't be guaranteed to meet the
deadline, and maybe also because of the time spent going from one thread
to another.

However, it does give a consistent timer, and seems to be an improvement
over NSTimer. In my measurements, CPU time waste from the high-frequency
NSTimer was reduced.
  • Loading branch information
cancel committed Feb 25, 2021
1 parent 4cd2da8 commit 916cb3c
Showing 1 changed file with 26 additions and 8 deletions.
34 changes: 26 additions & 8 deletions sokol_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -3102,14 +3102,6 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {

_sapp.macos.window.contentView = _sapp.macos.view;
[_sapp.macos.window makeFirstResponder:_sapp.macos.view];

NSTimer* timer_obj = [NSTimer timerWithTimeInterval:0.001
target:_sapp.macos.view
selector:@selector(timerFired:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer_obj forMode:NSDefaultRunLoopMode];
timer_obj = nil;
#endif
_sapp.valid = true;
if (_sapp.fullscreen) {
Expand Down Expand Up @@ -3244,6 +3236,16 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {

@implementation _sapp_macos_view
#if defined(SOKOL_GLCORE33)
CVDisplayLinkRef displayLink;
_SOKOL_PRIVATE CVReturn _sapp_displaylink_callback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) {
_SOKOL_UNUSED(displayLink);
_SOKOL_UNUSED(now);
_SOKOL_UNUSED(outputTime);
_SOKOL_UNUSED(flagsIn);
_SOKOL_UNUSED(flagsOut);
[(_sapp_macos_view*)displayLinkContext performSelectorOnMainThread:@selector(timerFired:) withObject:nil waitUntilDone:FALSE];
return kCVReturnSuccess;
}
/* NOTE: this is a hack/fix when the initial window size has been clipped by
macOS because it didn't fit on the screen, in that case the
frame size of the window is reported wrong if low-dpi rendering
Expand All @@ -3253,6 +3255,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {
Hooking into reshape and getting the frame dimensions seems to report
the correct dimensions.
*/

- (void)reshape {
_sapp_macos_update_dimensions();
[super reshape];
Expand All @@ -3266,6 +3269,14 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {
GLint swapInt = 1;
NSOpenGLContext* ctx = [_sapp.macos.view openGLContext];
[ctx setValues:&swapInt forParameter:NSOpenGLContextParameterSwapInterval];

CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
CVDisplayLinkSetOutputCallback(displayLink, &_sapp_displaylink_callback, self);
CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);
CVDisplayLinkStart(displayLink);

[ctx makeCurrentContext];
}
#endif
Expand Down Expand Up @@ -3302,6 +3313,13 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() {
}
}

- (void)dealloc {
#if defined(SOKOL_GLCORE33)
CVDisplayLinkRelease(displayLink);
#endif
[super dealloc];
}

- (void)drawRect:(NSRect)rect {
_SOKOL_UNUSED(rect);
/* Catch any last-moment input events */
Expand Down

0 comments on commit 916cb3c

Please sign in to comment.