/* =================== 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; }
/* =============== 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; }
/* ================ 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) { 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; // 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; }
/* ================ 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 }