Little "lags" ?

Started by PinkieSwirl, February 19, 2012, 12:27:00

Previous topic - Next topic

PinkieSwirl

I get some little "lags", when i play a lwjgl application in 2D, for example the space invaders example game, or my own. Tested this on different computers (windows) with different java versions with lwjgl 2.8.3.
When i play at ~60 fps, the lag occurs every second (the sprites jump a little bit, if they move).

kappa

how is the fps capped? using Display.sync(60), vSync() or some other method?

Jonas

It might be garbage collection kicking in?  That can have a minor, yet noticeable effect for 1-2 frames, and tends to happen at fairly regular intervals.  You might try giving -XX:+UseConcMarkSweepGC as a VM argument to switch to a different garbage collection method, that helped me a bit when I had a similar situation.

PinkieSwirl

In my project i use Display.sync(60) with an option for vSync.
Something like this:

initDisplay(){
 ...
 Display.setVSyncEnabled(vSync);
}
loop() {
 ...
 Display.update();
 Display.sync(60);
}


On my pc with a intel hd "videocard", vsync has no impact?
On my other pc with a real card vsync limits the framerate.

But the lag occurs even when i do something like this:
long time = getTime();
 ...
 time = 16 - (getTime() - time);
 if (time >= 1)
  Thread.sleep(time);


Thats why i thought i do something wrong in my render function, but in the space invaders example the lag occurs too. So...?

EDIT:
Quote from: Jonas on February 19, 2012, 13:31:28
It might be garbage collection kicking in?  That can have a minor, yet noticeable effect for 1-2 frames, and tends to happen at fairly regular intervals.  You might try giving -XX:+UseConcMarkSweepGC as a VM argument to switch to a different garbage collection method, that helped me a bit when I had a similar situation.

I tried it but it has no effect (I just put "-XX:+UseConcMarkSweepGC" as an argument thats right?). And the lag isn't that minor~

princec

Thread.sleep() is not especially accurate.

Cas :)

PinkieSwirl

I know but thats not the point :D.

The problem is, it lags, but the framerate is constant at 63 fps (or 60 with vsync).

Before using lwjgl i used java2d for basic game developing / learning. And this lag occurs never, even with Thread.sleep().

princec

63fps is not exactly the right speed is it :)

Cas :)

matheus23

@Cas:
This is, because he is using
time = 16 - (getTime() - time);
, and this is kind of inaccurate, because he should acctually sleep 16.6666* ms.

Maybe the problem is, that you use both Display.sync() and your own sleep too. (Are you doing it like that, or did I missunderstood that?)
My github account and currently active project: https://github.com/matheus23/UniverseEngine

CodeBunny

I've had my games run at 63 fps before, when I am only using Display.sync(60). This definitely happens on more than one machine.

It's true, I do not have v-sync on, but still; my fps should be set to 60 but it isn't.

And yes, I see the "little lags" PinkySwirl mentioned from time to time. It's one of those issues I've always meant to look into but never really focused on.

matheus23

@CodeBunny

This is because, you usually compute the number of time your game has to wait in one frame. Usually you say:
int frameTime = 1000 / 60;

now acctually, if you divide 1000 by 60, you get 16.66666*, but as it is an int, (or long) frameTime will be set to 16. That means, your game will slightly sleep less, than it acctually should. If you run the game, you will get 63 fps, because he will only calculate the fps, if 1000ms are gone since the last second. That means, if you would take 16 ms per frame for 60 frames, you will have passed 16 * 60 = 960 [ms]. But acctually the fps counter waits for 1000ms, so you need 3 more frames to get above 1000ms: 16 * 63 = 1008.

