GLAutoDrawable: Fix GLEventListener lifecycle and expose more user control (API Change) ; Added GLDrawableUtil
A GLEventListener resides in two states, initialized and uninitialized. When added to a GLAutoDrawable, it is uninitialized. A first 'display()' will issue GLEventListener's 'init(..)' which renders it initialized. This is usually accompanied by 'reshape(..)' propagating the drawable's dimension.
Destruction of the GLAutoDrawable will issue GLEventListener's 'dispose(..)' which renders it uninitialized.
It turns our these means of GLEventListener controls are not sufficient in case the user requires to remove and add them during the lifecycle and rendering of their GLAutoDrawable host. GLAutoDrawable 'removeGLEventListener(..)' merely removes the GLEventListener from the list, but does not complete it's lifecycle, i.e. issues 'dispose(..)' if initialized to realease GL related resources.
Hence the following essential API changes are made to complete the lifecycle:
+ public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove);
disposing a single GLEventListener, allowing it's removal from the list being optional
This is demonstrated via GLDrawableUtil.swapGLContextAndAllGLEventListener(GLAutoDrawable a, GLAutoDrawable b), see below.
++++++++
Further more the following API changes were made to expose complete control of GLEventListener to the user:
- public void removeGLEventListener(GLEventListener listener); + public GLEventListener removeGLEventListener(GLEventListener listener);
The return value allows simple pipelining, and also delivers information whether the passed listener was actually removed.
- public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException; + public int getGLEventListenerCount(); + public GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException;
Dropping the redundant removal by index, while adding count and get methods.
+ public boolean getGLEventListenerInitState(GLEventListener listener); + public void setGLEventListenerInitState(GLEventListener listener, boolean initialized);
Allows retrieving and setting of listener states.
All in all these API changes allows a user to experience all freedoms in dealing w/ GLEventListeners hosted by GLAutoDrawable impl. and shall be future proof.
Note that we have avoided the Iterator pattern due to it's overhead of temporal objects creation. The simple indexed access allows us to implement each method as an atomic operation.
+++++++++++
Further more a simple enqueue(..) method has been added, allowing to just enqueue a GLRunnable w/o provoking it's execution - as invoke(..) does. This method pleases a use case where GLRunnables are batched and shall be executed later on..
public boolean invoke(boolean wait, GLRunnable glRunnable); + public void enqueue(GLRunnable glRunnable);
+++++++++++
Added GLDrawableUtil, exposes utility function to rearrange GLEventListener, modifiy GLAutoDrawable, etc.
GLDrawableUtil.swapGLContextAndAllGLEventListener(GLAutoDrawable a, GLAutoDrawable b) is tested and demonstrated w/ TestGLContextDrawableSwitchNEWT.
Adding Andres Colubri's Test Case (junit'fyed), which provokes a Deadlock on OSX - Adding a similar one w/o deadlock and less framework bits.
Andres Colubri reported a test case in the forum: <http://forum.jogamp.org/Thread-blocking-issue-with-AWT-but-not-NEWT-on-OSX-td4026674.html>
Which is now included as TestGLCanvasAWTActionDeadlock01AWT. A similar w/ less framework bits and w/o dealock is also included as TestGLCanvasAWTActionDeadlock00AWT.
A followup commit will incl. a fix after further analysis.
A commit at this point where TestGLCanvasAWTActionDeadlock01AWT still freezes on OSX is done to be able to reproduce the bug and see the fix as a patch.
Analyzed OSX Deadlock w/ AWT Applet & CALayer: Andres Colubri's Test Case, Commit 77db6a5c22cb4a53cf911b4caf57127770c70968
[1] - The AWT/Applet test case on OSX utilized offscreen CALayer, which is correct. [2] - the GLEventListener.display(..) method calls Frame.setTitle(".."); which is correct, but freezes when called right after GLEventListener.init(..)
BUG on OSX/CALayer: If frame.setTitle() is issued right after initialization the call hangs in at apple.awt.CWindow._setTitle(Native Method) at apple.awt.CWindow.setTitle(CWindow.java:765) [1.6.0_37, build 1.6.0_37-b06-434-11M3909]
Happens w/ Oracle's JRE7u9 as well!
Workaround: - Set 'justInitialized' flag in GLEventListener.init(..) - Clear 'justInitialized' flag in GLEventListener.display(..) at the end - Skip Frame.setTitle(..) in GLEventListener.display(..) if 'true == justInitialized'
Somebody may send a bugreport to Oracle / OpenJDK.
Fix GLDrawableHelper.recreateGLDrawable(..): Sync GL command stream before destruction of drawable
Lack of finishing the GL command stream lead to a SIGSEGV on Windows w/ Nvidia driver where probably pending GL commands were still being processed concurrently.