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