is this the best performace I can get from the game loop?

http://www.angelfire.com/clone/wolfbane/loop2.jar (cut and paste please)

The jar file contains a loop (one is by KevGlass the other is by David Brackeen). I am trying to achive smooth animtion at around 60 fps. Currently it is not smooth, it stutters a the time. My question is, is the performance i am getting correct? Using the loop I use, am I seeing the results I am suppose to see (with stutter).

The mainClass.java contains the code for the loops. you can activate any version by decomenting it in the constructor. Can someone pease take a look and let me know what you think? I have seen games run very smoothly at 60 fps, how can I get my demo to run smoothly as well?

I can’t open the jar - Winzip and 7zip say it’s invalid.

Jar works fine here.

The loop you’ve got from the spaceinvaders code isn’t very accurate on reporting FPS so if thats what you’re using to monitor the “smoothness” then it’s not going to work out. Second, with a target frame time of 15ms you’re actually aiming for 66.666666r fps which probably isn’t too great.

Kev

hey Kev, you kind of answered my question. So you are saying that 66 fps is not good enough? How is it then that I see games runing smoothly at 60 fps and less?

Second point of confusion. My monitor refresh is set to 85 hz. If I set it to 60hz then the loop runs lot smoother. Can someone please confirm that. Also what is the reason for this, considering that I am limiting the fps anyway?

Its not the 66 fps target that I was pointing out really. The question is really how are you determining the “smoothness” ?

Kev

um… visually. I can see visually that the box moving around jerks too often. Do you see that as well? Or is it consistent in it’s movement for you?

ALomost certainly your frame rate limit isnt working if that chnages things…

Anglefire is refusing your link.

It is likely you’ve created a test case that the eye is particularly good at detecting unsmooth movement. As an example, a single colored quad over a single color background will only good if you sync it to refresh and move a multiple of 1 pixel at a time.

A few things just ocurred to me:

(1) What are you calling a “stutter”? Are you sure it isn’t a tear? Tearing happens when you update the image in the mdist of a scan. Scan synching removes tearing.

(2)WHenever you see momentary irregular pauses in a Java game its a good idea to run your profiler and look at your memory situation. Object leaks can cause this by causing needless full GC runs.

Jeff you have to cut and paste the link.

By “stutter” I mean that the box in my demo doesnt move very smoothly. I am sure it is not tear. It is also a very basic demo and I dont think GC is the issue here, although I could be wrong of course.

frame rate not working… hum. Here is the code I dont see what I got wrong since it is a copy of Kev’s code

Loop

long lastLoopTime = getTime();
			
			long lastFpsTime = 0;
			int fps = 0;
			
			while (true) 
			{
				// work out how long its been since the last update, this
				// will be used to calculate how far the entities should
				// move this loop
				long delta = getTime() - lastLoopTime;
				lastLoopTime = getTime();
	
				// update the frame counter
				lastFpsTime += delta;
				fps++;
				
				// update our FPS counter if a second has passed since
				// we last recorded
				
				if (lastFpsTime >= 1000) {
					totalFps = fps;
					lastFpsTime = 0;
					fps = 0;
					
				}
				
				
				update_KevGlass(delta);
				
				render();
				
				
				sleep(lastLoopTime+15-getTime());
	   		}
	   		
	   	}

update:

if (x + 50 >= width)
		{
			currDx = -dx;
			x = width - 50;	
		}
		
		if (x < 0 )
		{
			currDx = dx;
			x = 0;
		}
		
		x += currDx * delta;

The getTime() and sleep() are the GAGE timer methods.

I have looked asll over and still cannot figure out why at 85hz I get choppy motion, while at 60Hz I get smooth motion. I do not chagne the code and call the sleep() method at the end of each cycle.

Ill try to run it this weekend and have a look.

Right now my suspicion is that what youa re seeing is tearing.

Tearing would be particualrly obvious moving a simple flat geometric shape like a reasonably large sized single-color box…

If it looks good at 60, but not 85 - the question is what refresh rate is your monitor at? I would bet (not a lot of money, but some :)) it’s at 60 Mhz.

It looks good at 85, and my refresh is ta 85. The prob I currently see it is that if I let the loop run as fast as possible (no sleep at all) then it is smooth at 85 and smooth at 60 hz refresh. But if I set a pause to like 10, then I get stutter when I am getting 67fps. I am now beggingin to suspect that neither Thread.yeild() nor Thread.sleep() are of good enough granuality to sleep an accurate amount of time. But I am using GAGE timer which has a sleep method that I am hoping is accurate.

So now a new question arises, which method does everyone usefor fixed rate fps? Thread.Yield(), Thread.Sleep(), or the sleep method in GAGE Timer? Is there another way?

