Fixed frametime

Started by
6 comments, last by cozzie 7 years, 2 months ago

Hi all,

I've been strugling to experiment with getting a constant fixed framerate.

Debugging so far didn't bring up the problem.

In short, this is what I'm doing (note; I know there are other/ better/ different ways to manage time steps, but I just want to know why this doesn't work):

- once: set fixed frametime, 1 / xx, i.e. 1/60 = 16.67ms

- each iteration

-- check how long last frame took

-- if < fixed frametime: wait till fixed time has passed

-- if > fixed frametime: skip frame aka wait till next fixed frametime has passed

-- update game logics using fixed deltaT

-- render

My debugging results show what I expect, some samples:


deltaT: 12.493622 ms
Currtime: 11748114, waitTill: 11748118
deltaT: 14.139329 ms
Currtime: 11748128, waitTill: 11748130
deltaT: 11.998593 ms
Currtime: 11748140, waitTill: 11748144
deltaT: 14.002699 ms
Currtime: 11748154, waitTill: 11748156
deltaT: 12.041601 ms
Currtime: 11748166, waitTill: 11748170

Though 'rounded', the waiting time and deltaT nicely add up to the fixed frametime.

The issue:

- with vsync enabled it's all good

- with vsync enabled I get jumping fps/ frametimes, between 45 and 80 (and in release mode up to 120fps...)

Below the code of what I'm doing.

Any input is really appreciated.


int CAppl::Run()
{
	MSG msg = {0};

	mTimer.Reset();
	mTimer.Tick();
	float fixedDeltaT = 1000.0f/60.0f;		// 60fps - 16.67ms per frame

	bool run = true;
	while(run)
	{
		mInputHandler.UpdateKeys();		

		while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
            TranslateMessage(&msg);
            DispatchMessage(&msg);
			if(msg.message == WM_QUIT) run = false;
		}

		if(!mAppPaused )
		{
			mTimer.Tick();
			CalculateFrameStats();

			float waitTime = 0.0f;
			if(mTimer.GetDeltaTime() < fixedDeltaT)
			{
				waitTime = fixedDeltaT - mTimer.GetDeltaTime();						// time left: wait till fixed frametime is passed
			}
			
			if(mTimer.GetDeltaTime() > fixedDeltaT) 
			{
				waitTime = fixedDeltaT - fmod(mTimer.GetDeltaTime(), fixedDeltaT);	// time exceeded: wait till next frametime is passed
			}

			if(waitTime > (fixedDeltaT - 1.0f) || waitTime < 1.0f) waitTime = 0.0f;

			uint64_t startWaitTime = mTimer.GetCurrTime();
			
			// DEBUGGING
			char tempText[100];
			//sprintf_s(tempText, "Currtime: %u\n", startWaitTime);
			//OutputDebugStringA(tempText);
	/*		sprintf_s(tempText, "deltaT: %f ms\n", mTimer.GetDeltaTime());
			OutputDebugStringA(tempText);
			sprintf_s(tempText, "waittime: %f ms\n", waitTime);
			OutputDebugStringA(tempText);			*/

			// CONTINUE
			uint64_t waitTill = startWaitTime + static_cast<uint64_t>(waitTime);
			
			sprintf_s(tempText, "Currtime: %u, waitTill: %u\n", static_cast<uint>(startWaitTime), static_cast<uint>(waitTill));
			OutputDebugStringA(tempText);

			while(mTimer.GetCurrTime() <= waitTill) {  }

			if(!Update(fixedDeltaT, mTimer.GetTotalTime()))
			{
				CLOG(FATAL, "GAMEBASE") << fatal_update_appl.c_str();
				return(int)msg.wParam;
			}
			if(!Render())
			{
				CLOG(FATAL, "GAMEBASE") << fatal_render_appl.c_str();
				return(int)msg.wParam;
			}
		}
		else
		{
			Sleep(100);
		}
    }
	return (int)msg.wParam;
}

void CGameTimer::Tick()
{
	std::chrono::high_resolution_clock::time_point currTime = std::chrono::high_resolution_clock::now();

	std::chrono::duration<double, std::milli> delta  = currTime - mPrevTime;
	mDeltaTime = delta.count();
	
	mPrevTime = currTime;

	// force nonnegative: if procesor goes into power save or sth., delta could be negative
	if(mDeltaTime < 0.0)
	{
		mDeltaTime = 0.0;
	}
}

uint64_t CGameTimer::GetTotalTime() const
{
	std::chrono::duration<double> addTime = std::chrono::high_resolution_clock::now() - mStartTime;	
	return static_cast<uint64_t>(addTime.count());	
}

float CGameTimer::GetDeltaTime() const
{
	return static_cast<float>(mDeltaTime);
}

uint64_t CGameTimer::GetCurrTime() const
{
	return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
}

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Advertisement

getting a constant fixed framerate.

a simple framerate limiter will get you a fixed framerate - bot only on hardware that's fast enough. if the hardware is not fast enough, you'll get a lower FPS, which will vary as the computational load varies.

ET accumulator and DT type stuff is only required for things like fix-your-timestep - IE algos that "decouple" (IE un-lockstep) render from update.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Hi. I know there are other options. Just like to fix this one

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

I haven't deeply examinated your code, but don't use std::chrono. In VS2012 & 2013 it wasn't accurate at all. I don't know if they fixed it in VS 2015.

I haven't deeply examinated your code, but don't use std::chrono. In VS2012 & 2013 it wasn't accurate at all. I don't know if they fixed it in VS 2015.

chrono uses QueryPerformanceCounter for steady_clock in VS 2015 (and thus also for high_resolution_clock).


I haven't deeply examinated your code, but don't use std::chrono. In VS2012 & 2013 it wasn't accurate at all. I don't know if they fixed it in VS 2015.

I had no issues with high_resolution_clock (and/or as they are the same steady clock) on VS 2013 and 2015.

Keep in mind that the graphics driver/api/OS will buffer frames as well. How your manual throttling interacts with this can be a huge source of issues. If you're attempting to minimize latency, the OS will do everything in its power to prevent that and try to buffer frames!

There is a really great tool for checking this, I think GpuView (someone please correct me if I'm wrong!).

Just for reference; I've decided to stop trying to get this 'practice' running.

Since I wont be using it later on and the efforts are not worth the results.

Know 'simply' going for the static updating rate and 'free' rendering rate (like the Fix your timestep approach).

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

This topic is closed to new replies.

Advertisement