Severe FPS differences with varying processors

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Aelis440
Posts: 52
Joined: Sun Oct 05, 2008 8:45 pm

Severe FPS differences with varying processors

Post by Aelis440 »

Hello everyone,

I had a question regarding FPS. I recently adjusted the code of my project so that units could turn and run "identically" on different computers by using a system which ran updates based on 'time' so that FPS did not affect movement (to avoid units moving faster on faster computers). However, in doing this, I found a peculiar difference among 3 different computers, here are their descriptions:

Computer 1: Laptop, pretty old, kinda slow (4 years). 1.73 GHz processor (intel)
Computer 2: Desktop, decent shape, 2-3 years old. 2.01GHz processor (amd)
Computer 3: Desktop, pretty much a beast, recently bought, dual core 3.01 GHz processor (amd)


Now, what is odd about this is that the delta times on Computer 1 are about 5-6 milliseconds. Meaning, it takes the computer to run an entire 'game loop' in this amount of time. On Computer 2, this time is about 2-3 seconds. Now, the SUPER odd thing is you would expect Computer 3 to run these game loops in less time, say 1 millisecond each. However, when we cout these numbers, we consistently get this sequence: "0, 0, 0, 0, x" where x is either 15, or 16 milliseconds. This would mean mean it ran 4 loops in less than a second, and the fifth loop in 15-16 milliseconds.

Note that all of these numbers increase when we slow the computers down by adding in a bunch of models into the view of the camera. However, this does not prevent Computer 3 from changing its pattern, it will just go "0, 0, 0, 31" for instance.

The reason this is such a huge issue is that the whole theory behind delta time assumes that faster computers will give u smaller delta time numbers, so you can usually depend on that during your calculations. But with these fluctuating values (a slow computers being high, a decent computer being low, and a really fast computer being REALLY high), I cannot write a formula for my movements which would be "fair" to all computers.

Finally, I think this may have to due with Computer 3 being a dual core processor. Any insight on the situation would be greatly appreciated.


Here is the code of our main:

Code: Select all

int main()
{
	// Create everything needed for the basic game engine to run.  If any of these fail, nothing will be able to continue.
	// We run a check at the end to make sure everything loaded properly.
	IrrlichtDevice* device = createDevice(EDT_OPENGL, dimension2d<s32>(1280, 1024), 16, false);
	//device->getFileSystem()->changeWorkingDirectoryTo("C:/Frontier/");  //Sets the working Directory
	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();
	IGUIEnvironment* env = device->getGUIEnvironment();
	ISoundEngine* engine = createIrrKlangDevice();
	// The returned timer is automatically created when you create a device.
	ITimer* timer = device->getTimer();
	if (device == 0 || driver == 0 || smgr == 0 || env == 0 || engine == 0)
		return 1;	// 1 indicates that something went wrong with one of these classes.
					// Look into Exceptions so that if this occurs to a player, we can print useful information to the screen.
	

	// This tells the video driver to draw 32bit images when drawing textures.
	driver->setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true); 
	// This tells the video driver to create mip-maps while drawing textures.
	driver->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, true);
	Manager manager(device, engine, smgr, driver, env);	// Create the event receiver
	device->setEventReceiver(&manager); //Set the event receiver, this MUST stay constant throughout the program.
	manager.onLoad();  // Initializes everything needed for the beginning of the program.

	// All of these variables are used to control the speed of the things in the game, NOT the FPS.
	// We have made the two indepedent of each other so the game plays almost identical on
	// faster and slower computers.
	int frameCounter = 0;
	double deltaTime;
	double oldTime = timer->getTime();
	double timeOfLastLoop = timer->getTime();
	double timeDifference;	// This is only used to make the math a little more readable where it is used.
	double currentTime;

	ITexture * mouseTexture = driver->getTexture("media/hand.tga");
	position2d<s32> mouseAdjustment;
	mouseAdjustment.X = device->getCursorControl()->getPosition().X + 1;
	mouseAdjustment.Y = device->getCursorControl()->getPosition().Y + 1;
	IGUIImage * mouse = env->addImage(mouseTexture, mouseAdjustment);
	device->getCursorControl()->setVisible(false);
	

	// This is the 'Game Loop' as long as it runs, the game will continually draw and redraw everything on the screen.
	// In almost all cases, this loop is not changed directly.  The only way the game changes is through the event receiver.
	while(device->run())
	{
		
		if (device->isWindowActive())
		{
			deltaTime = timer->getTime() - timeOfLastLoop;
			

					cout<< deltaTime << endl;


			mouseAdjustment.X = device->getCursorControl()->getPosition().X + 1;
			mouseAdjustment.Y = device->getCursorControl()->getPosition().Y + 1;
			if(mouse != 0)
			{
				mouse->remove();
				mouse = 0;
			}
			if(!manager.getRButtonIsDown())
			{
				mouse = env->addImage(mouseTexture, mouseAdjustment);
			}
		
			// Allows the game to be 'unpaused' and restarts the game timer when the window becomes active.
			// See the 'else' statement below for clarity.
			if (timer->isStopped())  
				timer->start();
		
			// Record the time between now and the previous loop


			// This allows the manager to know what that time is so it may use it in its calculations.
			// However, with really fast computers, often, deltaTime will be 0 since the 'Game Loop'
			// is running so fast.  This check prevents jagged movement when deltaTime is 0.
			if(deltaTime > 0)
			{
				manager.setDeltaTime(deltaTime);
				manager.updateKeyInput();	 //Updates the game based on any key inputs.
				manager.updateGameplay();
				manager.checkDistances();
			}

				
			// This allows the FPS to be displayed every time we have gone through 500 frames.
			if(frameCounter == 500)
			{
				currentTime = timer->getTime();					// Tag the time since this "time" will be used in two different
				timeDifference = currentTime - oldTime;			// calculations.  This allows us to not call getTime() twice,
				oldTime = currentTime;							// which, if we did, would cause us to "lose" milliseconds in
																// our calculations.
				manager.updateFPS(frameCounter / timeDifference * MILISECONDS_PER_SECOND);
				frameCounter = 0;	// reset the frame counter
			}

			driver->beginScene(true, true, 0);	
			
			// Anything you want to see BEFORE the screen updates (per loop), must be inserted	BEFORE smgr->drawAll();
			smgr->drawAll();

			manager.updateAspects(); 
			// Any GUI aspects that need to be seen BEFORE the screen updates (per loop), must be inserted BEFORE env->drawAll();
			env->drawAll();
			
			// This tells the video driver to finish drawing the scene, else we would never be able to continue.
			driver->endScene();

			frameCounter++;
         timeOfLastLoop = timer->getTime();
		}

		else
		{	// This allows us to pause the game and not have it 'accelerate' when tabbed out of, then back into by stopping the virtual timer from updating.
			if (!timer->isStopped())
				timer->stop();
		}
	}

	// This ends the program and exits.  As a convention, main is always of 'int' type and therefore must return a value.
	// We return 0 to indicate that the program ran to completion.
	// Any other error would return another Counter(i.e. return 1 that we saw above) for debugging purposes.
	device->drop();
	return 0;
}


