src/video/cocoa/SDL_cocoaopengl.m
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Mon, 22 Apr 2013 12:07:16 -0700
changeset 7085 152cc7ddfa57
parent 7037 3fedf1f25b94
child 7108 732d2cac80c0
permissions -rw-r--r--
Mac no longer loses OpenGL context when window is hidden.

This fixes an issue that would arise when you minimize / order out an
OpenGL window on Mac, where the window would lose it's window device.
Without a window device, you cannot render to the window.

It does so by making two changes:
- Windows are no longer "oneShot" (which caused their window device to
get destroyed when they're minified or ordered out)
- Windows are no longer "deferred" (which caused the OS to defer
window device creation until the window is shown, which meant that
we couldn't properly makeCurrent to it)

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