src/video/cocoa/SDL_cocoaopengl.m
author Sam Lantinga <slouken@libsdl.org>
Mon, 07 Jul 2014 12:48:25 -0700
changeset 8986 1c81316ac642
parent 8604 459bd7365e9d
child 9587 18979eac0a35
permissions -rw-r--r--
Fixed bug 2631 - Mac: minor code cleanup

Alex Szpakowski

Some minor changes to the Mac-specific backend code:

- Fixed up some code style issues (mostly brace style inconsistencies).

- Fixed a compiler warning in SDL_cocoaevents.m.

- Removed some useless code now that the 10.7 SDK is required to build SDL.

- Removed Gestalt(gestaltSystemVersion, ...) call and switched to NSAppKitVersionNumber for version checking code. Using Gestalt with gestaltSystemVersion will give 0x1090 in Mac OS 10.10+, and the whole Gestalt function was deprecated in Mac OS 10.8.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4 
     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.
     8 
     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:
    12 
    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.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 /* NSOpenGL implementation of SDL OpenGL support */
    24 
    25 #if SDL_VIDEO_OPENGL_CGL
    26 #include "SDL_cocoavideo.h"
    27 #include "SDL_cocoaopengl.h"
    28 
    29 #include <OpenGL/CGLTypes.h>
    30 #include <OpenGL/OpenGL.h>
    31 #include <OpenGL/CGLRenderers.h>
    32 
    33 #include "SDL_loadso.h"
    34 #include "SDL_opengl.h"
    35 
    36 #define DEFAULT_OPENGL  "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
    37 
    38 @implementation SDLOpenGLContext : NSOpenGLContext
    39 
    40 - (id)initWithFormat:(NSOpenGLPixelFormat *)format
    41         shareContext:(NSOpenGLContext *)share
    42 {
    43     self = [super initWithFormat:format shareContext:share];
    44     if (self) {
    45         SDL_AtomicSet(&self->dirty, 0);
    46         self->window = NULL;
    47     }
    48     return self;
    49 }
    50 
    51 - (void)scheduleUpdate
    52 {
    53     SDL_AtomicAdd(&self->dirty, 1);
    54 }
    55 
    56 /* This should only be called on the thread on which a user is using the context. */
    57 - (void)updateIfNeeded
    58 {
    59     int value = SDL_AtomicSet(&self->dirty, 0);
    60     if (value > 0) {
    61         /* We call the real underlying update here, since -[SDLOpenGLContext update] just calls us. */
    62         [super update];
    63     }
    64 }
    65 
    66 /* This should only be called on the thread on which a user is using the context. */
    67 - (void)update
    68 {
    69     /* This ensures that regular 'update' calls clear the atomic dirty flag. */
    70     [self scheduleUpdate];
    71     [self updateIfNeeded];
    72 }
    73 
    74 /* Updates the drawable for the contexts and manages related state. */
    75 - (void)setWindow:(SDL_Window *)newWindow
    76 {
    77     if (self->window) {
    78         SDL_WindowData *oldwindowdata = (SDL_WindowData *)self->window->driverdata;
    79 
    80         /* Make sure to remove us from the old window's context list, or we'll get scheduled updates from it too. */
    81         NSMutableArray *contexts = oldwindowdata->nscontexts;
    82         @synchronized (contexts) {
    83             [contexts removeObject:self];
    84         }
    85     }
    86 
    87     self->window = newWindow;
    88 
    89     if (newWindow) {
    90         SDL_WindowData *windowdata = (SDL_WindowData *)newWindow->driverdata;
    91 
    92         /* Now sign up for scheduled updates for the new window. */
    93         NSMutableArray *contexts = windowdata->nscontexts;
    94         @synchronized (contexts) {
    95             [contexts addObject:self];
    96         }
    97 
    98         if ([self view] != [windowdata->nswindow contentView]) {
    99             [self setView:[windowdata->nswindow contentView]];
   100             if (self == [NSOpenGLContext currentContext]) {
   101                 [self update];
   102             } else {
   103                 [self scheduleUpdate];
   104             }
   105         }
   106     } else {
   107         [self clearDrawable];
   108         if (self == [NSOpenGLContext currentContext]) {
   109             [self update];
   110         } else {
   111             [self scheduleUpdate];
   112         }
   113     }
   114 }
   115 
   116 @end
   117 
   118 
   119 int
   120 Cocoa_GL_LoadLibrary(_THIS, const char *path)
   121 {
   122     /* Load the OpenGL library */
   123     if (path == NULL) {
   124         path = SDL_getenv("SDL_OPENGL_LIBRARY");
   125     }
   126     if (path == NULL) {
   127         path = DEFAULT_OPENGL;
   128     }
   129     _this->gl_config.dll_handle = SDL_LoadObject(path);
   130     if (!_this->gl_config.dll_handle) {
   131         return -1;
   132     }
   133     SDL_strlcpy(_this->gl_config.driver_path, path,
   134                 SDL_arraysize(_this->gl_config.driver_path));
   135     return 0;
   136 }
   137 
   138 void *
   139 Cocoa_GL_GetProcAddress(_THIS, const char *proc)
   140 {
   141     return SDL_LoadFunction(_this->gl_config.dll_handle, proc);
   142 }
   143 
   144 void
   145 Cocoa_GL_UnloadLibrary(_THIS)
   146 {
   147     SDL_UnloadObject(_this->gl_config.dll_handle);
   148     _this->gl_config.dll_handle = NULL;
   149 }
   150 
   151 SDL_GLContext
   152 Cocoa_GL_CreateContext(_THIS, SDL_Window * window)
   153 {
   154     NSAutoreleasePool *pool;
   155     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   156     SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
   157     SDL_bool lion_or_later = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6;
   158     NSOpenGLPixelFormatAttribute attr[32];
   159     NSOpenGLPixelFormat *fmt;
   160     SDLOpenGLContext *context;
   161     NSOpenGLContext *share_context = nil;
   162     int i = 0;
   163     const char *glversion;
   164     int glversion_major;
   165     int glversion_minor;
   166 
   167     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
   168         SDL_SetError ("OpenGL ES is not supported on this platform");
   169         return NULL;
   170     }
   171     if ((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) && !lion_or_later) {
   172         SDL_SetError ("OpenGL Core Profile is not supported on this platform version");
   173         return NULL;
   174     }
   175 
   176     pool = [[NSAutoreleasePool alloc] init];
   177 
   178     /* specify a profile if we're on Lion (10.7) or later. */
   179     if (lion_or_later) {
   180         NSOpenGLPixelFormatAttribute profile = NSOpenGLProfileVersionLegacy;
   181         if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) {
   182             profile = NSOpenGLProfileVersion3_2Core;
   183         }
   184         attr[i++] = NSOpenGLPFAOpenGLProfile;
   185         attr[i++] = profile;
   186     }
   187 
   188     attr[i++] = NSOpenGLPFAColorSize;
   189     attr[i++] = SDL_BYTESPERPIXEL(display->current_mode.format)*8;
   190 
   191     attr[i++] = NSOpenGLPFADepthSize;
   192     attr[i++] = _this->gl_config.depth_size;
   193 
   194     if (_this->gl_config.double_buffer) {
   195         attr[i++] = NSOpenGLPFADoubleBuffer;
   196     }
   197 
   198     if (_this->gl_config.stereo) {
   199         attr[i++] = NSOpenGLPFAStereo;
   200     }
   201 
   202     if (_this->gl_config.stencil_size) {
   203         attr[i++] = NSOpenGLPFAStencilSize;
   204         attr[i++] = _this->gl_config.stencil_size;
   205     }
   206 
   207     if ((_this->gl_config.accum_red_size +
   208          _this->gl_config.accum_green_size +
   209          _this->gl_config.accum_blue_size +
   210          _this->gl_config.accum_alpha_size) > 0) {
   211         attr[i++] = NSOpenGLPFAAccumSize;
   212         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;
   213     }
   214 
   215     if (_this->gl_config.multisamplebuffers) {
   216         attr[i++] = NSOpenGLPFASampleBuffers;
   217         attr[i++] = _this->gl_config.multisamplebuffers;
   218     }
   219 
   220     if (_this->gl_config.multisamplesamples) {
   221         attr[i++] = NSOpenGLPFASamples;
   222         attr[i++] = _this->gl_config.multisamplesamples;
   223         attr[i++] = NSOpenGLPFANoRecovery;
   224     }
   225 
   226     if (_this->gl_config.accelerated >= 0) {
   227         if (_this->gl_config.accelerated) {
   228             attr[i++] = NSOpenGLPFAAccelerated;
   229         } else {
   230             attr[i++] = NSOpenGLPFARendererID;
   231             attr[i++] = kCGLRendererGenericFloatID;
   232         }
   233     }
   234 
   235     attr[i++] = NSOpenGLPFAScreenMask;
   236     attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display);
   237     attr[i] = 0;
   238 
   239     fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
   240     if (fmt == nil) {
   241         SDL_SetError("Failed creating OpenGL pixel format");
   242         [pool release];
   243         return NULL;
   244     }
   245 
   246     if (_this->gl_config.share_with_current_context) {
   247         share_context = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
   248     }
   249 
   250     context = [[SDLOpenGLContext alloc] initWithFormat:fmt shareContext:share_context];
   251 
   252     [fmt release];
   253 
   254     if (context == nil) {
   255         SDL_SetError("Failed creating OpenGL context");
   256         [pool release];
   257         return NULL;
   258     }
   259 
   260     [pool release];
   261 
   262     if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) {
   263         Cocoa_GL_DeleteContext(_this, context);
   264         SDL_SetError("Failed making OpenGL context current");
   265         return NULL;
   266     }
   267 
   268     if (_this->gl_config.major_version < 3 &&
   269         _this->gl_config.profile_mask == 0 &&
   270         _this->gl_config.flags == 0) {
   271         /* This is a legacy profile, so to match other backends, we're done. */
   272     } else {
   273         const GLubyte *(APIENTRY * glGetStringFunc)(GLenum);
   274 
   275         glGetStringFunc = (const GLubyte *(APIENTRY *)(GLenum)) SDL_GL_GetProcAddress("glGetString");
   276         if (!glGetStringFunc) {
   277             Cocoa_GL_DeleteContext(_this, context);
   278             SDL_SetError ("Failed getting OpenGL glGetString entry point");
   279             return NULL;
   280         }
   281 
   282         glversion = (const char *)glGetStringFunc(GL_VERSION);
   283         if (glversion == NULL) {
   284             Cocoa_GL_DeleteContext(_this, context);
   285             SDL_SetError ("Failed getting OpenGL context version");
   286             return NULL;
   287         }
   288 
   289         if (SDL_sscanf(glversion, "%d.%d", &glversion_major, &glversion_minor) != 2) {
   290             Cocoa_GL_DeleteContext(_this, context);
   291             SDL_SetError ("Failed parsing OpenGL context version");
   292             return NULL;
   293         }
   294 
   295         if ((glversion_major < _this->gl_config.major_version) ||
   296            ((glversion_major == _this->gl_config.major_version) && (glversion_minor < _this->gl_config.minor_version))) {
   297             Cocoa_GL_DeleteContext(_this, context);
   298             SDL_SetError ("Failed creating OpenGL context at version requested");
   299             return NULL;
   300         }
   301 
   302         /* In the future we'll want to do this, but to match other platforms
   303            we'll leave the OpenGL version the way it is for now
   304          */
   305         /*_this->gl_config.major_version = glversion_major;*/
   306         /*_this->gl_config.minor_version = glversion_minor;*/
   307     }
   308     return context;
   309 }
   310 
   311 int
   312 Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   313 {
   314     NSAutoreleasePool *pool;
   315 
   316     pool = [[NSAutoreleasePool alloc] init];
   317 
   318     if (context) {
   319         SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
   320         [nscontext setWindow:window];
   321         [nscontext updateIfNeeded];
   322         [nscontext makeCurrentContext];
   323     } else {
   324         [NSOpenGLContext clearCurrentContext];
   325     }
   326 
   327     [pool release];
   328     return 0;
   329 }
   330 
   331 void
   332 Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
   333 {
   334     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
   335     NSView *contentView = [windata->nswindow contentView];
   336     NSRect viewport = [contentView bounds];
   337 
   338     /* This gives us the correct viewport for a Retina-enabled view, only
   339      * supported on 10.7+. */
   340     if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) {
   341         viewport = [contentView convertRectToBacking:viewport];
   342     }
   343 
   344     if (w) {
   345         *w = viewport.size.width;
   346     }
   347 
   348     if (h) {
   349         *h = viewport.size.height;
   350     }
   351 }
   352 
   353 int
   354 Cocoa_GL_SetSwapInterval(_THIS, int interval)
   355 {
   356     NSAutoreleasePool *pool;
   357     NSOpenGLContext *nscontext;
   358     GLint value;
   359     int status;
   360 
   361     if (interval < 0) {  /* no extension for this on Mac OS X at the moment. */
   362         return SDL_SetError("Late swap tearing currently unsupported");
   363     }
   364 
   365     pool = [[NSAutoreleasePool alloc] init];
   366 
   367     nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
   368     if (nscontext != nil) {
   369         value = interval;
   370         [nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval];
   371         status = 0;
   372     } else {
   373         status = SDL_SetError("No current OpenGL context");
   374     }
   375 
   376     [pool release];
   377     return status;
   378 }
   379 
   380 int
   381 Cocoa_GL_GetSwapInterval(_THIS)
   382 {
   383     NSAutoreleasePool *pool;
   384     NSOpenGLContext *nscontext;
   385     GLint value;
   386     int status = 0;
   387 
   388     pool = [[NSAutoreleasePool alloc] init];
   389 
   390     nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
   391     if (nscontext != nil) {
   392         [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
   393         status = (int)value;
   394     }
   395 
   396     [pool release];
   397     return status;
   398 }
   399 
   400 void
   401 Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
   402 {
   403     NSAutoreleasePool *pool;
   404 
   405     pool = [[NSAutoreleasePool alloc] init];
   406 
   407     SDLOpenGLContext* nscontext = (SDLOpenGLContext*)SDL_GL_GetCurrentContext();
   408     [nscontext flushBuffer];
   409     [nscontext updateIfNeeded];
   410 
   411     [pool release];
   412 }
   413 
   414 void
   415 Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
   416 {
   417     NSAutoreleasePool *pool;
   418     SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
   419 
   420     pool = [[NSAutoreleasePool alloc] init];
   421 
   422     [nscontext setWindow:NULL];
   423     [nscontext release];
   424 
   425     [pool release];
   426 }
   427 
   428 #endif /* SDL_VIDEO_OPENGL_CGL */
   429 
   430 /* vi: set ts=4 sw=4 expandtab: */