Mac: Support for multiple contexts per SDL_Window.

This commit is contained in:
Jørgen P. Tjernø 2013-08-07 16:29:25 -07:00
parent 20c8287efc
commit 9fb9406bbc
4 changed files with 72 additions and 20 deletions

View file

@ -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

View file

@ -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 @@ Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
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
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
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];

View file

@ -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;

View file

@ -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 @@ static __inline__ void ConvertNSRect(NSRect *r)
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 @@ static __inline__ void ConvertNSRect(NSRect *r)
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 @@ SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created
data->nswindow = nswindow;
data->created = created;
data->videodata = videodata;
data->nscontexts = [[NSMutableArray alloc] init];
pool = [[NSAutoreleasePool alloc] init];
@ -799,7 +810,7 @@ Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
[nswindow setFrameOrigin:rect.origin];
s_moveHack = moveHack;
[windata->nscontext scheduleUpdate];
ScheduleContextUpdates(windata);
[pool release];
}
@ -816,7 +827,7 @@ Cocoa_SetWindowSize(_THIS, SDL_Window * window)
size.height = window->h;
[nswindow setContentSize:size];
[windata->nscontext scheduleUpdate];
ScheduleContextUpdates(windata);
[pool release];
}
@ -903,7 +914,7 @@ Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
[nswindow zoom:nil];
[windata->nscontext scheduleUpdate];
ScheduleContextUpdates(windata);
[pool release];
}
@ -1040,7 +1051,7 @@ Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display
[nswindow makeKeyAndOrderFront:nil];
[data->listener resumeVisibleObservation];
[data->nscontext scheduleUpdate];
ScheduleContextUpdates(data);
[pool release];
}
@ -1133,6 +1144,14 @@ Cocoa_DestroyWindow(_THIS, SDL_Window * window)
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];