Yes.

Use 1.4 or later and the nanosecond timer.

Totally jumpy here. My (rather old) mainboard has some shite chipsets which causes QPC (which is used by nanoTime) to leap. Didnt happen with win9x… does happen with 2k and above. Well, duh.

I used to use some adaptive yield loop+nanoTime, but that doesnt work anymore… for me anyways. There arent many machines affected… so you could just ignore the issue. Well, unfortunately I cant ignore it :wink:

It caps the maximum time to spend per frame at some point and if its too late with this frame, it will hurry a bit more with the next one (so with triple buffering you wont drop a frame if some frames took a tad too long).

private long timeNow, timeThen, timeLate = 0;
[...]
g.dispose();
//throttle
long gapTo = 1000000000L/75L + timeThen;
do{
	Thread.yield();
	timeNow = System.nanoTime();
}while(gapTo > timeNow+timeLate);

if(gapTo<timeNow)
	timeLate = timeNow-gapTo;
else
	timeLate = 0;

timeThen = timeNow;
//-
strategy.show();

The other method, which I’m using now uses currentTimeMillis millis again, sorta averages the last 10 frames and adjusts the amount of yielding accordingly. Seems to work fine if the time per frame doesnt fluctuate too much. (I havent tested it that much yet, but it seems to work fine.)

private long lastFrame=0;
private long []fa=new long[10];
private int faptr=0;
private float yield=1f;
[...]
long timeNow = System.currentTimeMillis();
fa[faptr++]=timeNow-lastFrame;
if(faptr>9)faptr=0;
lastFrame=timeNow;
long sum=0;
for(int i=0;i<10;i++)
	sum+=fa[i];
if(sum>160) //16msec*10 for ~62.5fps
	yield*=0.95f;
else if(yield<1f)
	yield=1f;
else
	yield*=1.05f;
for(int i=0;i<yield;i++)
	Thread.yield();

Feel free to experiment with different factors and/or less/more frames for averaging.

PLEASE bug report this. If there is hardware out there that nanotimer is failing on I think the JDK team needs to know.

I wondered about that.

“Returns the current value of the most precise available system timer, in nanoseconds.”

I mean even with leaping it still does what it says on the tin. Nothing more… nothing less. Its some hardware issue, which can happen with some of those ancient (5+ years old) chipsets. Eventually worth a note in the javadoc comment, but thats about it.

Details on the issue can be found here:
http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323&


Two years ago I filed some bug report. It got ignored… and the bug is still there (transparent frame icons doesnt work with JFrame.setDefaultLookAndFeelDecorated(true)). Easy to understand and easy to reproduce… so, I dont see much of a reason to go through that hassle again. Especially with something like this, which is extremely hard to reproduce (because you need such faulty hardware) and it will dissappear before it gets addressed anyways.

Thanks i will try your approaches. Jeff I am using 1.5 and the GAGE Timer which uses nanoTime, or nanoTime itself in the other loop examples in the code.

Ok I have made the modifications using Onyx’s Yield code. I get the same results as I do with Gage timer sleep code. Both examples can be found here: (cut and paste the links please)

Kevin’s space invaders loop using GAGE 1.5 nanoTimer and the GAGE sleep method
angelfire.com/clone/wolfbane/loop_KevGlass.jar

David Brackeen’s loop using the NanoTimer() and Onyx’s yield code.
angelfire.com/clone/wolfbane/loop_NanoTimer.jar

I have included the file mainClass.java where all the different loops reside. I am still seeing stutter, can you guys test it and let me know what you think my problem is. I beleive that I should be able to get smooth animation at 60fps going. I come to this conclusion because if I let the loops run as fast as possible (ie no sleep ) then I get smooth animation at both 85hz refresh and 60hz refresh.

To see an example of this , go to any one of the loops, remove the sleep or yield code (depending which loop you are looking at), set your monitor refresh to 60hz, then run the code. You will see that while the fps stays the same, the stutter is not there when removing the yield code.

Fair enough, but I stil lthin kthey should include a note and the link in the docs. It will ultimately save them grief, so Id BR it just as “Nanotime inconsistant on old x86 motherboards, should be a note in the docs”
or something like that 8)

Thanks

JK


Two years ago I filed some bug report. It got ignored… and the bug is still there (transparent frame icons doesnt work with JFrame.setDefaultLookAndFeelDecorated(true)). Easy to understand and easy to reproduce… so, I dont see much of a reason to go through that hassle again. Especially with something like this, which is extremely hard to reproduce (because you need such faulty hardware) and it will dissappear before it gets addressed anyways.