Solving Stuttering With Fixed Timesteps, Once and For All

Wait, I thought the wrapping was achieved later in the code by something like:

if (now < then) { }

…Yes?

More observations (although… note that most if not all of my observations throughout both the TIGForums thread and this thread are basically subjective…):

Recently I seem to have observed that the GM example actually stutters more than I had thought. I think it’s usually better than the Java examples and all around GM’s the most consistent, but currently I suspect that:

-When GM stutters it can be more noticeable than some Java implementations? Especially on (only on?) those computers on which LWJGL’s vsync can take effect.

-GM usually tends to run smoothly for longer periods of time than the Java examples, but not? on those computers for which the Java examples don’t stutter (i.e. my school’s computers). Furthermore, on those computers GM seems to alternate between no stuttering and stuttering more frequently than the Java examples.

Also, another issue: While the simple GM example stutters on those school computers, I had difficulty detecting any stuttering (there was some stuttering, but very little of it) with the demo for a game of mine, Platform Battle 2. In fact I think this might also have been the case during some trials on our desktop (although Java stutters on it). This may have something to do with the implementation:

-With the simple example, nothing is scaled and the box is moved at 2 pixels, whereas, in PB2, although the object I observed (a moving platform in the tutorial) still moves at 2 pixels, the graphics are scaled to two times its “actual” size by a method by ChevyRay.

-PB2 uses a sprite for the platform and has a patterned background. (I do, however, think that I looked pretty closely…)

Install FRAPS demo and report the FPS.

Cas :slight_smile:

Wait, isn’t the FPS reported by the program enough?


I updated the box.com download with a new example. If I understand correctly, it’s a sort of hybrid between Cas’s example and Eli Delventhal’s. I’m not sure if it’s any smoother than any of the other Java examples, but there’s at least one new thing being done here.

I noticed that Cas’s example can loop many times without CPU problems. I think this means that, even if one of these example programs loops many times, the CPU only starts groaning if it also renders very fast (although it seems that the CPU still starts groaning if the looping is too fast). I tried looping like this in the hybrid example because it seems to me that, since the program checks the time more often, the timing would be more precise.

Also, I incorporated Eli Delventhal’s timing method but applied it not only to logic updates but also to the rendering, which amounts, if I understand correctly and if I’m using the right terms, to making logic and rendering almost completely independent of each other in a sense. Put another way, they’re each sort of on their own schedule.

Again, I can’t really tell if all this allows the program to run any better than any of the other examples, but there it is anyway.

Here’s some of the relevant code:

public void start() {
		try {
			Display.setDisplayMode(new DisplayMode(800, 600));
			Display.create();
		} catch (LWJGLException e) {
			e.printStackTrace();
			System.exit(0);
		}
		
		initGL(); // init OpenGL
		
		vsync = false;
		dsync = false;
		wait = true;
		drawInterpolated = true;
		
		timerResolution = 1000000000;
		updateRate = 60;
		renderRate = GraphicsEnvironment.getLocalGraphicsEnvironment()
				.getDefaultScreenDevice()
				.getDisplayMode().getRefreshRate();
		if (renderRate == java.awt.DisplayMode.REFRESH_RATE_UNKNOWN) renderRate = 60;
		
		double updateInterval = timerResolution / (double) updateRate;
		double renderInterval = timerResolution / (double) renderRate;
		double lastFPSTime = System.nanoTime();
		double lastUpdateTime = lastFPSTime;
		double lastRenderTime = lastFPSTime;
		int updateCount = 0;
		int renderCount = 0;
		int loopCount = 0;
		updatesPerSecond = 0;
		rendersPerSecond = 0;
		loopsPerSecond = 0;
		maxUpdates = 5;
		
		Display.setVSyncEnabled(vsync);
		
		while (!Display.isCloseRequested()) {
			double now = System.nanoTime();
			int localUpdateCount = 0;
			while (now - lastUpdateTime > updateInterval && localUpdateCount < maxUpdates) {
				update();
				lastUpdateTime += updateInterval;
				localUpdateCount++;
				updateCount++;
			}
			if (now - lastUpdateTime > updateInterval) {
				lastUpdateTime = now - updateInterval;
			}
			now = System.nanoTime();
			if (now - lastFPSTime > timerResolution) {
				lastFPSTime = now;
				//lastFPSTime += timerResolution;
				updatesPerSecond = updateCount;
				rendersPerSecond = renderCount;
				loopsPerSecond = loopCount;
				updateCount = 0;
				renderCount = 0;
				loopCount = 0;
				Display.setTitle(updatesPerSecond
						+ ", " + rendersPerSecond
						+ ", " + loopsPerSecond
						+ "; VSync: "+ vsync
						+ "; Display.sync(): " + dsync 
						+ "; Interpolated drawing: " + drawInterpolated 
						+ "; Yield and sleep: " + wait);
			}
			interpolation = (float) ((now - lastUpdateTime) / updateInterval);
			now = System.nanoTime();
			if (now - lastRenderTime > renderInterval) {
				renderGL();
				Display.update();
				//lastRenderTime = now;
				lastRenderTime += renderInterval;
				renderCount++;
			}
			while (now - lastRenderTime > renderInterval) {
				lastRenderTime += renderInterval;
			}
			loopCount++;
			if (dsync) {
				Display.sync(60); // cap fps to 60fps
			} else if (wait) {
				Thread.yield();
				try {
					Thread.sleep(1);
				} catch (Exception e) {}
			}
		}
		
		Display.destroy();
	}

