Where/when is it ok to call setFullscreen()?

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Where/when is it ok to call setFullscreen()?

Marian Schedenig
I allow users to toggle my game's fullscreen mode from an ingame menu. When the fullscreen button is clicked, I call:

glWindow.setUndecorated(fullscreen);
glWindow.setFullscreen(fullscreen);

(fullscreen being a boolean variable, of course)

Sometimes this works fine, but often it triggers a lock exception (see below) and apparently locks up the animator (I use an FPSAnimator). Resize events still update my window, but the animator doesn't.

I do all my own logic from my GLEventListener's display() method. I tried disabling the animator before calling setFullscreen() and reenabling it afterwards, but it didn't help, probably since setFullscreen() internally calls runOnEDTIfAvail() anyway.

This is all on Linux/X11/KDE by the way, I haven't yet tested it on other platforms.

Perhaps I'm simply calling setFullscreen() from the wrong location. But in that case, where/when *is* the correct time to call it?

Exception in thread "main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0" com.jogamp.opengl.util.AnimatorBase$UncaughtAnimatorException: javax.media.opengl.GLException: Caught RuntimeException: Waited 5000ms for: <7d0e0c8b, 2559b9d1>[count 1, qsz 0, owner <main-Display-.x11_:0-1-EDT-1>] - <main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0> on thread main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0
	at com.jogamp.opengl.util.AWTAnimatorImpl.display(AWTAnimatorImpl.java:84)
	at com.jogamp.opengl.util.AnimatorBase.display(AnimatorBase.java:446)
	at com.jogamp.opengl.util.FPSAnimator$MainTask.run(FPSAnimator.java:175)
	at java.util.TimerThread.mainLoop(Timer.java:555)
	at java.util.TimerThread.run(Timer.java:505)
Caused by: javax.media.opengl.GLException: Caught RuntimeException: Waited 5000ms for: <7d0e0c8b, 2559b9d1>[count 1, qsz 0, owner <main-Display-.x11_:0-1-EDT-1>] - <main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0> on thread main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0
	at javax.media.opengl.GLException.newGLException(GLException.java:75)
	at jogamp.opengl.GLDrawableHelper.invokeGLImpl(GLDrawableHelper.java:1318)
	at jogamp.opengl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:1138)
	at com.jogamp.newt.opengl.GLWindow.display(GLWindow.java:666)
	at com.jogamp.opengl.util.AWTAnimatorImpl.display(AWTAnimatorImpl.java:77)
	... 4 more
Caused by: java.lang.RuntimeException: Waited 5000ms for: <7d0e0c8b, 2559b9d1>[count 1, qsz 0, owner <main-Display-.x11_:0-1-EDT-1>] - <main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0>
	at jogamp.common.util.locks.RecursiveLockImpl01Unfairish.lock(RecursiveLockImpl01Unfairish.java:198)
	at jogamp.nativewindow.ResourceToolkitLock.lock(ResourceToolkitLock.java:56)
	at javax.media.nativewindow.DefaultGraphicsDevice.lock(DefaultGraphicsDevice.java:126)
	at jogamp.newt.driver.x11.DisplayDriver.dispatchMessagesNative(DisplayDriver.java:109)
	at jogamp.newt.WindowImpl$FullScreenAction.run(WindowImpl.java:2347)
	at jogamp.newt.WindowImpl.runOnEDTIfAvail(WindowImpl.java:2123)
	at jogamp.newt.WindowImpl.setFullscreenImpl(WindowImpl.java:2457)
	at jogamp.newt.WindowImpl.setFullscreen(WindowImpl.java:2434)
	at com.jogamp.newt.opengl.GLWindow.setFullscreen(GLWindow.java:432)
Reply | Threaded
Open this post in threaded view
|

Re: Where/when is it ok to call setFullscreen()?

Sven Gothel
Administrator
On 08/19/2014 01:18 AM, Marian Schedenig [via jogamp] wrote:

