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