2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 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.
24 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.
26 ===========================================================================
31 ** This file contains ALL Win32 specific stuff having to do with the
32 ** OpenGL refresh. When a port is being made the following functions
33 ** must be implemented by the port:
40 ** Note that the GLW_xxx functions are Windows specific GL-subsystem
41 ** related functions that are relevant ONLY to win_glimp.c
43 #include "../../idlib/precompiled.h"
46 #include "win_local.h"
47 #include "rc/AFEditor_resource.h"
48 #include "rc/doom_resource.h"
49 #include "../../renderer/tr_local.h"
51 static void GLW_InitExtensions( void );
54 // WGL_ARB_extensions_string
55 PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
57 // WGL_EXT_swap_interval
58 PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
60 // WGL_ARB_pixel_format
61 PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB;
62 PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB;
63 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
66 PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
67 PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
68 PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
69 PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
70 PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB;
72 // WGL_ARB_render_texture
73 PFNWGLBINDTEXIMAGEARBPROC wglBindTexImageARB;
74 PFNWGLRELEASETEXIMAGEARBPROC wglReleaseTexImageARB;
75 PFNWGLSETPBUFFERATTRIBARBPROC wglSetPbufferAttribARB;
79 /* ARB_pixel_format */
80 #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
81 #define WGL_DRAW_TO_WINDOW_ARB 0x2001
82 #define WGL_DRAW_TO_BITMAP_ARB 0x2002
83 #define WGL_ACCELERATION_ARB 0x2003
84 #define WGL_NEED_PALETTE_ARB 0x2004
85 #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
86 #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
87 #define WGL_SWAP_METHOD_ARB 0x2007
88 #define WGL_NUMBER_OVERLAYS_ARB 0x2008
89 #define WGL_NUMBER_UNDERLAYS_ARB 0x2009
90 #define WGL_TRANSPARENT_ARB 0x200A
91 #define WGL_SHARE_DEPTH_ARB 0x200C
92 #define WGL_SHARE_STENCIL_ARB 0x200D
93 #define WGL_SHARE_ACCUM_ARB 0x200E
94 #define WGL_SUPPORT_GDI_ARB 0x200F
95 #define WGL_SUPPORT_OPENGL_ARB 0x2010
96 #define WGL_DOUBLE_BUFFER_ARB 0x2011
97 #define WGL_STEREO_ARB 0x2012
98 #define WGL_PIXEL_TYPE_ARB 0x2013
99 #define WGL_COLOR_BITS_ARB 0x2014
100 #define WGL_RED_BITS_ARB 0x2015
101 #define WGL_RED_SHIFT_ARB 0x2016
102 #define WGL_GREEN_BITS_ARB 0x2017
103 #define WGL_GREEN_SHIFT_ARB 0x2018
104 #define WGL_BLUE_BITS_ARB 0x2019
105 #define WGL_BLUE_SHIFT_ARB 0x201A
106 #define WGL_ALPHA_BITS_ARB 0x201B
107 #define WGL_ALPHA_SHIFT_ARB 0x201C
108 #define WGL_ACCUM_BITS_ARB 0x201D
109 #define WGL_ACCUM_RED_BITS_ARB 0x201E
110 #define WGL_ACCUM_GREEN_BITS_ARB 0x201F
111 #define WGL_ACCUM_BLUE_BITS_ARB 0x2020
112 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
113 #define WGL_DEPTH_BITS_ARB 0x2022
114 #define WGL_STENCIL_BITS_ARB 0x2023
115 #define WGL_AUX_BUFFERS_ARB 0x2024
116 #define WGL_NO_ACCELERATION_ARB 0x2025
117 #define WGL_GENERIC_ACCELERATION_ARB 0x2026
118 #define WGL_FULL_ACCELERATION_ARB 0x2027
119 #define WGL_SWAP_EXCHANGE_ARB 0x2028
120 #define WGL_SWAP_COPY_ARB 0x2029
121 #define WGL_SWAP_UNDEFINED_ARB 0x202A
122 #define WGL_TYPE_RGBA_ARB 0x202B
123 #define WGL_TYPE_COLORINDEX_ARB 0x202C
124 #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
125 #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
126 #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
127 #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
128 #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
130 /* ARB_multisample */
131 #define WGL_SAMPLE_BUFFERS_ARB 0x2041
132 #define WGL_SAMPLES_ARB 0x2042
137 // function declaration
139 bool QGL_Init( const char *dllname );
140 void QGL_Shutdown( void );
145 ========================
146 GLimp_GetOldGammaRamp
147 ========================
149 static void GLimp_SaveGamma( void ) {
153 hDC = GetDC( GetDesktopWindow() );
154 success = GetDeviceGammaRamp( hDC, win32.oldHardwareGamma );
155 common->DPrintf( "...getting default gamma ramp: %s\n", success ? "success" : "failed" );
156 ReleaseDC( GetDesktopWindow(), hDC );
160 ========================
162 ========================
164 static void GLimp_RestoreGamma( void ) {
168 // if we never read in a reasonable looking
169 // table, don't write it out
170 if ( win32.oldHardwareGamma[0][255] == 0 ) {
174 hDC = GetDC( GetDesktopWindow() );
175 success = SetDeviceGammaRamp( hDC, win32.oldHardwareGamma );
176 common->DPrintf ( "...restoring hardware gamma: %s\n", success ? "success" : "failed" );
177 ReleaseDC( GetDesktopWindow(), hDC );
182 ========================
185 The renderer calls this when the user adjusts r_gamma or r_brightness
186 ========================
188 void GLimp_SetGamma( unsigned short red[256], unsigned short green[256], unsigned short blue[256] ) {
189 unsigned short table[3][256];
196 for ( i = 0; i < 256; i++ ) {
197 table[0][i] = red[i];
198 table[1][i] = green[i];
199 table[2][i] = blue[i];
202 if ( !SetDeviceGammaRamp( win32.hDC, table ) ) {
203 common->Printf( "WARNING: SetDeviceGammaRamp failed.\n" );
208 =============================================================================
210 WglExtension Grabbing
212 This is gross -- creating a window just to get a context to get the wgl extensions
214 =============================================================================
221 Only used to get wglExtensions
224 LONG WINAPI FakeWndProc (
230 if ( uMsg == WM_DESTROY ) {
234 if ( uMsg != WM_CREATE ) {
235 return DefWindowProc(hWnd, uMsg, wParam, lParam);
238 const static PIXELFORMATDESCRIPTOR pfd = {
239 sizeof(PIXELFORMATDESCRIPTOR),
241 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
262 pixelFormat = ChoosePixelFormat(hDC, &pfd);
263 SetPixelFormat(hDC, pixelFormat, &pfd);
264 hGLRC = qwglCreateContext(hDC);
265 qwglMakeCurrent(hDC, hGLRC);
268 wglMakeCurrent(NULL, NULL);
269 wglDeleteContext(hGLRC);
270 ReleaseDC(hWnd, hDC);
272 return DefWindowProc(hWnd, uMsg, wParam, lParam);
278 GLW_GetWGLExtensionsWithFakeWindow
281 void GLW_CheckWGLExtensions( HDC hDC ) {
282 wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
283 GLimp_ExtensionPointer("wglGetExtensionsStringARB");
284 if ( wglGetExtensionsStringARB ) {
285 glConfig.wgl_extensions_string = (const char *) wglGetExtensionsStringARB(hDC);
287 glConfig.wgl_extensions_string = "";
290 // WGL_EXT_swap_control
291 wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) GLimp_ExtensionPointer( "wglSwapIntervalEXT" );
292 r_swapInterval.SetModified(); // force a set next frame
294 // WGL_ARB_pixel_format
295 wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)GLimp_ExtensionPointer("wglGetPixelFormatAttribivARB");
296 wglGetPixelFormatAttribfvARB = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)GLimp_ExtensionPointer("wglGetPixelFormatAttribfvARB");
297 wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)GLimp_ExtensionPointer("wglChoosePixelFormatARB");
300 wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)GLimp_ExtensionPointer("wglCreatePbufferARB");
301 wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)GLimp_ExtensionPointer("wglGetPbufferDCARB");
302 wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)GLimp_ExtensionPointer("wglReleasePbufferDCARB");
303 wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)GLimp_ExtensionPointer("wglDestroyPbufferARB");
304 wglQueryPbufferARB = (PFNWGLQUERYPBUFFERARBPROC)GLimp_ExtensionPointer("wglQueryPbufferARB");
306 // WGL_ARB_render_texture
307 wglBindTexImageARB = (PFNWGLBINDTEXIMAGEARBPROC)GLimp_ExtensionPointer("wglBindTexImageARB");
308 wglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARBPROC)GLimp_ExtensionPointer("wglReleaseTexImageARB");
309 wglSetPbufferAttribARB = (PFNWGLSETPBUFFERATTRIBARBPROC)GLimp_ExtensionPointer("wglSetPbufferAttribARB");
314 GLW_GetWGLExtensionsWithFakeWindow
317 static void GLW_GetWGLExtensionsWithFakeWindow( void ) {
321 // Create a window for the sole purpose of getting
322 // a valid context to get the wglextensions
323 hWnd = CreateWindow(WIN32_FAKE_WINDOW_CLASS_NAME, GAME_NAME,
328 NULL, NULL, win32.hInstance, NULL );
330 common->FatalError( "GLW_GetWGLExtensionsWithFakeWindow: Couldn't create fake window" );
333 HDC hDC = GetDC( hWnd );
334 HGLRC gRC = wglCreateContext( hDC );
335 wglMakeCurrent( hDC, gRC );
336 GLW_CheckWGLExtensions( hDC );
337 wglDeleteContext( gRC );
338 ReleaseDC( hWnd, hDC );
340 DestroyWindow( hWnd );
341 while ( GetMessage( &msg, NULL, 0, 0 ) ) {
342 TranslateMessage( &msg );
343 DispatchMessage( &msg );
347 //=============================================================================
354 void GLW_WM_CREATE( HWND hWnd ) {
363 Set the pixelformat for the window before it is
364 shown, and create the rendering context
367 static bool GLW_InitDriver( glimpParms_t parms ) {
368 PIXELFORMATDESCRIPTOR src =
370 sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
372 PFD_DRAW_TO_WINDOW | // support window
373 PFD_SUPPORT_OPENGL | // support OpenGL
374 PFD_DOUBLEBUFFER, // double buffered
375 PFD_TYPE_RGBA, // RGBA type
376 32, // 32-bit color depth
377 0, 0, 0, 0, 0, 0, // color bits ignored
378 8, // 8 bit destination alpha
379 0, // shift bit ignored
380 0, // no accumulation buffer
381 0, 0, 0, 0, // accum bits ignored
382 24, // 24-bit z-buffer
383 8, // 8-bit stencil buffer
384 0, // no auxiliary buffer
385 PFD_MAIN_PLANE, // main layer
387 0, 0, 0 // layer masks ignored
390 common->Printf( "Initializing OpenGL driver\n" );
393 // get a DC for our window if we don't already have one allocated
395 if ( win32.hDC == NULL ) {
396 common->Printf( "...getting DC: " );
398 if ( ( win32.hDC = GetDC( win32.hWnd ) ) == NULL ) {
399 common->Printf( "^3failed^0\n" );
402 common->Printf( "succeeded\n" );
405 // the multisample path uses the wgl
406 if ( wglChoosePixelFormatARB && parms.multiSamples > 1 ) {
408 FLOAT fAttributes[] = {0, 0};
411 // FIXME: specify all the other stuff
412 iAttributes[0] = WGL_SAMPLE_BUFFERS_ARB;
414 iAttributes[2] = WGL_SAMPLES_ARB;
415 iAttributes[3] = parms.multiSamples;
416 iAttributes[4] = WGL_DOUBLE_BUFFER_ARB;
417 iAttributes[5] = TRUE;
418 iAttributes[6] = WGL_STENCIL_BITS_ARB;
420 iAttributes[8] = WGL_DEPTH_BITS_ARB;
422 iAttributes[10] = WGL_RED_BITS_ARB;
424 iAttributes[12] = WGL_BLUE_BITS_ARB;
426 iAttributes[14] = WGL_GREEN_BITS_ARB;
428 iAttributes[16] = WGL_ALPHA_BITS_ARB;
433 wglChoosePixelFormatARB( win32.hDC, iAttributes, fAttributes, 1, &win32.pixelformat, &numFormats );
435 // this is the "classic" choose pixel format path
437 // eventually we may need to have more fallbacks, but for
438 // now, ask for everything
439 if ( parms.stereo ) {
440 common->Printf( "...attempting to use stereo\n" );
441 src.dwFlags |= PFD_STEREO;
445 // choose, set, and describe our desired pixel format. If we're
446 // using a minidriver then we need to bypass the GDI functions,
447 // otherwise use the GDI functions.
449 if ( ( win32.pixelformat = ChoosePixelFormat( win32.hDC, &src ) ) == 0 ) {
450 common->Printf( "...^3GLW_ChoosePFD failed^0\n");
453 common->Printf( "...PIXELFORMAT %d selected\n", win32.pixelformat );
457 DescribePixelFormat( win32.hDC, win32.pixelformat, sizeof( win32.pfd ), &win32.pfd );
458 glConfig.colorBits = win32.pfd.cColorBits;
459 glConfig.depthBits = win32.pfd.cDepthBits;
460 glConfig.stencilBits = win32.pfd.cStencilBits;
462 // XP seems to set this incorrectly
463 if ( !glConfig.stencilBits ) {
464 glConfig.stencilBits = 8;
467 // the same SetPixelFormat is used either way
468 if ( SetPixelFormat( win32.hDC, win32.pixelformat, &win32.pfd ) == FALSE ) {
469 common->Printf( "...^3SetPixelFormat failed^0\n", win32.hDC );
474 // startup the OpenGL subsystem by creating a context and making it current
476 common->Printf( "...creating GL context: " );
477 if ( ( win32.hGLRC = qwglCreateContext( win32.hDC ) ) == 0 ) {
478 common->Printf( "^3failed^0\n" );
481 common->Printf( "succeeded\n" );
483 common->Printf( "...making context current: " );
484 if ( !qwglMakeCurrent( win32.hDC, win32.hGLRC ) ) {
485 qwglDeleteContext( win32.hGLRC );
487 common->Printf( "^3failed^0\n" );
490 common->Printf( "succeeded\n" );
497 GLW_CreateWindowClasses
500 static void GLW_CreateWindowClasses( void ) {
504 // register the window class if necessary
506 if ( win32.windowClassRegistered ) {
510 memset( &wc, 0, sizeof( wc ) );
513 wc.lpfnWndProc = (WNDPROC) MainWndProc;
516 wc.hInstance = win32.hInstance;
517 wc.hIcon = LoadIcon( win32.hInstance, MAKEINTRESOURCE(IDI_ICON1));
518 wc.hCursor = LoadCursor (NULL,IDC_ARROW);
519 wc.hbrBackground = (struct HBRUSH__ *)COLOR_GRAYTEXT;
521 wc.lpszClassName = WIN32_WINDOW_CLASS_NAME;
523 if ( !RegisterClass( &wc ) ) {
524 common->FatalError( "GLW_CreateWindow: could not register window class" );
526 common->Printf( "...registered window class\n" );
528 // now register the fake window class that is only used
529 // to get wgl extensions
531 wc.lpfnWndProc = (WNDPROC) FakeWndProc;
534 wc.hInstance = win32.hInstance;
535 wc.hIcon = LoadIcon( win32.hInstance, MAKEINTRESOURCE(IDI_ICON1));
536 wc.hCursor = LoadCursor (NULL,IDC_ARROW);
537 wc.hbrBackground = (struct HBRUSH__ *)COLOR_GRAYTEXT;
539 wc.lpszClassName = WIN32_FAKE_WINDOW_CLASS_NAME;
541 if ( !RegisterClass( &wc ) ) {
542 common->FatalError( "GLW_CreateWindow: could not register window class" );
544 common->Printf( "...registered fake window class\n" );
546 win32.windowClassRegistered = true;
550 =======================
553 Responsible for creating the Win32 window.
554 If cdsFullscreen is true, it won't have a border
555 =======================
557 static bool GLW_CreateWindow( glimpParms_t parms ) {
563 // compute width and height
565 if ( parms.fullScreen ) {
566 exstyle = WS_EX_TOPMOST;
567 stylebits = WS_POPUP|WS_VISIBLE|WS_SYSMENU;
576 // adjust width and height for window border
577 r.bottom = parms.height;
580 r.right = parms.width;
583 stylebits = WINDOW_STYLE|WS_SYSMENU;
584 AdjustWindowRect (&r, stylebits, FALSE);
586 w = r.right - r.left;
587 h = r.bottom - r.top;
589 x = win32.win_xpos.GetInteger();
590 y = win32.win_ypos.GetInteger();
592 // adjust window coordinates if necessary
593 // so that the window is completely on screen
594 if ( x + w > win32.desktopWidth ) {
595 x = ( win32.desktopWidth - w );
597 if ( y + h > win32.desktopHeight ) {
598 y = ( win32.desktopHeight - h );
608 win32.hWnd = CreateWindowEx (
610 WIN32_WINDOW_CLASS_NAME,
620 common->Printf( "^3GLW_CreateWindow() - Couldn't create window^0\n" );
624 ::SetTimer( win32.hWnd, 0, 100, NULL );
626 ShowWindow( win32.hWnd, SW_SHOW );
627 UpdateWindow( win32.hWnd );
628 common->Printf( "...created window @ %d,%d (%dx%d)\n", x, y, w, h );
630 if ( !GLW_InitDriver( parms ) ) {
631 ShowWindow( win32.hWnd, SW_HIDE );
632 DestroyWindow( win32.hWnd );
637 SetForegroundWindow( win32.hWnd );
638 SetFocus( win32.hWnd );
640 glConfig.isFullscreen = parms.fullScreen;
647 static void PrintCDSError( int value ) {
649 case DISP_CHANGE_RESTART:
650 common->Printf( "restart required\n" );
652 case DISP_CHANGE_BADPARAM:
653 common->Printf( "bad param\n" );
655 case DISP_CHANGE_BADFLAGS:
656 common->Printf( "bad flags\n" );
658 case DISP_CHANGE_FAILED:
659 common->Printf( "DISP_CHANGE_FAILED\n" );
661 case DISP_CHANGE_BADMODE:
662 common->Printf( "bad mode\n" );
664 case DISP_CHANGE_NOTUPDATED:
665 common->Printf( "not updated\n" );
668 common->Printf( "unknown error %d\n", value );
679 static bool GLW_SetFullScreen( glimpParms_t parms ) {
681 // for some reason, bounds checker claims that windows is
682 // writing past the bounds of dm in the get display frequency call
695 // first make sure the user is not trying to select a mode that his card/monitor can't handle
697 for ( modeNum = 0 ; ; modeNum++ ) {
698 if ( !EnumDisplaySettings( NULL, modeNum, &devmode ) ) {
700 // we got a resolution match, but not a frequency match
701 // so disable the frequency requirement
702 common->Printf( "...^3%dhz is unsupported at %dx%d^0\n", parms.displayHz, parms.width, parms.height );
706 common->Printf( "...^3%dx%d is unsupported in 32 bit^0\n", parms.width, parms.height );
709 if ( (int)devmode.dmPelsWidth >= parms.width
710 && (int)devmode.dmPelsHeight >= parms.height
711 && devmode.dmBitsPerPel == 32 ) {
715 if ( parms.displayHz == 0 || devmode.dmDisplayFrequency == parms.displayHz ) {
721 memset( &dm, 0, sizeof( dm ) );
722 dm.dmSize = sizeof( dm );
724 dm.dmPelsWidth = parms.width;
725 dm.dmPelsHeight = parms.height;
726 dm.dmBitsPerPel = 32;
727 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
729 if ( parms.displayHz != 0 ) {
730 dm.dmDisplayFrequency = parms.displayHz;
731 dm.dmFields |= DM_DISPLAYFREQUENCY;
734 common->Printf( "...calling CDS: " );
736 // try setting the exact mode requested, because some drivers don't report
737 // the low res modes in EnumDisplaySettings, but still work
738 if ( ( cdsRet = ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) ) == DISP_CHANGE_SUCCESSFUL ) {
739 common->Printf( "ok\n" );
740 win32.cdsFullscreen = true;
745 // the exact mode failed, so scan EnumDisplaySettings for the next largest mode
747 common->Printf( "^3failed^0, " );
749 PrintCDSError( cdsRet );
751 common->Printf( "...trying next higher resolution:" );
753 // we could do a better matching job here...
754 for ( modeNum = 0 ; ; modeNum++ ) {
755 if ( !EnumDisplaySettings( NULL, modeNum, &devmode ) ) {
758 if ( (int)devmode.dmPelsWidth >= parms.width
759 && (int)devmode.dmPelsHeight >= parms.height
760 && devmode.dmBitsPerPel == 32 ) {
762 if ( ( cdsRet = ChangeDisplaySettings( &devmode, CDS_FULLSCREEN ) ) == DISP_CHANGE_SUCCESSFUL ) {
763 common->Printf( "ok\n" );
764 win32.cdsFullscreen = true;
772 common->Printf( "\n...^3no high res mode found^0\n" );
782 This is the platform specific OpenGL initialization function. It
783 is responsible for loading OpenGL, initializing it,
784 creating a window of the appropriate size, doing
785 fullscreen manipulations, etc. Its overall responsibility is
786 to make sure that a functional OpenGL subsystem is operating
787 when it returns to the ref.
789 If there is any failure, the renderer will revert back to safe
790 parameters and try again.
793 bool GLimp_Init( glimpParms_t parms ) {
794 const char *driverName;
797 common->Printf( "Initializing OpenGL subsystem\n" );
799 // check our desktop attributes
800 hDC = GetDC( GetDesktopWindow() );
801 win32.desktopBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
802 win32.desktopWidth = GetDeviceCaps( hDC, HORZRES );
803 win32.desktopHeight = GetDeviceCaps( hDC, VERTRES );
804 ReleaseDC( GetDesktopWindow(), hDC );
806 // we can't run in a window unless it is 32 bpp
807 if ( win32.desktopBitsPixel < 32 && !parms.fullScreen ) {
808 common->Printf("^3Windowed mode requires 32 bit desktop depth^0\n");
812 // save the hardware gamma so it can be
816 // create our window classes if we haven't already
817 GLW_CreateWindowClasses();
819 // this will load the dll and set all our qgl* function pointers,
820 // but doesn't create a window
822 // r_glDriver is only intended for using instrumented OpenGL
823 // dlls. Normal users should never have to use it, and it is
825 driverName = r_glDriver.GetString()[0] ? r_glDriver.GetString() : "opengl32";
826 if ( !QGL_Init( driverName ) ) {
827 common->Printf( "^3GLimp_Init() could not load r_glDriver \"%s\"^0\n", driverName );
831 // getting the wgl extensions involves creating a fake window to get a context,
832 // which is pretty disgusting, and seems to mess with the AGP VAR allocation
833 GLW_GetWGLExtensionsWithFakeWindow();
835 // try to change to fullscreen
836 if ( parms.fullScreen ) {
837 if ( !GLW_SetFullScreen( parms ) ) {
843 // try to create a window with the correct pixel format
844 // and init the renderer context
845 if ( !GLW_CreateWindow( parms ) ) {
850 // wglSwapinterval, etc
851 GLW_CheckWGLExtensions( win32.hDC );
854 GLimp_EnableLogging( ( r_logFile.GetInteger() != 0 ) );
864 Sets up the screen based on passed parms..
867 bool GLimp_SetScreenParms( glimpParms_t parms ) {
873 memset( &dm, 0, sizeof( dm ) );
874 dm.dmSize = sizeof( dm );
875 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
876 if ( parms.displayHz != 0 ) {
877 dm.dmDisplayFrequency = parms.displayHz;
878 dm.dmFields |= DM_DISPLAYFREQUENCY;
881 win32.cdsFullscreen = parms.fullScreen;
882 glConfig.isFullscreen = parms.fullScreen;
884 if ( parms.fullScreen ) {
885 exstyle = WS_EX_TOPMOST;
886 stylebits = WS_POPUP|WS_VISIBLE|WS_SYSMENU;
887 SetWindowLong( win32.hWnd, GWL_STYLE, stylebits );
888 SetWindowLong( win32.hWnd, GWL_EXSTYLE, exstyle );
889 dm.dmPelsWidth = parms.width;
890 dm.dmPelsHeight = parms.height;
891 dm.dmBitsPerPel = 32;
896 // adjust width and height for window border
897 r.bottom = parms.height;
900 r.right = parms.width;
902 w = r.right - r.left;
903 h = r.bottom - r.top;
905 x = win32.win_xpos.GetInteger();
906 y = win32.win_ypos.GetInteger();
908 // adjust window coordinates if necessary
909 // so that the window is completely on screen
910 if ( x + w > win32.desktopWidth ) {
911 x = ( win32.desktopWidth - w );
913 if ( y + h > win32.desktopHeight ) {
914 y = ( win32.desktopHeight - h );
922 dm.dmPelsWidth = win32.desktopWidth;
923 dm.dmPelsHeight = win32.desktopHeight;
924 dm.dmBitsPerPel = win32.desktopBitsPixel;
926 stylebits = WINDOW_STYLE|WS_SYSMENU;
927 AdjustWindowRect (&r, stylebits, FALSE);
928 SetWindowLong( win32.hWnd, GWL_STYLE, stylebits );
929 SetWindowLong( win32.hWnd, GWL_EXSTYLE, exstyle );
930 common->Printf( "%i %i %i %i\n", x, y, w, h );
932 bool ret = ( ChangeDisplaySettings( &dm, parms.fullScreen ? CDS_FULLSCREEN : 0 ) == DISP_CHANGE_SUCCESSFUL );
933 SetWindowPos( win32.hWnd, parms.fullScreen ? HWND_TOPMOST : HWND_NOTOPMOST, x, y, w, h, parms.fullScreen ? SWP_NOSIZE | SWP_NOMOVE : SWP_SHOWWINDOW );
941 This routine does all OS specific shutdown procedures for the OpenGL
945 void GLimp_Shutdown( void ) {
946 const char *success[] = { "failed", "success" };
949 common->Printf( "Shutting down OpenGL subsystem\n" );
951 // set current context to NULL
952 if ( qwglMakeCurrent ) {
953 retVal = qwglMakeCurrent( NULL, NULL ) != 0;
954 common->Printf( "...wglMakeCurrent( NULL, NULL ): %s\n", success[retVal] );
959 retVal = qwglDeleteContext( win32.hGLRC ) != 0;
960 common->Printf( "...deleting GL context: %s\n", success[retVal] );
966 retVal = ReleaseDC( win32.hWnd, win32.hDC ) != 0;
967 common->Printf( "...releasing DC: %s\n", success[retVal] );
973 common->Printf( "...destroying window\n" );
974 ShowWindow( win32.hWnd, SW_HIDE );
975 DestroyWindow( win32.hWnd );
979 // reset display settings
980 if ( win32.cdsFullscreen ) {
981 common->Printf( "...resetting display\n" );
982 ChangeDisplaySettings( 0, 0 );
983 win32.cdsFullscreen = false;
986 // close the thread so the handle doesn't dangle
987 if ( win32.renderThreadHandle ) {
988 common->Printf( "...closing smp thread\n" );
989 CloseHandle( win32.renderThreadHandle );
990 win32.renderThreadHandle = NULL;
994 GLimp_RestoreGamma();
996 // shutdown QGL subsystem
1002 =====================
1004 =====================
1006 void GLimp_SwapBuffers( void ) {
1008 // wglSwapinterval is a windows-private extension,
1009 // so we must check for it here instead of portably
1011 if ( r_swapInterval.IsModified() ) {
1012 r_swapInterval.ClearModified();
1014 if ( wglSwapIntervalEXT ) {
1015 wglSwapIntervalEXT( r_swapInterval.GetInteger() );
1019 qwglSwapBuffers( win32.hDC );
1021 //Sys_DebugPrintf( "*** SwapBuffers() ***\n" );
1025 ===========================================================
1029 ===========================================================
1032 //#define REALLOC_DC
1036 GLimp_ActivateContext
1040 void GLimp_ActivateContext( void ) {
1041 if ( !qwglMakeCurrent( win32.hDC, win32.hGLRC ) ) {
1048 GLimp_DeactivateContext
1052 void GLimp_DeactivateContext( void ) {
1054 if ( !qwglMakeCurrent( win32.hDC, NULL ) ) {
1058 // makeCurrent NULL frees the DC, so get another
1059 if ( ( win32.hDC = GetDC( win32.hWnd ) ) == NULL ) {
1068 GLimp_RenderThreadWrapper
1072 static void GLimp_RenderThreadWrapper( void ) {
1073 win32.glimpRenderThread();
1075 // unbind the context before we die
1076 qwglMakeCurrent( win32.hDC, NULL );
1080 =======================
1081 GLimp_SpawnRenderThread
1083 Returns false if the system only has a single processor
1084 =======================
1086 bool GLimp_SpawnRenderThread( void (*function)( void ) ) {
1089 // check number of processors
1090 GetSystemInfo( &info );
1091 if ( info.dwNumberOfProcessors < 2 ) {
1095 // create the IPC elements
1096 win32.renderCommandsEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
1097 win32.renderCompletedEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
1098 win32.renderActiveEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
1100 win32.glimpRenderThread = function;
1102 win32.renderThreadHandle = CreateThread(
1103 NULL, // LPSECURITY_ATTRIBUTES lpsa,
1104 0, // DWORD cbStack,
1105 (LPTHREAD_START_ROUTINE)GLimp_RenderThreadWrapper, // LPTHREAD_START_ROUTINE lpStartAddr,
1106 0, // LPVOID lpvThreadParm,
1107 0, // DWORD fdwCreate,
1108 &win32.renderThreadId );
1110 if ( !win32.renderThreadHandle ) {
1111 common->Error( "GLimp_SpawnRenderThread: failed" );
1114 SetThreadPriority( win32.renderThreadHandle, THREAD_PRIORITY_ABOVE_NORMAL );
1116 // make sure they always run on different processors
1117 SetThreadAffinityMask( GetCurrentThread, 1 );
1118 SetThreadAffinityMask( win32.renderThreadHandle, 2 );
1125 //#define DEBUG_PRINTS
1133 void *GLimp_BackEndSleep( void ) {
1137 OutputDebugString( "-->GLimp_BackEndSleep\n" );
1139 ResetEvent( win32.renderActiveEvent );
1141 // after this, the front end can exit GLimp_FrontEndSleep
1142 SetEvent( win32.renderCompletedEvent );
1144 WaitForSingleObject( win32.renderCommandsEvent, INFINITE );
1146 ResetEvent( win32.renderCompletedEvent );
1147 ResetEvent( win32.renderCommandsEvent );
1149 data = win32.smpData;
1151 // after this, the main thread can exit GLimp_WakeRenderer
1152 SetEvent( win32.renderActiveEvent );
1155 OutputDebugString( "<--GLimp_BackEndSleep\n" );
1166 void GLimp_FrontEndSleep( void ) {
1168 OutputDebugString( "-->GLimp_FrontEndSleep\n" );
1170 WaitForSingleObject( win32.renderCompletedEvent, INFINITE );
1173 OutputDebugString( "<--GLimp_FrontEndSleep\n" );
1177 volatile bool renderThreadActive;
1185 void GLimp_WakeBackEnd( void *data ) {
1189 OutputDebugString( "-->GLimp_WakeBackEnd\n" );
1191 win32.smpData = data;
1193 if ( renderThreadActive ) {
1194 common->FatalError( "GLimp_WakeBackEnd: already active" );
1197 r = WaitForSingleObject( win32.renderActiveEvent, 0 );
1198 if ( r == WAIT_OBJECT_0 ) {
1199 common->FatalError( "GLimp_WakeBackEnd: already signaled" );
1202 r = WaitForSingleObject( win32.renderCommandsEvent, 0 );
1203 if ( r == WAIT_OBJECT_0 ) {
1204 common->FatalError( "GLimp_WakeBackEnd: commands already signaled" );
1207 // after this, the renderer can continue through GLimp_RendererSleep
1208 SetEvent( win32.renderCommandsEvent );
1210 r = WaitForSingleObject( win32.renderActiveEvent, 5000 );
1212 if ( r == WAIT_TIMEOUT ) {
1213 common->FatalError( "GLimp_WakeBackEnd: WAIT_TIMEOUT" );
1217 OutputDebugString( "<--GLimp_WakeBackEnd\n" );
1221 //===================================================================
1225 GLimp_ExtensionPointer
1227 Returns a function pointer for an OpenGL extension entry point
1230 GLExtension_t GLimp_ExtensionPointer( const char *name ) {
1233 proc = (GLExtension_t)qwglGetProcAddress( name );
1236 common->Printf( "Couldn't find proc address for: %s\n", name );