FRAPS tells it like it is :slight_smile:

Cas :slight_smile:

Well, I think I’ll have to look into it more to be able to use it?


Two things:

a) You know, I think I’m just going to incorporate the “extra sleeping thread” fix; with it, at least three of the Java examples seem to work just fine, as far as I can tell so far. The Java examples still stutter on my laptop, but so does the Game Maker example. Note: the download has not yet been updated.

I still feel that this solution is a bit inelegant, though. The extra thread forces the program to use a more precise (?) timer, right? Does that mean that functions like System.nanoTime() become more precise, that Thread.sleep becomes more precise, or both? I’d like to think that it’s Thread.sleep; it would be nice to know that the timing, at least, is always reliable.

Does anyone know why the reliability of Thread.sleep would be so conditional (?)? Will they ever make it so Thread.sleep always behaves as it does with this solution?

b) Before incorporating that solution, though, something strange happened on my laptop: it started acting like our desktop for a moment! That is, the Game Maker example seemed to run more smoothly than usual, and some if not most of the Java examples were less smooth than usual and couldn’t maintain 60 FPS. The programs started to behave as normal after I restarted the computer; this sometimes works on my desktop. Thus, it seems to me that there are (at least) two common computer settings, one in which Game Maker and Java behave similarly, and one in which Game Maker gets less stuttering than usual but in which Java gets more. What could be the cause of this?

btw really appreciate your work here Saucer.
My game still jitters when there not much going on.

And the “DelventhalExample” looks the best to me. Gotta try that. Nice package

Thanks for the input, Cero! It’s been a while since I’ve visited this topic, ha ha.

Have you tried the “extra sleeping thread” method? It seems that the fix:

  • has no effect on computers that yield little stuttering anyway,
  • reduces most stuttering on the computer I tested that yielded the most stuttering, and
  • has no effect on my laptop, on which the GM test program and my programs all stutter.

Note that I haven’t updated the downloads with this fix.

By the way, although I had known about that fix from when this thread was started, it seemed too inelegant. Eventually, I decided to incorporate it into my programs.

as yes you mean this


new Thread() { 
{ setDaemon(true); start(); } 
@Override public void run() { while(true) {try {Thread.sleep(Integer.MAX_VALUE);}catch(Throwable t){} } } 
}; 

sure, I use this.

Also I have to add. the stutter, in general, seems to happen more often when there is not a much going on.
For example in m game, when I’m just walking and there is nothing fancy going on, its more likely to happen than when there is more going on.
This would also explain why my simple cube example is so very vulnerable to this, and seems to stutter somewhat in all game loop examples
So my guess is that, why a game would run at a very high FPS normally, like > 600 or something, slowing it down to 60 can cause stutters way more likely than slowing it down form like 200 fps or 100 fps to 60.

so I guess this is the bottom line: The higher your fps WOULD BE, the more the slowing down has to be done, the higher the chance of stuttering is.
This doesn’t seems to apply for fullscreen Vsynced.

Yeah, so with the computers I’ve tested, the only computer on which I get stuttering even after applying the extra sleeping thread method is the computer on which the Game Maker example stutters. How has the GM example been running for you?

Also, I suspect that the stuttering only seems to get worse with less going on— in other words, it’s just less noticeable with more going on, and doesn’t actually yield stuttering any less. But I haven’t really tested this guess precisely.

minimal stuttering, 100x times better than Cas’ method (which my game is using right now)

I dont think thats it. See - I have a side scroller, which makes it really apparent when walking in one direction.

Also I cannot capture it. Using FRAPS the stuttering disappears when recording - further confirming my theory

Fraps capture individual frames, like if you did a readback to the CPU after each Display.update() on LWJGL. Even if the frame doesn’t actually end up on the screen due to the asynchronous behaviour between your CPU, your GPU and your monitor, Fraps will still capture it.

Using OpenGL and the desktop window compositor you are never going to be rid of stuttering, end of story. Gamemaker directly interfaces with the DWC because it uses DirectX. It’s a Windows fail. The only ways around it are: go fullscreen or turn off DWC or go back to Windows XP.

Cas :slight_smile:

btw Saucer, did you try libgdx because of the stuttering ? was just curious, never used it before

No, I haven’t. Is it pretty widely used?

Absolutely.
LWJGL along with libgdx are 2 big engines, although different.
Pretty sure in JOGL you would have to do it all yourself, and I hear libgdx is a little more high level than lwjgl.
So i guess it has something like this aswell.

LWJGL is not an engine, just a simple binding to OpenGL, OpenAL and OpenCL, so pretty low level. LibGDX has a lower and higher level API and uses LWJGL underneath for its desktop versions.

Wait, I looked a little bit into libGDX: apparently it uses some C/C++ (= “native code”?)? Anyone know the details of what that does for libGDX?

Make it’s faster. There is example native box2d wrapper, bullet wrapper is coming. Lot of bytebuffer stuff etc. There is native code in every openGl wrapper too.
User don’t have use any native code so it’s hided from the end user pretty well.

…Wait yeah, you’ve brought up a good point: LWJGL, for example, uses native code, too! Hence the DLL. Oops. Thank you for the input, pitbuller.