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 }