SDL-1.2.14
[sdl_omap.git] / src / video / quartz / SDL_QuartzGL.m
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009  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/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         long 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         long 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             long 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             long 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 }