src/video/x11/SDL_x11gl.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 01 Feb 2006 08:17:54 +0000
changeset 1315 e94b0d7c33bc
parent 1312 c9b51268668f
child 1336 3692456e7b0f
permissions -rw-r--r--
Merged useful fixes from 1.3 branch
     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 
    23 #include <stdlib.h>	/* For getenv() prototype */
    24 #include <string.h>
    25 
    26 #include "SDL_events_c.h"
    27 #include "SDL_error.h"
    28 #include "SDL_x11video.h"
    29 #include "SDL_x11dga_c.h"
    30 #include "SDL_x11gl_c.h"
    31 
    32 #if defined(sgi)
    33 /* IRIX doesn't have a GL library versioning system */
    34 #define DEFAULT_OPENGL	"libGL.so"
    35 #elif defined(MACOSX)
    36 #define DEFAULT_OPENGL	"/usr/X11R6/lib/libGL.1.dylib"
    37 #else
    38 #define DEFAULT_OPENGL	"libGL.so.1"
    39 #endif
    40 
    41 #ifndef GLX_ARB_multisample
    42 #define GLX_ARB_multisample
    43 #define GLX_SAMPLE_BUFFERS_ARB             100000
    44 #define GLX_SAMPLES_ARB                    100001
    45 #endif
    46 
    47 XVisualInfo *X11_GL_GetVisual(_THIS)
    48 {
    49 #ifdef HAVE_OPENGL_X11
    50 	/* 64 seems nice. */
    51 	int attribs[64];
    52 	int i;
    53 
    54 	/* load the gl driver from a default path */
    55 	if ( ! this->gl_config.driver_loaded ) {
    56 	        /* no driver has been loaded, use default (ourselves) */
    57 	        if ( X11_GL_LoadLibrary(this, NULL) < 0 ) {
    58 		        return NULL;
    59 		}
    60 	}
    61 
    62 	/* See if we already have a window which we must use */
    63 	if ( SDL_windowid ) {
    64 		XWindowAttributes a;
    65 		XVisualInfo vi_in;
    66 		int out_count;
    67 
    68 		pXGetWindowAttributes(SDL_Display, SDL_Window, &a);
    69 		vi_in.screen = SDL_Screen;
    70 		vi_in.visualid = pXVisualIDFromVisual(a.visual);
    71 		glx_visualinfo = pXGetVisualInfo(SDL_Display,
    72 	                     VisualScreenMask|VisualIDMask, &vi_in, &out_count);
    73 		return glx_visualinfo;
    74 	}
    75 
    76         /* Setup our GLX attributes according to the gl_config. */
    77 	i = 0;
    78 	attribs[i++] = GLX_RGBA;
    79 	attribs[i++] = GLX_RED_SIZE;
    80 	attribs[i++] = this->gl_config.red_size;
    81 	attribs[i++] = GLX_GREEN_SIZE;
    82 	attribs[i++] = this->gl_config.green_size;
    83 	attribs[i++] = GLX_BLUE_SIZE;
    84 	attribs[i++] = this->gl_config.blue_size;
    85 
    86 	if( this->gl_config.alpha_size ) {
    87 		attribs[i++] = GLX_ALPHA_SIZE;
    88 		attribs[i++] = this->gl_config.alpha_size;
    89 	}
    90 
    91 	if( this->gl_config.buffer_size ) {
    92 		attribs[i++] = GLX_BUFFER_SIZE;
    93 		attribs[i++] = this->gl_config.buffer_size;
    94 	}
    95 
    96 	if( this->gl_config.double_buffer ) {
    97 		attribs[i++] = GLX_DOUBLEBUFFER;
    98 	}
    99 
   100 	attribs[i++] = GLX_DEPTH_SIZE;
   101 	attribs[i++] = this->gl_config.depth_size;
   102 
   103 	if( this->gl_config.stencil_size ) {
   104 		attribs[i++] = GLX_STENCIL_SIZE;
   105 		attribs[i++] = this->gl_config.stencil_size;
   106 	}
   107 
   108 	if( this->gl_config.accum_red_size ) {
   109 		attribs[i++] = GLX_ACCUM_RED_SIZE;
   110 		attribs[i++] = this->gl_config.accum_red_size;
   111 	}
   112 
   113 	if( this->gl_config.accum_green_size ) {
   114 		attribs[i++] = GLX_ACCUM_GREEN_SIZE;
   115 		attribs[i++] = this->gl_config.accum_green_size;
   116 	}
   117 
   118 	if( this->gl_config.accum_blue_size ) {
   119 		attribs[i++] = GLX_ACCUM_BLUE_SIZE;
   120 		attribs[i++] = this->gl_config.accum_blue_size;
   121 	}
   122 
   123 	if( this->gl_config.accum_alpha_size ) {
   124 		attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
   125 		attribs[i++] = this->gl_config.accum_alpha_size;
   126 	}
   127 
   128 	if( this->gl_config.stereo ) {
   129 		attribs[i++] = GLX_STEREO;
   130 		attribs[i++] = this->gl_config.stereo;
   131 	}
   132 	
   133 	if( this->gl_config.multisamplebuffers ) {
   134 		attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
   135 		attribs[i++] = this->gl_config.multisamplebuffers;
   136 	}
   137 	
   138 	if( this->gl_config.multisamplesamples ) {
   139 		attribs[i++] = GLX_SAMPLES_ARB;
   140 		attribs[i++] = this->gl_config.multisamplesamples;
   141 	}
   142 
   143 #ifdef GLX_DIRECT_COLOR /* Try for a DirectColor visual for gamma support */
   144 	if ( !getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) {
   145 		attribs[i++] = GLX_X_VISUAL_TYPE;
   146 		attribs[i++] = GLX_DIRECT_COLOR;
   147 	}
   148 #endif
   149 	attribs[i++] = None;
   150 
   151  	glx_visualinfo = this->gl_data->glXChooseVisual(GFX_Display, 
   152 						  SDL_Screen, attribs);
   153 #ifdef GLX_DIRECT_COLOR
   154 	if( !glx_visualinfo && !getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) { /* No DirectColor visual?  Try again.. */
   155 		attribs[i-3] = None;
   156  		glx_visualinfo = this->gl_data->glXChooseVisual(GFX_Display, 
   157 						  SDL_Screen, attribs);
   158 	}
   159 #endif
   160 	if( !glx_visualinfo ) {
   161 		SDL_SetError( "Couldn't find matching GLX visual");
   162 		return NULL;
   163 	}
   164 /*
   165 	printf("Found GLX visual 0x%x\n", glx_visualinfo->visualid);
   166 */
   167 	return glx_visualinfo;
   168 #else
   169 	SDL_SetError("X11 driver not configured with OpenGL");
   170 	return NULL;
   171 #endif
   172 }
   173 
   174 int X11_GL_CreateWindow(_THIS, int w, int h)
   175 {
   176 	int retval;
   177 #ifdef HAVE_OPENGL_X11
   178 	XSetWindowAttributes attributes;
   179 	unsigned long mask;
   180 	unsigned long black;
   181 
   182 	black = (glx_visualinfo->visual == DefaultVisual(SDL_Display,
   183 						 	SDL_Screen))
   184 	       	? BlackPixel(SDL_Display, SDL_Screen) : 0;
   185 	attributes.background_pixel = black;
   186 	attributes.border_pixel = black;
   187 	attributes.colormap = SDL_XColorMap;
   188 	mask = CWBackPixel | CWBorderPixel | CWColormap;
   189 
   190 	SDL_Window = pXCreateWindow(SDL_Display, WMwindow,
   191 			0, 0, w, h, 0, glx_visualinfo->depth,
   192 			InputOutput, glx_visualinfo->visual,
   193 			mask, &attributes);
   194 	if ( !SDL_Window ) {
   195 		SDL_SetError("Could not create window");
   196 		return -1;
   197 	}
   198 	retval = 0;
   199 #else
   200 	SDL_SetError("X11 driver not configured with OpenGL");
   201 	retval = -1;
   202 #endif
   203 	return(retval);
   204 }
   205 
   206 int X11_GL_CreateContext(_THIS)
   207 {
   208 	int retval;
   209 #ifdef HAVE_OPENGL_X11
   210 	/* We do this to create a clean separation between X and GLX errors. */
   211 	pXSync( SDL_Display, False );
   212 	glx_context = this->gl_data->glXCreateContext(GFX_Display, 
   213 				     glx_visualinfo, NULL, True);
   214 	pXSync( GFX_Display, False );
   215 
   216 	if (glx_context == NULL) {
   217 		SDL_SetError("Could not create GL context");
   218 		return -1;
   219 	}
   220 
   221 	gl_active = 1;
   222 #else
   223 	SDL_SetError("X11 driver not configured with OpenGL");
   224 #endif
   225 	if ( gl_active ) {
   226 		retval = 0;
   227 	} else {
   228 		retval = -1;
   229 	}
   230 	return(retval);
   231 }
   232 
   233 void X11_GL_Shutdown(_THIS)
   234 {
   235 #ifdef HAVE_OPENGL_X11
   236 	/* Clean up OpenGL */
   237 	if( glx_context ) {
   238 		this->gl_data->glXMakeCurrent(GFX_Display, None, NULL);
   239 
   240 		if (glx_context != NULL)
   241 			this->gl_data->glXDestroyContext(GFX_Display, glx_context);
   242 
   243 		glx_context = NULL;
   244 	}
   245 	gl_active = 0;
   246 #endif /* HAVE_OPENGL_X11 */
   247 }
   248 
   249 #ifdef HAVE_OPENGL_X11
   250 
   251 /* Make the current context active */
   252 int X11_GL_MakeCurrent(_THIS)
   253 {
   254 	int retval;
   255 	
   256 	retval = 0;
   257 	if ( ! this->gl_data->glXMakeCurrent(GFX_Display,
   258 	                                     SDL_Window, glx_context) ) {
   259 		SDL_SetError("Unable to make GL context current");
   260 		retval = -1;
   261 	}
   262 	pXSync( GFX_Display, False );
   263 
   264 	/* More Voodoo X server workarounds... Grr... */
   265 	SDL_Lock_EventThread();
   266 	X11_CheckDGAMouse(this);
   267 	SDL_Unlock_EventThread();
   268 
   269 	return(retval);
   270 }
   271 
   272 /* Get attribute data from glX. */
   273 int X11_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value)
   274 {
   275 	int retval;
   276 	int glx_attrib = None;
   277 
   278 	switch( attrib ) {
   279 	    case SDL_GL_RED_SIZE:
   280 		glx_attrib = GLX_RED_SIZE;
   281 		break;
   282 	    case SDL_GL_GREEN_SIZE:
   283 		glx_attrib = GLX_GREEN_SIZE;
   284 		break;
   285 	    case SDL_GL_BLUE_SIZE:
   286 		glx_attrib = GLX_BLUE_SIZE;
   287 		break;
   288 	    case SDL_GL_ALPHA_SIZE:
   289 		glx_attrib = GLX_ALPHA_SIZE;
   290 		break;
   291 	    case SDL_GL_DOUBLEBUFFER:
   292 		glx_attrib = GLX_DOUBLEBUFFER;
   293 		break;
   294 	    case SDL_GL_BUFFER_SIZE:
   295 		glx_attrib = GLX_BUFFER_SIZE;
   296 		break;
   297 	    case SDL_GL_DEPTH_SIZE:
   298 		glx_attrib = GLX_DEPTH_SIZE;
   299 		break;
   300 	    case SDL_GL_STENCIL_SIZE:
   301 		glx_attrib = GLX_STENCIL_SIZE;
   302 		break;
   303 	    case SDL_GL_ACCUM_RED_SIZE:
   304 		glx_attrib = GLX_ACCUM_RED_SIZE;
   305 		break;
   306 	    case SDL_GL_ACCUM_GREEN_SIZE:
   307 		glx_attrib = GLX_ACCUM_GREEN_SIZE;
   308 		break;
   309 	    case SDL_GL_ACCUM_BLUE_SIZE:
   310 		glx_attrib = GLX_ACCUM_BLUE_SIZE;
   311 		break;
   312 	    case SDL_GL_ACCUM_ALPHA_SIZE:
   313 		glx_attrib = GLX_ACCUM_ALPHA_SIZE;
   314 		break;
   315 	    case SDL_GL_STEREO:
   316 		glx_attrib = GLX_STEREO;
   317 		break;
   318  	    case SDL_GL_MULTISAMPLEBUFFERS:
   319  		glx_attrib = GLX_SAMPLE_BUFFERS_ARB;
   320  		break;
   321  	    case SDL_GL_MULTISAMPLESAMPLES:
   322  		glx_attrib = GLX_SAMPLES_ARB;
   323  		break;
   324 	    default:
   325 		return(-1);
   326 	}
   327 
   328 	retval = this->gl_data->glXGetConfig(GFX_Display, glx_visualinfo, glx_attrib, value);
   329 
   330 	return retval;
   331 }
   332 
   333 void X11_GL_SwapBuffers(_THIS)
   334 {
   335 	this->gl_data->glXSwapBuffers(GFX_Display, SDL_Window);
   336 }
   337 
   338 #endif /* HAVE_OPENGL_X11 */
   339 
   340 void X11_GL_UnloadLibrary(_THIS)
   341 {
   342 #ifdef HAVE_OPENGL_X11
   343 	if ( this->gl_config.driver_loaded ) {
   344 
   345 		/* !!! FIXME: Can we just use SDL_UnloadObject() everywhere? */
   346 		#ifdef USE_DLOPEN
   347 		dlclose(this->gl_config.dll_handle);
   348 		#else
   349 		SDL_UnloadObject(this->gl_config.dll_handle);
   350 		#endif
   351 
   352 		this->gl_data->glXGetProcAddress = NULL;
   353 		this->gl_data->glXChooseVisual = NULL;
   354 		this->gl_data->glXCreateContext = NULL;
   355 		this->gl_data->glXDestroyContext = NULL;
   356 		this->gl_data->glXMakeCurrent = NULL;
   357 		this->gl_data->glXSwapBuffers = NULL;
   358 
   359 		this->gl_config.dll_handle = NULL;
   360 		this->gl_config.driver_loaded = 0;
   361 	}
   362 #endif
   363 }
   364 
   365 #ifdef HAVE_OPENGL_X11
   366 
   367 static void *do_dlsym(void *handle, const char *name)
   368 {
   369 	/* !!! FIXME: Can we just use SDL_LoadFunction() everywhere? */
   370 #ifdef USE_DLOPEN
   371 	return dlsym(handle, name);
   372 #else
   373 	return SDL_LoadFunction(handle, name);
   374 #endif
   375 }
   376 
   377 #if defined(__OpenBSD__) && !defined(__ELF__)
   378 #define do_dlsym(x,y) do_dlsym(x, "_" y)
   379 #endif
   380 
   381 /* Passing a NULL path means load pointers from the application */
   382 int X11_GL_LoadLibrary(_THIS, const char* path) 
   383 {
   384 	void* handle = NULL;
   385 
   386 	if ( gl_active ) {
   387 		SDL_SetError("OpenGL context already created");
   388 		return -1;
   389 	}
   390 
   391 	if ( path == NULL ) {
   392 		path = getenv("SDL_VIDEO_GL_DRIVER");
   393 		if ( path == NULL ) {
   394 			path = DEFAULT_OPENGL;
   395 		}
   396 	}
   397 
   398 	/* !!! FIXME: Can we just use SDL_LoadObject() everywhere? */
   399 	#ifdef USE_DLOPEN
   400 	{
   401 		#ifdef RTLD_GLOBAL
   402 			int dlopen_flags = RTLD_LAZY | RTLD_GLOBAL;
   403 		#else
   404 			int dlopen_flags = RTLD_LAZY;
   405 		#endif
   406 		handle = dlopen(path, dlopen_flags);
   407 		if ( handle == NULL ) {
   408 			SDL_SetError("Could not load OpenGL library: %s", (const char *) dlerror());
   409 			return -1;
   410 		}
   411 	}
   412 	#else
   413 		handle = SDL_LoadObject(path);
   414 		if ( handle == NULL ) {
   415 			/* SDL_LoadObject() will call SDL_SetError() for us. */
   416 			return -1;
   417 		}
   418 	#endif
   419 
   420 
   421 	/* Unload the old driver and reset the pointers */
   422 	X11_GL_UnloadLibrary(this);
   423 
   424 	/* Load new function pointers */
   425 	this->gl_data->glXGetProcAddress =
   426 		(void *(*)(const GLubyte *)) do_dlsym(handle, "glXGetProcAddressARB");
   427 	this->gl_data->glXChooseVisual =
   428 		(XVisualInfo *(*)(Display *, int, int *)) do_dlsym(handle, "glXChooseVisual");
   429 	this->gl_data->glXCreateContext =
   430 		(GLXContext (*)(Display *, XVisualInfo *, GLXContext, int)) do_dlsym(handle, "glXCreateContext");
   431 	this->gl_data->glXDestroyContext =
   432 		(void (*)(Display *, GLXContext)) do_dlsym(handle, "glXDestroyContext");
   433 	this->gl_data->glXMakeCurrent =
   434 		(int (*)(Display *, GLXDrawable, GLXContext)) do_dlsym(handle, "glXMakeCurrent");
   435 	this->gl_data->glXSwapBuffers =
   436 		(void (*)(Display *, GLXDrawable)) do_dlsym(handle, "glXSwapBuffers");
   437 	this->gl_data->glXGetConfig =
   438 		(int (*)(Display *, XVisualInfo *, int, int *)) do_dlsym(handle, "glXGetConfig");
   439 	this->gl_data->glXQueryExtensionsString =
   440 		(const char *(*)(Display *, int)) do_dlsym(handle, "glXQueryExtensionsString");
   441 	
   442 
   443 	if ( (this->gl_data->glXChooseVisual == NULL) || 
   444 	     (this->gl_data->glXCreateContext == NULL) ||
   445 	     (this->gl_data->glXDestroyContext == NULL) ||
   446 	     (this->gl_data->glXMakeCurrent == NULL) ||
   447 	     (this->gl_data->glXSwapBuffers == NULL) ||
   448 	     (this->gl_data->glXGetConfig == NULL) ||
   449 	     (this->gl_data->glXQueryExtensionsString == NULL)) {
   450 		SDL_SetError("Could not retrieve OpenGL functions");
   451 		return -1;
   452 	}
   453 
   454 	this->gl_config.dll_handle = handle;
   455 	this->gl_config.driver_loaded = 1;
   456 	if ( path ) {
   457 		strncpy(this->gl_config.driver_path, path,
   458 			sizeof(this->gl_config.driver_path)-1);
   459 	} else {
   460 		strcpy(this->gl_config.driver_path, "");
   461 	}
   462 	return 0;
   463 }
   464 
   465 void *X11_GL_GetProcAddress(_THIS, const char* proc)
   466 {
   467 	static char procname[1024];
   468 	void* handle;
   469 	void* retval;
   470 	
   471 	handle = this->gl_config.dll_handle;
   472 	if ( this->gl_data->glXGetProcAddress ) {
   473 		return this->gl_data->glXGetProcAddress((const GLubyte *)proc);
   474 	}
   475 #if defined(__OpenBSD__) && !defined(__ELF__)
   476 #undef do_dlsym
   477 #endif
   478 	retval = do_dlsym(handle, proc);
   479 	if (!retval && strlen(proc) <= 1022) {
   480 		procname[0] = '_';
   481 		strcpy(procname + 1, proc);
   482 		retval = do_dlsym(handle, procname);
   483 	}
   484 	return retval;
   485 }
   486 
   487 #endif /* HAVE_OPENGL_X11 */