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: */