Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Setting GraphicsDevice to 30Hz Refresh Actually Sets 29Hz. Why?

 
Stevens Miller
Bartender
Posts: 1377
28
C++ Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I posted this at StackOverflow, but it didn't get much traction.

I am using Java SE8 on Windows 10 to set my ViewSonic VX2453 monitor to a 30Hz refresh rate when it is in full-screen mode. When I query the device, however, it reports that it is set to 29Hz. Both 30Hz and 29Hz are listed among the display modes available for the monitor. Here's my code, which reports all of the available display modes for each of the three monitors on my computer. The VX2453 is the first of the three: Here's my output (with extraneous lines edited out):
run:
Device 0:
dm[ 0]:  640 x  480 : 32 -  56
...
dm[40]: 1920 x 1080 : 32 -  29
...
dm[43]: 1920 x 1080 : 32 -  30
...
dm[45]: 1400 x 1050 : 32 -  60
Device 1:
dm[ 0]:  768 x 1024 : 32 -  75
...
dm[18]:  600 x  800 : 32 -  56
Device 2:
dm[ 0]:  768 x 1024 : 32 -  75
...
dm[22]:  720 x 1280 : 32 -  60
1920 x 1080 32 - 29
The monitor is initially at 60Hz before the program runs.

setDisplayMode throws an IllegalArgumentException if any of its parameters are not supported by the GraphicsDevice. My call, asking for 30Hz, does not throw an exception (but, as a test, a call asking for 31Hz does thrown an exception).

Why does a successful call to setDisplayMode specifying a refresh rate of 30Hz end up returning 29Hz in a subsequent call to getDisplayMode?
The one comment I got at SO suggested it was a truncation from the actual rate of 29.97, and that I should check with another utility. Below is the update I added in response.

UPDATE:

As Durandl suggested, I checked the actual refresh rate after each requested change. Here's what I got:
Asked for  Reported  Actual
   59         60      60.1
   60         60      60.1
   25         25      49.9
   50         50      50.0
   29         29      59.9
   30         29      60.0
Now, in "PC" mode, the monitor's menu reports my screen resolution as "1920x1080," for all the rates above (which is what I asked for). But, in "AV" mode (where it slightly overscans the physical screen), the monitor's menu reports it as either "1080p" or "1080i." For all the refresh rates below 50, it is 1080i. For all of them at 50 or above, it is 1080p. Thus, as it appears the lower rates all put the monitor into interlaced mode, that explains why the vertical frequency is (roughly) twice the requested refresh rate. That part makes sense, as does the slight departure the monitor reports from the integral values requested. But it still doesn't explain why a request for "30" returns "29."

Interestingly, there is no screen flicker in the "change" from 59Hz to 60Hz, both of which report 60 from getDisplayMode, nor is there any screen flicker in the "change" from 29Hz to 30Hz, both of which report 29 from getDisplayMode. I'm guessing those pairs of modes are actually the same, in operation.

Still puzzled about the odd return value. Anyone got an idea what's behind it?
 
Junilu Lacar
Bartender
Pie
Posts: 8861
81
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No idea what's going on there. I tried your code out on my MacBookPro with two external monitors attached. Didn't see the same problem. My display modes actually get restored once the program exits. I also got one run where Java basically did a core dump. I don't think it was happy.

Have a cow for your trouble though. I hope you or somebody figures it out.
 
Stevens Miller
Bartender
Posts: 1377
28
C++ Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:I tried your code out on my MacBookPro with two external monitors attached. Didn't see the same problem.

Extraordinary. And thanks for trying my code on your machine. Java's weaknesses included not playing well with hardware. This may be a symptom of that.

My display modes actually get restored once the program exits.

That's in the code (myDevice.setFullScreenWindow(null); and, I think, the OS might know about mode changes during applications.

I also got one run where Java basically did a core dump. I don't think it was happy.

Whoa. That shouldn't happen. While I don't know why it reports a different refresh rate than I've requested, I'm pretty confident that my code is compliant with all relevant contracts, and ought not to cause an exception. What kind of "dump" are you getting?

Have a cow for your trouble though.

Thanks!

I hope you or somebody figures it out.

Yeah, me too.
 
Junilu Lacar
Bartender
Pie
Posts: 8861
81
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One thing I noticed in the API docs was that these graphics device calls are Native.  So, if there's something going on between Java making the call to the native OS routines and what those are doing outside of the JVM and whatever values they're returning and how Java ends up interpreting those return values, I don't know if there's much you can do about it except maybe report it as a potential issue for your platform and then wait for an update. Maybe.
 
Stevens Miller
Bartender
Posts: 1377
28
C++ Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:One thing I noticed in the API docs was that these graphics device calls are Native.

Where did you see that? It's not really surprising (dealing with hardware pretty much calls for native code), but it's rare to see it acknowledged in the javadoc. Indeed, much of the display-related javadoc is uncharacteristically terse, vague, and/or opaque. For example, BufferStrategy.show() blocks when called until the next time the monitor where the show will occur does a vertical sync, when that monitor is in full-screen mode. For games and animation, that's exactly what you want. But the javadoc says nothing about it. I discovered this behavior by experiment (and, later, found it confirmed in the book, "Killer Game Programming in Java," although the author gives no reference to authority to back up his statement). Other entries are similar. For example, Toolkit.sync()'s entire entry is this:

Synchronizes this toolkit's graphics state. Some window systems may do buffering of graphics events.
This method ensures that the display is up-to-date. It is useful for animation.

"Graphics state?" What's that? Graphic "events?" What are those? And how is this "useful for animation?" Useful how?

