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