src/video/x11/SDL_x11gl.c
author Ryan C. Gordon
Tue, 29 Sep 2009 13:50:33 +0000
branchSDL-1.2
changeset 4268 d48035d857d3
parent 4183 39e748f251c6
child 4289 91c458013850
permissions -rw-r--r--
Make SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL) work with GLX_SGI_swap_control.

Fixes Bugzilla #697.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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 #include "../../events/SDL_events_c.h"
    26 #include "SDL_x11dga_c.h"
    27 #include "SDL_x11gl_c.h"
    28 
    29 #if defined(__IRIX__)
    30 /* IRIX doesn't have a GL library versioning system */
    31 #define DEFAULT_OPENGL	"libGL.so"
    32 #elif defined(__MACOSX__)
    33 #define DEFAULT_OPENGL	"/usr/X11R6/lib/libGL.1.dylib"
    34 #elif defined(__QNXNTO__)
    35 #define DEFAULT_OPENGL	"libGL.so.3"
    36 #elif defined(__OpenBSD__)
    37 #define DEFAULT_OPENGL	"libGL.so.4.0"
    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 /* GLX_EXT_visual_rating stuff that might not be in the system headers... */
    49 #ifndef GLX_VISUAL_CAVEAT_EXT
    50 #define GLX_VISUAL_CAVEAT_EXT              0x20
    51 #endif
    52 #ifndef GLX_NONE_EXT
    53 #define GLX_NONE_EXT                       0x8000
    54 #endif
    55 #ifndef GLX_SLOW_VISUAL_EXT
    56 #define GLX_SLOW_VISUAL_EXT                0x8001
    57 #endif
    58 #ifndef GLX_NON_CONFORMANT_VISUAL_EXT
    59 #define GLX_NON_CONFORMANT_VISUAL_EXT      0x800D
    60 #endif
    61 
    62 
    63 #if SDL_VIDEO_OPENGL_GLX
    64 static int glXExtensionSupported(_THIS, const char *extension)
    65 {
    66 	const char *extensions;
    67 	const char *start;
    68 	const char *where, *terminator;
    69 
    70 	/* Extension names should not have spaces. */
    71 	where = SDL_strchr(extension, ' ');
    72 	if ( where || *extension == '\0' ) {
    73 	      return 0;
    74 	}
    75 
    76 	extensions = this->gl_data->glXQueryExtensionsString(GFX_Display,SDL_Screen);
    77 	/* It takes a bit of care to be fool-proof about parsing the
    78 	 * OpenGL extensions string. Don't be fooled by sub-strings, etc.
    79 	 */
    80 	
    81 	start = extensions;
    82 	
    83 	for (;;) {
    84 		where = SDL_strstr(start, extension);
    85 		if (!where) break;
    86 		
    87 		terminator = where + strlen(extension);
    88 		if (where == start || *(where - 1) == ' ')
    89 	        if (*terminator == ' ' || *terminator == '\0') return 1;
    90 						  
    91 		start = terminator;
    92 	}
    93 	return 0;
    94 }
    95 #endif /* SDL_VIDEO_OPENGL_GLX */
    96 
    97 XVisualInfo *X11_GL_GetVisual(_THIS)
    98 {
    99 #if SDL_VIDEO_OPENGL_GLX
   100 	/* 64 seems nice. */
   101 	int attribs[64];
   102 	int i;
   103 
   104 	/* load the gl driver from a default path */
   105 	if ( ! this->gl_config.driver_loaded ) {
   106 	        /* no driver has been loaded, use default (ourselves) */
   107 	        if ( X11_GL_LoadLibrary(this, NULL) < 0 ) {
   108 		        return NULL;
   109 		}
   110 	}
   111 
   112 	/* See if we already have a window which we must use */
   113 	if ( SDL_windowid ) {
   114 		XWindowAttributes a;
   115 		XVisualInfo vi_in;
   116 		int out_count;
   117 
   118 		XGetWindowAttributes(SDL_Display, SDL_Window, &a);
   119 		vi_in.screen = SDL_Screen;
   120 		vi_in.visualid = XVisualIDFromVisual(a.visual);
   121 		glx_visualinfo = XGetVisualInfo(SDL_Display,
   122 	                     VisualScreenMask|VisualIDMask, &vi_in, &out_count);
   123 		return glx_visualinfo;
   124 	}
   125 
   126         /* Setup our GLX attributes according to the gl_config. */
   127 	i = 0;
   128 	attribs[i++] = GLX_RGBA;
   129 	attribs[i++] = GLX_RED_SIZE;
   130 	attribs[i++] = this->gl_config.red_size;
   131 	attribs[i++] = GLX_GREEN_SIZE;
   132 	attribs[i++] = this->gl_config.green_size;
   133 	attribs[i++] = GLX_BLUE_SIZE;
   134 	attribs[i++] = this->gl_config.blue_size;
   135 
   136 	if( this->gl_config.alpha_size ) {
   137 		attribs[i++] = GLX_ALPHA_SIZE;
   138 		attribs[i++] = this->gl_config.alpha_size;
   139 	}
   140 
   141 	if( this->gl_config.buffer_size ) {
   142 		attribs[i++] = GLX_BUFFER_SIZE;
   143 		attribs[i++] = this->gl_config.buffer_size;
   144 	}
   145 
   146 	if( this->gl_config.double_buffer ) {
   147 		attribs[i++] = GLX_DOUBLEBUFFER;
   148 	}
   149 
   150 	attribs[i++] = GLX_DEPTH_SIZE;
   151 	attribs[i++] = this->gl_config.depth_size;
   152 
   153 	if( this->gl_config.stencil_size ) {
   154 		attribs[i++] = GLX_STENCIL_SIZE;
   155 		attribs[i++] = this->gl_config.stencil_size;
   156 	}
   157 
   158 	if( this->gl_config.accum_red_size ) {
   159 		attribs[i++] = GLX_ACCUM_RED_SIZE;
   160 		attribs[i++] = this->gl_config.accum_red_size;
   161 	}
   162 
   163 	if( this->gl_config.accum_green_size ) {
   164 		attribs[i++] = GLX_ACCUM_GREEN_SIZE;
   165 		attribs[i++] = this->gl_config.accum_green_size;
   166 	}
   167 
   168 	if( this->gl_config.accum_blue_size ) {
   169 		attribs[i++] = GLX_ACCUM_BLUE_SIZE;
   170 		attribs[i++] = this->gl_config.accum_blue_size;
   171 	}
   172 
   173 	if( this->gl_config.accum_alpha_size ) {
   174 		attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
   175 		attribs[i++] = this->gl_config.accum_alpha_size;
   176 	}
   177 
   178 	if( this->gl_config.stereo ) {
   179 		attribs[i++] = GLX_STEREO;
   180 	}
   181 	
   182 	if( this->gl_config.multisamplebuffers ) {
   183 		attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
   184 		attribs[i++] = this->gl_config.multisamplebuffers;
   185 	}
   186 	
   187 	if( this->gl_config.multisamplesamples ) {
   188 		attribs[i++] = GLX_SAMPLES_ARB;
   189 		attribs[i++] = this->gl_config.multisamplesamples;
   190 	}
   191 
   192 	if( this->gl_config.accelerated >= 0 &&
   193 	    glXExtensionSupported(this, "GLX_EXT_visual_rating") ) {
   194 		attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
   195 		attribs[i++] = GLX_NONE_EXT;
   196 	}
   197 
   198 #ifdef GLX_DIRECT_COLOR /* Try for a DirectColor visual for gamma support */
   199 	if ( !SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) {
   200 		attribs[i++] = GLX_X_VISUAL_TYPE;
   201 		attribs[i++] = GLX_DIRECT_COLOR;
   202 	}
   203 #endif
   204 	attribs[i++] = None;
   205 
   206  	glx_visualinfo = this->gl_data->glXChooseVisual(GFX_Display, 
   207 						  SDL_Screen, attribs);
   208 #ifdef GLX_DIRECT_COLOR
   209 	if( !glx_visualinfo && !SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) { /* No DirectColor visual?  Try again.. */
   210 		attribs[i-3] = None;
   211  		glx_visualinfo = this->gl_data->glXChooseVisual(GFX_Display, 
   212 						  SDL_Screen, attribs);
   213 	}
   214 #endif
   215 	if( !glx_visualinfo ) {
   216 		SDL_SetError( "Couldn't find matching GLX visual");
   217 		return NULL;
   218 	}
   219 /*
   220 	printf("Found GLX visual 0x%x\n", glx_visualinfo->visualid);
   221 */
   222 	return glx_visualinfo;
   223 #else
   224 	SDL_SetError("X11 driver not configured with OpenGL");
   225 	return NULL;
   226 #endif
   227 }
   228 
   229 int X11_GL_CreateWindow(_THIS, int w, int h)
   230 {
   231 	int retval;
   232 #if SDL_VIDEO_OPENGL_GLX
   233 	XSetWindowAttributes attributes;
   234 	unsigned long mask;
   235 	unsigned long black;
   236 
   237 	black = (glx_visualinfo->visual == DefaultVisual(SDL_Display,
   238 						 	SDL_Screen))
   239 	       	? BlackPixel(SDL_Display, SDL_Screen) : 0;
   240 	attributes.background_pixel = black;
   241 	attributes.border_pixel = black;
   242 	attributes.colormap = SDL_XColorMap;
   243 	mask = CWBackPixel | CWBorderPixel | CWColormap;
   244 
   245 	SDL_Window = XCreateWindow(SDL_Display, WMwindow,
   246 			0, 0, w, h, 0, glx_visualinfo->depth,
   247 			InputOutput, glx_visualinfo->visual,
   248 			mask, &attributes);
   249 	if ( !SDL_Window ) {
   250 		SDL_SetError("Could not create window");
   251 		return -1;
   252 	}
   253 	retval = 0;
   254 #else
   255 	SDL_SetError("X11 driver not configured with OpenGL");
   256 	retval = -1;
   257 #endif
   258 	return(retval);
   259 }
   260 
   261 int X11_GL_CreateContext(_THIS)
   262 {
   263 	int retval;
   264 #if SDL_VIDEO_OPENGL_GLX
   265 
   266 	/* We do this to create a clean separation between X and GLX errors. */
   267 	XSync( SDL_Display, False );
   268 	glx_context = this->gl_data->glXCreateContext(GFX_Display, 
   269 				     glx_visualinfo, NULL, True);
   270 	XSync( GFX_Display, False );
   271 
   272 	if ( glx_context == NULL ) {
   273 		SDL_SetError("Could not create GL context");
   274 		return(-1);
   275 	}
   276 	if ( X11_GL_MakeCurrent(this) < 0 ) {
   277 		return(-1);
   278 	}
   279 	gl_active = 1;
   280 
   281 	if ( !glXExtensionSupported(this, "GLX_SGI_swap_control") ) {
   282 		this->gl_data->glXSwapIntervalSGI = NULL;
   283 	}
   284 	if ( !glXExtensionSupported(this, "GLX_MESA_swap_control") ) {
   285 		this->gl_data->glXSwapIntervalMESA = NULL;
   286 		this->gl_data->glXGetSwapIntervalMESA = NULL;
   287 	}
   288 	if ( this->gl_config.swap_control >= 0 ) {
   289 		if ( this->gl_data->glXSwapIntervalMESA ) {
   290 			this->gl_data->glXSwapIntervalMESA(this->gl_config.swap_control);
   291 		} else if ( this->gl_data->glXSwapIntervalSGI ) {
   292 			if (this->gl_data->glXSwapIntervalSGI(this->gl_config.swap_control) != 0) {
   293 				this->gl_data->sgi_swap_interval = this->gl_config.swap_control;
   294 			}
   295 		}
   296 	}
   297 #else
   298 	SDL_SetError("X11 driver not configured with OpenGL");
   299 #endif
   300 	if ( gl_active ) {
   301 		retval = 0;
   302 	} else {
   303 		retval = -1;
   304 	}
   305 	return(retval);
   306 }
   307 
   308 void X11_GL_Shutdown(_THIS)
   309 {
   310 #if SDL_VIDEO_OPENGL_GLX
   311 	/* Clean up OpenGL */
   312 	if( glx_context ) {
   313 		this->gl_data->glXMakeCurrent(GFX_Display, None, NULL);
   314 
   315 		if (glx_context != NULL)
   316 			this->gl_data->glXDestroyContext(GFX_Display, glx_context);
   317 
   318 		glx_context = NULL;
   319 	}
   320 	gl_active = 0;
   321 #endif /* SDL_VIDEO_OPENGL_GLX */
   322 }
   323 
   324 #if SDL_VIDEO_OPENGL_GLX
   325 
   326 /* Make the current context active */
   327 int X11_GL_MakeCurrent(_THIS)
   328 {
   329 	int retval;
   330 	
   331 	retval = 0;
   332 	if ( ! this->gl_data->glXMakeCurrent(GFX_Display,
   333 	                                     SDL_Window, glx_context) ) {
   334 		SDL_SetError("Unable to make GL context current");
   335 		retval = -1;
   336 	}
   337 	XSync( GFX_Display, False );
   338 
   339 	/* More Voodoo X server workarounds... Grr... */
   340 	SDL_Lock_EventThread();
   341 	X11_CheckDGAMouse(this);
   342 	SDL_Unlock_EventThread();
   343 
   344 	return(retval);
   345 }
   346 
   347 /* Get attribute data from glX. */
   348 int X11_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value)
   349 {
   350 	int retval = -1;
   351 	int unsupported = 0;
   352 	int glx_attrib = None;
   353 
   354 	switch( attrib ) {
   355 	    case SDL_GL_RED_SIZE:
   356 		glx_attrib = GLX_RED_SIZE;
   357 		break;
   358 	    case SDL_GL_GREEN_SIZE:
   359 		glx_attrib = GLX_GREEN_SIZE;
   360 		break;
   361 	    case SDL_GL_BLUE_SIZE:
   362 		glx_attrib = GLX_BLUE_SIZE;
   363 		break;
   364 	    case SDL_GL_ALPHA_SIZE:
   365 		glx_attrib = GLX_ALPHA_SIZE;
   366 		break;
   367 	    case SDL_GL_DOUBLEBUFFER:
   368 		glx_attrib = GLX_DOUBLEBUFFER;
   369 		break;
   370 	    case SDL_GL_BUFFER_SIZE:
   371 		glx_attrib = GLX_BUFFER_SIZE;
   372 		break;
   373 	    case SDL_GL_DEPTH_SIZE:
   374 		glx_attrib = GLX_DEPTH_SIZE;
   375 		break;
   376 	    case SDL_GL_STENCIL_SIZE:
   377 		glx_attrib = GLX_STENCIL_SIZE;
   378 		break;
   379 	    case SDL_GL_ACCUM_RED_SIZE:
   380 		glx_attrib = GLX_ACCUM_RED_SIZE;
   381 		break;
   382 	    case SDL_GL_ACCUM_GREEN_SIZE:
   383 		glx_attrib = GLX_ACCUM_GREEN_SIZE;
   384 		break;
   385 	    case SDL_GL_ACCUM_BLUE_SIZE:
   386 		glx_attrib = GLX_ACCUM_BLUE_SIZE;
   387 		break;
   388 	    case SDL_GL_ACCUM_ALPHA_SIZE:
   389 		glx_attrib = GLX_ACCUM_ALPHA_SIZE;
   390 		break;
   391 	    case SDL_GL_STEREO:
   392 		glx_attrib = GLX_STEREO;
   393 		break;
   394  	    case SDL_GL_MULTISAMPLEBUFFERS:
   395  		glx_attrib = GLX_SAMPLE_BUFFERS_ARB;
   396  		break;
   397  	    case SDL_GL_MULTISAMPLESAMPLES:
   398  		glx_attrib = GLX_SAMPLES_ARB;
   399  		break;
   400  	    case SDL_GL_ACCELERATED_VISUAL:
   401 		if ( glXExtensionSupported(this, "GLX_EXT_visual_rating") ) {
   402 			glx_attrib = GLX_VISUAL_CAVEAT_EXT;
   403 			retval = this->gl_data->glXGetConfig(GFX_Display, glx_visualinfo, glx_attrib, value);
   404 			if ( *value == GLX_SLOW_VISUAL_EXT ) {
   405 				*value = SDL_FALSE;
   406 			} else {
   407 				*value = SDL_TRUE;
   408 			}
   409 			return retval;
   410 		} else {
   411 			unsupported = 1;
   412 		}
   413 		break;
   414 	    case SDL_GL_SWAP_CONTROL:
   415 		if ( this->gl_data->glXGetSwapIntervalMESA ) {
   416 			*value = this->gl_data->glXGetSwapIntervalMESA();
   417 			return 0;
   418 		} else if ( this->gl_data->glXSwapIntervalSGI ) {
   419 			*value = this->gl_data->sgi_swap_interval;
   420 			return 0;
   421 		} else {
   422 			unsupported = 1;
   423 		}
   424 		break;
   425 	    default:
   426 			unsupported = 1;
   427 			break;
   428 	}
   429 
   430 	if (unsupported) {
   431 		SDL_SetError("OpenGL attribute is unsupported on this system");
   432 	} else {
   433 		retval = this->gl_data->glXGetConfig(GFX_Display, glx_visualinfo, glx_attrib, value);
   434 	}
   435 	return retval;
   436 }
   437 
   438 void X11_GL_SwapBuffers(_THIS)
   439 {
   440 	this->gl_data->glXSwapBuffers(GFX_Display, SDL_Window);
   441 }
   442 
   443 #endif /* SDL_VIDEO_OPENGL_GLX */
   444 
   445 #define OPENGL_REQUIRS_DLOPEN
   446 #if defined(OPENGL_REQUIRS_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   447 #include <dlfcn.h>
   448 #define GL_LoadObject(X)	dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
   449 #define GL_LoadFunction		dlsym
   450 #define GL_UnloadObject		dlclose
   451 #else
   452 #define GL_LoadObject	SDL_LoadObject
   453 #define GL_LoadFunction	SDL_LoadFunction
   454 #define GL_UnloadObject	SDL_UnloadObject
   455 #endif
   456 
   457 void X11_GL_UnloadLibrary(_THIS)
   458 {
   459 #if SDL_VIDEO_OPENGL_GLX
   460 	if ( this->gl_config.driver_loaded ) {
   461 
   462 		GL_UnloadObject(this->gl_config.dll_handle);
   463 
   464 		this->gl_data->glXGetProcAddress = NULL;
   465 		this->gl_data->glXChooseVisual = NULL;
   466 		this->gl_data->glXCreateContext = NULL;
   467 		this->gl_data->glXDestroyContext = NULL;
   468 		this->gl_data->glXMakeCurrent = NULL;
   469 		this->gl_data->glXSwapBuffers = NULL;
   470 		this->gl_data->glXSwapIntervalSGI = NULL;
   471 		this->gl_data->glXSwapIntervalMESA = NULL;
   472 		this->gl_data->glXGetSwapIntervalMESA = NULL;
   473 
   474 		this->gl_config.dll_handle = NULL;
   475 		this->gl_config.driver_loaded = 0;
   476 	}
   477 #endif
   478 }
   479 
   480 #if SDL_VIDEO_OPENGL_GLX
   481 
   482 /* Passing a NULL path means load pointers from the application */
   483 int X11_GL_LoadLibrary(_THIS, const char* path) 
   484 {
   485 	void* handle = NULL;
   486 
   487 	if ( gl_active ) {
   488 		SDL_SetError("OpenGL context already created");
   489 		return -1;
   490 	}
   491 
   492 	if ( path == NULL ) {
   493 		path = SDL_getenv("SDL_VIDEO_GL_DRIVER");
   494 		if ( path == NULL ) {
   495 			path = DEFAULT_OPENGL;
   496 		}
   497 	}
   498 
   499 	handle = GL_LoadObject(path);
   500 	if ( handle == NULL ) {
   501 #if defined(OPENGL_REQUIRS_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   502 		SDL_SetError("Failed loading %s", path);
   503 #else
   504 		/* SDL_LoadObject() will call SDL_SetError() for us. */
   505 #endif
   506 		return -1;
   507 	}
   508 
   509 	/* Unload the old driver and reset the pointers */
   510 	X11_GL_UnloadLibrary(this);
   511 
   512 	/* Load new function pointers */
   513 	this->gl_data->glXGetProcAddress =
   514 		(void *(*)(const GLubyte *)) GL_LoadFunction(handle, "glXGetProcAddressARB");
   515 	this->gl_data->glXChooseVisual =
   516 		(XVisualInfo *(*)(Display *, int, int *)) GL_LoadFunction(handle, "glXChooseVisual");
   517 	this->gl_data->glXCreateContext =
   518 		(GLXContext (*)(Display *, XVisualInfo *, GLXContext, int)) GL_LoadFunction(handle, "glXCreateContext");
   519 	this->gl_data->glXDestroyContext =
   520 		(void (*)(Display *, GLXContext)) GL_LoadFunction(handle, "glXDestroyContext");
   521 	this->gl_data->glXMakeCurrent =
   522 		(int (*)(Display *, GLXDrawable, GLXContext)) GL_LoadFunction(handle, "glXMakeCurrent");
   523 	this->gl_data->glXSwapBuffers =
   524 		(void (*)(Display *, GLXDrawable)) GL_LoadFunction(handle, "glXSwapBuffers");
   525 	this->gl_data->glXGetConfig =
   526 		(int (*)(Display *, XVisualInfo *, int, int *)) GL_LoadFunction(handle, "glXGetConfig");
   527 	this->gl_data->glXQueryExtensionsString =
   528 		(const char *(*)(Display *, int)) GL_LoadFunction(handle, "glXQueryExtensionsString");
   529 	this->gl_data->glXSwapIntervalSGI =
   530 		(int (*)(int)) GL_LoadFunction(handle, "glXSwapIntervalSGI");
   531 	this->gl_data->glXSwapIntervalMESA =
   532 		(GLint (*)(unsigned)) GL_LoadFunction(handle, "glXSwapIntervalMESA");
   533 	this->gl_data->glXGetSwapIntervalMESA =
   534 		(GLint (*)(void)) GL_LoadFunction(handle, "glXGetSwapIntervalMESA");
   535 
   536 	if ( (this->gl_data->glXChooseVisual == NULL) || 
   537 	     (this->gl_data->glXCreateContext == NULL) ||
   538 	     (this->gl_data->glXDestroyContext == NULL) ||
   539 	     (this->gl_data->glXMakeCurrent == NULL) ||
   540 	     (this->gl_data->glXSwapBuffers == NULL) ||
   541 	     (this->gl_data->glXGetConfig == NULL) ||
   542 	     (this->gl_data->glXQueryExtensionsString == NULL)) {
   543 		SDL_SetError("Could not retrieve OpenGL functions");
   544 		return -1;
   545 	}
   546 
   547 	this->gl_config.dll_handle = handle;
   548 	this->gl_config.driver_loaded = 1;
   549 	if ( path ) {
   550 		SDL_strlcpy(this->gl_config.driver_path, path,
   551 			SDL_arraysize(this->gl_config.driver_path));
   552 	} else {
   553 		*this->gl_config.driver_path = '\0';
   554 	}
   555 	return 0;
   556 }
   557 
   558 void *X11_GL_GetProcAddress(_THIS, const char* proc)
   559 {
   560 	void* handle;
   561 	
   562 	handle = this->gl_config.dll_handle;
   563 	if ( this->gl_data->glXGetProcAddress ) {
   564 		return this->gl_data->glXGetProcAddress((const GLubyte *)proc);
   565 	}
   566 	return GL_LoadFunction(handle, proc);
   567 }
   568 
   569 #endif /* SDL_VIDEO_OPENGL_GLX */