Lately, that's what I'm working on: animation. So coping with vertical sync signals and buffering are suddenly a big part of what I'm doing. And, for the first time, it seems as though the (typically lucid and helpful) javadoc has suddenly become outright timid about telling me how things work.

It's disappointing, to say the least.
 
Junilu Lacar
Bartender
Pie
Posts: 8861
81
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I should have double checked before I replied. A couple of fields in the DisplayMode class were marked @Native; that's what I vaguely remembered when I replied. Actually, looking back at the guidelines, JavaDocs aren't even supposed to say if a method is native or synchronized. I still might assume that whatever graphics capabilities Java were to access were at least OS specific since it is getting down close to the hardware. I'm no expert in display drivers and such though so don't take anything I say as authoritative. I wouldn't

One thing this thread has done for me though is made me look at the Graphics trail in the Tutorials. Gives me ideas on how I might spice up future Code Retreats with a plug-and-play GUI-based framework for Conway's Game of Life.
 
Junilu Lacar
Bartender
Pie
Posts: 8861
81
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stevens Miller wrote:
Synchronizes this toolkit's graphics state. Some window systems may do buffering of graphics events.
This method ensures that the display is up-to-date. It is useful for animation.

"Graphics state?" What's that? Graphic "events?" What are those? And how is this "useful for animation?" Useful how?

Again, no authority here, but from what little experience I had playing around with graphics in the long, distant past, I'd imagine this had to do with things like refreshing, flipping, clearing, painting, and drawing to display page buffers. I remember the idea of double buffering and drawing to a hidden buffer while the system was busy displaying the "active" buffer. I did this kind of thing for character window "shadows" and highlighting/unhighlighting window borders. Ah, waxing nostalgic now for Clipper and calling out to routines written in C. Ancient, stone-age technologies by today's standards, like in the MS/DOS days.
 
Stevens Miller
Bartender
Posts: 1377
28
C++ Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
Stevens Miller wrote:"Graphics state?" What's that? Graphic "events?" What are those? And how is this "useful for animation?" Useful how?

Again, no authority here, but from what little experience I had playing around with graphics in the long, distant past, I'd imagine this had to do with things like refreshing, flipping, clearing, painting, and drawing to display page buffers.
Same here, but it's not typical of good documentation (and I consider the vast majority of the SE8 API javadoc to be excellent) to require that we "imagine" what a method does. It feels, to me, like the person who wrote this particular javadoc didn't really know what the method does, asked someone who also didn't really know, and got, "It's useful for animation" as the answer. Just not up to par, imho.

I remember the idea of double buffering and drawing to a hidden buffer while the system was busy displaying the "active" buffer.
Oh, that technique is very much still with us. In fact, what drove me to this particular point of inquiry was the fact that (afaik) Java doesn't offer any way to synchronize screen-refresh to a monitor's actual vsync event while in window mode. In full-screen mode, like I said, BufferStrategy.show does this automatically (though, again, this fact is jaw-droppingly absent from the API javadoc).

I did this kind of thing for character window "shadows" and highlighting/unhighlighting window borders. Ah, waxing nostalgic now for Clipper and calling out to routines written in C. Ancient, stone-age technologies by today's standards, like in the MS/DOS days.
Heh. I lived through those days too. We were able to do some excellent things with those methods and, for those of us who remember them, the possibilities when they are combined with the speed of modern hardware and the maturity of modern libraries are close to Olympian. The biggest difference I see in graphics programming today and in how we did it at the New York Institute of Technology's Computer Graphics Laboratory in the '80s, is that the frame of animation we took hours to draw back then can be drawn in less than a frame-time today. In the '80s, we were making movies and playing them back when they were finally done. Today, we are computing the imagery in real time, and interacting with it as it is computed. The underlying methodologies are largely unchanged: we still use polygons, transformation matrices, texture maps, transparency maps, bump maps, and so on. We still script the motions of objects along parameterized cubic splines, or other algebraic trajectories. Much of what I had to learn, 30 years ago, is perfectly practical knowledge that I can still use today.

But...

We never had to worry about being synchronized with a monitor's refresh events. When you record your frame to videotape, it will synchronize itself when you play it. The problem of making sure your time-step precisely matches your frame-rate did not exist in those days, because we couldn't come close to computing a frame in less than one frame-time. I imagine the early arcade games had to cope with this (Space Invaders, for example), but I do recall many of them clearly ignoring it. As a result, you not only got somewhat uneven animation, you also got "tearing," which is when the display flips from one frame to the next mid-way through the process of painting it onto the screen. You can cope with both if you can block on the vsync event. Coping with tearing is implicit in blocking on vsync. Making sure your animation is even (that is, free from temporal aliasing, which some folks rather inelegantly now call "janking"), is a bit harder, because you also need to know which frame you are blocked waiting for. If you miss one and don't know it, your animation falls behind. You can check a system clock, like the Windows performance counter or System.nanoTime(), and catch up, but you can't live without being able to block on vsync somehow. And, alas, I have not yet found a standard way to do that in Java while in window mode.

My quest continues...
 
Junilu Lacar
Bartender
Pie
Posts: 8861
81
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I posted this in another forum some time ago but you might want to check out the book in case it has something useful for you:

 
Stevens Miller
Bartender
Posts: 1377
28
C++ Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:I posted this in another forum some time ago but you might want to check out the book in case it has something useful for you:



Hey, great link! Thanks.

Now, if you have a moment, this whole line of investigation has taken me to a mind-blowing revelation that maybe you can help me understand. Please have a look at my latest question in Java in General. I'm feeling pretty confused just now...
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic