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