src/video/quartz/SDL_QuartzGL.m
author Sam Lantinga
Thu, 27 Apr 2006 07:59:16 +0000
changeset 1736 3b2a92126f4d
parent 1403 376665398b25
child 1737 eacc5bc01d1c
permissions -rw-r--r--
Implemented bug #2, 117:

Date: Mon, 21 Mar 2005 12:06:14 +0100
From: Per Inge Mathisen
Subject: Re: [SDL] Outstanding patches?

The patch adds support for setting SDL_GL_SWAP_CONTROL to Windows and
X11. In Windows you can also query this enum to check that it is
working, or see what the default is - such functionality does not
exist in GLX. For more information on the standards implemented:
http://oss.sgi.com/projects/ogl-sample/registry/SGI/swap_control.txt
http://oss.sgi.com/projects/ogl-sample/registry/EXT/wgl_swap_control.txt
     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@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     attr[i++] = NSOpenGLPFAScreenMask;
   116     attr[i++] = CGDisplayIDToOpenGLDisplayMask (display_id);
   117     attr[i] = 0;
   118 
   119     fmt = [ [ NSOpenGLPixelFormat alloc ] initWithAttributes:attr ];
   120     if (fmt == nil) {
   121         SDL_SetError ("Failed creating OpenGL pixel format");
   122         return 0;
   123     }
   124 
   125     gl_context = [ [ NSOpenGLContext alloc ] initWithFormat:fmt
   126                                                shareContext:nil];
   127 
   128     [ fmt release ];
   129 
   130     if (gl_context == nil) {
   131         SDL_SetError ("Failed creating OpenGL context");
   132         return 0;
   133     }
   134 
   135     /* Synchronize QZ_GL_SwapBuffers() to vertical retrace.
   136      * (Apple's documentation is not completely clear about what this setting
   137      * exactly does, IMHO - for a detailed explanation see
   138      * http://lists.apple.com/archives/mac-opengl/2006/Jan/msg00080.html )
   139      */
   140     if ( this->gl_config.swap_control >= 0 ) {
   141         long value;
   142         value = this->gl_config.swap_control;
   143         [ gl_context setValues: &value forParameter: NSOpenGLCPSwapInterval ];
   144     }
   145 
   146     /*
   147      * Wisdom from Apple engineer in reference to UT2003's OpenGL performance:
   148      *  "You are blowing a couple of the internal OpenGL function caches. This
   149      *  appears to be happening in the VAO case.  You can tell OpenGL to up
   150      *  the cache size by issuing the following calls right after you create
   151      *  the OpenGL context.  The default cache size is 16."    --ryan.
   152      */
   153 
   154     #ifndef GLI_ARRAY_FUNC_CACHE_MAX
   155     #define GLI_ARRAY_FUNC_CACHE_MAX 284
   156     #endif
   157 
   158     #ifndef GLI_SUBMIT_FUNC_CACHE_MAX
   159     #define GLI_SUBMIT_FUNC_CACHE_MAX 280
   160     #endif
   161 
   162     {
   163         long cache_max = 64;
   164         CGLContextObj ctx = [ gl_context cglContext ];
   165         CGLSetParameter (ctx, GLI_SUBMIT_FUNC_CACHE_MAX, &cache_max);
   166         CGLSetParameter (ctx, GLI_ARRAY_FUNC_CACHE_MAX, &cache_max);
   167     }
   168 
   169     /* End Wisdom from Apple Engineer section. --ryan. */
   170 
   171     return 1;
   172 }
   173 
   174 void QZ_TearDownOpenGL (_THIS) {
   175 
   176     [ NSOpenGLContext clearCurrentContext ];
   177     [ gl_context clearDrawable ];
   178     [ gl_context release ];
   179 }
   180 
   181 
   182 /* SDL OpenGL functions */
   183 static const char *DEFAULT_OPENGL_LIB_NAME =
   184     "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib";
   185 
   186 int    QZ_GL_LoadLibrary    (_THIS, const char *location) {
   187     if ( gl_context != NULL ) {
   188         SDL_SetError("OpenGL context already created");
   189         return -1;
   190     }
   191 
   192     if (opengl_library != NULL)
   193         SDL_UnloadObject(opengl_library);
   194 
   195     if (location == NULL)
   196         location = DEFAULT_OPENGL_LIB_NAME;
   197 
   198     opengl_library = SDL_LoadObject(location);
   199     if (opengl_library != NULL) {
   200         this->gl_config.driver_loaded = 1;
   201         return 0;
   202     }
   203 
   204     this->gl_config.driver_loaded = 0;
   205     return -1;
   206 }
   207 
   208 void*  QZ_GL_GetProcAddress (_THIS, const char *proc) {
   209     return SDL_LoadFunction(opengl_library, proc);
   210 }
   211 
   212 int    QZ_GL_GetAttribute   (_THIS, SDL_GLattr attrib, int* value) {
   213 
   214     GLenum attr = 0;
   215 
   216     QZ_GL_MakeCurrent (this);
   217 
   218     switch (attrib) {
   219         case SDL_GL_RED_SIZE: attr = GL_RED_BITS;   break;
   220         case SDL_GL_BLUE_SIZE: attr = GL_BLUE_BITS;  break;
   221         case SDL_GL_GREEN_SIZE: attr = GL_GREEN_BITS; break;
   222         case SDL_GL_ALPHA_SIZE: attr = GL_ALPHA_BITS; break;
   223         case SDL_GL_DOUBLEBUFFER: attr = GL_DOUBLEBUFFER; break;
   224         case SDL_GL_DEPTH_SIZE: attr = GL_DEPTH_BITS;  break;
   225         case SDL_GL_STENCIL_SIZE: attr = GL_STENCIL_BITS; break;
   226         case SDL_GL_ACCUM_RED_SIZE: attr = GL_ACCUM_RED_BITS; break;
   227         case SDL_GL_ACCUM_GREEN_SIZE: attr = GL_ACCUM_GREEN_BITS; break;
   228         case SDL_GL_ACCUM_BLUE_SIZE: attr = GL_ACCUM_BLUE_BITS; break;
   229         case SDL_GL_ACCUM_ALPHA_SIZE: attr = GL_ACCUM_ALPHA_BITS; break;
   230         case SDL_GL_STEREO: attr = GL_STEREO; break;
   231         case SDL_GL_MULTISAMPLEBUFFERS: attr = GL_SAMPLE_BUFFERS_ARB; break;
   232         case SDL_GL_MULTISAMPLESAMPLES: attr = GL_SAMPLES_ARB; break;
   233         case SDL_GL_BUFFER_SIZE:
   234         {
   235             GLint bits = 0;
   236             GLint component;
   237 
   238             /* there doesn't seem to be a single flag in OpenGL for this! */
   239             glGetIntegerv (GL_RED_BITS, &component);   bits += component;
   240             glGetIntegerv (GL_GREEN_BITS,&component);  bits += component;
   241             glGetIntegerv (GL_BLUE_BITS, &component);  bits += component;
   242             glGetIntegerv (GL_ALPHA_BITS, &component); bits += component;
   243 
   244             *value = bits;
   245         }
   246         return 0;
   247     }
   248 
   249     glGetIntegerv (attr, (GLint *)value);
   250     return 0;
   251 }
   252 
   253 int    QZ_GL_MakeCurrent    (_THIS) {
   254     [ gl_context makeCurrentContext ];
   255     return 0;
   256 }
   257 
   258 void   QZ_GL_SwapBuffers    (_THIS) {
   259     [ gl_context flushBuffer ];
   260 }