Bug 1039 - Specify behavior of GLEventListener Exceptions occurring while GLAutoDrawable processing
Summary: Specify behavior of GLEventListener Exceptions occurring while GLAutoDrawable...
Alias: None
Product: Jogl
Classification: JogAmp
Component: core (show other bugs)
Version: 2
Hardware: All all
: --- enhancement
Assignee: Sven Gothel
Depends on:
Reported: 2014-07-29 22:28 CEST by Sven Gothel
Modified: 2014-08-06 06:06 CEST (History)
3 users (show)

See Also:
Type: ---
SCM Refs:
ba1ffe66697c3175b423cb7ab9b686d73959708d 60f397da5fd27e2140a0c1b3a102bba0e67c9f19 07a4801f3b5bfd4fba9a1a4a542ce2f2eae4396a 88eef9e4eae8e63762252f1d11bca2bd0fde809b 5c1214b26ad6c877a9c0f8099a7fc2a230a8b245
Workaround: ---


Note You need to log in before you can comment on or make changes to this bug.
Description Sven Gothel 2014-07-29 22:28:43 CEST
Specify behavior of GLEventListener Exceptions occurring while GLAutoDrawable processing.

We shall not suppress exceptions thrown while processing GLAutoDrawable
in general.

This may only be allowed while destruction,
however, we might want to throw the first caught exception afterwards.

GLDrawableHelper is suspicious of at least suppressing GLEventListener.init(..)
exceptions, as well as within destruction.

What shall happen if GLEventListener throws an exception during 
GLAutoDrawable.display(..) ?

- Throw an exception

What shall happen when using off-thread rendering,
i.e. using an animator ?

- Stop the animator 
- ...

Maybe the animator, or better the GLAutoDrawable shall 
provide plugin-in an exception handler
allowing the user application to react on off-thread GLExceptions.
Comment 1 Sven Gothel 2014-07-31 02:36:43 CEST
Consistent Exception Behavior

Spec - 1st draft

GLDrawableHelper is used in all GLAutoDrawable implementations
and for most operations.

GLAutoDrawable/GLDrawableHelper invoke(..) method:

- invoke(..) forwards a caught exception
  - if blocking, it forwards an exception
    happening within the passed GLRunnable(s).
    Here the exception is caught, printed 
    and then thrown by invoke itself.

  - if non-blocking, an exception
    happening within the passed GLRunnable(s)
    will be thrown in the thread issuing it's execution, 
    i.e. display() call.
    Here the exception is not caught and simply thrown 
    by the GLRunnable.

GLAutoDrawable.destroy() -> GLDrawableHelper.disposeGL(..) method:

- disposeAllGLEventListener() being invoked by disposeGL(..),
  catches exception thrown by GLEventListener.dispose(..)
  and prints them to stderr.
  The first caught exception is re-thrown at the end as an GLException.

- disposeGL() catches re-thrown GLException by disposeAllGLEventListener()
  for GLEventListener.dispose(..)
  and re-throws it when operation is complete.

- disposeGL() catches an exception thrown at context destruction or release
  and re-throws it when operation is complete.
  An early exception at context.makeCurrent() is _not_ caught,
  since it is the first operation which simply shall unwind the stack.

GLAutoDrawable.display() -> GLDrawableHelper.invokeGLImpl(..) method:

- invokeGLImpl(..) for display() follows disposeGL() mechanism, i.e.
  it catches exception thrown at 
  GLEventListener's init(..), reshape(..) and display(..) methods
  and re-throws it when operation is complete.

  It also catches an exception thrown at context release
  and re-throws it when operation is complete.
  An early exception at context.makeCurrent() is _not_ caught,
  since it is the first operation which simply shall unwind the stack.


None of the above thrown exception shall be caught and suppressed
on the caller side.

If an operation must be completed while an exception is caught,
it shall be cached and re-thrown after the operations.

In case multiple exception at multiple places are caught within
an operation, they all shall be cached and the first one 
shall be re-thrown.

In case of multiple exception from the same place,
i.e. a loop through all GLEventListener, 
the first shall be cached and re-thrown after operation is completed.

It has to be determined, whether we like to dump the exceptions,
especially the ones who get suppressed in case of multiple exceptions.


In case off-thread operations cause an exception,
an exception handler shall be able to be installed,
e.g. within GLAutoDrawable or an Animator object.

The latter might be more suitable, since it installs a handler
within the multithreaded manager.

Since GLAnimatorControl is attached to GLAutoDrawable, 
we might have good solution here.
Comment 2 Sven Gothel 2014-07-31 02:43:15 CEST

Implements spec as described in comment 1

TODO: Offthread exception handler
Comment 3 Sven Gothel 2014-07-31 08:41:16 CEST
  Fix NPE regression of commit ba1ffe66697c3175b423cb7ab9b686d73959708d
Comment 4 Julien Gouesse 2014-07-31 10:58:21 CEST
(In reply to comment #2)
> TODO: Offthread exception handler

Good idea. I agree with this suggestion.
Comment 5 Sven Gothel 2014-08-05 22:59:06 CEST
In case of an exception thrown within an GLEventListener
called off-thread by Animator:
  - Animator shall stop
  - Animator shall forward the exception

GLDrawableHelper shall also flush all queued GLRunnable tasks
in case of an exception, so that another thread waiting until it's completion
is notified and continues processing.
Comment 6 Sven Gothel 2014-08-05 23:02:11 CEST
  Implements behavior of comment 5
Comment 7 Sven Gothel 2014-08-06 06:02:06 CEST
commit 88eef9e4eae8e63762252f1d11bca2bd0fde809b:

Add GLAnimatorControl.UncaughtGLAnimatorExceptionHandler interface to optionally handle
uncaught exception within an animator thread by the user.

Implementation also requires to flush all enqueued GLRunnable instances
via GLAutoDrawable.invoked(..) in case such exception occurs.
Hence 'GLAutoDrawable.flushGLRunnables()' has been added.

Only subsequent exceptions, which cannot be thrown are dumped to System.stderr.


Handling of exceptions during dispose()

Exception in NEWT's disposeGL*() are also caught and re-thrown after
the NEWT window has been destroyed in WindowImpl.destroyAction:

    - GLEventListener.dispose(..)
    - GLDrawableHelper.disposeAllGLEventListener(..)
        - GLDrawableHelper.disposeGL(..)
        - GLAutoDrawableBase.destroyImplInLock(..)
            - GLWindow.GLLifecycleHook.destroyActionInLock(..)
            - WindowImpl.destroyAction on NEWT-EDT
                - WindowImpl.destroy

Further more, exceptions occuring in native windowing toolkit triggered destroy()
are ignored:
    - GLAutoDrawableBase.defaultWindowDestroyNotifyOp(..)

It has to be seen whether such exception handling for
dispose() shall be added to AWT/SWT.


TestGLException01NEWT covers all GLEventListener exception cases
on-thread and off-thread (via animator).

Comment 8 Sven Gothel 2014-08-06 06:06:46 CEST
commit 5c1214b26ad6c877a9c0f8099a7fc2a230a8b245:
  Rename GLAnimatorControl.UncaughtGLAnimatorExceptionHandler
  to     GLAnimatorControl.UncaughtExceptionHandler
  for simplicity.