Quantcast
Channel: Анал со зрелой
Viewing all articles
Browse latest Browse all 47

Cross Platform Time for dt

$
0
0

Generally a game loop will look something like this:

while ( 1 )
{
	float dt = Time( );
	Game( dt );
}

Generally the delta time slices between each game loop are useful to advance the game to the next frame, or tick. dt stands for the elapsed time since the last moment we asked for elapsed time, or, delta time. In effect we are using one frame’s worth of delayed time to advance state, so the visuals of the game are actually always one tick behind — but that’s totally acceptable and not noticeable to the user.

Getting that time slice is a little tricky. Usually games would want somewhat sub-millisecond resolution, since milliseconds is a pretty easy to reason about metric. 60 fps is about 16 milliseconds, so if we want to run a game at 60 fps we better use less than 16 milliseconds during each tick. If a major system of a game starts taking upwards of 5 or so milliseconds, then that system better be what the game is about! If a major system takes less than a millisecond, or roughly 1-2 milliseconds, it’s probably pretty well optimized. So we need sub-millisecond precision in our time function. Many time functions provided by operating systems are at best millisecond precision (not good enough if we want to measure less than a millisecond), or sometimes seconds precision.

Also, the time function itself should just be a straightforward function that returns a float, and has no parameters. So, I went through some digging and came up with a cross platform solution:

// These functions are intended be called from a single thread only. In a
// multi-threaded environment make sure to call Time from the main thread only.
// Also try to set a thread affinity for the main thread to avoid core swaps.
// This can help prevent annoying bios bugs etc. from giving weird time-warp
// effects as the main thread gets passed from one core to another. This shouldn't
// be a problem, but it's a good practice to setup the affinity. Calling these
// functions on multiple threads multiple times will grant a heft performance
// loss in the form of false sharing due to CPU cache synchronization across
// multiple cores.

#if PLATFORM == WINDOWS

	float Time( )
	{
		static int first = 1;
		static LARGE_INTEGER prev;
		static double factor;

		LARGE_INTEGER now;
		QueryPerformanceCounter( &now );

		if ( first )
		{
			first = 0;
			prev = now;
			LARGE_INTEGER freq;
			QueryPerformanceFrequency( &freq );
			factor = 1.0 / (double)freq.QuadPart;
		}

		float elapsed = (float)((double)(now.QuadPart - prev.QuadPart) * factor);
		prev = now;
		return elapsed;
	}

#elif PLATFORM == MAC

	#include <mach/mach_time.h>

	float Time( )
	{
		static int first = 1;
		static uint64_t prev = 0;
		static double factor;
	
		if ( first )
		{
			first = 0;
			mach_timebase_info_data_t info;
			mach_timebase_info( &info );
			factor = ((double)info.numer / (double)info.denom) * 1000000000.0;
			prev = mach_absolute_time( );
			return 0;
		}
	
		uint64_t now = mach_absolute_time( );
		float elapsed = (float)((double)(now - prev) * factor);
		prev = now;
		return elapsed;
	}

#else // nix via posix

	#include <time.h>
	
	float Time( )
	{
		static int first = 1;
		struct timespec prev;
		
		if ( first )
		{
			first = 0;
			clock_gettime( CLOCK_MONOTONIC, &prev );
			return 0;
		}
		
		struct timespec now;
		clock_gettime( CLOCK_MONOTONIC, &now );
		float elapsed = (float)((double)(now.tv_nsec - prev.tv_nsec) * 1000000000.0);
		prev = now;
		return elapsed;
	}

#endif

These functions should work on majority of major game platforms and give high resolution elapsed times between calls. They are intended to be used on the main thread within the main loop, once per tick.

If one wanted to use these functions for performance timing they should be modified to pass in some state, rather than rely on using static state. Static state is perfectly acceptable for the intended use case of main-loop main-thread. Be sure to read the comments in the source code!

I posted this source code in a finalized version here on github inside of tinytime.h.

 

TwitterRedditFacebookShare


Viewing all articles
Browse latest Browse all 47

Trending Articles