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