src/video/x11/SDL_x11gl.c
author Sam Lantinga <slouken@lokigames.com>
Fri, 11 May 2001 00:35:31 +0000
changeset 29 a8360daed17d
parent 26 c447d5b9275d
child 110 7edee9f0f2cc
permissions -rw-r--r--
Oops, the OpenBSD fix didn't.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001  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@devolution.com
    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 #ifdef GLX_DIRECT_COLOR /* Try for a DirectColor visual for gamma support */
   122 	attribs[i++] = GLX_X_VISUAL_TYPE;
   123 	attribs[i++] = GLX_DIRECT_COLOR;
   124 #endif
   125 	attribs[i++] = None;
   126 
   127  	glx_visualinfo = this->gl_data->glXChooseVisual(GFX_Display, 
   128 						  SDL_Screen, attribs);
   129 #ifdef GLX_DIRECT_COLOR
   130 	if( !glx_visualinfo ) { /* No DirectColor visual?  Try again.. */
   131 		attribs[i-3] = None;
   132  		glx_visualinfo = this->gl_data->glXChooseVisual(GFX_Display, 
   133 						  SDL_Screen, attribs);
   134 	}
   135 #endif
   136 	if( !glx_visualinfo ) {
   137 		SDL_SetError( "Couldn't find matching GLX visual");
   138 		return NULL;
   139 	}
   140 	return glx_visualinfo;
   141 #else
   142 	SDL_SetError("X11 driver not configured with OpenGL");
   143 	return NULL;
   144 #endif
   145 }
   146 
   147 int X11_GL_CreateWindow(_THIS, int w, int h)
   148 {
   149 	int retval;
   150 #ifdef HAVE_OPENGL
   151 	XSetWindowAttributes attributes;
   152 	unsigned long mask;
   153 	unsigned long black;
   154 
   155 	black = (glx_visualinfo->visual == DefaultVisual(SDL_Display,
   156 						 	SDL_Screen))
   157 	       	? BlackPixel(SDL_Display, SDL_Screen) : 0;
   158 	attributes.background_pixel = black;
   159 	attributes.border_pixel = black;
   160 	attributes.colormap = SDL_XColorMap;
   161 	mask = CWBackPixel | CWBorderPixel | CWColormap;
   162 
   163 	SDL_Window = XCreateWindow(SDL_Display, WMwindow,
   164 			0, 0, w, h, 0, glx_visualinfo->depth,
   165 			InputOutput, glx_visualinfo->visual,
   166 			mask, &attributes);
   167 	if ( !SDL_Window ) {
   168 		SDL_SetError("Could not create window");
   169 		return -1;
   170 	}
   171 	retval = 0;
   172 #else
   173 	SDL_SetError("X11 driver not configured with OpenGL");
   174 	retval = -1;
   175 #endif
   176 	return(retval);
   177 }
   178 
   179 int X11_GL_CreateContext(_THIS)
   180 {
   181 	int retval;
   182 #ifdef HAVE_OPENGL
   183 	/* We do this to create a clean separation between X and GLX errors. */
   184 	XSync( SDL_Display, False );
   185 	glx_context = this->gl_data->glXCreateContext(GFX_Display, 
   186 				     glx_visualinfo, NULL, True);
   187 	XSync( GFX_Display, False );
   188 
   189 	if (glx_context == NULL) {
   190 		SDL_SetError("Could not create GL context");
   191 		return -1;
   192 	}
   193 
   194 	gl_active = 1;
   195 #else
   196 	SDL_SetError("X11 driver not configured with OpenGL");
   197 #endif
   198 	if ( gl_active ) {
   199 		retval = 0;
   200 	} else {
   201 		retval = -1;
   202 	}
   203 	return(retval);
   204 }
   205 
   206 void X11_GL_Shutdown(_THIS)
   207 {
   208 #ifdef HAVE_OPENGL
   209 	/* Clean up OpenGL */
   210 	if( glx_context ) {
   211 		this->gl_data->glXMakeCurrent(GFX_Display, None, NULL);
   212 
   213 		if (glx_context != NULL)
   214 			this->gl_data->glXDestroyContext(GFX_Display, glx_context);
   215 
   216 		if( this->gl_data->glXReleaseBuffersMESA ) {
   217 		    this->gl_data->glXReleaseBuffersMESA(GFX_Display,SDL_Window);
   218 		}
   219 		glx_context = NULL;
   220 	}
   221 	gl_active = 0;
   222 #endif /* HAVE_OPENGL */
   223 }
   224 
   225 #ifdef HAVE_OPENGL
   226 
   227 /* Make the current context active */
   228 int X11_GL_MakeCurrent(_THIS)
   229 {
   230 	int retval;
   231 
   232 	retval = 0;
   233 	if ( ! this->gl_data->glXMakeCurrent(GFX_Display,
   234 	                                     SDL_Window, glx_context) ) {
   235 		SDL_SetError("Unable to make GL context current");
   236 		retval = -1;
   237 	}
   238 	XSync( GFX_Display, False );
   239 
   240 	/* More Voodoo X server workarounds... Grr... */
   241 	SDL_Lock_EventThread();
   242 	X11_CheckDGAMouse(this);
   243 	SDL_Unlock_EventThread();
   244 
   245 	return(retval);
   246 }
   247 
   248 /* Get attribute data from glX. */
   249 int X11_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value)
   250 {
   251 	int retval;
   252 	int glx_attrib = None;
   253 
   254 	switch( attrib ) {
   255 	    case SDL_GL_RED_SIZE:
   256 		glx_attrib = GLX_RED_SIZE;
   257 		break;
   258 	    case SDL_GL_GREEN_SIZE:
   259 		glx_attrib = GLX_GREEN_SIZE;
   260 		break;
   261 	    case SDL_GL_BLUE_SIZE:
   262 		glx_attrib = GLX_BLUE_SIZE;
   263 		break;
   264 	    case SDL_GL_ALPHA_SIZE:
   265 		glx_attrib = GLX_ALPHA_SIZE;
   266 		break;
   267 	    case SDL_GL_DOUBLEBUFFER:
   268 		glx_attrib = GLX_DOUBLEBUFFER;
   269 		break;
   270 	    case SDL_GL_BUFFER_SIZE:
   271 		glx_attrib = GLX_BUFFER_SIZE;
   272 		break;
   273 	    case SDL_GL_DEPTH_SIZE:
   274 		glx_attrib = GLX_DEPTH_SIZE;
   275 		break;
   276 	    case SDL_GL_STENCIL_SIZE:
   277 		glx_attrib = GLX_STENCIL_SIZE;
   278 		break;
   279 	    case SDL_GL_ACCUM_RED_SIZE:
   280 		glx_attrib = GLX_ACCUM_RED_SIZE;
   281 		break;
   282 	    case SDL_GL_ACCUM_GREEN_SIZE:
   283 		glx_attrib = GLX_ACCUM_GREEN_SIZE;
   284 		break;
   285 	    case SDL_GL_ACCUM_BLUE_SIZE:
   286 		glx_attrib = GLX_ACCUM_BLUE_SIZE;
   287 		break;
   288 	    case SDL_GL_ACCUM_ALPHA_SIZE:
   289 		glx_attrib = GLX_ACCUM_ALPHA_SIZE;
   290 		break;
   291 	    default:
   292 		return(-1);
   293 	}
   294 
   295 	retval = this->gl_data->glXGetConfig(GFX_Display, glx_visualinfo, glx_attrib, value);
   296 
   297 	return retval;
   298 }
   299 
   300 void X11_GL_SwapBuffers(_THIS)
   301 {
   302 	this->gl_data->glXSwapBuffers(GFX_Display, SDL_Window);
   303 }
   304 
   305 #endif /* HAVE_OPENGL */
   306 
   307 void X11_GL_UnloadLibrary(_THIS)
   308 {
   309 #ifdef HAVE_OPENGL
   310 	if ( this->gl_config.driver_loaded ) {
   311 		dlclose(this->gl_config.dll_handle);
   312 
   313 		this->gl_data->glXGetProcAddress = NULL;
   314 		this->gl_data->glXChooseVisual = NULL;
   315 		this->gl_data->glXCreateContext = NULL;
   316 		this->gl_data->glXDestroyContext = NULL;
   317 		this->gl_data->glXMakeCurrent = NULL;
   318 		this->gl_data->glXSwapBuffers = NULL;
   319 
   320 		this->gl_config.dll_handle = NULL;
   321 		this->gl_config.driver_loaded = 0;
   322 	}
   323 #endif
   324 }
   325 
   326 #ifdef HAVE_OPENGL
   327 
   328 /* Passing a NULL path means load pointers from the application */
   329 int X11_GL_LoadLibrary(_THIS, const char* path) 
   330 {
   331 	void* handle;
   332 	int dlopen_flags;
   333 
   334  	if ( gl_active ) {
   335  		SDL_SetError("OpenGL context already created");
   336  		return -1;
   337  	}
   338 
   339 #ifdef RTLD_GLOBAL
   340 	dlopen_flags = RTLD_LAZY | RTLD_GLOBAL;
   341 #else
   342 	dlopen_flags = RTLD_LAZY;
   343 #endif
   344 	handle = dlopen(path, dlopen_flags);
   345 	/* Catch the case where the application isn't linked with GL */
   346 	if ( (dlsym(handle, "glXChooseVisual") == NULL) && (path == NULL) ) {
   347 		dlclose(handle);
   348 		path = getenv("SDL_VIDEO_GL_DRIVER");
   349 		if ( path == NULL ) {
   350 			path = DEFAULT_OPENGL;
   351 		}
   352 		handle = dlopen(path, dlopen_flags);
   353 	}
   354 	if ( handle == NULL ) {
   355 		SDL_SetError("Could not load OpenGL library");
   356 		return -1;
   357 	}
   358 
   359 	/* Unload the old driver and reset the pointers */
   360 	X11_GL_UnloadLibrary(this);
   361 
   362 	/* Load new function pointers */
   363 	this->gl_data->glXGetProcAddress = dlsym(handle, "glXGetProcAddressARB");
   364 	this->gl_data->glXChooseVisual = dlsym(handle, "glXChooseVisual");
   365 	this->gl_data->glXCreateContext = dlsym(handle, "glXCreateContext");
   366 	this->gl_data->glXDestroyContext = dlsym(handle, "glXDestroyContext");
   367 	this->gl_data->glXMakeCurrent = dlsym(handle, "glXMakeCurrent");
   368 	this->gl_data->glXSwapBuffers = dlsym(handle, "glXSwapBuffers");
   369 	this->gl_data->glXGetConfig = dlsym(handle, "glXGetConfig");
   370 	/* We don't compare below for this in case we're not using Mesa. */
   371 	this->gl_data->glXReleaseBuffersMESA = dlsym( handle, "glXReleaseBuffersMESA" );
   372 
   373 	if ( (this->gl_data->glXChooseVisual == NULL) || 
   374 	     (this->gl_data->glXCreateContext == NULL) ||
   375 	     (this->gl_data->glXDestroyContext == NULL) ||
   376 	     (this->gl_data->glXMakeCurrent == NULL) ||
   377 	     (this->gl_data->glXSwapBuffers == NULL) ||
   378 	     (this->gl_data->glXGetConfig == NULL) ) {
   379 		SDL_SetError("Could not retrieve OpenGL functions");
   380 		return -1;
   381 	}
   382 
   383 	this->gl_config.dll_handle = handle;
   384 	this->gl_config.driver_loaded = 1;
   385 	if ( path ) {
   386 		strncpy(this->gl_config.driver_path, path,
   387 			sizeof(this->gl_config.driver_path)-1);
   388 	} else {
   389 		strcpy(this->gl_config.driver_path, "");
   390 	}
   391 	return 0;
   392 }
   393 
   394 void *X11_GL_GetProcAddress(_THIS, const char* proc)
   395 {
   396 	void* handle;
   397 	
   398 	handle = this->gl_config.dll_handle;
   399 #if 0 /* This doesn't work correctly yet */
   400 	if ( this->gl_data->glXGetProcAddress ) {
   401         void *func, *func2;
   402 		func = this->gl_data->glXGetProcAddress(proc);
   403         func2 = dlsym(handle, proc);
   404         if ( func != func2 ) {
   405 fprintf(stderr, "glXGetProcAddress returned %p and dlsym returned %p for %s\n", func, func2, proc);
   406         }
   407         return this->gl_data->glXGetProcAddress(proc);
   408 	}
   409 #endif
   410 	return dlsym(handle, proc);
   411 }
   412 
   413 #endif /* HAVE_OPENGL */