> I allow users to toggle my game's fullscreen mode from an ingame menu. When
> the fullscreen button is clicked, I call:
>
> glWindow.setUndecorated(fullscreen);
> glWindow.setFullscreen(fullscreen);
>
>
> (fullscreen being a boolean variable, of course)
>
> Sometimes this works fine, but often it triggers a lock exception (see below)
> and apparently locks up the animator (I use an FPSAnimator). Resize events
> still update my window, but the animator doesn't.
>
> I do all my own logic from my GLEventListener's display() method. I tried
> disabling the animator before calling setFullscreen() and reenabling it
> afterwards, but it didn't help, probably since setFullscreen() internally
> calls runOnEDTIfAvail() anyway.
>
> This is all on Linux/X11/KDE by the way, I haven't yet tested it on other
> platforms.
>
> Perhaps I'm simply calling setFullscreen() from the wrong location. But in
> that case, where/when *is* the correct time to call it?
Thread (NEWT-EDT) and location seems to be fine,
however an issue w/ the FPSAWTAnimator-Timer0 thread exist.

Of course, it shall not be invoked from the AWT-EDT thread,
*iff* an AWT canvas is involved (e.g. NewtCanvasAWT).

Before we go fullscreen, we ofc attempt to pause the animator
and resume it afterwards - this seems to not work here.

TBH .. our unit tests 'only' test the Animator implementation,
not FPSAnimator, since the latter is inferior (no v-sync .. etc).

Please file a bug report, maybe you can even add a unit test using the
FPSAnimator which reproduces the issue at hand.
You could simply copy one of our fullscreen animator tests.

Q: You use NewtCanvasAWT or a plain GLWindow ?

In case of the latter (GLWindow), you may also give the animator
a hint that no AWT threading issue is involved:
  animator.setModeBits(false, AnimatorBase.MODE_EXPECT_AWT_RENDERING_THREAD);

This will allow the animator to be properly paused and resumed,
i.e. operation can block and wait until completed.
Here the DefaultAnimatorImpl will be used instead of AWTAnimatorImpl,
which is also the default if running AWT-headless or w/o AWT support classes.

However, I guess we should see to even the AWT FPSAnimator issue.

~Sven

>
> Exception in thread "main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0" com.jogamp.opengl.util.AnimatorBase$UncaughtAnimatorException: javax.media.opengl.GLException: Caught RuntimeException: Waited 5000ms for: <7d0e0c8b, 2559b9d1>[count 1, qsz 0, owner <main-Display-.x11_:0-1-EDT-1>] - <main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0> on thread main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0
> at com.jogamp.opengl.util.AWTAnimatorImpl.display(AWTAnimatorImpl.java:84)
> at com.jogamp.opengl.util.AnimatorBase.display(AnimatorBase.java:446)
> at com.jogamp.opengl.util.FPSAnimator$MainTask.run(FPSAnimator.java:175)
> at java.util.TimerThread.mainLoop(Timer.java:555)
> at java.util.TimerThread.run(Timer.java:505)
> Caused by: javax.media.opengl.GLException: Caught RuntimeException: Waited 5000ms for: <7d0e0c8b, 2559b9d1>[count 1, qsz 0, owner <main-Display-.x11_:0-1-EDT-1>] - <main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0> on thread main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0
> at javax.media.opengl.GLException.newGLException(GLException.java:75)
> at jogamp.opengl.GLDrawableHelper.invokeGLImpl(GLDrawableHelper.java:1318)
> at jogamp.opengl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:1138)
> at com.jogamp.newt.opengl.GLWindow.display(GLWindow.java:666)
> at com.jogamp.opengl.util.AWTAnimatorImpl.display(AWTAnimatorImpl.java:77)
> ... 4 more
> Caused by: java.lang.RuntimeException: Waited 5000ms for: <7d0e0c8b, 2559b9d1>[count 1, qsz 0, owner <main-Display-.x11_:0-1-EDT-1>] - <main-Display-.x11_:0-1-EDT-1-FPSAWTAnimator-Timer0>
> at jogamp.common.util.locks.RecursiveLockImpl01Unfairish.lock(RecursiveLockImpl01Unfairish.java:198)
> at jogamp.nativewindow.ResourceToolkitLock.lock(ResourceToolkitLock.java:56)
> at javax.media.nativewindow.DefaultGraphicsDevice.lock(DefaultGraphicsDevice.java:126)
> at jogamp.newt.driver.x11.DisplayDriver.dispatchMessagesNative(DisplayDriver.java:109)
> at jogamp.newt.WindowImpl$FullScreenAction.run(WindowImpl.java:2347)
> at jogamp.newt.WindowImpl.runOnEDTIfAvail(WindowImpl.java:2123)
> at jogamp.newt.WindowImpl.setFullscreenImpl(WindowImpl.java:2457)
> at jogamp.newt.WindowImpl.setFullscreen(WindowImpl.java:2434)
> at com.jogamp.newt.opengl.GLWindow.setFullscreen(GLWindow.java:432)
>


