gl_backend.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  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. #pragma hdrstop
  21. #include "../../idlib/precompiled.h"
  22. #include "../tr_local.h"
  23. #include "../../framework/Common_local.h"
  24. idCVar r_drawFlickerBox( "r_drawFlickerBox", "0", CVAR_RENDERER | CVAR_BOOL, "visual test for dropping frames" );
  25. idCVar stereoRender_warp( "stereoRender_warp", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "use the optical warping renderprog instead of stereoDeGhost" );
  26. idCVar stereoRender_warpStrength( "stereoRender_warpStrength", "1.45", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "amount of pre-distortion" );
  27. idCVar stereoRender_warpCenterX( "stereoRender_warpCenterX", "0.5", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "center for left eye, right eye will be 1.0 - this" );
  28. idCVar stereoRender_warpCenterY( "stereoRender_warpCenterY", "0.5", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "center for both eyes" );
  29. idCVar stereoRender_warpParmZ( "stereoRender_warpParmZ", "0", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "development parm" );
  30. idCVar stereoRender_warpParmW( "stereoRender_warpParmW", "0", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "development parm" );
  31. idCVar stereoRender_warpTargetFraction( "stereoRender_warpTargetFraction", "1.0", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "fraction of half-width the through-lens view covers" );
  32. idCVar r_showSwapBuffers( "r_showSwapBuffers", "0", CVAR_BOOL, "Show timings from GL_BlockingSwapBuffers" );
  33. idCVar r_syncEveryFrame( "r_syncEveryFrame", "1", CVAR_BOOL, "Don't let the GPU buffer execution past swapbuffers" );
  34. static int swapIndex; // 0 or 1 into renderSync
  35. static GLsync renderSync[2];
  36. void GLimp_SwapBuffers();
  37. void RB_SetMVP( const idRenderMatrix & mvp );
  38. /*
  39. ============================================================================
  40. RENDER BACK END THREAD FUNCTIONS
  41. ============================================================================
  42. */
  43. /*
  44. =============
  45. RB_DrawFlickerBox
  46. =============
  47. */
  48. static void RB_DrawFlickerBox() {
  49. if ( !r_drawFlickerBox.GetBool() ) {
  50. return;
  51. }
  52. if ( tr.frameCount & 1 ) {
  53. qglClearColor( 1, 0, 0, 1 );
  54. } else {
  55. qglClearColor( 0, 1, 0, 1 );
  56. }
  57. qglScissor( 0, 0, 256, 256 );
  58. qglClear( GL_COLOR_BUFFER_BIT );
  59. }
  60. /*
  61. =============
  62. RB_SetBuffer
  63. =============
  64. */
  65. static void RB_SetBuffer( const void *data ) {
  66. // see which draw buffer we want to render the frame to
  67. const setBufferCommand_t * cmd = (const setBufferCommand_t *)data;
  68. RENDERLOG_PRINTF( "---------- RB_SetBuffer ---------- to buffer # %d\n", cmd->buffer );
  69. GL_Scissor( 0, 0, tr.GetWidth(), tr.GetHeight() );
  70. // clear screen for debugging
  71. // automatically enable this with several other debug tools
  72. // that might leave unrendered portions of the screen
  73. if ( r_clear.GetFloat() || idStr::Length( r_clear.GetString() ) != 1 || r_singleArea.GetBool() || r_showOverDraw.GetBool() ) {
  74. float c[3];
  75. if ( sscanf( r_clear.GetString(), "%f %f %f", &c[0], &c[1], &c[2] ) == 3 ) {
  76. GL_Clear( true, false, false, 0, c[0], c[1], c[2], 1.0f );
  77. } else if ( r_clear.GetInteger() == 2 ) {
  78. GL_Clear( true, false, false, 0, 0.0f, 0.0f, 0.0f, 1.0f );
  79. } else if ( r_showOverDraw.GetBool() ) {
  80. GL_Clear( true, false, false, 0, 1.0f, 1.0f, 1.0f, 1.0f );
  81. } else {
  82. GL_Clear( true, false, false, 0, 0.4f, 0.0f, 0.25f, 1.0f );
  83. }
  84. }
  85. }
  86. /*
  87. =============
  88. GL_BlockingSwapBuffers
  89. We want to exit this with the GPU idle, right at vsync
  90. =============
  91. */
  92. const void GL_BlockingSwapBuffers() {
  93. RENDERLOG_PRINTF( "***************** GL_BlockingSwapBuffers *****************\n\n\n" );
  94. const int beforeFinish = Sys_Milliseconds();
  95. if ( !glConfig.syncAvailable ) {
  96. glFinish();
  97. }
  98. const int beforeSwap = Sys_Milliseconds();
  99. if ( r_showSwapBuffers.GetBool() && beforeSwap - beforeFinish > 1 ) {
  100. common->Printf( "%i msec to glFinish\n", beforeSwap - beforeFinish );
  101. }
  102. GLimp_SwapBuffers();
  103. const int beforeFence = Sys_Milliseconds();
  104. if ( r_showSwapBuffers.GetBool() && beforeFence - beforeSwap > 1 ) {
  105. common->Printf( "%i msec to swapBuffers\n", beforeFence - beforeSwap );
  106. }
  107. if ( glConfig.syncAvailable ) {
  108. swapIndex ^= 1;
  109. if ( qglIsSync( renderSync[swapIndex] ) ) {
  110. qglDeleteSync( renderSync[swapIndex] );
  111. }
  112. // draw something tiny to ensure the sync is after the swap
  113. const int start = Sys_Milliseconds();
  114. qglScissor( 0, 0, 1, 1 );
  115. qglEnable( GL_SCISSOR_TEST );
  116. qglClear( GL_COLOR_BUFFER_BIT );
  117. renderSync[swapIndex] = qglFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 );
  118. const int end = Sys_Milliseconds();
  119. if ( r_showSwapBuffers.GetBool() && end - start > 1 ) {
  120. common->Printf( "%i msec to start fence\n", end - start );
  121. }
  122. GLsync syncToWaitOn;
  123. if ( r_syncEveryFrame.GetBool() ) {
  124. syncToWaitOn = renderSync[swapIndex];
  125. } else {
  126. syncToWaitOn = renderSync[!swapIndex];
  127. }
  128. if ( qglIsSync( syncToWaitOn ) ) {
  129. for ( GLenum r = GL_TIMEOUT_EXPIRED; r == GL_TIMEOUT_EXPIRED; ) {
  130. r = qglClientWaitSync( syncToWaitOn, GL_SYNC_FLUSH_COMMANDS_BIT, 1000 * 1000 );
  131. }
  132. }
  133. }
  134. const int afterFence = Sys_Milliseconds();
  135. if ( r_showSwapBuffers.GetBool() && afterFence - beforeFence > 1 ) {
  136. common->Printf( "%i msec to wait on fence\n", afterFence - beforeFence );
  137. }
  138. const int64 exitBlockTime = Sys_Microseconds();
  139. static int64 prevBlockTime;
  140. if ( r_showSwapBuffers.GetBool() && prevBlockTime ) {
  141. const int delta = (int) ( exitBlockTime - prevBlockTime );
  142. common->Printf( "blockToBlock: %i\n", delta );
  143. }
  144. prevBlockTime = exitBlockTime;
  145. }
  146. /*
  147. ====================
  148. R_MakeStereoRenderImage
  149. ====================
  150. */
  151. static void R_MakeStereoRenderImage( idImage *image ) {
  152. idImageOpts opts;
  153. opts.width = renderSystem->GetWidth();
  154. opts.height = renderSystem->GetHeight();
  155. opts.numLevels = 1;
  156. opts.format = FMT_RGBA8;
  157. image->AllocImage( opts, TF_LINEAR, TR_CLAMP );
  158. }
  159. /*
  160. ====================
  161. RB_StereoRenderExecuteBackEndCommands
  162. Renders the draw list twice, with slight modifications for left eye / right eye
  163. ====================
  164. */
  165. void RB_StereoRenderExecuteBackEndCommands( const emptyCommand_t * const allCmds ) {
  166. uint64 backEndStartTime = Sys_Microseconds();
  167. // If we are in a monoscopic context, this draws to the only buffer, and is
  168. // the same as GL_BACK. In a quad-buffer stereo context, this is necessary
  169. // to prevent GL from forcing the rendering to go to both BACK_LEFT and
  170. // BACK_RIGHT at a performance penalty.
  171. // To allow stereo deghost processing, the views have to be copied to separate
  172. // textures anyway, so there isn't any benefit to rendering to BACK_RIGHT for
  173. // that eye.
  174. qglDrawBuffer( GL_BACK_LEFT );
  175. // create the stereoRenderImage if we haven't already
  176. static idImage * stereoRenderImages[2];
  177. for ( int i = 0; i < 2; i++ ) {
  178. if ( stereoRenderImages[i] == NULL ) {
  179. stereoRenderImages[i] = globalImages->ImageFromFunction( va("_stereoRender%i",i), R_MakeStereoRenderImage );
  180. }
  181. // resize the stereo render image if the main window has changed size
  182. if ( stereoRenderImages[i]->GetUploadWidth() != renderSystem->GetWidth() ||
  183. stereoRenderImages[i]->GetUploadHeight() != renderSystem->GetHeight() ) {
  184. stereoRenderImages[i]->Resize( renderSystem->GetWidth(), renderSystem->GetHeight() );
  185. }
  186. }
  187. // In stereoRender mode, the front end has generated two RC_DRAW_VIEW commands
  188. // with slightly different origins for each eye.
  189. // TODO: only do the copy after the final view has been rendered, not mirror subviews?
  190. // Render the 3D draw views from the screen origin so all the screen relative
  191. // texture mapping works properly, then copy the portion we are going to use
  192. // off to a texture.
  193. bool foundEye[2] = { false, false };
  194. for ( int stereoEye = 1; stereoEye >= -1; stereoEye -= 2 ) {
  195. // set up the target texture we will draw to
  196. const int targetEye = ( stereoEye == 1 ) ? 1 : 0;
  197. // Set the back end into a known default state to fix any stale render state issues
  198. GL_SetDefaultState();
  199. renderProgManager.Unbind();
  200. renderProgManager.ZeroUniforms();
  201. for ( const emptyCommand_t * cmds = allCmds; cmds != NULL; cmds = (const emptyCommand_t *)cmds->next ) {
  202. switch ( cmds->commandId ) {
  203. case RC_NOP:
  204. break;
  205. case RC_DRAW_VIEW_GUI:
  206. case RC_DRAW_VIEW_3D:
  207. {
  208. const drawSurfsCommand_t * const dsc = (const drawSurfsCommand_t *)cmds;
  209. const viewDef_t & eyeViewDef = *dsc->viewDef;
  210. if ( eyeViewDef.renderView.viewEyeBuffer && eyeViewDef.renderView.viewEyeBuffer != stereoEye ) {
  211. // this is the render view for the other eye
  212. continue;
  213. }
  214. foundEye[ targetEye ] = true;
  215. RB_DrawView( dsc, stereoEye );
  216. if ( cmds->commandId == RC_DRAW_VIEW_GUI ) {
  217. }
  218. }
  219. break;
  220. case RC_SET_BUFFER:
  221. RB_SetBuffer( cmds );
  222. break;
  223. case RC_COPY_RENDER:
  224. RB_CopyRender( cmds );
  225. break;
  226. case RC_POST_PROCESS:
  227. {
  228. postProcessCommand_t * cmd = (postProcessCommand_t *)cmds;
  229. if ( cmd->viewDef->renderView.viewEyeBuffer != stereoEye ) {
  230. break;
  231. }
  232. RB_PostProcess( cmds );
  233. }
  234. break;
  235. default:
  236. common->Error( "RB_ExecuteBackEndCommands: bad commandId" );
  237. break;
  238. }
  239. }
  240. // copy to the target
  241. stereoRenderImages[ targetEye ]->CopyFramebuffer( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() );
  242. }
  243. // perform the final compositing / warping / deghosting to the actual framebuffer(s)
  244. assert( foundEye[0] && foundEye[1] );
  245. GL_SetDefaultState();
  246. RB_SetMVP( renderMatrix_identity );
  247. // If we are in quad-buffer pixel format but testing another 3D mode,
  248. // make sure we draw to both eyes. This is likely to be sub-optimal
  249. // performance on most cards and drivers, but it is better than getting
  250. // a confusing, half-ghosted view.
  251. if ( renderSystem->GetStereo3DMode() != STEREO3D_QUAD_BUFFER ) {
  252. glDrawBuffer( GL_BACK );
  253. }
  254. GL_State( GLS_DEPTHFUNC_ALWAYS );
  255. GL_Cull( CT_TWO_SIDED );
  256. // We just want to do a quad pass - so make sure we disable any texgen and
  257. // set the texture matrix to the identity so we don't get anomalies from
  258. // any stale uniform data being present from a previous draw call
  259. const float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
  260. const float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
  261. renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_S, texS );
  262. renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_T, texT );
  263. // disable any texgen
  264. const float texGenEnabled[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  265. renderProgManager.SetRenderParm( RENDERPARM_TEXGEN_0_ENABLED, texGenEnabled );
  266. renderProgManager.BindShader_Texture();
  267. GL_Color( 1, 1, 1, 1 );
  268. switch( renderSystem->GetStereo3DMode() ) {
  269. case STEREO3D_QUAD_BUFFER:
  270. glDrawBuffer( GL_BACK_RIGHT );
  271. GL_SelectTexture( 0 );
  272. stereoRenderImages[1]->Bind();
  273. GL_SelectTexture( 1 );
  274. stereoRenderImages[0]->Bind();
  275. RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
  276. glDrawBuffer( GL_BACK_LEFT );
  277. GL_SelectTexture( 1 );
  278. stereoRenderImages[1]->Bind();
  279. GL_SelectTexture( 0 );
  280. stereoRenderImages[0]->Bind();
  281. RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
  282. break;
  283. case STEREO3D_HDMI_720:
  284. // HDMI 720P 3D
  285. GL_SelectTexture( 0 );
  286. stereoRenderImages[1]->Bind();
  287. GL_SelectTexture( 1 );
  288. stereoRenderImages[0]->Bind();
  289. GL_ViewportAndScissor( 0, 0, 1280, 720 );
  290. RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
  291. GL_SelectTexture( 0 );
  292. stereoRenderImages[0]->Bind();
  293. GL_SelectTexture( 1 );
  294. stereoRenderImages[1]->Bind();
  295. GL_ViewportAndScissor( 0, 750, 1280, 720 );
  296. RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
  297. // force the HDMI 720P 3D guard band to a constant color
  298. glScissor( 0, 720, 1280, 30 );
  299. glClear( GL_COLOR_BUFFER_BIT );
  300. break;
  301. default:
  302. case STEREO3D_SIDE_BY_SIDE:
  303. if ( stereoRender_warp.GetBool() ) {
  304. // this is the Rift warp
  305. // renderSystem->GetWidth() / GetHeight() have returned equal values (640 for initial Rift)
  306. // and we are going to warp them onto a symetric square region of each half of the screen
  307. renderProgManager.BindShader_StereoWarp();
  308. // clear the entire screen to black
  309. // we could be smart and only clear the areas we aren't going to draw on, but
  310. // clears are fast...
  311. glScissor ( 0, 0, glConfig.nativeScreenWidth, glConfig.nativeScreenHeight );
  312. glClearColor( 0, 0, 0, 0 );
  313. glClear( GL_COLOR_BUFFER_BIT );
  314. // the size of the box that will get the warped pixels
  315. // With the 7" displays, this will be less than half the screen width
  316. const int pixelDimensions = ( glConfig.nativeScreenWidth >> 1 ) * stereoRender_warpTargetFraction.GetFloat();
  317. // Always scissor to the half-screen boundary, but the viewports
  318. // might cross that boundary if the lenses can be adjusted closer
  319. // together.
  320. glViewport( ( glConfig.nativeScreenWidth >> 1 ) - pixelDimensions,
  321. ( glConfig.nativeScreenHeight >> 1 ) - ( pixelDimensions >> 1 ),
  322. pixelDimensions, pixelDimensions );
  323. glScissor ( 0, 0, glConfig.nativeScreenWidth >> 1, glConfig.nativeScreenHeight );
  324. idVec4 color( stereoRender_warpCenterX.GetFloat(), stereoRender_warpCenterY.GetFloat(), stereoRender_warpParmZ.GetFloat(), stereoRender_warpParmW.GetFloat() );
  325. // don't use GL_Color(), because we don't want to clamp
  326. renderProgManager.SetRenderParm( RENDERPARM_COLOR, color.ToFloatPtr() );
  327. GL_SelectTexture( 0 );
  328. stereoRenderImages[0]->Bind();
  329. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
  330. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
  331. RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
  332. idVec4 color2( stereoRender_warpCenterX.GetFloat(), stereoRender_warpCenterY.GetFloat(), stereoRender_warpParmZ.GetFloat(), stereoRender_warpParmW.GetFloat() );
  333. // don't use GL_Color(), because we don't want to clamp
  334. renderProgManager.SetRenderParm( RENDERPARM_COLOR, color2.ToFloatPtr() );
  335. glViewport( ( glConfig.nativeScreenWidth >> 1 ),
  336. ( glConfig.nativeScreenHeight >> 1 ) - ( pixelDimensions >> 1 ),
  337. pixelDimensions, pixelDimensions );
  338. glScissor ( glConfig.nativeScreenWidth >> 1, 0, glConfig.nativeScreenWidth >> 1, glConfig.nativeScreenHeight );
  339. GL_SelectTexture( 0 );
  340. stereoRenderImages[1]->Bind();
  341. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
  342. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
  343. RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
  344. break;
  345. }
  346. // a non-warped side-by-side-uncompressed (dual input cable) is rendered
  347. // just like STEREO3D_SIDE_BY_SIDE_COMPRESSED, so fall through.
  348. case STEREO3D_SIDE_BY_SIDE_COMPRESSED:
  349. GL_SelectTexture( 0 );
  350. stereoRenderImages[0]->Bind();
  351. GL_SelectTexture( 1 );
  352. stereoRenderImages[1]->Bind();
  353. GL_ViewportAndScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() );
  354. RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
  355. GL_SelectTexture( 0 );
  356. stereoRenderImages[1]->Bind();
  357. GL_SelectTexture( 1 );
  358. stereoRenderImages[0]->Bind();
  359. GL_ViewportAndScissor( renderSystem->GetWidth(), 0, renderSystem->GetWidth(), renderSystem->GetHeight() );
  360. RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
  361. break;
  362. case STEREO3D_TOP_AND_BOTTOM_COMPRESSED:
  363. GL_SelectTexture( 1 );
  364. stereoRenderImages[0]->Bind();
  365. GL_SelectTexture( 0 );
  366. stereoRenderImages[1]->Bind();
  367. GL_ViewportAndScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() );
  368. RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
  369. GL_SelectTexture( 1 );
  370. stereoRenderImages[1]->Bind();
  371. GL_SelectTexture( 0 );
  372. stereoRenderImages[0]->Bind();
  373. GL_ViewportAndScissor( 0, renderSystem->GetHeight(), renderSystem->GetWidth(), renderSystem->GetHeight() );
  374. RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
  375. break;
  376. case STEREO3D_INTERLACED:
  377. // every other scanline
  378. GL_SelectTexture( 0 );
  379. stereoRenderImages[0]->Bind();
  380. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  381. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  382. GL_SelectTexture( 1 );
  383. stereoRenderImages[1]->Bind();
  384. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  385. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  386. GL_ViewportAndScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight()*2 );
  387. renderProgManager.BindShader_StereoInterlace();
  388. RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
  389. GL_SelectTexture( 0 );
  390. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  391. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  392. GL_SelectTexture( 1 );
  393. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  394. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  395. break;
  396. }
  397. // debug tool
  398. RB_DrawFlickerBox();
  399. // make sure the drawing is actually started
  400. qglFlush();
  401. // we may choose to sync to the swapbuffers before the next frame
  402. // stop rendering on this thread
  403. uint64 backEndFinishTime = Sys_Microseconds();
  404. backEnd.pc.totalMicroSec = backEndFinishTime - backEndStartTime;
  405. }
  406. /*
  407. ====================
  408. RB_ExecuteBackEndCommands
  409. This function will be called syncronously if running without
  410. smp extensions, or asyncronously by another thread.
  411. ====================
  412. */
  413. void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds ) {
  414. // r_debugRenderToTexture
  415. int c_draw3d = 0;
  416. int c_draw2d = 0;
  417. int c_setBuffers = 0;
  418. int c_copyRenders = 0;
  419. resolutionScale.SetCurrentGPUFrameTime( commonLocal.GetRendererGPUMicroseconds() );
  420. renderLog.StartFrame();
  421. if ( cmds->commandId == RC_NOP && !cmds->next ) {
  422. return;
  423. }
  424. if ( renderSystem->GetStereo3DMode() != STEREO3D_OFF ) {
  425. RB_StereoRenderExecuteBackEndCommands( cmds );
  426. renderLog.EndFrame();
  427. return;
  428. }
  429. uint64 backEndStartTime = Sys_Microseconds();
  430. // needed for editor rendering
  431. GL_SetDefaultState();
  432. // If we have a stereo pixel format, this will draw to both
  433. // the back left and back right buffers, which will have a
  434. // performance penalty.
  435. qglDrawBuffer( GL_BACK );
  436. for ( ; cmds != NULL; cmds = (const emptyCommand_t *)cmds->next ) {
  437. switch ( cmds->commandId ) {
  438. case RC_NOP:
  439. break;
  440. case RC_DRAW_VIEW_3D:
  441. case RC_DRAW_VIEW_GUI:
  442. RB_DrawView( cmds, 0 );
  443. if ( ((const drawSurfsCommand_t *)cmds)->viewDef->viewEntitys ) {
  444. c_draw3d++;
  445. } else {
  446. c_draw2d++;
  447. }
  448. break;
  449. case RC_SET_BUFFER:
  450. c_setBuffers++;
  451. break;
  452. case RC_COPY_RENDER:
  453. RB_CopyRender( cmds );
  454. c_copyRenders++;
  455. break;
  456. case RC_POST_PROCESS:
  457. RB_PostProcess( cmds );
  458. break;
  459. default:
  460. common->Error( "RB_ExecuteBackEndCommands: bad commandId" );
  461. break;
  462. }
  463. }
  464. RB_DrawFlickerBox();
  465. // Fix for the steam overlay not showing up while in game without Shell/Debug/Console/Menu also rendering
  466. qglColorMask( 1, 1, 1, 1 );
  467. qglFlush();
  468. // stop rendering on this thread
  469. uint64 backEndFinishTime = Sys_Microseconds();
  470. backEnd.pc.totalMicroSec = backEndFinishTime - backEndStartTime;
  471. if ( r_debugRenderToTexture.GetInteger() == 1 ) {
  472. common->Printf( "3d: %i, 2d: %i, SetBuf: %i, CpyRenders: %i, CpyFrameBuf: %i\n", c_draw3d, c_draw2d, c_setBuffers, c_copyRenders, backEnd.pc.c_copyFrameBuffer );
  473. backEnd.pc.c_copyFrameBuffer = 0;
  474. }
  475. renderLog.EndFrame();
  476. }