Mercurial > sdl-ios-xcode
comparison src/video/x11/SDL_x11opengl.c @ 1952:420716272158
Implemented X11 OpenGL support.
Added support for the SDL_VIDEO_OPENGL environment variable.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Fri, 28 Jul 2006 08:43:17 +0000 |
parents | |
children | 214880ed48c3 |
comparison
equal
deleted
inserted
replaced
1951:7177581dc9fa | 1952:420716272158 |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 1997-2006 Sam Lantinga | |
4 | |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Lesser General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2.1 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 Lesser General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Lesser General Public | |
16 License along with _this library; if not, write to the Free Software | |
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | |
19 Sam Lantinga | |
20 slouken@libsdl.org | |
21 */ | |
22 #include "SDL_config.h" | |
23 | |
24 #include "SDL_x11video.h" | |
25 | |
26 /* GLX implementation of SDL OpenGL support */ | |
27 | |
28 #if SDL_VIDEO_OPENGL_GLX | |
29 #include "SDL_loadso.h" | |
30 | |
31 #if defined(__IRIX__) | |
32 /* IRIX doesn't have a GL library versioning system */ | |
33 #define DEFAULT_OPENGL "libGL.so" | |
34 #elif defined(__MACOSX__) | |
35 #define DEFAULT_OPENGL "/usr/X11R6/lib/libGL.1.dylib" | |
36 #elif defined(__QNXNTO__) | |
37 #define DEFAULT_OPENGL "libGL.so.3" | |
38 #else | |
39 #define DEFAULT_OPENGL "libGL.so.1" | |
40 #endif | |
41 | |
42 #ifndef GLX_ARB_multisample | |
43 #define GLX_ARB_multisample | |
44 #define GLX_SAMPLE_BUFFERS_ARB 100000 | |
45 #define GLX_SAMPLES_ARB 100001 | |
46 #endif | |
47 | |
48 #ifndef GLX_EXT_visual_rating | |
49 #define GLX_EXT_visual_rating | |
50 #define GLX_VISUAL_CAVEAT_EXT 0x20 | |
51 #define GLX_NONE_EXT 0x8000 | |
52 #define GLX_SLOW_VISUAL_EXT 0x8001 | |
53 #define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D | |
54 #endif | |
55 | |
56 #define OPENGL_REQUIRS_DLOPEN | |
57 #if defined(OPENGL_REQUIRS_DLOPEN) && defined(SDL_LOADSO_DLOPEN) | |
58 #include <dlfcn.h> | |
59 #define GL_LoadObject(X) dlopen(X, (RTLD_NOW|RTLD_GLOBAL)) | |
60 #define GL_LoadFunction dlsym | |
61 #define GL_UnloadObject dlclose | |
62 #else | |
63 #define GL_LoadObject SDL_LoadObject | |
64 #define GL_LoadFunction SDL_LoadFunction | |
65 #define GL_UnloadObject SDL_UnloadObject | |
66 #endif | |
67 | |
68 int | |
69 X11_GL_LoadLibrary(_THIS, const char *path) | |
70 { | |
71 void *handle; | |
72 | |
73 if (_this->gl_config.driver_loaded) { | |
74 if (path) { | |
75 SDL_SetError("OpenGL library already loaded"); | |
76 return -1; | |
77 } else { | |
78 ++_this->gl_config.driver_loaded; | |
79 return 0; | |
80 } | |
81 } | |
82 if (path == NULL) { | |
83 path = SDL_getenv("SDL_OPENGL_LIBRARY"); | |
84 } | |
85 if (path == NULL) { | |
86 path = DEFAULT_OPENGL; | |
87 } | |
88 handle = GL_LoadObject(path); | |
89 if (!handle) { | |
90 return -1; | |
91 } | |
92 | |
93 /* Load new function pointers */ | |
94 _this->gl_data->glXGetProcAddress = | |
95 (void *(*)(const GLubyte *)) GL_LoadFunction(handle, | |
96 "glXGetProcAddressARB"); | |
97 _this->gl_data->glXChooseVisual = | |
98 (XVisualInfo * (*)(Display *, int, int *)) GL_LoadFunction(handle, | |
99 "glXChooseVisual"); | |
100 _this->gl_data->glXCreateContext = | |
101 (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int)) | |
102 GL_LoadFunction(handle, "glXCreateContext"); | |
103 _this->gl_data->glXDestroyContext = | |
104 (void (*)(Display *, GLXContext)) GL_LoadFunction(handle, | |
105 "glXDestroyContext"); | |
106 _this->gl_data->glXMakeCurrent = | |
107 (int (*)(Display *, GLXDrawable, GLXContext)) GL_LoadFunction(handle, | |
108 "glXMakeCurrent"); | |
109 _this->gl_data->glXSwapBuffers = | |
110 (void (*)(Display *, GLXDrawable)) GL_LoadFunction(handle, | |
111 "glXSwapBuffers"); | |
112 _this->gl_data->glXGetConfig = | |
113 (int (*)(Display *, XVisualInfo *, int, int *)) | |
114 GL_LoadFunction(handle, "glXGetConfig"); | |
115 | |
116 if (!_this->gl_data->glXChooseVisual || | |
117 !_this->gl_data->glXCreateContext || | |
118 !_this->gl_data->glXDestroyContext || | |
119 !_this->gl_data->glXMakeCurrent || | |
120 !_this->gl_data->glXSwapBuffers || !_this->gl_data->glXGetConfig) { | |
121 SDL_SetError("Could not retrieve OpenGL functions"); | |
122 return -1; | |
123 } | |
124 | |
125 _this->gl_config.dll_handle = handle; | |
126 SDL_strlcpy(_this->gl_config.driver_path, path, | |
127 SDL_arraysize(_this->gl_config.driver_path)); | |
128 _this->gl_config.driver_loaded = 1; | |
129 return 0; | |
130 } | |
131 | |
132 void * | |
133 X11_GL_GetProcAddress(_THIS, const char *proc) | |
134 { | |
135 void *handle; | |
136 | |
137 handle = _this->gl_config.dll_handle; | |
138 if (_this->gl_data->glXGetProcAddress) { | |
139 return _this->gl_data->glXGetProcAddress((const GLubyte *) proc); | |
140 } | |
141 return GL_LoadFunction(handle, proc); | |
142 } | |
143 | |
144 static void | |
145 X11_GL_UnloadLibrary(_THIS) | |
146 { | |
147 if (_this->gl_config.driver_loaded > 0) { | |
148 if (--_this->gl_config.driver_loaded > 0) { | |
149 return; | |
150 } | |
151 GL_UnloadObject(_this->gl_config.dll_handle); | |
152 _this->gl_config.dll_handle = NULL; | |
153 } | |
154 } | |
155 | |
156 static SDL_bool | |
157 HasExtension(const char *extension, const char *extensions) | |
158 { | |
159 const char *start; | |
160 const char *where, *terminator; | |
161 | |
162 /* Extension names should not have spaces. */ | |
163 where = SDL_strchr(extension, ' '); | |
164 if (where || *extension == '\0') | |
165 return SDL_FALSE; | |
166 | |
167 if (!extensions) | |
168 return SDL_FALSE; | |
169 | |
170 /* It takes a bit of care to be fool-proof about parsing the | |
171 * OpenGL extensions string. Don't be fooled by sub-strings, | |
172 * etc. */ | |
173 | |
174 start = extensions; | |
175 | |
176 for (;;) { | |
177 where = SDL_strstr(start, extension); | |
178 if (!where) | |
179 break; | |
180 | |
181 terminator = where + SDL_strlen(extension); | |
182 if (where == start || *(where - 1) == ' ') | |
183 if (*terminator == ' ' || *terminator == '\0') | |
184 return SDL_TRUE; | |
185 | |
186 start = terminator; | |
187 } | |
188 return SDL_FALSE; | |
189 } | |
190 | |
191 static void | |
192 X11_GL_InitExtensions(_THIS) | |
193 { | |
194 Display *display = ((SDL_VideoData *) _this->driverdata)->display; | |
195 int screen = ((SDL_DisplayData *) SDL_CurrentDisplay.driverdata)->screen; | |
196 XVisualInfo *vinfo; | |
197 XSetWindowAttributes xattr; | |
198 Window w; | |
199 GLXContext context; | |
200 const char *(*glXQueryExtensionsStringFunc) (Display *, int); | |
201 const char *extensions; | |
202 | |
203 vinfo = X11_GL_GetVisual(_this, display, screen); | |
204 if (!vinfo) { | |
205 return; | |
206 } | |
207 xattr.background_pixel = 0; | |
208 xattr.border_pixel = 0; | |
209 xattr.colormap = | |
210 XCreateColormap(display, RootWindow(display, screen), vinfo->visual, | |
211 AllocNone); | |
212 w = XCreateWindow(display, RootWindow(display, screen), 0, 0, 32, 32, 0, | |
213 vinfo->depth, InputOutput, vinfo->visual, | |
214 (CWBackPixel | CWBorderPixel | CWColormap), &xattr); | |
215 context = _this->gl_data->glXCreateContext(display, vinfo, NULL, True); | |
216 if (context) { | |
217 _this->gl_data->glXMakeCurrent(display, w, context); | |
218 } | |
219 XFree(vinfo); | |
220 | |
221 glXQueryExtensionsStringFunc = | |
222 (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this, | |
223 "glXQueryExtensionsString"); | |
224 if (glXQueryExtensionsStringFunc) { | |
225 extensions = glXQueryExtensionsStringFunc(display, screen); | |
226 } else { | |
227 extensions = NULL; | |
228 } | |
229 | |
230 /* Check for SGI_swap_control */ | |
231 if (HasExtension("SGI_swap_control", extensions)) { | |
232 _this->gl_data->glXSwapIntervalSGI = | |
233 (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI"); | |
234 } | |
235 | |
236 /* Check for GLX_MESA_swap_control */ | |
237 if (HasExtension("GLX_MESA_swap_control", extensions)) { | |
238 _this->gl_data->glXSwapIntervalMESA = | |
239 (GLint(*)(unsigned)) X11_GL_GetProcAddress(_this, | |
240 "glXSwapIntervalMESA"); | |
241 _this->gl_data->glXGetSwapIntervalMESA = | |
242 (GLint(*)(void)) X11_GL_GetProcAddress(_this, | |
243 "glXGetSwapIntervalMESA"); | |
244 } | |
245 | |
246 /* Check for GLX_EXT_visual_rating */ | |
247 if (HasExtension("GLX_EXT_visual_rating", extensions)) { | |
248 _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE; | |
249 } | |
250 | |
251 if (context) { | |
252 _this->gl_data->glXMakeCurrent(display, None, NULL); | |
253 _this->gl_data->glXDestroyContext(display, context); | |
254 } | |
255 XDestroyWindow(display, w); | |
256 X11_PumpEvents(_this); | |
257 } | |
258 | |
259 int | |
260 X11_GL_Initialize(_THIS) | |
261 { | |
262 if (_this->gl_data) { | |
263 ++_this->gl_data->initialized; | |
264 return 0; | |
265 } | |
266 | |
267 _this->gl_data = | |
268 (struct SDL_GLDriverData *) SDL_calloc(1, | |
269 sizeof(struct | |
270 SDL_GLDriverData)); | |
271 if (!_this->gl_data) { | |
272 SDL_OutOfMemory(); | |
273 return -1; | |
274 } | |
275 _this->gl_data->initialized = 1; | |
276 | |
277 if (X11_GL_LoadLibrary(_this, NULL) < 0) { | |
278 return -1; | |
279 } | |
280 | |
281 /* Initialize extensions */ | |
282 X11_GL_InitExtensions(_this); | |
283 | |
284 return 0; | |
285 } | |
286 | |
287 void | |
288 X11_GL_Shutdown(_THIS) | |
289 { | |
290 if (!_this->gl_data || (--_this->gl_data->initialized > 0)) { | |
291 return; | |
292 } | |
293 | |
294 X11_GL_UnloadLibrary(_this); | |
295 | |
296 SDL_free(_this->gl_data); | |
297 _this->gl_data = NULL; | |
298 } | |
299 | |
300 XVisualInfo * | |
301 X11_GL_GetVisual(_THIS, Display * display, int screen) | |
302 { | |
303 XVisualInfo *vinfo; | |
304 | |
305 /* 64 seems nice. */ | |
306 int attribs[64]; | |
307 int i; | |
308 | |
309 /* Setup our GLX attributes according to the gl_config. */ | |
310 i = 0; | |
311 attribs[i++] = GLX_RGBA; | |
312 attribs[i++] = GLX_RED_SIZE; | |
313 attribs[i++] = _this->gl_config.red_size; | |
314 attribs[i++] = GLX_GREEN_SIZE; | |
315 attribs[i++] = _this->gl_config.green_size; | |
316 attribs[i++] = GLX_BLUE_SIZE; | |
317 attribs[i++] = _this->gl_config.blue_size; | |
318 | |
319 if (_this->gl_config.alpha_size) { | |
320 attribs[i++] = GLX_ALPHA_SIZE; | |
321 attribs[i++] = _this->gl_config.alpha_size; | |
322 } | |
323 | |
324 if (_this->gl_config.buffer_size) { | |
325 attribs[i++] = GLX_BUFFER_SIZE; | |
326 attribs[i++] = _this->gl_config.buffer_size; | |
327 } | |
328 | |
329 if (_this->gl_config.double_buffer) { | |
330 attribs[i++] = GLX_DOUBLEBUFFER; | |
331 } | |
332 | |
333 attribs[i++] = GLX_DEPTH_SIZE; | |
334 attribs[i++] = _this->gl_config.depth_size; | |
335 | |
336 if (_this->gl_config.stencil_size) { | |
337 attribs[i++] = GLX_STENCIL_SIZE; | |
338 attribs[i++] = _this->gl_config.stencil_size; | |
339 } | |
340 | |
341 if (_this->gl_config.accum_red_size) { | |
342 attribs[i++] = GLX_ACCUM_RED_SIZE; | |
343 attribs[i++] = _this->gl_config.accum_red_size; | |
344 } | |
345 | |
346 if (_this->gl_config.accum_green_size) { | |
347 attribs[i++] = GLX_ACCUM_GREEN_SIZE; | |
348 attribs[i++] = _this->gl_config.accum_green_size; | |
349 } | |
350 | |
351 if (_this->gl_config.accum_blue_size) { | |
352 attribs[i++] = GLX_ACCUM_BLUE_SIZE; | |
353 attribs[i++] = _this->gl_config.accum_blue_size; | |
354 } | |
355 | |
356 if (_this->gl_config.accum_alpha_size) { | |
357 attribs[i++] = GLX_ACCUM_ALPHA_SIZE; | |
358 attribs[i++] = _this->gl_config.accum_alpha_size; | |
359 } | |
360 | |
361 if (_this->gl_config.stereo) { | |
362 attribs[i++] = GLX_STEREO; | |
363 } | |
364 | |
365 if (_this->gl_config.multisamplebuffers) { | |
366 attribs[i++] = GLX_SAMPLE_BUFFERS_ARB; | |
367 attribs[i++] = _this->gl_config.multisamplebuffers; | |
368 } | |
369 | |
370 if (_this->gl_config.multisamplesamples) { | |
371 attribs[i++] = GLX_SAMPLES_ARB; | |
372 attribs[i++] = _this->gl_config.multisamplesamples; | |
373 } | |
374 | |
375 if (_this->gl_config.accelerated >= 0 | |
376 && _this->gl_data->HAS_GLX_EXT_visual_rating) { | |
377 attribs[i++] = GLX_VISUAL_CAVEAT_EXT; | |
378 attribs[i++] = GLX_NONE_EXT; | |
379 } | |
380 #ifdef GLX_DIRECT_COLOR /* Try for a DirectColor visual for gamma support */ | |
381 if (!SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR")) { | |
382 attribs[i++] = GLX_X_VISUAL_TYPE; | |
383 attribs[i++] = GLX_DIRECT_COLOR; | |
384 } | |
385 #endif | |
386 attribs[i++] = None; | |
387 | |
388 vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs); | |
389 #ifdef GLX_DIRECT_COLOR | |
390 if (!vinfo && !SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR")) { /* No DirectColor visual? Try again.. */ | |
391 attribs[i - 3] = None; | |
392 vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs); | |
393 } | |
394 #endif | |
395 if (!vinfo) { | |
396 SDL_SetError("Couldn't find matching GLX visual"); | |
397 } | |
398 return vinfo; | |
399 } | |
400 | |
401 SDL_GLContext | |
402 X11_GL_CreateContext(_THIS, SDL_Window * window) | |
403 { | |
404 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; | |
405 Display *display = data->videodata->display; | |
406 int screen = | |
407 ((SDL_DisplayData *) SDL_GetDisplayFromWindow(window)->driverdata)-> | |
408 screen; | |
409 XWindowAttributes xattr; | |
410 XVisualInfo v, *vinfo; | |
411 int n; | |
412 GLXContext context = NULL; | |
413 | |
414 /* We do _this to create a clean separation between X and GLX errors. */ | |
415 XSync(display, False); | |
416 XGetWindowAttributes(display, data->window, &xattr); | |
417 v.screen = screen; | |
418 v.visualid = XVisualIDFromVisual(xattr.visual); | |
419 vinfo = XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n); | |
420 if (vinfo) { | |
421 context = | |
422 _this->gl_data->glXCreateContext(display, vinfo, NULL, True); | |
423 XFree(vinfo); | |
424 } | |
425 XSync(display, False); | |
426 | |
427 if (!context) { | |
428 SDL_SetError("Could not create GL context"); | |
429 } | |
430 return (SDL_GLContext) context; | |
431 } | |
432 | |
433 int | |
434 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) | |
435 { | |
436 Display *display = ((SDL_VideoData *) _this->driverdata)->display; | |
437 Window drawable = | |
438 (window ? ((SDL_WindowData *) window->driverdata)->window : None); | |
439 GLXContext glx_context = (GLXContext) context; | |
440 int status; | |
441 | |
442 status = 0; | |
443 if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) { | |
444 SDL_SetError("Unable to make GL context current"); | |
445 status = -1; | |
446 } | |
447 XSync(display, False); | |
448 | |
449 return (status); | |
450 } | |
451 | |
452 int | |
453 X11_GL_SetSwapInterval(_THIS, int interval) | |
454 { | |
455 int status; | |
456 | |
457 if (_this->gl_data->glXSwapIntervalMESA) { | |
458 status = _this->gl_data->glXSwapIntervalMESA(interval); | |
459 if (status != 0) { | |
460 SDL_SetError("glxSwapIntervalMESA failed"); | |
461 status = -1; | |
462 } | |
463 } else if (_this->gl_data->glXSwapIntervalSGI) { | |
464 status = _this->gl_data->glXSwapIntervalSGI(interval); | |
465 if (status != 0) { | |
466 SDL_SetError("glxSwapIntervalSGI failed"); | |
467 status = -1; | |
468 } | |
469 } else { | |
470 SDL_Unsupported(); | |
471 status = -1; | |
472 } | |
473 return status; | |
474 } | |
475 | |
476 int | |
477 X11_GL_GetSwapInterval(_THIS) | |
478 { | |
479 if (_this->gl_data->glXGetSwapIntervalMESA) { | |
480 return _this->gl_data->glXGetSwapIntervalMESA(); | |
481 } else { | |
482 SDL_Unsupported(); | |
483 return -1; | |
484 } | |
485 } | |
486 | |
487 void | |
488 X11_GL_SwapWindow(_THIS, SDL_Window * window) | |
489 { | |
490 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; | |
491 Display *display = data->videodata->display; | |
492 | |
493 _this->gl_data->glXSwapBuffers(display, data->window); | |
494 } | |
495 | |
496 void | |
497 X11_GL_DeleteContext(_THIS, SDL_GLContext context) | |
498 { | |
499 Display *display = ((SDL_VideoData *) _this->driverdata)->display; | |
500 GLXContext glx_context = (GLXContext) context; | |
501 | |
502 _this->gl_data->glXDestroyContext(display, glx_context); | |
503 } | |
504 | |
505 #endif /* SDL_VIDEO_OPENGL_GLX */ | |
506 | |
507 /* vi: set ts=4 sw=4 expandtab: */ |