DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

RenderLog.cpp (11404B)


      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 #pragma hdrstop
     29 #include "tr_local.h"
     30 
     31 /*
     32 ================================================================================================
     33 Contains the RenderLog implementation.
     34 
     35 TODO:	Emit statistics to the logfile at the end of views and frames.
     36 ================================================================================================
     37 */
     38 
     39 idCVar r_logLevel( "r_logLevel", "2", CVAR_INTEGER, "1 = blocks only, 2 = everything", 1, 2 );
     40 
     41 static const int LOG_LEVEL_BLOCKS_ONLY	= 1;
     42 static const int LOG_LEVEL_EVERYTHING	= 2;
     43 
     44 const char * renderLogMainBlockLabels[] = {
     45 	ASSERT_ENUM_STRING( MRB_NONE,							0 ),
     46 	ASSERT_ENUM_STRING( MRB_BEGIN_DRAWING_VIEW,				1 ),
     47 	ASSERT_ENUM_STRING( MRB_FILL_DEPTH_BUFFER,				2 ),
     48 	ASSERT_ENUM_STRING( MRB_DRAW_INTERACTIONS,				3 ),
     49 	ASSERT_ENUM_STRING( MRB_DRAW_SHADER_PASSES,				4 ),
     50 	ASSERT_ENUM_STRING( MRB_FOG_ALL_LIGHTS,					5 ),
     51 	ASSERT_ENUM_STRING( MRB_DRAW_SHADER_PASSES_POST,		6 ),
     52 	ASSERT_ENUM_STRING( MRB_DRAW_DEBUG_TOOLS,				7 ),
     53 	ASSERT_ENUM_STRING( MRB_CAPTURE_COLORBUFFER,			8 ),
     54 	ASSERT_ENUM_STRING( MRB_POSTPROCESS,					9 ),
     55 	ASSERT_ENUM_STRING( MRB_GPU_SYNC,						10 ),
     56 	ASSERT_ENUM_STRING( MRB_END_FRAME,						11 ),
     57 	ASSERT_ENUM_STRING( MRB_BINK_FRAME,						12 ),
     58 	ASSERT_ENUM_STRING( MRB_BINK_NEXT_FRAME,				13 ),
     59 	ASSERT_ENUM_STRING( MRB_TOTAL,							14 ),
     60 	ASSERT_ENUM_STRING( MRB_MAX,							15 )
     61 };
     62 
     63 extern uint64 Sys_Microseconds();
     64 /*
     65 ================================================================================================
     66 
     67 PIX events on all platforms
     68 
     69 ================================================================================================
     70 */
     71 
     72 
     73 /*
     74 ================================================
     75 pixEvent_t 
     76 ================================================
     77 */
     78 struct pixEvent_t {
     79 	char		name[256];
     80 	uint64		cpuTime;
     81 	uint64		gpuTime;
     82 };
     83 
     84 idCVar r_pix( "r_pix", "0", CVAR_INTEGER, "print GPU/CPU event timing" );
     85 
     86 static const int	MAX_PIX_EVENTS = 256;
     87 // defer allocation of this until needed, so we don't waste lots of memory
     88 pixEvent_t *		pixEvents;	// [MAX_PIX_EVENTS]
     89 int					numPixEvents;
     90 int					numPixLevels;
     91 static GLuint		timeQueryIds[MAX_PIX_EVENTS];
     92 
     93 /*
     94 ========================
     95 PC_BeginNamedEvent
     96 
     97 FIXME: this is not thread safe on the PC
     98 ========================
     99 */
    100 void PC_BeginNamedEvent( const char *szName, ... ) {
    101 #if 0
    102 	if ( !r_pix.GetBool() ) {
    103 		return;
    104 	}
    105 	if ( !pixEvents ) {
    106 		// lazy allocation to not waste memory
    107 		pixEvents = (pixEvent_t *)Mem_ClearedAlloc( sizeof( *pixEvents ) * MAX_PIX_EVENTS, TAG_CRAP );
    108 	}
    109 	if ( numPixEvents >= MAX_PIX_EVENTS ) {
    110 		idLib::FatalError( "PC_BeginNamedEvent: event overflow" );
    111 	}
    112 	if ( ++numPixLevels > 1 ) {
    113 		return;	// only get top level timing information
    114 	}
    115 	if ( !qglGetQueryObjectui64vEXT ) {
    116 		return;
    117 	}
    118 
    119 	GL_CheckErrors();
    120 	if ( timeQueryIds[0] == 0 ) {
    121 		qglGenQueriesARB( MAX_PIX_EVENTS, timeQueryIds );
    122 	}
    123 	qglFinish();
    124 	qglBeginQueryARB( GL_TIME_ELAPSED_EXT, timeQueryIds[numPixEvents] );
    125 	GL_CheckErrors();
    126 
    127 	pixEvent_t *ev = &pixEvents[numPixEvents++];
    128 	strncpy( ev->name, szName, sizeof( ev->name ) - 1 );
    129 	ev->cpuTime = Sys_Microseconds();
    130 #endif
    131 }
    132 
    133 /*
    134 ========================
    135 PC_EndNamedEvent
    136 ========================
    137 */
    138 void PC_EndNamedEvent() {
    139 #if 0
    140 	if ( !r_pix.GetBool() ) {
    141 		return;
    142 	}
    143 	if ( numPixLevels <= 0 ) {
    144 		idLib::FatalError( "PC_EndNamedEvent: level underflow" );
    145 	}
    146 	if ( --numPixLevels > 0 ) {
    147 		// only do timing on top level events
    148 		return;
    149 	}
    150 	if ( !qglGetQueryObjectui64vEXT ) {
    151 		return;
    152 	}
    153 
    154 	pixEvent_t *ev = &pixEvents[numPixEvents-1];
    155 	ev->cpuTime = Sys_Microseconds() - ev->cpuTime;
    156 
    157 	GL_CheckErrors();
    158 	qglEndQueryARB( GL_TIME_ELAPSED_EXT );
    159 	GL_CheckErrors();
    160 #endif
    161 }
    162 
    163 /*
    164 ========================
    165 PC_EndFrame
    166 ========================
    167 */
    168 void PC_EndFrame() {
    169 #if 0
    170 	if ( !r_pix.GetBool() ) {
    171 		return;
    172 	}
    173 
    174 	int64 totalGPU = 0;
    175 	int64 totalCPU = 0;
    176 
    177 	idLib::Printf( "----- GPU Events -----\n" );
    178 	for ( int i = 0 ; i < numPixEvents ; i++ ) {
    179 		pixEvent_t *ev = &pixEvents[i];
    180 
    181 		int64 gpuTime = 0;
    182 		qglGetQueryObjectui64vEXT( timeQueryIds[i], GL_QUERY_RESULT, (GLuint64EXT *)&gpuTime );
    183 		ev->gpuTime = gpuTime;
    184 
    185 		idLib::Printf( "%2d: %1.2f (GPU) %1.3f (CPU) = %s\n", i, ev->gpuTime / 1000000.0f, ev->cpuTime / 1000.0f, ev->name );
    186 		totalGPU += ev->gpuTime;
    187 		totalCPU += ev->cpuTime;
    188 	}
    189 	idLib::Printf( "%2d: %1.2f (GPU) %1.3f (CPU) = total\n", numPixEvents, totalGPU / 1000000.0f, totalCPU / 1000.0f );
    190 	memset( pixEvents, 0, numPixLevels * sizeof( pixEvents[0] ) );
    191 	
    192 	numPixEvents = 0;
    193 	numPixLevels = 0;
    194 #endif
    195 }
    196 
    197 
    198 /*
    199 ================================================================================================
    200 
    201 idRenderLog
    202 
    203 ================================================================================================
    204 */
    205 
    206 idRenderLog	renderLog;
    207 
    208 #if !defined( STUB_RENDER_LOG )
    209 
    210 /*
    211 ========================
    212 idRenderLog::idRenderLog
    213 ========================
    214 */
    215 idRenderLog::idRenderLog() {
    216 	activeLevel = 0;
    217 	indentString[0] = '\0';
    218 	indentLevel = 0;
    219 	logFile = NULL;
    220 
    221 	frameStartTime = 0;
    222 	closeBlockTime = 0;
    223 	logLevel = 0;
    224 }
    225 
    226 /*
    227 ========================
    228 idRenderLog::StartFrame
    229 ========================
    230 */
    231 void idRenderLog::StartFrame() {
    232 	if ( r_logFile.GetInteger() == 0 ) {
    233 		return;
    234 	}
    235 
    236 	// open a new logfile
    237 	indentLevel = 0;
    238 	indentString[0] = '\0';
    239 	activeLevel = r_logLevel.GetInteger();
    240 
    241 	struct tm		*newtime;
    242 	time_t			aclock;
    243 
    244 	char ospath[ MAX_OSPATH ];
    245 
    246 	char qpath[128];
    247 	sprintf( qpath, "renderlogPC_%04i.txt", r_logFile.GetInteger() );
    248 	idStr finalPath = fileSystem->RelativePathToOSPath( qpath );		
    249 	sprintf( ospath, "%s", finalPath.c_str() );
    250 	/*
    251 	for ( int i = 0; i < 9999 ; i++ ) {
    252 		char qpath[128];
    253 		sprintf( qpath, "renderlog_%04i.txt", r_logFile.GetInteger() );
    254 		idStr finalPath = fileSystem->RelativePathToOSPath( qpath );
    255 		fileSystem->RelativePathToOSPath( qpath, ospath, MAX_OSPATH ,FSPATH_BASE );
    256 		if ( !fileSystem->FileExists( finalPath.c_str() ) ) {
    257 			break; // use this name
    258 		}
    259 	}
    260 	*/
    261 
    262 	common->SetRefreshOnPrint( false );	// problems are caused if this print causes a refresh...
    263 
    264 	if ( logFile != NULL ) {
    265 		fileSystem->CloseFile( logFile );
    266 		logFile = NULL;
    267 	}
    268 
    269 	logFile = fileSystem->OpenFileWrite( ospath );	
    270 	if ( logFile == NULL ) {
    271 		idLib::Warning( "Failed to open logfile %s", ospath );
    272 		return;
    273 	}
    274 	idLib::Printf( "Opened logfile %s\n", ospath );
    275 
    276 	// write the time out to the top of the file
    277 	time( &aclock );
    278 	newtime = localtime( &aclock );
    279 	const char *str = asctime( newtime );
    280 	logFile->Printf( "// %s", str );
    281 	logFile->Printf( "// %s\n\n", com_version.GetString() );
    282 
    283 	frameStartTime = Sys_Microseconds();
    284 	closeBlockTime = frameStartTime;
    285 	OpenBlock( "Frame" );
    286 }
    287 
    288 /*
    289 ========================
    290 idRenderLog::EndFrame
    291 ========================
    292 */
    293 void idRenderLog::EndFrame() {
    294 	PC_EndFrame();
    295 
    296 	if ( logFile != NULL ) {
    297 		if ( r_logFile.GetInteger() == 1 ) {
    298 			Close();
    299 		}
    300 		// log is open, so decrement r_logFile and stop if it is zero
    301 		r_logFile.SetInteger( r_logFile.GetInteger() - 1 );
    302 		idLib::Printf( "Frame logged.\n" );
    303 		return;
    304 	}
    305 }
    306 
    307 /*
    308 ========================
    309 idRenderLog::Close
    310 ========================
    311 */
    312 void idRenderLog::Close() {
    313 	if ( logFile != NULL ) {
    314 		CloseBlock();
    315 		idLib::Printf( "Closing logfile\n" );
    316 		fileSystem->CloseFile( logFile );
    317 		logFile = NULL;
    318 		activeLevel = 0;
    319 	}
    320 }
    321 
    322 /*
    323 ========================
    324 idRenderLog::OpenMainBlock
    325 ========================
    326 */
    327 void idRenderLog::OpenMainBlock( renderLogMainBlock_t block ) {
    328 }
    329 
    330 /*
    331 ========================
    332 idRenderLog::CloseMainBlock
    333 ========================
    334 */
    335 void idRenderLog::CloseMainBlock() {
    336 }
    337 
    338 /*
    339 ========================
    340 idRenderLog::OpenBlock
    341 ========================
    342 */
    343 void idRenderLog::OpenBlock( const char *label ) {
    344 	// Allow the PIX functionality even when logFile is not running.
    345 	PC_BeginNamedEvent( label );
    346 
    347 	if ( logFile != NULL ) {
    348 		LogOpenBlock( RENDER_LOG_INDENT_MAIN_BLOCK, label, NULL );
    349 	}
    350 }
    351 
    352 /*
    353 ========================
    354 idRenderLog::CloseBlock
    355 ========================
    356 */
    357 void idRenderLog::CloseBlock() {
    358 	PC_EndNamedEvent();
    359 
    360 	if ( logFile != NULL ) {
    361 		LogCloseBlock( RENDER_LOG_INDENT_MAIN_BLOCK );
    362 	}
    363 }
    364 
    365 /*
    366 ========================
    367 idRenderLog::Printf
    368 ========================
    369 */
    370 void idRenderLog::Printf( const char *fmt, ... ) {
    371 	if ( activeLevel <= LOG_LEVEL_BLOCKS_ONLY ) {
    372 		return;
    373 	}
    374 
    375 	if ( logFile == NULL ) {
    376 		return;
    377 	}
    378 
    379 	va_list marker;
    380 	logFile->Printf( "%s", indentString );
    381 	va_start( marker, fmt );
    382 	logFile->VPrintf( fmt, marker );
    383 	va_end( marker );
    384 //	logFile->Flush();		this makes it take waaaay too long
    385 }
    386 
    387 /*
    388 ========================
    389 idRenderLog::LogOpenBlock
    390 ========================
    391 */
    392 void idRenderLog::LogOpenBlock( renderLogIndentLabel_t label, const char * fmt, va_list args ) {
    393 
    394 	uint64 now = Sys_Microseconds();
    395 
    396 	if ( logFile != NULL ) {
    397 		if ( now - closeBlockTime >= 1000 ) {
    398 			logFile->Printf( "%s%1.1f msec gap from last closeblock\n", indentString, ( now - closeBlockTime ) * ( 1.0f / 1000.0f ) );
    399 		}
    400 		logFile->Printf( "%s", indentString );
    401 		logFile->VPrintf( fmt, args );
    402 		logFile->Printf( " {\n" );
    403 	}
    404 
    405 	Indent( label );
    406 
    407 	if ( logLevel >= MAX_LOG_LEVELS ) {
    408 		idLib::Warning( "logLevel %d >= MAX_LOG_LEVELS", logLevel );
    409 	}
    410 
    411 
    412 	logLevel++;
    413 }
    414 
    415 /*
    416 ========================
    417 idRenderLog::LogCloseBlock
    418 ========================
    419 */
    420 void idRenderLog::LogCloseBlock( renderLogIndentLabel_t label ) {
    421 	closeBlockTime = Sys_Microseconds();
    422 
    423 	assert( logLevel > 0 );
    424 	logLevel--;
    425 
    426 	Outdent( label );
    427 
    428 	if ( logFile != NULL ) {
    429 	}
    430 }
    431 
    432 #else	// !STUB_RENDER_LOG
    433 
    434 /*
    435 ========================
    436 idRenderLog::OpenBlock
    437 ========================
    438 */
    439 void idRenderLog::OpenBlock( const char *label ) {
    440 	PC_BeginNamedEvent( label );
    441 }
    442 
    443 /*
    444 ========================
    445 idRenderLog::CloseBlock
    446 ========================
    447 */
    448 void idRenderLog::CloseBlock() {
    449 	PC_EndNamedEvent();
    450 }
    451 
    452 #endif // !STUB_RENDER_LOG