win_glimp.cpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition 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 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. 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.
  18. ===========================================================================
  19. */
  20. /*
  21. ** WIN_GLIMP.C
  22. **
  23. ** This file contains ALL Win32 specific stuff having to do with the
  24. ** OpenGL refresh. When a port is being made the following functions
  25. ** must be implemented by the port:
  26. **
  27. ** GLimp_SwapBuffers
  28. ** GLimp_Init
  29. ** GLimp_Shutdown
  30. ** GLimp_SetGamma
  31. **
  32. ** Note that the GLW_xxx functions are Windows specific GL-subsystem
  33. ** related functions that are relevant ONLY to win_glimp.c
  34. */
  35. #pragma hdrstop
  36. #include "../../idlib/precompiled.h"
  37. #include "win_local.h"
  38. #include "rc/doom_resource.h"
  39. #include "../../renderer/tr_local.h"
  40. // WGL_ARB_extensions_string
  41. PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
  42. // WGL_EXT_swap_interval
  43. PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
  44. // WGL_ARB_pixel_format
  45. PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB;
  46. PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB;
  47. PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
  48. // WGL_ARB_create_context
  49. PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
  50. idCVar r_useOpenGL32( "r_useOpenGL32", "1", CVAR_INTEGER, "0 = OpenGL 2.0, 1 = OpenGL 3.2 compatibility profile, 2 = OpenGL 3.2 core profile", 0, 2 );
  51. //
  52. // function declaration
  53. //
  54. bool QGL_Init( const char *dllname );
  55. void QGL_Shutdown();
  56. /*
  57. ========================
  58. GLimp_TestSwapBuffers
  59. ========================
  60. */
  61. void GLimp_TestSwapBuffers( const idCmdArgs &args ) {
  62. idLib::Printf( "GLimp_TimeSwapBuffers\n" );
  63. static const int MAX_FRAMES = 5;
  64. uint64 timestamps[MAX_FRAMES];
  65. qglDisable( GL_SCISSOR_TEST );
  66. int frameMilliseconds = 16;
  67. for ( int swapInterval = 2 ; swapInterval >= -1 ; swapInterval-- ) {
  68. wglSwapIntervalEXT( swapInterval );
  69. for ( int i = 0 ; i < MAX_FRAMES ; i++ ) {
  70. if ( swapInterval == -1 ) {
  71. Sys_Sleep( frameMilliseconds );
  72. }
  73. if ( i & 1 ) {
  74. qglClearColor( 0, 1, 0, 1 );
  75. } else {
  76. qglClearColor( 1, 0, 0, 1 );
  77. }
  78. qglClear( GL_COLOR_BUFFER_BIT );
  79. qwglSwapBuffers( win32.hDC );
  80. qglFinish();
  81. timestamps[i] = Sys_Microseconds();
  82. }
  83. idLib::Printf( "\nswapinterval %i\n", swapInterval );
  84. for ( int i = 1 ; i < MAX_FRAMES ; i++ ) {
  85. idLib::Printf( "%i microseconds\n", (int)(timestamps[i] - timestamps[i-1]) );
  86. }
  87. }
  88. }
  89. /*
  90. ========================
  91. GLimp_GetOldGammaRamp
  92. ========================
  93. */
  94. static void GLimp_SaveGamma() {
  95. HDC hDC;
  96. BOOL success;
  97. hDC = GetDC( GetDesktopWindow() );
  98. success = GetDeviceGammaRamp( hDC, win32.oldHardwareGamma );
  99. common->DPrintf( "...getting default gamma ramp: %s\n", success ? "success" : "failed" );
  100. ReleaseDC( GetDesktopWindow(), hDC );
  101. }
  102. /*
  103. ========================
  104. GLimp_RestoreGamma
  105. ========================
  106. */
  107. static void GLimp_RestoreGamma() {
  108. HDC hDC;
  109. BOOL success;
  110. // if we never read in a reasonable looking
  111. // table, don't write it out
  112. if ( win32.oldHardwareGamma[0][255] == 0 ) {
  113. return;
  114. }
  115. hDC = GetDC( GetDesktopWindow() );
  116. success = SetDeviceGammaRamp( hDC, win32.oldHardwareGamma );
  117. common->DPrintf ( "...restoring hardware gamma: %s\n", success ? "success" : "failed" );
  118. ReleaseDC( GetDesktopWindow(), hDC );
  119. }
  120. /*
  121. ========================
  122. GLimp_SetGamma
  123. The renderer calls this when the user adjusts r_gamma or r_brightness
  124. ========================
  125. */
  126. void GLimp_SetGamma( unsigned short red[256], unsigned short green[256], unsigned short blue[256] ) {
  127. unsigned short table[3][256];
  128. int i;
  129. if ( !win32.hDC ) {
  130. return;
  131. }
  132. for ( i = 0; i < 256; i++ ) {
  133. table[0][i] = red[i];
  134. table[1][i] = green[i];
  135. table[2][i] = blue[i];
  136. }
  137. if ( !SetDeviceGammaRamp( win32.hDC, table ) ) {
  138. common->Printf( "WARNING: SetDeviceGammaRamp failed.\n" );
  139. }
  140. }
  141. /*
  142. =============================================================================
  143. WglExtension Grabbing
  144. This is gross -- creating a window just to get a context to get the wgl extensions
  145. =============================================================================
  146. */
  147. /*
  148. ========================
  149. R_CheckWinExtension
  150. ========================
  151. */
  152. bool R_CheckWinExtension( const char * name ) {
  153. if ( !strstr( glConfig.wgl_extensions_string, name ) ) {
  154. idLib::Printf( "X..%s not found\n", name );
  155. return false;
  156. }
  157. idLib::Printf( "...using %s\n", name );
  158. return true;
  159. }
  160. /*
  161. ====================
  162. FakeWndProc
  163. Only used to get wglExtensions
  164. ====================
  165. */
  166. LONG WINAPI FakeWndProc (
  167. HWND hWnd,
  168. UINT uMsg,
  169. WPARAM wParam,
  170. LPARAM lParam) {
  171. if ( uMsg == WM_DESTROY ) {
  172. PostQuitMessage(0);
  173. }
  174. if ( uMsg != WM_CREATE ) {
  175. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  176. }
  177. const static PIXELFORMATDESCRIPTOR pfd = {
  178. sizeof(PIXELFORMATDESCRIPTOR),
  179. 1,
  180. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
  181. PFD_TYPE_RGBA,
  182. 24,
  183. 0, 0, 0, 0, 0, 0,
  184. 8, 0,
  185. 0, 0, 0, 0,
  186. 24, 8,
  187. 0,
  188. PFD_MAIN_PLANE,
  189. 0,
  190. 0,
  191. 0,
  192. 0,
  193. };
  194. int pixelFormat;
  195. HDC hDC;
  196. HGLRC hGLRC;
  197. hDC = GetDC(hWnd);
  198. // Set up OpenGL
  199. pixelFormat = ChoosePixelFormat(hDC, &pfd);
  200. SetPixelFormat(hDC, pixelFormat, &pfd);
  201. hGLRC = qwglCreateContext(hDC);
  202. qwglMakeCurrent(hDC, hGLRC);
  203. // free things
  204. wglMakeCurrent(NULL, NULL);
  205. wglDeleteContext(hGLRC);
  206. ReleaseDC(hWnd, hDC);
  207. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  208. }
  209. /*
  210. ==================
  211. GLW_GetWGLExtensionsWithFakeWindow
  212. ==================
  213. */
  214. void GLW_CheckWGLExtensions( HDC hDC ) {
  215. wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
  216. GLimp_ExtensionPointer("wglGetExtensionsStringARB");
  217. if ( wglGetExtensionsStringARB ) {
  218. glConfig.wgl_extensions_string = (const char *) wglGetExtensionsStringARB(hDC);
  219. } else {
  220. glConfig.wgl_extensions_string = "";
  221. }
  222. // WGL_EXT_swap_control
  223. wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) GLimp_ExtensionPointer( "wglSwapIntervalEXT" );
  224. r_swapInterval.SetModified(); // force a set next frame
  225. // WGL_EXT_swap_control_tear
  226. glConfig.swapControlTearAvailable = R_CheckWinExtension( "WGL_EXT_swap_control_tear" );
  227. // WGL_ARB_pixel_format
  228. wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)GLimp_ExtensionPointer("wglGetPixelFormatAttribivARB");
  229. wglGetPixelFormatAttribfvARB = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)GLimp_ExtensionPointer("wglGetPixelFormatAttribfvARB");
  230. wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)GLimp_ExtensionPointer("wglChoosePixelFormatARB");
  231. // wglCreateContextAttribsARB
  232. wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress( "wglCreateContextAttribsARB" );
  233. }
  234. /*
  235. ==================
  236. GLW_GetWGLExtensionsWithFakeWindow
  237. ==================
  238. */
  239. static void GLW_GetWGLExtensionsWithFakeWindow() {
  240. HWND hWnd;
  241. MSG msg;
  242. // Create a window for the sole purpose of getting
  243. // a valid context to get the wglextensions
  244. hWnd = CreateWindow(WIN32_FAKE_WINDOW_CLASS_NAME, GAME_NAME,
  245. WS_OVERLAPPEDWINDOW,
  246. 40, 40,
  247. 640,
  248. 480,
  249. NULL, NULL, win32.hInstance, NULL );
  250. if ( !hWnd ) {
  251. common->FatalError( "GLW_GetWGLExtensionsWithFakeWindow: Couldn't create fake window" );
  252. }
  253. HDC hDC = GetDC( hWnd );
  254. HGLRC gRC = wglCreateContext( hDC );
  255. wglMakeCurrent( hDC, gRC );
  256. GLW_CheckWGLExtensions( hDC );
  257. wglDeleteContext( gRC );
  258. ReleaseDC( hWnd, hDC );
  259. DestroyWindow( hWnd );
  260. while ( GetMessage( &msg, NULL, 0, 0 ) ) {
  261. TranslateMessage( &msg );
  262. DispatchMessage( &msg );
  263. }
  264. }
  265. //=============================================================================
  266. /*
  267. ====================
  268. GLW_WM_CREATE
  269. ====================
  270. */
  271. void GLW_WM_CREATE( HWND hWnd ) {
  272. }
  273. /*
  274. ========================
  275. CreateOpenGLContextOnDC
  276. ========================
  277. */
  278. static HGLRC CreateOpenGLContextOnDC( const HDC hdc, const bool debugContext ) {
  279. int useOpenGL32 = r_useOpenGL32.GetInteger();
  280. HGLRC m_hrc = NULL;
  281. for ( int i = 0; i < 2; i++ ) {
  282. const int glMajorVersion = ( useOpenGL32 != 0 ) ? 3 : 2;
  283. const int glMinorVersion = ( useOpenGL32 != 0 ) ? 2 : 0;
  284. const int glDebugFlag = debugContext ? WGL_CONTEXT_DEBUG_BIT_ARB : 0;
  285. const int glProfileMask = ( useOpenGL32 != 0 ) ? WGL_CONTEXT_PROFILE_MASK_ARB : 0;
  286. const int glProfile = ( useOpenGL32 == 1 ) ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : ( ( useOpenGL32 == 2 ) ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : 0 );
  287. const int attribs[] =
  288. {
  289. WGL_CONTEXT_MAJOR_VERSION_ARB, glMajorVersion,
  290. WGL_CONTEXT_MINOR_VERSION_ARB, glMinorVersion,
  291. WGL_CONTEXT_FLAGS_ARB, glDebugFlag,
  292. glProfileMask, glProfile,
  293. 0
  294. };
  295. m_hrc = wglCreateContextAttribsARB( hdc, 0, attribs );
  296. if ( m_hrc != NULL ) {
  297. idLib::Printf( "created OpenGL %d.%d context\n", glMajorVersion, glMinorVersion );
  298. break;
  299. }
  300. idLib::Printf( "failed to create OpenGL %d.%d context\n", glMajorVersion, glMinorVersion );
  301. useOpenGL32 = 0; // fall back to OpenGL 2.0
  302. }
  303. if ( m_hrc == NULL ) {
  304. int err = GetLastError();
  305. switch( err ) {
  306. case ERROR_INVALID_VERSION_ARB: idLib::Printf( "ERROR_INVALID_VERSION_ARB\n" ); break;
  307. case ERROR_INVALID_PROFILE_ARB: idLib::Printf( "ERROR_INVALID_PROFILE_ARB\n" ); break;
  308. default: idLib::Printf( "unknown error: 0x%x\n", err ); break;
  309. }
  310. }
  311. return m_hrc;
  312. }
  313. /*
  314. ====================
  315. GLW_ChoosePixelFormat
  316. Returns -1 on failure, or a pixel format
  317. ====================
  318. */
  319. static int GLW_ChoosePixelFormat( const HDC hdc, const int multisamples, const bool stereo3D ) {
  320. FLOAT fAttributes[] = { 0, 0 };
  321. int iAttributes[] = {
  322. WGL_SAMPLE_BUFFERS_ARB, ( ( multisamples > 1 ) ? 1 : 0 ),
  323. WGL_SAMPLES_ARB, multisamples,
  324. WGL_DOUBLE_BUFFER_ARB, TRUE,
  325. WGL_STENCIL_BITS_ARB, 8,
  326. WGL_DEPTH_BITS_ARB, 24,
  327. WGL_RED_BITS_ARB, 8,
  328. WGL_BLUE_BITS_ARB, 8,
  329. WGL_GREEN_BITS_ARB, 8,
  330. WGL_ALPHA_BITS_ARB, 8,
  331. WGL_STEREO_ARB, ( stereo3D ? TRUE : FALSE ),
  332. 0, 0
  333. };
  334. int pixelFormat;
  335. UINT numFormats;
  336. if ( !wglChoosePixelFormatARB( hdc, iAttributes, fAttributes, 1, &pixelFormat, &numFormats ) ) {
  337. return -1;
  338. }
  339. return pixelFormat;
  340. }
  341. /*
  342. ====================
  343. GLW_InitDriver
  344. Set the pixelformat for the window before it is
  345. shown, and create the rendering context
  346. ====================
  347. */
  348. static bool GLW_InitDriver( glimpParms_t parms ) {
  349. PIXELFORMATDESCRIPTOR src =
  350. {
  351. sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
  352. 1, // version number
  353. PFD_DRAW_TO_WINDOW | // support window
  354. PFD_SUPPORT_OPENGL | // support OpenGL
  355. PFD_DOUBLEBUFFER, // double buffered
  356. PFD_TYPE_RGBA, // RGBA type
  357. 32, // 32-bit color depth
  358. 0, 0, 0, 0, 0, 0, // color bits ignored
  359. 8, // 8 bit destination alpha
  360. 0, // shift bit ignored
  361. 0, // no accumulation buffer
  362. 0, 0, 0, 0, // accum bits ignored
  363. 24, // 24-bit z-buffer
  364. 8, // 8-bit stencil buffer
  365. 0, // no auxiliary buffer
  366. PFD_MAIN_PLANE, // main layer
  367. 0, // reserved
  368. 0, 0, 0 // layer masks ignored
  369. };
  370. common->Printf( "Initializing OpenGL driver\n" );
  371. //
  372. // get a DC for our window if we don't already have one allocated
  373. //
  374. if ( win32.hDC == NULL ) {
  375. common->Printf( "...getting DC: " );
  376. if ( ( win32.hDC = GetDC( win32.hWnd ) ) == NULL ) {
  377. common->Printf( "^3failed^0\n" );
  378. return false;
  379. }
  380. common->Printf( "succeeded\n" );
  381. }
  382. // the multisample path uses the wgl
  383. if ( wglChoosePixelFormatARB ) {
  384. win32.pixelformat = GLW_ChoosePixelFormat( win32.hDC, parms.multiSamples, parms.stereo );
  385. } else {
  386. // this is the "classic" choose pixel format path
  387. common->Printf( "Using classic ChoosePixelFormat\n" );
  388. // eventually we may need to have more fallbacks, but for
  389. // now, ask for everything
  390. if ( parms.stereo ) {
  391. common->Printf( "...attempting to use stereo\n" );
  392. src.dwFlags |= PFD_STEREO;
  393. }
  394. //
  395. // choose, set, and describe our desired pixel format. If we're
  396. // using a minidriver then we need to bypass the GDI functions,
  397. // otherwise use the GDI functions.
  398. //
  399. if ( ( win32.pixelformat = ChoosePixelFormat( win32.hDC, &src ) ) == 0 ) {
  400. common->Printf( "...^3GLW_ChoosePFD failed^0\n");
  401. return false;
  402. }
  403. common->Printf( "...PIXELFORMAT %d selected\n", win32.pixelformat );
  404. }
  405. // get the full info
  406. DescribePixelFormat( win32.hDC, win32.pixelformat, sizeof( win32.pfd ), &win32.pfd );
  407. glConfig.colorBits = win32.pfd.cColorBits;
  408. glConfig.depthBits = win32.pfd.cDepthBits;
  409. glConfig.stencilBits = win32.pfd.cStencilBits;
  410. // XP seems to set this incorrectly
  411. if ( !glConfig.stencilBits ) {
  412. glConfig.stencilBits = 8;
  413. }
  414. // the same SetPixelFormat is used either way
  415. if ( SetPixelFormat( win32.hDC, win32.pixelformat, &win32.pfd ) == FALSE ) {
  416. common->Printf( "...^3SetPixelFormat failed^0\n", win32.hDC );
  417. return false;
  418. }
  419. //
  420. // startup the OpenGL subsystem by creating a context and making it current
  421. //
  422. common->Printf( "...creating GL context: " );
  423. win32.hGLRC = CreateOpenGLContextOnDC( win32.hDC, r_debugContext.GetBool() );
  424. if ( win32.hGLRC == 0 ) {
  425. common->Printf( "^3failed^0\n" );
  426. return false;
  427. }
  428. common->Printf( "succeeded\n" );
  429. common->Printf( "...making context current: " );
  430. if ( !qwglMakeCurrent( win32.hDC, win32.hGLRC ) ) {
  431. qwglDeleteContext( win32.hGLRC );
  432. win32.hGLRC = NULL;
  433. common->Printf( "^3failed^0\n" );
  434. return false;
  435. }
  436. common->Printf( "succeeded\n" );
  437. return true;
  438. }
  439. /*
  440. ====================
  441. GLW_CreateWindowClasses
  442. ====================
  443. */
  444. static void GLW_CreateWindowClasses() {
  445. WNDCLASS wc;
  446. //
  447. // register the window class if necessary
  448. //
  449. if ( win32.windowClassRegistered ) {
  450. return;
  451. }
  452. memset( &wc, 0, sizeof( wc ) );
  453. wc.style = 0;
  454. wc.lpfnWndProc = (WNDPROC) MainWndProc;
  455. wc.cbClsExtra = 0;
  456. wc.cbWndExtra = 0;
  457. wc.hInstance = win32.hInstance;
  458. wc.hIcon = LoadIcon( win32.hInstance, MAKEINTRESOURCE(IDI_ICON1));
  459. wc.hCursor = NULL;
  460. wc.hbrBackground = (struct HBRUSH__ *)COLOR_GRAYTEXT;
  461. wc.lpszMenuName = 0;
  462. wc.lpszClassName = WIN32_WINDOW_CLASS_NAME;
  463. if ( !RegisterClass( &wc ) ) {
  464. common->FatalError( "GLW_CreateWindow: could not register window class" );
  465. }
  466. common->Printf( "...registered window class\n" );
  467. // now register the fake window class that is only used
  468. // to get wgl extensions
  469. wc.style = 0;
  470. wc.lpfnWndProc = (WNDPROC) FakeWndProc;
  471. wc.cbClsExtra = 0;
  472. wc.cbWndExtra = 0;
  473. wc.hInstance = win32.hInstance;
  474. wc.hIcon = LoadIcon( win32.hInstance, MAKEINTRESOURCE(IDI_ICON1));
  475. wc.hCursor = LoadCursor (NULL,IDC_ARROW);
  476. wc.hbrBackground = (struct HBRUSH__ *)COLOR_GRAYTEXT;
  477. wc.lpszMenuName = 0;
  478. wc.lpszClassName = WIN32_FAKE_WINDOW_CLASS_NAME;
  479. if ( !RegisterClass( &wc ) ) {
  480. common->FatalError( "GLW_CreateWindow: could not register window class" );
  481. }
  482. common->Printf( "...registered fake window class\n" );
  483. win32.windowClassRegistered = true;
  484. }
  485. /*
  486. ========================
  487. GetDisplayName
  488. ========================
  489. */
  490. static const char * GetDisplayName( const int deviceNum ) {
  491. static DISPLAY_DEVICE device;
  492. device.cb = sizeof( device );
  493. if ( !EnumDisplayDevices(
  494. 0, // lpDevice
  495. deviceNum,
  496. &device,
  497. 0 /* dwFlags */ ) ) {
  498. return NULL;
  499. }
  500. return device.DeviceName;
  501. }
  502. /*
  503. ========================
  504. GetDeviceName
  505. ========================
  506. */
  507. static idStr GetDeviceName( const int deviceNum ) {
  508. DISPLAY_DEVICE device = {};
  509. device.cb = sizeof( device );
  510. if ( !EnumDisplayDevices(
  511. 0, // lpDevice
  512. deviceNum,
  513. &device,
  514. 0 /* dwFlags */ ) ) {
  515. return false;
  516. }
  517. // get the monitor for this display
  518. if ( ! (device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP ) ) {
  519. return false;
  520. }
  521. return idStr( device.DeviceName );
  522. }
  523. /*
  524. ========================
  525. GetDisplayCoordinates
  526. ========================
  527. */
  528. static bool GetDisplayCoordinates( const int deviceNum, int & x, int & y, int & width, int & height, int & displayHz ) {
  529. idStr deviceName = GetDeviceName( deviceNum );
  530. if ( deviceName.Length() == 0 ) {
  531. return false;
  532. }
  533. DISPLAY_DEVICE device = {};
  534. device.cb = sizeof( device );
  535. if ( !EnumDisplayDevices(
  536. 0, // lpDevice
  537. deviceNum,
  538. &device,
  539. 0 /* dwFlags */ ) ) {
  540. return false;
  541. }
  542. DISPLAY_DEVICE monitor;
  543. monitor.cb = sizeof( monitor );
  544. if ( !EnumDisplayDevices(
  545. deviceName.c_str(),
  546. 0,
  547. &monitor,
  548. 0 /* dwFlags */ ) ) {
  549. return false;
  550. }
  551. DEVMODE devmode;
  552. devmode.dmSize = sizeof( devmode );
  553. if ( !EnumDisplaySettings( deviceName.c_str(),ENUM_CURRENT_SETTINGS, &devmode ) ) {
  554. return false;
  555. }
  556. common->Printf( "display device: %i\n", deviceNum );
  557. common->Printf( " DeviceName : %s\n", device.DeviceName );
  558. common->Printf( " DeviceString: %s\n", device.DeviceString );
  559. common->Printf( " StateFlags : 0x%x\n", device.StateFlags );
  560. common->Printf( " DeviceID : %s\n", device.DeviceID );
  561. common->Printf( " DeviceKey : %s\n", device.DeviceKey );
  562. common->Printf( " DeviceName : %s\n", monitor.DeviceName );
  563. common->Printf( " DeviceString: %s\n", monitor.DeviceString );
  564. common->Printf( " StateFlags : 0x%x\n", monitor.StateFlags );
  565. common->Printf( " DeviceID : %s\n", monitor.DeviceID );
  566. common->Printf( " DeviceKey : %s\n", monitor.DeviceKey );
  567. common->Printf( " dmPosition.x : %i\n", devmode.dmPosition.x );
  568. common->Printf( " dmPosition.y : %i\n", devmode.dmPosition.y );
  569. common->Printf( " dmBitsPerPel : %i\n", devmode.dmBitsPerPel );
  570. common->Printf( " dmPelsWidth : %i\n", devmode.dmPelsWidth );
  571. common->Printf( " dmPelsHeight : %i\n", devmode.dmPelsHeight );
  572. common->Printf( " dmDisplayFlags : 0x%x\n", devmode.dmDisplayFlags );
  573. common->Printf( " dmDisplayFrequency: %i\n", devmode.dmDisplayFrequency );
  574. x = devmode.dmPosition.x;
  575. y = devmode.dmPosition.y;
  576. width = devmode.dmPelsWidth;
  577. height = devmode.dmPelsHeight;
  578. displayHz = devmode.dmDisplayFrequency;
  579. return true;
  580. }
  581. /*
  582. ====================
  583. DMDFO
  584. ====================
  585. */
  586. static const char * DMDFO( int dmDisplayFixedOutput ) {
  587. switch( dmDisplayFixedOutput ) {
  588. case DMDFO_DEFAULT: return "DMDFO_DEFAULT";
  589. case DMDFO_CENTER: return "DMDFO_CENTER";
  590. case DMDFO_STRETCH: return "DMDFO_STRETCH";
  591. }
  592. return "UNKNOWN";
  593. }
  594. /*
  595. ====================
  596. PrintDevMode
  597. ====================
  598. */
  599. static void PrintDevMode( DEVMODE & devmode ) {
  600. common->Printf( " dmPosition.x : %i\n", devmode.dmPosition.x );
  601. common->Printf( " dmPosition.y : %i\n", devmode.dmPosition.y );
  602. common->Printf( " dmBitsPerPel : %i\n", devmode.dmBitsPerPel );
  603. common->Printf( " dmPelsWidth : %i\n", devmode.dmPelsWidth );
  604. common->Printf( " dmPelsHeight : %i\n", devmode.dmPelsHeight );
  605. common->Printf( " dmDisplayFixedOutput: %s\n", DMDFO( devmode.dmDisplayFixedOutput ) );
  606. common->Printf( " dmDisplayFlags : 0x%x\n", devmode.dmDisplayFlags );
  607. common->Printf( " dmDisplayFrequency : %i\n", devmode.dmDisplayFrequency );
  608. }
  609. /*
  610. ====================
  611. DumpAllDisplayDevices
  612. ====================
  613. */
  614. void DumpAllDisplayDevices() {
  615. common->Printf( "\n" );
  616. for ( int deviceNum = 0 ; ; deviceNum++ ) {
  617. DISPLAY_DEVICE device = {};
  618. device.cb = sizeof( device );
  619. if ( !EnumDisplayDevices(
  620. 0, // lpDevice
  621. deviceNum,
  622. &device,
  623. 0 /* dwFlags */ ) ) {
  624. break;
  625. }
  626. common->Printf( "display device: %i\n", deviceNum );
  627. common->Printf( " DeviceName : %s\n", device.DeviceName );
  628. common->Printf( " DeviceString: %s\n", device.DeviceString );
  629. common->Printf( " StateFlags : 0x%x\n", device.StateFlags );
  630. common->Printf( " DeviceID : %s\n", device.DeviceID );
  631. common->Printf( " DeviceKey : %s\n", device.DeviceKey );
  632. for ( int monitorNum = 0 ; ; monitorNum++ ) {
  633. DISPLAY_DEVICE monitor = {};
  634. monitor.cb = sizeof( monitor );
  635. if ( !EnumDisplayDevices(
  636. device.DeviceName,
  637. monitorNum,
  638. &monitor,
  639. 0 /* dwFlags */ ) ) {
  640. break;
  641. }
  642. common->Printf( " DeviceName : %s\n", monitor.DeviceName );
  643. common->Printf( " DeviceString: %s\n", monitor.DeviceString );
  644. common->Printf( " StateFlags : 0x%x\n", monitor.StateFlags );
  645. common->Printf( " DeviceID : %s\n", monitor.DeviceID );
  646. common->Printf( " DeviceKey : %s\n", monitor.DeviceKey );
  647. DEVMODE currentDevmode = {};
  648. if ( !EnumDisplaySettings( device.DeviceName,ENUM_CURRENT_SETTINGS, &currentDevmode ) ) {
  649. common->Printf( "ERROR: EnumDisplaySettings(ENUM_CURRENT_SETTINGS) failed!\n" );
  650. }
  651. common->Printf( " -------------------\n" );
  652. common->Printf( " ENUM_CURRENT_SETTINGS\n" );
  653. PrintDevMode( currentDevmode );
  654. DEVMODE registryDevmode = {};
  655. if ( !EnumDisplaySettings( device.DeviceName,ENUM_REGISTRY_SETTINGS, &registryDevmode ) ) {
  656. common->Printf( "ERROR: EnumDisplaySettings(ENUM_CURRENT_SETTINGS) failed!\n" );
  657. }
  658. common->Printf( " -------------------\n" );
  659. common->Printf( " ENUM_CURRENT_SETTINGS\n" );
  660. PrintDevMode( registryDevmode );
  661. for ( int modeNum = 0 ; ; modeNum++ ) {
  662. DEVMODE devmode = {};
  663. if ( !EnumDisplaySettings( device.DeviceName,modeNum, &devmode ) ) {
  664. break;
  665. }
  666. if ( devmode.dmBitsPerPel != 32 ) {
  667. continue;
  668. }
  669. if ( devmode.dmDisplayFrequency < 60 ) {
  670. continue;
  671. }
  672. if ( devmode.dmPelsHeight < 720 ) {
  673. continue;
  674. }
  675. common->Printf( " -------------------\n" );
  676. common->Printf( " modeNum : %i\n", modeNum );
  677. PrintDevMode( devmode );
  678. }
  679. }
  680. }
  681. common->Printf( "\n" );
  682. }
  683. /*
  684. ====================
  685. R_GetModeListForDisplay
  686. ====================
  687. */
  688. bool R_GetModeListForDisplay( const int requestedDisplayNum, idList<vidMode_t> & modeList ) {
  689. modeList.Clear();
  690. bool verbose = false;
  691. for ( int displayNum = requestedDisplayNum; ; displayNum++ ) {
  692. DISPLAY_DEVICE device;
  693. device.cb = sizeof( device );
  694. if ( !EnumDisplayDevices(
  695. 0, // lpDevice
  696. displayNum,
  697. &device,
  698. 0 /* dwFlags */ ) ) {
  699. return false;
  700. }
  701. // get the monitor for this display
  702. if ( ! (device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP ) ) {
  703. continue;
  704. }
  705. DISPLAY_DEVICE monitor;
  706. monitor.cb = sizeof( monitor );
  707. if ( !EnumDisplayDevices(
  708. device.DeviceName,
  709. 0,
  710. &monitor,
  711. 0 /* dwFlags */ ) ) {
  712. continue;
  713. }
  714. DEVMODE devmode;
  715. devmode.dmSize = sizeof( devmode );
  716. if ( verbose ) {
  717. common->Printf( "display device: %i\n", displayNum );
  718. common->Printf( " DeviceName : %s\n", device.DeviceName );
  719. common->Printf( " DeviceString: %s\n", device.DeviceString );
  720. common->Printf( " StateFlags : 0x%x\n", device.StateFlags );
  721. common->Printf( " DeviceID : %s\n", device.DeviceID );
  722. common->Printf( " DeviceKey : %s\n", device.DeviceKey );
  723. common->Printf( " DeviceName : %s\n", monitor.DeviceName );
  724. common->Printf( " DeviceString: %s\n", monitor.DeviceString );
  725. common->Printf( " StateFlags : 0x%x\n", monitor.StateFlags );
  726. common->Printf( " DeviceID : %s\n", monitor.DeviceID );
  727. common->Printf( " DeviceKey : %s\n", monitor.DeviceKey );
  728. }
  729. for ( int modeNum = 0 ; ; modeNum++ ) {
  730. if ( !EnumDisplaySettings( device.DeviceName,modeNum, &devmode ) ) {
  731. break;
  732. }
  733. if ( devmode.dmBitsPerPel != 32 ) {
  734. continue;
  735. }
  736. if ( ( devmode.dmDisplayFrequency != 60 ) && ( devmode.dmDisplayFrequency != 120 ) ) {
  737. continue;
  738. }
  739. if ( devmode.dmPelsHeight < 720 ) {
  740. continue;
  741. }
  742. if ( verbose ) {
  743. common->Printf( " -------------------\n" );
  744. common->Printf( " modeNum : %i\n", modeNum );
  745. common->Printf( " dmPosition.x : %i\n", devmode.dmPosition.x );
  746. common->Printf( " dmPosition.y : %i\n", devmode.dmPosition.y );
  747. common->Printf( " dmBitsPerPel : %i\n", devmode.dmBitsPerPel );
  748. common->Printf( " dmPelsWidth : %i\n", devmode.dmPelsWidth );
  749. common->Printf( " dmPelsHeight : %i\n", devmode.dmPelsHeight );
  750. common->Printf( " dmDisplayFixedOutput: %s\n", DMDFO( devmode.dmDisplayFixedOutput ) );
  751. common->Printf( " dmDisplayFlags : 0x%x\n", devmode.dmDisplayFlags );
  752. common->Printf( " dmDisplayFrequency : %i\n", devmode.dmDisplayFrequency );
  753. }
  754. vidMode_t mode;
  755. mode.width = devmode.dmPelsWidth;
  756. mode.height = devmode.dmPelsHeight;
  757. mode.displayHz = devmode.dmDisplayFrequency;
  758. modeList.AddUnique( mode );
  759. }
  760. if ( modeList.Num() > 0 ) {
  761. class idSort_VidMode : public idSort_Quick< vidMode_t, idSort_VidMode > {
  762. public:
  763. int Compare( const vidMode_t & a, const vidMode_t & b ) const {
  764. int wd = a.width - b.width;
  765. int hd = a.height - b.height;
  766. int fd = a.displayHz - b.displayHz;
  767. return ( hd != 0 ) ? hd : ( wd != 0 ) ? wd : fd;
  768. }
  769. };
  770. // sort with lowest resolution first
  771. modeList.SortWithTemplate( idSort_VidMode() );
  772. return true;
  773. }
  774. }
  775. // Never gets here
  776. }
  777. /*
  778. ====================
  779. GLW_GetWindowDimensions
  780. ====================
  781. */
  782. static bool GLW_GetWindowDimensions( const glimpParms_t parms, int &x, int &y, int &w, int &h ) {
  783. //
  784. // compute width and height
  785. //
  786. if ( parms.fullScreen != 0 ) {
  787. if ( parms.fullScreen == -1 ) {
  788. // borderless window at specific location, as for spanning
  789. // multiple monitor outputs
  790. x = parms.x;
  791. y = parms.y;
  792. w = parms.width;
  793. h = parms.height;
  794. } else {
  795. // get the current monitor position and size on the desktop, assuming
  796. // any required ChangeDisplaySettings has already been done
  797. int displayHz = 0;
  798. if ( !GetDisplayCoordinates( parms.fullScreen - 1, x, y, w, h, displayHz ) ) {
  799. return false;
  800. }
  801. }
  802. } else {
  803. RECT r;
  804. // adjust width and height for window border
  805. r.bottom = parms.height;
  806. r.left = 0;
  807. r.top = 0;
  808. r.right = parms.width;
  809. AdjustWindowRect (&r, WINDOW_STYLE|WS_SYSMENU, FALSE);
  810. w = r.right - r.left;
  811. h = r.bottom - r.top;
  812. x = parms.x;
  813. y = parms.y;
  814. }
  815. return true;
  816. }
  817. /*
  818. =======================
  819. GLW_CreateWindow
  820. Responsible for creating the Win32 window.
  821. If fullscreen, it won't have a border
  822. =======================
  823. */
  824. static bool GLW_CreateWindow( glimpParms_t parms ) {
  825. int x, y, w, h;
  826. if ( !GLW_GetWindowDimensions( parms, x, y, w, h ) ) {
  827. return false;
  828. }
  829. int stylebits;
  830. int exstyle;
  831. if ( parms.fullScreen != 0 ) {
  832. exstyle = WS_EX_TOPMOST;
  833. stylebits = WS_POPUP|WS_VISIBLE|WS_SYSMENU;
  834. } else {
  835. exstyle = 0;
  836. stylebits = WINDOW_STYLE|WS_SYSMENU;
  837. }
  838. win32.hWnd = CreateWindowEx (
  839. exstyle,
  840. WIN32_WINDOW_CLASS_NAME,
  841. GAME_NAME,
  842. stylebits,
  843. x, y, w, h,
  844. NULL,
  845. NULL,
  846. win32.hInstance,
  847. NULL);
  848. if ( !win32.hWnd ) {
  849. common->Printf( "^3GLW_CreateWindow() - Couldn't create window^0\n" );
  850. return false;
  851. }
  852. ::SetTimer( win32.hWnd, 0, 100, NULL );
  853. ShowWindow( win32.hWnd, SW_SHOW );
  854. UpdateWindow( win32.hWnd );
  855. common->Printf( "...created window @ %d,%d (%dx%d)\n", x, y, w, h );
  856. // makeCurrent NULL frees the DC, so get another
  857. win32.hDC = GetDC( win32.hWnd );
  858. if ( !win32.hDC ) {
  859. common->Printf( "^3GLW_CreateWindow() - GetDC()failed^0\n" );
  860. return false;
  861. }
  862. // Check to see if we can get a stereo pixel format, even if we aren't going to use it,
  863. // so the menu option can be
  864. if ( GLW_ChoosePixelFormat( win32.hDC, parms.multiSamples, true ) != -1 ) {
  865. glConfig.stereoPixelFormatAvailable = true;
  866. } else {
  867. glConfig.stereoPixelFormatAvailable = false;
  868. }
  869. if ( !GLW_InitDriver( parms ) ) {
  870. ShowWindow( win32.hWnd, SW_HIDE );
  871. DestroyWindow( win32.hWnd );
  872. win32.hWnd = NULL;
  873. return false;
  874. }
  875. SetForegroundWindow( win32.hWnd );
  876. SetFocus( win32.hWnd );
  877. glConfig.isFullscreen = parms.fullScreen;
  878. return true;
  879. }
  880. /*
  881. ===================
  882. PrintCDSError
  883. ===================
  884. */
  885. static void PrintCDSError( int value ) {
  886. switch ( value ) {
  887. case DISP_CHANGE_RESTART:
  888. common->Printf( "restart required\n" );
  889. break;
  890. case DISP_CHANGE_BADPARAM:
  891. common->Printf( "bad param\n" );
  892. break;
  893. case DISP_CHANGE_BADFLAGS:
  894. common->Printf( "bad flags\n" );
  895. break;
  896. case DISP_CHANGE_FAILED:
  897. common->Printf( "DISP_CHANGE_FAILED\n" );
  898. break;
  899. case DISP_CHANGE_BADMODE:
  900. common->Printf( "bad mode\n" );
  901. break;
  902. case DISP_CHANGE_NOTUPDATED:
  903. common->Printf( "not updated\n" );
  904. break;
  905. default:
  906. common->Printf( "unknown error %d\n", value );
  907. break;
  908. }
  909. }
  910. /*
  911. ===================
  912. GLW_ChangeDislaySettingsIfNeeded
  913. Optionally ChangeDisplaySettings to get a different fullscreen resolution.
  914. Default uses the full desktop resolution.
  915. ===================
  916. */
  917. static bool GLW_ChangeDislaySettingsIfNeeded( glimpParms_t parms ) {
  918. // If we had previously changed the display settings on a different monitor,
  919. // go back to standard.
  920. if ( win32.cdsFullscreen != 0 && win32.cdsFullscreen != parms.fullScreen ) {
  921. win32.cdsFullscreen = 0;
  922. ChangeDisplaySettings( 0, 0 );
  923. Sys_Sleep( 1000 ); // Give the driver some time to think about this change
  924. }
  925. // 0 is dragable mode on desktop, -1 is borderless window on desktop
  926. if ( parms.fullScreen <= 0 ) {
  927. return true;
  928. }
  929. // if we are already in the right resolution, don't do a ChangeDisplaySettings
  930. int x, y, width, height, displayHz;
  931. if ( !GetDisplayCoordinates( parms.fullScreen - 1, x, y, width, height, displayHz ) ) {
  932. return false;
  933. }
  934. if ( width == parms.width && height == parms.height && ( displayHz == parms.displayHz || parms.displayHz == 0 ) ) {
  935. return true;
  936. }
  937. DEVMODE dm = {};
  938. dm.dmSize = sizeof( dm );
  939. dm.dmPelsWidth = parms.width;
  940. dm.dmPelsHeight = parms.height;
  941. dm.dmBitsPerPel = 32;
  942. dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
  943. if ( parms.displayHz != 0 ) {
  944. dm.dmDisplayFrequency = parms.displayHz;
  945. dm.dmFields |= DM_DISPLAYFREQUENCY;
  946. }
  947. common->Printf( "...calling CDS: " );
  948. const char * const deviceName = GetDisplayName( parms.fullScreen - 1 );
  949. int cdsRet;
  950. if ( ( cdsRet = ChangeDisplaySettingsEx(
  951. deviceName,
  952. &dm,
  953. NULL,
  954. CDS_FULLSCREEN,
  955. NULL) ) == DISP_CHANGE_SUCCESSFUL ) {
  956. common->Printf( "ok\n" );
  957. win32.cdsFullscreen = parms.fullScreen;
  958. return true;
  959. }
  960. common->Printf( "^3failed^0, " );
  961. PrintCDSError( cdsRet );
  962. return false;
  963. }
  964. /*
  965. ===================
  966. GLimp_Init
  967. This is the platform specific OpenGL initialization function. It
  968. is responsible for loading OpenGL, initializing it,
  969. creating a window of the appropriate size, doing
  970. fullscreen manipulations, etc. Its overall responsibility is
  971. to make sure that a functional OpenGL subsystem is operating
  972. when it returns to the ref.
  973. If there is any failure, the renderer will revert back to safe
  974. parameters and try again.
  975. ===================
  976. */
  977. bool GLimp_Init( glimpParms_t parms ) {
  978. const char *driverName;
  979. HDC hDC;
  980. cmdSystem->AddCommand( "testSwapBuffers", GLimp_TestSwapBuffers, CMD_FL_SYSTEM, "Times swapbuffer options" );
  981. common->Printf( "Initializing OpenGL subsystem with multisamples:%i stereo:%i fullscreen:%i\n",
  982. parms.multiSamples, parms.stereo, parms.fullScreen );
  983. // check our desktop attributes
  984. hDC = GetDC( GetDesktopWindow() );
  985. win32.desktopBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
  986. win32.desktopWidth = GetDeviceCaps( hDC, HORZRES );
  987. win32.desktopHeight = GetDeviceCaps( hDC, VERTRES );
  988. ReleaseDC( GetDesktopWindow(), hDC );
  989. // we can't run in a window unless it is 32 bpp
  990. if ( win32.desktopBitsPixel < 32 && parms.fullScreen <= 0 ) {
  991. common->Printf("^3Windowed mode requires 32 bit desktop depth^0\n");
  992. return false;
  993. }
  994. // save the hardware gamma so it can be
  995. // restored on exit
  996. GLimp_SaveGamma();
  997. // create our window classes if we haven't already
  998. GLW_CreateWindowClasses();
  999. // this will load the dll and set all our qgl* function pointers,
  1000. // but doesn't create a window
  1001. // r_glDriver is only intended for using instrumented OpenGL
  1002. // dlls. Normal users should never have to use it, and it is
  1003. // not archived.
  1004. driverName = r_glDriver.GetString()[0] ? r_glDriver.GetString() : "opengl32";
  1005. if ( !QGL_Init( driverName ) ) {
  1006. common->Printf( "^3GLimp_Init() could not load r_glDriver \"%s\"^0\n", driverName );
  1007. return false;
  1008. }
  1009. // getting the wgl extensions involves creating a fake window to get a context,
  1010. // which is pretty disgusting, and seems to mess with the AGP VAR allocation
  1011. GLW_GetWGLExtensionsWithFakeWindow();
  1012. // Optionally ChangeDisplaySettings to get a different fullscreen resolution.
  1013. if ( !GLW_ChangeDislaySettingsIfNeeded( parms ) ) {
  1014. GLimp_Shutdown();
  1015. return false;
  1016. }
  1017. // try to create a window with the correct pixel format
  1018. // and init the renderer context
  1019. if ( !GLW_CreateWindow( parms ) ) {
  1020. GLimp_Shutdown();
  1021. return false;
  1022. }
  1023. glConfig.isFullscreen = parms.fullScreen;
  1024. glConfig.isStereoPixelFormat = parms.stereo;
  1025. glConfig.nativeScreenWidth = parms.width;
  1026. glConfig.nativeScreenHeight = parms.height;
  1027. glConfig.multisamples = parms.multiSamples;
  1028. glConfig.pixelAspect = 1.0f; // FIXME: some monitor modes may be distorted
  1029. // should side-by-side stereo modes be consider aspect 0.5?
  1030. // get the screen size, which may not be reliable...
  1031. // If we use the windowDC, I get my 30" monitor, even though the window is
  1032. // on a 27" monitor, so get a dedicated DC for the full screen device name.
  1033. const idStr deviceName = GetDeviceName( Max( 0, parms.fullScreen - 1 ) );
  1034. HDC deviceDC = CreateDC( deviceName.c_str(), deviceName.c_str(), NULL, NULL );
  1035. const int mmWide = GetDeviceCaps( win32.hDC, HORZSIZE );
  1036. DeleteDC( deviceDC );
  1037. if ( mmWide == 0 ) {
  1038. glConfig.physicalScreenWidthInCentimeters = 100.0f;
  1039. } else {
  1040. glConfig.physicalScreenWidthInCentimeters = 0.1f * mmWide;
  1041. }
  1042. // wglSwapinterval, etc
  1043. GLW_CheckWGLExtensions( win32.hDC );
  1044. // check logging
  1045. GLimp_EnableLogging( ( r_logFile.GetInteger() != 0 ) );
  1046. return true;
  1047. }
  1048. /*
  1049. ===================
  1050. GLimp_SetScreenParms
  1051. Sets up the screen based on passed parms..
  1052. ===================
  1053. */
  1054. bool GLimp_SetScreenParms( glimpParms_t parms ) {
  1055. // Optionally ChangeDisplaySettings to get a different fullscreen resolution.
  1056. if ( !GLW_ChangeDislaySettingsIfNeeded( parms ) ) {
  1057. return false;
  1058. }
  1059. int x, y, w, h;
  1060. if ( !GLW_GetWindowDimensions( parms, x, y, w, h ) ) {
  1061. return false;
  1062. }
  1063. int exstyle;
  1064. int stylebits;
  1065. if ( parms.fullScreen ) {
  1066. exstyle = WS_EX_TOPMOST;
  1067. stylebits = WS_POPUP|WS_VISIBLE|WS_SYSMENU;
  1068. } else {
  1069. exstyle = 0;
  1070. stylebits = WINDOW_STYLE|WS_SYSMENU;
  1071. }
  1072. SetWindowLong( win32.hWnd, GWL_STYLE, stylebits );
  1073. SetWindowLong( win32.hWnd, GWL_EXSTYLE, exstyle );
  1074. SetWindowPos( win32.hWnd, parms.fullScreen ? HWND_TOPMOST : HWND_NOTOPMOST, x, y, w, h, SWP_SHOWWINDOW );
  1075. glConfig.isFullscreen = parms.fullScreen;
  1076. glConfig.pixelAspect = 1.0f; // FIXME: some monitor modes may be distorted
  1077. glConfig.isFullscreen = parms.fullScreen;
  1078. glConfig.nativeScreenWidth = parms.width;
  1079. glConfig.nativeScreenHeight = parms.height;
  1080. return true;
  1081. }
  1082. /*
  1083. ===================
  1084. GLimp_Shutdown
  1085. This routine does all OS specific shutdown procedures for the OpenGL
  1086. subsystem.
  1087. ===================
  1088. */
  1089. void GLimp_Shutdown() {
  1090. const char *success[] = { "failed", "success" };
  1091. int retVal;
  1092. common->Printf( "Shutting down OpenGL subsystem\n" );
  1093. // set current context to NULL
  1094. if ( qwglMakeCurrent ) {
  1095. retVal = qwglMakeCurrent( NULL, NULL ) != 0;
  1096. common->Printf( "...wglMakeCurrent( NULL, NULL ): %s\n", success[retVal] );
  1097. }
  1098. // delete HGLRC
  1099. if ( win32.hGLRC ) {
  1100. retVal = qwglDeleteContext( win32.hGLRC ) != 0;
  1101. common->Printf( "...deleting GL context: %s\n", success[retVal] );
  1102. win32.hGLRC = NULL;
  1103. }
  1104. // release DC
  1105. if ( win32.hDC ) {
  1106. retVal = ReleaseDC( win32.hWnd, win32.hDC ) != 0;
  1107. common->Printf( "...releasing DC: %s\n", success[retVal] );
  1108. win32.hDC = NULL;
  1109. }
  1110. // destroy window
  1111. if ( win32.hWnd ) {
  1112. common->Printf( "...destroying window\n" );
  1113. ShowWindow( win32.hWnd, SW_HIDE );
  1114. DestroyWindow( win32.hWnd );
  1115. win32.hWnd = NULL;
  1116. }
  1117. // reset display settings
  1118. if ( win32.cdsFullscreen ) {
  1119. common->Printf( "...resetting display\n" );
  1120. ChangeDisplaySettings( 0, 0 );
  1121. win32.cdsFullscreen = 0;
  1122. }
  1123. // close the thread so the handle doesn't dangle
  1124. if ( win32.renderThreadHandle ) {
  1125. common->Printf( "...closing smp thread\n" );
  1126. CloseHandle( win32.renderThreadHandle );
  1127. win32.renderThreadHandle = NULL;
  1128. }
  1129. // restore gamma
  1130. GLimp_RestoreGamma();
  1131. // shutdown QGL subsystem
  1132. QGL_Shutdown();
  1133. }
  1134. /*
  1135. =====================
  1136. GLimp_SwapBuffers
  1137. =====================
  1138. */
  1139. void GLimp_SwapBuffers() {
  1140. if ( r_swapInterval.IsModified() ) {
  1141. r_swapInterval.ClearModified();
  1142. int interval = 0;
  1143. if ( r_swapInterval.GetInteger() == 1 ) {
  1144. interval = ( glConfig.swapControlTearAvailable ) ? -1 : 1;
  1145. } else if ( r_swapInterval.GetInteger() == 2 ) {
  1146. interval = 1;
  1147. }
  1148. if ( wglSwapIntervalEXT ) {
  1149. wglSwapIntervalEXT( interval );
  1150. }
  1151. }
  1152. qwglSwapBuffers( win32.hDC );
  1153. }
  1154. /*
  1155. ===========================================================
  1156. SMP acceleration
  1157. ===========================================================
  1158. */
  1159. /*
  1160. ===================
  1161. GLimp_ActivateContext
  1162. ===================
  1163. */
  1164. void GLimp_ActivateContext() {
  1165. if ( !qwglMakeCurrent( win32.hDC, win32.hGLRC ) ) {
  1166. win32.wglErrors++;
  1167. }
  1168. }
  1169. /*
  1170. ===================
  1171. GLimp_DeactivateContext
  1172. ===================
  1173. */
  1174. void GLimp_DeactivateContext() {
  1175. qglFinish();
  1176. if ( !qwglMakeCurrent( win32.hDC, NULL ) ) {
  1177. win32.wglErrors++;
  1178. }
  1179. }
  1180. /*
  1181. ===================
  1182. GLimp_RenderThreadWrapper
  1183. ===================
  1184. */
  1185. static void GLimp_RenderThreadWrapper() {
  1186. win32.glimpRenderThread();
  1187. // unbind the context before we die
  1188. qwglMakeCurrent( win32.hDC, NULL );
  1189. }
  1190. /*
  1191. =======================
  1192. GLimp_SpawnRenderThread
  1193. Returns false if the system only has a single processor
  1194. =======================
  1195. */
  1196. bool GLimp_SpawnRenderThread( void (*function)() ) {
  1197. SYSTEM_INFO info;
  1198. // check number of processors
  1199. GetSystemInfo( &info );
  1200. if ( info.dwNumberOfProcessors < 2 ) {
  1201. return false;
  1202. }
  1203. // create the IPC elements
  1204. win32.renderCommandsEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  1205. win32.renderCompletedEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  1206. win32.renderActiveEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  1207. win32.glimpRenderThread = function;
  1208. win32.renderThreadHandle = CreateThread(
  1209. NULL, // LPSECURITY_ATTRIBUTES lpsa,
  1210. 0, // DWORD cbStack,
  1211. (LPTHREAD_START_ROUTINE)GLimp_RenderThreadWrapper, // LPTHREAD_START_ROUTINE lpStartAddr,
  1212. 0, // LPVOID lpvThreadParm,
  1213. 0, // DWORD fdwCreate,
  1214. &win32.renderThreadId );
  1215. if ( !win32.renderThreadHandle ) {
  1216. common->Error( "GLimp_SpawnRenderThread: failed" );
  1217. }
  1218. SetThreadPriority( win32.renderThreadHandle, THREAD_PRIORITY_ABOVE_NORMAL );
  1219. #if 0
  1220. // make sure they always run on different processors
  1221. SetThreadAffinityMask( GetCurrentThread, 1 );
  1222. SetThreadAffinityMask( win32.renderThreadHandle, 2 );
  1223. #endif
  1224. return true;
  1225. }
  1226. //#define DEBUG_PRINTS
  1227. /*
  1228. ===================
  1229. GLimp_BackEndSleep
  1230. ===================
  1231. */
  1232. void *GLimp_BackEndSleep() {
  1233. void *data;
  1234. #ifdef DEBUG_PRINTS
  1235. OutputDebugString( "-->GLimp_BackEndSleep\n" );
  1236. #endif
  1237. ResetEvent( win32.renderActiveEvent );
  1238. // after this, the front end can exit GLimp_FrontEndSleep
  1239. SetEvent( win32.renderCompletedEvent );
  1240. WaitForSingleObject( win32.renderCommandsEvent, INFINITE );
  1241. ResetEvent( win32.renderCompletedEvent );
  1242. ResetEvent( win32.renderCommandsEvent );
  1243. data = win32.smpData;
  1244. // after this, the main thread can exit GLimp_WakeRenderer
  1245. SetEvent( win32.renderActiveEvent );
  1246. #ifdef DEBUG_PRINTS
  1247. OutputDebugString( "<--GLimp_BackEndSleep\n" );
  1248. #endif
  1249. return data;
  1250. }
  1251. /*
  1252. ===================
  1253. GLimp_FrontEndSleep
  1254. ===================
  1255. */
  1256. void GLimp_FrontEndSleep() {
  1257. #ifdef DEBUG_PRINTS
  1258. OutputDebugString( "-->GLimp_FrontEndSleep\n" );
  1259. #endif
  1260. WaitForSingleObject( win32.renderCompletedEvent, INFINITE );
  1261. #ifdef DEBUG_PRINTS
  1262. OutputDebugString( "<--GLimp_FrontEndSleep\n" );
  1263. #endif
  1264. }
  1265. volatile bool renderThreadActive;
  1266. /*
  1267. ===================
  1268. GLimp_WakeBackEnd
  1269. ===================
  1270. */
  1271. void GLimp_WakeBackEnd( void *data ) {
  1272. int r;
  1273. #ifdef DEBUG_PRINTS
  1274. OutputDebugString( "-->GLimp_WakeBackEnd\n" );
  1275. #endif
  1276. win32.smpData = data;
  1277. if ( renderThreadActive ) {
  1278. common->FatalError( "GLimp_WakeBackEnd: already active" );
  1279. }
  1280. r = WaitForSingleObject( win32.renderActiveEvent, 0 );
  1281. if ( r == WAIT_OBJECT_0 ) {
  1282. common->FatalError( "GLimp_WakeBackEnd: already signaled" );
  1283. }
  1284. r = WaitForSingleObject( win32.renderCommandsEvent, 0 );
  1285. if ( r == WAIT_OBJECT_0 ) {
  1286. common->FatalError( "GLimp_WakeBackEnd: commands already signaled" );
  1287. }
  1288. // after this, the renderer can continue through GLimp_RendererSleep
  1289. SetEvent( win32.renderCommandsEvent );
  1290. r = WaitForSingleObject( win32.renderActiveEvent, 5000 );
  1291. if ( r == WAIT_TIMEOUT ) {
  1292. common->FatalError( "GLimp_WakeBackEnd: WAIT_TIMEOUT" );
  1293. }
  1294. #ifdef DEBUG_PRINTS
  1295. OutputDebugString( "<--GLimp_WakeBackEnd\n" );
  1296. #endif
  1297. }
  1298. /*
  1299. ===================
  1300. GLimp_ExtensionPointer
  1301. Returns a function pointer for an OpenGL extension entry point
  1302. ===================
  1303. */
  1304. GLExtension_t GLimp_ExtensionPointer( const char *name ) {
  1305. void (*proc)();
  1306. proc = (GLExtension_t)qwglGetProcAddress( name );
  1307. if ( !proc ) {
  1308. common->Printf( "Couldn't find proc address for: %s\n", name );
  1309. }
  1310. return proc;
  1311. }