You can easily solve the problem with "High Resolution" Timers. The standard Java library allows that (via milliseconds AND nanoseconds (See Thread.sleep and System.nanoTime()), just take a look at this:
private class DelayHandler implements UniPrintable {

		/* Delay-Handling: */
		private HighResTime sleep;
		private HighResTime delta;
		private HighResTime timeOld;
		private HighResTime time;
		private HighResTime fpsTime;
		private HighResTime realSleepBegin;
		private HighResTime realSleepEnd;
		private HighResTime realSleep;

		/* FPS-Handling: */
		public float fps;
		private long frames;
		private HighResTime fpsTimeOld;
		private long up;

		public DelayHandler() {
			sleep = new HighResTime(0, 0);
			delta = new HighResTime(0, 0);
			timeOld = new HighResTime(0, 0);
			time = new HighResTime(0, 0);
			fpsTime = new HighResTime(0, 0);
			realSleepBegin = new HighResTime(0, 0);
			realSleepEnd = new HighResTime(0, 0);
			realSleep = new HighResTime(0, 0);
			fps = 0f;
			frames = 0;
			fpsTimeOld = new HighResTime(0, 0);
			up = 60;
			setFpsTime(60);
			Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
		}

		private HighResTime getDelta() {
			frames++;
			time.set();
			delta.setSubtract(time, timeOld);

			if (frames >= up) {
				fps = ((up * 1000f) / (time.time - fpsTimeOld.time));
				frames = 0;
				UniPrint.printf("%s >> fps: %G\n", getClassName(), fps);
				fpsTimeOld.set(time.time, time.timeNano);
			}

			return delta;
		}

		/**
		 * Call this after every frame.
		 * 
		 * @param fps
		 *            - The wanted FPS to sync to.
		 * @return whether you should exit the loop or not.
		 */
		public boolean update(boolean dodelay) {
			sleep.setSubtract(fpsTime, getDelta());
			sleep.normalizeNano();
				if (dodelay) {
				try {
					realSleepBegin.set();
					while (sleep.time > 0) {
						Thread.sleep(sleep.time, (int) sleep.timeNano);
						realSleepEnd.set();
						realSleep.setSubtract(realSleepEnd, realSleepBegin);
						sleep.setSubtract(sleep, realSleep);
					}
					timeOld.set();
					return false;
				} catch (InterruptedException e) {
					UniPrint.printerrf(this, "Error while sleeping!\n");
					e.printStackTrace();
					return true;
				}
			}
			return false;
		}
		
		public void setFpsTime(long fps) {
			fpsTime.set(1000L/fps, (1000000000L/fps)%1000000L);
		}
		
		/**
		 * Set how much frames to wait, until the next
		 * frame rate is printed. Also affects fps
		 * calculation, because fps are calculated, 
		 * when they are printed.
		 * @param frames - the frames to wait.
		 */
		public void setFpsCalcDelay(long frames) {
			up = frames;
		}
		
		public String getClassName() {
			return getClass().getSimpleName();
		}

		private class HighResTime {
			
			public long timeNano;
			public long time;
			
			public HighResTime(long timeNano, long time) {
				this.timeNano = timeNano;
				this.time = time;
			}
			
			public void set() {
				timeNano = System.nanoTime();
				time = System.currentTimeMillis();
			}
			
			public void set(long t, long tn) {
				time = t;
				timeNano = tn;
			}
			
			public void setSubtract(HighResTime t1, HighResTime t2) {
				timeNano = t1.timeNano - t2.timeNano;
				time = t1.time -t2.time;
			}
			
			public void normalizeNano() {
				timeNano = timeNano % 1000000L;
				timeNano = timeNano < 0 ? timeNano+1000000L : timeNano;
			}
			
		}
	}

(This is code from my UniverseEngine :) )
The Code is not very good written and documented (cause its private), but it should give you an idea :)

[EDIT: Little corrections...]
My github account and currently active project: https://github.com/matheus23/UniverseEngine

CodeBunny

I understand how to do it on my own; I'm talking about using the standard LWJGL call Display.sync (which is what should be used, because it's supposed to package all of the logic you are talking about. The problem is more that the standard API call is not correct, not that I'm unable to create my own method of keeping framerate.

It's getting fixed, though. There's a topic here: http://lwjgl.org/forum/index.php/topic,4452.0.html.

CodeBunny

Also are you sure your code is optimal? The main problem is that using Thread.sleep and similar functions results in poor behavior, because those methods do not always result in perfect timing.

matheus23

@CodeBunny:
1st: Oh, sorry, misunderstood that :)
2nd: Hmm.... The only other ways of implementing sleep is the "Native" way: sleep() (for windows) and usleep() (for everything else (?)). But I have never used JNI, and I'm not planning to do it... The only other way of Thread.sleep()-kind methods is the LockSupport (or something like that :/, Googleing it showed, that thats not the name ...), which I tried out too, but was muuuuuch worse. And as it is a personal interest too: Is there a good alternative too Thread.sleep() ? Many people ask for something like that.
My github account and currently active project: https://github.com/matheus23/UniverseEngine

CodeBunny

That's actually what this thread (http://lwjgl.org/forum/index.php/topic,4452.0.html) is entirely about - apparently, it's difficult to get a truly optimal game loop framerate.