Mac: Support for multiple contexts per SDL_Window.
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "SDL_config.h"
23 /* NSOpenGL implementation of SDL OpenGL support */
25 #if SDL_VIDEO_OPENGL_CGL
26 #include "SDL_cocoavideo.h"
27 #include "SDL_cocoaopengl.h"
29 #include <OpenGL/CGLTypes.h>
30 #include <OpenGL/OpenGL.h>
31 #include <OpenGL/CGLRenderers.h>
33 #include "SDL_loadso.h"
34 #include "SDL_opengl.h"
36 #define DEFAULT_OPENGL "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
39 #ifndef kCGLPFAOpenGLProfile
40 #define kCGLPFAOpenGLProfile 99
42 #ifndef kCGLOGLPVersion_Legacy
43 #define kCGLOGLPVersion_Legacy 0x1000
45 #ifndef kCGLOGLPVersion_3_2_Core
46 #define kCGLOGLPVersion_3_2_Core 0x3200
49 @implementation SDLOpenGLContext : NSOpenGLContext
51 - (id)initWithFormat:(NSOpenGLPixelFormat *)format
52 shareContext:(NSOpenGLContext *)share
54 self = [super initWithFormat:format shareContext:share];
56 SDL_AtomicSet(&self->dirty, 0);
62 - (void)scheduleUpdate
64 SDL_AtomicAdd(&self->dirty, 1);
67 /* This should only be called on the thread on which a user is using the context. */
68 - (void)updateIfNeeded
70 int value = SDL_AtomicSet(&self->dirty, 0);
72 /* We call the real underlying update here, since -[SDLOpenGLContext update] just calls us. */
77 /* This should only be called on the thread on which a user is using the context. */
80 /* This ensures that regular 'update' calls clear the atomic dirty flag. */
81 [self scheduleUpdate];
82 [self updateIfNeeded];
85 /* Updates the drawable for the contexts and manages related state. */
86 - (void)setWindow:(SDL_Window *)newWindow
89 SDL_WindowData *oldwindowdata = (SDL_WindowData *)self->window->driverdata;
91 /* Make sure to remove us from the old window's context list, or we'll get scheduled updates from it too. */
92 NSMutableArray *contexts = oldwindowdata->nscontexts;
93 @synchronized (contexts) {
94 [contexts removeObject:self];
98 self->window = newWindow;
101 SDL_WindowData *windowdata = (SDL_WindowData *)newWindow->driverdata;
103 /* Now sign up for scheduled updates for the new window. */
104 NSMutableArray *contexts = windowdata->nscontexts;
105 @synchronized (contexts) {
106 [contexts addObject:self];
109 if ([self view] != [windowdata->nswindow contentView]) {
110 [self setView:[windowdata->nswindow contentView]];
111 [self scheduleUpdate];
114 [self clearDrawable];
115 [self scheduleUpdate];
123 Cocoa_GL_LoadLibrary(_THIS, const char *path)
125 /* Load the OpenGL library */
127 path = SDL_getenv("SDL_OPENGL_LIBRARY");
130 path = DEFAULT_OPENGL;
132 _this->gl_config.dll_handle = SDL_LoadObject(path);
133 if (!_this->gl_config.dll_handle) {
136 SDL_strlcpy(_this->gl_config.driver_path, path,
137 SDL_arraysize(_this->gl_config.driver_path));
142 Cocoa_GL_GetProcAddress(_THIS, const char *proc)
144 return SDL_LoadFunction(_this->gl_config.dll_handle, proc);
148 Cocoa_GL_UnloadLibrary(_THIS)
150 SDL_UnloadObject(_this->gl_config.dll_handle);
151 _this->gl_config.dll_handle = NULL;
155 Cocoa_GL_CreateContext(_THIS, SDL_Window * window)
157 const int wantver = (_this->gl_config.major_version << 8) |
158 (_this->gl_config.minor_version);
159 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
160 NSAutoreleasePool *pool;
161 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
162 SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
163 NSOpenGLPixelFormatAttribute attr[32];
164 NSOpenGLPixelFormat *fmt;
165 SDLOpenGLContext *context;
166 NSOpenGLContext *share_context = nil;
169 if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
170 SDL_SetError ("OpenGL ES not supported on this platform");
174 /* Sadly, we'll have to update this as life progresses, since we need to
175 set an enum for context profiles, not a context version number */
176 if (wantver > 0x0302) {
177 SDL_SetError ("OpenGL > 3.2 is not supported on this platform");
181 pool = [[NSAutoreleasePool alloc] init];
183 /* specify a profile if we're on Lion (10.7) or later. */
184 if (data->osversion >= 0x1070) {
185 NSOpenGLPixelFormatAttribute profile = kCGLOGLPVersion_Legacy;
186 if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) {
187 if (wantver == 0x0302) {
188 profile = kCGLOGLPVersion_3_2_Core;
191 attr[i++] = kCGLPFAOpenGLProfile;
195 attr[i++] = NSOpenGLPFAColorSize;
196 attr[i++] = SDL_BYTESPERPIXEL(display->current_mode.format)*8;
198 attr[i++] = NSOpenGLPFADepthSize;
199 attr[i++] = _this->gl_config.depth_size;
201 if (_this->gl_config.double_buffer) {
202 attr[i++] = NSOpenGLPFADoubleBuffer;
205 if (_this->gl_config.stereo) {
206 attr[i++] = NSOpenGLPFAStereo;
209 if (_this->gl_config.stencil_size) {
210 attr[i++] = NSOpenGLPFAStencilSize;
211 attr[i++] = _this->gl_config.stencil_size;
214 if ((_this->gl_config.accum_red_size +
215 _this->gl_config.accum_green_size +
216 _this->gl_config.accum_blue_size +
217 _this->gl_config.accum_alpha_size) > 0) {
218 attr[i++] = NSOpenGLPFAAccumSize;
219 attr[i++] = _this->gl_config.accum_red_size + _this->gl_config.accum_green_size + _this->gl_config.accum_blue_size + _this->gl_config.accum_alpha_size;
222 if (_this->gl_config.multisamplebuffers) {
223 attr[i++] = NSOpenGLPFASampleBuffers;
224 attr[i++] = _this->gl_config.multisamplebuffers;
227 if (_this->gl_config.multisamplesamples) {
228 attr[i++] = NSOpenGLPFASamples;
229 attr[i++] = _this->gl_config.multisamplesamples;
230 attr[i++] = NSOpenGLPFANoRecovery;
233 if (_this->gl_config.accelerated >= 0) {
234 if (_this->gl_config.accelerated) {
235 attr[i++] = NSOpenGLPFAAccelerated;
237 attr[i++] = NSOpenGLPFARendererID;
238 attr[i++] = kCGLRendererGenericFloatID;
242 attr[i++] = NSOpenGLPFAScreenMask;
243 attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display);
246 fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
248 SDL_SetError ("Failed creating OpenGL pixel format");
253 if (_this->gl_config.share_with_current_context) {
254 share_context = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
257 context = [[SDLOpenGLContext alloc] initWithFormat:fmt shareContext:share_context];
261 if (context == nil) {
262 SDL_SetError ("Failed creating OpenGL context");
269 if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) {
270 Cocoa_GL_DeleteContext(_this, context);
278 Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
280 NSAutoreleasePool *pool;
282 pool = [[NSAutoreleasePool alloc] init];
285 SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
286 [nscontext setWindow:window];
287 [nscontext updateIfNeeded];
288 [nscontext makeCurrentContext];
290 [NSOpenGLContext clearCurrentContext];
298 Cocoa_GL_SetSwapInterval(_THIS, int interval)
300 NSAutoreleasePool *pool;
301 NSOpenGLContext *nscontext;
305 pool = [[NSAutoreleasePool alloc] init];
307 nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
308 if (nscontext != nil) {
310 [nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval];
313 status = SDL_SetError("No current OpenGL context");
321 Cocoa_GL_GetSwapInterval(_THIS)
323 NSAutoreleasePool *pool;
324 NSOpenGLContext *nscontext;
328 pool = [[NSAutoreleasePool alloc] init];
330 nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
331 if (nscontext != nil) {
332 [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
341 Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
343 NSAutoreleasePool *pool;
345 pool = [[NSAutoreleasePool alloc] init];
347 SDLOpenGLContext* nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
348 [nscontext flushBuffer];
349 [nscontext updateIfNeeded];
355 Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
357 NSAutoreleasePool *pool;
358 SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
360 pool = [[NSAutoreleasePool alloc] init];
362 [nscontext setWindow:NULL];
368 #endif /* SDL_VIDEO_OPENGL_CGL */
370 /* vi: set ts=4 sw=4 expandtab: */