Skip to content

Commit

Permalink
cocoa: Backed out CVDisplayLink code for macOS vsync.
Browse files Browse the repository at this point in the history
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 04b50f6
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 84 deletions.
7 changes: 1 addition & 6 deletions src/video/cocoa/SDL_cocoaopengl.h
Expand Up @@ -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


Expand Down
101 changes: 23 additions & 78 deletions src/video/cocoa/SDL_cocoaopengl.m
Expand Up @@ -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
Expand All @@ -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;
}
Expand Down Expand Up @@ -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


Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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. */
Expand Down

0 comments on commit 04b50f6

Please sign in to comment.