win_glimp.c (39965B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 /* 23 ** WIN_GLIMP.C 24 ** 25 ** This file contains ALL Win32 specific stuff having to do with the 26 ** OpenGL refresh. When a port is being made the following functions 27 ** must be implemented by the port: 28 ** 29 ** GLimp_EndFrame 30 ** GLimp_Init 31 ** GLimp_LogComment 32 ** GLimp_Shutdown 33 ** 34 ** Note that the GLW_xxx functions are Windows specific GL-subsystem 35 ** related functions that are relevant ONLY to win_glimp.c 36 */ 37 #include <assert.h> 38 #include "../renderer/tr_local.h" 39 #include "../qcommon/qcommon.h" 40 #include "resource.h" 41 #include "glw_win.h" 42 #include "win_local.h" 43 44 extern void WG_CheckHardwareGamma( void ); 45 extern void WG_RestoreGamma( void ); 46 47 typedef enum { 48 RSERR_OK, 49 50 RSERR_INVALID_FULLSCREEN, 51 RSERR_INVALID_MODE, 52 53 RSERR_UNKNOWN 54 } rserr_t; 55 56 #define TRY_PFD_SUCCESS 0 57 #define TRY_PFD_FAIL_SOFT 1 58 #define TRY_PFD_FAIL_HARD 2 59 60 #define WINDOW_CLASS_NAME "Quake 3: Arena" 61 62 static void GLW_InitExtensions( void ); 63 static rserr_t GLW_SetMode( const char *drivername, 64 int mode, 65 int colorbits, 66 qboolean cdsFullscreen ); 67 68 static qboolean s_classRegistered = qfalse; 69 70 // 71 // function declaration 72 // 73 void QGL_EnableLogging( qboolean enable ); 74 qboolean QGL_Init( const char *dllname ); 75 void QGL_Shutdown( void ); 76 77 // 78 // variable declarations 79 // 80 glwstate_t glw_state; 81 82 cvar_t *r_allowSoftwareGL; // don't abort out if the pixelformat claims software 83 cvar_t *r_maskMinidriver; // allow a different dll name to be treated as if it were opengl32.dll 84 85 86 87 /* 88 ** GLW_StartDriverAndSetMode 89 */ 90 static qboolean GLW_StartDriverAndSetMode( const char *drivername, 91 int mode, 92 int colorbits, 93 qboolean cdsFullscreen ) 94 { 95 rserr_t err; 96 97 err = GLW_SetMode( drivername, r_mode->integer, colorbits, cdsFullscreen ); 98 99 switch ( err ) 100 { 101 case RSERR_INVALID_FULLSCREEN: 102 ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" ); 103 return qfalse; 104 case RSERR_INVALID_MODE: 105 ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode ); 106 return qfalse; 107 default: 108 break; 109 } 110 return qtrue; 111 } 112 113 /* 114 ** ChoosePFD 115 ** 116 ** Helper function that replaces ChoosePixelFormat. 117 */ 118 #define MAX_PFDS 256 119 120 static int GLW_ChoosePFD( HDC hDC, PIXELFORMATDESCRIPTOR *pPFD ) 121 { 122 PIXELFORMATDESCRIPTOR pfds[MAX_PFDS+1]; 123 int maxPFD = 0; 124 int i; 125 int bestMatch = 0; 126 127 ri.Printf( PRINT_ALL, "...GLW_ChoosePFD( %d, %d, %d )\n", ( int ) pPFD->cColorBits, ( int ) pPFD->cDepthBits, ( int ) pPFD->cStencilBits ); 128 129 // count number of PFDs 130 if ( glConfig.driverType > GLDRV_ICD ) 131 { 132 maxPFD = qwglDescribePixelFormat( hDC, 1, sizeof( PIXELFORMATDESCRIPTOR ), &pfds[0] ); 133 } 134 else 135 { 136 maxPFD = DescribePixelFormat( hDC, 1, sizeof( PIXELFORMATDESCRIPTOR ), &pfds[0] ); 137 } 138 if ( maxPFD > MAX_PFDS ) 139 { 140 ri.Printf( PRINT_WARNING, "...numPFDs > MAX_PFDS (%d > %d)\n", maxPFD, MAX_PFDS ); 141 maxPFD = MAX_PFDS; 142 } 143 144 ri.Printf( PRINT_ALL, "...%d PFDs found\n", maxPFD - 1 ); 145 146 // grab information 147 for ( i = 1; i <= maxPFD; i++ ) 148 { 149 if ( glConfig.driverType > GLDRV_ICD ) 150 { 151 qwglDescribePixelFormat( hDC, i, sizeof( PIXELFORMATDESCRIPTOR ), &pfds[i] ); 152 } 153 else 154 { 155 DescribePixelFormat( hDC, i, sizeof( PIXELFORMATDESCRIPTOR ), &pfds[i] ); 156 } 157 } 158 159 // look for a best match 160 for ( i = 1; i <= maxPFD; i++ ) 161 { 162 // 163 // make sure this has hardware acceleration 164 // 165 if ( ( pfds[i].dwFlags & PFD_GENERIC_FORMAT ) != 0 ) 166 { 167 if ( !r_allowSoftwareGL->integer ) 168 { 169 if ( r_verbose->integer ) 170 { 171 ri.Printf( PRINT_ALL, "...PFD %d rejected, software acceleration\n", i ); 172 } 173 continue; 174 } 175 } 176 177 // verify pixel type 178 if ( pfds[i].iPixelType != PFD_TYPE_RGBA ) 179 { 180 if ( r_verbose->integer ) 181 { 182 ri.Printf( PRINT_ALL, "...PFD %d rejected, not RGBA\n", i ); 183 } 184 continue; 185 } 186 187 // verify proper flags 188 if ( ( ( pfds[i].dwFlags & pPFD->dwFlags ) & pPFD->dwFlags ) != pPFD->dwFlags ) 189 { 190 if ( r_verbose->integer ) 191 { 192 ri.Printf( PRINT_ALL, "...PFD %d rejected, improper flags (%x instead of %x)\n", i, pfds[i].dwFlags, pPFD->dwFlags ); 193 } 194 continue; 195 } 196 197 // verify enough bits 198 if ( pfds[i].cDepthBits < 15 ) 199 { 200 continue; 201 } 202 if ( ( pfds[i].cStencilBits < 4 ) && ( pPFD->cStencilBits > 0 ) ) 203 { 204 continue; 205 } 206 207 // 208 // selection criteria (in order of priority): 209 // 210 // PFD_STEREO 211 // colorBits 212 // depthBits 213 // stencilBits 214 // 215 if ( bestMatch ) 216 { 217 // check stereo 218 if ( ( pfds[i].dwFlags & PFD_STEREO ) && ( !( pfds[bestMatch].dwFlags & PFD_STEREO ) ) && ( pPFD->dwFlags & PFD_STEREO ) ) 219 { 220 bestMatch = i; 221 continue; 222 } 223 224 if ( !( pfds[i].dwFlags & PFD_STEREO ) && ( pfds[bestMatch].dwFlags & PFD_STEREO ) && ( pPFD->dwFlags & PFD_STEREO ) ) 225 { 226 bestMatch = i; 227 continue; 228 } 229 230 // check color 231 if ( pfds[bestMatch].cColorBits != pPFD->cColorBits ) 232 { 233 // prefer perfect match 234 if ( pfds[i].cColorBits == pPFD->cColorBits ) 235 { 236 bestMatch = i; 237 continue; 238 } 239 // otherwise if this PFD has more bits than our best, use it 240 else if ( pfds[i].cColorBits > pfds[bestMatch].cColorBits ) 241 { 242 bestMatch = i; 243 continue; 244 } 245 } 246 247 // check depth 248 if ( pfds[bestMatch].cDepthBits != pPFD->cDepthBits ) 249 { 250 // prefer perfect match 251 if ( pfds[i].cDepthBits == pPFD->cDepthBits ) 252 { 253 bestMatch = i; 254 continue; 255 } 256 // otherwise if this PFD has more bits than our best, use it 257 else if ( pfds[i].cDepthBits > pfds[bestMatch].cDepthBits ) 258 { 259 bestMatch = i; 260 continue; 261 } 262 } 263 264 // check stencil 265 if ( pfds[bestMatch].cStencilBits != pPFD->cStencilBits ) 266 { 267 // prefer perfect match 268 if ( pfds[i].cStencilBits == pPFD->cStencilBits ) 269 { 270 bestMatch = i; 271 continue; 272 } 273 // otherwise if this PFD has more bits than our best, use it 274 else if ( ( pfds[i].cStencilBits > pfds[bestMatch].cStencilBits ) && 275 ( pPFD->cStencilBits > 0 ) ) 276 { 277 bestMatch = i; 278 continue; 279 } 280 } 281 } 282 else 283 { 284 bestMatch = i; 285 } 286 } 287 288 if ( !bestMatch ) 289 return 0; 290 291 if ( ( pfds[bestMatch].dwFlags & PFD_GENERIC_FORMAT ) != 0 ) 292 { 293 if ( !r_allowSoftwareGL->integer ) 294 { 295 ri.Printf( PRINT_ALL, "...no hardware acceleration found\n" ); 296 return 0; 297 } 298 else 299 { 300 ri.Printf( PRINT_ALL, "...using software emulation\n" ); 301 } 302 } 303 else if ( pfds[bestMatch].dwFlags & PFD_GENERIC_ACCELERATED ) 304 { 305 ri.Printf( PRINT_ALL, "...MCD acceleration found\n" ); 306 } 307 else 308 { 309 ri.Printf( PRINT_ALL, "...hardware acceleration found\n" ); 310 } 311 312 *pPFD = pfds[bestMatch]; 313 314 return bestMatch; 315 } 316 317 /* 318 ** void GLW_CreatePFD 319 ** 320 ** Helper function zeros out then fills in a PFD 321 */ 322 static void GLW_CreatePFD( PIXELFORMATDESCRIPTOR *pPFD, int colorbits, int depthbits, int stencilbits, qboolean stereo ) 323 { 324 PIXELFORMATDESCRIPTOR src = 325 { 326 sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd 327 1, // version number 328 PFD_DRAW_TO_WINDOW | // support window 329 PFD_SUPPORT_OPENGL | // support OpenGL 330 PFD_DOUBLEBUFFER, // double buffered 331 PFD_TYPE_RGBA, // RGBA type 332 24, // 24-bit color depth 333 0, 0, 0, 0, 0, 0, // color bits ignored 334 0, // no alpha buffer 335 0, // shift bit ignored 336 0, // no accumulation buffer 337 0, 0, 0, 0, // accum bits ignored 338 24, // 24-bit z-buffer 339 8, // 8-bit stencil buffer 340 0, // no auxiliary buffer 341 PFD_MAIN_PLANE, // main layer 342 0, // reserved 343 0, 0, 0 // layer masks ignored 344 }; 345 346 src.cColorBits = colorbits; 347 src.cDepthBits = depthbits; 348 src.cStencilBits = stencilbits; 349 350 if ( stereo ) 351 { 352 ri.Printf( PRINT_ALL, "...attempting to use stereo\n" ); 353 src.dwFlags |= PFD_STEREO; 354 glConfig.stereoEnabled = qtrue; 355 } 356 else 357 { 358 glConfig.stereoEnabled = qfalse; 359 } 360 361 *pPFD = src; 362 } 363 364 /* 365 ** GLW_MakeContext 366 */ 367 static int GLW_MakeContext( PIXELFORMATDESCRIPTOR *pPFD ) 368 { 369 int pixelformat; 370 371 // 372 // don't putz around with pixelformat if it's already set (e.g. this is a soft 373 // reset of the graphics system) 374 // 375 if ( !glw_state.pixelFormatSet ) 376 { 377 // 378 // choose, set, and describe our desired pixel format. If we're 379 // using a minidriver then we need to bypass the GDI functions, 380 // otherwise use the GDI functions. 381 // 382 if ( ( pixelformat = GLW_ChoosePFD( glw_state.hDC, pPFD ) ) == 0 ) 383 { 384 ri.Printf( PRINT_ALL, "...GLW_ChoosePFD failed\n"); 385 return TRY_PFD_FAIL_SOFT; 386 } 387 ri.Printf( PRINT_ALL, "...PIXELFORMAT %d selected\n", pixelformat ); 388 389 if ( glConfig.driverType > GLDRV_ICD ) 390 { 391 qwglDescribePixelFormat( glw_state.hDC, pixelformat, sizeof( *pPFD ), pPFD ); 392 if ( qwglSetPixelFormat( glw_state.hDC, pixelformat, pPFD ) == FALSE ) 393 { 394 ri.Printf ( PRINT_ALL, "...qwglSetPixelFormat failed\n"); 395 return TRY_PFD_FAIL_SOFT; 396 } 397 } 398 else 399 { 400 DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( *pPFD ), pPFD ); 401 402 if ( SetPixelFormat( glw_state.hDC, pixelformat, pPFD ) == FALSE ) 403 { 404 ri.Printf (PRINT_ALL, "...SetPixelFormat failed\n", glw_state.hDC ); 405 return TRY_PFD_FAIL_SOFT; 406 } 407 } 408 409 glw_state.pixelFormatSet = qtrue; 410 } 411 412 // 413 // startup the OpenGL subsystem by creating a context and making it current 414 // 415 if ( !glw_state.hGLRC ) 416 { 417 ri.Printf( PRINT_ALL, "...creating GL context: " ); 418 if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 ) 419 { 420 ri.Printf (PRINT_ALL, "failed\n"); 421 422 return TRY_PFD_FAIL_HARD; 423 } 424 ri.Printf( PRINT_ALL, "succeeded\n" ); 425 426 ri.Printf( PRINT_ALL, "...making context current: " ); 427 if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) ) 428 { 429 qwglDeleteContext( glw_state.hGLRC ); 430 glw_state.hGLRC = NULL; 431 ri.Printf (PRINT_ALL, "failed\n"); 432 return TRY_PFD_FAIL_HARD; 433 } 434 ri.Printf( PRINT_ALL, "succeeded\n" ); 435 } 436 437 return TRY_PFD_SUCCESS; 438 } 439 440 441 /* 442 ** GLW_InitDriver 443 ** 444 ** - get a DC if one doesn't exist 445 ** - create an HGLRC if one doesn't exist 446 */ 447 static qboolean GLW_InitDriver( const char *drivername, int colorbits ) 448 { 449 int tpfd; 450 int depthbits, stencilbits; 451 static PIXELFORMATDESCRIPTOR pfd; // save between frames since 'tr' gets cleared 452 453 ri.Printf( PRINT_ALL, "Initializing OpenGL driver\n" ); 454 455 // 456 // get a DC for our window if we don't already have one allocated 457 // 458 if ( glw_state.hDC == NULL ) 459 { 460 ri.Printf( PRINT_ALL, "...getting DC: " ); 461 462 if ( ( glw_state.hDC = GetDC( g_wv.hWnd ) ) == NULL ) 463 { 464 ri.Printf( PRINT_ALL, "failed\n" ); 465 return qfalse; 466 } 467 ri.Printf( PRINT_ALL, "succeeded\n" ); 468 } 469 470 if ( colorbits == 0 ) 471 { 472 colorbits = glw_state.desktopBitsPixel; 473 } 474 475 // 476 // implicitly assume Z-buffer depth == desktop color depth 477 // 478 if ( r_depthbits->integer == 0 ) { 479 if ( colorbits > 16 ) { 480 depthbits = 24; 481 } else { 482 depthbits = 16; 483 } 484 } else { 485 depthbits = r_depthbits->integer; 486 } 487 488 // 489 // do not allow stencil if Z-buffer depth likely won't contain it 490 // 491 stencilbits = r_stencilbits->integer; 492 if ( depthbits < 24 ) 493 { 494 stencilbits = 0; 495 } 496 497 // 498 // make two attempts to set the PIXELFORMAT 499 // 500 501 // 502 // first attempt: r_colorbits, depthbits, and r_stencilbits 503 // 504 if ( !glw_state.pixelFormatSet ) 505 { 506 GLW_CreatePFD( &pfd, colorbits, depthbits, stencilbits, r_stereo->integer ); 507 if ( ( tpfd = GLW_MakeContext( &pfd ) ) != TRY_PFD_SUCCESS ) 508 { 509 if ( tpfd == TRY_PFD_FAIL_HARD ) 510 { 511 ri.Printf( PRINT_WARNING, "...failed hard\n" ); 512 return qfalse; 513 } 514 515 // 516 // punt if we've already tried the desktop bit depth and no stencil bits 517 // 518 if ( ( r_colorbits->integer == glw_state.desktopBitsPixel ) && 519 ( stencilbits == 0 ) ) 520 { 521 ReleaseDC( g_wv.hWnd, glw_state.hDC ); 522 glw_state.hDC = NULL; 523 524 ri.Printf( PRINT_ALL, "...failed to find an appropriate PIXELFORMAT\n" ); 525 526 return qfalse; 527 } 528 529 // 530 // second attempt: desktop's color bits and no stencil 531 // 532 if ( colorbits > glw_state.desktopBitsPixel ) 533 { 534 colorbits = glw_state.desktopBitsPixel; 535 } 536 GLW_CreatePFD( &pfd, colorbits, depthbits, 0, r_stereo->integer ); 537 if ( GLW_MakeContext( &pfd ) != TRY_PFD_SUCCESS ) 538 { 539 if ( glw_state.hDC ) 540 { 541 ReleaseDC( g_wv.hWnd, glw_state.hDC ); 542 glw_state.hDC = NULL; 543 } 544 545 ri.Printf( PRINT_ALL, "...failed to find an appropriate PIXELFORMAT\n" ); 546 547 return qfalse; 548 } 549 } 550 551 /* 552 ** report if stereo is desired but unavailable 553 */ 554 if ( !( pfd.dwFlags & PFD_STEREO ) && ( r_stereo->integer != 0 ) ) 555 { 556 ri.Printf( PRINT_ALL, "...failed to select stereo pixel format\n" ); 557 glConfig.stereoEnabled = qfalse; 558 } 559 } 560 561 /* 562 ** store PFD specifics 563 */ 564 glConfig.colorBits = ( int ) pfd.cColorBits; 565 glConfig.depthBits = ( int ) pfd.cDepthBits; 566 glConfig.stencilBits = ( int ) pfd.cStencilBits; 567 568 return qtrue; 569 } 570 571 /* 572 ** GLW_CreateWindow 573 ** 574 ** Responsible for creating the Win32 window and initializing the OpenGL driver. 575 */ 576 #define WINDOW_STYLE (WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE) 577 static qboolean GLW_CreateWindow( const char *drivername, int width, int height, int colorbits, qboolean cdsFullscreen ) 578 { 579 RECT r; 580 cvar_t *vid_xpos, *vid_ypos; 581 int stylebits; 582 int x, y, w, h; 583 int exstyle; 584 585 // 586 // register the window class if necessary 587 // 588 if ( !s_classRegistered ) 589 { 590 WNDCLASS wc; 591 592 memset( &wc, 0, sizeof( wc ) ); 593 594 wc.style = 0; 595 wc.lpfnWndProc = (WNDPROC) glw_state.wndproc; 596 wc.cbClsExtra = 0; 597 wc.cbWndExtra = 0; 598 wc.hInstance = g_wv.hInstance; 599 wc.hIcon = LoadIcon( g_wv.hInstance, MAKEINTRESOURCE(IDI_ICON1)); 600 wc.hCursor = LoadCursor (NULL,IDC_ARROW); 601 wc.hbrBackground = (void *)COLOR_GRAYTEXT; 602 wc.lpszMenuName = 0; 603 wc.lpszClassName = WINDOW_CLASS_NAME; 604 605 if ( !RegisterClass( &wc ) ) 606 { 607 ri.Error( ERR_FATAL, "GLW_CreateWindow: could not register window class" ); 608 } 609 s_classRegistered = qtrue; 610 ri.Printf( PRINT_ALL, "...registered window class\n" ); 611 } 612 613 // 614 // create the HWND if one does not already exist 615 // 616 if ( !g_wv.hWnd ) 617 { 618 // 619 // compute width and height 620 // 621 r.left = 0; 622 r.top = 0; 623 r.right = width; 624 r.bottom = height; 625 626 if ( cdsFullscreen || !Q_stricmp( _3DFX_DRIVER_NAME, drivername ) ) 627 { 628 exstyle = WS_EX_TOPMOST; 629 stylebits = WS_POPUP|WS_VISIBLE|WS_SYSMENU; 630 } 631 else 632 { 633 exstyle = 0; 634 stylebits = WINDOW_STYLE|WS_SYSMENU; 635 AdjustWindowRect (&r, stylebits, FALSE); 636 } 637 638 w = r.right - r.left; 639 h = r.bottom - r.top; 640 641 if ( cdsFullscreen || !Q_stricmp( _3DFX_DRIVER_NAME, drivername ) ) 642 { 643 x = 0; 644 y = 0; 645 } 646 else 647 { 648 vid_xpos = ri.Cvar_Get ("vid_xpos", "", 0); 649 vid_ypos = ri.Cvar_Get ("vid_ypos", "", 0); 650 x = vid_xpos->integer; 651 y = vid_ypos->integer; 652 653 // adjust window coordinates if necessary 654 // so that the window is completely on screen 655 if ( x < 0 ) 656 x = 0; 657 if ( y < 0 ) 658 y = 0; 659 660 if ( w < glw_state.desktopWidth && 661 h < glw_state.desktopHeight ) 662 { 663 if ( x + w > glw_state.desktopWidth ) 664 x = ( glw_state.desktopWidth - w ); 665 if ( y + h > glw_state.desktopHeight ) 666 y = ( glw_state.desktopHeight - h ); 667 } 668 } 669 670 g_wv.hWnd = CreateWindowEx ( 671 exstyle, 672 WINDOW_CLASS_NAME, 673 "Quake 3: Arena", 674 stylebits, 675 x, y, w, h, 676 NULL, 677 NULL, 678 g_wv.hInstance, 679 NULL); 680 681 if ( !g_wv.hWnd ) 682 { 683 ri.Error (ERR_FATAL, "GLW_CreateWindow() - Couldn't create window"); 684 } 685 686 ShowWindow( g_wv.hWnd, SW_SHOW ); 687 UpdateWindow( g_wv.hWnd ); 688 ri.Printf( PRINT_ALL, "...created window@%d,%d (%dx%d)\n", x, y, w, h ); 689 } 690 else 691 { 692 ri.Printf( PRINT_ALL, "...window already present, CreateWindowEx skipped\n" ); 693 } 694 695 if ( !GLW_InitDriver( drivername, colorbits ) ) 696 { 697 ShowWindow( g_wv.hWnd, SW_HIDE ); 698 DestroyWindow( g_wv.hWnd ); 699 g_wv.hWnd = NULL; 700 701 return qfalse; 702 } 703 704 SetForegroundWindow( g_wv.hWnd ); 705 SetFocus( g_wv.hWnd ); 706 707 return qtrue; 708 } 709 710 static void PrintCDSError( int value ) 711 { 712 switch ( value ) 713 { 714 case DISP_CHANGE_RESTART: 715 ri.Printf( PRINT_ALL, "restart required\n" ); 716 break; 717 case DISP_CHANGE_BADPARAM: 718 ri.Printf( PRINT_ALL, "bad param\n" ); 719 break; 720 case DISP_CHANGE_BADFLAGS: 721 ri.Printf( PRINT_ALL, "bad flags\n" ); 722 break; 723 case DISP_CHANGE_FAILED: 724 ri.Printf( PRINT_ALL, "DISP_CHANGE_FAILED\n" ); 725 break; 726 case DISP_CHANGE_BADMODE: 727 ri.Printf( PRINT_ALL, "bad mode\n" ); 728 break; 729 case DISP_CHANGE_NOTUPDATED: 730 ri.Printf( PRINT_ALL, "not updated\n" ); 731 break; 732 default: 733 ri.Printf( PRINT_ALL, "unknown error %d\n", value ); 734 break; 735 } 736 } 737 738 /* 739 ** GLW_SetMode 740 */ 741 static rserr_t GLW_SetMode( const char *drivername, 742 int mode, 743 int colorbits, 744 qboolean cdsFullscreen ) 745 { 746 HDC hDC; 747 const char *win_fs[] = { "W", "FS" }; 748 int cdsRet; 749 DEVMODE dm; 750 751 // 752 // print out informational messages 753 // 754 ri.Printf( PRINT_ALL, "...setting mode %d:", mode ); 755 if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) ) 756 { 757 ri.Printf( PRINT_ALL, " invalid mode\n" ); 758 return RSERR_INVALID_MODE; 759 } 760 ri.Printf( PRINT_ALL, " %d %d %s\n", glConfig.vidWidth, glConfig.vidHeight, win_fs[cdsFullscreen] ); 761 762 // 763 // check our desktop attributes 764 // 765 hDC = GetDC( GetDesktopWindow() ); 766 glw_state.desktopBitsPixel = GetDeviceCaps( hDC, BITSPIXEL ); 767 glw_state.desktopWidth = GetDeviceCaps( hDC, HORZRES ); 768 glw_state.desktopHeight = GetDeviceCaps( hDC, VERTRES ); 769 ReleaseDC( GetDesktopWindow(), hDC ); 770 771 // 772 // verify desktop bit depth 773 // 774 if ( glConfig.driverType != GLDRV_VOODOO ) 775 { 776 if ( glw_state.desktopBitsPixel < 15 || glw_state.desktopBitsPixel == 24 ) 777 { 778 if ( colorbits == 0 || ( !cdsFullscreen && colorbits >= 15 ) ) 779 { 780 if ( MessageBox( NULL, 781 "It is highly unlikely that a correct\n" 782 "windowed display can be initialized with\n" 783 "the current desktop display depth. Select\n" 784 "'OK' to try anyway. Press 'Cancel' if you\n" 785 "have a 3Dfx Voodoo, Voodoo-2, or Voodoo Rush\n" 786 "3D accelerator installed, or if you otherwise\n" 787 "wish to quit.", 788 "Low Desktop Color Depth", 789 MB_OKCANCEL | MB_ICONEXCLAMATION ) != IDOK ) 790 { 791 return RSERR_INVALID_MODE; 792 } 793 } 794 } 795 } 796 797 // do a CDS if needed 798 if ( cdsFullscreen ) 799 { 800 memset( &dm, 0, sizeof( dm ) ); 801 802 dm.dmSize = sizeof( dm ); 803 804 dm.dmPelsWidth = glConfig.vidWidth; 805 dm.dmPelsHeight = glConfig.vidHeight; 806 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; 807 808 if ( r_displayRefresh->integer != 0 ) 809 { 810 dm.dmDisplayFrequency = r_displayRefresh->integer; 811 dm.dmFields |= DM_DISPLAYFREQUENCY; 812 } 813 814 // try to change color depth if possible 815 if ( colorbits != 0 ) 816 { 817 if ( glw_state.allowdisplaydepthchange ) 818 { 819 dm.dmBitsPerPel = colorbits; 820 dm.dmFields |= DM_BITSPERPEL; 821 ri.Printf( PRINT_ALL, "...using colorsbits of %d\n", colorbits ); 822 } 823 else 824 { 825 ri.Printf( PRINT_ALL, "WARNING:...changing depth not supported on Win95 < pre-OSR 2.x\n" ); 826 } 827 } 828 else 829 { 830 ri.Printf( PRINT_ALL, "...using desktop display depth of %d\n", glw_state.desktopBitsPixel ); 831 } 832 833 // 834 // if we're already in fullscreen then just create the window 835 // 836 if ( glw_state.cdsFullscreen ) 837 { 838 ri.Printf( PRINT_ALL, "...already fullscreen, avoiding redundant CDS\n" ); 839 840 if ( !GLW_CreateWindow ( drivername, glConfig.vidWidth, glConfig.vidHeight, colorbits, qtrue ) ) 841 { 842 ri.Printf( PRINT_ALL, "...restoring display settings\n" ); 843 ChangeDisplaySettings( 0, 0 ); 844 return RSERR_INVALID_MODE; 845 } 846 } 847 // 848 // need to call CDS 849 // 850 else 851 { 852 ri.Printf( PRINT_ALL, "...calling CDS: " ); 853 854 // try setting the exact mode requested, because some drivers don't report 855 // the low res modes in EnumDisplaySettings, but still work 856 if ( ( cdsRet = ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) ) == DISP_CHANGE_SUCCESSFUL ) 857 { 858 ri.Printf( PRINT_ALL, "ok\n" ); 859 860 if ( !GLW_CreateWindow ( drivername, glConfig.vidWidth, glConfig.vidHeight, colorbits, qtrue) ) 861 { 862 ri.Printf( PRINT_ALL, "...restoring display settings\n" ); 863 ChangeDisplaySettings( 0, 0 ); 864 return RSERR_INVALID_MODE; 865 } 866 867 glw_state.cdsFullscreen = qtrue; 868 } 869 else 870 { 871 // 872 // the exact mode failed, so scan EnumDisplaySettings for the next largest mode 873 // 874 DEVMODE devmode; 875 int modeNum; 876 877 ri.Printf( PRINT_ALL, "failed, " ); 878 879 PrintCDSError( cdsRet ); 880 881 ri.Printf( PRINT_ALL, "...trying next higher resolution:" ); 882 883 // we could do a better matching job here... 884 for ( modeNum = 0 ; ; modeNum++ ) { 885 if ( !EnumDisplaySettings( NULL, modeNum, &devmode ) ) { 886 modeNum = -1; 887 break; 888 } 889 if ( devmode.dmPelsWidth >= glConfig.vidWidth 890 && devmode.dmPelsHeight >= glConfig.vidHeight 891 && devmode.dmBitsPerPel >= 15 ) { 892 break; 893 } 894 } 895 896 if ( modeNum != -1 && ( cdsRet = ChangeDisplaySettings( &devmode, CDS_FULLSCREEN ) ) == DISP_CHANGE_SUCCESSFUL ) 897 { 898 ri.Printf( PRINT_ALL, " ok\n" ); 899 if ( !GLW_CreateWindow( drivername, glConfig.vidWidth, glConfig.vidHeight, colorbits, qtrue) ) 900 { 901 ri.Printf( PRINT_ALL, "...restoring display settings\n" ); 902 ChangeDisplaySettings( 0, 0 ); 903 return RSERR_INVALID_MODE; 904 } 905 906 glw_state.cdsFullscreen = qtrue; 907 } 908 else 909 { 910 ri.Printf( PRINT_ALL, " failed, " ); 911 912 PrintCDSError( cdsRet ); 913 914 ri.Printf( PRINT_ALL, "...restoring display settings\n" ); 915 ChangeDisplaySettings( 0, 0 ); 916 917 glw_state.cdsFullscreen = qfalse; 918 glConfig.isFullscreen = qfalse; 919 if ( !GLW_CreateWindow( drivername, glConfig.vidWidth, glConfig.vidHeight, colorbits, qfalse) ) 920 { 921 return RSERR_INVALID_MODE; 922 } 923 return RSERR_INVALID_FULLSCREEN; 924 } 925 } 926 } 927 } 928 else 929 { 930 if ( glw_state.cdsFullscreen ) 931 { 932 ChangeDisplaySettings( 0, 0 ); 933 } 934 935 glw_state.cdsFullscreen = qfalse; 936 if ( !GLW_CreateWindow( drivername, glConfig.vidWidth, glConfig.vidHeight, colorbits, qfalse ) ) 937 { 938 return RSERR_INVALID_MODE; 939 } 940 } 941 942 // 943 // success, now check display frequency, although this won't be valid on Voodoo(2) 944 // 945 memset( &dm, 0, sizeof( dm ) ); 946 dm.dmSize = sizeof( dm ); 947 if ( EnumDisplaySettings( NULL, ENUM_CURRENT_SETTINGS, &dm ) ) 948 { 949 glConfig.displayFrequency = dm.dmDisplayFrequency; 950 } 951 952 // NOTE: this is overridden later on standalone 3Dfx drivers 953 glConfig.isFullscreen = cdsFullscreen; 954 955 return RSERR_OK; 956 } 957 958 /* 959 ** GLW_InitExtensions 960 */ 961 static void GLW_InitExtensions( void ) 962 { 963 if ( !r_allowExtensions->integer ) 964 { 965 ri.Printf( PRINT_ALL, "*** IGNORING OPENGL EXTENSIONS ***\n" ); 966 return; 967 } 968 969 ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" ); 970 971 // GL_S3_s3tc 972 glConfig.textureCompression = TC_NONE; 973 if ( strstr( glConfig.extensions_string, "GL_S3_s3tc" ) ) 974 { 975 if ( r_ext_compressed_textures->integer ) 976 { 977 glConfig.textureCompression = TC_S3TC; 978 ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" ); 979 } 980 else 981 { 982 glConfig.textureCompression = TC_NONE; 983 ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" ); 984 } 985 } 986 else 987 { 988 ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" ); 989 } 990 991 // GL_EXT_texture_env_add 992 glConfig.textureEnvAddAvailable = qfalse; 993 if ( strstr( glConfig.extensions_string, "EXT_texture_env_add" ) ) 994 { 995 if ( r_ext_texture_env_add->integer ) 996 { 997 glConfig.textureEnvAddAvailable = qtrue; 998 ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); 999 } 1000 else 1001 { 1002 glConfig.textureEnvAddAvailable = qfalse; 1003 ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" ); 1004 } 1005 } 1006 else 1007 { 1008 ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" ); 1009 } 1010 1011 // WGL_EXT_swap_control 1012 qwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) qwglGetProcAddress( "wglSwapIntervalEXT" ); 1013 if ( qwglSwapIntervalEXT ) 1014 { 1015 ri.Printf( PRINT_ALL, "...using WGL_EXT_swap_control\n" ); 1016 r_swapInterval->modified = qtrue; // force a set next frame 1017 } 1018 else 1019 { 1020 ri.Printf( PRINT_ALL, "...WGL_EXT_swap_control not found\n" ); 1021 } 1022 1023 // GL_ARB_multitexture 1024 qglMultiTexCoord2fARB = NULL; 1025 qglActiveTextureARB = NULL; 1026 qglClientActiveTextureARB = NULL; 1027 if ( strstr( glConfig.extensions_string, "GL_ARB_multitexture" ) ) 1028 { 1029 if ( r_ext_multitexture->integer ) 1030 { 1031 qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) qwglGetProcAddress( "glMultiTexCoord2fARB" ); 1032 qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) qwglGetProcAddress( "glActiveTextureARB" ); 1033 qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) qwglGetProcAddress( "glClientActiveTextureARB" ); 1034 1035 if ( qglActiveTextureARB ) 1036 { 1037 qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glConfig.maxActiveTextures ); 1038 1039 if ( glConfig.maxActiveTextures > 1 ) 1040 { 1041 ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); 1042 } 1043 else 1044 { 1045 qglMultiTexCoord2fARB = NULL; 1046 qglActiveTextureARB = NULL; 1047 qglClientActiveTextureARB = NULL; 1048 ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" ); 1049 } 1050 } 1051 } 1052 else 1053 { 1054 ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); 1055 } 1056 } 1057 else 1058 { 1059 ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); 1060 } 1061 1062 // GL_EXT_compiled_vertex_array 1063 qglLockArraysEXT = NULL; 1064 qglUnlockArraysEXT = NULL; 1065 if ( strstr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) && ( glConfig.hardwareType != GLHW_RIVA128 ) ) 1066 { 1067 if ( r_ext_compiled_vertex_array->integer ) 1068 { 1069 ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" ); 1070 qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) qwglGetProcAddress( "glLockArraysEXT" ); 1071 qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) qwglGetProcAddress( "glUnlockArraysEXT" ); 1072 if (!qglLockArraysEXT || !qglUnlockArraysEXT) { 1073 ri.Error (ERR_FATAL, "bad getprocaddress"); 1074 } 1075 } 1076 else 1077 { 1078 ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); 1079 } 1080 } 1081 else 1082 { 1083 ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); 1084 } 1085 1086 // WGL_3DFX_gamma_control 1087 qwglGetDeviceGammaRamp3DFX = NULL; 1088 qwglSetDeviceGammaRamp3DFX = NULL; 1089 1090 if ( strstr( glConfig.extensions_string, "WGL_3DFX_gamma_control" ) ) 1091 { 1092 if ( !r_ignorehwgamma->integer && r_ext_gamma_control->integer ) 1093 { 1094 qwglGetDeviceGammaRamp3DFX = ( BOOL ( WINAPI * )( HDC, LPVOID ) ) qwglGetProcAddress( "wglGetDeviceGammaRamp3DFX" ); 1095 qwglSetDeviceGammaRamp3DFX = ( BOOL ( WINAPI * )( HDC, LPVOID ) ) qwglGetProcAddress( "wglSetDeviceGammaRamp3DFX" ); 1096 1097 if ( qwglGetDeviceGammaRamp3DFX && qwglSetDeviceGammaRamp3DFX ) 1098 { 1099 ri.Printf( PRINT_ALL, "...using WGL_3DFX_gamma_control\n" ); 1100 } 1101 else 1102 { 1103 qwglGetDeviceGammaRamp3DFX = NULL; 1104 qwglSetDeviceGammaRamp3DFX = NULL; 1105 } 1106 } 1107 else 1108 { 1109 ri.Printf( PRINT_ALL, "...ignoring WGL_3DFX_gamma_control\n" ); 1110 } 1111 } 1112 else 1113 { 1114 ri.Printf( PRINT_ALL, "...WGL_3DFX_gamma_control not found\n" ); 1115 } 1116 } 1117 1118 /* 1119 ** GLW_CheckOSVersion 1120 */ 1121 static qboolean GLW_CheckOSVersion( void ) 1122 { 1123 #define OSR2_BUILD_NUMBER 1111 1124 1125 OSVERSIONINFO vinfo; 1126 1127 vinfo.dwOSVersionInfoSize = sizeof(vinfo); 1128 1129 glw_state.allowdisplaydepthchange = qfalse; 1130 1131 if ( GetVersionEx( &vinfo) ) 1132 { 1133 if ( vinfo.dwMajorVersion > 4 ) 1134 { 1135 glw_state.allowdisplaydepthchange = qtrue; 1136 } 1137 else if ( vinfo.dwMajorVersion == 4 ) 1138 { 1139 if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) 1140 { 1141 glw_state.allowdisplaydepthchange = qtrue; 1142 } 1143 else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) 1144 { 1145 if ( LOWORD( vinfo.dwBuildNumber ) >= OSR2_BUILD_NUMBER ) 1146 { 1147 glw_state.allowdisplaydepthchange = qtrue; 1148 } 1149 } 1150 } 1151 } 1152 else 1153 { 1154 ri.Printf( PRINT_ALL, "GLW_CheckOSVersion() - GetVersionEx failed\n" ); 1155 return qfalse; 1156 } 1157 1158 return qtrue; 1159 } 1160 1161 /* 1162 ** GLW_LoadOpenGL 1163 ** 1164 ** GLimp_win.c internal function that attempts to load and use 1165 ** a specific OpenGL DLL. 1166 */ 1167 static qboolean GLW_LoadOpenGL( const char *drivername ) 1168 { 1169 char buffer[1024]; 1170 qboolean cdsFullscreen; 1171 1172 Q_strncpyz( buffer, drivername, sizeof(buffer) ); 1173 Q_strlwr(buffer); 1174 1175 // 1176 // determine if we're on a standalone driver 1177 // 1178 if ( strstr( buffer, "opengl32" ) != 0 || r_maskMinidriver->integer ) 1179 { 1180 glConfig.driverType = GLDRV_ICD; 1181 } 1182 else 1183 { 1184 glConfig.driverType = GLDRV_STANDALONE; 1185 1186 ri.Printf( PRINT_ALL, "...assuming '%s' is a standalone driver\n", drivername ); 1187 1188 if ( strstr( buffer, _3DFX_DRIVER_NAME ) ) 1189 { 1190 glConfig.driverType = GLDRV_VOODOO; 1191 } 1192 } 1193 1194 // disable the 3Dfx splash screen 1195 _putenv("FX_GLIDE_NO_SPLASH=0"); 1196 1197 // 1198 // load the driver and bind our function pointers to it 1199 // 1200 if ( QGL_Init( buffer ) ) 1201 { 1202 cdsFullscreen = r_fullscreen->integer; 1203 1204 // create the window and set up the context 1205 if ( !GLW_StartDriverAndSetMode( drivername, r_mode->integer, r_colorbits->integer, cdsFullscreen ) ) 1206 { 1207 // if we're on a 24/32-bit desktop and we're going fullscreen on an ICD, 1208 // try it again but with a 16-bit desktop 1209 if ( glConfig.driverType == GLDRV_ICD ) 1210 { 1211 if ( r_colorbits->integer != 16 || 1212 cdsFullscreen != qtrue || 1213 r_mode->integer != 3 ) 1214 { 1215 if ( !GLW_StartDriverAndSetMode( drivername, 3, 16, qtrue ) ) 1216 { 1217 goto fail; 1218 } 1219 } 1220 } 1221 else 1222 { 1223 goto fail; 1224 } 1225 } 1226 1227 if ( glConfig.driverType == GLDRV_VOODOO ) 1228 { 1229 glConfig.isFullscreen = qtrue; 1230 } 1231 1232 return qtrue; 1233 } 1234 fail: 1235 1236 QGL_Shutdown(); 1237 1238 return qfalse; 1239 } 1240 1241 /* 1242 ** GLimp_EndFrame 1243 */ 1244 void GLimp_EndFrame (void) 1245 { 1246 // 1247 // swapinterval stuff 1248 // 1249 if ( r_swapInterval->modified ) { 1250 r_swapInterval->modified = qfalse; 1251 1252 if ( !glConfig.stereoEnabled ) { // why? 1253 if ( qwglSwapIntervalEXT ) { 1254 qwglSwapIntervalEXT( r_swapInterval->integer ); 1255 } 1256 } 1257 } 1258 1259 1260 // don't flip if drawing to front buffer 1261 if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 ) 1262 { 1263 if ( glConfig.driverType > GLDRV_ICD ) 1264 { 1265 if ( !qwglSwapBuffers( glw_state.hDC ) ) 1266 { 1267 ri.Error( ERR_FATAL, "GLimp_EndFrame() - SwapBuffers() failed!\n" ); 1268 } 1269 } 1270 else 1271 { 1272 SwapBuffers( glw_state.hDC ); 1273 } 1274 } 1275 1276 // check logging 1277 QGL_EnableLogging( r_logFile->integer ); 1278 } 1279 1280 static void GLW_StartOpenGL( void ) 1281 { 1282 qboolean attemptedOpenGL32 = qfalse; 1283 qboolean attempted3Dfx = qfalse; 1284 1285 // 1286 // load and initialize the specific OpenGL driver 1287 // 1288 if ( !GLW_LoadOpenGL( r_glDriver->string ) ) 1289 { 1290 if ( !Q_stricmp( r_glDriver->string, OPENGL_DRIVER_NAME ) ) 1291 { 1292 attemptedOpenGL32 = qtrue; 1293 } 1294 else if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) ) 1295 { 1296 attempted3Dfx = qtrue; 1297 } 1298 1299 if ( !attempted3Dfx ) 1300 { 1301 attempted3Dfx = qtrue; 1302 if ( GLW_LoadOpenGL( _3DFX_DRIVER_NAME ) ) 1303 { 1304 ri.Cvar_Set( "r_glDriver", _3DFX_DRIVER_NAME ); 1305 r_glDriver->modified = qfalse; 1306 } 1307 else 1308 { 1309 if ( !attemptedOpenGL32 ) 1310 { 1311 if ( !GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) ) 1312 { 1313 ri.Error( ERR_FATAL, "GLW_StartOpenGL() - could not load OpenGL subsystem\n" ); 1314 } 1315 ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME ); 1316 r_glDriver->modified = qfalse; 1317 } 1318 else 1319 { 1320 ri.Error( ERR_FATAL, "GLW_StartOpenGL() - could not load OpenGL subsystem\n" ); 1321 } 1322 } 1323 } 1324 else if ( !attemptedOpenGL32 ) 1325 { 1326 attemptedOpenGL32 = qtrue; 1327 if ( GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) ) 1328 { 1329 ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME ); 1330 r_glDriver->modified = qfalse; 1331 } 1332 else 1333 { 1334 ri.Error( ERR_FATAL, "GLW_StartOpenGL() - could not load OpenGL subsystem\n" ); 1335 } 1336 } 1337 } 1338 } 1339 1340 /* 1341 ** GLimp_Init 1342 ** 1343 ** This is the platform specific OpenGL initialization function. It 1344 ** is responsible for loading OpenGL, initializing it, setting 1345 ** extensions, creating a window of the appropriate size, doing 1346 ** fullscreen manipulations, etc. Its overall responsibility is 1347 ** to make sure that a functional OpenGL subsystem is operating 1348 ** when it returns to the ref. 1349 */ 1350 void GLimp_Init( void ) 1351 { 1352 char buf[1024]; 1353 cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE ); 1354 cvar_t *cv; 1355 1356 ri.Printf( PRINT_ALL, "Initializing OpenGL subsystem\n" ); 1357 1358 // 1359 // check OS version to see if we can do fullscreen display changes 1360 // 1361 if ( !GLW_CheckOSVersion() ) 1362 { 1363 ri.Error( ERR_FATAL, "GLimp_Init() - incorrect operating system\n" ); 1364 } 1365 1366 // save off hInstance and wndproc 1367 cv = ri.Cvar_Get( "win_hinstance", "", 0 ); 1368 sscanf( cv->string, "%i", (int *)&g_wv.hInstance ); 1369 1370 cv = ri.Cvar_Get( "win_wndproc", "", 0 ); 1371 sscanf( cv->string, "%i", (int *)&glw_state.wndproc ); 1372 1373 r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); 1374 r_maskMinidriver = ri.Cvar_Get( "r_maskMinidriver", "0", CVAR_LATCH ); 1375 1376 // load appropriate DLL and initialize subsystem 1377 GLW_StartOpenGL(); 1378 1379 // get our config strings 1380 Q_strncpyz( glConfig.vendor_string, qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) ); 1381 Q_strncpyz( glConfig.renderer_string, qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) ); 1382 Q_strncpyz( glConfig.version_string, qglGetString (GL_VERSION), sizeof( glConfig.version_string ) ); 1383 Q_strncpyz( glConfig.extensions_string, qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) ); 1384 1385 // 1386 // chipset specific configuration 1387 // 1388 Q_strncpyz( buf, glConfig.renderer_string, sizeof(buf) ); 1389 Q_strlwr( buf ); 1390 1391 // 1392 // NOTE: if changing cvars, do it within this block. This allows them 1393 // to be overridden when testing driver fixes, etc. but only sets 1394 // them to their default state when the hardware is first installed/run. 1395 // 1396 if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) ) 1397 { 1398 glConfig.hardwareType = GLHW_GENERIC; 1399 1400 ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); 1401 1402 // VOODOO GRAPHICS w/ 2MB 1403 if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) ) 1404 { 1405 ri.Cvar_Set( "r_picmip", "2" ); 1406 ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); 1407 } 1408 else 1409 { 1410 ri.Cvar_Set( "r_picmip", "1" ); 1411 1412 if ( strstr( buf, "rage 128" ) || strstr( buf, "rage128" ) ) 1413 { 1414 ri.Cvar_Set( "r_finish", "0" ); 1415 } 1416 // Savage3D and Savage4 should always have trilinear enabled 1417 else if ( strstr( buf, "savage3d" ) || strstr( buf, "s3 savage4" ) ) 1418 { 1419 ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); 1420 } 1421 } 1422 } 1423 1424 // 1425 // this is where hardware specific workarounds that should be 1426 // detected/initialized every startup should go. 1427 // 1428 if ( strstr( buf, "banshee" ) || strstr( buf, "voodoo3" ) ) 1429 { 1430 glConfig.hardwareType = GLHW_3DFX_2D3D; 1431 } 1432 // VOODOO GRAPHICS w/ 2MB 1433 else if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) ) 1434 { 1435 } 1436 else if ( strstr( buf, "glzicd" ) ) 1437 { 1438 } 1439 else if ( strstr( buf, "rage pro" ) || strstr( buf, "Rage Pro" ) || strstr( buf, "ragepro" ) ) 1440 { 1441 glConfig.hardwareType = GLHW_RAGEPRO; 1442 } 1443 else if ( strstr( buf, "rage 128" ) ) 1444 { 1445 } 1446 else if ( strstr( buf, "permedia2" ) ) 1447 { 1448 glConfig.hardwareType = GLHW_PERMEDIA2; 1449 } 1450 else if ( strstr( buf, "riva 128" ) ) 1451 { 1452 glConfig.hardwareType = GLHW_RIVA128; 1453 } 1454 else if ( strstr( buf, "riva tnt " ) ) 1455 { 1456 } 1457 1458 ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string ); 1459 1460 GLW_InitExtensions(); 1461 WG_CheckHardwareGamma(); 1462 } 1463 1464 /* 1465 ** GLimp_Shutdown 1466 ** 1467 ** This routine does all OS specific shutdown procedures for the OpenGL 1468 ** subsystem. 1469 */ 1470 void GLimp_Shutdown( void ) 1471 { 1472 // const char *strings[] = { "soft", "hard" }; 1473 const char *success[] = { "failed", "success" }; 1474 int retVal; 1475 1476 // FIXME: Brian, we need better fallbacks from partially initialized failures 1477 if ( !qwglMakeCurrent ) { 1478 return; 1479 } 1480 1481 ri.Printf( PRINT_ALL, "Shutting down OpenGL subsystem\n" ); 1482 1483 // restore gamma. We do this first because 3Dfx's extension needs a valid OGL subsystem 1484 WG_RestoreGamma(); 1485 1486 // set current context to NULL 1487 if ( qwglMakeCurrent ) 1488 { 1489 retVal = qwglMakeCurrent( NULL, NULL ) != 0; 1490 1491 ri.Printf( PRINT_ALL, "...wglMakeCurrent( NULL, NULL ): %s\n", success[retVal] ); 1492 } 1493 1494 // delete HGLRC 1495 if ( glw_state.hGLRC ) 1496 { 1497 retVal = qwglDeleteContext( glw_state.hGLRC ) != 0; 1498 ri.Printf( PRINT_ALL, "...deleting GL context: %s\n", success[retVal] ); 1499 glw_state.hGLRC = NULL; 1500 } 1501 1502 // release DC 1503 if ( glw_state.hDC ) 1504 { 1505 retVal = ReleaseDC( g_wv.hWnd, glw_state.hDC ) != 0; 1506 ri.Printf( PRINT_ALL, "...releasing DC: %s\n", success[retVal] ); 1507 glw_state.hDC = NULL; 1508 } 1509 1510 // destroy window 1511 if ( g_wv.hWnd ) 1512 { 1513 ri.Printf( PRINT_ALL, "...destroying window\n" ); 1514 ShowWindow( g_wv.hWnd, SW_HIDE ); 1515 DestroyWindow( g_wv.hWnd ); 1516 g_wv.hWnd = NULL; 1517 glw_state.pixelFormatSet = qfalse; 1518 } 1519 1520 // close the r_logFile 1521 if ( glw_state.log_fp ) 1522 { 1523 fclose( glw_state.log_fp ); 1524 glw_state.log_fp = 0; 1525 } 1526 1527 // reset display settings 1528 if ( glw_state.cdsFullscreen ) 1529 { 1530 ri.Printf( PRINT_ALL, "...resetting display\n" ); 1531 ChangeDisplaySettings( 0, 0 ); 1532 glw_state.cdsFullscreen = qfalse; 1533 } 1534 1535 // shutdown QGL subsystem 1536 QGL_Shutdown(); 1537 1538 memset( &glConfig, 0, sizeof( glConfig ) ); 1539 memset( &glState, 0, sizeof( glState ) ); 1540 } 1541 1542 /* 1543 ** GLimp_LogComment 1544 */ 1545 void GLimp_LogComment( char *comment ) 1546 { 1547 if ( glw_state.log_fp ) { 1548 fprintf( glw_state.log_fp, "%s", comment ); 1549 } 1550 } 1551 1552 1553 /* 1554 =========================================================== 1555 1556 SMP acceleration 1557 1558 =========================================================== 1559 */ 1560 1561 HANDLE renderCommandsEvent; 1562 HANDLE renderCompletedEvent; 1563 HANDLE renderActiveEvent; 1564 1565 void (*glimpRenderThread)( void ); 1566 1567 void GLimp_RenderThreadWrapper( void ) { 1568 glimpRenderThread(); 1569 1570 // unbind the context before we die 1571 qwglMakeCurrent( glw_state.hDC, NULL ); 1572 } 1573 1574 /* 1575 ======================= 1576 GLimp_SpawnRenderThread 1577 ======================= 1578 */ 1579 HANDLE renderThreadHandle; 1580 int renderThreadId; 1581 qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) { 1582 1583 renderCommandsEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); 1584 renderCompletedEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); 1585 renderActiveEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); 1586 1587 glimpRenderThread = function; 1588 1589 renderThreadHandle = CreateThread( 1590 NULL, // LPSECURITY_ATTRIBUTES lpsa, 1591 0, // DWORD cbStack, 1592 (LPTHREAD_START_ROUTINE)GLimp_RenderThreadWrapper, // LPTHREAD_START_ROUTINE lpStartAddr, 1593 0, // LPVOID lpvThreadParm, 1594 0, // DWORD fdwCreate, 1595 &renderThreadId ); 1596 1597 if ( !renderThreadHandle ) { 1598 return qfalse; 1599 } 1600 1601 return qtrue; 1602 } 1603 1604 static void *smpData; 1605 static int wglErrors; 1606 1607 void *GLimp_RendererSleep( void ) { 1608 void *data; 1609 1610 if ( !qwglMakeCurrent( glw_state.hDC, NULL ) ) { 1611 wglErrors++; 1612 } 1613 1614 ResetEvent( renderActiveEvent ); 1615 1616 // after this, the front end can exit GLimp_FrontEndSleep 1617 SetEvent( renderCompletedEvent ); 1618 1619 WaitForSingleObject( renderCommandsEvent, INFINITE ); 1620 1621 if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) ) { 1622 wglErrors++; 1623 } 1624 1625 ResetEvent( renderCompletedEvent ); 1626 ResetEvent( renderCommandsEvent ); 1627 1628 data = smpData; 1629 1630 // after this, the main thread can exit GLimp_WakeRenderer 1631 SetEvent( renderActiveEvent ); 1632 1633 return data; 1634 } 1635 1636 1637 void GLimp_FrontEndSleep( void ) { 1638 WaitForSingleObject( renderCompletedEvent, INFINITE ); 1639 1640 if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) ) { 1641 wglErrors++; 1642 } 1643 } 1644 1645 1646 void GLimp_WakeRenderer( void *data ) { 1647 smpData = data; 1648 1649 if ( !qwglMakeCurrent( glw_state.hDC, NULL ) ) { 1650 wglErrors++; 1651 } 1652 1653 // after this, the renderer can continue through GLimp_RendererSleep 1654 SetEvent( renderCommandsEvent ); 1655 1656 WaitForSingleObject( renderActiveEvent, INFINITE ); 1657 } 1658