src/video/cocoa/SDL_cocoaopengl.m
author stopiccot <alexey.petruchik@gmail.com>
Sun, 06 Jan 2013 19:04:53 +0300
changeset 6832 156e608ec4ef
parent 6567 d50613615139
child 6848 478ecc8a58b3
permissions -rw-r--r--
Replaced manual NSAutoreleasePool handing with @autorelease
     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     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
    84     SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
    85     NSOpenGLPixelFormatAttribute attr[32];
    86     NSOpenGLPixelFormat *fmt;
    87     NSOpenGLContext *context;
    88     int i = 0;
    89 
    90     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
    91         SDL_SetError ("OpenGL ES not supported on this platform");
    92         return NULL;
    93     }
    94 
    95     /* Sadly, we'll have to update this as life progresses, since we need to
    96        set an enum for context profiles, not a context version number */
    97     if (wantver > 0x0302) {
    98         SDL_SetError ("OpenGL > 3.2 is not supported on this platform");
    99         return NULL;
   100     }
   101 
   102     @autoreleasepool {
   103         /* specify a profile if we're on Lion (10.7) or later. */
   104         if (data->osversion >= 0x1070) {
   105             NSOpenGLPixelFormatAttribute profile = kCGLOGLPVersion_Legacy;
   106             if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) {
   107                 if (wantver == 0x0302) {
   108                     profile = kCGLOGLPVersion_3_2_Core;
   109                 }
   110             }
   111             attr[i++] = kCGLPFAOpenGLProfile;
   112             attr[i++] = profile;
   113         }
   114 
   115     #ifndef FULLSCREEN_TOGGLEABLE
   116         if (window->flags & SDL_WINDOW_FULLSCREEN) {
   117             attr[i++] = NSOpenGLPFAFullScreen;
   118         }
   119     #endif
   120 
   121         attr[i++] = NSOpenGLPFAColorSize;
   122         attr[i++] = SDL_BYTESPERPIXEL(display->current_mode.format)*8;
   123 
   124         attr[i++] = NSOpenGLPFADepthSize;
   125         attr[i++] = _this->gl_config.depth_size;
   126 
   127         if (_this->gl_config.double_buffer) {
   128             attr[i++] = NSOpenGLPFADoubleBuffer;
   129         }
   130 
   131         if (_this->gl_config.stereo) {
   132             attr[i++] = NSOpenGLPFAStereo;
   133         }
   134 
   135         if (_this->gl_config.stencil_size) {
   136             attr[i++] = NSOpenGLPFAStencilSize;
   137             attr[i++] = _this->gl_config.stencil_size;
   138         }
   139 
   140         if ((_this->gl_config.accum_red_size +
   141              _this->gl_config.accum_green_size +
   142              _this->gl_config.accum_blue_size +
   143              _this->gl_config.accum_alpha_size) > 0) {
   144             attr[i++] = NSOpenGLPFAAccumSize;
   145             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;
   146         }
   147 
   148         if (_this->gl_config.multisamplebuffers) {
   149             attr[i++] = NSOpenGLPFASampleBuffers;
   150             attr[i++] = _this->gl_config.multisamplebuffers;
   151         }
   152 
   153         if (_this->gl_config.multisamplesamples) {
   154             attr[i++] = NSOpenGLPFASamples;
   155             attr[i++] = _this->gl_config.multisamplesamples;
   156             attr[i++] = NSOpenGLPFANoRecovery;
   157         }
   158 
   159         if (_this->gl_config.accelerated >= 0) {
   160             if (_this->gl_config.accelerated) {
   161                 attr[i++] = NSOpenGLPFAAccelerated;
   162             } else {
   163                 attr[i++] = NSOpenGLPFARendererID;
   164                 attr[i++] = kCGLRendererGenericFloatID;
   165             }
   166         }
   167 
   168         attr[i++] = NSOpenGLPFAScreenMask;
   169         attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display);
   170         attr[i] = 0;
   171 
   172         fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
   173         if (fmt == nil) {
   174             SDL_SetError ("Failed creating OpenGL pixel format");
   175             return NULL;
   176         }
   177 
   178         context = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:nil];
   179 
   180         [fmt release];
   181 
   182         if (context == nil) {
   183             SDL_SetError ("Failed creating OpenGL context");
   184             return NULL;
   185         }
   186 
   187         /*
   188          * Wisdom from Apple engineer in reference to UT2003's OpenGL performance:
   189          *  "You are blowing a couple of the internal OpenGL function caches. This
   190          *  appears to be happening in the VAO case.  You can tell OpenGL to up
   191          *  the cache size by issuing the following calls right after you create
   192          *  the OpenGL context.  The default cache size is 16."    --ryan.
   193          */
   194 
   195         #ifndef GLI_ARRAY_FUNC_CACHE_MAX
   196         #define GLI_ARRAY_FUNC_CACHE_MAX 284
   197         #endif
   198 
   199         #ifndef GLI_SUBMIT_FUNC_CACHE_MAX
   200         #define GLI_SUBMIT_FUNC_CACHE_MAX 280
   201         #endif
   202 
   203         {
   204             GLint cache_max = 64;
   205             CGLContextObj ctx = [context CGLContextObj];
   206             CGLSetParameter (ctx, GLI_SUBMIT_FUNC_CACHE_MAX, &cache_max);
   207             CGLSetParameter (ctx, GLI_ARRAY_FUNC_CACHE_MAX, &cache_max);
   208         }
   209     }
   210     /* End Wisdom from Apple Engineer section. --ryan. */
   211 
   212     if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) {
   213         Cocoa_GL_DeleteContext(_this, context);
   214         return NULL;
   215     }
   216 
   217     return context;
   218 }
   219 
   220 int
   221 Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   222 {
   223     @autoreleasepool {
   224         if (context) {
   225             SDL_WindowData *windowdata = (SDL_WindowData *)window->driverdata;
   226             NSOpenGLContext *nscontext = (NSOpenGLContext *)context;
   227 
   228             if (window->flags & SDL_WINDOW_SHOWN) {
   229     #ifndef FULLSCREEN_TOGGLEABLE
   230                 if (window->flags & SDL_WINDOW_FULLSCREEN) {
   231                     [nscontext setFullScreen];
   232                 } else
   233     #endif
   234                 {
   235                     [nscontext setView:[windowdata->nswindow contentView]];
   236                     [nscontext update];
   237                 }
   238             }
   239             [nscontext makeCurrentContext];
   240         } else {
   241             [NSOpenGLContext clearCurrentContext];
   242         }
   243     }
   244 
   245     return 0;
   246 }
   247 
   248 int
   249 Cocoa_GL_SetSwapInterval(_THIS, int interval)
   250 {
   251     NSOpenGLContext *nscontext;
   252     GLint value;
   253     int status;
   254 
   255     @autoreleasepool {
   256         nscontext = [NSOpenGLContext currentContext];
   257         if (nscontext != nil) {
   258             value = interval;
   259             [nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval];
   260             status = 0;
   261         } else {
   262             SDL_SetError("No current OpenGL context");
   263             status = -1;
   264         }
   265     }
   266 
   267     return status;
   268 }
   269 
   270 int
   271 Cocoa_GL_GetSwapInterval(_THIS)
   272 {
   273     NSOpenGLContext *nscontext;
   274     GLint value;
   275     int status = 0;
   276 
   277     @autoreleasepool {
   278         nscontext = [NSOpenGLContext currentContext];
   279         if (nscontext != nil) {
   280             [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
   281             status = (int)value;
   282         }
   283     }
   284 
   285     return status;
   286 }
   287 
   288 void
   289 Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
   290 {
   291     NSOpenGLContext *nscontext;
   292 
   293     @autoreleasepool {
   294         /* FIXME: Do we need to get the context for the window? */
   295         nscontext = [NSOpenGLContext currentContext];
   296         if (nscontext != nil) {
   297             [nscontext flushBuffer];
   298         }
   299     }
   300 }
   301 
   302 void
   303 Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
   304 {
   305     NSOpenGLContext *nscontext = (NSOpenGLContext *)context;
   306 
   307     @autoreleasepool {
   308         [nscontext clearDrawable];
   309         [nscontext release];
   310     }
   311 }
   312 
   313 #endif /* SDL_VIDEO_OPENGL_CGL */
   314 
   315 /* vi: set ts=4 sw=4 expandtab: */