Why Java games look choppy: Vertical Retrace

This is a pointless thread that I wanted to start to let other newbs like myself know why their animations look terrible.

I’ve always wondered why many java games look so crap, including mine. The animation isn’t smooth even when running on state-of-the-art computers. At first I blamed the garbage collector since it pauses all threads and it’s uncontrollable. But GC pauses are usually insignificantly small.

The real problem is the vertical screen retrace (the monitor refresh rate). Chet Haase showed the problem is his blog entry: Make Your Animations Less Ch-Ch-Choppy.

Vertical retrace is a massive problem because it can cause your images to be displayed up to 16.6 milliseconds late if the screen refreshes at 60Hz. This is noticable to the human eye.

The other problem is that it causes your animations to become ‘torn’ when a new image is drawn half-way through the vertical retrace, so the top half of the old screen image remains but the new one takes up the bottom half. This looks fugly to say the least.

As Chet said in his follow-up blog,
Smooth Moves:

"The fix is easy for anyone writing a fullscreen Java application; applications that use the FlipBufferStrategy get this for free. When that buffer strategy copies its contents to the screen from the back buffer, it specifically waits for the vertical blank interface, and thus avoids tearing completely.

The fix is not as easy for typical windowed (non-fullscreen) applications, because there is currently no way to tell Java to wait for this interval, and there is no way for your code to know when it is a good time to go ahead with the copy. We hope to address this in a future release (I just filed a bug on it last week!), but in the meantime there is no way to get this behavior."

Anyway, i think this is one of the last things Java 2D needs to make our apps look decent, so if someone can help me find that bug & vote for it, (and politely hassle Sun’s J2D team to work it out ;)), all the better for us.

PS: Interestingly, on my computer with the OGL pipeline enabled I get v-syncing when my BufferStrategy uses 2 buffers, but with 3 or more I lose the v-syncing.

Here’s the bug Chet Haase reported, and I’ve cast my 2 lousy votes against it, join in!

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6378181

Not sure if this would help, but I wrapped this up for vsync in Java2D windows in the Mini Adventure days:

http://www.newdawnsoftware.com/resources/pxsync/

It’s a small native library that allows you to get vsync in a window on Windows. On other platforms v-sync is the default anyway.

Probably doesn’t work for OpenGL pipeline of course :frowning:

Kev

Awesome, JGO power all the way :D, 0 -> 8 votes in 24hrs. At this rate it should be in the top 25 RFE’s by the end of the month ;).

Thanks for the code! I’m going to give it a try & compare performance since Chet did something similar & the app ate ~100% of CPU power.

When you say on other platforms it is the default, do you mean that all painting is sync’ed? Is that a rule for all Linux & Macs?

Keith

Last time I check windows using X dispaly are vsynced by default yes. So that covers Linux and MacOS X.

Kev

We do intend to fix this in upcoming release. Didn’t make it into JDK 6, unfortunately.
So save your votes for bugs we don’t intend to fix =)

Dmitri

Cool, can’t wait for JDK 7 then. That fix will be the best thing for percieved performance.

Its great to have you & Chris Campbell keeping us informed here.

Keith

http://koti.mbnet.fi/akini/java/vsync/
I did a small test program with vsync library (with and without vsync).

BufferedFrame (without vsync):

  • eat only 1-2% CPU
  • targetFPS=100, run at constant 99-100 fps, use System.currentTimemillis() + Thread.sleep for fps capping

BufferedFrameVSYNC (with vsync):

  • eat 99-100% CPU if I remove Thread.sleep() method call at the end of mainloop
  • run at 61-62 fps with vsync library, I tested it on laptop lcd screen

Animation:
text is animated based on delta time and drawn to a new position. Both versions suffer occassional few pixels hops, but probably due to my doMainLoop implementation(??).

Final conclusion:
You still need an accurate sleep method to consume less CPU. Eating all cpus on windowed (small) game is not nice.