src/video/cocoa/SDL_cocoaopengl.m
author Sam Lantinga <slouken@libsdl.org>
Mon, 08 Dec 2008 00:27:32 +0000
changeset 2859 99210400e8b9
parent 2738 79c1bd651f04
child 3057 089a77aebb7d
permissions -rw-r--r--
Updated copyright date
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_cocoavideo.h"
    25 
    26 /* NSOpenGL implementation of SDL OpenGL support */
    27 
    28 #if SDL_VIDEO_OPENGL_CGL
    29 #include <OpenGL/CGLTypes.h>
    30 #include <OpenGL/OpenGL.h>
    31 
    32 #include "SDL_loadso.h"
    33 #include "SDL_opengl.h"
    34 
    35 
    36 #define DEFAULT_OPENGL  "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
    37 
    38 /* This is implemented in Mac OS X 10.3 and above */
    39 #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3
    40 @implementation NSOpenGLContext(CGLContextAccess)
    41 - (CGLContextObj)CGLContextObj;
    42 {
    43     return _contextAuxiliary;
    44 }
    45 @end
    46 #endif /* < 10.3 */
    47 
    48 int
    49 Cocoa_GL_LoadLibrary(_THIS, const char *path)
    50 {
    51     if (_this->gl_config.driver_loaded) {
    52         if (path) {
    53             SDL_SetError("OpenGL library already loaded");
    54             return -1;
    55         } else {
    56             ++_this->gl_config.driver_loaded;
    57             return 0;
    58         }
    59     }
    60     if (path == NULL) {
    61         path = SDL_getenv("SDL_OPENGL_LIBRARY");
    62     }
    63     if (path == NULL) {
    64         path = DEFAULT_OPENGL;
    65     }
    66     _this->gl_config.dll_handle = SDL_LoadObject(path);
    67     if (!_this->gl_config.dll_handle) {
    68         return -1;
    69     }
    70     SDL_strlcpy(_this->gl_config.driver_path, path,
    71                 SDL_arraysize(_this->gl_config.driver_path));
    72     _this->gl_config.driver_loaded = 1;
    73     return 0;
    74 }
    75 
    76 void *
    77 Cocoa_GL_GetProcAddress(_THIS, const char *proc)
    78 {
    79     return SDL_LoadFunction(_this->gl_config.dll_handle, proc);
    80 }
    81 
    82 static void
    83 Cocoa_GL_UnloadLibrary(_THIS)
    84 {
    85     if (_this->gl_config.driver_loaded > 0) {
    86         if (--_this->gl_config.driver_loaded > 0) {
    87             return;
    88         }
    89         SDL_UnloadObject(_this->gl_config.dll_handle);
    90         _this->gl_config.dll_handle = NULL;
    91     }
    92 }
    93 
    94 static int
    95 Cocoa_GL_Initialize(_THIS)
    96 {
    97     if (_this->gl_data) {
    98         ++_this->gl_data->initialized;
    99         return 0;
   100     }
   101 
   102     _this->gl_data =
   103         (struct SDL_GLDriverData *) SDL_calloc(1,
   104                                                sizeof(struct
   105                                                       SDL_GLDriverData));
   106     if (!_this->gl_data) {
   107         SDL_OutOfMemory();
   108         return -1;
   109     }
   110     _this->gl_data->initialized = 1;
   111 
   112     if (Cocoa_GL_LoadLibrary(_this, NULL) < 0) {
   113         return -1;
   114     }
   115     return 0;
   116 }
   117 
   118 static void
   119 Cocoa_GL_Shutdown(_THIS)
   120 {
   121     if (!_this->gl_data || (--_this->gl_data->initialized > 0)) {
   122         return;
   123     }
   124 
   125     Cocoa_GL_UnloadLibrary(_this);
   126 
   127     SDL_free(_this->gl_data);
   128     _this->gl_data = NULL;
   129 }
   130 
   131 int
   132 Cocoa_GL_SetupWindow(_THIS, SDL_Window * window)
   133 {
   134     if (Cocoa_GL_Initialize(_this) < 0) {
   135         return -1;
   136     }
   137     return 0;
   138 }
   139 
   140 void
   141 Cocoa_GL_CleanupWindow(_THIS, SDL_Window * window)
   142 {
   143     Cocoa_GL_Shutdown(_this);
   144 }
   145 
   146 SDL_GLContext
   147 Cocoa_GL_CreateContext(_THIS, SDL_Window * window)
   148 {
   149     NSAutoreleasePool *pool;
   150     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   151     SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
   152     NSOpenGLPixelFormatAttribute attr[32];
   153     NSOpenGLPixelFormat *fmt;
   154     NSOpenGLContext *context;
   155     int i = 0;
   156 
   157     pool = [[NSAutoreleasePool alloc] init];
   158 
   159     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   160         attr[i++] = NSOpenGLPFAFullScreen;
   161     }
   162 
   163     attr[i++] = NSOpenGLPFAColorSize;
   164     attr[i++] = SDL_BYTESPERPIXEL(display->current_mode.format)*8;
   165 
   166     attr[i++] = NSOpenGLPFADepthSize;
   167     attr[i++] = _this->gl_config.depth_size;
   168 
   169     if (_this->gl_config.double_buffer) {
   170         attr[i++] = NSOpenGLPFADoubleBuffer;
   171     }
   172 
   173     if (_this->gl_config.stereo) {
   174         attr[i++] = NSOpenGLPFAStereo;
   175     }
   176 
   177     if (_this->gl_config.stencil_size) {
   178         attr[i++] = NSOpenGLPFAStencilSize;
   179         attr[i++] = _this->gl_config.stencil_size;
   180     }
   181 
   182     if ((_this->gl_config.accum_red_size +
   183          _this->gl_config.accum_green_size +
   184          _this->gl_config.accum_blue_size +
   185          _this->gl_config.accum_alpha_size) > 0) {
   186         attr[i++] = NSOpenGLPFAAccumSize;
   187         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;
   188     }
   189 
   190     if (_this->gl_config.multisamplebuffers) {
   191         attr[i++] = NSOpenGLPFASampleBuffers;
   192         attr[i++] = _this->gl_config.multisamplebuffers;
   193     }
   194 
   195     if (_this->gl_config.multisamplesamples) {
   196         attr[i++] = NSOpenGLPFASamples;
   197         attr[i++] = _this->gl_config.multisamplesamples;
   198         attr[i++] = NSOpenGLPFANoRecovery;
   199     }
   200 
   201     if (_this->gl_config.accelerated > 0) {
   202         attr[i++] = NSOpenGLPFAAccelerated;
   203     }
   204 
   205     attr[i++] = NSOpenGLPFAScreenMask;
   206     attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display);
   207     attr[i] = 0;
   208 
   209     fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
   210     if (fmt == nil) {
   211         SDL_SetError ("Failed creating OpenGL pixel format");
   212         [pool release];
   213         return NULL;
   214     }
   215 
   216     context = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:nil];
   217 
   218     [fmt release];
   219 
   220     if (context == nil) {
   221         SDL_SetError ("Failed creating OpenGL context");
   222         [pool release];
   223         return NULL;
   224     }
   225 
   226     /*
   227      * Wisdom from Apple engineer in reference to UT2003's OpenGL performance:
   228      *  "You are blowing a couple of the internal OpenGL function caches. This
   229      *  appears to be happening in the VAO case.  You can tell OpenGL to up
   230      *  the cache size by issuing the following calls right after you create
   231      *  the OpenGL context.  The default cache size is 16."    --ryan.
   232      */
   233 
   234     #ifndef GLI_ARRAY_FUNC_CACHE_MAX
   235     #define GLI_ARRAY_FUNC_CACHE_MAX 284
   236     #endif
   237 
   238     #ifndef GLI_SUBMIT_FUNC_CACHE_MAX
   239     #define GLI_SUBMIT_FUNC_CACHE_MAX 280
   240     #endif
   241 
   242     {
   243         long cache_max = 64;
   244         CGLContextObj ctx = [context CGLContextObj];
   245         CGLSetParameter (ctx, GLI_SUBMIT_FUNC_CACHE_MAX, &cache_max);
   246         CGLSetParameter (ctx, GLI_ARRAY_FUNC_CACHE_MAX, &cache_max);
   247     }
   248 
   249     /* End Wisdom from Apple Engineer section. --ryan. */
   250 
   251     [pool release];
   252 
   253     if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) {
   254         Cocoa_GL_DeleteContext(_this, context);
   255         return NULL;
   256     }
   257 
   258     return context;
   259 }
   260 
   261 int
   262 Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   263 {
   264     NSAutoreleasePool *pool;
   265 
   266     pool = [[NSAutoreleasePool alloc] init];
   267 
   268     if (context) {
   269         SDL_WindowData *windowdata = (SDL_WindowData *)window->driverdata;
   270         NSOpenGLContext *nscontext = (NSOpenGLContext *)context;
   271 
   272         if (window->flags & SDL_WINDOW_FULLSCREEN) {
   273             [nscontext setFullScreen];
   274         } else {
   275             [nscontext setView:[windowdata->window contentView]];
   276             [nscontext update];
   277         }
   278         [nscontext makeCurrentContext];
   279     } else {
   280         [NSOpenGLContext clearCurrentContext];
   281     }
   282 
   283     [pool release];
   284     return 0;
   285 }
   286 
   287 int
   288 Cocoa_GL_SetSwapInterval(_THIS, int interval)
   289 {
   290     NSAutoreleasePool *pool;
   291     NSOpenGLContext *nscontext;
   292     GLint value;
   293     int status;
   294 
   295     pool = [[NSAutoreleasePool alloc] init];
   296 
   297     nscontext = [NSOpenGLContext currentContext];
   298     if (nscontext != nil) {
   299         value = interval;
   300         [nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval];
   301         status = 0;
   302     } else {
   303         SDL_SetError("No current OpenGL context");
   304         status = -1;
   305     }
   306 
   307     [pool release];
   308     return status;
   309 }
   310 
   311 int
   312 Cocoa_GL_GetSwapInterval(_THIS)
   313 {
   314     NSAutoreleasePool *pool;
   315     NSOpenGLContext *nscontext;
   316     GLint value;
   317     int status;
   318 
   319     pool = [[NSAutoreleasePool alloc] init];
   320 
   321     nscontext = [NSOpenGLContext currentContext];
   322     if (nscontext != nil) {
   323         [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
   324         status = (int)value;
   325     } else {
   326         SDL_SetError("No current OpenGL context");
   327         status = -1;
   328     }
   329 
   330     [pool release];
   331     return status;
   332 }
   333 
   334 void
   335 Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
   336 {
   337     NSAutoreleasePool *pool;
   338     NSOpenGLContext *nscontext;
   339 
   340     pool = [[NSAutoreleasePool alloc] init];
   341 
   342     /* FIXME: Do we need to get the context for the window? */
   343     nscontext = [NSOpenGLContext currentContext];
   344     if (nscontext != nil) {
   345         [nscontext flushBuffer];
   346     }
   347 
   348     [pool release];
   349 }
   350 
   351 void
   352 Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
   353 {
   354     NSAutoreleasePool *pool;
   355     NSOpenGLContext *nscontext = (NSOpenGLContext *)context;
   356 
   357     pool = [[NSAutoreleasePool alloc] init];
   358 
   359     [nscontext clearDrawable];
   360     [nscontext release];
   361 
   362     [pool release];
   363 }
   364 
   365 #endif /* SDL_VIDEO_OPENGL_CGL */
   366 
   367 /* vi: set ts=4 sw=4 expandtab: */