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