Mac: Support for multiple contexts per SDL_Window.
authorJørgen P. Tjernø <jorgen@valvesoftware.com>
Wed, 07 Aug 2013 16:29:25 -0700
changeset 7595 ede2237fcebf
parent 7594 6abcf951af68
child 7596 45e5c263c096
Mac: Support for multiple contexts per SDL_Window.
src/video/cocoa/SDL_cocoaopengl.h
src/video/cocoa/SDL_cocoaopengl.m
src/video/cocoa/SDL_cocoawindow.h
src/video/cocoa/SDL_cocoawindow.m
--- a/src/video/cocoa/SDL_cocoaopengl.h	Wed Aug 07 16:29:21 2013 -0700
+++ b/src/video/cocoa/SDL_cocoaopengl.h	Wed Aug 07 16:29:25 2013 -0700
@@ -35,12 +35,14 @@
 
 @interface SDLOpenGLContext : NSOpenGLContext {
     SDL_atomic_t dirty;
+    SDL_Window *window;
 }
 
 - (id)initWithFormat:(NSOpenGLPixelFormat *)format
         shareContext:(NSOpenGLContext *)share;
 - (void)scheduleUpdate;
 - (void)updateIfNeeded;
+- (void)setWindow:(SDL_Window *)window;
 
 @end
 
--- a/src/video/cocoa/SDL_cocoaopengl.m	Wed Aug 07 16:29:21 2013 -0700
+++ b/src/video/cocoa/SDL_cocoaopengl.m	Wed Aug 07 16:29:25 2013 -0700
@@ -51,8 +51,12 @@
 - (id)initWithFormat:(NSOpenGLPixelFormat *)format
         shareContext:(NSOpenGLContext *)share
 {
-    SDL_AtomicSet(&self->dirty, 0);
-    return [super initWithFormat:format shareContext:share];
+    self = [super initWithFormat:format shareContext:share];
+    if (self) {
+        SDL_AtomicSet(&self->dirty, 0);
+        self->window = NULL;
+    }
+    return self;
 }
 
 - (void)scheduleUpdate
@@ -78,6 +82,40 @@
     [self updateIfNeeded];
 }
 
+/* Updates the drawable for the contexts and manages related state. */
+- (void)setWindow:(SDL_Window *)newWindow
+{
+    if (self->window) {
+        SDL_WindowData *oldwindowdata = (SDL_WindowData *)self->window->driverdata;
+
+        /* Make sure to remove us from the old window's context list, or we'll get scheduled updates from it too. */
+        NSMutableArray *contexts = oldwindowdata->nscontexts;
+        @synchronized (contexts) {
+            [contexts removeObject:self];
+        }
+    }
+
+    self->window = newWindow;
+
+    if (newWindow) {
+        SDL_WindowData *windowdata = (SDL_WindowData *)newWindow->driverdata;
+
+        /* Now sign up for scheduled updates for the new window. */
+        NSMutableArray *contexts = windowdata->nscontexts;
+        @synchronized (contexts) {
+            [contexts addObject:self];
+        }
+
+        if ([self view] != [windowdata->nswindow contentView]) {
+            [self setView:[windowdata->nswindow contentView]];
+            [self scheduleUpdate];
+        }
+    } else {
+        [self clearDrawable];
+        [self scheduleUpdate];
+    }
+}
+
 @end
 
 
