From 6a505b32888541a66f2e5f23d75fd05b1fb1aed7 Mon Sep 17 00:00:00 2001 From: "J?rgen P. Tjern?" Date: Wed, 7 Aug 2013 16:29:25 -0700 Subject: [PATCH] Mac: Support for multiple contexts per SDL_Window. --- src/video/cocoa/SDL_cocoaopengl.h | 2 ++ src/video/cocoa/SDL_cocoaopengl.m | 57 ++++++++++++++++++++++++------- src/video/cocoa/SDL_cocoawindow.h | 2 +- src/video/cocoa/SDL_cocoawindow.m | 31 +++++++++++++---- 4 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/video/cocoa/SDL_cocoaopengl.h b/src/video/cocoa/SDL_cocoaopengl.h index 9a20b4a6a..2d06700b6 100644 --- a/src/video/cocoa/SDL_cocoaopengl.h +++ b/src/video/cocoa/SDL_cocoaopengl.h @@ -35,12 +35,14 @@ struct SDL_GLDriverData @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 diff --git a/src/video/cocoa/SDL_cocoaopengl.m b/src/video/cocoa/SDL_cocoaopengl.m index 43af675f4..0d49ba0cc 100644 --- a/src/video/cocoa/SDL_cocoaopengl.m +++ b/src/video/cocoa/SDL_cocoaopengl.m @@ -51,8 +51,12 @@ @implementation SDLOpenGLContext : NSOpenGLContext - (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 @@ - (void)update [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 @@ - (void)update 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 @@ - (void)update 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 @@ - (void)update 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]; diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h index 50a741de9..022694f52 100644 --- a/src/video/cocoa/SDL_cocoawindow.h +++ b/src/video/cocoa/SDL_cocoawindow.h @@ -83,7 +83,7 @@ struct SDL_WindowData { SDL_Window *window; NSWindow *nswindow; - SDLOpenGLContext *nscontext; + NSMutableArray *nscontexts; SDL_bool created; Cocoa_WindowListener *listener; struct SDL_VideoData *videodata; diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 530d6bb11..9cee4d3ba 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -42,6 +42,16 @@ static __inline__ void ConvertNSRect(NSRect *r) 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 @@ - (void)windowDidMove:(NSNotification *)aNotification 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 @@ - (void)windowDidResize:(NSNotification *)aNotification 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 @@ - (void)resetCursorRects data->nswindow = nswindow; data->created = created; data->videodata = videodata; + data->nscontexts = [[NSMutableArray alloc] init]; pool = [[NSAutoreleasePool alloc] init]; @@ -799,7 +810,7 @@ - (void)resetCursorRects [nswindow setFrameOrigin:rect.origin]; s_moveHack = moveHack; - [windata->nscontext scheduleUpdate]; + ScheduleContextUpdates(windata); [pool release]; } @@ -816,7 +827,7 @@ - (void)resetCursorRects size.height = window->h; [nswindow setContentSize:size]; - [windata->nscontext scheduleUpdate]; + ScheduleContextUpdates(windata); [pool release]; } @@ -903,7 +914,7 @@ - (void)resetCursorRects [nswindow zoom:nil]; - [windata->nscontext scheduleUpdate]; + ScheduleContextUpdates(windata); [pool release]; } @@ -1040,7 +1051,7 @@ - (void)resetCursorRects [nswindow makeKeyAndOrderFront:nil]; [data->listener resumeVisibleObservation]; - [data->nscontext scheduleUpdate]; + ScheduleContextUpdates(data); [pool release]; } @@ -1133,6 +1144,14 @@ - (void)resetCursorRects 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];