src/video/x11/SDL_x11gl.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 22 Jul 2003 15:10:06 +0000
changeset 655 9c42ee1b7d77
parent 646 0f2029a70548
child 656 864e2d2a9a55
permissions -rw-r--r--
Date: Thu, 24 Apr 2003 15:13:47 -0400
From: Shawn Kirst
Subject: SDL-1.2.5 patch to add ARB_multisample support

Attached is a patch I have written for SDL-1.2.5 that adds ARB_multisample
support. I only have the X11 and Win32 video patched. The Win32 patch also
adds support for WGL_ARB_pixel_format, as it was required for getting a
multisample capable pixel format. No additional GL header files are required
to compile on either platform (though you need an up-to-date glx.h for X11).

Requesting a multisample pixel format is made possible using
SDL_GL_SetAttribute with the two new SDL_GLattr's I've added
(SDL_GL_SAMPLE_BUFFERS and SDL_GL_SAMPLES). I've been using SDL in my
projects for quite a while now, so I am happy to contribute back to the
project. Now you can have and control FSAA in your SDL/GL apps at the
application level!
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 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     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 #include <stdlib.h>	/* For getenv() prototype */
    29 #include <string.h>
    30 
    31 #include "SDL_events_c.h"
    32 #include "SDL_error.h"
    33 #include "SDL_x11video.h"
    34 #include "SDL_x11dga_c.h"
    35 #include "SDL_x11gl_c.h"
    36 
    37 #define DEFAULT_OPENGL	"libGL.so.1"
    38 
    39 /* return the preferred visual to use for openGL graphics */
    40 XVisualInfo *X11_GL_GetVisual(_THIS)
    41 {
    42 #ifdef HAVE_OPENGL
    43 	/* 64 seems nice. */
    44 	int attribs[64];
    45 	int i;
    46 
    47 	/* load the gl driver from a default path */
    48 	if ( ! this->gl_config.driver_loaded ) {
    49 	        /* no driver has been loaded, use default (ourselves) */
    50 	        if ( X11_GL_LoadLibrary(this, NULL) < 0 ) {
    51 		        return NULL;
    52 		}
    53 	}
    54 
    55 	/* See if we already have a window which we must use */
    56 	if ( SDL_windowid ) {
    57 		XWindowAttributes a;
    58 		XVisualInfo vi_in;
    59 		int out_count;
    60 
    61 		XGetWindowAttributes(SDL_Display, SDL_Window, &a);
    62 		vi_in.screen = SDL_Screen;
    63 		vi_in.visualid = XVisualIDFromVisual(a.visual);
    64 		glx_visualinfo = XGetVisualInfo(SDL_Display,
    65 	                     VisualScreenMask|VisualIDMask, &vi_in, &out_count);
    66 		return glx_visualinfo;
    67 	}
    68 
    69         /* Setup our GLX attributes according to the gl_config. */
    70 	i = 0;
    71 	attribs[i++] = GLX_RGBA;
    72 	attribs[i++] = GLX_RED_SIZE;
    73 	attribs[i++] = this->gl_config.red_size;
    74 	attribs[i++] = GLX_GREEN_SIZE;
    75 	attribs[i++] = this->gl_config.green_size;
    76 	attribs[i++] = GLX_BLUE_SIZE;
    77 	attribs[i++] = this->gl_config.blue_size;
    78 
    79 	if( this->gl_config.alpha_size ) {
    80 		attribs[i++] = GLX_ALPHA_SIZE;
    81 		attribs[i++] = this->gl_config.alpha_size;
    82 	}
    83 
    84 	if( this->gl_config.buffer_size ) {
    85 		attribs[i++] = GLX_BUFFER_SIZE;
    86 		attribs[i++] = this->gl_config.buffer_size;
    87 	}
    88 
    89 	if( this->gl_config.double_buffer ) {
    90 		attribs[i++] = GLX_DOUBLEBUFFER;
    91 	}
    92 
    93 	attribs[i++] = GLX_DEPTH_SIZE;
    94 	attribs[i++] = this->gl_config.depth_size;
    95 
    96 	if( this->gl_config.stencil_size ) {
    97 		attribs[i++] = GLX_STENCIL_SIZE;
    98 		attribs[i++] = this->gl_config.stencil_size;
    99 	}
   100 
   101 	if( this->gl_config.accum_red_size ) {
   102 		attribs[i++] = GLX_ACCUM_RED_SIZE;
   103 		attribs[i++] = this->gl_config.accum_red_size;
   104 	}
   105 
   106 	if( this->gl_config.accum_green_size ) {
   107 		attribs[i++] = GLX_ACCUM_GREEN_SIZE;
   108 		attribs[i++] = this->gl_config.accum_green_size;
   109 	}
   110 
   111 	if( this->gl_config.accum_blue_size ) {
   112 		attribs[i++] = GLX_ACCUM_BLUE_SIZE;
   113 		attribs[i++] = this->gl_config.accum_blue_size;
   114 	}
   115 
   116 	if( this->gl_config.accum_alpha_size ) {
   117 		attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
   118 		attribs[i++] = this->gl_config.accum_alpha_size;
   119 	}
   120 
   121 	if( this->gl_config.stereo ) {
   122 		attribs[i++] = GLX_STEREO;
   123 		attribs[i++] = this->gl_config.stereo;
   124 	}
   125 	
   126 	if( this->gl_config.sample_buffers ) {
   127 		attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
   128 		attribs[i++] = this->gl_config.sample_buffers;
   129 	}
   130 	
   131 	if( this->gl_config.samples ) {
   132 		attribs[i++] = GLX_SAMPLES_ARB;
   133 		attribs[i++] = this->gl_config.samples;
   134 	}
   135 
   136 #ifdef GLX_DIRECT_COLOR /* Try for a DirectColor visual for gamma support */
   137 	attribs[i++] = GLX_X_VISUAL_TYPE;
   138 	attribs[i++] = GLX_DIRECT_COLOR;
   139 #endif
   140 	attribs[i++] = None;
   141 
   142  	glx_visualinfo = this->gl_data->glXChooseVisual(GFX_Display, 
   143 						  SDL_Screen, attribs);
   144 #ifdef GLX_DIRECT_COLOR
   145 	if( !glx_visualinfo ) { /* No DirectColor visual?  Try again.. */
   146 		attribs[i-3] = None;
   147  		glx_visualinfo = this->gl_data->glXChooseVisual(GFX_Display, 
   148 						  SDL_Screen, attribs);
   149 	}
   150 #endif
   151 	if( !glx_visualinfo ) {
   152 		SDL_SetError( "Couldn't find matching GLX visual");
   153 		return NULL;
   154 	}
   155 	return glx_visualinfo;
   156 #else
   157 	SDL_SetError("X11 driver not configured with OpenGL");
   158 	return NULL;
   159 #endif
   160 }
   161 
   162 int X11_GL_CreateWindow(_THIS, int w, int h)
   163 {
   164 	int retval;
   165 #ifdef HAVE_OPENGL
   166 	XSetWindowAttributes attributes;
   167 	unsigned long mask;
   168 	unsigned long black;
   169 
   170 	black = (glx_visualinfo->visual == DefaultVisual(SDL_Display,
   171 						 	SDL_Screen))
   172 	       	? BlackPixel(SDL_Display, SDL_Screen) : 0;
   173 	attributes.background_pixel = black;
   174 	attributes.border_pixel = black;
   175 	attributes.colormap = SDL_XColorMap;
   176 	mask = CWBackPixel | CWBorderPixel | CWColormap;
   177 
   178 	SDL_Window = XCreateWindow(SDL_Display, WMwindow,
   179 			0, 0, w, h, 0, glx_visualinfo->depth,
   180 			InputOutput, glx_visualinfo->visual,
   181 			mask, &attributes);
   182 	if ( !SDL_Window ) {
   183 		SDL_SetError("Could not create window");
   184 		return -1;
   185 	}
   186 	retval = 0;
   187 #else
   188 	SDL_SetError("X11 driver not configured with OpenGL");
   189 	retval = -1;
   190 #endif
   191 	return(retval);
   192 }
   193 
   194 int X11_GL_CreateContext(_THIS)
   195 {
   196 	int retval;
   197 #ifdef HAVE_OPENGL
   198 	/* We do this to create a clean separation between X and GLX errors. */
   199 	XSync( SDL_Display, False );
   200 	glx_context = this->gl_data->glXCreateContext(GFX_Display, 
   201 				     glx_visualinfo, NULL, True);
   202 	XSync( GFX_Display, False );
   203 
   204 	if (glx_context == NULL) {
   205 		SDL_SetError("Could not create GL context");
   206 		return -1;
   207 	}
   208 
   209 	gl_active = 1;
   210 #else
   211 	SDL_SetError("X11 driver not configured with OpenGL");
   212 #endif
   213 	if ( gl_active ) {
   214 		retval = 0;
   215 	} else {
   216 		retval = -1;
   217 	}
   218 	return(retval);
   219 }
   220 
   221 void X11_GL_Shutdown(_THIS)
   222 {
   223 #ifdef HAVE_OPENGL
   224 	/* Clean up OpenGL */
   225 	if( glx_context ) {
   226 		this->gl_data->glXMakeCurrent(GFX_Display, None, NULL);
   227 
   228 		if (glx_context != NULL)
   229 			this->gl_data->glXDestroyContext(GFX_Display, glx_context);
   230 
   231 		if( this->gl_data->glXReleaseBuffersMESA ) {
   232 		    this->gl_data->glXReleaseBuffersMESA(GFX_Display,SDL_Window);
   233 		}
   234 		glx_context = NULL;
   235 	}
   236 	gl_active = 0;
   237 #endif /* HAVE_OPENGL */
   238 }
   239 
   240 #ifdef HAVE_OPENGL
   241 
   242 static int ExtensionSupported(const char *extension)
   243 {
   244 	const GLubyte *extensions = NULL;
   245 	const GLubyte *start;
   246 	GLubyte *where, *terminator;
   247 
   248 	/* Extension names should not have spaces. */
   249 	where = (GLubyte *) strchr(extension, ' ');
   250 	if (where || *extension == '\0')
   251 	      return 0;
   252 	
   253 	extensions = current_video->glGetString(GL_EXTENSIONS);
   254 	/* It takes a bit of care to be fool-proof about parsing the
   255 	 *      OpenGL extensions string. Don't be fooled by sub-strings,
   256 	 *           etc. */
   257 	
   258 	start = extensions;
   259 	
   260 	for (;;)
   261 	{
   262 		where = (GLubyte *) strstr((const char *) start, extension);
   263 		if (!where) break;
   264 		
   265 		terminator = where + strlen(extension);
   266 		if (where == start || *(where - 1) == ' ')
   267 	        if (*terminator == ' ' || *terminator == '\0') return 1;
   268 						  
   269 		start = terminator;
   270 	}
   271 	
   272 	return 0;
   273 }
   274 
   275 /* Make the current context active */
   276 int X11_GL_MakeCurrent(_THIS)
   277 {
   278 	int retval;
   279 	
   280 	retval = 0;
   281 	if ( ! this->gl_data->glXMakeCurrent(GFX_Display,
   282 	                                     SDL_Window, glx_context) ) {
   283 		SDL_SetError("Unable to make GL context current");
   284 		retval = -1;
   285 	}
   286 	XSync( GFX_Display, False );
   287 
   288 	/* 
   289 	 * The context is now current, check for glXReleaseBuffersMESA() 
   290 	 * extension. If extension is _not_ supported, destroy the pointer 
   291 	 * (to make sure it will not be called in X11_GL_Shutdown() ).
   292 	 * 
   293 	 * DRI/Mesa drivers include glXReleaseBuffersMESA() in the libGL.so, 
   294 	 * but there's no need to call it (is is only needed for some old 
   295 	 * non-DRI drivers).
   296 	 * 
   297 	 * When using for example glew (http://glew.sf.net), dlsym() for
   298 	 * glXReleaseBuffersMESA() returns the pointer from the glew library
   299 	 * (namespace conflict).
   300 	 *
   301 	 * The glXReleaseBuffersMESA() pointer in the glew is NULL, if the 
   302 	 * driver doesn't support this extension. So blindly calling it will
   303 	 * cause segfault with DRI/Mesa drivers!
   304 	 * 
   305 	 */
   306 	
   307 	if ( ! ExtensionSupported("glXReleaseBuffersMESA") ) {
   308 		this->gl_data->glXReleaseBuffersMESA = NULL;
   309 	}
   310 
   311 	/* More Voodoo X server workarounds... Grr... */
   312 	SDL_Lock_EventThread();
   313 	X11_CheckDGAMouse(this);
   314 	SDL_Unlock_EventThread();
   315 
   316 	return(retval);
   317 }
   318 
   319 /* Get attribute data from glX. */
   320 int X11_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value)
   321 {
   322 	int retval;
   323 	int glx_attrib = None;
   324 
   325 	switch( attrib ) {
   326 	    case SDL_GL_RED_SIZE:
   327 		glx_attrib = GLX_RED_SIZE;
   328 		break;
   329 	    case SDL_GL_GREEN_SIZE:
   330 		glx_attrib = GLX_GREEN_SIZE;
   331 		break;
   332 	    case SDL_GL_BLUE_SIZE:
   333 		glx_attrib = GLX_BLUE_SIZE;
   334 		break;
   335 	    case SDL_GL_ALPHA_SIZE:
   336 		glx_attrib = GLX_ALPHA_SIZE;
   337 		break;
   338 	    case SDL_GL_DOUBLEBUFFER:
   339 		glx_attrib = GLX_DOUBLEBUFFER;
   340 		break;
   341 	    case SDL_GL_BUFFER_SIZE:
   342 		glx_attrib = GLX_BUFFER_SIZE;
   343 		break;
   344 	    case SDL_GL_DEPTH_SIZE:
   345 		glx_attrib = GLX_DEPTH_SIZE;
   346 		break;
   347 	    case SDL_GL_STENCIL_SIZE:
   348 		glx_attrib = GLX_STENCIL_SIZE;
   349 		break;
   350 	    case SDL_GL_ACCUM_RED_SIZE:
   351 		glx_attrib = GLX_ACCUM_RED_SIZE;
   352 		break;
   353 	    case SDL_GL_ACCUM_GREEN_SIZE:
   354 		glx_attrib = GLX_ACCUM_GREEN_SIZE;
   355 		break;
   356 	    case SDL_GL_ACCUM_BLUE_SIZE:
   357 		glx_attrib = GLX_ACCUM_BLUE_SIZE;
   358 		break;
   359 	    case SDL_GL_ACCUM_ALPHA_SIZE:
   360 		glx_attrib = GLX_ACCUM_ALPHA_SIZE;
   361 		break;
   362 	    case SDL_GL_STEREO:
   363 		glx_attrib = GLX_STEREO;
   364 		break;
   365  	    case SDL_GL_SAMPLE_BUFFERS:
   366  		glx_attrib = GLX_SAMPLE_BUFFERS_ARB;
   367  		break;
   368  	    case SDL_GL_SAMPLES:
   369  		glx_attrib = GLX_SAMPLES_ARB;
   370  		break;
   371 	    default:
   372 		return(-1);
   373 	}
   374 
   375 	retval = this->gl_data->glXGetConfig(GFX_Display, glx_visualinfo, glx_attrib, value);
   376 
   377 	return retval;
   378 }
   379 
   380 void X11_GL_SwapBuffers(_THIS)
   381 {
   382 	this->gl_data->glXSwapBuffers(GFX_Display, SDL_Window);
   383 }
   384 
   385 #endif /* HAVE_OPENGL */
   386 
   387 void X11_GL_UnloadLibrary(_THIS)
   388 {
   389 #ifdef HAVE_OPENGL
   390 	if ( this->gl_config.driver_loaded ) {
   391 		dlclose(this->gl_config.dll_handle);
   392 
   393 		this->gl_data->glXGetProcAddress = NULL;
   394 		this->gl_data->glXChooseVisual = NULL;
   395 		this->gl_data->glXCreateContext = NULL;
   396 		this->gl_data->glXDestroyContext = NULL;
   397 		this->gl_data->glXMakeCurrent = NULL;
   398 		this->gl_data->glXSwapBuffers = NULL;
   399 
   400 		this->gl_config.dll_handle = NULL;
   401 		this->gl_config.driver_loaded = 0;
   402 	}
   403 #endif
   404 }
   405 
   406 #ifdef HAVE_OPENGL
   407 
   408 /* Passing a NULL path means load pointers from the application */
   409 int X11_GL_LoadLibrary(_THIS, const char* path) 
   410 {
   411 	void* handle;
   412 	int dlopen_flags;
   413 
   414  	if ( gl_active ) {
   415  		SDL_SetError("OpenGL context already created");
   416  		return -1;
   417  	}
   418 
   419 #ifdef RTLD_GLOBAL
   420 	dlopen_flags = RTLD_LAZY | RTLD_GLOBAL;
   421 #else
   422 	dlopen_flags = RTLD_LAZY;
   423 #endif
   424 	handle = dlopen(path, dlopen_flags);
   425 	/* Catch the case where the application isn't linked with GL */
   426 	if ( (dlsym(handle, "glXChooseVisual") == NULL) && (path == NULL) ) {
   427 		dlclose(handle);
   428 		path = getenv("SDL_VIDEO_GL_DRIVER");
   429 		if ( path == NULL ) {
   430 			path = DEFAULT_OPENGL;
   431 		}
   432 		handle = dlopen(path, dlopen_flags);
   433 	}
   434 	if ( handle == NULL ) {
   435 		SDL_SetError("Could not load OpenGL library");
   436 		return -1;
   437 	}
   438 
   439 	/* Unload the old driver and reset the pointers */
   440 	X11_GL_UnloadLibrary(this);
   441 
   442 	/* Load new function pointers */
   443 	this->gl_data->glXGetProcAddress =
   444 		(void *(*)(const GLubyte *)) dlsym(handle, "glXGetProcAddressARB");
   445 	this->gl_data->glXChooseVisual =
   446 		(XVisualInfo *(*)(Display *, int, int *)) dlsym(handle, "glXChooseVisual");
   447 	this->gl_data->glXCreateContext =
   448 		(GLXContext (*)(Display *, XVisualInfo *, GLXContext, int)) dlsym(handle, "glXCreateContext");
   449 	this->gl_data->glXDestroyContext =
   450 		(void (*)(Display *, GLXContext)) dlsym(handle, "glXDestroyContext");
   451 	this->gl_data->glXMakeCurrent =
   452 		(int (*)(Display *, GLXDrawable, GLXContext)) dlsym(handle, "glXMakeCurrent");
   453 	this->gl_data->glXSwapBuffers =
   454 		(void (*)(Display *, GLXDrawable)) dlsym(handle, "glXSwapBuffers");
   455 	this->gl_data->glXGetConfig =
   456 		(int (*)(Display *, XVisualInfo *, int, int *)) dlsym(handle, "glXGetConfig");
   457 	this->gl_data->glXQueryExtensionsString =
   458 		(const char *(*)(Display *, int)) dlsym(handle, "glXQueryExtensionsString");
   459 	
   460 	/* We don't compare below for this in case we're not using Mesa. */
   461 	this->gl_data->glXReleaseBuffersMESA =
   462 		(void (*)(Display *, GLXDrawable)) dlsym( handle, "glXReleaseBuffersMESA" );
   463 	
   464 	
   465 	if ( (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->glXGetConfig == NULL) ||
   471 	     (this->gl_data->glXQueryExtensionsString == NULL)) {
   472 		SDL_SetError("Could not retrieve OpenGL functions");
   473 		return -1;
   474 	}
   475 
   476 	this->gl_config.dll_handle = handle;
   477 	this->gl_config.driver_loaded = 1;
   478 	if ( path ) {
   479 		strncpy(this->gl_config.driver_path, path,
   480 			sizeof(this->gl_config.driver_path)-1);
   481 	} else {
   482 		strcpy(this->gl_config.driver_path, "");
   483 	}
   484 	return 0;
   485 }
   486 
   487 void *X11_GL_GetProcAddress(_THIS, const char* proc)
   488 {
   489 	static char procname[1024];
   490 	void* handle;
   491 	void* retval;
   492 	
   493 	handle = this->gl_config.dll_handle;
   494 	if ( this->gl_data->glXGetProcAddress ) {
   495 		return this->gl_data->glXGetProcAddress(proc);
   496 	}
   497 #if defined(__OpenBSD__) && !defined(__ELF__)
   498 #undef dlsym(x,y);
   499 #endif
   500 	retval = dlsym(handle, proc);
   501 	if (!retval && strlen(proc) <= 1022) {
   502 		procname[0] = '_';
   503 		strcpy(procname + 1, proc);
   504 		retval = dlsym(handle, procname);
   505 	}
   506 	return retval;
   507 }
   508 
   509 #endif /* HAVE_OPENGL */