Skip to content
Permalink
Browse files

cocoa: Backed out CVDisplayLink code for macOS vsync.

This was to deal with broken vsync support in macOS 10.14, which we assumed
would remain broken indefinitely, but a later 10.14 released fixed it.

This is a loss of late-swap support, but there are several subtle problems
in our CVDiplayLink code that are also evaporating, to be fair.

Fixes Bugzilla #4575.

(Backed out changeset 8760fed23001)
  • Loading branch information
icculus committed Jun 11, 2019
1 parent 39733dc commit 04b50f6c6bef67b744b192c78775771b51ff2141
Showing with 24 additions and 84 deletions.
  1. +1 −6 src/video/cocoa/SDL_cocoaopengl.h
  2. +23 −78 src/video/cocoa/SDL_cocoaopengl.m
@@ -36,19 +36,14 @@ struct SDL_GLDriverData
@interface SDLOpenGLContext : NSOpenGLContext {
SDL_atomic_t dirty;
SDL_Window *window;
CVDisplayLinkRef displayLink;
@public SDL_mutex *swapIntervalMutex;
@public SDL_cond *swapIntervalCond;
@public SDL_atomic_t swapIntervalSetting;
@public SDL_atomic_t swapIntervalsPassed;
}

- (id)initWithFormat:(NSOpenGLPixelFormat *)format
shareContext:(NSOpenGLContext *)share;
- (void)scheduleUpdate;
- (void)updateIfNeeded;
- (void)setWindow:(SDL_Window *)window;
- (void)dealloc;

@end


@@ -36,23 +36,6 @@

#define DEFAULT_OPENGL "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"

static CVReturn
DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
{
SDLOpenGLContext *nscontext = (SDLOpenGLContext *) displayLinkContext;

/*printf("DISPLAY LINK! %u\n", (unsigned int) SDL_GetTicks()); */
const int setting = SDL_AtomicGet(&nscontext->swapIntervalSetting);
if (setting != 0) { /* nothing to do if vsync is disabled, don't even lock */
SDL_LockMutex(nscontext->swapIntervalMutex);
SDL_AtomicAdd(&nscontext->swapIntervalsPassed, 1);
SDL_CondSignal(nscontext->swapIntervalCond);
SDL_UnlockMutex(nscontext->swapIntervalMutex);
}

return kCVReturnSuccess;
}

@implementation SDLOpenGLContext : NSOpenGLContext

- (id)initWithFormat:(NSOpenGLPixelFormat *)format
@@ -62,20 +45,6 @@ - (id)initWithFormat:(NSOpenGLPixelFormat *)format
if (self) {
SDL_AtomicSet(&self->dirty, 0);
self->window = NULL;
SDL_AtomicSet(&self->swapIntervalSetting, 0);
SDL_AtomicSet(&self->swapIntervalsPassed, 0);
self->swapIntervalCond = SDL_CreateCond();
self->swapIntervalMutex = SDL_CreateMutex();
if (!self->swapIntervalCond || !self->swapIntervalMutex) {
[self release];
return nil;
}

/* !!! FIXME: check return values. */
CVDisplayLinkCreateWithActiveCGDisplays(&self->displayLink);
CVDisplayLinkSetOutputCallback(self->displayLink, &DisplayLinkCallback, self);
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(self->displayLink, [self CGLContextObj], [format CGLPixelFormatObj]);
CVDisplayLinkStart(displayLink);
}
return self;
}
@@ -145,19 +114,6 @@ - (void)setWindow:(SDL_Window *)newWindow
}
}

- (void)dealloc
{
if (self->displayLink) {
CVDisplayLinkRelease(self->displayLink);
}
if (self->swapIntervalCond) {
SDL_DestroyCond(self->swapIntervalCond);
}
if (self->swapIntervalMutex) {
SDL_DestroyMutex(self->swapIntervalMutex);
}
[super dealloc];
}
@end


@@ -208,7 +164,6 @@ - (void)dealloc
const char *glversion;
int glversion_major;
int glversion_minor;
int interval;

if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
#if SDL_VIDEO_OPENGL_EGL
@@ -320,10 +275,6 @@ - (void)dealloc
return NULL;
}

/* vsync is handled separately by synchronizing with a display link. */
interval = 0;
[context setValues:&interval forParameter:NSOpenGLCPSwapInterval];

if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) {
Cocoa_GL_DeleteContext(_this, context);
SDL_SetError("Failed making OpenGL context current");
@@ -417,17 +368,21 @@ - (void)dealloc
Cocoa_GL_SetSwapInterval(_THIS, int interval)
{ @autoreleasepool
{
SDLOpenGLContext *nscontext = (SDLOpenGLContext *) SDL_GL_GetCurrentContext();
NSOpenGLContext *nscontext;
GLint value;
int status;

if (nscontext == nil) {
status = SDL_SetError("No current OpenGL context");
} else {
SDL_LockMutex(nscontext->swapIntervalMutex);
SDL_AtomicSet(&nscontext->swapIntervalsPassed, 0);
SDL_AtomicSet(&nscontext->swapIntervalSetting, interval);
SDL_UnlockMutex(nscontext->swapIntervalMutex);
if (interval < 0) { /* no extension for this on Mac OS X at the moment. */
return SDL_SetError("Late swap tearing currently unsupported");
}

nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
if (nscontext != nil) {
value = interval;
[nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval];
status = 0;
} else {
status = SDL_SetError("No current OpenGL context");
}

return status;
@@ -437,8 +392,17 @@ - (void)dealloc
Cocoa_GL_GetSwapInterval(_THIS)
{ @autoreleasepool
{
SDLOpenGLContext *nscontext = (SDLOpenGLContext *) SDL_GL_GetCurrentContext();
return nscontext ? SDL_AtomicGet(&nscontext->swapIntervalSetting) : 0;
NSOpenGLContext *nscontext;
GLint value;
int status = 0;

nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
if (nscontext != nil) {
[nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
status = (int)value;
}

return status;
}}

int
@@ -447,25 +411,6 @@ - (void)dealloc
{
SDLOpenGLContext* nscontext = (SDLOpenGLContext*)SDL_GL_GetCurrentContext();
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
const int setting = SDL_AtomicGet(&nscontext->swapIntervalSetting);

if (setting == 0) {
/* nothing to do if vsync is disabled, don't even lock */
} else if (setting < 0) { /* late swap tearing */
SDL_LockMutex(nscontext->swapIntervalMutex);
while (SDL_AtomicGet(&nscontext->swapIntervalsPassed) == 0) {
SDL_CondWait(nscontext->swapIntervalCond, nscontext->swapIntervalMutex);
}
SDL_AtomicSet(&nscontext->swapIntervalsPassed, 0);
SDL_UnlockMutex(nscontext->swapIntervalMutex);
} else {
SDL_LockMutex(nscontext->swapIntervalMutex);
do { /* always wait here so we know we just hit a swap interval. */
SDL_CondWait(nscontext->swapIntervalCond, nscontext->swapIntervalMutex);
} while ((SDL_AtomicGet(&nscontext->swapIntervalsPassed) % setting) != 0);
SDL_AtomicSet(&nscontext->swapIntervalsPassed, 0);
SDL_UnlockMutex(nscontext->swapIntervalMutex);
}

/* on 10.14 ("Mojave") and later, this deadlocks if two contexts in two
threads try to swap at the same time, so put a mutex around it. */

0 comments on commit 04b50f6

Please sign in to comment.