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