DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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 }