--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/x11/SDL_x11opengl.c Fri Jul 28 08:43:17 2006 +0000
@@ -0,0 +1,507 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2006 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with _this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include "SDL_x11video.h"
+
+/* GLX implementation of SDL OpenGL support */
+
+#if SDL_VIDEO_OPENGL_GLX
+#include "SDL_loadso.h"
+
+#if defined(__IRIX__)
+/* IRIX doesn't have a GL library versioning system */
+#define DEFAULT_OPENGL "libGL.so"
+#elif defined(__MACOSX__)
+#define DEFAULT_OPENGL "/usr/X11R6/lib/libGL.1.dylib"
+#elif defined(__QNXNTO__)
+#define DEFAULT_OPENGL "libGL.so.3"
+#else
+#define DEFAULT_OPENGL "libGL.so.1"
+#endif
+
+#ifndef GLX_ARB_multisample
+#define GLX_ARB_multisample
+#define GLX_SAMPLE_BUFFERS_ARB 100000
+#define GLX_SAMPLES_ARB 100001
+#endif
+
+#ifndef GLX_EXT_visual_rating
+#define GLX_EXT_visual_rating
+#define GLX_VISUAL_CAVEAT_EXT 0x20
+#define GLX_NONE_EXT 0x8000
+#define GLX_SLOW_VISUAL_EXT 0x8001
+#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D
+#endif
+
+#define OPENGL_REQUIRS_DLOPEN
+#if defined(OPENGL_REQUIRS_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
+#include <dlfcn.h>
+#define GL_LoadObject(X) dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
+#define GL_LoadFunction dlsym
+#define GL_UnloadObject dlclose
+#else
+#define GL_LoadObject SDL_LoadObject
+#define GL_LoadFunction SDL_LoadFunction
+#define GL_UnloadObject SDL_UnloadObject
+#endif
+
+int
+X11_GL_LoadLibrary(_THIS, const char *path)
+{
+ void *handle;
+
+ if (_this->gl_config.driver_loaded) {
+ if (path) {
+ SDL_SetError("OpenGL library already loaded");
+ return -1;
+ } else {
+ ++_this->gl_config.driver_loaded;
+ return 0;
+ }
+ }
+ if (path == NULL) {
+ path = SDL_getenv("SDL_OPENGL_LIBRARY");
+ }
+ if (path == NULL) {
+ path = DEFAULT_OPENGL;
+ }
+ handle = GL_LoadObject(path);
+ if (!handle) {
+ return -1;
+ }
+
+ /* Load new function pointers */
+ _this->gl_data->glXGetProcAddress =
+ (void *(*)(const GLubyte *)) GL_LoadFunction(handle,
+ "glXGetProcAddressARB");
+ _this->gl_data->glXChooseVisual =
+ (XVisualInfo * (*)(Display *, int, int *)) GL_LoadFunction(handle,
+ "glXChooseVisual");
+ _this->gl_data->glXCreateContext =
+ (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
+ GL_LoadFunction(handle, "glXCreateContext");
+ _this->gl_data->glXDestroyContext =
+ (void (*)(Display *, GLXContext)) GL_LoadFunction(handle,
+ "glXDestroyContext");
+ _this->gl_data->glXMakeCurrent =
+ (int (*)(Display *, GLXDrawable, GLXContext)) GL_LoadFunction(handle,
+ "glXMakeCurrent");
+ _this->gl_data->glXSwapBuffers =
+ (void (*)(Display *, GLXDrawable)) GL_LoadFunction(handle,
+ "glXSwapBuffers");
+ _this->gl_data->glXGetConfig =
+ (int (*)(Display *, XVisualInfo *, int, int *))
+ GL_LoadFunction(handle, "glXGetConfig");
+
+ if (!_this->gl_data->glXChooseVisual ||
+ !_this->gl_data->glXCreateContext ||
+ !_this->gl_data->glXDestroyContext ||
+ !_this->gl_data->glXMakeCurrent ||
+ !_this->gl_data->glXSwapBuffers || !_this->gl_data->glXGetConfig) {
+ SDL_SetError("Could not retrieve OpenGL functions");
+ return -1;
+ }
+
+ _this->gl_config.dll_handle = handle;
+ SDL_strlcpy(_this->gl_config.driver_path, path,
+ SDL_arraysize(_this->gl_config.driver_path));
+ _this->gl_config.driver_loaded = 1;
+ return 0;
+}
+
+void *
+X11_GL_GetProcAddress(_THIS, const char *proc)
+{
+ void *handle;
+
+ handle = _this->gl_config.dll_handle;
+ if (_this->gl_data->glXGetProcAddress) {
+ return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
+ }
+ return GL_LoadFunction(handle, proc);
+}
+
+static void
+X11_GL_UnloadLibrary(_THIS)
+{
+ if (_this->gl_config.driver_loaded > 0) {
+ if (--_this->gl_config.driver_loaded > 0) {
+ return;
+ }
+ GL_UnloadObject(_this->gl_config.dll_handle);
+ _this->gl_config.dll_handle = NULL;
+ }
+}
+
+static SDL_bool
+HasExtension(const char *extension, const char *extensions)
+{
+ const char *start;
+ const char *where, *terminator;
+
+ /* Extension names should not have spaces. */
+ where = SDL_strchr(extension, ' ');
+ if (where || *extension == '\0')
+ return SDL_FALSE;
+
+ if (!extensions)
+ return SDL_FALSE;
+
+ /* It takes a bit of care to be fool-proof about parsing the
+ * OpenGL extensions string. Don't be fooled by sub-strings,
+ * etc. */
+
+ start = extensions;
+
+ for (;;) {
+ where = SDL_strstr(start, extension);
+ if (!where)
+ break;
+
+ terminator = where + SDL_strlen(extension);
+ if (where == start || *(where - 1) == ' ')
+ if (*terminator == ' ' || *terminator == '\0')
+ return SDL_TRUE;
+
+ start = terminator;
+ }
+ return SDL_FALSE;
+}
+
+static void
+X11_GL_InitExtensions(_THIS)
+{
+ Display *display = ((SDL_VideoData *) _this->driverdata)->display;
+ int screen = ((SDL_DisplayData *) SDL_CurrentDisplay.driverdata)->screen;
+ XVisualInfo *vinfo;
+ XSetWindowAttributes xattr;
+ Window w;
+ GLXContext context;
+ const char *(*glXQueryExtensionsStringFunc) (Display *, int);
+ const char *extensions;
+
+ vinfo = X11_GL_GetVisual(_this, display, screen);
+ if (!vinfo) {
+ return;
+ }
+ xattr.background_pixel = 0;
+ xattr.border_pixel = 0;
+ xattr.colormap =
+ XCreateColormap(display, RootWindow(display, screen), vinfo->visual,
+ AllocNone);
+ w = XCreateWindow(display, RootWindow(display, screen), 0, 0, 32, 32, 0,
+ vinfo->depth, InputOutput, vinfo->visual,
+ (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
+ context = _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
+ if (context) {
+ _this->gl_data->glXMakeCurrent(display, w, context);
+ }
+ XFree(vinfo);
+
+ glXQueryExtensionsStringFunc =
+ (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
+ "glXQueryExtensionsString");
+ if (glXQueryExtensionsStringFunc) {
+ extensions = glXQueryExtensionsStringFunc(display, screen);
+ } else {
+ extensions = NULL;
+ }
+
+ /* Check for SGI_swap_control */
+ if (HasExtension("SGI_swap_control", extensions)) {
+ _this->gl_data->glXSwapIntervalSGI =
+ (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
+ }
+
+ /* Check for GLX_MESA_swap_control */
+ if (HasExtension("GLX_MESA_swap_control", extensions)) {
+ _this->gl_data->glXSwapIntervalMESA =
+ (GLint(*)(unsigned)) X11_GL_GetProcAddress(_this,
+ "glXSwapIntervalMESA");
+ _this->gl_data->glXGetSwapIntervalMESA =
+ (GLint(*)(void)) X11_GL_GetProcAddress(_this,
+ "glXGetSwapIntervalMESA");
+ }
+
+ /* Check for GLX_EXT_visual_rating */
+ if (HasExtension("GLX_EXT_visual_rating", extensions)) {
+ _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
+ }
+
+ if (context) {
+ _this->gl_data->glXMakeCurrent(display, None, NULL);
+ _this->gl_data->glXDestroyContext(display, context);
+ }
+ XDestroyWindow(display, w);
+ X11_PumpEvents(_this);
+}
+
+int
+X11_GL_Initialize(_THIS)
+{
+ if (_this->gl_data) {
+ ++_this->gl_data->initialized;
+ return 0;
+ }
+
+ _this->gl_data =
+ (struct SDL_GLDriverData *) SDL_calloc(1,
+ sizeof(struct
+ SDL_GLDriverData));
+ if (!_this->gl_data) {
+ SDL_OutOfMemory();
+ return -1;
+ }
+ _this->gl_data->initialized = 1;
+
+ if (X11_GL_LoadLibrary(_this, NULL) < 0) {
+ return -1;
+ }
+
+ /* Initialize extensions */
+ X11_GL_InitExtensions(_this);
+
+ return 0;
+}
+
+void
+X11_GL_Shutdown(_THIS)
+{
+ if (!_this->gl_data || (--_this->gl_data->initialized > 0)) {
+ return;
+ }
+
+ X11_GL_UnloadLibrary(_this);
+
+ SDL_free(_this->gl_data);
+ _this->gl_data = NULL;
+}
+
+XVisualInfo *
+X11_GL_GetVisual(_THIS, Display * display, int screen)
+{
+ XVisualInfo *vinfo;
+
+ /* 64 seems nice. */
+ int attribs[64];
+ int i;
+
+ /* Setup our GLX attributes according to the gl_config. */
+ i = 0;
+ attribs[i++] = GLX_RGBA;
+ attribs[i++] = GLX_RED_SIZE;
+ attribs[i++] = _this->gl_config.red_size;
+ attribs[i++] = GLX_GREEN_SIZE;
+ attribs[i++] = _this->gl_config.green_size;
+ attribs[i++] = GLX_BLUE_SIZE;
+ attribs[i++] = _this->gl_config.blue_size;
+
+ if (_this->gl_config.alpha_size) {
+ attribs[i++] = GLX_ALPHA_SIZE;
+ attribs[i++] = _this->gl_config.alpha_size;
+ }
+
+ if (_this->gl_config.buffer_size) {
+ attribs[i++] = GLX_BUFFER_SIZE;
+ attribs[i++] = _this->gl_config.buffer_size;
+ }
+
+ if (_this->gl_config.double_buffer) {
+ attribs[i++] = GLX_DOUBLEBUFFER;
+ }
+
+ attribs[i++] = GLX_DEPTH_SIZE;
+ attribs[i++] = _this->gl_config.depth_size;
+
+ if (_this->gl_config.stencil_size) {
+ attribs[i++] = GLX_STENCIL_SIZE;
+ attribs[i++] = _this->gl_config.stencil_size;
+ }
+
+ if (_this->gl_config.accum_red_size) {
+ attribs[i++] = GLX_ACCUM_RED_SIZE;
+ attribs[i++] = _this->gl_config.accum_red_size;
+ }
+
+ if (_this->gl_config.accum_green_size) {
+ attribs[i++] = GLX_ACCUM_GREEN_SIZE;
+ attribs[i++] = _this->gl_config.accum_green_size;
+ }
+
+ if (_this->gl_config.accum_blue_size) {
+ attribs[i++] = GLX_ACCUM_BLUE_SIZE;
+ attribs[i++] = _this->gl_config.accum_blue_size;
+ }
+
+ if (_this->gl_config.accum_alpha_size) {
+ attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
+ attribs[i++] = _this->gl_config.accum_alpha_size;
+ }
+
+ if (_this->gl_config.stereo) {
+ attribs[i++] = GLX_STEREO;
+ }
+
+ if (_this->gl_config.multisamplebuffers) {
+ attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
+ attribs[i++] = _this->gl_config.multisamplebuffers;
+ }
+
+ if (_this->gl_config.multisamplesamples) {
+ attribs[i++] = GLX_SAMPLES_ARB;
+ attribs[i++] = _this->gl_config.multisamplesamples;
+ }
+
+ if (_this->gl_config.accelerated >= 0
+ && _this->gl_data->HAS_GLX_EXT_visual_rating) {
+ attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
+ attribs[i++] = GLX_NONE_EXT;
+ }
+#ifdef GLX_DIRECT_COLOR /* Try for a DirectColor visual for gamma support */
+ if (!SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR")) {
+ attribs[i++] = GLX_X_VISUAL_TYPE;
+ attribs[i++] = GLX_DIRECT_COLOR;
+ }
+#endif
+ attribs[i++] = None;
+
+ vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
+#ifdef GLX_DIRECT_COLOR
+ if (!vinfo && !SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR")) { /* No DirectColor visual? Try again.. */
+ attribs[i - 3] = None;
+ vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
+ }
+#endif
+ if (!vinfo) {
+ SDL_SetError("Couldn't find matching GLX visual");
+ }
+ return vinfo;
+}
+
+SDL_GLContext
+X11_GL_CreateContext(_THIS, SDL_Window * window)
+{
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ Display *display = data->videodata->display;
+ int screen =
+ ((SDL_DisplayData *) SDL_GetDisplayFromWindow(window)->driverdata)->
+ screen;
+ XWindowAttributes xattr;
+ XVisualInfo v, *vinfo;
+ int n;
+ GLXContext context = NULL;
+
+ /* We do _this to create a clean separation between X and GLX errors. */
+ XSync(display, False);
+ XGetWindowAttributes(display, data->window, &xattr);
+ v.screen = screen;
+ v.visualid = XVisualIDFromVisual(xattr.visual);
+ vinfo = XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
+ if (vinfo) {
+ context =
+ _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
+ XFree(vinfo);
+ }
+ XSync(display, False);
+
+ if (!context) {
+ SDL_SetError("Could not create GL context");
+ }
+ return (SDL_GLContext) context;
+}
+
+int
+X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
+{
+ Display *display = ((SDL_VideoData *) _this->driverdata)->display;
+ Window drawable =
+ (window ? ((SDL_WindowData *) window->driverdata)->window : None);
+ GLXContext glx_context = (GLXContext) context;
+ int status;
+
+ status = 0;
+ if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
+ SDL_SetError("Unable to make GL context current");
+ status = -1;
+ }
+ XSync(display, False);
+
+ return (status);
+}
+
+int
+X11_GL_SetSwapInterval(_THIS, int interval)
+{
+ int status;
+
+ if (_this->gl_data->glXSwapIntervalMESA) {
+ status = _this->gl_data->glXSwapIntervalMESA(interval);
+ if (status != 0) {
+ SDL_SetError("glxSwapIntervalMESA failed");
+ status = -1;
+ }
+ } else if (_this->gl_data->glXSwapIntervalSGI) {
+ status = _this->gl_data->glXSwapIntervalSGI(interval);
+ if (status != 0) {
+ SDL_SetError("glxSwapIntervalSGI failed");
+ status = -1;
+ }
+ } else {
+ SDL_Unsupported();
+ status = -1;
+ }
+ return status;
+}
+
+int
+X11_GL_GetSwapInterval(_THIS)
+{
+ if (_this->gl_data->glXGetSwapIntervalMESA) {
+ return _this->gl_data->glXGetSwapIntervalMESA();
+ } else {
+ SDL_Unsupported();
+ return -1;
+ }
+}
+
+void
+X11_GL_SwapWindow(_THIS, SDL_Window * window)
+{
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ Display *display = data->videodata->display;
+
+ _this->gl_data->glXSwapBuffers(display, data->window);
+}
+
+void
+X11_GL_DeleteContext(_THIS, SDL_GLContext context)
+{
+ Display *display = ((SDL_VideoData *) _this->driverdata)->display;
+ GLXContext glx_context = (GLXContext) context;
+
+ _this->gl_data->glXDestroyContext(display, glx_context);
+}
+
+#endif /* SDL_VIDEO_OPENGL_GLX */
+
+/* vi: set ts=4 sw=4 expandtab: */