📄 linux_glimp.c
字号:
{
if (r_mode->integer != 3)
{
if ( !GLW_StartDriverAndSetMode( name, 3, fullscreen ) )
{
goto fail;
}
} else
goto fail;
}
return qtrue;
} else
{
ri.Printf( PRINT_ALL, "failed\n" );
}
fail:
QGL_Shutdown();
return qfalse;
}
/*
** XErrorHandler
** the default X error handler exits the application
** I found out that on some hosts some operations would raise X errors (GLXUnsupportedPrivateRequest)
** but those don't seem to be fatal .. so the default would be to just ignore them
** our implementation mimics the default handler behaviour (not completely cause I'm lazy)
*/
int qXErrorHandler(Display *dpy, XErrorEvent *ev)
{
static char buf[1024];
XGetErrorText(dpy, ev->error_code, buf, 1024);
ri.Printf( PRINT_ALL, "X Error of failed request: %s\n", buf);
ri.Printf( PRINT_ALL, " Major opcode of failed request: %d\n", ev->request_code, buf);
ri.Printf( PRINT_ALL, " Minor opcode of failed request: %d\n", ev->minor_code);
ri.Printf( PRINT_ALL, " Serial number of failed request: %d\n", ev->serial);
return 0;
}
/*
** GLimp_Init
**
** This routine is responsible for initializing the OS specific portions
** of OpenGL.
*/
void GLimp_Init( void )
{
qboolean attemptedlibGL = qfalse;
qboolean attempted3Dfx = qfalse;
qboolean success = qfalse;
char buf[1024];
cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE );
// guarded, as this is only relevant to SMP renderer thread
#ifdef SMP
if (!XInitThreads())
{
Com_Printf("GLimp_Init() - XInitThreads() failed, disabling r_smp\n");
ri.Cvar_Set( "r_smp", "0" );
}
#endif
r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH );
r_previousglDriver = ri.Cvar_Get( "r_previousglDriver", "", CVAR_ROM );
InitSig();
// Hack here so that if the UI
if ( *r_previousglDriver->string )
{
// The UI changed it on us, hack it back
// This means the renderer can't be changed on the fly
ri.Cvar_Set( "r_glDriver", r_previousglDriver->string );
}
// set up our custom error handler for X failures
XSetErrorHandler(&qXErrorHandler);
//
// load and initialize the specific OpenGL driver
//
if ( !GLW_LoadOpenGL( r_glDriver->string ) )
{
if ( !Q_stricmp( r_glDriver->string, OPENGL_DRIVER_NAME ) )
{
attemptedlibGL = qtrue;
} else if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
{
attempted3Dfx = qtrue;
}
#if 0
// TTimo
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=455
// old legacy load code, was confusing people who had a bad OpenGL setup
if ( !attempted3Dfx && !success )
{
attempted3Dfx = qtrue;
if ( GLW_LoadOpenGL( _3DFX_DRIVER_NAME ) )
{
ri.Cvar_Set( "r_glDriver", _3DFX_DRIVER_NAME );
r_glDriver->modified = qfalse;
success = qtrue;
}
}
#endif
// try ICD before trying 3Dfx standalone driver
if ( !attemptedlibGL && !success )
{
attemptedlibGL = qtrue;
if ( GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) )
{
ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME );
r_glDriver->modified = qfalse;
success = qtrue;
}
}
if (!success)
ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" );
}
// Save it in case the UI stomps it
ri.Cvar_Set( "r_previousglDriver", r_glDriver->string );
// This values force the UI to disable driver selection
glConfig.driverType = GLDRV_ICD;
glConfig.hardwareType = GLHW_GENERIC;
// get our config strings
Q_strncpyz( glConfig.vendor_string, qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) );
Q_strncpyz( glConfig.renderer_string, qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) );
if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n')
glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0;
Q_strncpyz( glConfig.version_string, qglGetString (GL_VERSION), sizeof( glConfig.version_string ) );
Q_strncpyz( glConfig.extensions_string, qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) );
//
// chipset specific configuration
//
strcpy( buf, glConfig.renderer_string );
strlwr( buf );
//
// NOTE: if changing cvars, do it within this block. This allows them
// to be overridden when testing driver fixes, etc. but only sets
// them to their default state when the hardware is first installed/run.
//
if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) )
{
glConfig.hardwareType = GLHW_GENERIC;
ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );
// VOODOO GRAPHICS w/ 2MB
if ( Q_stristr( buf, "voodoo graphics/1 tmu/2 mb" ) )
{
ri.Cvar_Set( "r_picmip", "2" );
ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
} else
{
ri.Cvar_Set( "r_picmip", "1" );
if ( Q_stristr( buf, "rage 128" ) || Q_stristr( buf, "rage128" ) )
{
ri.Cvar_Set( "r_finish", "0" );
}
// Savage3D and Savage4 should always have trilinear enabled
else if ( Q_stristr( buf, "savage3d" ) || Q_stristr( buf, "s3 savage4" ) )
{
ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
}
}
}
//
// this is where hardware specific workarounds that should be
// detected/initialized every startup should go.
//
if ( Q_stristr( buf, "banshee" ) || Q_stristr( buf, "Voodoo_Graphics" ) )
{
glConfig.hardwareType = GLHW_3DFX_2D3D;
} else if ( Q_stristr( buf, "rage pro" ) || Q_stristr( buf, "RagePro" ) )
{
glConfig.hardwareType = GLHW_RAGEPRO;
} else if ( Q_stristr( buf, "permedia2" ) )
{
glConfig.hardwareType = GLHW_PERMEDIA2;
} else if ( Q_stristr( buf, "riva 128" ) )
{
glConfig.hardwareType = GLHW_RIVA128;
} else if ( Q_stristr( buf, "riva tnt " ) )
{
}
ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string );
// initialize extensions
GLW_InitExtensions();
GLW_InitGamma();
InitSig(); // not clear why this is at begin & end of function
return;
}
/*
** GLimp_EndFrame
**
** Responsible for doing a swapbuffers and possibly for other stuff
** as yet to be determined. Probably better not to make this a GLimp
** function and instead do a call to GLimp_SwapBuffers.
*/
void GLimp_EndFrame (void)
{
// don't flip if drawing to front buffer
if ( stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 )
{
qglXSwapBuffers(dpy, win);
}
// check logging
QGL_EnableLogging( (qboolean)r_logFile->integer ); // bk001205 - was ->value
}
#ifdef SMP
/*
===========================================================
SMP acceleration
===========================================================
*/
static pthread_mutex_t smpMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t renderCommandsEvent = PTHREAD_COND_INITIALIZER;
static pthread_cond_t renderCompletedEvent = PTHREAD_COND_INITIALIZER;
static void (*glimpRenderThread)( void );
static void *GLimp_RenderThreadWrapper( void *arg )
{
Com_Printf( "Render thread starting\n" );
glimpRenderThread();
qglXMakeCurrent( dpy, None, NULL );
Com_Printf( "Render thread terminating\n" );
return arg;
}
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
{
pthread_t renderThread;
int ret;
pthread_mutex_init( &smpMutex, NULL );
pthread_cond_init( &renderCommandsEvent, NULL );
pthread_cond_init( &renderCompletedEvent, NULL );
glimpRenderThread = function;
ret = pthread_create( &renderThread,
NULL, // attributes
GLimp_RenderThreadWrapper,
NULL ); // argument
if ( ret ) {
ri.Printf( PRINT_ALL, "pthread_create returned %d: %s", ret, strerror( ret ) );
return qfalse;
} else {
ret = pthread_detach( renderThread );
if ( ret ) {
ri.Printf( PRINT_ALL, "pthread_detach returned %d: %s", ret, strerror( ret ) );
}
}
return qtrue;
}
static volatile void *smpData = NULL;
static volatile qboolean smpDataReady;
void *GLimp_RendererSleep( void )
{
void *data;
qglXMakeCurrent( dpy, None, NULL );
pthread_mutex_lock( &smpMutex );
{
smpData = NULL;
smpDataReady = qfalse;
// after this, the front end can exit GLimp_FrontEndSleep
pthread_cond_signal( &renderCompletedEvent );
while ( !smpDataReady ) {
pthread_cond_wait( &renderCommandsEvent, &smpMutex );
}
data = (void *)smpData;
}
pthread_mutex_unlock( &smpMutex );
qglXMakeCurrent( dpy, win, ctx );
return data;
}
void GLimp_FrontEndSleep( void )
{
pthread_mutex_lock( &smpMutex );
{
while ( smpData ) {
pthread_cond_wait( &renderCompletedEvent, &smpMutex );
}
}
pthread_mutex_unlock( &smpMutex );
qglXMakeCurrent( dpy, win, ctx );
}
void GLimp_WakeRenderer( void *data )
{
qglXMakeCurrent( dpy, None, NULL );
pthread_mutex_lock( &smpMutex );
{
assert( smpData == NULL );
smpData = data;
smpDataReady = qtrue;
// after this, the renderer can continue through GLimp_RendererSleep
pthread_cond_signal( &renderCommandsEvent );
}
pthread_mutex_unlock( &smpMutex );
}
#else
void GLimp_RenderThreadWrapper( void *stub ) {}
qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) {
ri.Printf( PRINT_WARNING, "ERROR: SMP support was disabled at compile time\n");
return qfalse;
}
void *GLimp_RendererSleep( void ) {
return NULL;
}
void GLimp_FrontEndSleep( void ) {}
void GLimp_WakeRenderer( void *data ) {}
#endif
/*****************************************************************************/
/* MOUSE */
/*****************************************************************************/
void IN_Init(void) {
Com_Printf ("\n------- Input Initialization -------\n");
// mouse variables
in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
in_dgamouse = Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE);
// turn on-off sub-frame timing of X events
in_subframe = Cvar_Get ("in_subframe", "1", CVAR_ARCHIVE);
// developer feature, allows to break without loosing mouse pointer
in_nograb = Cvar_Get ("in_nograb", "0", 0);
// bk001130 - from cvs.17 (mkv), joystick variables
in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH);
// bk001130 - changed this to match win32
in_joystickDebug = Cvar_Get ("in_debugjoystick", "0", CVAR_TEMP);
joy_threshold = Cvar_Get ("joy_threshold", "0.15", CVAR_ARCHIVE); // FIXME: in_joythreshold
if (in_mouse->value)
mouse_avail = qtrue;
else
mouse_avail = qfalse;
IN_StartupJoystick( ); // bk001130 - from cvs1.17 (mkv)
Com_Printf ("------------------------------------\n");
}
void IN_Shutdown(void)
{
mouse_avail = qfalse;
}
void IN_Frame (void) {
// bk001130 - from cvs 1.17 (mkv)
IN_JoyMove(); // FIXME: disable if on desktop?
if ( cls.keyCatchers & KEYCATCH_CONSOLE )
{
// temporarily deactivate if not in the game and
// running on the desktop
// voodoo always counts as full screen
if (Cvar_VariableValue ("r_fullscreen") == 0
&& strcmp( Cvar_VariableString("r_glDriver"), _3DFX_DRIVER_NAME ) )
{
IN_DeactivateMouse ();
return;
}
}
IN_ActivateMouse();
}
void IN_Activate(void)
{
}
// bk001130 - cvs1.17 joystick code (mkv) was here, no linux_joystick.c
void Sys_SendKeyEvents (void) {
// XEvent event; // bk001204 - unused
if (!dpy)
return;
HandleEvents();
}
// bk010216 - added stubs for non-Linux UNIXes here
// FIXME - use NO_JOYSTICK or something else generic
#if defined( __FreeBSD__ ) // rb010123
void IN_StartupJoystick( void ) {}
void IN_JoyMove( void ) {}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -