Ejemplo n.º 1
0
void	idBoundsTrack::Test()
{
	ClearAll();
	idRandom	r;
	
	for( int i = 0 ; i < 1800 ; i++ )
	{
		idBounds b;
		for( int j = 0 ; j < 3 ; j++ )
		{
			b[0][j] = r.RandomInt( 20000 ) - 10000;
			b[1][j] = b[0][j] + r.RandomInt( 1000 );
		}
		SetIndex( i, b );
	}
	
	const idBounds testBounds( idVec3( -1000, 2000, -3000 ), idVec3( 1500, 4500, -500 ) );
	SetIndex( 1800, testBounds );
	SetIndex( 0, testBounds );
	
	const shortBounds_t	shortTestBounds( testBounds );
	
	int intersectedIndexes1[ MAX_BOUNDS_TRACK_INDEXES ];
	const int numHits1 = FindBoundsIntersectionsTEST( shortTestBounds, boundsList, maxIndex, intersectedIndexes1 );
	
	int intersectedIndexes2[ MAX_BOUNDS_TRACK_INDEXES ];
	const int numHits2 = FindBoundsIntersectionsSimSIMD( shortTestBounds, boundsList, maxIndex, intersectedIndexes2 );
	idLib::Printf( "%i intersections\n", numHits1 );
	if( numHits1 != numHits2 )
	{
		idLib::Printf( "different results\n" );
	}
	else
	{
		for( int i = 0 ; i < numHits1 ; i++ )
		{
			if( intersectedIndexes1[i] != intersectedIndexes2[i] )
			{
				idLib::Printf( "different results\n" );
				break;
			}
		}
	}
	
	// run again for debugging failure
	FindBoundsIntersectionsTEST( shortTestBounds, boundsList, maxIndex, intersectedIndexes1 );
	FindBoundsIntersectionsSimSIMD( shortTestBounds, boundsList, maxIndex, intersectedIndexes2 );
	
	// timing
	const int64 start = Sys_Microseconds();
	for( int i = 0 ; i < 40 ; i++ )
	{
		FindBoundsIntersectionsSimSIMD( shortTestBounds, boundsList, maxIndex, intersectedIndexes2 );
	}
	const int64 stop = Sys_Microseconds();
	idLib::Printf( "%" PRId64 " microseconds for 40 itterations\n", stop - start );
}
Ejemplo n.º 2
0
/*
* CL_MouseExtrapolate
* asymptotic extrapolation function
*/
static void CL_MouseExtrapolate( int mx, int my, float *extra_x, float *extra_y )
{

	static unsigned int frameNo = 0;
	static float sub_x = 0, sub_y = 0;
	static int64_t lastMicros = 0;
	static int64_t avgMicros = 0;

	float add_x = 0.0, add_y = 0.0;
	float decay = 1.0;
	float decaySum = buf_size > 1 ? 0.0 : decay;
	unsigned int i;

	int64_t micros;
	if( !lastMicros )
		lastMicros = Sys_Microseconds() - 10000;    // start at 100 FPS
	micros = Sys_Microseconds();                        // get current time in us
	avgMicros = ( avgMicros + ( micros - lastMicros ) ) / 2; // calc running avg of us per frame

	assert( buf_size );
	frameNo = ( frameNo + 1 ) % buf_size;   // we use the buffer in a cyclic fashion

	// normalize mouse movement to pixels per microsecond
	buf_x[frameNo] = mx / (float) avgMicros;
	buf_y[frameNo] = my / (float) avgMicros;

	// calculate asymptotically weighted sum of movement over the last few frames
	assert( buf_decay >= 0.0 );
	for( i = 0; i < buf_size; ++i )
	{
		const unsigned int f = ( frameNo-i ) % buf_size;
		assert( f <= buf_size );
		add_x += buf_x[f] * decay;
		add_y += buf_y[f] * decay;
		decaySum += decay;
		decay *= buf_decay;
	}
	assert( decaySum >= 1.0 );
	add_x /= decaySum;
	add_y /= decaySum;

	// calculate difference to last frame and re-weigh it with avg us per frame
	// we need to extrapolate the delta, not the momentum alone, so the mouse will come to
	// rest at the same spot ultimately, regardless of extrapolation on or off
	*extra_x = ( add_x - sub_x ) * avgMicros;
	*extra_y = ( add_y - sub_y ) * avgMicros;

	sub_x = add_x;
	sub_y = add_y;
	lastMicros = micros;
}
/*
========================
idParallelJobList_Threads::RunJobs
========================
*/
int idParallelJobList_Threads::RunJobs( unsigned int threadNum, threadJobListState_t& state, bool singleJob )
{
	uint64 start = Sys_Microseconds();
	
	numThreadsExecuting.Increment();
	
	int result = RunJobsInternal( threadNum, state, singleJob );
	
	numThreadsExecuting.Decrement();
	
	deferredThreadStats.threadTotalTime[threadNum] += Sys_Microseconds() - start;
	
	return result;
}
Ejemplo n.º 4
0
/*
========================
idLobby::UpdateSnaps
========================
*/
void idLobby::UpdateSnaps()
{

	assert( lobbyType == GetActingGameStateLobbyType() );
	
	SCOPED_PROFILE_EVENT( "UpdateSnaps" );
	
#if 0
	uint64 startTimeMicroSec = Sys_Microseconds();
#endif
	
	haveSubmittedSnaps = false;
	
	if( !SendCompletedSnaps() )
	{
		// If we weren't able to send all the submitted snaps, we need to wait till we can.
		// We can't start new jobs until they are all sent out.
		return;
	}
	
	for( int p = 0; p < peers.Num(); p++ )
	{
		peer_t& peer = peers[p];
		
		if( !peer.IsConnected() )
		{
			continue;
		}
		
		if( peer.needToSubmitPendingSnap )
		{
			// Submit the snap
			if( SubmitPendingSnap( p ) )
			{
				peer.needToSubmitPendingSnap = false;	// only clear this if we actually submitted the snap
			}
			
		}
	}
	
#if 0
	uint64 endTimeMicroSec = Sys_Microseconds();
	
	if( endTimeMicroSec - startTimeMicroSec > 200 )  	// .2 ms
	{
		idLib::Printf( "NET: UpdateSnaps time in ms: %f\n", ( float )( endTimeMicroSec - startTimeMicroSec ) / 1000.0f );
	}
#endif
}
Ejemplo n.º 5
0
/*
========================
GLimp_TestSwapBuffers
========================
*/
void GLimp_TestSwapBuffers( const idCmdArgs &args ) {
#if !NGD_USE_OPENGL_ES_2_0
    idLib::Printf( "GLimp_TimeSwapBuffers\n" );
    static const int MAX_FRAMES = 5;
    uint64	timestamps[MAX_FRAMES];
    glDisable( GL_SCISSOR_TEST );

    int frameMilliseconds = 16;
    for ( int swapInterval = 2 ; swapInterval >= -1 ; swapInterval-- ) {
        wglSwapIntervalEXT( swapInterval );
        for ( int i = 0 ; i < MAX_FRAMES ; i++ ) {
            if ( swapInterval == -1 ) {
                Sys_Sleep( frameMilliseconds );
            }
            if ( i & 1 ) {
                glClearColor( 0, 1, 0, 1 );
            } else {
                glClearColor( 1, 0, 0, 1 );
            }
            glClear( GL_COLOR_BUFFER_BIT );
            ::SwapBuffers( win32.hDC );
            glFinish();
            timestamps[i] = Sys_Microseconds();
        }

        idLib::Printf( "\nswapinterval %i\n", swapInterval );
        for ( int i = 1 ; i < MAX_FRAMES ; i++ ) {
            idLib::Printf( "%i microseconds\n", (int)(timestamps[i] - timestamps[i-1]) );
        }
    }
#else
    NGD_MISSING_FUNCTIONALITY;
#endif // !NGD_USE_OPENGL_ES_2_0
}
Ejemplo n.º 6
0
/*
========================
PC_BeginNamedEvent

FIXME: this is not thread safe on the PC
========================
*/
void PC_BeginNamedEvent( const char *szName, ... ) {
#if 0
	if ( !r_pix.GetBool() ) {
		return;
	}
	if ( !pixEvents ) {
		// lazy allocation to not waste memory
		pixEvents = (pixEvent_t *)Mem_ClearedAlloc( sizeof( *pixEvents ) * MAX_PIX_EVENTS, TAG_CRAP );
	}
	if ( numPixEvents >= MAX_PIX_EVENTS ) {
		idLib::FatalError( "PC_BeginNamedEvent: event overflow" );
	}
	if ( ++numPixLevels > 1 ) {
		return;	// only get top level timing information
	}
	if ( !glGetQueryObjectui64vEXT ) {
		return;
	}

	GL_CheckErrors();
	if ( timeQueryIds[0] == 0 ) {
		glGenQueries( MAX_PIX_EVENTS, timeQueryIds );
	}
	glFinish();
	glBeginQuery( GL_TIME_ELAPSED_EXT, timeQueryIds[numPixEvents] );
	GL_CheckErrors();

	pixEvent_t *ev = &pixEvents[numPixEvents++];
	strncpy( ev->name, szName, sizeof( ev->name ) - 1 );
	ev->cpuTime = Sys_Microseconds();
#endif
}
Ejemplo n.º 7
0
/*
========================
idRenderLog::StartFrame
========================
*/
void idRenderLog::StartFrame() {
	if ( r_logFile.GetInteger() == 0 ) {
		return;
	}

	// open a new logfile
	indentLevel = 0;
	indentString[0] = '\0';
	activeLevel = r_logLevel.GetInteger();

	struct tm		*newtime;
	time_t			aclock;

	char ospath[ MAX_OSPATH ];

	char qpath[128];
	sprintf( qpath, "renderlogPC_%04i.txt", r_logFile.GetInteger() );
	idStr finalPath = fileSystem->RelativePathToOSPath( qpath );		
	sprintf( ospath, "%s", finalPath.c_str() );
	/*
	for ( int i = 0; i < 9999 ; i++ ) {
		char qpath[128];
		sprintf( qpath, "renderlog_%04i.txt", r_logFile.GetInteger() );
		idStr finalPath = fileSystem->RelativePathToOSPath( qpath );
		fileSystem->RelativePathToOSPath( qpath, ospath, MAX_OSPATH ,FSPATH_BASE );
		if ( !fileSystem->FileExists( finalPath.c_str() ) ) {
			break; // use this name
		}
	}
	*/

	common->SetRefreshOnPrint( false );	// problems are caused if this print causes a refresh...

	if ( logFile != NULL ) {
		fileSystem->CloseFile( logFile );
		logFile = NULL;
	}

	logFile = fileSystem->OpenFileWrite( ospath );	
	if ( logFile == NULL ) {
		idLib::Warning( "Failed to open logfile %s", ospath );
		return;
	}
	idLib::Printf( "Opened logfile %s\n", ospath );

	// write the time out to the top of the file
	time( &aclock );
	newtime = localtime( &aclock );
	const char *str = asctime( newtime );
	logFile->Printf( "// %s", str );
	logFile->Printf( "// %s\n\n", com_version.GetString() );

	frameStartTime = Sys_Microseconds();
	closeBlockTime = frameStartTime;
	OpenBlock( "Frame" );
}
/*
========================
idParallelJobList_Threads::Submit
========================
*/
void idParallelJobList_Threads::Submit( idParallelJobList_Threads* waitForJobList, int parallelism )
{
	assert( done );
	assert( numSyncs <= maxSyncs );
	assert( ( unsigned int ) jobList.Num() <= maxJobs + numSyncs * 2 );
	assert( fetchLock.GetValue() == 0 );
	
	done = false;
	currentJob.SetValue( 0 );
	
	memset( &deferredThreadStats, 0, sizeof( deferredThreadStats ) );
	deferredThreadStats.numExecutedJobs = jobList.Num() - numSyncs * 2;
	deferredThreadStats.numExecutedSyncs = numSyncs;
	deferredThreadStats.submitTime = Sys_Microseconds();
	deferredThreadStats.startTime = 0;
	deferredThreadStats.endTime = 0;
	deferredThreadStats.waitTime = 0;
	
	if( jobList.Num() == 0 )
	{
		return;
	}
	
	if( waitForJobList != NULL )
	{
		waitForGuard = & waitForJobList->doneGuards[waitForJobList->currentDoneGuard];
	}
	else
	{
		waitForGuard = NULL;
	}
	
	currentDoneGuard = ( currentDoneGuard + 1 ) & ( NUM_DONE_GUARDS - 1 );
	doneGuards[currentDoneGuard].SetValue( 1 );
	
	signalJobCount.Alloc();
	signalJobCount[signalJobCount.Num() - 1].SetValue( jobList.Num() - lastSignalJob );
	
	job_t& job = jobList.Alloc();
	job.function = Nop;
	job.data = & JOB_LIST_DONE;
	
	if( threaded )
	{
		// hand over to the manager
		void SubmitJobList( idParallelJobList_Threads * jobList, int parallelism );
		SubmitJobList( this, parallelism );
	}
	else
	{
		// run all the jobs right here
		threadJobListState_t state( GetVersion() );
		RunJobs( 0, state, false );
	}
}
Ejemplo n.º 9
0
int Sys_Milliseconds (void)
{

	/*	ioq3-urt: We have moved initialization to Sys_InitTimers()
		notice SDL puts timeGetTime's precision to 1ms with timeBeginTime(1) */

	if (clu.sys_microGranularity->integer)	
		return Sys_Microseconds() / 1000;  // hopefully, but somewhat unlikely, more precise
	else	
		return timeGetTime() - microdifference;
}
Ejemplo n.º 10
0
/*
========================
idRenderLog::LogCloseBlock
========================
*/
void idRenderLog::LogCloseBlock( renderLogIndentLabel_t label ) {
	closeBlockTime = Sys_Microseconds();

	assert( logLevel > 0 );
	logLevel--;

	Outdent( label );

	if ( logFile != NULL ) {
	}
}
Ejemplo n.º 11
0
static dynvar_get_status_t Com_Sys_Uptime_f( void **val )
{
	static char buf[32];
	const quint64 us = Sys_Microseconds();
	const unsigned int h = us / 3600000000u;
	const unsigned int min = ( us / 60000000 ) % 60;
	const unsigned int sec = ( us / 1000000 ) % 60;
	const unsigned int usec = us % 1000000;
	sprintf( buf, "%02u:%02u:%02u.%06u", h, min, sec, usec );
	*val = buf;
	return DYNVAR_GET_OK;
}
/*
========================
idParallelJobList_Threads::Wait
========================
*/
void idParallelJobList_Threads::Wait()
{
	if( jobList.Num() > 0 )
	{
		// don't lock up but return if the job list was never properly submitted
		if( !verify( !done && signalJobCount.Num() > 0 ) )
		{
			return;
		}
		
		bool waited = false;
		uint64 waitStart = Sys_Microseconds();
		
		while( signalJobCount[signalJobCount.Num() - 1].GetValue() > 0 )
		{
			Sys_Yield();
			waited = true;
		}
		version.Increment();
		while( numThreadsExecuting.GetValue() > 0 )
		{
			Sys_Yield();
			waited = true;
		}
		
		jobList.SetNum( 0 );
		signalJobCount.SetNum( 0 );
		numSyncs = 0;
		lastSignalJob = 0;
		
		uint64 waitEnd = Sys_Microseconds();
		deferredThreadStats.waitTime = waited ? ( waitEnd - waitStart ) : 0;
	}
	memcpy( & threadStats, & deferredThreadStats, sizeof( threadStats ) );
	done = true;
}
Ejemplo n.º 13
0
/*
========================
idRenderLog::LogOpenBlock
========================
*/
void idRenderLog::LogOpenBlock( renderLogIndentLabel_t label, const char * fmt, va_list args ) {

	uint64 now = Sys_Microseconds();

	if ( logFile != NULL ) {
		if ( now - closeBlockTime >= 1000 ) {
			logFile->Printf( "%s%1.1f msec gap from last closeblock\n", indentString, ( now - closeBlockTime ) * ( 1.0f / 1000.0f ) );
		}
		logFile->Printf( "%s", indentString );
		logFile->VPrintf( fmt, args );
		logFile->Printf( " {\n" );
	}

	Indent( label );

	if ( logLevel >= MAX_LOG_LEVELS ) {
		idLib::Warning( "logLevel %d >= MAX_LOG_LEVELS", logLevel );
	}


	logLevel++;
}
Ejemplo n.º 14
0
/*
========================
PC_EndNamedEvent
========================
*/
void PC_EndNamedEvent() {
#if 0
	if ( !r_pix.GetBool() ) {
		return;
	}
	if ( numPixLevels <= 0 ) {
		idLib::FatalError( "PC_EndNamedEvent: level underflow" );
	}
	if ( --numPixLevels > 0 ) {
		// only do timing on top level events
		return;
	}
	if ( !glGetQueryObjectui64vEXT ) {
		return;
	}

	pixEvent_t *ev = &pixEvents[numPixEvents-1];
	ev->cpuTime = Sys_Microseconds() - ev->cpuTime;

	GL_CheckErrors();
	glEndQuery( GL_TIME_ELAPSED_EXT );
	GL_CheckErrors();
#endif
}
Ejemplo n.º 15
0
/*
 * Windows main function. Containts the
 * initialization code and the main loop
 */
int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
		LPSTR lpCmdLine, int nCmdShow)
{
	MSG msg;
	long long oldtime, newtime;

	/* Previous instances do not exist in Win32 */
	if (hPrevInstance)
	{
		return 0;
	}

	/* Make the current instance global */
	global_hInstance = hInstance;

	/* Setup FPU if necessary */
	Sys_SetupFPU();

	/* Force DPI awareness */
	Sys_SetHighDPIMode();

	/* Parse the command line arguments */
	ParseCommandLine(lpCmdLine);

	/* Are we portable? */
	for (int i = 0; i < argc; i++) {
		if (strcmp(argv[i], "-portable") == 0) {
			is_portable = true;
		}
	}

	/* Need to redirect stdout before anything happens. */
#ifndef DEDICATED_ONLY
	Sys_RedirectStdout();
#endif

	printf("Yamagi Quake II v%s\n", YQ2VERSION);
	printf("=====================\n\n");

#ifndef DEDICATED_ONLY
	printf("Client build options:\n");
#ifdef SDL2
	printf(" + SDL2\n");
#else
	printf(" - SDL2 (using 1.2)\n");
#endif
#ifdef CDA
	printf(" + CD audio\n");
#else
	printf(" - CD audio\n");
#endif
#ifdef OGG
	printf(" + OGG/Vorbis\n");
#else
	printf(" - OGG/Vorbis\n");
#endif
#ifdef USE_OPENAL
	printf(" + OpenAL audio\n");
#else
	printf(" - OpenAL audio\n");
#endif
#ifdef ZIP
	printf(" + Zip file support\n");
#else
	printf(" - Zip file support\n");
#endif
#endif

	printf("Platform: %s\n", YQ2OSTYPE);
	printf("Architecture: %s\n", YQ2ARCH);


	/* Seed PRNG */
	randk_seed();

	/* Call the initialization code */
	Qcommon_Init(argc, argv);

	/* Save our time */
	oldtime = Sys_Microseconds();

	/* The legendary main loop */
	while (1)
	{
		/* If at a full screen console, don't update unless needed */
		if (Minimized || (dedicated && dedicated->value))
		{
			Sleep(1);
		}

		while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
		{
			if (!GetMessage(&msg, NULL, 0, 0))
			{
				Com_Quit();
			}

			sys_msg_time = msg.time;
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		// Throttle the game a little bit
		Sys_Nanosleep(5000);

		newtime = Sys_Microseconds();
		Qcommon_Frame(newtime - oldtime);
		oldtime = newtime;
	}

	/* never gets here */
	return TRUE;
}
Ejemplo n.º 16
0
/*
=================
R_AddLights
=================
*/
void R_AddLights()
{
	SCOPED_PROFILE_EVENT( "R_AddLights" );
	
	//-------------------------------------------------
	// check each light individually, possibly in parallel
	//-------------------------------------------------
	
	if( r_useParallelAddLights.GetBool() )
	{
		for( viewLight_t* vLight = tr.viewDef->viewLights; vLight != NULL; vLight = vLight->next )
		{
			tr.frontEndJobList->AddJob( ( jobRun_t )R_AddSingleLight, vLight );
		}
		tr.frontEndJobList->Submit();
		tr.frontEndJobList->Wait();
	}
	else
	{
		for( viewLight_t* vLight = tr.viewDef->viewLights; vLight != NULL; vLight = vLight->next )
		{
			R_AddSingleLight( vLight );
		}
	}
	
	//-------------------------------------------------
	// cull lights from the list if they turned out to not be needed
	//-------------------------------------------------
	
	tr.pc.c_viewLights = 0;
	viewLight_t** ptr = &tr.viewDef->viewLights;
	while( *ptr != NULL )
	{
		viewLight_t* vLight = *ptr;
		
		if( vLight->removeFromList )
		{
			vLight->lightDef->viewCount = -1;	// this probably doesn't matter with current code
			*ptr = vLight->next;
			continue;
		}
		
		ptr = &vLight->next;
		
		// serial work
		tr.pc.c_viewLights++;
		
		for( shadowOnlyEntity_t* shadEnt = vLight->shadowOnlyViewEntities; shadEnt != NULL; shadEnt = shadEnt->next )
		{
			// this will add it to the viewEntities list, but with an empty scissor rect
			R_SetEntityDefViewEntity( shadEnt->edef );
		}
		
		if( r_showLightScissors.GetBool() )
		{
			R_ShowColoredScreenRect( vLight->scissorRect, vLight->lightDef->index );
		}
	}
	
	//-------------------------------------------------
	// Add jobs to setup pre-light shadow volumes.
	//-------------------------------------------------
	
	if( r_useParallelAddShadows.GetInteger() == 1 )
	{
		for( viewLight_t* vLight = tr.viewDef->viewLights; vLight != NULL; vLight = vLight->next )
		{
			for( preLightShadowVolumeParms_t* shadowParms = vLight->preLightShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
			{
				tr.frontEndJobList->AddJob( ( jobRun_t )PreLightShadowVolumeJob, shadowParms );
			}
			vLight->preLightShadowVolumes = NULL;
		}
	}
	else
	{
		int start = Sys_Microseconds();
		
		for( viewLight_t* vLight = tr.viewDef->viewLights; vLight != NULL; vLight = vLight->next )
		{
			for( preLightShadowVolumeParms_t* shadowParms = vLight->preLightShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
			{
				PreLightShadowVolumeJob( shadowParms );
			}
			vLight->preLightShadowVolumes = NULL;
		}
		
		int end = Sys_Microseconds();
		tr.backend.pc.shadowMicroSec += end - start;
	}
}
Ejemplo n.º 17
0
int
Sys_Milliseconds(void)
{
	return (int)(Sys_Microseconds()/1000ll);
}
/*
========================
idCommonLocal::RunNetworkSnapshotFrame
========================
*/
void idCommonLocal::RunNetworkSnapshotFrame() {

    // Process any reliable messages we've received
    for ( int i = 0; i < reliableQueue.Num(); i++ ) {
        game->ProcessReliableMessage( reliableQueue[i].client, reliableQueue[i].type, idBitMsg( (const byte *)reliableQueue[i].data, reliableQueue[i].dataSize ) );
        Mem_Free( reliableQueue[i].data );
    }
    reliableQueue.Clear();

    // abuse the game timing to time presentable thinking on clients
    time_gameFrame = Sys_Microseconds();
    time_maxGameFrame = 0;
    count_numGameFrames = 0;

    if ( snapPrevious.serverTime >= 0 ) {

        int	msec_interval = 1 + idMath::Ftoi( (float)initialBaseTicksPerSec  );

        static int clientTimeResidual = 0;
        static int lastTime = Sys_Milliseconds();
        int currentTime = Sys_Milliseconds();
        int deltaFrameTime = idMath::ClampInt( 1, 33, currentTime - lastTime );

        clientTimeResidual += idMath::ClampInt( 0, 50, currentTime - lastTime );
        lastTime = currentTime;

        extern idCVar com_fixedTic;
        if ( com_fixedTic.GetBool() ) {
            clientTimeResidual = 0;
        }

        do {
            // If we are extrapolating and have fresher snapshots, then use the freshest one
            while ( ( snapCurrentTime >= snapRate || com_forceLatestSnap.GetBool() ) && readSnapshotIndex < writeSnapshotIndex ) {
                snapCurrentTime -= snapRate;
                ProcessNextSnapshot();
            }

            // this only matters when running < 60 fps
            // JAF Game()->GetRenderWorld()->UpdateDeferredPositions();

            // Clamp the current time so that it doesn't fall outside of our extrapolation bounds
            snapCurrentTime = idMath::ClampInt( 0, snapRate + Min( (int)snapRate, (int)net_maxExtrapolationInMS.GetInteger() ), snapCurrentTime );

            if ( snapRate <= 0 ) {
                idLib::Warning("snapRate <= 0. Resetting to 100");
                snapRate = 100;
            }

            float fraction = (float)snapCurrentTime / (float)snapRate;
            if ( !IsValid( fraction ) ) {
                idLib::Warning("Interpolation Fraction invalid: snapCurrentTime %d / snapRate %d", (int)snapCurrentTime, (int)snapRate );
                fraction = 0.0f;
            }

            InterpolateSnapshot( snapPrevious, snapCurrent, fraction, true );

            // Default to a snap scale of 1
            float snapRateScale = net_interpolationBaseRate.GetFloat();

            snapTimeBuffered = CalcSnapTimeBuffered( totalBufferedTime, totalRecvTime );
            effectiveSnapRate = static_cast< float > ( totalBufferedTime ) / static_cast< float > ( totalRecvTime );

            if ( net_minBufferedSnapPCT_Static.GetFloat() > 0.0f ) {
                optimalPCTBuffer = session->GetTitleStorageFloat( "net_minBufferedSnapPCT_Static", net_minBufferedSnapPCT_Static.GetFloat() );
            }

            // Calculate optimal amount of buffered time we want
            if ( net_optimalDynamic.GetBool() ) {
                optimalTimeBuffered = idMath::ClampInt( 0, net_maxBufferedSnapMS.GetInteger(), snapRate * optimalPCTBuffer );
                optimalTimeBufferedWindow = snapRate * net_minBufferedSnapWinPCT_Static.GetFloat();
            } else {
                optimalTimeBuffered = net_optimalSnapTime.GetFloat();
                optimalTimeBufferedWindow = net_optimalSnapWindow.GetFloat();
            }

            // Scale snapRate based on where we are in the buffer
            if ( snapTimeBuffered <= optimalTimeBuffered ) {
                if ( snapTimeBuffered <= idMath::FLT_SMALLEST_NON_DENORMAL ) {
                    snapRateScale = 0;
                } else {
                    snapRateScale = net_interpolationFallbackRate.GetFloat();
                    // When we interpolate past our cushion of buffered snapshot, we want to slow smoothly slow the
                    // rate of interpolation. frac will go from 1.0 to 0.0 (if snapshots stop coming in).
                    float startSlowdown = ( net_interpolationSlowdownStart.GetFloat() * optimalTimeBuffered );
                    if ( startSlowdown > 0 && snapTimeBuffered < startSlowdown ) {
                        float frac = idMath::ClampFloat( 0.0f, 1.0f, snapTimeBuffered / startSlowdown );
                        if ( !IsValid( frac ) ) {
                            frac = 0.0f;
                        }
                        snapRateScale = Square( frac ) * snapRateScale;
                        if ( !IsValid( snapRateScale ) ) {
                            snapRateScale = 0.0f;
                        }
                    }
                }


            } else if ( snapTimeBuffered > optimalTimeBuffered + optimalTimeBufferedWindow ) {
                // Go faster
                snapRateScale = net_interpolationCatchupRate.GetFloat();

            }

            float delta_interpolate = (float)initialBaseTicksPerSec * snapRateScale;
            if ( net_effectiveSnapRateEnable.GetBool() ) {

                float deltaFrameGameMS = static_cast<float>( initialBaseTicksPerSec ) * static_cast<float>( deltaFrameTime / 1000.0f );
                delta_interpolate = ( deltaFrameGameMS * snapRateScale * effectiveSnapRate ) + snapCurrentResidual;
                if ( !IsValid( delta_interpolate ) ) {
                    delta_interpolate = 0.0f;
                }

                snapCurrentResidual = idMath::Frac( delta_interpolate ); // fixme: snapCurrentTime should just be a float, but would require changes in d4 too
                if ( !IsValid( snapCurrentResidual ) ) {
                    snapCurrentResidual = 0.0f;
                }

                if ( net_effectiveSnapRateDebug.GetBool() ) {
                    idLib::Printf("%d/%.2f snapRateScale: %.2f effectiveSR: %.2f d.interp: %.2f snapTimeBuffered: %.2f res: %.2f\n", deltaFrameTime, deltaFrameGameMS, snapRateScale, effectiveSnapRate, delta_interpolate, snapTimeBuffered, snapCurrentResidual );
                }
            }

            assert( IsValid( delta_interpolate ) );
            int interpolate_interval = idMath::Ftoi( delta_interpolate );

            snapCurrentTime += interpolate_interval;	// advance interpolation time by the scaled interpolate_interval
            clientTimeResidual -= msec_interval;		// advance local client residual time (fixed step)

        } while ( clientTimeResidual >= msec_interval );

        if ( clientTimeResidual < 0 ) {
            clientTimeResidual = 0;
        }
    }

    time_gameFrame = Sys_Microseconds() - time_gameFrame;
}
Ejemplo n.º 19
0
/*
===============
idGameThread::Run

Run in a background thread for performance, but can also
be called directly in the foreground thread for comparison.
===============
*/
int idGameThread::Run() {
	commonLocal.frameTiming.startGameTime = Sys_Microseconds();

	// debugging tool to test frame dropping behavior
	if ( com_sleepGame.GetInteger() ) {
		Sys_Sleep( com_sleepGame.GetInteger() );
	}

	if ( numGameFrames == 0 ) {
		// Ensure there's no stale gameReturn data from a paused game
		ret = gameReturn_t();
	}

	if ( isClient ) {
		// run the game logic
		for ( int i = 0; i < numGameFrames; i++ ) {
			SCOPED_PROFILE_EVENT( "Client Prediction" );
			if ( userCmdMgr ) {
				game->ClientRunFrame( *userCmdMgr, ( i == numGameFrames - 1 ), ret );
			}
			if ( ret.syncNextGameFrame || ret.sessionCommand[0] != 0 ) {
				break;
			}
		}
	} else {
		// run the game logic
		for ( int i = 0; i < numGameFrames; i++ ) {
			SCOPED_PROFILE_EVENT( "GameTic" );
			if ( userCmdMgr ) {
				game->RunFrame( *userCmdMgr, ret );
			}
			if ( ret.syncNextGameFrame || ret.sessionCommand[0] != 0 ) {
				break;
			}
		}
	}

	// we should have consumed all of our usercmds
	if ( userCmdMgr ) {
		if ( userCmdMgr->HasUserCmdForPlayer( game->GetLocalClientNum() ) && common->GetCurrentGame() == DOOM3_BFG ) {
			idLib::Printf( "idGameThread::Run: didn't consume all usercmds\n" );
		}
	}

	commonLocal.frameTiming.finishGameTime = Sys_Microseconds();

	SetThreadGameTime( ( commonLocal.frameTiming.finishGameTime - commonLocal.frameTiming.startGameTime ) / 1000 );

	// build render commands and geometry
	{
		SCOPED_PROFILE_EVENT( "Draw" );
		commonLocal.Draw();
	}

	commonLocal.frameTiming.finishDrawTime = Sys_Microseconds();

	SetThreadRenderTime( ( commonLocal.frameTiming.finishDrawTime - commonLocal.frameTiming.finishGameTime ) / 1000 );

	SetThreadTotalTime( ( commonLocal.frameTiming.finishDrawTime - commonLocal.frameTiming.startGameTime ) / 1000 );

	return 0;
}
/*
========================
idParallelJobList_Threads::RunJobsInternal
========================
*/
int idParallelJobList_Threads::RunJobsInternal( unsigned int threadNum, threadJobListState_t& state, bool singleJob )
{
	if( state.version != version.GetValue() )
	{
		// trying to run an old version of this list that is already done
		return RUN_DONE;
	}
	
	assert( threadNum < MAX_THREADS );
	
	if( deferredThreadStats.startTime == 0 )
	{
		deferredThreadStats.startTime = Sys_Microseconds();	// first time any thread is running jobs from this list
	}
	
	int result = RUN_OK;
	
	do
	{
	
		// run through all signals and syncs before the last job that has been or is being executed
		// this loop is really an optimization to minimize the time spent in the fetchLock section below
		for( ; state.lastJobIndex < ( int ) currentJob.GetValue() && state.lastJobIndex < jobList.Num(); state.lastJobIndex++ )
		{
			if( jobList[state.lastJobIndex].data == & JOB_SIGNAL )
			{
				state.signalIndex++;
				assert( state.signalIndex < signalJobCount.Num() );
			}
			else if( jobList[state.lastJobIndex].data == & JOB_SYNCHRONIZE )
			{
				assert( state.signalIndex > 0 );
				if( signalJobCount[state.signalIndex - 1].GetValue() > 0 )
				{
					// stalled on a synchronization point
					return ( result | RUN_STALLED );
				}
			}
			else if( jobList[state.lastJobIndex].data == & JOB_LIST_DONE )
			{
				if( signalJobCount[signalJobCount.Num() - 1].GetValue() > 0 )
				{
					// stalled on a synchronization point
					return ( result | RUN_STALLED );
				}
			}
		}
		
		// try to lock to fetch a new job
		if( fetchLock.Increment() == 1 )
		{
		
			// grab a new job
			state.nextJobIndex = currentJob.Increment() - 1;
			
			// run through any remaining signals and syncs (this should rarely iterate more than once)
			for( ; state.lastJobIndex <= state.nextJobIndex && state.lastJobIndex < jobList.Num(); state.lastJobIndex++ )
			{
				if( jobList[state.lastJobIndex].data == & JOB_SIGNAL )
				{
					state.signalIndex++;
					assert( state.signalIndex < signalJobCount.Num() );
				}
				else if( jobList[state.lastJobIndex].data == & JOB_SYNCHRONIZE )
				{
					assert( state.signalIndex > 0 );
					if( signalJobCount[state.signalIndex - 1].GetValue() > 0 )
					{
						// return this job to the list
						currentJob.Decrement();
						// release the fetch lock
						fetchLock.Decrement();
						// stalled on a synchronization point
						return ( result | RUN_STALLED );
					}
				}
				else if( jobList[state.lastJobIndex].data == & JOB_LIST_DONE )
				{
					if( signalJobCount[signalJobCount.Num() - 1].GetValue() > 0 )
					{
						// return this job to the list
						currentJob.Decrement();
						// release the fetch lock
						fetchLock.Decrement();
						// stalled on a synchronization point
						return ( result | RUN_STALLED );
					}
					// decrement the done count
					doneGuards[currentDoneGuard].Decrement();
				}
			}
			// release the fetch lock
			fetchLock.Decrement();
		}
		else
		{
			// release the fetch lock
			fetchLock.Decrement();
			// another thread is fetching right now so consider stalled
			return ( result | RUN_STALLED );
		}
		
		// if at the end of the job list we're done
		if( state.nextJobIndex >= jobList.Num() )
		{
			return ( result | RUN_DONE );
		}
		
		// execute the next job
		{
			uint64 jobStart = Sys_Microseconds();
			
			jobList[state.nextJobIndex].function( jobList[state.nextJobIndex].data );
			jobList[state.nextJobIndex].executed = 1;
			
			uint64 jobEnd = Sys_Microseconds();
			deferredThreadStats.threadExecTime[threadNum] += jobEnd - jobStart;
			
#ifndef _DEBUG
			if( jobs_longJobMicroSec.GetInteger() > 0 )
			{
				if( jobEnd - jobStart > jobs_longJobMicroSec.GetInteger()
						&& GetId() != JOBLIST_UTILITY )
				{
					longJobTime = ( jobEnd - jobStart ) * ( 1.0f / 1000.0f );
					longJobFunc = jobList[state.nextJobIndex].function;
					longJobData = jobList[state.nextJobIndex].data;
					const char* jobName = GetJobName( jobList[state.nextJobIndex].function );
					const char* jobListName = GetJobListName( GetId() );
					idLib::Printf( "%1.1f milliseconds for a single '%s' job from job list %s on thread %d\n", longJobTime, jobName, jobListName, threadNum );
				}
			}
#endif
		}
		
		result |= RUN_PROGRESS;
		
		// decrease the job count for the current signal
		if( signalJobCount[state.signalIndex].Decrement() == 0 )
		{
			// if this was the very last job of the job list
			if( state.signalIndex == signalJobCount.Num() - 1 )
			{
				deferredThreadStats.endTime = Sys_Microseconds();
				return ( result | RUN_DONE );
			}
		}
		
	}
	while( ! singleJob );
	
	return result;
}
Ejemplo n.º 21
0
/*
===================
R_AddModels

The end result of running this is the addition of drawSurf_t to the
tr.viewDef->drawSurfs[] array and light link chains, along with
frameData and vertexCache allocations to support the drawSurfs.
===================
*/
void R_AddModels()
{
	SCOPED_PROFILE_EVENT( "R_AddModels" );
	
	tr.viewDef->viewEntitys = R_SortViewEntities( tr.viewDef->viewEntitys );
	
	//-------------------------------------------------
	// Go through each view entity that is either visible to the view, or to
	// any light that intersects the view (for shadows).
	//-------------------------------------------------
	
	if( r_useParallelAddModels.GetBool() )
	{
		for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
		{
			tr.frontEndJobList->AddJob( ( jobRun_t )R_AddSingleModel, vEntity );
		}
		tr.frontEndJobList->Submit();
		tr.frontEndJobList->Wait();
	}
	else
	{
		for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
		{
			R_AddSingleModel( vEntity );
		}
	}
	
	//-------------------------------------------------
	// Kick off jobs to setup static and dynamic shadow volumes.
	//-------------------------------------------------
	
	if( r_useParallelAddShadows.GetInteger() == 1 )
	{
		for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
		{
			for( staticShadowVolumeParms_t* shadowParms = vEntity->staticShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
			{
				tr.frontEndJobList->AddJob( ( jobRun_t )StaticShadowVolumeJob, shadowParms );
			}
			for( dynamicShadowVolumeParms_t* shadowParms = vEntity->dynamicShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
			{
				tr.frontEndJobList->AddJob( ( jobRun_t )DynamicShadowVolumeJob, shadowParms );
			}
			vEntity->staticShadowVolumes = NULL;
			vEntity->dynamicShadowVolumes = NULL;
		}
		tr.frontEndJobList->Submit();
		// wait here otherwise the shadow volume index buffer may be unmapped before all shadow volumes have been constructed
		tr.frontEndJobList->Wait();
	}
	else
	{
		int start = Sys_Microseconds();
		
		for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
		{
			for( staticShadowVolumeParms_t* shadowParms = vEntity->staticShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
			{
				StaticShadowVolumeJob( shadowParms );
			}
			for( dynamicShadowVolumeParms_t* shadowParms = vEntity->dynamicShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
			{
				DynamicShadowVolumeJob( shadowParms );
			}
			vEntity->staticShadowVolumes = NULL;
			vEntity->dynamicShadowVolumes = NULL;
		}
		
		int end = Sys_Microseconds();
		backEnd.pc.shadowMicroSec += end - start;
	}
	
	//-------------------------------------------------
	// Move the draw surfs to the view.
	//-------------------------------------------------
	
	tr.viewDef->numDrawSurfs = 0;	// clear the ambient surface list
	tr.viewDef->maxDrawSurfs = 0;	// will be set to INITIAL_DRAWSURFS on R_LinkDrawSurfToView
	
	for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
	{
		for( drawSurf_t* ds = vEntity->drawSurfs; ds != NULL; )
		{
			drawSurf_t* next = ds->nextOnLight;
			if( ds->linkChain == NULL )
			{
				R_LinkDrawSurfToView( ds, tr.viewDef );
			}
			else
			{
				ds->nextOnLight = *ds->linkChain;
				*ds->linkChain = ds;
			}
			ds = next;
		}
		vEntity->drawSurfs = NULL;
	}
}
Ejemplo n.º 22
0
/*
 * Windows main function. Containts the
 * initialization code and the main loop
 */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
  MSG msg;
  long long oldtime, newtime;

  /* Previous instances do not exist in Win32 */
  if (hPrevInstance) {
    return 0;
  }

  /* Make the current instance global */
  global_hInstance = hInstance;

  /* Setup FPU if necessary */
  Sys_SetupFPU();

  /* Force DPI awareness */
  Sys_SetHighDPIMode();

  /* Parse the command line arguments */
  ParseCommandLine(lpCmdLine);

  /* Are we portable? */
  for (int i = 0; i < argc; i++) {
    if (strcmp(argv[i], "-portable") == 0) {
      is_portable = true;
    }
  }

/* Need to redirect stdout before anything happens. */
#ifndef DEDICATED_ONLY
  Sys_RedirectStdout();
#endif

  /* Seed PRNG */
  randk_seed();

  /* Call the initialization code */
  Qcommon_Init(argc, argv);

  /* Save our time */
  oldtime = Sys_Microseconds();

  /* The legendary main loop */
  while (1) {
    /* If at a full screen console, don't update unless needed */
    if (Minimized || (dedicated && dedicated->value)) {
      Sleep(1);
    }

    while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
      if (!GetMessage(&msg, NULL, 0, 0)) {
        Com_Quit();
      }

      sys_msg_time = msg.time;
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }

    // Throttle the game a little bit
    Sys_Nanosleep(5000);

    newtime = Sys_Microseconds();
    Qcommon_Frame(newtime - oldtime);
    oldtime = newtime;
  }

  /* never gets here */
  return TRUE;
}
Ejemplo n.º 23
0
/*
* Sys_Milliseconds
*/
unsigned int Sys_Milliseconds( void )
{
	return Sys_Microseconds() / 1000;
}
Ejemplo n.º 24
0
bool RB_RenderShadowMaps( viewLight_t* vLight ) {

	const idMaterial* lightShader = vLight->lightShader;

	if (lightShader->IsFogLight() || lightShader->IsBlendLight()) {
		return true;
	}

	if (!vLight->localInteractions && !vLight->globalInteractions
		&& !vLight->translucentInteractions) {
		return true;
	}

	if (!vLight->lightShader->LightCastsShadows()) {
		return true;
	}

	int lod = r_smForceLod.GetInteger();
	if(lod < 0) {
		lod = vLight->shadowMapLod;
	}
	lod = Max( 0, Min( lod, 2 ) );

	const uint64 startTime = Sys_Microseconds();

	const float polygonOffsetBias = vLight->lightDef->ShadowPolygonOffsetBias();
	const float polygonOffsetFactor = vLight->lightDef->ShadowPolygonOffsetFactor();
	glEnable( GL_POLYGON_OFFSET_FILL );
	glPolygonOffset( polygonOffsetFactor, polygonOffsetBias );

	switch (r_smFaceCullMode.GetInteger())
	{
	case 0:
		glEnable( GL_CULL_FACE );
		glFrontFace( GL_CCW );
		break;
	case 1:
		glEnable( GL_CULL_FACE );
		glFrontFace( GL_CW );
		break;
	case 2:
	default:
		glDisable( GL_CULL_FACE );
		break;
	}

	ShadowRenderList renderlist;
	int numShadowMaps = 0;

	if (vLight->lightDef->parms.parallel) {
		assert( vLight->lightDef->numShadowMapFrustums == 1 );
		shadowMapFrustum_t& frustum = vLight->lightDef->shadowMapFrustums[0];

		if (!shadowMapAllocator.Allocate( 0, 6, vLight->shadowCoords )) {
			return false;
		}

		const float cascadeDistances[6] = {
			r_smCascadeDistance0.GetFloat(),
			r_smCascadeDistance1.GetFloat(),
			r_smCascadeDistance2.GetFloat(),
			r_smCascadeDistance3.GetFloat(),
			r_smCascadeDistance4.GetFloat(),
			100000
		};

		lod = 0;
		float nextNearDistance = 1;
		for (int c = 0; c < 6; ++c) {
			idFrustum viewFrustum = backEnd.viewDef->viewFrustum;
			viewFrustum.MoveFarDistance( cascadeDistances[c] ); //move far before near, so far is always greater than near
			viewFrustum.MoveNearDistance( nextNearDistance );
			nextNearDistance = cascadeDistances[c];

			idVec3 viewCorners[8];
			viewFrustum.ToPoints( viewCorners );

			for (int i = 0; i < 8; ++i) {
				viewCorners[i] = frustum.viewMatrix * viewCorners[i];
			}

			idVec2 viewMinimum = viewCorners[0].ToVec2();
			idVec2 viewMaximum = viewCorners[0].ToVec2();

			for (int i = 1; i < 8; ++i) {
				const float x = viewCorners[i].x;
				const float y = viewCorners[i].y;

				viewMinimum.x = Min( viewMinimum.x, x );
				viewMinimum.y = Min( viewMinimum.y, y );

				viewMaximum.x = Max( viewMaximum.x, x );
				viewMaximum.y = Max( viewMaximum.y, y );
			}

			idVec2 minimum, maximum;

			if (c < r_smViewDependendCascades.GetInteger()) {
				minimum.x = Max( frustum.viewSpaceBounds[0].x, viewMinimum.x );
				minimum.y = Max( frustum.viewSpaceBounds[0].y, viewMinimum.y );
				maximum.x = Min( frustum.viewSpaceBounds[1].x, viewMaximum.x );
				maximum.y = Min( frustum.viewSpaceBounds[1].y, viewMaximum.y );
			}
			else {
				minimum = frustum.viewSpaceBounds[0].ToVec2();
				maximum = frustum.viewSpaceBounds[1].ToVec2();
			}

			float r = idMath::Abs( maximum.x - minimum.x ) * 0.5f;
			float l = -r;
			float t = idMath::Abs( maximum.y - minimum.y ) * 0.5f;
			float b = -t;

			vLight->viewMatrices[c] = frustum.viewMatrix;
			vLight->viewMatrices[c][12] = -(maximum.x + minimum.x) * 0.5f;
			vLight->viewMatrices[c][13] = -(maximum.y + minimum.y) * 0.5f;
			vLight->viewMatrices[c][14] = -(frustum.viewSpaceBounds[1].z + 1);

			const float f = fabs( frustum.viewSpaceBounds[1].z - frustum.viewSpaceBounds[0].z );
			const float n = 1;

			vLight->projectionMatrices[c] = fhRenderMatrix::identity;
			vLight->projectionMatrices[c][0] = 2.0f / (r - l);
			vLight->projectionMatrices[c][5] = 2.0f / (b - t);
			vLight->projectionMatrices[c][10] = -2.0f / (f - n);
			vLight->projectionMatrices[c][12] = -((r + l) / (r - l));
			vLight->projectionMatrices[c][13] = -((t + b) / (t - b));
			vLight->projectionMatrices[c][14] = -((f + n) / (f - n));
			vLight->projectionMatrices[c][15] = 1.0f;

			vLight->viewProjectionMatrices[c] = vLight->projectionMatrices[c] * vLight->viewMatrices[c];
			vLight->width[c] = fabs( r * 2 );
			vLight->height[c] = fabs( t * 2 );

			vLight->culled[c] = false;
		}

		renderlist.AddInteractions( vLight, nullptr, 0 );

		numShadowMaps = 6;
	}
	else if (vLight->lightDef->parms.pointLight) {
		assert( vLight->lightDef->numShadowMapFrustums == 6 );

		idVec3 viewCorners[8];
		backEnd.viewDef->viewFrustum.ToPoints( viewCorners );

		for (int i = 0; i < 6; ++i) {
			if (r_smLightSideCulling.GetBool()) {
				vLight->culled[i] = vLight->lightDef->shadowMapFrustums[i].Cull(viewCorners);
			}
			else {
				vLight->culled[i] = false;
			}

			if (vLight->culled[i]) {
				continue;
			}

			if (!shadowMapAllocator.Allocate(lod, 1, &vLight->shadowCoords[i])) {
				return false;
			}

			vLight->viewMatrices[i] = vLight->lightDef->shadowMapFrustums[i].viewMatrix;
			vLight->projectionMatrices[i] = vLight->lightDef->shadowMapFrustums[i].projectionMatrix;
			vLight->viewProjectionMatrices[i] = vLight->lightDef->shadowMapFrustums[i].viewProjectionMatrix;
		}

		renderlist.AddInteractions( vLight, vLight->lightDef->shadowMapFrustums, vLight->lightDef->numShadowMapFrustums );

		numShadowMaps = 6;
	}
	else {
		//projected light

		if (!shadowMapAllocator.Allocate( lod, 1, vLight->shadowCoords )) {
			return false;
		}

		assert( vLight->lightDef->numShadowMapFrustums == 1 );

		vLight->viewMatrices[0] = vLight->lightDef->shadowMapFrustums[0].viewMatrix;
		vLight->projectionMatrices[0] = vLight->lightDef->shadowMapFrustums[0].projectionMatrix;
		vLight->viewProjectionMatrices[0] = vLight->lightDef->shadowMapFrustums[0].viewProjectionMatrix;
		vLight->culled[0] = false;

		renderlist.AddInteractions( vLight, &vLight->lightDef->shadowMapFrustums[0], 1 );
		numShadowMaps = 1;
	}

	for (int side = 0; side < numShadowMaps; side++) {
		if(vLight->culled[side]) {
			continue;
		}

		const fhFramebuffer* framebuffer = fhFramebuffer::shadowmapFramebuffer;

		const int width = framebuffer->GetWidth() * vLight->shadowCoords[side].scale.x;
		const int height = framebuffer->GetHeight() * vLight->shadowCoords[side].scale.y;
		const int offsetX = framebuffer->GetWidth() * vLight->shadowCoords[side].offset.x;
		const int offsetY = framebuffer->GetHeight() * vLight->shadowCoords[side].offset.y;

		glViewport( offsetX, offsetY, width, height );
		glScissor( offsetX, offsetY, width, height );

		renderlist.Submit( vLight->viewMatrices[side].ToFloatPtr(), vLight->projectionMatrices[side].ToFloatPtr(), side, lod );
		backEnd.stats.groups[backEndGroup::ShadowMap0 + lod].passes += 1;
	}

	const uint64 endTime = Sys_Microseconds();
	backEnd.stats.groups[backEndGroup::ShadowMap0 + lod].time += static_cast<uint32>(endTime - startTime);

	return true;
}
Ejemplo n.º 25
0
void JoystickSamplingThread( void* data )
{
	static int prevTime = 0;
	static uint64 nextCheck[MAX_JOYSTICKS] = { 0 };
	const uint64 waitTime = 5000000; // poll every 5 seconds to see if a controller was connected
	while( 1 )
	{
		// hopefully we see close to 4000 usec each loop
		int	now = Sys_Microseconds();
		int	delta;
		if( prevTime == 0 )
		{
			delta = 4000;
		}
		else
		{
			delta = now - prevTime;
		}
		prevTime = now;
		threadTimeDeltas[threadCount & 255] = delta;
		threadCount++;
		
		{
			XINPUT_STATE	joyData[MAX_JOYSTICKS];
			bool			validData[MAX_JOYSTICKS];
			for( int i = 0 ; i < MAX_JOYSTICKS ; i++ )
			{
				if( now >= nextCheck[i] )
				{
					// XInputGetState might block... for a _really_ long time..
					validData[i] = XInputGetState( i, &joyData[i] ) == ERROR_SUCCESS;
					
					// allow an immediate data poll if the input device is connected else
					// wait for some time to see if another device was reconnected.
					// Checking input state infrequently for newly connected devices prevents
					// severe slowdowns on PC, especially on WinXP64.
					if( validData[i] )
					{
						nextCheck[i] = 0;
					}
					else
					{
						nextCheck[i] = now + waitTime;
					}
				}
			}
			
			// do this short amount of processing inside a critical section
			idScopedCriticalSection cs( win32.g_Joystick.mutexXis );
			
			for( int i = 0 ; i < MAX_JOYSTICKS ; i++ )
			{
				controllerState_t* cs = &win32.g_Joystick.controllers[i];
				
				if( !validData[i] )
				{
					cs->valid = false;
					continue;
				}
				cs->valid = true;
				
				XINPUT_STATE& current = joyData[i];
				
				cs->current = current;
				
				// Switch from using cs->current to current to reduce chance of Load-Hit-Store on consoles
				
				threadPacket[threadCount & 255] = current.dwPacketNumber;
#if 0
				if( xis.dwPacketNumber == oldXis[ inputDeviceNum ].dwPacketNumber )
				{
					return numEvents;
				}
#endif
				cs->buttonBits |= current.Gamepad.wButtons;
			}
		}
		
		// we want this to be processed at least 250 times a second
		WaitForSingleObject( win32.g_Joystick.timer, INFINITE );
	}
}
Ejemplo n.º 26
0
/*
=================
idCommonLocal::Frame
=================
*/
void idCommonLocal::Frame() {
	try {
		SCOPED_PROFILE_EVENT( "Common::Frame" );

		// This is the only place this is incremented
		idLib::frameNumber++;

		// allow changing SIMD usage on the fly
		if ( com_forceGenericSIMD.IsModified() ) {
			idSIMD::InitProcessor( "doom", com_forceGenericSIMD.GetBool() );
			com_forceGenericSIMD.ClearModified();
		}

		// Do the actual switch between Doom 3 and the classics here so
		// that things don't get confused in the middle of the frame.
		PerformGameSwitch();

		// pump all the events
		Sys_GenerateEvents();

		// write config file if anything changed
		WriteConfiguration(); 

		eventLoop->RunEventLoop();

		// Activate the shell if it's been requested
		if ( showShellRequested && game ) {
			game->Shell_Show( true );
			showShellRequested = false;
		}

		// if the console or another gui is down, we don't need to hold the mouse cursor
		bool chatting = false;
		if ( console->Active() || Dialog().IsDialogActive() || session->IsSystemUIShowing() || ( game && game->InhibitControls() && !IsPlayingDoomClassic() ) ) {
			Sys_GrabMouseCursor( false );
			usercmdGen->InhibitUsercmd( INHIBIT_SESSION, true );
			chatting = true;
		} else {
			Sys_GrabMouseCursor( true );
			usercmdGen->InhibitUsercmd( INHIBIT_SESSION, false );
		}

		const bool pauseGame = ( !mapSpawned || ( !IsMultiplayer() && ( Dialog().IsDialogPausing() || session->IsSystemUIShowing() || ( game && game->Shell_IsActive() ) ) ) ) && !IsPlayingDoomClassic();

		// save the screenshot and audio from the last draw if needed
		if ( aviCaptureMode ) {
			idStr name = va("demos/%s/%s_%05i.tga", aviDemoShortName.c_str(), aviDemoShortName.c_str(), aviDemoFrameCount++ );
			renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL );

			// remove any printed lines at the top before taking the screenshot
			console->ClearNotifyLines();

			// this will call Draw, possibly multiple times if com_aviDemoSamples is > 1
			renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL );
		}

		//--------------------------------------------
		// wait for the GPU to finish drawing
		//
		// It is imporant to minimize the time spent between this
		// section and the call to renderSystem->RenderCommandBuffers(),
		// because the GPU is completely idle.
		//--------------------------------------------
		// this should exit right after vsync, with the GPU idle and ready to draw
		// This may block if the GPU isn't finished renderng the previous frame.
		frameTiming.startSyncTime = Sys_Microseconds();
		const emptyCommand_t * renderCommands = NULL;
		if ( com_smp.GetBool() ) {
			renderCommands = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu );
		} else {
			// the GPU will stay idle through command generation for minimal
			// input latency
			renderSystem->SwapCommandBuffers_FinishRendering( &time_frontend, &time_backend, &time_shadows, &time_gpu );
		}
		frameTiming.finishSyncTime = Sys_Microseconds();

		//--------------------------------------------
		// Determine how many game tics we are going to run,
		// now that the previous frame is completely finished.
		//
		// It is important that any waiting on the GPU be done
		// before this, or there will be a bad stuttering when
		// dropping frames for performance management.
		//--------------------------------------------

		// input:
		// thisFrameTime
		// com_noSleep
		// com_engineHz
		// com_fixedTic
		// com_deltaTimeClamp
		// IsMultiplayer
		//
		// in/out state:
		// gameFrame
		// gameTimeResidual
		// lastFrameTime
		// syncNextFrame
		//
		// Output:
		// numGameFrames

		// How many game frames to run
		int numGameFrames = 0;

		for(;;) {
			const int thisFrameTime = Sys_Milliseconds();
			static int lastFrameTime = thisFrameTime;	// initialized only the first time
			const int deltaMilliseconds = thisFrameTime - lastFrameTime;
			lastFrameTime = thisFrameTime;

			// if there was a large gap in time since the last frame, or the frame
			// rate is very very low, limit the number of frames we will run
			const int clampedDeltaMilliseconds = Min( deltaMilliseconds, com_deltaTimeClamp.GetInteger() );

			gameTimeResidual += clampedDeltaMilliseconds * timescale.GetFloat();

			// don't run any frames when paused
			if ( pauseGame ) {
				gameFrame++;
				gameTimeResidual = 0;
				break;
			}

			// debug cvar to force multiple game tics
			if ( com_fixedTic.GetInteger() > 0 ) {
				numGameFrames = com_fixedTic.GetInteger();
				gameFrame += numGameFrames;
				gameTimeResidual = 0;
				break;
			}

			if ( syncNextGameFrame ) {
				// don't sleep at all
				syncNextGameFrame = false;
				gameFrame++;
				numGameFrames++;
				gameTimeResidual = 0;
				break;
			}

			for ( ;; ) {
				// How much time to wait before running the next frame,
				// based on com_engineHz
				const int frameDelay = FRAME_TO_MSEC( gameFrame + 1 ) - FRAME_TO_MSEC( gameFrame );
				if ( gameTimeResidual < frameDelay ) {
					break;
				}
				gameTimeResidual -= frameDelay;
				gameFrame++;
				numGameFrames++;
				// if there is enough residual left, we may run additional frames
			}

			if ( numGameFrames > 0 ) {
				// ready to actually run them
				break;
			}

			// if we are vsyncing, we always want to run at least one game
			// frame and never sleep, which might happen due to scheduling issues
			// if we were just looking at real time.
			if ( com_noSleep.GetBool() ) {
				numGameFrames = 1;
				gameFrame += numGameFrames;
				gameTimeResidual = 0;
				break;
			}

			// not enough time has passed to run a frame, as might happen if
			// we don't have vsync on, or the monitor is running at 120hz while
			// com_engineHz is 60, so sleep a bit and check again
			Sys_Sleep( 0 );
		}

		//--------------------------------------------
		// It would be better to push as much of this as possible
		// either before or after the renderSystem->SwapCommandBuffers(),
		// because the GPU is completely idle.
		//--------------------------------------------

		// Update session and syncronize to the new session state after sleeping
		session->UpdateSignInManager();
		session->Pump();
		session->ProcessSnapAckQueue();

		if ( session->GetState() == idSession::LOADING ) {
			// If the session reports we should be loading a map, load it!
			ExecuteMapChange();
			mapSpawnData.savegameFile = NULL;
			mapSpawnData.persistentPlayerInfo.Clear();
			return;
		} else if ( session->GetState() != idSession::INGAME && mapSpawned ) {
			// If the game is running, but the session reports we are not in a game, disconnect
			// This happens when a server disconnects us or we sign out
			LeaveGame();
			return;
		}

		if ( mapSpawned && !pauseGame ) {
			if ( IsClient() ) {
				RunNetworkSnapshotFrame();
			}
		}

		ExecuteReliableMessages();

		// send frame and mouse events to active guis
		GuiFrameEvents();

		//--------------------------------------------
		// Prepare usercmds and kick off the game processing
		// in a background thread
		//--------------------------------------------

		// get the previous usercmd for bypassed head tracking transform
		const usercmd_t	previousCmd = usercmdGen->GetCurrentUsercmd();

		// build a new usercmd
		int deviceNum = session->GetSignInManager().GetMasterInputDevice();
		usercmdGen->BuildCurrentUsercmd( deviceNum );
		if ( deviceNum == -1 ) {
			for ( int i = 0; i < MAX_INPUT_DEVICES; i++ ) {
				Sys_PollJoystickInputEvents( i );
				Sys_EndJoystickInputEvents();
			}
		}
		if ( pauseGame ) {
			usercmdGen->Clear();
		}

		usercmd_t newCmd = usercmdGen->GetCurrentUsercmd();

		// Store server game time - don't let time go past last SS time in case we are extrapolating
		if ( IsClient() ) {
			newCmd.serverGameMilliseconds = std::min( Game()->GetServerGameTimeMs(), Game()->GetSSEndTime() );
		} else {
			newCmd.serverGameMilliseconds = Game()->GetServerGameTimeMs();
		}

		userCmdMgr.MakeReadPtrCurrentForPlayer( Game()->GetLocalClientNum() );

		// Stuff a copy of this userCmd for each game frame we are going to run.
		// Ideally, the usercmds would be built in another thread so you could
		// still get 60hz control accuracy when the game is running slower.
		for ( int i = 0 ; i < numGameFrames ; i++ ) {
			newCmd.clientGameMilliseconds = FRAME_TO_MSEC( gameFrame-numGameFrames+i+1 );
			userCmdMgr.PutUserCmdForPlayer( game->GetLocalClientNum(), newCmd );
		}

		// If we're in Doom or Doom 2, run tics and upload the new texture.
		if ( ( GetCurrentGame() == DOOM_CLASSIC || GetCurrentGame() == DOOM2_CLASSIC ) && !( Dialog().IsDialogPausing() || session->IsSystemUIShowing() ) ) {
			RunDoomClassicFrame();
		}
		
		// start the game / draw command generation thread going in the background
		gameReturn_t ret = gameThread.RunGameAndDraw( numGameFrames, userCmdMgr, IsClient(), gameFrame - numGameFrames );

		if ( !com_smp.GetBool() ) {
			// in non-smp mode, run the commands we just generated, instead of
			// frame-delayed ones from a background thread
			renderCommands = renderSystem->SwapCommandBuffers_FinishCommandBuffers();
		}

		//----------------------------------------
		// Run the render back end, getting the GPU busy with new commands
		// ASAP to minimize the pipeline bubble.
		//----------------------------------------
		frameTiming.startRenderTime = Sys_Microseconds();
		renderSystem->RenderCommandBuffers( renderCommands );
		if ( com_sleepRender.GetInteger() > 0 ) {
			// debug tool to test frame adaption
			Sys_Sleep( com_sleepRender.GetInteger() );
		}
		frameTiming.finishRenderTime = Sys_Microseconds();

		// make sure the game / draw thread has completed
		// This may block if the game is taking longer than the render back end
		gameThread.WaitForThread();

		// Send local usermds to the server.
		// This happens after the game frame has run so that prediction data is up to date.
		SendUsercmds( Game()->GetLocalClientNum() );

		// Now that we have an updated game frame, we can send out new snapshots to our clients
		session->Pump(); // Pump to get updated usercmds to relay
		SendSnapshots();

		// Render the sound system using the latest commands from the game thread
		if ( pauseGame ) {
			soundWorld->Pause();
			soundSystem->SetPlayingSoundWorld( menuSoundWorld );
		} else {
			soundWorld->UnPause();
			soundSystem->SetPlayingSoundWorld( soundWorld );
		}
		soundSystem->Render();

		// process the game return for map changes, etc
		ProcessGameReturn( ret );

		idLobbyBase & lobby = session->GetActivePlatformLobbyBase();
		if ( lobby.HasActivePeers() ) {
			if ( net_drawDebugHud.GetInteger() == 1 ) {
				lobby.DrawDebugNetworkHUD();
			}
			if ( net_drawDebugHud.GetInteger() == 2 ) {
				lobby.DrawDebugNetworkHUD2();
			}
			lobby.DrawDebugNetworkHUD_ServerSnapshotMetrics( net_drawDebugHud.GetInteger() == 3 );
		}

		// report timing information
		if ( com_speeds.GetBool() ) {
			static int lastTime = Sys_Milliseconds();
			int	nowTime = Sys_Milliseconds();
			int	com_frameMsec = nowTime - lastTime;
			lastTime = nowTime;
			Printf( "frame:%d all:%3d gfr:%3d rf:%3lld bk:%3lld\n", idLib::frameNumber, com_frameMsec, time_gameFrame, time_frontend / 1000, time_backend / 1000 );
			time_gameFrame = 0;
			time_gameDraw = 0;
		}

		// the FPU stack better be empty at this point or some bad code or compiler bug left values on the stack
		if ( !Sys_FPU_StackIsEmpty() ) {
			Printf( Sys_FPU_GetState() );
			FatalError( "idCommon::Frame: the FPU stack is not empty at the end of the frame\n" );
		}

		mainFrameTiming = frameTiming;

		session->GetSaveGameManager().Pump();
	} catch( idException & ) {
		return;			// an ERP_DROP was thrown
	}
}