Note that the (if deltaTime > 0) did NOT affect the values for computer 3, or any computer for that matter.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

You don't say which version of Irrlicht you're using, but if I had to guess, I'd say you are using .

The issue is that older versions of the Irrlicht timer code use GetTickCount() instead of QueryPerformanceCounter() on multi-core systems. The function GetTickCount() is not nearly as accurate. If I remember correctly it has a 15ms resolution, which is not very good.

You could either update os.cpp and rebuild the library, or you could write some simple code to keep a running average of the elapsed time.

Travis
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Urgh, yes, that fix didn't make it into 1.4.2.

You could either:

Download the SVN trunk.

Replace the source/Irrlicht/os.cpp file in your 1.4.2 SDK with this version, then recompile Irrlicht.

Get a trunk build from the nightly builds server (which seems to be down at the time of writing).
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Ethan
Posts: 9
Joined: Sun Oct 12, 2008 9:00 pm

Post by Ethan »

Flame on me if this is a dumb idea, but wouldn't it be possible to just do something like

Code: Select all

f32 deltaTime = 1.0f / myVideoDriver->getFPS();
to get a deltaTime?
At least until this bug is fixed in irrlicht timing.
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

No, because getFPS() is only updated once a second so isn't going to be very accurate ;)
Image Image Image
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

<pedant>Not more frequently than every 1500 ms</pedant>

It's not obvious from the API though, so I've updated the comment in SVN 1650 to hopefully make it clearer what getFPS() is and isn't for.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Ethan
Posts: 9
Joined: Sun Oct 12, 2008 9:00 pm

Post by Ethan »

why does no one get a bug fixed irrlicht.dll for download, instead of letting everyone compile it themselves?

would be cool, this bug really sucks, i spend quite some hours looking
for a bug in my framework.

edit:

i recompiled the irrlicht.dll and it works great now, thanks for that fix
but i still think it's not cool to leave everyone with dual core with the broken timer alone, till hes desperate enough to watch the forum.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

There's a nightly build server which offers the most recent SVN versions for direct use.
Ethan
Posts: 9
Joined: Sun Oct 12, 2008 9:00 pm

Post by Ethan »

yea well okay, i missed that one. ;) my fault.
too fast reading...

well then theres still the buggy dll in the sdk which drives users (especially irrlicht newbies like me) nuts.
you have to know that theres a nightly build, first.

i hope you know what i want to say, it's not very comfortable to have to find the bug yourself, to find the right words for the forum search, and then download a new build or compile it yourself.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

This fix is already scheduled for Irrlicht 1.5, it just takes some time until all those changes will go into a stable release.
Aelis440
Posts: 52
Joined: Sun Oct 05, 2008 8:45 pm

RE

Post by Aelis440 »

Thanks for all the help :). I plan on using the SVN, on a side note... rough estimate on 1.5? weeks, months?
arnir
Competition winner
Posts: 154
Joined: Sat Jan 20, 2007 4:36 pm
Location: Czech Republic

Post by arnir »

is now fixed? (in 1.5? )
programmer is bad designer
designer is bad programmer
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

At least the mentioned changes are in. Whether it fixes all those issues is not guaranteed.
Post Reply