e14743d1 |
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 | } |