signature.asc (828 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Where/when is it ok to call setFullscreen()?

gouessej
Administrator
I confirm that this problem doesn't occur with a more basic animator and I'm under GNU Linux (Mageia Linux 4, 64 bits, KDE 4).
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Where/when is it ok to call setFullscreen()?

Marian Schedenig
In reply to this post by Sven Gothel
Thanks Sven, it seems indeed to be working perfectly fine with standard Animator.

I have both Animator implementations in my game, but I didn't think of trying it with the standard one. By default I use FPSAnimator, as far as I recall because when I first wrote the code, I had issues with Animator on Linux, though I can't recall in detail now (I think the framerate wasn't the 60Hz I was expecting from my screen settings). Animator seems to do exactly what I want now though, so I'll switch the default to that and just leave FPSAnimator as a fallback config option.

I'll see if I can come up with a minimal FPSAnimator example in the next few days.
Reply | Threaded
Open this post in threaded view
|

Re: Where/when is it ok to call setFullscreen()?

Sven Gothel
Administrator
On 08/19/2014 04:58 PM, Marian Schedenig [via jogamp] wrote:
> Thanks Sven, it seems indeed to be working perfectly fine with standard Animator.
>
> I have both Animator implementations in my game, but I didn't think of trying
> it with the standard one. By default I use FPSAnimator, as far as I recall
> because when I first wrote the code, I had issues with Animator on Linux,
> though I can't recall in detail now (I think the framerate wasn't the 60Hz I
> was expecting from my screen settings). Animator seems to do exactly what I
> want now though, so I'll switch the default to that and just leave FPSAnimator
> as a fallback config option.

Great.

>
> I'll see if I can come up with a minimal FPSAnimator example in the next few
> days.

Thank you for undergoing this effort!
It will help to fix this issue - a lot.

~Sven



signature.asc (828 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Where/when is it ok to call setFullscreen()?

Marian Schedenig
Unfortunately, it turns out that the standard Animator did not help after all.

Both Animator and FPSAnimator sometimes work, occasionally even two or three times in a row, but usually crash (with the same exception). I must have had an unusually long success streak right after switching to Animator, because it seemed to consistently work when I posted my previous message, but now the behaviour and success rate of both implementations is identical.

I wrote a simple test application that just displays a GLWindow and toggles fullscreen mode via a key event - and it works flawlessly. With both animators.

I've been trying to add bits and pieces from my faulty application to the test project. So far I've added my shaders, GL program switches, a clear command for every frame, and actually calling the fullscreen toggle from within the display event - and it still works perfectly.

So the good news is that it appears to work just fine with both animators under "normal" circumstances. The bad news is that so far I've been unable to figure out what exactly I'm doing wrong that causes the error.

I've been running my application with the -Djogl.debug.DebugGL flag, and the only warnings I get are shader recompilation performance warnings that seem to an Nvidia driver thing.
Reply | Threaded
Open this post in threaded view
|

Re: Where/when is it ok to call setFullscreen()?

Sven Gothel
Administrator
On 08/24/2014 02:35 AM, Marian Schedenig [via jogamp] wrote:

> Unfortunately, it turns out that the standard Animator did not help after all.
>
> Both Animator and FPSAnimator sometimes work, occasionally even two or three
> times in a row, but usually crash (with the same exception). I must have had
> an unusually long success streak right after switching to Animator, because it
> seemed to consistently work when I posted my previous message, but now the
> behaviour and success rate of both implementations is identical.
>
> I wrote a simple test application that just displays a GLWindow and toggles
> fullscreen mode via a key event - and it works flawlessly. With both animators.
>
> I've been trying to add bits and pieces from my faulty application to the test
> project. So far I've added my shaders, GL program switches, a clear command
> for every frame, and actually calling the fullscreen toggle from within the
> display event - and it still works perfectly.
>
> So the good news is that it appears to work just fine with both animators
> under "normal" circumstances. The bad news is that so far I've been unable to
> figure out what exactly I'm doing wrong that causes the error.
>
> I've been running my application with the -Djogl.debug.DebugGL flag, and the
> only warnings I get are shader recompilation performance warnings that seem to
> an Nvidia driver thing.
Yeah .. a hard bug.

Surely I would love to have a test case.

~Sven



signature.asc (828 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Where/when is it ok to call setFullscreen()?

Marian Schedenig
Ok, I solved it. I failed to reproduce it in a test case, unfortunately, but trying to port over bits and pieces at least showed me roughly where the crash originated. I'm still not exactly sure what causes it, I can just describe the general situation.

I have several listeners on my GLWindow. The input listeners for the keyboard and mouse just translate input events to internal data structures and add them to an input queue. Then during my main loop, which is triggered once per frame by the display() callback method, I do the following:

1) Clear the screen via glClear().
2) Iterate through the queued input events.
3) Update my game logic (fixed rate loop).
4) Render a frame.
5) Return whether to keep running or quit the application.

