123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code 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
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #ifndef USE_SDL
- #include "../../idlib/precompiled.h"
- #include "../../renderer/tr_local.h"
- #include "local.h"
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- extern "C" {
- # include "libXNVCtrl/NVCtrlLib.h"
- }
- idCVar sys_videoRam( "sys_videoRam", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "Texture memory on the video card (in megabytes) - 0: autodetect", 0, 512 );
- Display *dpy = NULL;
- static int scrnum = 0;
- Window win = 0;
- bool dga_found = false;
- static GLXContext ctx = NULL;
- static bool vidmode_ext = false;
- static int vidmode_MajorVersion = 0, vidmode_MinorVersion = 0; // major and minor of XF86VidExtensions
- static XF86VidModeModeInfo **vidmodes;
- static int num_vidmodes;
- static bool vidmode_active = false;
- // backup gamma ramp
- static int save_rampsize = 0;
- static unsigned short *save_red, *save_green, *save_blue;
- void GLimp_WakeBackEnd(void *a) {
- common->DPrintf("GLimp_WakeBackEnd stub\n");
- }
- #ifdef ID_GL_HARDLINK
- void GLimp_EnableLogging(bool log) {
- static bool logging;
- if (log != logging)
- {
- common->DPrintf("GLimp_EnableLogging - disabled at compile time (ID_GL_HARDLINK)\n");
- logging = log;
- }
- }
- #endif
- void GLimp_FrontEndSleep() {
- common->DPrintf("GLimp_FrontEndSleep stub\n");
- }
- void *GLimp_BackEndSleep() {
- common->DPrintf("GLimp_BackEndSleep stub\n");
- return 0;
- }
- bool GLimp_SpawnRenderThread(void (*a) ()) {
- common->DPrintf("GLimp_SpawnRenderThread stub\n");
- return false;
- }
- void GLimp_ActivateContext() {
- assert( dpy );
- assert( ctx );
- qglXMakeCurrent( dpy, win, ctx );
- }
- void GLimp_DeactivateContext() {
- assert( dpy );
- qglXMakeCurrent( dpy, None, NULL );
- }
- /*
- =================
- GLimp_SaveGamma
- save and restore the original gamma of the system
- =================
- */
- void GLimp_SaveGamma() {
- if ( save_rampsize ) {
- return;
- }
- assert( dpy );
-
- XF86VidModeGetGammaRampSize( dpy, scrnum, &save_rampsize);
- save_red = (unsigned short *)malloc(save_rampsize*sizeof(unsigned short));
- save_green = (unsigned short *)malloc(save_rampsize*sizeof(unsigned short));
- save_blue = (unsigned short *)malloc(save_rampsize*sizeof(unsigned short));
- XF86VidModeGetGammaRamp( dpy, scrnum, save_rampsize, save_red, save_green, save_blue);
- }
- /*
- =================
- GLimp_RestoreGamma
- save and restore the original gamma of the system
- =================
- */
- void GLimp_RestoreGamma() {
- if (!save_rampsize)
- return;
-
- XF86VidModeSetGammaRamp( dpy, scrnum, save_rampsize, save_red, save_green, save_blue);
-
- free(save_red); free(save_green); free(save_blue);
- save_rampsize = 0;
- }
- /*
- =================
- GLimp_SetGamma
- gamma ramp is generated by the renderer from r_gamma and r_brightness for 256 elements
- the size of the gamma ramp can not be changed on X (I need to confirm this)
- =================
- */
- void GLimp_SetGamma(unsigned short red[256], unsigned short green[256], unsigned short blue[256]) {
- if ( dpy ) {
- int size;
-
- GLimp_SaveGamma();
- XF86VidModeGetGammaRampSize( dpy, scrnum, &size);
- common->DPrintf("XF86VidModeGetGammaRampSize: %d\n", size);
- if ( size > 256 ) {
- // silly generic resample
- int i;
- unsigned short *l_red, *l_green, *l_blue;
- l_red = (unsigned short *)malloc(size*sizeof(unsigned short));
- l_green = (unsigned short *)malloc(size*sizeof(unsigned short));
- l_blue = (unsigned short *)malloc(size*sizeof(unsigned short));
- //int r_size = 256;
- int r_i; float r_f;
- for(i=0; i<size-1; i++) {
- r_f = (float)i*255.0f/(float)(size-1);
- r_i = (int)floor(r_f);
- r_f -= (float)r_i;
- l_red[i] = (int)round((1.0f-r_f)*(float)red[r_i]+r_f*(float)red[r_i+1]);
- l_green[i] = (int)round((1.0f-r_f)*(float)green[r_i]+r_f*(float)green[r_i+1]);
- l_blue[i] = (int)round((1.0f-r_f)*(float)blue[r_i]+r_f*(float)blue[r_i+1]);
- }
- l_red[size-1] = red[255]; l_green[size-1] = green[255]; l_blue[size-1] = blue[255];
- XF86VidModeSetGammaRamp( dpy, scrnum, size, l_red, l_green, l_blue );
- free(l_red); free(l_green); free(l_blue);
- } else {
- XF86VidModeSetGammaRamp( dpy, scrnum, size, red, green, blue );
- }
- }
- }
- void GLimp_Shutdown() {
- if ( dpy ) {
-
- Sys_XUninstallGrabs();
-
- GLimp_RestoreGamma();
- qglXDestroyContext( dpy, ctx );
-
- #if !defined( ID_GL_HARDLINK )
- GLimp_dlclose();
- #endif
-
- XDestroyWindow( dpy, win );
- if ( vidmode_active ) {
- XF86VidModeSwitchToMode( dpy, scrnum, vidmodes[0] );
- }
- XFlush( dpy );
- // FIXME: that's going to crash
- //XCloseDisplay( dpy );
- vidmode_active = false;
- dpy = NULL;
- win = 0;
- ctx = NULL;
- }
- }
- void GLimp_SwapBuffers() {
- assert( dpy );
- qglXSwapBuffers( dpy, win );
- }
- /*
- GLX_TestDGA
- Check for DGA - update in_dgamouse if needed
- */
- void GLX_TestDGA() {
- int dga_MajorVersion = 0, dga_MinorVersion = 0;
- assert( dpy );
- #if defined( ID_ENABLE_DGA )
- if ( !XF86DGAQueryVersion( dpy, &dga_MajorVersion, &dga_MinorVersion ) ) {
- // unable to query, probalby not supported
- common->Printf( "Failed to detect DGA DirectVideo Mouse\n" );
- cvarSystem->SetCVarBool( "in_dgamouse", false );
- dga_found = false;
- } else {
- common->Printf( "DGA DirectVideo Mouse (Version %d.%d) initialized\n",
- dga_MajorVersion, dga_MinorVersion );
- dga_found = true;
- }
- #else
- dga_found = false;
- #endif
- }
- /*
- ** 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 idXErrorHandler(Display * l_dpy, XErrorEvent * ev) {
- char buf[1024];
- common->Printf( "Fatal X Error:\n" );
- common->Printf( " Major opcode of failed request: %d\n", ev->request_code );
- common->Printf( " Minor opcode of failed request: %d\n", ev->minor_code );
- common->Printf( " Serial number of failed request: %lu\n", ev->serial );
- XGetErrorText( l_dpy, ev->error_code, buf, 1024 );
- common->Printf( "%s\n", buf );
- return 0;
- }
- bool GLimp_OpenDisplay( void ) {
- if ( dpy ) {
- return true;
- }
- if ( cvarSystem->GetCVarInteger( "net_serverDedicated" ) == 1 ) {
- common->DPrintf( "not opening the display: dedicated server\n" );
- return false;
- }
- common->Printf( "Setup X display connection\n" );
- // that should be the first call into X
- if ( !XInitThreads() ) {
- common->Printf("XInitThreads failed\n");
- return false;
- }
-
- // set up our custom error handler for X failures
- XSetErrorHandler( &idXErrorHandler );
- if ( !( dpy = XOpenDisplay(NULL) ) ) {
- common->Printf( "Couldn't open the X display\n" );
- return false;
- }
- scrnum = DefaultScreen( dpy );
- return true;
- }
- /*
- ===============
- GLX_Init
- ===============
- */
- int GLX_Init(glimpParms_t a) {
- int attrib[] = {
- GLX_RGBA, // 0
- GLX_RED_SIZE, 8, // 1, 2
- GLX_GREEN_SIZE, 8, // 3, 4
- GLX_BLUE_SIZE, 8, // 5, 6
- GLX_DOUBLEBUFFER, // 7
- GLX_DEPTH_SIZE, 24, // 8, 9
- GLX_STENCIL_SIZE, 8, // 10, 11
- GLX_ALPHA_SIZE, 8, // 12, 13
- None
- };
- // these match in the array
- #define ATTR_RED_IDX 2
- #define ATTR_GREEN_IDX 4
- #define ATTR_BLUE_IDX 6
- #define ATTR_DEPTH_IDX 9
- #define ATTR_STENCIL_IDX 11
- #define ATTR_ALPHA_IDX 13
- Window root;
- XVisualInfo *visinfo;
- XSetWindowAttributes attr;
- XSizeHints sizehints;
- unsigned long mask;
- int colorbits, depthbits, stencilbits;
- int tcolorbits, tdepthbits, tstencilbits;
- int actualWidth, actualHeight;
- int i;
- const char *glstring;
- if ( !GLimp_OpenDisplay() ) {
- return false;
- }
- common->Printf( "Initializing OpenGL display\n" );
- root = RootWindow( dpy, scrnum );
- actualWidth = glConfig.vidWidth;
- actualHeight = glConfig.vidHeight;
- // Get video mode list
- if ( !XF86VidModeQueryVersion( dpy, &vidmode_MajorVersion, &vidmode_MinorVersion ) ) {
- vidmode_ext = false;
- common->Printf("XFree86-VidModeExtension not available\n");
- } else {
- vidmode_ext = true;
- common->Printf("Using XFree86-VidModeExtension Version %d.%d\n",
- vidmode_MajorVersion, vidmode_MinorVersion);
- }
- GLX_TestDGA();
- if ( vidmode_ext ) {
- int best_fit, best_dist, dist, x, y;
- XF86VidModeGetAllModeLines( dpy, scrnum, &num_vidmodes, &vidmodes );
- // Are we going fullscreen? If so, let's change video mode
- if ( a.fullScreen ) {
- best_dist = 9999999;
- best_fit = -1;
- for (i = 0; i < num_vidmodes; i++) {
- if (a.width > vidmodes[i]->hdisplay ||
- a.height > vidmodes[i]->vdisplay)
- continue;
- x = a.width - vidmodes[i]->hdisplay;
- y = a.height - vidmodes[i]->vdisplay;
- dist = (x * x) + (y * y);
- if (dist < best_dist) {
- best_dist = dist;
- best_fit = i;
- }
- }
- if (best_fit != -1) {
- actualWidth = vidmodes[best_fit]->hdisplay;
- actualHeight = vidmodes[best_fit]->vdisplay;
- // change to the mode
- XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
- vidmode_active = true;
- // Move the viewport to top left
- // FIXME: center?
- XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
- common->Printf( "Free86-VidModeExtension Activated at %dx%d\n", actualWidth, actualHeight );
- } else {
- a.fullScreen = false;
- common->Printf( "Free86-VidModeExtension: No acceptable modes found\n" );
- }
- } else {
- common->Printf( "XFree86-VidModeExtension: not fullscreen, ignored\n" );
- }
- }
- // color, depth and stencil
- colorbits = 24;
- depthbits = 24;
- stencilbits = 8;
- for (i = 0; i < 16; i++) {
- // 0 - default
- // 1 - minus colorbits
- // 2 - minus depthbits
- // 3 - minus stencil
- if ((i % 4) == 0 && i) {
- // one pass, reduce
- switch (i / 4) {
- case 2:
- if (colorbits == 24)
- colorbits = 16;
- break;
- case 1:
- if (depthbits == 24)
- depthbits = 16;
- else if (depthbits == 16)
- depthbits = 8;
- case 3:
- if (stencilbits == 24)
- stencilbits = 16;
- else if (stencilbits == 16)
- stencilbits = 8;
- }
- }
- tcolorbits = colorbits;
- tdepthbits = depthbits;
- tstencilbits = stencilbits;
- if ((i % 4) == 3) { // reduce colorbits
- if (tcolorbits == 24)
- tcolorbits = 16;
- }
- if ((i % 4) == 2) { // reduce depthbits
- if (tdepthbits == 24)
- tdepthbits = 16;
- else if (tdepthbits == 16)
- tdepthbits = 8;
- }
- if ((i % 4) == 1) { // reduce stencilbits
- if (tstencilbits == 24)
- tstencilbits = 16;
- else if (tstencilbits == 16)
- tstencilbits = 8;
- else
- tstencilbits = 0;
- }
- if (tcolorbits == 24) {
- attrib[ATTR_RED_IDX] = 8;
- attrib[ATTR_GREEN_IDX] = 8;
- attrib[ATTR_BLUE_IDX] = 8;
- } else {
- // must be 16 bit
- attrib[ATTR_RED_IDX] = 4;
- attrib[ATTR_GREEN_IDX] = 4;
- attrib[ATTR_BLUE_IDX] = 4;
- }
-
- attrib[ATTR_DEPTH_IDX] = tdepthbits; // default to 24 depth
- attrib[ATTR_STENCIL_IDX] = tstencilbits;
- visinfo = qglXChooseVisual(dpy, scrnum, attrib);
- if (!visinfo) {
- continue;
- }
- common->Printf( "Using %d/%d/%d Color bits, %d Alpha bits, %d depth, %d stencil display.\n",
- attrib[ATTR_RED_IDX], attrib[ATTR_GREEN_IDX],
- attrib[ATTR_BLUE_IDX], attrib[ATTR_ALPHA_IDX],
- attrib[ATTR_DEPTH_IDX],
- attrib[ATTR_STENCIL_IDX]);
- glConfig.colorBits = tcolorbits;
- glConfig.depthBits = tdepthbits;
- glConfig.stencilBits = tstencilbits;
- break;
- }
- if (!visinfo) {
- common->Printf("Couldn't get a visual\n");
- return false;
- }
- // window attributes
- attr.background_pixel = BlackPixel(dpy, scrnum);
- attr.border_pixel = 0;
- attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
- attr.event_mask = X_MASK;
- if (vidmode_active) {
- mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore |
- CWEventMask | CWOverrideRedirect;
- attr.override_redirect = True;
- attr.backing_store = NotUseful;
- attr.save_under = False;
- } else {
- mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
- }
- win = XCreateWindow(dpy, root, 0, 0,
- actualWidth, actualHeight,
- 0, visinfo->depth, InputOutput,
- visinfo->visual, mask, &attr);
- XStoreName(dpy, win, GAME_NAME);
- // don't let the window be resized
- // FIXME: allow resize (win32 does)
- sizehints.flags = PMinSize | PMaxSize;
- sizehints.min_width = sizehints.max_width = actualWidth;
- sizehints.min_height = sizehints.max_height = actualHeight;
- XSetWMNormalHints(dpy, win, &sizehints);
- XMapWindow( dpy, win );
- if ( vidmode_active ) {
- XMoveWindow( dpy, win, 0, 0 );
- }
- XFlush(dpy);
- XSync(dpy, False);
- ctx = qglXCreateContext(dpy, visinfo, NULL, True);
- XSync(dpy, False);
- // Free the visinfo after we're done with it
- XFree(visinfo);
- qglXMakeCurrent(dpy, win, ctx);
- glstring = (const char *) qglGetString(GL_RENDERER);
- common->Printf("GL_RENDERER: %s\n", glstring);
-
- glstring = (const char *) qglGetString(GL_EXTENSIONS);
- common->Printf("GL_EXTENSIONS: %s\n", glstring);
- // FIXME: here, software GL test
- glConfig.isFullscreen = a.fullScreen;
-
- if ( glConfig.isFullscreen ) {
- Sys_GrabMouseCursor( true );
- }
-
- return true;
- }
- /*
- ===================
- GLimp_Init
- This is the platform specific OpenGL initialization function. It
- is responsible for loading OpenGL, initializing it,
- creating a window of the appropriate size, doing
- fullscreen manipulations, etc. Its overall responsibility is
- to make sure that a functional OpenGL subsystem is operating
- when it returns to the ref.
- If there is any failure, the renderer will revert back to safe
- parameters and try again.
- ===================
- */
- bool GLimp_Init( glimpParms_t a ) {
- if ( !GLimp_OpenDisplay() ) {
- return false;
- }
-
- #ifndef ID_GL_HARDLINK
- if ( !GLimp_dlopen() ) {
- return false;
- }
- #endif
-
- if (!GLX_Init(a)) {
- return false;
- }
-
- return true;
- }
- /*
- ===================
- GLimp_SetScreenParms
- ===================
- */
- bool GLimp_SetScreenParms( glimpParms_t parms ) {
- return true;
- }
- #endif
- /*
- ================
- Sys_GetVideoRam
- returns in megabytes
- open your own display connection for the query and close it
- using the one shared with GLimp_Init is not stable
- ================
- */
- int Sys_GetVideoRam( void ) {
- #ifdef USE_SDL
- return 128;
- #else
- static int run_once = 0;
- int major, minor, value;
- Display *l_dpy;
- int l_scrnum;
- if ( run_once ) {
- return run_once;
- }
- if ( sys_videoRam.GetInteger() ) {
- run_once = sys_videoRam.GetInteger();
- return sys_videoRam.GetInteger();
- }
- // try a few strategies to guess the amount of video ram
- common->Printf( "guessing video ram ( use +set sys_videoRam to force ) ..\n" );
- if ( !GLimp_OpenDisplay( ) ) {
- run_once = 64;
- return run_once;
- }
- l_dpy = dpy;
- l_scrnum = scrnum;
- // go for nvidia ext first
- if ( XNVCTRLQueryVersion( l_dpy, &major, &minor ) ) {
- common->Printf( "found XNVCtrl extension %d.%d\n", major, minor );
- if ( XNVCTRLIsNvScreen( l_dpy, l_scrnum ) ) {
- if ( XNVCTRLQueryAttribute( l_dpy, l_scrnum, 0, NV_CTRL_VIDEO_RAM, &value ) ) {
- run_once = value / 1024;
- return run_once;
- } else {
- common->Printf( "XNVCtrlQueryAttribute NV_CTRL_VIDEO_RAM failed\n" );
- }
- } else {
- common->Printf( "default screen %d is not controlled by NVIDIA driver\n", l_scrnum );
- }
- }
- // try ATI /proc read ( for the lack of a better option )
- int fd;
- if ( ( fd = open( "/proc/dri/0/umm", O_RDONLY ) ) != -1 ) {
- int len;
- char umm_buf[ 1024 ];
- char *line;
- if ( ( len = read( fd, umm_buf, 1024 ) ) != -1 ) {
- // should be way enough to get the full file
- // grab "free LFB = " line and "free Inv = " lines
- umm_buf[ len-1 ] = '\0';
- line = umm_buf;
- line = strtok( umm_buf, "\n" );
- int total = 0;
- while ( line ) {
- if ( strlen( line ) >= 13 && strstr( line, "max LFB =" ) == line ) {
- total += atoi( line + 12 );
- } else if ( strlen( line ) >= 13 && strstr( line, "max Inv =" ) == line ) {
- total += atoi( line + 12 );
- }
- line = strtok( NULL, "\n" );
- }
- if ( total ) {
- run_once = total / 1048576;
- // round to the lower 16Mb
- run_once &= ~15;
- return run_once;
- }
- } else {
- common->Printf( "read /proc/dri/0/umm failed: %s\n", strerror( errno ) );
- }
- }
- common->Printf( "guess failed, return default low-end VRAM setting ( 64MB VRAM )\n" );
- run_once = 64;
- return run_once;
- #endif
- }
|