src/video/cocoa/SDL_cocoaopengl.m
author Sam Lantinga <slouken@libsdl.org>
Fri, 27 Dec 2013 10:18:11 -0800
changeset 8083 3782a12331d6
parent 7897 622d75108e60
child 8093 b43765095a6f
permissions -rw-r--r--
Bump SDL to build with 10.7 SDK.

This also bumps the minimum requirement for building SDL to 10.7, and
removes some checking we no longer need.

CR: saml
     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 #include "SDL_cocoaopengl.h"
    28 
    29 #include <OpenGL/CGLTypes.h>
    30 #include <OpenGL/OpenGL.h>
    31 #include <OpenGL/CGLRenderers.h>
    32 
    33 #include "SDL_loadso.h"
    34 #include "SDL_opengl.h"
    35 
    36 #define DEFAULT_OPENGL  "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
    37 
    38 #ifndef kCGLPFAOpenGLProfile
    39 #define kCGLPFAOpenGLProfile 99
    40 #endif
    41 #ifndef kCGLOGLPVersion_Legacy
    42 #define kCGLOGLPVersion_Legacy 0x1000
    43 #endif
    44 #ifndef kCGLOGLPVersion_GL3_Core
    45 #define kCGLOGLPVersion_GL3_Core 0x3200
    46 #endif
    47 #ifndef kCGLOGLPVersion_GL4_Core
    48 #define kCGLOGLPVersion_GL4_Core 0x4100
    49 #endif
    50 
    51 @implementation SDLOpenGLContext : NSOpenGLContext
    52 
    53 - (id)initWithFormat:(NSOpenGLPixelFormat *)format
    54         shareContext:(NSOpenGLContext *)share
    55 {
    56     self = [super initWithFormat:format shareContext:share];
    57     if (self) {
    58         SDL_AtomicSet(&self->dirty, 0);
    59         self->window = NULL;
    60     }
    61     return self;
    62 }
    63 
    64 - (void)scheduleUpdate
    65 {
    66     SDL_AtomicAdd(&self->dirty, 1);
    67 }
    68 
    69 /* This should only be called on the thread on which a user is using the context. */
    70 - (void)updateIfNeeded
    71 {
    72     int value = SDL_AtomicSet(&self->dirty, 0);
    73     if (value > 0) {
    74         /* We call the real underlying update here, since -[SDLOpenGLContext update] just calls us. */
    75         [super update];
    76     }
    77 }
    78 
    79 /* This should only be called on the thread on which a user is using the context. */
    80 - (void)update
    81 {
    82     /* This ensures that regular 'update' calls clear the atomic dirty flag. */
    83     [self scheduleUpdate];
    84     [self updateIfNeeded];
    85 }
    86 
    87 /* Updates the drawable for the contexts and manages related state. */
    88 - (void)setWindow:(SDL_Window *)newWindow
    89 {
    90     if (self->window) {
    91         SDL_WindowData *oldwindowdata = (SDL_WindowData *)self->window->driverdata;
    92 
    93         /* Make sure to remove us from the old window's context list, or we'll get scheduled updates from it too. */
    94         NSMutableArray *contexts = oldwindowdata->nscontexts;
    95         @synchronized (contexts) {
    96             [contexts removeObject:self];
    97         }
    98     }
    99 
   100     self->window = newWindow;
   101 
   102     if (newWindow) {
   103         SDL_WindowData *windowdata = (SDL_WindowData *)newWindow->driverdata;
   104 
   105         /* Now sign up for scheduled updates for the new window. */
   106         NSMutableArray *contexts = windowdata->nscontexts;
   107         @synchronized (contexts) {
   108             [contexts addObject:self];
   109         }
   110 
   111         if ([self view] != [windowdata->nswindow contentView]) {
   112             [self setView:[windowdata->nswindow contentView]];
   113             [self scheduleUpdate];
   114         }
   115     } else {
   116         [self clearDrawable];
   117         [self scheduleUpdate];
   118     }
   119 }
   120 
   121 @end
   122 
   123 
   124 int
   125 Cocoa_GL_LoadLibrary(_THIS, const char *path)
   126 {
   127     /* Load the OpenGL library */
   128     if (path == NULL) {
   129         path = SDL_getenv("SDL_OPENGL_LIBRARY");
   130     }
   131     if (path == NULL) {
   132         path = DEFAULT_OPENGL;
   133     }
   134     _this->gl_config.dll_handle = SDL_LoadObject(path);
   135     if (!_this->gl_config.dll_handle) {
   136         return -1;
   137     }
   138     SDL_strlcpy(_this->gl_config.driver_path, path,
   139                 SDL_arraysize(_this->gl_config.driver_path));
   140     return 0;
   141 }
   142 
   143 void *
   144 Cocoa_GL_GetProcAddress(_THIS, const char *proc)
   145 {
   146     return SDL_LoadFunction(_this->gl_config.dll_handle, proc);
   147 }
   148 
   149 void
   150 Cocoa_GL_UnloadLibrary(_THIS)
   151 {
   152     SDL_UnloadObject(_this->gl_config.dll_handle);
   153     _this->gl_config.dll_handle = NULL;
   154 }
   155 
   156 SDL_GLContext
   157 Cocoa_GL_CreateContext(_THIS, SDL_Window * window)
   158 {
   159     const int wantver = (_this->gl_config.major_version << 8) |
   160                         (_this->gl_config.minor_version);
   161     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   162     NSAutoreleasePool *pool;
   163     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   164     SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
   165     NSOpenGLPixelFormatAttribute attr[32];
   166     NSOpenGLPixelFormat *fmt;
   167     SDLOpenGLContext *context;
   168     NSOpenGLContext *share_context = nil;
   169     int i = 0;
   170 
   171     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
   172         SDL_SetError ("OpenGL ES is not supported on this platform");
   173         return NULL;
   174     }
   175 
   176     /* Sadly, we'll have to update this as life progresses, since we need to
   177        set an enum for context profiles, not a context version number */
   178     if (wantver > 0x0401) {
   179         SDL_SetError ("OpenGL > 4.1 is not supported on this platform");
   180         return NULL;
   181     }
   182 
   183     pool = [[NSAutoreleasePool alloc] init];
   184 
   185     /* specify a profile if we're on Lion (10.7) or later. */
   186     if (data->osversion >= 0x1070) {
   187         NSOpenGLPixelFormatAttribute profile = kCGLOGLPVersion_Legacy;
   188         if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) {
   189             if (wantver == 0x0302) {
   190                 profile = kCGLOGLPVersion_GL3_Core;
   191             } else if ((wantver == 0x0401) && (data->osversion >= 0x1090)) {
   192                 profile = kCGLOGLPVersion_GL4_Core;
   193             } else {
   194                 SDL_SetError("Requested GL version is not supported on this platform");
   195                 [pool release];
   196                 return NULL;
   197             }
   198         }
   199         attr[i++] = kCGLPFAOpenGLProfile;
   200         attr[i++] = profile;
   201     }
   202 
   203     attr[i++] = NSOpenGLPFAColorSize;
   204     attr[i++] = SDL_BYTESPERPIXEL(display->current_mode.format)*8;
   205 
   206     attr[i++] = NSOpenGLPFADepthSize;
   207     attr[i++] = _this->gl_config.depth_size;
   208 
   209     if (_this->gl_config.double_buffer) {
   210         attr[i++] = NSOpenGLPFADoubleBuffer;
   211     }
   212 
   213     if (_this->gl_config.stereo) {
   214         attr[i++] = NSOpenGLPFAStereo;
   215     }
   216 
   217     if (_this->gl_config.stencil_size) {
   218         attr[i++] = NSOpenGLPFAStencilSize;
   219         attr[i++] = _this->gl_config.stencil_size;
   220     }
   221 
   222     if ((_this->gl_config.accum_red_size +
   223          _this->gl_config.accum_green_size +
   224          _this->gl_config.accum_blue_size +
   225          _this->gl_config.accum_alpha_size) > 0) {
   226         attr[i++] = NSOpenGLPFAAccumSize;
   227         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;
   228     }
   229 
   230     if (_this->gl_config.multisamplebuffers) {
   231         attr[i++] = NSOpenGLPFASampleBuffers;
   232         attr[i++] = _this->gl_config.multisamplebuffers;
   233     }
   234 
   235     if (_this->gl_config.multisamplesamples) {
   236         attr[i++] = NSOpenGLPFASamples;
   237         attr[i++] = _this->gl_config.multisamplesamples;
   238         attr[i++] = NSOpenGLPFANoRecovery;
   239     }
   240 
   241     if (_this->gl_config.accelerated >= 0) {
   242         if (_this->gl_config.accelerated) {
   243             attr[i++] = NSOpenGLPFAAccelerated;
   244         } else {
   245             attr[i++] = NSOpenGLPFARendererID;
   246             attr[i++] = kCGLRendererGenericFloatID;
   247         }
   248     }
   249 
   250     attr[i++] = NSOpenGLPFAScreenMask;
   251     attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display);
   252     attr[i] = 0;
   253 
   254     fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
   255     if (fmt == nil) {
   256         SDL_SetError ("Failed creating OpenGL pixel format");
   257         [pool release];
   258         return NULL;
   259     }
   260 
   261     if (_this->gl_config.share_with_current_context) {
   262         share_context = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
   263     }
   264 
   265     context = [[SDLOpenGLContext alloc] initWithFormat:fmt shareContext:share_context];
   266 
   267     [fmt release];
   268 
   269     if (context == nil) {
   270         SDL_SetError ("Failed creating OpenGL context");
   271         [pool release];
   272         return NULL;
   273     }
   274 
   275     [pool release];
   276 
   277     if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) {
   278         Cocoa_GL_DeleteContext(_this, context);
   279         return NULL;
   280     }
   281 
   282     return context;
   283 }
   284 
   285 int
   286 Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   287 {
   288     NSAutoreleasePool *pool;
   289 
   290     pool = [[NSAutoreleasePool alloc] init];
   291 
   292     if (context) {
   293         SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
   294         [nscontext setWindow:window];
   295         [nscontext updateIfNeeded];
   296         [nscontext makeCurrentContext];
   297     } else {
   298         [NSOpenGLContext clearCurrentContext];
   299     }
   300 
   301     [pool release];
   302     return 0;
   303 }
   304 
   305 void
   306 Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
   307 {
   308     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
   309     NSView *contentView = [windata->nswindow contentView];
   310     NSRect viewport = [contentView bounds];
   311 
   312     /* This gives us the correct viewport for a Retina-enabled view, only
   313      * supported on 10.7+. */
   314     if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) {
   315         viewport = [contentView convertRectToBacking:viewport];
   316     }
   317 
   318     if (w) {
   319         *w = viewport.size.width;
   320     }
   321 
   322     if (h) {
   323         *h = viewport.size.height;
   324     }
   325 }
   326 
   327 int
   328 Cocoa_GL_SetSwapInterval(_THIS, int interval)
   329 {
   330     NSAutoreleasePool *pool;
   331     NSOpenGLContext *nscontext;
   332     GLint value;
   333     int status;
   334 
   335     if (interval < 0) {  /* no extension for this on Mac OS X at the moment. */
   336         return SDL_SetError("Late swap tearing currently unsupported");
   337     }
   338 
   339     pool = [[NSAutoreleasePool alloc] init];
   340 
   341     nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
   342     if (nscontext != nil) {
   343         value = interval;
   344         [nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval];
   345         status = 0;
   346     } else {
   347         status = SDL_SetError("No current OpenGL context");
   348     }
   349 
   350     [pool release];
   351     return status;
   352 }
   353 
   354 int
   355 Cocoa_GL_GetSwapInterval(_THIS)
   356 {
   357     NSAutoreleasePool *pool;
   358     NSOpenGLContext *nscontext;
   359     GLint value;
   360     int status = 0;
   361 
   362     pool = [[NSAutoreleasePool alloc] init];
   363 
   364     nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
   365     if (nscontext != nil) {
   366         [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
   367         status = (int)value;
   368     }
   369 
   370     [pool release];
   371     return status;
   372 }
   373 
   374 void
   375 Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
   376 {
   377     NSAutoreleasePool *pool;
   378 
   379     pool = [[NSAutoreleasePool alloc] init];
   380 
   381     SDLOpenGLContext* nscontext = (SDLOpenGLContext*)SDL_GL_GetCurrentContext();
   382     [nscontext flushBuffer];
   383     [nscontext updateIfNeeded];
   384 
   385     [pool release];
   386 }
   387 
   388 void
   389 Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
   390 {
   391     NSAutoreleasePool *pool;
   392     SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
   393 
   394     pool = [[NSAutoreleasePool alloc] init];
   395 
   396     [nscontext setWindow:NULL];
   397     [nscontext release];
   398 
   399     [pool release];
   400 }
   401 
   402 #endif /* SDL_VIDEO_OPENGL_CGL */
   403 
   404 /* vi: set ts=4 sw=4 expandtab: */