adds native gamma support for 3dfx Voodoo1/2 to the linux quake2 port hosted at icculus.org. some glide hacks are employed which are self- contained in the newly created fx_gamma.c. it is a compile time makefile option. The icculus-quake2 project is at: http://icculus.org/quake2/ This patch is prepared against the latest cvs/svn version, but it applies to their 0.16.2 release, as well: http://icculus.org/quake2/files/quake2-r0.16.2.tar.gz diff -urN quake2-20060507/Makefile quake2/Makefile --- quake2-20060507/Makefile 2005-09-07 15:57:40.000000000 +0300 +++ quake2/Makefile 2007-07-06 12:55:04.000000000 +0300 @@ -30,6 +30,7 @@ BUILD_QMAX=NO # build the fancier GL graphics BUILD_RETEXTURE=YES # build a version supporting retextured graphics BUILD_REDBLUE=NO # build a red-blue 3d glasses renderer... +USE_3DFXGAMMA=YES # adds hardware gamma support for old Voodoo1/2 boards. linux only STATICSDL=NO SDLDIR=/usr/local/lib @@ -372,6 +373,13 @@ ifeq ($(strip $(BUILD_SDLGL)),YES) TARGETS += $(BUILDDIR)/ref_sdlgl.$(SHLIBEXT) endif + + ifeq ($(OSTYPE),Linux) + ifeq ($(strip $(USE_3DFXGAMMA)),YES) + GLXCFLAGS:=$(GLXCFLAGS) -DUSE_3DFXGAMMA + endif + endif + endif # ARCH x86_64 ifeq ($(ARCH),i386) @@ -402,6 +410,13 @@ ifeq ($(strip $(BUILD_SDLGL)),YES) TARGETS += $(BUILDDIR)/ref_sdlgl.$(SHLIBEXT) endif + + ifeq ($(OSTYPE),Linux) + ifeq ($(strip $(USE_3DFXGAMMA)),YES) + GLXCFLAGS:=$(GLXCFLAGS) -DUSE_3DFXGAMMA + endif + endif + endif # ARCH i386 ifeq ($(strip $(BUILD_AA)),YES) @@ -1795,6 +1810,7 @@ REF_GLX_OBJS = \ $(BUILDDIR)/ref_gl/gl_glx.o \ + $(BUILDDIR)/ref_gl/fx_gamma.o \ $(BUILDDIR)/ref_gl/rw_linux.o \ $(BUILDDIR)/ref_gl/joystick.o # $(BUILDDIR)/ref_gl/rw_x11.o @@ -1869,6 +1885,9 @@ $(BUILDDIR)/ref_gl/gl_glx.o : $(LINUX_DIR)/gl_glx.c $(DO_GL_SHLIB_CC) $(GLXCFLAGS) +$(BUILDDIR)/ref_gl/fx_gamma.o : $(LINUX_DIR)/fx_gamma.c + $(DO_GL_SHLIB_CC) $(GLXCFLAGS) + $(BUILDDIR)/ref_gl/rw_linux.o : $(LINUX_DIR)/rw_linux.c $(DO_GL_SHLIB_CC) $(XCFLAGS) diff -urNp quake2-20060507/src/linux/qgl_linux.c quake2/src/linux/qgl_linux.c --- quake2-20060507/src/linux/qgl_linux.c 2005-09-07 15:57:40.000000000 +0300 +++ quake2/src/linux/qgl_linux.c 2007-07-06 12:52:37.000000000 +0300 @@ -2997,7 +2997,11 @@ qboolean QGL_Init( const char *dllname ) if ( glw_state.OpenGLLib ) QGL_Shutdown(); +#ifdef RTLD_GLOBAL + if ( ( glw_state.OpenGLLib = dlopen( dllname, RTLD_LAZY | RTLD_GLOBAL ) ) == 0 ) +#else if ( ( glw_state.OpenGLLib = dlopen( dllname, RTLD_LAZY ) ) == 0 ) +#endif { char fn[MAX_OSPATH]; char *path; diff -urNp quake2-20060507/src/linux/fx_gamma.c quake2/src/linux/fx_gamma.c --- quake2-20060507/src/linux/fx_gamma.c 1970-01-01 02:00:00.000000000 +0200 +++ quake2/src/linux/fx_gamma.c 2007-07-06 12:49:36.000000000 +0300 @@ -0,0 +1,214 @@ +/* + * Small library providing gamma control functions for 3Dfx Voodoo1/2 + * cards by abusing the exposed glide symbols when using fxMesa. + * + * Author: O. Sezer License: GPL + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the accompanying COPYING file for more details. + * + * Compiling as a shared library: + * gcc lib3dfxgamma.c -O2 -fPIC -Wall -o lib3dfxgamma.so -shared + * + * How to use: + * If you are linking to the opengl library at compile time (-lGL), + * not much is necessary. If you dlopen() the opengl library, then + * RTLD_GLOBAL flag is necessary so that the library's symbols would be + * available to you: SDL_GL_LoadLibrary() is just fine in this regard. + * In either case, if the gllib is an fxMesa library, then you will have + * the necessary glide symbols exposed on you. Decide whether you have + * a Voodoo1/2 and then use the functions here. + * + * Issues: + * glSetDeviceGammaRamp3DFX works nicely with Voodoo2, but it crashes + * Voodoo1. The ramp functions are added for completeness sake anyway. + * do3dfxGammaCtrl works just fine for both Voodoo1 and Voodoo2. + * Besides, the GammaRamp3DFX functions are only available for Glide3: + * Glide2 users cannot benefit them, but the gamma control option is + * available for both Glide2 and Glide3. Therefore employing the gamma + * control option seems more beneficial. + * + * Revision history: + * v0.0.1, 2005-06-04: Initial version, do3dfxGammaCtrl works fine, + * glGetDeviceGammaRamp3DFX & co need more care + * v0.0.2, 2005-06-13: tried following the exact win32 versions for + * glGetDeviceGammaRamp3DFX/glSetDeviceGammaRamp3DFX + * v0.0.3, 2005-12-05: Updated documentation about the RTLD_GLOBAL flag. + * v0.0.4, 2006-03-16: Fixed incorrect prototype for the grGet function + * (it takes a signed int param*, not unsigned). + * Also renamed FX_Get to FX_GetInteger to be more + * explicit. + */ + +#include +#include + +#if defined(USE_3DFXGAMMA) + +#include + +#define USE_GAMMA_RAMPS 0 + +#include "fx_gamma.h" + +/**********************************************************************/ + +/** PRIVATE STUFF **/ + +/* 3dfx glide2 func for gamma correction */ +static void (*FX_GammaControl2)(float) = NULL; +/* 3dfx glide3 func for gamma correction */ +static void (*FX_GammaControl3)(float, float, float) = NULL; + +#if USE_GAMMA_RAMPS +/* 3dfx glide3 funcs to make a replacement wglSetDeviceGammaRamp3DFX */ +#define GR_GAMMA_TABLE_ENTRIES 0x05 +static unsigned int (*FX_GetInteger)(unsigned int, unsigned int, signed int *) = NULL; +static void (*FX_LoadGammaTable)(unsigned int, unsigned int *, unsigned int *, unsigned int *) = NULL; +#endif + +/**********************************************************************/ + +/* + * Init_3dfxGammaCtrl + * Sends 0 for failure, 2 for glide2 or 3 for glide3 api. + */ +int Init_3dfxGammaCtrl (void) +{ + void *symslist; + int ret = 0; + + if (FX_GammaControl2 != NULL) + return 2; + if (FX_GammaControl3 != NULL) + return 3; + + symslist = (void *) dlopen(NULL, RTLD_LAZY); + if (symslist != NULL) + { + if ((FX_GammaControl2 = (void (*) (float)) dlsym(symslist, "grGammaCorrectionValue")) != NULL) + ret = 2; + else if ((FX_GammaControl3 = (void (*) (float, float, float)) dlsym(symslist, "guGammaCorrectionRGB")) != NULL) + ret = 3; + + dlclose(symslist); + } + else + { /* shouldn't happen. */ + ret = -1; + } + + return ret; +} + +void Shutdown_3dfxGamma (void) +{ + FX_GammaControl2 = NULL; + FX_GammaControl3 = NULL; +#if USE_GAMMA_RAMPS + FX_GetInteger = NULL; + FX_LoadGammaTable = NULL; +#endif +} + +/* + * do3dfxGammaCtrl + */ +void do3dfxGammaCtrl (float value) +{ + if (FX_GammaControl2) + FX_GammaControl2 (value); + else if (FX_GammaControl3) + FX_GammaControl3 (value, value, value); +} + +/**********************************************************************/ +#if USE_GAMMA_RAMPS +static int Check_3DfxGammaRamp (void) +{ + void *symslist; + + if (FX_LoadGammaTable != NULL) + return 1; + + symslist = (void *) dlopen(NULL, RTLD_LAZY); + if (symslist != NULL) + { + FX_GetInteger = (unsigned int (*) (unsigned int, unsigned int, signed int *)) dlsym(symslist, "grGet"); + FX_LoadGammaTable = (void (*) (unsigned int, unsigned int *, unsigned int *, unsigned int *)) dlsym(symslist, "grLoadGammaTable"); + if ((FX_LoadGammaTable != NULL) && (FX_GetInteger != NULL)) + return 1; + } + + return 0; +} + +/* + * glSetDeviceGammaRamp3DFX is adapted from Mesa-6.x + * + * glSetDeviceGammaRamp3DFX crashes Voodoo1, at least + * currently, so it is not recommended yet. + */ +int glSetDeviceGammaRamp3DFX (void *arrays) +{ + int tableSize = 0; + int i, inc, idx; + unsigned short *red, *green, *blue; + unsigned int gammaTableR[256], gammaTableG[256], gammaTableB[256]; + + if ((FX_LoadGammaTable == NULL) || (FX_GetInteger == NULL)) + return 0; + + FX_GetInteger (GR_GAMMA_TABLE_ENTRIES, 4, &tableSize); + if (!tableSize) + return 0; + + inc = 256 / tableSize; + + red = (unsigned short *)arrays; + green = (unsigned short *)arrays + 256; + blue = (unsigned short *)arrays + 512; + + for (i = 0, idx = 0; i < tableSize; i++, idx += inc) + { + gammaTableR[i] = red[idx] >> 8; + gammaTableG[i] = green[idx] >> 8; + gammaTableB[i] = blue[idx] >> 8; + } + + FX_LoadGammaTable(tableSize, gammaTableR, gammaTableG, gammaTableB); + + return 1; +} + +/* + * glGetDeviceGammaRamp3DFX + * Sends a 1.0 gamma table. Also to be used for querying the lib. + */ +int glGetDeviceGammaRamp3DFX (void *arrays) +{ + int i; + unsigned short gammaTable[3][256]; + + if ((FX_LoadGammaTable == NULL) || (FX_GetInteger == NULL)) + { + if (Check_3DfxGammaRamp() == 0) + return 0; + } + + for (i = 0; i < 256; i++) + { + gammaTable[0][i] = i << 8; + gammaTable[1][i] = i << 8; + gammaTable[2][i] = i << 8; + } + + memcpy (arrays, gammaTable, 3 * 256 * sizeof(unsigned short)); + + return 1; +} +#endif /* USE_GAMMA_RAMPS */ + +#endif /* USE_3DFXGAMMA */ + diff -urNp quake2-20060507/src/linux/fx_gamma.h quake2/src/linux/fx_gamma.h --- quake2-20060507/src/linux/fx_gamma.h 1970-01-01 02:00:00.000000000 +0200 +++ quake2/src/linux/fx_gamma.h 2007-07-06 12:49:36.000000000 +0300 @@ -0,0 +1,43 @@ +/* + * Small library providing gamma control functions for 3Dfx Voodoo1/2 + * cards by abusing the exposed glide symbols when using fxMesa. + * Author: O. Sezer License: GPL + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the accompanying COPYING file for more details. + */ + +#ifndef __FXGAMMA_H +#define __FXGAMMA_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern void Shutdown_3dfxGamma (void); + +extern int Init_3dfxGammaCtrl (void); + /* returns 0 for failure, 2 for glide2 or 3 for glide3 api. */ + +extern void do3dfxGammaCtrl (float value); + /* gamma correction procedure. takes the gamma value as its + arg (must be between 1 and 0.333) */ + +#if USE_GAMMA_RAMPS + +extern int glSetDeviceGammaRamp3DFX (void *arrays); + /* returns 1 for success, 0 for failure. */ + +extern int glGetDeviceGammaRamp3DFX (void *arrays); + /* sends a 1.0 gamma table. use for querying the lib. + returns 1 for success, 0 for failure. */ + +#endif /* USE_GAMMA_RAMPS */ + +#ifdef __cplusplus +} +#endif + +#endif /* __FXGAMMA_H */ + diff -urNp quake2-20060507/src/linux/gl_glx.c quake2/src/linux/gl_glx.c --- quake2-20060507/src/linux/gl_glx.c 2005-01-28 00:35:20.000000000 +0200 +++ quake2/src/linux/gl_glx.c 2007-07-06 12:49:36.000000000 +0300 @@ -112,6 +112,10 @@ static XF86VidModeModeInfo **vidmodes; static int num_vidmodes; static qboolean vidmode_active = false; static XF86VidModeGamma oldgamma; +#ifdef USE_3DFXGAMMA +/* evil glide gamma hack */ +#include "fx_gamma.h" +#endif static qboolean mouse_active = false; static qboolean dgamouse = false; @@ -699,6 +703,7 @@ int GLimp_SetMode( int *pwidth, int *phe } } + gl_state.fxgamma = false; gl_state.hwgamma = false; /* do some pantsness */ @@ -766,14 +771,8 @@ int GLimp_SetMode( int *pwidth, int *phe XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]); vidmode_active = true; - if (XF86VidModeGetGamma(dpy, scrnum, &oldgamma)) { + if (XF86VidModeGetGamma(dpy, scrnum, &oldgamma)) gl_state.hwgamma = true; - /* We can not reliably detect hardware gamma - changes across software gamma calls, which - can reset the flag, so change it anyway */ - vid_gamma->modified = true; - ri.Con_Printf( PRINT_ALL, "Using hardware gamma\n"); - } // Move the viewport to top left XF86VidModeSetViewPort(dpy, scrnum, 0, 0); @@ -869,6 +868,26 @@ int GLimp_SetMode( int *pwidth, int *phe qglXMakeCurrent(dpy, win, ctx); +#ifdef USE_3DFXGAMMA + if (!Q_strncasecmp ((char *)qglGetString(GL_RENDERER), "Mesa Glide", 10)) + { /* attempt to use glide symbols for gamma */ + gl_state.hwgamma = false; + gl_state.fxgamma = Init_3dfxGammaCtrl(); + if (gl_state.fxgamma) + ri.Con_Printf(PRINT_ALL, "Using 3dfx glide gamma controls\n"); + } +#endif /* USE_3DFXGAMMA */ + if (gl_state.hwgamma) + ri.Con_Printf(PRINT_ALL, "Using hardware gamma\n"); + + if (gl_state.hwgamma || gl_state.fxgamma) + { + /* We can not reliably detect hardware gamma + changes across software gamma calls, which + can reset the flag, so change it anyway */ + vid_gamma->modified = true; + } + return rserr_ok; } @@ -887,6 +906,11 @@ void GLimp_Shutdown( void ) mouse_active = false; dgamouse = false; +#ifdef USE_3DFXGAMMA + if (gl_state.fxgamma) + Shutdown_3dfxGamma(); +#endif /* USE_3DFXGAMMA */ + if (dpy) { if (ctx) qglXDestroyContext(dpy, ctx); @@ -980,6 +1004,14 @@ void UpdateHardwareGamma() g = (1.3 - vid_gamma->value + 1); g = (g>1 ? g : 1); + +#ifdef USE_3DFXGAMMA + if (gl_state.fxgamma) + { + do3dfxGammaCtrl (g); + return; + } +#endif /* USE_3DFXGAMMA */ gamma.red = oldgamma.red * g; gamma.green = oldgamma.green * g; gamma.blue = oldgamma.blue * g; diff -urNp quake2-20060507/src/ref_candygl/gl_local.h quake2/src/ref_candygl/gl_local.h --- quake2-20060507/src/ref_candygl/gl_local.h 2003-07-12 04:59:52.000000000 +0300 +++ quake2/src/ref_candygl/gl_local.h 2007-07-06 12:49:36.000000000 +0300 @@ -525,12 +525,13 @@ typedef struct qboolean texture_compression; // Heffo - ARB Texture Compression - unsigned char originalRedGammaTable[256]; unsigned char originalGreenGammaTable[256]; unsigned char originalBlueGammaTable[256]; - qboolean hwgamma; - + + qboolean hwgamma; + qboolean fxgamma; + } glstate_t; extern glconfig_t gl_config; diff -urNp quake2-20060507/src/ref_gl/gl_image.c quake2/src/ref_gl/gl_image.c --- quake2-20060507/src/ref_gl/gl_image.c 2004-09-25 01:06:52.000000000 +0300 +++ quake2/src/ref_gl/gl_image.c 2007-07-06 12:49:36.000000000 +0300 @@ -1568,14 +1568,15 @@ void GL_InitImages (void) ri.Sys_Error( ERR_FATAL, "Couldn't load pics/16to8.pcx"); } - if ( gl_config.renderer & ( GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2 ) ) + if ( ( gl_config.renderer & ( GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2 ) ) + && !gl_state.fxgamma) { g = 1.0F; } for ( i = 0; i < 256; i++ ) { - if ( g == 1 || gl_state.hwgamma ) + if ( g == 1 || gl_state.hwgamma || gl_state.fxgamma) { gammatable[i] = i; } diff -urNp quake2-20060507/src/ref_gl/gl_local.h quake2/src/ref_gl/gl_local.h --- quake2-20060507/src/ref_gl/gl_local.h 2005-09-06 16:02:26.000000000 +0300 +++ quake2/src/ref_gl/gl_local.h 2007-07-06 12:49:36.000000000 +0300 @@ -432,6 +432,7 @@ typedef struct qboolean stereo_enabled; qboolean hwgamma; + qboolean fxgamma; /* hack to use glide symbols exposed upon us */ unsigned char originalRedGammaTable[256]; unsigned char originalGreenGammaTable[256]; diff -urNp quake2-20060507/src/ref_gl/gl_rmain.c quake2/src/ref_gl/gl_rmain.c --- quake2-20060507/src/ref_gl/gl_rmain.c 2005-09-07 01:46:08.000000000 +0300 +++ quake2/src/ref_gl/gl_rmain.c 2007-07-06 12:49:36.000000000 +0300 @@ -1484,7 +1484,7 @@ void R_BeginFrame( float camera_separati { vid_gamma->modified = false; - if ( gl_state.hwgamma ) { + if ( gl_state.hwgamma || gl_state.fxgamma) { UpdateHardwareGamma(); } else if ( gl_config.renderer & ( GL_RENDERER_VOODOO ) ) {