Home | History | Annotate | Download | only in quartz
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012  Sam Lantinga
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Library General Public
      7     License as published by the Free Software Foundation; either
      8     version 2 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Library General Public License for more details.
     14 
     15     You should have received a copy of the GNU Library General Public
     16     License along with this library; if not, write to the Free
     17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     18 
     19     Sam Lantinga
     20     slouken (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 #include "SDL_QuartzVideo.h"
     25 
     26 /*
     27  * GL_ARB_Multisample is supposed to be available in 10.1, according to Apple:
     28  *
     29  *   http://developer.apple.com/graphicsimaging/opengl/extensions.html#GL_ARB_multisample
     30  *
     31  *  ...but it isn't in the system headers, according to Sam:
     32  *
     33  *   http://lists.libsdl.org/pipermail/sdl-libsdl.org/2003-December/039794.html
     34  *
     35  * These are normally enums and not #defines in the system headers.
     36  *
     37  *   --ryan.
     38  */
     39 #if (MAC_OS_X_VERSION_MAX_ALLOWED < 1020)
     40 #define NSOpenGLPFASampleBuffers ((NSOpenGLPixelFormatAttribute) 55)
     41 #define NSOpenGLPFASamples ((NSOpenGLPixelFormatAttribute) 56)
     42 #endif
     43 
     44 #ifdef __powerpc__   /* we lost this in 10.6, which has no PPC support. */
     45 @implementation NSOpenGLContext (CGLContextAccess)
     46 - (CGLContextObj) cglContext;
     47 {
     48     return _contextAuxiliary;
     49 }
     50 @end
     51 CGLContextObj QZ_GetCGLContextObj(NSOpenGLContext *nsctx)
     52 {
     53     return [nsctx cglContext];
     54 }
     55 #else
     56 CGLContextObj QZ_GetCGLContextObj(NSOpenGLContext *nsctx)
     57 {
     58     return (CGLContextObj) [nsctx CGLContextObj];
     59 }
     60 #endif
     61 
     62 
     63 /* OpenGL helper functions (used internally) */
     64 
     65 int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) {
     66 
     67     NSOpenGLPixelFormatAttribute attr[32];
     68     NSOpenGLPixelFormat *fmt;
     69     int i = 0;
     70     int colorBits = bpp;
     71 
     72     /* if a GL library hasn't been loaded at this point, load the default. */
     73     if (!this->gl_config.driver_loaded) {
     74         if (QZ_GL_LoadLibrary(this, NULL) == -1)
     75             return 0;
     76     }
     77 
     78     if ( flags & SDL_FULLSCREEN ) {
     79 
     80         attr[i++] = NSOpenGLPFAFullScreen;
     81     }
     82     /* In windowed mode, the OpenGL pixel depth must match device pixel depth */
     83     else if ( colorBits != device_bpp ) {
     84 
     85         colorBits = device_bpp;
     86     }
     87 
     88     attr[i++] = NSOpenGLPFAColorSize;
     89     attr[i++] = colorBits;
     90 
     91     attr[i++] = NSOpenGLPFADepthSize;
     92     attr[i++] = this->gl_config.depth_size;
     93 
     94     if ( this->gl_config.double_buffer ) {
     95         attr[i++] = NSOpenGLPFADoubleBuffer;
     96     }
     97 
     98     if ( this->gl_config.stereo ) {
     99         attr[i++] = NSOpenGLPFAStereo;
    100     }
    101 
    102     if ( this->gl_config.stencil_size != 0 ) {
    103         attr[i++] = NSOpenGLPFAStencilSize;
    104         attr[i++] = this->gl_config.stencil_size;
    105     }
    106 
    107     if ( (this->gl_config.accum_red_size +
    108           this->gl_config.accum_green_size +
    109           this->gl_config.accum_blue_size +
    110           this->gl_config.accum_alpha_size) > 0 ) {
    111         attr[i++] = NSOpenGLPFAAccumSize;
    112         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;
    113     }
    114 
    115     if ( this->gl_config.multisamplebuffers != 0 ) {
    116         attr[i++] = NSOpenGLPFASampleBuffers;
    117         attr[i++] = this->gl_config.multisamplebuffers;
    118     }
    119 
    120     if ( this->gl_config.multisamplesamples != 0 ) {
    121         attr[i++] = NSOpenGLPFASamples;
    122         attr[i++] = this->gl_config.multisamplesamples;
    123         attr[i++] = NSOpenGLPFANoRecovery;
    124     }
    125 
    126     if ( this->gl_config.accelerated > 0 ) {
    127         attr[i++] = NSOpenGLPFAAccelerated;
    128     }
    129 
    130     attr[i++] = NSOpenGLPFAScreenMask;
    131     attr[i++] = CGDisplayIDToOpenGLDisplayMask (display_id);
    132     attr[i] = 0;
    133 
    134     fmt = [ [ NSOpenGLPixelFormat alloc ] initWithAttributes:attr ];
    135     if (fmt == nil) {
    136         SDL_SetError ("Failed creating OpenGL pixel format");
    137         return 0;
    138     }
    139 
    140     gl_context = [ [ NSOpenGLContext alloc ] initWithFormat:fmt
    141                                                shareContext:nil];
    142 
    143     [ fmt release ];
    144 
    145     if (gl_context == nil) {
    146         SDL_SetError ("Failed creating OpenGL context");
    147         return 0;
    148     }
    149 
    150     /* Synchronize QZ_GL_SwapBuffers() to vertical retrace.
    151      * (Apple's documentation is not completely clear about what this setting
    152      * exactly does, IMHO - for a detailed explanation see
    153      * http://lists.apple.com/archives/mac-opengl/2006/Jan/msg00080.html )
    154      */
    155     if ( this->gl_config.swap_control >= 0 ) {
    156         GLint value;
    157         value = this->gl_config.swap_control;
    158         [ gl_context setValues: &value forParameter: NSOpenGLCPSwapInterval ];
    159     }
    160 
    161     /*
    162      * Wisdom from Apple engineer in reference to UT2003's OpenGL performance:
    163      *  "You are blowing a couple of the internal OpenGL function caches. This
    164      *  appears to be happening in the VAO case.  You can tell OpenGL to up
    165      *  the cache size by issuing the following calls right after you create
    166      *  the OpenGL context.  The default cache size is 16."    --ryan.
    167      */
    168 
    169     #ifndef GLI_ARRAY_FUNC_CACHE_MAX
    170     #define GLI_ARRAY_FUNC_CACHE_MAX 284
    171     #endif
    172 
    173     #ifndef GLI_SUBMIT_FUNC_CACHE_MAX
    174     #define GLI_SUBMIT_FUNC_CACHE_MAX 280
    175     #endif
    176 
    177     {
    178         GLint cache_max = 64;
    179         CGLContextObj ctx = QZ_GetCGLContextObj(gl_context);
    180         CGLSetParameter (ctx, GLI_SUBMIT_FUNC_CACHE_MAX, &cache_max);
    181         CGLSetParameter (ctx, GLI_ARRAY_FUNC_CACHE_MAX, &cache_max);
    182     }
    183 
    184     /* End Wisdom from Apple Engineer section. --ryan. */
    185 
    186     return 1;
    187 }
    188 
    189 void QZ_TearDownOpenGL (_THIS) {
    190 
    191     [ NSOpenGLContext clearCurrentContext ];
    192     [ gl_context clearDrawable ];
    193     [ gl_context release ];
    194 }
    195 
    196 
    197 /* SDL OpenGL functions */
    198 static const char *DEFAULT_OPENGL_LIB_NAME =
    199     "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib";
    200 
    201 int    QZ_GL_LoadLibrary    (_THIS, const char *location) {
    202     if ( gl_context != NULL ) {
    203         SDL_SetError("OpenGL context already created");
    204         return -1;
    205     }
    206 
    207     if (opengl_library != NULL)
    208         SDL_UnloadObject(opengl_library);
    209 
    210     if (location == NULL)
    211         location = DEFAULT_OPENGL_LIB_NAME;
    212 
    213     opengl_library = SDL_LoadObject(location);
    214     if (opengl_library != NULL) {
    215         this->gl_config.driver_loaded = 1;
    216         return 0;
    217     }
    218 
    219     this->gl_config.driver_loaded = 0;
    220     return -1;
    221 }
    222 
    223 void*  QZ_GL_GetProcAddress (_THIS, const char *proc) {
    224     return SDL_LoadFunction(opengl_library, proc);
    225 }
    226 
    227 int    QZ_GL_GetAttribute   (_THIS, SDL_GLattr attrib, int* value) {
    228 
    229     GLenum attr = 0;
    230 
    231     QZ_GL_MakeCurrent (this);
    232 
    233     switch (attrib) {
    234         case SDL_GL_RED_SIZE: attr = GL_RED_BITS;   break;
    235         case SDL_GL_BLUE_SIZE: attr = GL_BLUE_BITS;  break;
    236         case SDL_GL_GREEN_SIZE: attr = GL_GREEN_BITS; break;
    237         case SDL_GL_ALPHA_SIZE: attr = GL_ALPHA_BITS; break;
    238         case SDL_GL_DOUBLEBUFFER: attr = GL_DOUBLEBUFFER; break;
    239         case SDL_GL_DEPTH_SIZE: attr = GL_DEPTH_BITS;  break;
    240         case SDL_GL_STENCIL_SIZE: attr = GL_STENCIL_BITS; break;
    241         case SDL_GL_ACCUM_RED_SIZE: attr = GL_ACCUM_RED_BITS; break;
    242         case SDL_GL_ACCUM_GREEN_SIZE: attr = GL_ACCUM_GREEN_BITS; break;
    243         case SDL_GL_ACCUM_BLUE_SIZE: attr = GL_ACCUM_BLUE_BITS; break;
    244         case SDL_GL_ACCUM_ALPHA_SIZE: attr = GL_ACCUM_ALPHA_BITS; break;
    245         case SDL_GL_STEREO: attr = GL_STEREO; break;
    246         case SDL_GL_MULTISAMPLEBUFFERS: attr = GL_SAMPLE_BUFFERS_ARB; break;
    247         case SDL_GL_MULTISAMPLESAMPLES: attr = GL_SAMPLES_ARB; break;
    248         case SDL_GL_BUFFER_SIZE:
    249         {
    250             GLint bits = 0;
    251             GLint component;
    252 
    253             /* there doesn't seem to be a single flag in OpenGL for this! */
    254             glGetIntegerv (GL_RED_BITS, &component);   bits += component;
    255             glGetIntegerv (GL_GREEN_BITS,&component);  bits += component;
    256             glGetIntegerv (GL_BLUE_BITS, &component);  bits += component;
    257             glGetIntegerv (GL_ALPHA_BITS, &component); bits += component;
    258 
    259             *value = bits;
    260             return 0;
    261         }
    262         case SDL_GL_ACCELERATED_VISUAL:
    263         {
    264             GLint val;
    265 	    /* FIXME: How do we get this information here?
    266             [fmt getValues: &val forAttribute: NSOpenGLPFAAccelerated attr forVirtualScreen: 0];
    267 	    */
    268 	    val = (this->gl_config.accelerated != 0);;
    269             *value = val;
    270             return 0;
    271         }
    272         case SDL_GL_SWAP_CONTROL:
    273         {
    274             GLint val;
    275             [ gl_context getValues: &val forParameter: NSOpenGLCPSwapInterval ];
    276             *value = val;
    277             return 0;
    278         }
    279     }
    280 
    281     glGetIntegerv (attr, (GLint *)value);
    282     return 0;
    283 }
    284 
    285 int    QZ_GL_MakeCurrent    (_THIS) {
    286     [ gl_context makeCurrentContext ];
    287     return 0;
    288 }
    289 
    290 void   QZ_GL_SwapBuffers    (_THIS) {
    291     [ gl_context flushBuffer ];
    292 }
    293