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