@@ -244,14 +282,8 @@
     pool = [[NSAutoreleasePool alloc] init];
 
     if (context) {
-        SDL_WindowData *windowdata = (SDL_WindowData *)window->driverdata;
         SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
-        windowdata->nscontext = nscontext;
-        if ([nscontext view] != [windowdata->nswindow contentView]) {
-            [nscontext setView:[windowdata->nswindow contentView]];
-            [nscontext scheduleUpdate];
-        }
-
+        [nscontext setWindow:window];
         [nscontext updateIfNeeded];
         [nscontext makeCurrentContext];
     } else {
@@ -309,11 +341,10 @@
 Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
 {
     NSAutoreleasePool *pool;
-    SDL_WindowData *windowdata = (SDL_WindowData *)window->driverdata;
-    SDLOpenGLContext *nscontext = windowdata->nscontext;
 
     pool = [[NSAutoreleasePool alloc] init];
 
+    SDLOpenGLContext* nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
     [nscontext flushBuffer];
     [nscontext updateIfNeeded];
 
@@ -324,11 +355,11 @@
 Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
 {
     NSAutoreleasePool *pool;
-    NSOpenGLContext *nscontext = (NSOpenGLContext *)context;
+    SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
 
     pool = [[NSAutoreleasePool alloc] init];
 
-    [nscontext clearDrawable];
+    [nscontext setWindow:NULL];
     [nscontext release];
 
     [pool release];
--- a/src/video/cocoa/SDL_cocoawindow.h	Wed Aug 07 16:29:21 2013 -0700
+++ b/src/video/cocoa/SDL_cocoawindow.h	Wed Aug 07 16:29:25 2013 -0700
@@ -83,7 +83,7 @@
 {
     SDL_Window *window;
     NSWindow *nswindow;
-    SDLOpenGLContext *nscontext;
+    NSMutableArray *nscontexts;
     SDL_bool created;
     Cocoa_WindowListener *listener;
     struct SDL_VideoData *videodata;
--- a/src/video/cocoa/SDL_cocoawindow.m	Wed Aug 07 16:29:21 2013 -0700
+++ b/src/video/cocoa/SDL_cocoawindow.m	Wed Aug 07 16:29:25 2013 -0700
@@ -42,6 +42,16 @@
     r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
 }
 
+static void ScheduleContextUpdates(SDL_WindowData *data)
+{
+    NSMutableArray *contexts = data->nscontexts;
+    @synchronized (contexts) {
+        for (SDLOpenGLContext *context in contexts) {
+            [context scheduleUpdate];
+        }
+    }
+}
+
 @implementation Cocoa_WindowListener
 
 - (void)listen:(SDL_WindowData *)data
@@ -211,7 +221,7 @@
     x = (int)rect.origin.x;
     y = (int)rect.origin.y;
 
-    [_data->nscontext scheduleUpdate];
+    ScheduleContextUpdates(_data);
 
     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
 }
@@ -228,7 +238,7 @@
     if (SDL_IsShapedWindow(_data->window))
         Cocoa_ResizeWindowShape(_data->window);
 
-    [_data->nscontext scheduleUpdate];
+    ScheduleContextUpdates(_data);
 
     /* The window can move during a resize event, such as when maximizing
        or resizing from a corner */
@@ -605,6 +615,7 @@
     data->nswindow = nswindow;
     data->created = created;
     data->videodata = videodata;
+    data->nscontexts = [[NSMutableArray alloc] init];
 
     pool = [[NSAutoreleasePool alloc] init];
 
@@ -799,7 +810,7 @@
     [nswindow setFrameOrigin:rect.origin];
     s_moveHack = moveHack;
 
-    [windata->nscontext scheduleUpdate];
+    ScheduleContextUpdates(windata);
 
     [pool release];
 }
@@ -816,7 +827,7 @@
     size.height = window->h;
     [nswindow setContentSize:size];
 
-    [windata->nscontext scheduleUpdate];
+    ScheduleContextUpdates(windata);
 
     [pool release];
 }
@@ -903,7 +914,7 @@
 
     [nswindow zoom:nil];
 
-    [windata->nscontext scheduleUpdate];
+    ScheduleContextUpdates(windata);
 
     [pool release];
 }
@@ -1040,7 +1051,7 @@
     [nswindow makeKeyAndOrderFront:nil];
     [data->listener resumeVisibleObservation];
 
-    [data->nscontext scheduleUpdate];
+    ScheduleContextUpdates(data);
 
     [pool release];
 }
@@ -1133,6 +1144,14 @@
         if (data->created) {
             [data->nswindow close];
         }
+
+        NSArray *contexts = [[data->nscontexts copy] autorelease];
+        for (SDLOpenGLContext *context in contexts) {
+            /* Calling setWindow:NULL causes the context to remove itself from the context list. */            
+            [context setWindow:NULL];
+        }
+        [data->nscontexts release];
+
         SDL_free(data);
     }
     [pool release];