src/video/x11/SDL_x11opengl.c
author Sam Lantinga
Tue, 08 Feb 2011 16:50:51 -0800
changeset 5229 c015d3e63631
parent 5021 cd3a1d87cab7
child 5243 3a8a452b49f0
permissions -rw-r--r--
Fixed setting the texture unit, still doesn't work.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 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_NONE_EXT
    43 #define GLX_NONE_EXT                       0x8000
    44 #endif
    45 
    46 #ifndef GLX_ARB_multisample
    47 #define GLX_ARB_multisample
    48 #define GLX_SAMPLE_BUFFERS_ARB             100000
    49 #define GLX_SAMPLES_ARB                    100001
    50 #endif
    51 
    52 #ifndef GLX_EXT_visual_rating
    53 #define GLX_EXT_visual_rating
    54 #define GLX_VISUAL_CAVEAT_EXT              0x20
    55 #define GLX_NONE_EXT                       0x8000
    56 #define GLX_SLOW_VISUAL_EXT                0x8001
    57 #define GLX_NON_CONFORMANT_VISUAL_EXT      0x800D
    58 #endif
    59 
    60 #ifndef GLX_ARB_create_context
    61 #define GLX_ARB_create_context
    62 #define GLX_CONTEXT_MAJOR_VERSION_ARB      0x2091
    63 #define GLX_CONTEXT_MINOR_VERSION_ARB      0x2092
    64 #define GLX_CONTEXT_FLAGS_ARB              0x2094
    65 #define GLX_CONTEXT_DEBUG_BIT_ARB          0x0001
    66 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
    67 
    68 /* Typedef for the GL 3.0 context creation function */
    69 typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy,
    70                                                         GLXFBConfig config,
    71                                                         GLXContext
    72                                                         share_context,
    73                                                         Bool direct,
    74                                                         const int
    75                                                         *attrib_list);
    76 #endif
    77 
    78 #define OPENGL_REQUIRS_DLOPEN
    79 #if defined(OPENGL_REQUIRS_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
    80 #include <dlfcn.h>
    81 #define GL_LoadObject(X)	dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
    82 #define GL_LoadFunction		dlsym
    83 #define GL_UnloadObject		dlclose
    84 #else
    85 #define GL_LoadObject	SDL_LoadObject
    86 #define GL_LoadFunction	SDL_LoadFunction
    87 #define GL_UnloadObject	SDL_UnloadObject
    88 #endif
    89 
    90 static void X11_GL_InitExtensions(_THIS);
    91 
    92 
    93 int
    94 X11_GL_LoadLibrary(_THIS, const char *path)
    95 {
    96     void *handle;
    97 
    98     /* Load the OpenGL library */
    99     if (path == NULL) {
   100         path = SDL_getenv("SDL_OPENGL_LIBRARY");
   101     }
   102     if (path == NULL) {
   103         path = DEFAULT_OPENGL;
   104     }
   105     _this->gl_config.dll_handle = SDL_LoadObject(path);
   106     if (!_this->gl_config.dll_handle) {
   107         return -1;
   108     }
   109     SDL_strlcpy(_this->gl_config.driver_path, path,
   110                 SDL_arraysize(_this->gl_config.driver_path));
   111 
   112     /* Allocate OpenGL memory */
   113     _this->gl_data =
   114         (struct SDL_GLDriverData *) SDL_calloc(1,
   115                                                sizeof(struct
   116                                                       SDL_GLDriverData));
   117     if (!_this->gl_data) {
   118         SDL_OutOfMemory();
   119         return -1;
   120     }
   121 
   122     /* Load function pointers */
   123     handle = _this->gl_config.dll_handle;
   124     _this->gl_data->glXGetProcAddress =
   125         (void *(*)(const GLubyte *))
   126             GL_LoadFunction(handle, "glXGetProcAddressARB");
   127     _this->gl_data->glXChooseVisual =
   128         (XVisualInfo * (*)(Display *, int, int *))
   129             X11_GL_GetProcAddress(_this, "glXChooseVisual");
   130     _this->gl_data->glXCreateContext =
   131         (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
   132             X11_GL_GetProcAddress(_this, "glXCreateContext");
   133     _this->gl_data->glXDestroyContext =
   134         (void (*)(Display *, GLXContext))
   135             X11_GL_GetProcAddress(_this, "glXDestroyContext");
   136     _this->gl_data->glXMakeCurrent =
   137         (int (*)(Display *, GLXDrawable, GLXContext))
   138             X11_GL_GetProcAddress(_this, "glXMakeCurrent");
   139     _this->gl_data->glXSwapBuffers =
   140         (void (*)(Display *, GLXDrawable))
   141             X11_GL_GetProcAddress(_this, "glXSwapBuffers");
   142 
   143     if (!_this->gl_data->glXChooseVisual ||
   144         !_this->gl_data->glXCreateContext ||
   145         !_this->gl_data->glXDestroyContext ||
   146         !_this->gl_data->glXMakeCurrent ||
   147         !_this->gl_data->glXSwapBuffers) {
   148         SDL_SetError("Could not retrieve OpenGL functions");
   149         return -1;
   150     }
   151 
   152     /* Initialize extensions */
   153     X11_GL_InitExtensions(_this);
   154 
   155     return 0;
   156 }
   157 
   158 void *
   159 X11_GL_GetProcAddress(_THIS, const char *proc)
   160 {
   161     if (_this->gl_data->glXGetProcAddress) {
   162         return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
   163     }
   164     return GL_LoadFunction(_this->gl_config.dll_handle, proc);
   165 }
   166 
   167 void
   168 X11_GL_UnloadLibrary(_THIS)
   169 {
   170     /* Don't actually unload the library, since it may have registered
   171      * X11 shutdown hooks, per the notes at:
   172      * http://dri.sourceforge.net/doc/DRIuserguide.html
   173      */
   174 #if 0
   175     GL_UnloadObject(_this->gl_config.dll_handle);
   176     _this->gl_config.dll_handle = NULL;
   177 #endif
   178 
   179     /* Free OpenGL memory */
   180     SDL_free(_this->gl_data);
   181     _this->gl_data = NULL;
   182 }
   183 
   184 static SDL_bool
   185 HasExtension(const char *extension, const char *extensions)
   186 {
   187     const char *start;
   188     const char *where, *terminator;
   189 
   190     /* Extension names should not have spaces. */
   191     where = SDL_strchr(extension, ' ');
   192     if (where || *extension == '\0')
   193         return SDL_FALSE;
   194 
   195     if (!extensions)
   196         return SDL_FALSE;
   197 
   198     /* It takes a bit of care to be fool-proof about parsing the
   199      * OpenGL extensions string. Don't be fooled by sub-strings,
   200      * etc. */
   201 
   202     start = extensions;
   203 
   204     for (;;) {
   205         where = SDL_strstr(start, extension);
   206         if (!where)
   207             break;
   208 
   209         terminator = where + SDL_strlen(extension);
   210         if (where == start || *(where - 1) == ' ')
   211             if (*terminator == ' ' || *terminator == '\0')
   212                 return SDL_TRUE;
   213 
   214         start = terminator;
   215     }
   216     return SDL_FALSE;
   217 }
   218 
   219 static void
   220 X11_GL_InitExtensions(_THIS)
   221 {
   222     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   223     int screen = ((SDL_DisplayData *) SDL_CurrentDisplay->driverdata)->screen;
   224     XVisualInfo *vinfo;
   225     XSetWindowAttributes xattr;
   226     Window w;
   227     GLXContext context;
   228     const char *(*glXQueryExtensionsStringFunc) (Display *, int);
   229     const char *extensions;
   230 
   231     vinfo = X11_GL_GetVisual(_this, display, screen);
   232     if (!vinfo) {
   233         return;
   234     }
   235     xattr.background_pixel = 0;
   236     xattr.border_pixel = 0;
   237     xattr.colormap =
   238         XCreateColormap(display, RootWindow(display, screen), vinfo->visual,
   239                         AllocNone);
   240     w = XCreateWindow(display, RootWindow(display, screen), 0, 0, 32, 32, 0,
   241                       vinfo->depth, InputOutput, vinfo->visual,
   242                       (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
   243     context = _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
   244     if (context) {
   245         _this->gl_data->glXMakeCurrent(display, w, context);
   246     }
   247     XFree(vinfo);
   248 
   249     glXQueryExtensionsStringFunc =
   250         (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
   251                                                                 "glXQueryExtensionsString");
   252     if (glXQueryExtensionsStringFunc) {
   253         extensions = glXQueryExtensionsStringFunc(display, screen);
   254     } else {
   255         extensions = NULL;
   256     }
   257 
   258     /* Check for SGI_swap_control */
   259     if (HasExtension("GLX_SGI_swap_control", extensions)) {
   260         _this->gl_data->glXSwapIntervalSGI =
   261             (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
   262     }
   263 
   264     /* Check for GLX_MESA_swap_control */
   265     if (HasExtension("GLX_MESA_swap_control", extensions)) {
   266         _this->gl_data->glXSwapIntervalMESA =
   267             (GLint(*)(unsigned)) X11_GL_GetProcAddress(_this,
   268                                                        "glXSwapIntervalMESA");
   269         _this->gl_data->glXGetSwapIntervalMESA =
   270             (GLint(*)(void)) X11_GL_GetProcAddress(_this,
   271                                                    "glXGetSwapIntervalMESA");
   272     }
   273 
   274     /* Check for GLX_EXT_visual_rating */
   275     if (HasExtension("GLX_EXT_visual_rating", extensions)) {
   276         _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
   277     }
   278 
   279     if (context) {
   280         _this->gl_data->glXMakeCurrent(display, None, NULL);
   281         _this->gl_data->glXDestroyContext(display, context);
   282     }
   283     XDestroyWindow(display, w);
   284     X11_PumpEvents(_this);
   285 }
   286 
   287 XVisualInfo *
   288 X11_GL_GetVisual(_THIS, Display * display, int screen)
   289 {
   290     XVisualInfo *vinfo;
   291 
   292     /* 64 seems nice. */
   293     int attribs[64];
   294     int i = 0;
   295 
   296     /* Setup our GLX attributes according to the gl_config. */
   297     attribs[i++] = GLX_RGBA;
   298     attribs[i++] = GLX_RED_SIZE;
   299     attribs[i++] = _this->gl_config.red_size;
   300     attribs[i++] = GLX_GREEN_SIZE;
   301     attribs[i++] = _this->gl_config.green_size;
   302     attribs[i++] = GLX_BLUE_SIZE;
   303     attribs[i++] = _this->gl_config.blue_size;
   304 
   305     if (_this->gl_config.alpha_size) {
   306         attribs[i++] = GLX_ALPHA_SIZE;
   307         attribs[i++] = _this->gl_config.alpha_size;
   308     }
   309 
   310     if (_this->gl_config.buffer_size) {
   311         attribs[i++] = GLX_BUFFER_SIZE;
   312         attribs[i++] = _this->gl_config.buffer_size;
   313     }
   314 
   315     if (_this->gl_config.double_buffer) {
   316         attribs[i++] = GLX_DOUBLEBUFFER;
   317     }
   318 
   319     attribs[i++] = GLX_DEPTH_SIZE;
   320     attribs[i++] = _this->gl_config.depth_size;
   321 
   322     if (_this->gl_config.stencil_size) {
   323         attribs[i++] = GLX_STENCIL_SIZE;
   324         attribs[i++] = _this->gl_config.stencil_size;
   325     }
   326 
   327     if (_this->gl_config.accum_red_size) {
   328         attribs[i++] = GLX_ACCUM_RED_SIZE;
   329         attribs[i++] = _this->gl_config.accum_red_size;
   330     }
   331 
   332     if (_this->gl_config.accum_green_size) {
   333         attribs[i++] = GLX_ACCUM_GREEN_SIZE;
   334         attribs[i++] = _this->gl_config.accum_green_size;
   335     }
   336 
   337     if (_this->gl_config.accum_blue_size) {
   338         attribs[i++] = GLX_ACCUM_BLUE_SIZE;
   339         attribs[i++] = _this->gl_config.accum_blue_size;
   340     }
   341 
   342     if (_this->gl_config.accum_alpha_size) {
   343         attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
   344         attribs[i++] = _this->gl_config.accum_alpha_size;
   345     }
   346 
   347     if (_this->gl_config.stereo) {
   348         attribs[i++] = GLX_STEREO;
   349     }
   350 
   351     if (_this->gl_config.multisamplebuffers) {
   352         attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
   353         attribs[i++] = _this->gl_config.multisamplebuffers;
   354     }
   355 
   356     if (_this->gl_config.multisamplesamples) {
   357         attribs[i++] = GLX_SAMPLES_ARB;
   358         attribs[i++] = _this->gl_config.multisamplesamples;
   359     }
   360 
   361     if (_this->gl_config.accelerated >= 0 &&
   362         _this->gl_data->HAS_GLX_EXT_visual_rating) {
   363         attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
   364         attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
   365                                                       GLX_SLOW_VISUAL_EXT;
   366     }
   367 
   368 #ifdef GLX_DIRECT_COLOR         /* Try for a DirectColor visual for gamma support */
   369     if (X11_UseDirectColorVisuals()) {
   370         attribs[i++] = GLX_X_VISUAL_TYPE;
   371         attribs[i++] = GLX_DIRECT_COLOR;
   372     }
   373 #endif
   374 
   375     attribs[i++] = None;
   376 
   377     vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   378 #ifdef GLX_DIRECT_COLOR
   379     if (!vinfo && X11_UseDirectColorVisuals()) {        /* No DirectColor visual?  Try again.. */
   380         attribs[i - 3] = None;
   381         vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   382     }
   383 #endif
   384     if (!vinfo) {
   385         SDL_SetError("Couldn't find matching GLX visual");
   386     }
   387     return vinfo;
   388 }
   389 
   390 SDL_GLContext
   391 X11_GL_CreateContext(_THIS, SDL_Window * window)
   392 {
   393     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   394     Display *display = data->videodata->display;
   395     int screen =
   396         ((SDL_DisplayData *) window->display->driverdata)->screen;
   397     XWindowAttributes xattr;
   398     XVisualInfo v, *vinfo;
   399     int n;
   400     GLXContext context = NULL;
   401 
   402     /* We do this to create a clean separation between X and GLX errors. */
   403     XSync(display, False);
   404     XGetWindowAttributes(display, data->xwindow, &xattr);
   405     v.screen = screen;
   406     v.visualid = XVisualIDFromVisual(xattr.visual);
   407     vinfo = XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
   408     if (vinfo) {
   409         if (_this->gl_config.major_version < 3) {
   410             context =
   411                 _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
   412         } else {
   413             /* If we want a GL 3.0 context or later we need to get a temporary
   414                context to grab the new context creation function */
   415             GLXContext temp_context =
   416                 _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
   417             if (!temp_context) {
   418                 SDL_SetError("Could not create GL context");
   419                 return NULL;
   420             } else {
   421                 int attribs[] = {
   422                     GLX_CONTEXT_MAJOR_VERSION_ARB,
   423                     _this->gl_config.major_version,
   424                     GLX_CONTEXT_MINOR_VERSION_ARB,
   425                     _this->gl_config.minor_version,
   426                     0
   427                 };
   428 
   429                 /* Get a pointer to the context creation function for GL 3.0 */
   430                 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs =
   431                     (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
   432                     glXGetProcAddress((GLubyte *)
   433                                       "glXCreateContextAttribsARB");
   434                 if (!glXCreateContextAttribs) {
   435                     SDL_SetError("GL 3.x is not supported");
   436                     context = temp_context;
   437                 } else {
   438                     /* Create a GL 3.x context */
   439                     GLXFBConfig *framebuffer_config = NULL;
   440                     int fbcount = 0;
   441                     GLXFBConfig *(*glXChooseFBConfig) (Display * disp,
   442                                                        int screen,
   443                                                        const int *attrib_list,
   444                                                        int *nelements);
   445 
   446                     glXChooseFBConfig =
   447                         (GLXFBConfig *
   448                          (*)(Display *, int, const int *,
   449                              int *)) _this->gl_data->
   450                         glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
   451 
   452                     if (!glXChooseFBConfig
   453                         || !(framebuffer_config =
   454                              glXChooseFBConfig(display,
   455                                                DefaultScreen(display), NULL,
   456                                                &fbcount))) {
   457                         SDL_SetError
   458                             ("No good framebuffers found. GL 3.x disabled");
   459                         context = temp_context;
   460                     } else {
   461                         context =
   462                             glXCreateContextAttribs(display,
   463                                                     framebuffer_config[0],
   464                                                     NULL, True, attribs);
   465                         _this->gl_data->glXDestroyContext(display,
   466                                                           temp_context);
   467                     }
   468                 }
   469             }
   470         }
   471         XFree(vinfo);
   472     }
   473     XSync(display, False);
   474 
   475     if (!context) {
   476         SDL_SetError("Could not create GL context");
   477         return NULL;
   478     }
   479 
   480     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
   481         X11_GL_DeleteContext(_this, context);
   482         return NULL;
   483     }
   484 
   485     return context;
   486 }
   487 
   488 int
   489 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   490 {
   491     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   492     Window drawable =
   493         (window ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
   494     GLXContext glx_context = (GLXContext) context;
   495     int status;
   496 
   497     status = 0;
   498     if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
   499         SDL_SetError("Unable to make GL context current");
   500         status = -1;
   501     }
   502     XSync(display, False);
   503 
   504     return (status);
   505 }
   506 
   507 /* 
   508    0 is a valid argument to glxSwapIntervalMESA and setting it to 0
   509    with the MESA version of the extension will undo the effect of a
   510    previous call with a value that is greater than zero (or at least
   511    that is what the FM says. OTOH, 0 is an invalid argument to
   512    glxSwapIntervalSGI and it returns an error if you call it with 0 as
   513    an argument.
   514 */
   515 
   516 static int swapinterval = -1;
   517 int
   518 X11_GL_SetSwapInterval(_THIS, int interval)
   519 {
   520     int status;
   521 
   522     if (_this->gl_data->glXSwapIntervalMESA) {
   523         status = _this->gl_data->glXSwapIntervalMESA(interval);
   524         if (status != 0) {
   525             SDL_SetError("glxSwapIntervalMESA failed");
   526             status = -1;
   527         } else {
   528             swapinterval = interval;
   529         }
   530     } else if (_this->gl_data->glXSwapIntervalSGI) {
   531         status = _this->gl_data->glXSwapIntervalSGI(interval);
   532         if (status != 0) {
   533             SDL_SetError("glxSwapIntervalSGI failed");
   534             status = -1;
   535         } else {
   536             swapinterval = interval;
   537         }
   538     } else {
   539         SDL_Unsupported();
   540         status = -1;
   541     }
   542     return status;
   543 }
   544 
   545 int
   546 X11_GL_GetSwapInterval(_THIS)
   547 {
   548     if (_this->gl_data->glXGetSwapIntervalMESA) {
   549         return _this->gl_data->glXGetSwapIntervalMESA();
   550     } else {
   551         return swapinterval;
   552     }
   553 }
   554 
   555 void
   556 X11_GL_SwapWindow(_THIS, SDL_Window * window)
   557 {
   558     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   559     Display *display = data->videodata->display;
   560 
   561     _this->gl_data->glXSwapBuffers(display, data->xwindow);
   562 }
   563 
   564 void
   565 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
   566 {
   567     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   568     GLXContext glx_context = (GLXContext) context;
   569 
   570     _this->gl_data->glXDestroyContext(display, glx_context);
   571     XSync(display, False);
   572 }
   573 
   574 #endif /* SDL_VIDEO_OPENGL_GLX */
   575 
   576 /* vi: set ts=4 sw=4 expandtab: */