[BUG] LWJGL sets wrong display mode on exit (Linux)

Started by vurpo, December 09, 2015, 13:49:04

Previous topic - Next topic

vurpo

Hello. I'm using Fedora 22, with a GTX 760 (with Nvidia proprietary driver), and two monitors. When I run an LWJGL application (tested with LibGDX and Minecraft), the display mode for one of my monitors is set wrong on application exit. Here is my xrandr output:

Screen 0: minimum 8 x 8, current 3200 x 1200, maximum 16384 x 16384
DVI-I-0 disconnected (normal left inverted right x axis y axis)
DVI-I-1 disconnected (normal left inverted right x axis y axis)
HDMI-0 connected primary 1920x1200+0+0 (normal left inverted right x axis y axis) 519mm x 324mm
   1920x1200     59.95*+  59.88  
   1920x1080     60.00    59.94    50.00    60.05    60.00    50.04  
   1680x1050     59.95  
   1600x1200     60.00  
   1440x900      59.89  
   1280x1024     75.02    60.02  
   1280x800      59.81  
   1280x720      60.00    59.94    50.00  
   1152x720      60.00  
   1024x768      75.03    60.00  
   800x600       75.00    60.32  
   720x576       50.00  
   720x480       59.94    60.05  
   640x480       75.00    59.94    59.93  
   624x464       59.95  
DP-0 disconnected (normal left inverted right x axis y axis)
DVI-D-0 connected 1280x1024+1920+176 (normal left inverted right x axis y axis) 338mm x 270mm
   1280x1024     60.02*+
   1024x768      60.00  
   800x600       60.32  
   640x480       59.94  
DP-1 disconnected (normal left inverted right x axis y axis)


On the monitor "HDMI-0", there are two different modes for the highest resolution: 59.95 Hz (default, works) and 59.88 Hz (doesn't work). When the mode for the monitor is set to 59.88 Hz, the screen goes blue (as if there's no signal). When a LWJGL application exits, it sets the mode for HDMI-0 to the one that doesn't work, and to fix it I have to use xrandr to set it back to the default mode.

When I run a LibGDX application with LWJGL debug output on (org.lwjgl.util.Debug), this is the output from the start of the game to the end:

[LWJGL] getPathFromClassLoader: searching for: openal
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String)
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String)
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String)
[LWJGL] getPathFromClassLoader: searching for: lwjgl
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String)
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String)
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String)
[LWJGL] getPathFromClassLoader: searching for: lwjgl
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String)
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String)
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String)
[LWJGL] getPathFromClassLoader: searching for: lwjgl
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: sun.misc.Launcher$AppClassLoader.findLibrary(java.lang.String)
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.net.URLClassLoader.findLibrary(java.lang.String)
[LWJGL] Failed to locate findLibrary method: java.lang.NoSuchMethodException: java.security.SecureClassLoader.findLibrary(java.lang.String)
[LWJGL] Found 27 OpenAL paths
[LWJGL] Testing '/tmp/libgdxmax/31ce78a2/libopenal64.so'
[LWJGL] Found OpenAL at '/tmp/libgdxmax/31ce78a2/libopenal64.so'
[LWJGL] MemoryUtil Accessor: AccessorUnsafe
[LWJGL] Xrandr extension version 1.4
[LWJGL] Using Xrandr for display mode switching
[LWJGL] XF86VidMode extension version 2.2
[LWJGL] Initial mode: 1920 x 1200 x 24 @59Hz
[LWJGL] Pixel format info: r = 8, g = 8, b = 8, a = 8, depth = 24, stencil = 0, sample buffers = 0, samples = 0

[the game is running, irrelevant non-LWJGL output is omitted...]

[LWJGL] XF86VidMode extension version 2.2


What's weird is that this just started happening a while ago, and I can't seem to see what caused it, as it worked fine before. I even reinstalled my system and started clean, and the issue is still there.

ali1234


tulius

Hotfix guy here.

Congrats, you have found yet another exotic output of xrandr that breaks the parsing logic.  :)

The core problem here is that it is a bad idea to parse xrandr text output in the first place.

Back when I did that hotfix, LWJGL would read the refresh rate from lib(x)randr (which is technically correct).
However, it was read with outdated API calls that deliberately returned wrong frequency values in multi-monitor setups, because other tools/programs break when the same modeline is returned multiple times - which happens if you attach more than one monitor.
Since LWJGL did parse xrandr anyway, I changed the code to use the values from the xrandr output, which are correct.
This fixed many problems with multi-monitor setups, displays with 120Hz, etc.

I didn't knew better at the time, but the real solution would have been to modify the C code and find out how to read the actual values from lib(x)randr.
Since I never found the time to do this, noone else did, and LWJGL 2 is EOL anyway, minecraft and other games still do not work with exotic xrandr outputs.

Short them solution: Patch the code again and use floats, but prepare for funny bug reports - By putting the right things in your xorg.conf, you can basically set that xrandr output to arbitrary strings, and people do this  :)
Real solution: Tell @grum and other mojang folks again and again until they switch to LWJGL 3, where everything is awesomeTM



ali1234

Or just use the workaround wrapper script I just posted on the github bug. :)

It's quite ironic that I can only make this workaround because you call an external binary rather than using libxrandr directly. If you did the latter and messed it up then I would have to make a preload library to dynamically patch the code, like I had to do with flash -> https://github.com/ali1234/fullscreenhack

What I would really like to know is, since I am not using full screen, why is LWJGL touching the screen mode *at all*?

tulius

LWJGL2 just always resets the monitor configuration on exit in case anything was changed (resolutions, frequency, bpp, gamma, secondary monitors disabled...)

But yeah, you are right, no need to do most of these things for windowed applications.

spasi

I've made an attempt to fix this. Two changes:

- The original frequency is stored as a string, used as is when the screen configuration is restored.
- The screen configuration is not reset on exit, unless there has been a display mode change.

I'm afraid I'm not able to test the patch atm, so please try the next nightly build and let me know how it goes.