src/video/x11/SDL_x11opengl.c
changeset 1952 420716272158
child 1953 214880ed48c3
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: */