src/video/cocoa/SDL_cocoaopengl.m
author Ryan C. Gordon <icculus@icculus.org>
Wed, 10 Oct 2012 23:10:04 -0400
changeset 6567 d50613615139
parent 6382 64d54101773a
child 6832 156e608ec4ef
permissions -rw-r--r--
Allow specifying of OpenGL 3.2 Core Profile on Mac OS X.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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_config.h"
    22 
    23 /* NSOpenGL implementation of SDL OpenGL support */
    24 
    25 #if SDL_VIDEO_OPENGL_CGL
    26 #include "SDL_cocoavideo.h"
    27 
    28 #include <OpenGL/CGLTypes.h>
    29 #include <OpenGL/OpenGL.h>
    30 #include <OpenGL/CGLRenderers.h>
    31 
    32 #include "SDL_loadso.h"
    33 #include "SDL_opengl.h"
    34 
    35 #define DEFAULT_OPENGL  "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
    36 
    37 
    38 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
    39 #define kCGLPFAOpenGLProfile 99
    40 #define kCGLOGLPVersion_Legacy 0x1000
    41 #define kCGLOGLPVersion_3_2_Core 0x3200
    42 #endif
    43 
    44 
    45 int
    46 Cocoa_GL_LoadLibrary(_THIS, const char *path)
    47 {
    48     /* Load the OpenGL library */
    49     if (path == NULL) {
    50         path = SDL_getenv("SDL_OPENGL_LIBRARY");
    51     }
    52     if (path == NULL) {
    53         path = DEFAULT_OPENGL;
    54     }
    55     _this->gl_config.dll_handle = SDL_LoadObject(path);
    56     if (!_this->gl_config.dll_handle) {
    57         return -1;
    58     }
    59     SDL_strlcpy(_this->gl_config.driver_path, path,
    60                 SDL_arraysize(_this->gl_config.driver_path));
    61     return 0;
    62 }
    63 
    64 void *
    65 Cocoa_GL_GetProcAddress(_THIS, const char *proc)
    66 {
    67     return SDL_LoadFunction(_this->gl_config.dll_handle, proc);
    68 }
    69 
    70 void
    71 Cocoa_GL_UnloadLibrary(_THIS)
    72 {
    73     SDL_UnloadObject(_this->gl_config.dll_handle);
    74     _this->gl_config.dll_handle = NULL;
    75 }
    76 
    77 SDL_GLContext
    78 Cocoa_GL_CreateContext(_THIS, SDL_Window * window)
    79 {
    80     const int wantver = (_this->gl_config.major_version << 8) |
    81                         (_this->gl_config.minor_version);
    82     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    83     NSAutoreleasePool *pool;
    84     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
    85     SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
    86     NSOpenGLPixelFormatAttribute attr[32];
    87     NSOpenGLPixelFormat *fmt;
    88     NSOpenGLContext *context;
    89     int i = 0;
    90 
    91     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
    92         SDL_SetError ("OpenGL ES not supported on this platform");
    93         return NULL;
    94     }
    95 
    96     /* Sadly, we'll have to update this as life progresses, since we need to
    97        set an enum for context profiles, not a context version number */
    98     if (wantver > 0x0302) {
    99         SDL_SetError ("OpenGL > 3.2 is not supported on this platform");
   100         return NULL;
   101     }
   102 
   103     pool = [[NSAutoreleasePool alloc] init];
   104 
   105     /* specify a profile if we're on Lion (10.7) or later. */
   106     if (data->osversion >= 0x1070) {
   107         NSOpenGLPixelFormatAttribute profile = kCGLOGLPVersion_Legacy;
   108         if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) {
   109             if (wantver == 0x0302) {
   110                 profile = kCGLOGLPVersion_3_2_Core;
   111             }
   112         }
   113         attr[i++] = kCGLPFAOpenGLProfile;
   114         attr[i++] = profile;
   115     }
   116 
   117 #ifndef FULLSCREEN_TOGGLEABLE
   118     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   119         attr[i++] = NSOpenGLPFAFullScreen;
   120     }
   121 #endif
   122 
   123     attr[i++] = NSOpenGLPFAColorSize;
   124     attr[i++] = SDL_BYTESPERPIXEL(display->current_mode.format)*8;
   125 
   126     attr[i++] = NSOpenGLPFADepthSize;
   127     attr[i++] = _this->gl_config.depth_size;
   128 
   129     if (_this->gl_config.double_buffer) {
   130         attr[i++] = NSOpenGLPFADoubleBuffer;
   131     }
   132 
   133     if (_this->gl_config.stereo) {
   134         attr[i++] = NSOpenGLPFAStereo;
   135     }
   136 
   137     if (_this->gl_config.stencil_size) {
   138         attr[i++] = NSOpenGLPFAStencilSize;
   139         attr[i++] = _this->gl_config.stencil_size;
   140     }
   141 
   142     if ((_this->gl_config.accum_red_size +
   143          _this->gl_config.accum_green_size +
   144          _this->gl_config.accum_blue_size +
   145          _this->gl_config.accum_alpha_size) > 0) {
   146         attr[i++] = NSOpenGLPFAAccumSize;
   147         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;
   148     }
   149 
   150     if (_this->gl_config.multisamplebuffers) {
   151         attr[i++] = NSOpenGLPFASampleBuffers;
   152         attr[i++] = _this->gl_config.multisamplebuffers;
   153     }
   154 
   155     if (_this->gl_config.multisamplesamples) {
   156         attr[i++] = NSOpenGLPFASamples;
   157         attr[i++] = _this->gl_config.multisamplesamples;
   158         attr[i++] = NSOpenGLPFANoRecovery;
   159     }
   160 
   161     if (_this->gl_config.accelerated >= 0) {
   162         if (_this->gl_config.accelerated) {
   163             attr[i++] = NSOpenGLPFAAccelerated;
   164         } else {
   165             attr[i++] = NSOpenGLPFARendererID;
   166             attr[i++] = kCGLRendererGenericFloatID;
   167         }
   168     }
   169 
   170     attr[i++] = NSOpenGLPFAScreenMask;
   171     attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display);
   172     attr[i] = 0;
   173 
   174     fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
   175     if (fmt == nil) {
   176         SDL_SetError ("Failed creating OpenGL pixel format");
   177         [pool release];
   178         return NULL;
   179     }
   180 
   181     context = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:nil];
   182 
   183     [fmt release];
   184 
   185     if (context == nil) {
   186         SDL_SetError ("Failed creating OpenGL context");
   187         [pool release];
   188         return NULL;
   189     }
   190 
   191     /*
   192      * Wisdom from Apple engineer in reference to UT2003's OpenGL performance:
   193      *  "You are blowing a couple of the internal OpenGL function caches. This
   194      *  appears to be happening in the VAO case.  You can tell OpenGL to up
   195      *  the cache size by issuing the following calls right after you create
   196      *  the OpenGL context.  The default cache size is 16."    --ryan.
   197      */
   198 
   199     #ifndef GLI_ARRAY_FUNC_CACHE_MAX
   200     #define GLI_ARRAY_FUNC_CACHE_MAX 284
   201     #endif
   202 
   203     #ifndef GLI_SUBMIT_FUNC_CACHE_MAX
   204     #define GLI_SUBMIT_FUNC_CACHE_MAX 280
   205     #endif
   206 
   207     {
   208         GLint cache_max = 64;
   209         CGLContextObj ctx = [context CGLContextObj];
   210         CGLSetParameter (ctx, GLI_SUBMIT_FUNC_CACHE_MAX, &cache_max);
   211         CGLSetParameter (ctx, GLI_ARRAY_FUNC_CACHE_MAX, &cache_max);
   212     }
   213 
   214     /* End Wisdom from Apple Engineer section. --ryan. */
   215 
   216     [pool release];
   217 
   218     if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) {
   219         Cocoa_GL_DeleteContext(_this, context);
   220         return NULL;
   221     }
   222 
   223     return context;
   224 }
   225 
   226 int
   227 Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   228 {
   229     NSAutoreleasePool *pool;
   230 
   231     pool = [[NSAutoreleasePool alloc] init];
   232 
   233     if (context) {
   234         SDL_WindowData *windowdata = (SDL_WindowData *)window->driverdata;
   235         NSOpenGLContext *nscontext = (NSOpenGLContext *)context;
   236 
   237         if (window->flags & SDL_WINDOW_SHOWN) {
   238 #ifndef FULLSCREEN_TOGGLEABLE
   239             if (window->flags & SDL_WINDOW_FULLSCREEN) {
   240                 [nscontext setFullScreen];
   241             } else
   242 #endif
   243             {
   244                 [nscontext setView:[windowdata->nswindow contentView]];
   245                 [nscontext update];
   246             }
   247         }
   248         [nscontext makeCurrentContext];
   249     } else {
   250         [NSOpenGLContext clearCurrentContext];
   251     }
   252 
   253     [pool release];
   254     return 0;
   255 }
   256 
   257 int
   258 Cocoa_GL_SetSwapInterval(_THIS, int interval)
   259 {
   260     NSAutoreleasePool *pool;
   261     NSOpenGLContext *nscontext;
   262     GLint value;
   263     int status;
   264 
   265     pool = [[NSAutoreleasePool alloc] init];
   266 
   267     nscontext = [NSOpenGLContext currentContext];
   268     if (nscontext != nil) {
   269         value = interval;
   270         [nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval];
   271         status = 0;
   272     } else {
   273         SDL_SetError("No current OpenGL context");
   274         status = -1;
   275     }
   276 
   277     [pool release];
   278     return status;
   279 }
   280 
   281 int
   282 Cocoa_GL_GetSwapInterval(_THIS)
   283 {
   284     NSAutoreleasePool *pool;
   285     NSOpenGLContext *nscontext;
   286     GLint value;
   287     int status = 0;
   288 
   289     pool = [[NSAutoreleasePool alloc] init];
   290 
   291     nscontext = [NSOpenGLContext currentContext];
   292     if (nscontext != nil) {
   293         [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
   294         status = (int)value;
   295     }
   296 
   297     [pool release];
   298     return status;
   299 }
   300 
   301 void
   302 Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
   303 {
   304     NSAutoreleasePool *pool;
   305     NSOpenGLContext *nscontext;
   306 
   307     pool = [[NSAutoreleasePool alloc] init];
   308 
   309     /* FIXME: Do we need to get the context for the window? */
   310     nscontext = [NSOpenGLContext currentContext];
   311     if (nscontext != nil) {
   312         [nscontext flushBuffer];
   313     }
   314 
   315     [pool release];
   316 }
   317 
   318 void
   319 Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
   320 {
   321     NSAutoreleasePool *pool;
   322     NSOpenGLContext *nscontext = (NSOpenGLContext *)context;
   323 
   324     pool = [[NSAutoreleasePool alloc] init];
   325 
   326     [nscontext clearDrawable];
   327     [nscontext release];
   328 
   329     [pool release];
   330 }
   331 
   332 #endif /* SDL_VIDEO_OPENGL_CGL */
   333 
   334 /* vi: set ts=4 sw=4 expandtab: */