Then back in display(), if the main loop returned false, I stop the animator and quit.

I have a custom set of GUI classes for drawing windows, labels, buttons etc. and handle input events for them. These are all processed during step 1. Fullscreen mode is toggled via a button that can be clicked (mouse down inside the button, followed by a mouse up inside the same button) or focused and triggered with the Enter key (keyDown event - keyUp is handled as well, but not used to trigger the button).

I was certain that both a mouse click and an Enter press trigged the crash, but it turned out that everything worked fine when I used only the mouse. Either I was mistaken, or during my first tests there were still more problems that also caused crashes with the mouse, and I'd "accidentally" fixed them while trying to figure out the problem. In any case, only the keyboard was causing the crashes. The button called a setFullscreen() method in my window wrapper class. Directly checking for the "f" key in the window listener's keyDown callback and calling setFullscreen() from there instead of queuing the key press also worked just fine.

So I removed the direct call to setFullscreen() from my button click callback. Instead, I now set a flag on my window class, and after calling the main loop, I check that flag in display() (let's call that step 6) and call that same setFullscreen() method if the flag is set. And it's solid as a rock this way.

The odd thing about it is that the mouse click and key presses trigger the same callback method. And it's all happening in step 2. There should be no drawing code whatsoever outside step 4, except for step 1. So both the input events and the drawing are completely decoupled from the part where I used to trigger setFullscreen(). And even if I move step 6 between steps 1 and 2, it runs just fine.

I expect it must be something very specific to my code (there's probably a stray call to some minor graphics update somewhere in my game logic that I haven't been able to find) and won't be of much help to anyone, but this is what I've been able to boil it down to, for what it's worth.
Reply | Threaded
Open this post in threaded view
|

Re: Where/when is it ok to call setFullscreen()?

Sven Gothel
Administrator
On 08/25/2014 11:55 PM, Marian Schedenig [via jogamp] wrote:

> Ok, I solved it. I failed to reproduce it in a test case, unfortunately, but
> trying to port over bits and pieces at least showed me roughly where the crash
> originated. I'm still not exactly sure what causes it, I can just describe the
> general situation.
>
> I have several listeners on my GLWindow. The input listeners for the keyboard
> and mouse just translate input events to internal data structures and add them
> to an input queue. Then during my main loop, which is triggered once per frame
> by the display() callback method, I do the following:
>
> 1) Clear the screen via glClear().
> 2) Iterate through the queued input events.
> 3) Update my game logic (fixed rate loop).
> 4) Render a frame.
> 5) Return whether to keep running or quit the application.
>
> Then back in display(), if the main loop returned false, I stop the animator
> and quit.
>
> I have a custom set of GUI classes for drawing windows, labels, buttons etc.
> and handle input events for them. These are all processed during step 1.
> Fullscreen mode is toggled via a button that can be clicked (mouse down inside
> the button, followed by a mouse up inside the same button) or focused and
> triggered with the Enter key (keyDown event - keyUp is handled as well, but
> not used to trigger the button).
You shall trigger fullscreen off-thread, i.e. not within
input event callback _or_ display(),
look at our unit test, e.g.
  new Thread() { public void run() { glw.setFullscreen(true); } }.run();

