DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

RenderSystem.cpp (27017B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition 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.
     13 
     14 Doom 3 BFG Edition 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.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 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.
     23 
     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.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 #include "tr_local.h"
     33 
     34 idRenderSystemLocal	tr;
     35 idRenderSystem * renderSystem = &tr;
     36 
     37 /*
     38 =====================
     39 R_PerformanceCounters
     40 
     41 This prints both front and back end counters, so it should
     42 only be called when the back end thread is idle.
     43 =====================
     44 */
     45 static void R_PerformanceCounters() {
     46 	if ( r_showPrimitives.GetInteger() != 0 ) {
     47 		common->Printf( "views:%i draws:%i tris:%i (shdw:%i)\n",
     48 			tr.pc.c_numViews,
     49 			backEnd.pc.c_drawElements + backEnd.pc.c_shadowElements,
     50 			( backEnd.pc.c_drawIndexes + backEnd.pc.c_shadowIndexes ) / 3,
     51 			backEnd.pc.c_shadowIndexes / 3
     52 			);
     53 	}
     54 
     55 	if ( r_showDynamic.GetBool() ) {
     56 		common->Printf( "callback:%i md5:%i dfrmVerts:%i dfrmTris:%i tangTris:%i guis:%i\n",
     57 			tr.pc.c_entityDefCallbacks,
     58 			tr.pc.c_generateMd5,
     59 			tr.pc.c_deformedVerts,
     60 			tr.pc.c_deformedIndexes/3,
     61 			tr.pc.c_tangentIndexes/3,
     62 			tr.pc.c_guiSurfs
     63 			); 
     64 	}
     65 
     66 	if ( r_showCull.GetBool() ) {
     67 		common->Printf( "%i box in %i box out\n",
     68 			tr.pc.c_box_cull_in, tr.pc.c_box_cull_out );
     69 	}
     70 	
     71 	if ( r_showAddModel.GetBool() ) {
     72 		common->Printf( "callback:%i createInteractions:%i createShadowVolumes:%i\n",
     73 			tr.pc.c_entityDefCallbacks, tr.pc.c_createInteractions, tr.pc.c_createShadowVolumes );
     74 		common->Printf( "viewEntities:%i  shadowEntities:%i  viewLights:%i\n", tr.pc.c_visibleViewEntities,
     75 			tr.pc.c_shadowViewEntities, tr.pc.c_viewLights );
     76 	}
     77 	if ( r_showUpdates.GetBool() ) {
     78 		common->Printf( "entityUpdates:%i  entityRefs:%i  lightUpdates:%i  lightRefs:%i\n", 
     79 			tr.pc.c_entityUpdates, tr.pc.c_entityReferences,
     80 			tr.pc.c_lightUpdates, tr.pc.c_lightReferences );
     81 	}
     82 	if ( r_showMemory.GetBool() ) {
     83 		common->Printf( "frameData: %i (%i)\n", frameData->frameMemoryAllocated.GetValue(), frameData->highWaterAllocated );
     84 	}
     85 
     86 	memset( &tr.pc, 0, sizeof( tr.pc ) );
     87 	memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
     88 }
     89 
     90 /*
     91 ====================
     92 RenderCommandBuffers
     93 ====================
     94 */
     95 void idRenderSystemLocal::RenderCommandBuffers( const emptyCommand_t * const cmdHead ) {
     96 	// if there isn't a draw view command, do nothing to avoid swapping a bad frame
     97 	bool	hasView = false;
     98 	for ( const emptyCommand_t * cmd = cmdHead ; cmd ; cmd = (const emptyCommand_t *)cmd->next ) {
     99 		if ( cmd->commandId == RC_DRAW_VIEW_3D || cmd->commandId == RC_DRAW_VIEW_GUI ) {
    100 			hasView = true;
    101 			break;
    102 		}
    103 	}
    104 	if ( !hasView ) {
    105 		return;
    106 	}
    107 
    108 	// r_skipBackEnd allows the entire time of the back end
    109 	// to be removed from performance measurements, although
    110 	// nothing will be drawn to the screen.  If the prints
    111 	// are going to a file, or r_skipBackEnd is later disabled,
    112 	// usefull data can be received.
    113 
    114 	// r_skipRender is usually more usefull, because it will still
    115 	// draw 2D graphics
    116 	if ( !r_skipBackEnd.GetBool() ) {
    117 		if ( glConfig.timerQueryAvailable ) {
    118 			if ( tr.timerQueryId == 0 ) {
    119 				qglGenQueriesARB( 1, & tr.timerQueryId );
    120 			}
    121 			qglBeginQueryARB( GL_TIME_ELAPSED_EXT, tr.timerQueryId );
    122 			RB_ExecuteBackEndCommands( cmdHead );
    123 			qglEndQueryARB( GL_TIME_ELAPSED_EXT );
    124 			qglFlush();
    125 		} else {
    126 			RB_ExecuteBackEndCommands( cmdHead );
    127 		}
    128 	}
    129 
    130 	// pass in null for now - we may need to do some map specific hackery in the future
    131 	resolutionScale.InitForMap( NULL );
    132 }
    133 
    134 /*
    135 ============
    136 R_GetCommandBuffer
    137 
    138 Returns memory for a command buffer (stretchPicCommand_t, 
    139 drawSurfsCommand_t, etc) and links it to the end of the
    140 current command chain.
    141 ============
    142 */
    143 void *R_GetCommandBuffer( int bytes ) {
    144 	emptyCommand_t	*cmd;
    145 
    146 	cmd = (emptyCommand_t *)R_FrameAlloc( bytes, FRAME_ALLOC_DRAW_COMMAND );
    147 	cmd->next = NULL;
    148 	frameData->cmdTail->next = &cmd->commandId;
    149 	frameData->cmdTail = cmd;
    150 
    151 	return (void *)cmd;
    152 }
    153 
    154 /*
    155 =================
    156 R_ViewStatistics
    157 =================
    158 */
    159 static void R_ViewStatistics( viewDef_t *parms ) {
    160 	// report statistics about this view
    161 	if ( !r_showSurfaces.GetBool() ) {
    162 		return;
    163 	}
    164 	common->Printf( "view:%p surfs:%i\n", parms, parms->numDrawSurfs );
    165 }
    166 
    167 /*
    168 =============
    169 R_AddDrawViewCmd
    170 
    171 This is the main 3D rendering command.  A single scene may
    172 have multiple views if a mirror, portal, or dynamic texture is present.
    173 =============
    174 */
    175 void	R_AddDrawViewCmd( viewDef_t *parms, bool guiOnly ) {
    176 	drawSurfsCommand_t	*cmd;
    177 
    178 	cmd = (drawSurfsCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
    179 	cmd->commandId = ( guiOnly ) ? RC_DRAW_VIEW_GUI : RC_DRAW_VIEW_3D;
    180 
    181 	cmd->viewDef = parms;
    182 
    183 	tr.pc.c_numViews++;
    184 
    185 	R_ViewStatistics( parms );
    186 }
    187 
    188 /*
    189 =============
    190 R_AddPostProcess
    191 
    192 This issues the command to do a post process after all the views have
    193 been rendered.
    194 =============
    195 */
    196 void	R_AddDrawPostProcess( viewDef_t * parms ) {
    197 	postProcessCommand_t * cmd = (postProcessCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
    198 	cmd->commandId = RC_POST_PROCESS;
    199 	cmd->viewDef = parms;
    200 }
    201 
    202 
    203 //=================================================================================
    204 
    205 
    206 /*
    207 =============
    208 R_CheckCvars
    209 
    210 See if some cvars that we watch have changed
    211 =============
    212 */
    213 static void R_CheckCvars() {
    214 
    215 	// gamma stuff
    216 	if ( r_gamma.IsModified() || r_brightness.IsModified() ) {
    217 		r_gamma.ClearModified();
    218 		r_brightness.ClearModified();
    219 		R_SetColorMappings();
    220 	}
    221 
    222 	// filtering
    223 	if ( r_maxAnisotropicFiltering.IsModified() || r_useTrilinearFiltering.IsModified() || r_lodBias.IsModified() ) {
    224 		idLib::Printf( "Updating texture filter parameters.\n" );
    225 		r_maxAnisotropicFiltering.ClearModified();
    226 		r_useTrilinearFiltering.ClearModified();
    227 		r_lodBias.ClearModified();
    228 		for ( int i = 0 ; i < globalImages->images.Num() ; i++ ) {
    229 			if ( globalImages->images[i] ) {
    230 				globalImages->images[i]->Bind();
    231 				globalImages->images[i]->SetTexParameters();
    232 			}
    233 		}
    234 	}
    235 
    236 	extern idCVar r_useSeamlessCubeMap;
    237 	if ( r_useSeamlessCubeMap.IsModified() ) {
    238 		r_useSeamlessCubeMap.ClearModified();
    239 		if ( glConfig.seamlessCubeMapAvailable ) {
    240 			if ( r_useSeamlessCubeMap.GetBool() ) {
    241 				qglEnable( GL_TEXTURE_CUBE_MAP_SEAMLESS );
    242 			} else {
    243 				qglDisable( GL_TEXTURE_CUBE_MAP_SEAMLESS );
    244 			}
    245 		}
    246 	}
    247 
    248 	extern idCVar r_useSRGB;
    249 	if ( r_useSRGB.IsModified() ) {
    250 		r_useSRGB.ClearModified();
    251 		if ( glConfig.sRGBFramebufferAvailable ) {
    252 			if ( r_useSRGB.GetBool() ) {
    253 				qglEnable( GL_FRAMEBUFFER_SRGB );
    254 			} else {
    255 				qglDisable( GL_FRAMEBUFFER_SRGB );
    256 			}
    257 		}
    258 	}
    259 
    260 
    261 	if ( r_multiSamples.IsModified() ) {
    262 		if ( r_multiSamples.GetInteger() > 0 ) {
    263 			qglEnable( GL_MULTISAMPLE_ARB );
    264 		} else {
    265 			qglDisable( GL_MULTISAMPLE_ARB );
    266 		}
    267 	}
    268 
    269 	// check for changes to logging state
    270 	GLimp_EnableLogging( r_logFile.GetInteger() != 0 );
    271 }
    272 
    273 /*
    274 =============
    275 idRenderSystemLocal::idRenderSystemLocal
    276 =============
    277 */
    278 idRenderSystemLocal::idRenderSystemLocal() :
    279 	unitSquareTriangles( NULL ),
    280 	zeroOneCubeTriangles( NULL ),
    281 	testImageTriangles( NULL ) {
    282 	Clear();
    283 }
    284 
    285 /*
    286 =============
    287 idRenderSystemLocal::~idRenderSystemLocal
    288 =============
    289 */
    290 idRenderSystemLocal::~idRenderSystemLocal() {
    291 }
    292 
    293 /*
    294 =============
    295 idRenderSystemLocal::SetColor
    296 =============
    297 */
    298 void idRenderSystemLocal::SetColor( const idVec4 & rgba ) {
    299 	currentColorNativeBytesOrder = LittleLong( PackColor( rgba ) );
    300 }
    301 
    302 /*
    303 =============
    304 idRenderSystemLocal::GetColor
    305 =============
    306 */
    307 uint32 idRenderSystemLocal::GetColor() {
    308 	return LittleLong( currentColorNativeBytesOrder );
    309 }
    310 
    311 /*
    312 =============
    313 idRenderSystemLocal::SetGLState
    314 =============
    315 */
    316 void idRenderSystemLocal::SetGLState( const uint64 glState ) {
    317 	currentGLState = glState;
    318 }
    319 
    320 /*
    321 =============
    322 idRenderSystemLocal::DrawFilled
    323 =============
    324 */
    325 void idRenderSystemLocal::DrawFilled( const idVec4 & color, float x, float y, float w, float h ) {
    326 	SetColor( color );
    327 	DrawStretchPic( x, y, w, h, 0.0f, 0.0f, 1.0f, 1.0f, whiteMaterial );
    328 }
    329 
    330 /*
    331 =============
    332 idRenderSystemLocal::DrawStretchPic
    333 =============
    334 */
    335 void idRenderSystemLocal::DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *material ) {
    336 	DrawStretchPic( idVec4( x, y, s1, t1 ), idVec4( x+w, y, s2, t1 ), idVec4( x+w, y+h, s2, t2 ), idVec4( x, y+h, s1, t2 ), material );
    337 }
    338 
    339 /*
    340 =============
    341 idRenderSystemLocal::DrawStretchPic
    342 =============
    343 */
    344 static triIndex_t quadPicIndexes[6] = { 3, 0, 2, 2, 0, 1 };
    345 void idRenderSystemLocal::DrawStretchPic( const idVec4 & topLeft, const idVec4 & topRight, const idVec4 & bottomRight, const idVec4 & bottomLeft, const idMaterial * material ) {
    346 	if ( !R_IsInitialized() ) {
    347 		return;
    348 	}
    349 	if ( material == NULL ) {
    350 		return;
    351 	}
    352 
    353 	idDrawVert * verts = guiModel->AllocTris( 4, quadPicIndexes, 6, material, currentGLState, STEREO_DEPTH_TYPE_NONE );
    354 	if ( verts == NULL ) {
    355 		return;
    356 	}
    357 
    358 	ALIGNTYPE16 idDrawVert localVerts[4];
    359 
    360 	localVerts[0].Clear();
    361 	localVerts[0].xyz[0] = topLeft.x;
    362 	localVerts[0].xyz[1] = topLeft.y;
    363 	localVerts[0].SetTexCoord( topLeft.z, topLeft.w );
    364 	localVerts[0].SetNativeOrderColor( currentColorNativeBytesOrder );
    365 	localVerts[0].ClearColor2();
    366 
    367 	localVerts[1].Clear();
    368 	localVerts[1].xyz[0] = topRight.x;
    369 	localVerts[1].xyz[1] = topRight.y;
    370 	localVerts[1].SetTexCoord( topRight.z, topRight.w );
    371 	localVerts[1].SetNativeOrderColor( currentColorNativeBytesOrder );
    372 	localVerts[1].ClearColor2();
    373 
    374 	localVerts[2].Clear();
    375 	localVerts[2].xyz[0] = bottomRight.x;
    376 	localVerts[2].xyz[1] = bottomRight.y;
    377 	localVerts[2].SetTexCoord( bottomRight.z, bottomRight.w );
    378 	localVerts[2].SetNativeOrderColor( currentColorNativeBytesOrder );
    379 	localVerts[2].ClearColor2();
    380 
    381 	localVerts[3].Clear();
    382 	localVerts[3].xyz[0] = bottomLeft.x;
    383 	localVerts[3].xyz[1] = bottomLeft.y;
    384 	localVerts[3].SetTexCoord( bottomLeft.z, bottomLeft.w );
    385 	localVerts[3].SetNativeOrderColor( currentColorNativeBytesOrder );
    386 	localVerts[3].ClearColor2();
    387 
    388 	WriteDrawVerts16( verts, localVerts, 4 );
    389 }
    390 
    391 /*
    392 =============
    393 idRenderSystemLocal::DrawStretchTri
    394 =============
    395 */
    396 void idRenderSystemLocal::DrawStretchTri( const idVec2 & p1, const idVec2 & p2, const idVec2 & p3, const idVec2 & t1, const idVec2 & t2, const idVec2 & t3, const idMaterial *material ) {
    397 	if ( !R_IsInitialized() ) {
    398 		return;
    399 	}
    400 	if ( material == NULL ) {
    401 		return;
    402 	}
    403 
    404 	triIndex_t tempIndexes[3] = { 1, 0, 2 };
    405 
    406 	idDrawVert * verts = guiModel->AllocTris( 3, tempIndexes, 3, material, currentGLState, STEREO_DEPTH_TYPE_NONE );
    407 	if ( verts == NULL ) {
    408 		return;
    409 	}
    410 
    411 	ALIGNTYPE16 idDrawVert localVerts[3];
    412 
    413 	localVerts[0].Clear();
    414 	localVerts[0].xyz[0] = p1.x;
    415 	localVerts[0].xyz[1] = p1.y;
    416 	localVerts[0].SetTexCoord( t1 );
    417 	localVerts[0].SetNativeOrderColor( currentColorNativeBytesOrder );
    418 	localVerts[0].ClearColor2();
    419 
    420 	localVerts[1].Clear();
    421 	localVerts[1].xyz[0] = p2.x;
    422 	localVerts[1].xyz[1] = p2.y;
    423 	localVerts[1].SetTexCoord( t2 );
    424 	localVerts[1].SetNativeOrderColor( currentColorNativeBytesOrder );
    425 	localVerts[1].ClearColor2();
    426 
    427 	localVerts[2].Clear();
    428 	localVerts[2].xyz[0] = p3.x;
    429 	localVerts[2].xyz[1] = p3.y;
    430 	localVerts[2].SetTexCoord( t3 );
    431 	localVerts[2].SetNativeOrderColor( currentColorNativeBytesOrder );
    432 	localVerts[2].ClearColor2();
    433 
    434 	WriteDrawVerts16( verts, localVerts, 3 );
    435 }
    436 
    437 /*
    438 =============
    439 idRenderSystemLocal::AllocTris
    440 =============
    441 */
    442 idDrawVert * idRenderSystemLocal::AllocTris( int numVerts, const triIndex_t * indexes, int numIndexes, const idMaterial * material, const stereoDepthType_t stereoType ) {
    443 	return guiModel->AllocTris( numVerts, indexes, numIndexes, material, currentGLState, stereoType );
    444 }
    445 
    446 /*
    447 =====================
    448 idRenderSystemLocal::DrawSmallChar
    449 
    450 small chars are drawn at native screen resolution
    451 =====================
    452 */
    453 void idRenderSystemLocal::DrawSmallChar( int x, int y, int ch ) {
    454 	int row, col;
    455 	float frow, fcol;
    456 	float size;
    457 
    458 	ch &= 255;
    459 
    460 	if ( ch == ' ' ) {
    461 		return;
    462 	}
    463 
    464 	if ( y < -SMALLCHAR_HEIGHT ) {
    465 		return;
    466 	}
    467 
    468 	row = ch >> 4;
    469 	col = ch & 15;
    470 
    471 	frow = row * 0.0625f;
    472 	fcol = col * 0.0625f;
    473 	size = 0.0625f;
    474 
    475 	DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT,
    476 					   fcol, frow, 
    477 					   fcol + size, frow + size, 
    478 					   charSetMaterial );
    479 }
    480 
    481 /*
    482 ==================
    483 idRenderSystemLocal::DrawSmallStringExt
    484 
    485 Draws a multi-colored string with a drop shadow, optionally forcing
    486 to a fixed color.
    487 
    488 Coordinates are at 640 by 480 virtual resolution
    489 ==================
    490 */
    491 void idRenderSystemLocal::DrawSmallStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor ) {
    492 	idVec4		color;
    493 	const unsigned char	*s;
    494 	int			xx;
    495 
    496 	// draw the colored text
    497 	s = (const unsigned char*)string;
    498 	xx = x;
    499 	SetColor( setColor );
    500 	while ( *s ) {
    501 		if ( idStr::IsColor( (const char*)s ) ) {
    502 			if ( !forceColor ) {
    503 				if ( *(s+1) == C_COLOR_DEFAULT ) {
    504 					SetColor( setColor );
    505 				} else {
    506 					color = idStr::ColorForIndex( *(s+1) );
    507 					color[3] = setColor[3];
    508 					SetColor( color );
    509 				}
    510 			}
    511 			s += 2;
    512 			continue;
    513 		}
    514 		DrawSmallChar( xx, y, *s );
    515 		xx += SMALLCHAR_WIDTH;
    516 		s++;
    517 	}
    518 	SetColor( colorWhite );
    519 }
    520 
    521 /*
    522 =====================
    523 idRenderSystemLocal::DrawBigChar
    524 =====================
    525 */
    526 void idRenderSystemLocal::DrawBigChar( int x, int y, int ch ) {
    527 	int row, col;
    528 	float frow, fcol;
    529 	float size;
    530 
    531 	ch &= 255;
    532 
    533 	if ( ch == ' ' ) {
    534 		return;
    535 	}
    536 
    537 	if ( y < -BIGCHAR_HEIGHT ) {
    538 		return;
    539 	}
    540 
    541 	row = ch >> 4;
    542 	col = ch & 15;
    543 
    544 	frow = row * 0.0625f;
    545 	fcol = col * 0.0625f;
    546 	size = 0.0625f;
    547 
    548 	DrawStretchPic( x, y, BIGCHAR_WIDTH, BIGCHAR_HEIGHT,
    549 					   fcol, frow, 
    550 					   fcol + size, frow + size, 
    551 					   charSetMaterial );
    552 }
    553 
    554 /*
    555 ==================
    556 idRenderSystemLocal::DrawBigStringExt
    557 
    558 Draws a multi-colored string with a drop shadow, optionally forcing
    559 to a fixed color.
    560 
    561 Coordinates are at 640 by 480 virtual resolution
    562 ==================
    563 */
    564 void idRenderSystemLocal::DrawBigStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor ) {
    565 	idVec4		color;
    566 	const char	*s;
    567 	int			xx;
    568 
    569 	// draw the colored text
    570 	s = string;
    571 	xx = x;
    572 	SetColor( setColor );
    573 	while ( *s ) {
    574 		if ( idStr::IsColor( s ) ) {
    575 			if ( !forceColor ) {
    576 				if ( *(s+1) == C_COLOR_DEFAULT ) {
    577 					SetColor( setColor );
    578 				} else {
    579 					color = idStr::ColorForIndex( *(s+1) );
    580 					color[3] = setColor[3];
    581 					SetColor( color );
    582 				}
    583 			}
    584 			s += 2;
    585 			continue;
    586 		}
    587 		DrawBigChar( xx, y, *s );
    588 		xx += BIGCHAR_WIDTH;
    589 		s++;
    590 	}
    591 	SetColor( colorWhite );
    592 }
    593 
    594 //======================================================================================
    595 
    596 /*
    597 ====================
    598 idRenderSystemLocal::SwapCommandBuffers
    599 
    600 Performs final closeout of any gui models being defined.
    601 
    602 Waits for the previous GPU rendering to complete and vsync.
    603 
    604 Returns the head of the linked command list that was just closed off.
    605 
    606 Returns timing information from the previous frame.
    607 
    608 After this is called, new command buffers can be built up in parallel
    609 with the rendering of the closed off command buffers by RenderCommandBuffers()
    610 ====================
    611 */
    612 const emptyCommand_t * idRenderSystemLocal::SwapCommandBuffers( 
    613 													uint64 * frontEndMicroSec,
    614 													uint64 * backEndMicroSec,
    615 													uint64 * shadowMicroSec,
    616 													uint64 * gpuMicroSec )  {
    617 
    618 	SwapCommandBuffers_FinishRendering( frontEndMicroSec, backEndMicroSec, shadowMicroSec, gpuMicroSec );
    619 
    620 	return SwapCommandBuffers_FinishCommandBuffers();
    621 }
    622 
    623 /*
    624 =====================
    625 idRenderSystemLocal::SwapCommandBuffers_FinishRendering
    626 =====================
    627 */
    628 void idRenderSystemLocal::SwapCommandBuffers_FinishRendering( 
    629 												uint64 * frontEndMicroSec,
    630 												uint64 * backEndMicroSec,
    631 												uint64 * shadowMicroSec,
    632 												uint64 * gpuMicroSec )  {
    633 	SCOPED_PROFILE_EVENT( "SwapCommandBuffers" );
    634 
    635 	if ( gpuMicroSec != NULL ) {
    636 		*gpuMicroSec = 0;		// until shown otherwise
    637 	}
    638 
    639 	if ( !R_IsInitialized() ) {
    640 		return;
    641 	}
    642 
    643 
    644 	// After coming back from an autoswap, we won't have anything to render
    645 	if ( frameData->cmdHead->next != NULL ) {
    646 		// wait for our fence to hit, which means the swap has actually happened
    647 		// We must do this before clearing any resources the GPU may be using
    648 		void GL_BlockingSwapBuffers();
    649 		GL_BlockingSwapBuffers();
    650 	}
    651 
    652 	// read back the start and end timer queries from the previous frame
    653 	if ( glConfig.timerQueryAvailable ) {
    654 		uint64 drawingTimeNanoseconds = 0;
    655 		if ( tr.timerQueryId != 0 ) {
    656 			qglGetQueryObjectui64vEXT( tr.timerQueryId, GL_QUERY_RESULT, &drawingTimeNanoseconds );
    657 		}
    658 		if ( gpuMicroSec != NULL ) {
    659 			*gpuMicroSec = drawingTimeNanoseconds / 1000;
    660 		}
    661 	}
    662 
    663 	//------------------------------
    664 
    665 	// save out timing information
    666 	if ( frontEndMicroSec != NULL ) {
    667 		*frontEndMicroSec = pc.frontEndMicroSec;
    668 	}
    669 	if ( backEndMicroSec != NULL ) {
    670 		*backEndMicroSec = backEnd.pc.totalMicroSec;
    671 	}
    672 	if ( shadowMicroSec != NULL ) {
    673 		*shadowMicroSec = backEnd.pc.shadowMicroSec;
    674 	}
    675 
    676 	// print any other statistics and clear all of them
    677 	R_PerformanceCounters();
    678 
    679 	// check for dynamic changes that require some initialization
    680 	R_CheckCvars();
    681 
    682     // check for errors
    683 	GL_CheckErrors();
    684 }
    685 
    686 /*
    687 =====================
    688 idRenderSystemLocal::SwapCommandBuffers_FinishCommandBuffers
    689 =====================
    690 */
    691 const emptyCommand_t * idRenderSystemLocal::SwapCommandBuffers_FinishCommandBuffers() {
    692 	if ( !R_IsInitialized() ) {
    693 		return NULL;
    694 	}
    695 
    696 	// close any gui drawing
    697 	guiModel->EmitFullScreen();
    698 	guiModel->Clear();
    699 
    700 	// unmap the buffer objects so they can be used by the GPU
    701 	vertexCache.BeginBackEnd();
    702 
    703 	// save off this command buffer
    704 	const emptyCommand_t * commandBufferHead = frameData->cmdHead;
    705 
    706 	// copy the code-used drawsurfs that were
    707 	// allocated at the start of the buffer memory to the backEnd referenced locations
    708 	backEnd.unitSquareSurface = tr.unitSquareSurface_;
    709 	backEnd.zeroOneCubeSurface = tr.zeroOneCubeSurface_;
    710 	backEnd.testImageSurface = tr.testImageSurface_;
    711 
    712 	// use the other buffers next frame, because another CPU
    713 	// may still be rendering into the current buffers
    714 	R_ToggleSmpFrame();
    715 
    716 	// possibly change the stereo3D mode
    717 	// PC
    718 	if ( glConfig.nativeScreenWidth == 1280 && glConfig.nativeScreenHeight == 1470 ) {
    719 		glConfig.stereo3Dmode = STEREO3D_HDMI_720;
    720 	} else {
    721 		glConfig.stereo3Dmode = GetStereoScopicRenderingMode();
    722 	}
    723 
    724 	// prepare the new command buffer
    725 	guiModel->BeginFrame();
    726 
    727 	//------------------------------
    728 	// Make sure that geometry used by code is present in the buffer cache.
    729 	// These use frame buffer cache (not static) because they may be used during
    730 	// map loads.
    731 	//
    732 	// It is important to do this first, so if the buffers overflow during
    733 	// scene generation, the basic surfaces needed for drawing the buffers will
    734 	// always be present.
    735 	//------------------------------
    736 	R_InitDrawSurfFromTri( tr.unitSquareSurface_, *tr.unitSquareTriangles );
    737 	R_InitDrawSurfFromTri( tr.zeroOneCubeSurface_, *tr.zeroOneCubeTriangles );
    738 	R_InitDrawSurfFromTri( tr.testImageSurface_, *tr.testImageTriangles );
    739 
    740 	// Reset render crop to be the full screen
    741 	renderCrops[0].x1 = 0;
    742 	renderCrops[0].y1 = 0;
    743 	renderCrops[0].x2 = GetWidth() - 1;
    744 	renderCrops[0].y2 = GetHeight() - 1;
    745 	currentRenderCrop = 0;
    746 
    747 	// this is the ONLY place this is modified
    748 	frameCount++;
    749 
    750 	// just in case we did a common->Error while this
    751 	// was set
    752 	guiRecursionLevel = 0;
    753 
    754 	// the first rendering will be used for commands like
    755 	// screenshot, rather than a possible subsequent remote
    756 	// or mirror render
    757 //	primaryWorld = NULL;
    758 
    759 	// set the time for shader effects in 2D rendering
    760 	frameShaderTime = Sys_Milliseconds() * 0.001;
    761 
    762 	setBufferCommand_t * cmd2 = (setBufferCommand_t *)R_GetCommandBuffer( sizeof( *cmd2 ) );
    763 	cmd2->commandId = RC_SET_BUFFER;
    764 	cmd2->buffer = (int)GL_BACK;
    765 
    766 	// the old command buffer can now be rendered, while the new one can
    767 	// be built in parallel
    768 	return commandBufferHead;
    769 }
    770 
    771 /*
    772 =====================
    773 idRenderSystemLocal::WriteDemoPics
    774 =====================
    775 */
    776 void idRenderSystemLocal::WriteDemoPics() {
    777 	common->WriteDemo()->WriteInt( DS_RENDER );
    778 	common->WriteDemo()->WriteInt( DC_GUI_MODEL );
    779 }
    780 
    781 /*
    782 =====================
    783 idRenderSystemLocal::DrawDemoPics
    784 =====================
    785 */
    786 void idRenderSystemLocal::DrawDemoPics() {
    787 }
    788 
    789 /*
    790 =====================
    791 idRenderSystemLocal::GetCroppedViewport
    792 
    793 Returns the current cropped pixel coordinates
    794 =====================
    795 */
    796 void idRenderSystemLocal::GetCroppedViewport( idScreenRect * viewport ) {
    797 	*viewport = renderCrops[currentRenderCrop];
    798 }
    799 
    800 /*
    801 ========================
    802 idRenderSystemLocal::PerformResolutionScaling
    803 
    804 The 3D rendering size can be smaller than the full window resolution to reduce
    805 fill rate requirements while still allowing the GUIs to be full resolution.
    806 In split screen mode the rendering size is also smaller.
    807 ========================
    808 */
    809 void idRenderSystemLocal::PerformResolutionScaling( int& newWidth, int& newHeight ) {
    810 
    811 	float xScale = 1.0f;
    812 	float yScale = 1.0f;
    813 	resolutionScale.GetCurrentResolutionScale( xScale, yScale );
    814 
    815 	newWidth = idMath::Ftoi( GetWidth() * xScale );
    816 	newHeight = idMath::Ftoi( GetHeight() * yScale );
    817 }
    818 
    819 /*
    820 ================
    821 idRenderSystemLocal::CropRenderSize
    822 ================
    823 */
    824 void idRenderSystemLocal::CropRenderSize( int width, int height ) {
    825 	if ( !R_IsInitialized() ) {
    826 		return;
    827 	}
    828 
    829 	// close any gui drawing before changing the size
    830 	guiModel->EmitFullScreen();
    831 	guiModel->Clear();
    832 
    833 
    834 	if ( width < 1 || height < 1 ) {
    835 		common->Error( "CropRenderSize: bad sizes" );
    836 	}
    837 
    838 	if ( common->WriteDemo() ) {
    839 		common->WriteDemo()->WriteInt( DS_RENDER );
    840 		common->WriteDemo()->WriteInt( DC_CROP_RENDER );
    841 		common->WriteDemo()->WriteInt( width );
    842 		common->WriteDemo()->WriteInt( height );
    843 
    844 		if ( r_showDemo.GetBool() ) {
    845 			common->Printf( "write DC_CROP_RENDER\n" );
    846 		}
    847 	}
    848 
    849 	idScreenRect & previous = renderCrops[currentRenderCrop];
    850 
    851 	currentRenderCrop++;
    852 
    853 	idScreenRect & current = renderCrops[currentRenderCrop];
    854 
    855 	current.x1 = previous.x1;
    856 	current.x2 = previous.x1 + width - 1;
    857 	current.y1 = previous.y2 - height + 1;
    858 	current.y2 = previous.y2;
    859 }
    860 
    861 /*
    862 ================
    863 idRenderSystemLocal::UnCrop
    864 ================
    865 */
    866 void idRenderSystemLocal::UnCrop() {
    867 	if ( !R_IsInitialized() ) {
    868 		return;
    869 	}
    870 
    871 	if ( currentRenderCrop < 1 ) {
    872 		common->Error( "idRenderSystemLocal::UnCrop: currentRenderCrop < 1" );
    873 	}
    874 
    875 	// close any gui drawing
    876 	guiModel->EmitFullScreen();
    877 	guiModel->Clear();
    878 
    879 	currentRenderCrop--;
    880 
    881 	if ( common->WriteDemo() ) {
    882 		common->WriteDemo()->WriteInt( DS_RENDER );
    883 		common->WriteDemo()->WriteInt( DC_UNCROP_RENDER );
    884 
    885 		if ( r_showDemo.GetBool() ) {
    886 			common->Printf( "write DC_UNCROP\n" );
    887 		}
    888 	}
    889 }
    890 
    891 /*
    892 ================
    893 idRenderSystemLocal::CaptureRenderToImage
    894 ================
    895 */
    896 void idRenderSystemLocal::CaptureRenderToImage( const char *imageName, bool clearColorAfterCopy ) {
    897 	if ( !R_IsInitialized() ) {
    898 		return;
    899 	}
    900 	guiModel->EmitFullScreen();
    901 	guiModel->Clear();
    902 
    903 	if ( common->WriteDemo() ) {
    904 		common->WriteDemo()->WriteInt( DS_RENDER );
    905 		common->WriteDemo()->WriteInt( DC_CAPTURE_RENDER );
    906 		common->WriteDemo()->WriteHashString( imageName );
    907 
    908 		if ( r_showDemo.GetBool() ) {
    909 			common->Printf( "write DC_CAPTURE_RENDER: %s\n", imageName );
    910 		}
    911 	}
    912 	idImage	* image = globalImages->GetImage( imageName );
    913 	if ( image == NULL ) {
    914 		image = globalImages->AllocImage( imageName );
    915 	}
    916 
    917 	idScreenRect & rc = renderCrops[currentRenderCrop];
    918 
    919 	copyRenderCommand_t *cmd = (copyRenderCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
    920 	cmd->commandId = RC_COPY_RENDER;
    921 	cmd->x = rc.x1;
    922 	cmd->y = rc.y1;
    923 	cmd->imageWidth = rc.GetWidth();
    924 	cmd->imageHeight = rc.GetHeight();
    925 	cmd->image = image;
    926 	cmd->clearColorAfterCopy = clearColorAfterCopy;
    927 
    928 	guiModel->Clear();
    929 }
    930 
    931 /*
    932 ==============
    933 idRenderSystemLocal::CaptureRenderToFile
    934 ==============
    935 */
    936 void idRenderSystemLocal::CaptureRenderToFile( const char *fileName, bool fixAlpha ) {
    937 	if ( !R_IsInitialized() ) {
    938 		return;
    939 	}
    940 
    941 	idScreenRect & rc = renderCrops[currentRenderCrop];
    942 
    943 	guiModel->EmitFullScreen();
    944 	guiModel->Clear();
    945 	RenderCommandBuffers( frameData->cmdHead );
    946 
    947 	qglReadBuffer( GL_BACK );
    948 
    949 	// include extra space for OpenGL padding to word boundaries
    950 	int	c = ( rc.GetWidth() + 3 ) * rc.GetHeight();
    951 	byte *data = (byte *)R_StaticAlloc( c * 3 );
    952 	
    953 	qglReadPixels( rc.x1, rc.y1, rc.GetWidth(), rc.GetHeight(), GL_RGB, GL_UNSIGNED_BYTE, data ); 
    954 
    955 	byte *data2 = (byte *)R_StaticAlloc( c * 4 );
    956 
    957 	for ( int i = 0 ; i < c ; i++ ) {
    958 		data2[ i * 4 ] = data[ i * 3 ];
    959 		data2[ i * 4 + 1 ] = data[ i * 3 + 1 ];
    960 		data2[ i * 4 + 2 ] = data[ i * 3 + 2 ];
    961 		data2[ i * 4 + 3 ] = 0xff;
    962 	}
    963 
    964 	R_WriteTGA( fileName, data2, rc.GetWidth(), rc.GetHeight(), true );
    965 
    966 	R_StaticFree( data );
    967 	R_StaticFree( data2 );
    968 }
    969 
    970 
    971 /*
    972 ==============
    973 idRenderSystemLocal::AllocRenderWorld
    974 ==============
    975 */
    976 idRenderWorld *idRenderSystemLocal::AllocRenderWorld() {
    977 	idRenderWorldLocal *rw;
    978 	rw = new (TAG_RENDER) idRenderWorldLocal;
    979 	worlds.Append( rw );
    980 	return rw;
    981 }
    982 
    983 /*
    984 ==============
    985 idRenderSystemLocal::FreeRenderWorld
    986 ==============
    987 */
    988 void idRenderSystemLocal::FreeRenderWorld( idRenderWorld *rw ) {
    989 	if ( primaryWorld == rw ) {
    990 		primaryWorld = NULL;
    991 	}
    992 	worlds.Remove( static_cast<idRenderWorldLocal *>(rw) );
    993 	delete rw;
    994 }
    995 
    996 /*
    997 ==============
    998 idRenderSystemLocal::PrintMemInfo
    999 ==============
   1000 */
   1001 void idRenderSystemLocal::PrintMemInfo( MemInfo_t *mi ) {
   1002 	// sum up image totals
   1003 	globalImages->PrintMemInfo( mi );
   1004 
   1005 	// sum up model totals
   1006 	renderModelManager->PrintMemInfo( mi );
   1007 
   1008 	// compute render totals
   1009 
   1010 }
   1011 
   1012 /*
   1013 ===============
   1014 idRenderSystemLocal::UploadImage
   1015 ===============
   1016 */
   1017 bool idRenderSystemLocal::UploadImage( const char *imageName, const byte *data, int width, int height  ) {
   1018 	idImage *image = globalImages->GetImage( imageName );
   1019 	if ( !image ) {
   1020 		return false;
   1021 	}
   1022 	image->UploadScratch( data, width, height );
   1023 	return true;
   1024 }