tr_frontend_main.cpp (13245B)
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 /* 35 ========================================================================================== 36 37 FRAME MEMORY ALLOCATION 38 39 ========================================================================================== 40 */ 41 42 static const unsigned int NUM_FRAME_DATA = 2; 43 static const unsigned int FRAME_ALLOC_ALIGNMENT = 128; 44 static const unsigned int MAX_FRAME_MEMORY = 64 * 1024 * 1024; // larger so that we can noclip on PC for dev purposes 45 46 idFrameData smpFrameData[NUM_FRAME_DATA]; 47 idFrameData * frameData; 48 unsigned int smpFrame; 49 50 //#define TRACK_FRAME_ALLOCS 51 52 #if defined( TRACK_FRAME_ALLOCS ) 53 idSysInterlockedInteger frameAllocTypeCount[FRAME_ALLOC_MAX]; 54 int frameHighWaterTypeCount[FRAME_ALLOC_MAX]; 55 #endif 56 57 /* 58 ==================== 59 R_ToggleSmpFrame 60 ==================== 61 */ 62 void R_ToggleSmpFrame() { 63 // update the highwater mark 64 if ( frameData->frameMemoryAllocated.GetValue() > frameData->highWaterAllocated ) { 65 frameData->highWaterAllocated = frameData->frameMemoryAllocated.GetValue(); 66 #if defined( TRACK_FRAME_ALLOCS ) 67 frameData->highWaterUsed = frameData->frameMemoryUsed.GetValue(); 68 for ( int i = 0; i < FRAME_ALLOC_MAX; i++ ) { 69 frameHighWaterTypeCount[i] = frameAllocTypeCount[i].GetValue(); 70 } 71 #endif 72 } 73 74 // switch to the next frame 75 smpFrame++; 76 frameData = &smpFrameData[smpFrame % NUM_FRAME_DATA]; 77 78 // reset the memory allocation 79 const unsigned int bytesNeededForAlignment = FRAME_ALLOC_ALIGNMENT - ( (unsigned int)frameData->frameMemory & ( FRAME_ALLOC_ALIGNMENT - 1 ) ); 80 frameData->frameMemoryAllocated.SetValue( bytesNeededForAlignment ); 81 frameData->frameMemoryUsed.SetValue( 0 ); 82 83 #if defined( TRACK_FRAME_ALLOCS ) 84 for ( int i = 0; i < FRAME_ALLOC_MAX; i++ ) { 85 frameAllocTypeCount[i].SetValue( 0 ); 86 } 87 #endif 88 89 // clear the command chain and make a RC_NOP command the only thing on the list 90 frameData->cmdHead = frameData->cmdTail = (emptyCommand_t *)R_FrameAlloc( sizeof( *frameData->cmdHead ), FRAME_ALLOC_DRAW_COMMAND ); 91 frameData->cmdHead->commandId = RC_NOP; 92 frameData->cmdHead->next = NULL; 93 } 94 95 /* 96 ===================== 97 R_ShutdownFrameData 98 ===================== 99 */ 100 void R_ShutdownFrameData() { 101 frameData = NULL; 102 for ( int i = 0; i < NUM_FRAME_DATA; i++ ) { 103 Mem_Free16( smpFrameData[i].frameMemory ); 104 smpFrameData[i].frameMemory = NULL; 105 } 106 } 107 108 /* 109 ===================== 110 R_InitFrameData 111 ===================== 112 */ 113 void R_InitFrameData() { 114 R_ShutdownFrameData(); 115 116 for ( int i = 0; i < NUM_FRAME_DATA; i++ ) { 117 smpFrameData[i].frameMemory = (byte *) Mem_Alloc16( MAX_FRAME_MEMORY, TAG_RENDER ); 118 } 119 120 // must be set before calling R_ToggleSmpFrame() 121 frameData = &smpFrameData[ 0 ]; 122 123 R_ToggleSmpFrame(); 124 } 125 126 /* 127 ================ 128 R_FrameAlloc 129 130 This data will be automatically freed when the 131 current frame's back end completes. 132 133 This should only be called by the front end. The 134 back end shouldn't need to allocate memory. 135 136 All temporary data, like dynamic tesselations 137 and local spaces are allocated here. 138 139 All memory is cache-line-cleared for the best performance. 140 ================ 141 */ 142 void *R_FrameAlloc( int bytes, frameAllocType_t type ) { 143 #if defined( TRACK_FRAME_ALLOCS ) 144 frameData->frameMemoryUsed.Add( bytes ); 145 frameAllocTypeCount[type].Add( bytes ); 146 #endif 147 148 bytes = ( bytes + FRAME_ALLOC_ALIGNMENT - 1 ) & ~ ( FRAME_ALLOC_ALIGNMENT - 1 ); 149 150 // thread safe add 151 int end = frameData->frameMemoryAllocated.Add( bytes ); 152 if ( end > MAX_FRAME_MEMORY ) { 153 idLib::Error( "R_FrameAlloc ran out of memory. bytes = %d, end = %d, highWaterAllocated = %d\n", bytes, end, frameData->highWaterAllocated ); 154 } 155 156 byte * ptr = frameData->frameMemory + end - bytes; 157 158 // cache line clear the memory 159 for ( int offset = 0; offset < bytes; offset += CACHE_LINE_SIZE ) { 160 ZeroCacheLine( ptr, offset ); 161 } 162 163 return ptr; 164 } 165 166 /* 167 ================== 168 R_ClearedFrameAlloc 169 ================== 170 */ 171 void *R_ClearedFrameAlloc( int bytes, frameAllocType_t type ) { 172 // NOTE: every allocation is cache line cleared 173 return R_FrameAlloc( bytes, type ); 174 } 175 176 /* 177 ========================================================================================== 178 179 FONT-END STATIC MEMORY ALLOCATION 180 181 ========================================================================================== 182 */ 183 184 /* 185 ================= 186 R_StaticAlloc 187 ================= 188 */ 189 void *R_StaticAlloc( int bytes, const memTag_t tag ) { 190 tr.pc.c_alloc++; 191 192 void * buf = Mem_Alloc( bytes, tag ); 193 194 // don't exit on failure on zero length allocations since the old code didn't 195 if ( buf == NULL && bytes != 0 ) { 196 common->FatalError( "R_StaticAlloc failed on %i bytes", bytes ); 197 } 198 return buf; 199 } 200 201 /* 202 ================= 203 R_ClearedStaticAlloc 204 ================= 205 */ 206 void *R_ClearedStaticAlloc( int bytes ) { 207 void * buf = R_StaticAlloc( bytes ); 208 memset( buf, 0, bytes ); 209 return buf; 210 } 211 212 /* 213 ================= 214 R_StaticFree 215 ================= 216 */ 217 void R_StaticFree( void *data ) { 218 tr.pc.c_free++; 219 Mem_Free( data ); 220 } 221 222 /* 223 ========================================================================================== 224 225 FONT-END RENDERING 226 227 ========================================================================================== 228 */ 229 230 /* 231 ================= 232 R_SortDrawSurfs 233 ================= 234 */ 235 static void R_SortDrawSurfs( drawSurf_t ** drawSurfs, const int numDrawSurfs ) { 236 #if 1 237 238 uint64 * indices = (uint64 *) _alloca16( numDrawSurfs * sizeof( indices[0] ) ); 239 240 // sort the draw surfs based on: 241 // 1. sort value (largest first) 242 // 2. depth (smallest first) 243 // 3. index (largest first) 244 assert( numDrawSurfs <= 0xFFFF ); 245 for ( int i = 0; i < numDrawSurfs; i++ ) { 246 float sort = SS_POST_PROCESS - drawSurfs[i]->sort; 247 assert( sort >= 0.0f ); 248 249 uint64 dist = 0; 250 if ( drawSurfs[i]->frontEndGeo != NULL ) { 251 float min = 0.0f; 252 float max = 1.0f; 253 idRenderMatrix::DepthBoundsForBounds( min, max, drawSurfs[i]->space->mvp, drawSurfs[i]->frontEndGeo->bounds ); 254 dist = idMath::Ftoui16( min * 0xFFFF ); 255 } 256 257 indices[i] = ( ( numDrawSurfs - i ) & 0xFFFF ) | ( dist << 16 ) | ( (uint64) ( *(uint32 *)&sort ) << 32 ); 258 } 259 260 const int64 MAX_LEVELS = 128; 261 int64 lo[MAX_LEVELS]; 262 int64 hi[MAX_LEVELS]; 263 264 // Keep the top of the stack in registers to avoid load-hit-stores. 265 register int64 st_lo = 0; 266 register int64 st_hi = numDrawSurfs - 1; 267 register int64 level = 0; 268 269 for ( ; ; ) { 270 register int64 i = st_lo; 271 register int64 j = st_hi; 272 if ( j - i >= 4 && level < MAX_LEVELS - 1 ) { 273 register uint64 pivot = indices[( i + j ) / 2]; 274 do { 275 while ( indices[i] > pivot ) i++; 276 while ( indices[j] < pivot ) j--; 277 if ( i > j ) break; 278 uint64 h = indices[i]; indices[i] = indices[j]; indices[j] = h; 279 } while ( ++i <= --j ); 280 281 // No need for these iterations because we are always sorting unique values. 282 //while ( indices[j] == pivot && st_lo < j ) j--; 283 //while ( indices[i] == pivot && i < st_hi ) i++; 284 285 assert( level < MAX_LEVELS - 1 ); 286 lo[level] = i; 287 hi[level] = st_hi; 288 st_hi = j; 289 level++; 290 } else { 291 for( ; i < j; j-- ) { 292 register int64 m = i; 293 for ( int64 k = i + 1; k <= j; k++ ) { 294 if ( indices[k] < indices[m] ) { 295 m = k; 296 } 297 } 298 uint64 h = indices[m]; indices[m] = indices[j]; indices[j] = h; 299 } 300 if ( --level < 0 ) { 301 break; 302 } 303 st_lo = lo[level]; 304 st_hi = hi[level]; 305 } 306 } 307 308 drawSurf_t ** newDrawSurfs = (drawSurf_t **) indices; 309 for ( int i = 0; i < numDrawSurfs; i++ ) { 310 newDrawSurfs[i] = drawSurfs[numDrawSurfs - ( indices[i] & 0xFFFF )]; 311 } 312 memcpy( drawSurfs, newDrawSurfs, numDrawSurfs * sizeof( drawSurfs[0] ) ); 313 314 #else 315 316 struct local_t { 317 static int R_QsortSurfaces( const void *a, const void *b ) { 318 const drawSurf_t * ea = *(drawSurf_t **)a; 319 const drawSurf_t * eb = *(drawSurf_t **)b; 320 if ( ea->sort < eb->sort ) { 321 return -1; 322 } 323 if ( ea->sort > eb->sort ) { 324 return 1; 325 } 326 return 0; 327 } 328 }; 329 330 // Add a sort offset so surfaces with equal sort orders still deterministically 331 // draw in the order they were added, at least within a given model. 332 float sorfOffset = 0.0f; 333 for ( int i = 0; i < numDrawSurfs; i++ ) { 334 drawSurf[i]->sort += sorfOffset; 335 sorfOffset += 0.000001f; 336 } 337 338 // sort the drawsurfs 339 qsort( drawSurfs, numDrawSurfs, sizeof( drawSurfs[0] ), local_t::R_QsortSurfaces ); 340 341 #endif 342 } 343 344 /* 345 ================ 346 R_RenderView 347 348 A view may be either the actual camera view, 349 a mirror / remote location, or a 3D view on a gui surface. 350 351 Parms will typically be allocated with R_FrameAlloc 352 ================ 353 */ 354 void R_RenderView( viewDef_t *parms ) { 355 // save view in case we are a subview 356 viewDef_t * oldView = tr.viewDef; 357 358 tr.viewDef = parms; 359 360 // setup the matrix for world space to eye space 361 R_SetupViewMatrix( tr.viewDef ); 362 363 // we need to set the projection matrix before doing 364 // portal-to-screen scissor calculations 365 R_SetupProjectionMatrix( tr.viewDef ); 366 367 // setup render matrices for faster culling 368 idRenderMatrix::Transpose( *(idRenderMatrix *)tr.viewDef->projectionMatrix, tr.viewDef->projectionRenderMatrix ); 369 idRenderMatrix viewRenderMatrix; 370 idRenderMatrix::Transpose( *(idRenderMatrix *)tr.viewDef->worldSpace.modelViewMatrix, viewRenderMatrix ); 371 idRenderMatrix::Multiply( tr.viewDef->projectionRenderMatrix, viewRenderMatrix, tr.viewDef->worldSpace.mvp ); 372 373 // the planes of the view frustum are needed for portal visibility culling 374 idRenderMatrix::GetFrustumPlanes( tr.viewDef->frustum, tr.viewDef->worldSpace.mvp, false, true ); 375 376 // the DOOM 3 frustum planes point outside the frustum 377 for ( int i = 0; i < 6; i++ ) { 378 tr.viewDef->frustum[i] = - tr.viewDef->frustum[i]; 379 } 380 // remove the Z-near to avoid portals from being near clipped 381 tr.viewDef->frustum[4][3] -= r_znear.GetFloat(); 382 383 // identify all the visible portal areas, and create view lights and view entities 384 // for all the the entityDefs and lightDefs that are in the visible portal areas 385 static_cast<idRenderWorldLocal *>(parms->renderWorld)->FindViewLightsAndEntities(); 386 387 // wait for any shadow volume jobs from the previous frame to finish 388 tr.frontEndJobList->Wait(); 389 390 // make sure that interactions exist for all light / entity combinations that are visible 391 // add any pre-generated light shadows, and calculate the light shader values 392 R_AddLights(); 393 394 // adds ambient surfaces and create any necessary interaction surfaces to add to the light lists 395 R_AddModels(); 396 397 // build up the GUIs on world surfaces 398 R_AddInGameGuis( tr.viewDef->drawSurfs, tr.viewDef->numDrawSurfs ); 399 400 // any viewLight that didn't have visible surfaces can have it's shadows removed 401 R_OptimizeViewLightsList(); 402 403 // sort all the ambient surfaces for translucency ordering 404 R_SortDrawSurfs( tr.viewDef->drawSurfs, tr.viewDef->numDrawSurfs ); 405 406 // generate any subviews (mirrors, cameras, etc) before adding this view 407 if ( R_GenerateSubViews( tr.viewDef->drawSurfs, tr.viewDef->numDrawSurfs ) ) { 408 // if we are debugging subviews, allow the skipping of the main view draw 409 if ( r_subviewOnly.GetBool() ) { 410 return; 411 } 412 } 413 414 // write everything needed to the demo file 415 if ( common->WriteDemo() ) { 416 static_cast<idRenderWorldLocal *>(parms->renderWorld)->WriteVisibleDefs( tr.viewDef ); 417 } 418 419 // add the rendering commands for this viewDef 420 R_AddDrawViewCmd( parms, false ); 421 422 // restore view in case we are a subview 423 tr.viewDef = oldView; 424 } 425 426 /* 427 ================ 428 R_RenderPostProcess 429 430 Because R_RenderView may be called by subviews we have to make sure the post process 431 pass happens after the active view and its subviews is done rendering. 432 ================ 433 */ 434 void R_RenderPostProcess( viewDef_t *parms ) { 435 viewDef_t * oldView = tr.viewDef; 436 437 R_AddDrawPostProcess( parms ); 438 439 tr.viewDef = oldView; 440 }