>
> I was certain that both a mouse click and an Enter press trigged the crash,
> but it turned out that everything worked fine when I used only the mouse.
> Either I was mistaken, or during my first tests there were still more problems
> that also caused crashes with the mouse, and I'd "accidentally" fixed them
> while trying to figure out the problem. In any case, only the keyboard was
> causing the crashes. The button called a setFullscreen() method in my window
> wrapper class. Directly checking for the "f" key in the window listener's
> keyDown callback and calling setFullscreen() from there instead of queuing the
> key press also worked just fine.
>
> So I removed the direct call to setFullscreen() from my button click callback.
> Instead, I now set a flag on my window class, and after calling the main loop,
> I check that flag in display() (let's call that step 6) and call that same
> setFullscreen() method if the flag is set. And it's solid as a rock this way.
Interesting that this works, since the context is still current
and the surface locked.

>
> The odd thing about it is that the mouse click and key presses trigger the
> same callback method. And it's all happening in step 2. There should be no
> drawing code whatsoever outside step 4, except for step 1. So both the input
> events and the drawing are completely decoupled from the part where I used to
> trigger setFullscreen(). And even if I move step 6 between steps 1 and 2, it
> runs just fine.
>
> I expect it must be something very specific to my code (there's probably a
> stray call to some minor graphics update somewhere in my game logic that I
> haven't been able to find) and won't be of much help to anyone, but this is
> what I've been able to boil it down to, for what it's worth.
Pls try manipulating the NEWT window (GLWindow here) not:
  A - within input event callback, or
  B - while the surface is locked (within display())

A) b/c this 'might' be a native callback and 'complicated' lifecycle
   operations or 'long' operations shall not happen here, think interrupt.
   If it works, it may not be stable on all platforms.

B) Manipulating the lifecycle (fullscreen may change resources)
   shall not happen from within a locked surface, e.g. display().
   E.g. we may even create a new surface/drawable
   with this operation (OSX/NewtCanvasAWT),
   or at least perform native reparenting.
   If it works, it may not be stable on all platforms.

We may need to emphasize this in the API docs.
If you glance over our many unit tests (do a calltrace of setFullscreen(..)),
you see how we safely do it.

Sorry for the inconvenience.

Hope this helps.

~Sven



signature.asc (828 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Where/when is it ok to call setFullscreen()?

Marian Schedenig
Oh, that explains it then. I guess I wasn't clear enough about calling it from within display() in my original post, sorry.

My (blind) assumption was that since setFullscreen() schedules the actual operation as an EDT runnable, it wouldn't matter where I called it. I guess that also explains why I couldn't reproduce it. The EDT thread switch probably bought me enough time to let it run smoothly when called at the end of display() in my game, or anywhere within display() in my test project (with its much simpler and faster rendering operations).

Based on what I found in the test cases, I changed it to this now:

@Override
public void setFullscreen(final boolean fullscreen)
{
	new Thread()
	{
		@Override
		public void run()
		{
			Thread t = glWindow.setExclusiveContextThread(null);
			
			glWindow.setFullscreen(fullscreen);
			
			if(!fullscreen)
			{
				center();
			}

			glWindow.setExclusiveContextThread(t);
		}
	}.start();
}

Thanks a lot for your help.