aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/javax/media/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/javax/media/opengl')
-rw-r--r--src/jogl/classes/javax/media/opengl/GLAnimatorControl.java52
-rw-r--r--src/jogl/classes/javax/media/opengl/GLAutoDrawable.java107
-rw-r--r--src/jogl/classes/javax/media/opengl/GLContext.java125
-rw-r--r--src/jogl/classes/javax/media/opengl/GLDrawable.java29
-rw-r--r--src/jogl/classes/javax/media/opengl/GLDrawableFactory.java86
-rw-r--r--src/jogl/classes/javax/media/opengl/GLException.java20
-rw-r--r--src/jogl/classes/javax/media/opengl/GLFBODrawable.java54
-rw-r--r--src/jogl/classes/javax/media/opengl/GLOffscreenAutoDrawable.java6
-rw-r--r--src/jogl/classes/javax/media/opengl/GLProfile.java148
-rw-r--r--src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java22
-rw-r--r--src/jogl/classes/javax/media/opengl/Threading.java42
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLCanvas.java205
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLJPanel.java573
13 files changed, 1031 insertions, 438 deletions
diff --git a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
index 827145654..d14ada48b 100644
--- a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
+++ b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
@@ -33,6 +33,38 @@ package javax.media.opengl;
* which implementation may drive a {@link javax.media.opengl.GLAutoDrawable} animation.
*/
public interface GLAnimatorControl extends FPSCounter {
+ /**
+ * A {@link GLAnimatorControl#setUncaughtExceptionHandler(UncaughtExceptionHandler) registered}
+ * {@link UncaughtExceptionHandler} instance is invoked when an {@link GLAnimatorControl animator} abruptly {@link #stop() stops}
+ * due to an uncaught exception from one of its {@link GLAutoDrawable}s.
+ * @see #uncaughtException(GLAnimatorControl, GLAutoDrawable, Throwable)
+ * @see GLAnimatorControl#setUncaughtExceptionHandler(UncaughtExceptionHandler)
+ * @since 2.2
+ */
+ public static interface UncaughtExceptionHandler {
+ /**
+ * Method invoked when the given {@link GLAnimatorControl} is {@link GLAnimatorControl#stop() stopped} due to the
+ * given uncaught exception happened on the given {@link GLAutoDrawable}.
+ * <p>
+ * The animator thread can still be retrieved via {@link GLAnimatorControl#getThread()}.
+ * </p>
+ * <p>
+ * All {@link GLAnimatorControl} states already reflect its stopped state.
+ * </p>
+ * <p>
+ * After this handler method is called, the {@link GLAnimatorControl} is stopped.
+ * </p>
+ * <p>
+ * Any exception thrown by this method will be ignored.
+ * </p>
+ * @param animator the {@link GLAnimatorControl}
+ * @param drawable the causing {@link GLAutoDrawable}
+ * @param cause the uncaught exception
+ * @see GLAnimatorControl#setUncaughtExceptionHandler(UncaughtExceptionHandler)
+ * @since 2.2
+ */
+ void uncaughtException(final GLAnimatorControl animator, final GLAutoDrawable drawable, final Throwable cause);
+ }
/**
* Indicates whether this animator has been {@link #start() started}.
@@ -181,4 +213,24 @@ public interface GLAnimatorControl extends FPSCounter {
* @throws IllegalArgumentException if drawable was not added to this animator
*/
void remove(GLAutoDrawable drawable);
+
+ /**
+ * Returns the {@link UncaughtExceptionHandler} invoked when this {@link GLAnimatorControl animator} abruptly {@link #stop() stops}
+ * due to an uncaught exception from one of its {@link GLAutoDrawable}s.
+ * <p>
+ * Default is <code>null</code>.
+ * </p>
+ * @since 2.2
+ */
+ UncaughtExceptionHandler getUncaughtExceptionHandler();
+
+ /**
+ * Set the handler invoked when this {@link GLAnimatorControl animator} abruptly {@link #stop() stops}
+ * due to an uncaught exception from one of its {@link GLAutoDrawable}s.
+ * @param handler the {@link UncaughtExceptionHandler} to use as this {@link GLAnimatorControl animator}'s uncaught exception
+ * handler. Pass <code>null</code> to unset the handler.
+ * @see UncaughtExceptionHandler#uncaughtException(GLAnimatorControl, GLAutoDrawable, Throwable)
+ * @since 2.2
+ */
+ void setUncaughtExceptionHandler(final UncaughtExceptionHandler handler);
}
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
index 377dce190..bded88d20 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
@@ -42,6 +42,10 @@ package javax.media.opengl;
import java.util.List;
+import javax.media.nativewindow.NativeSurface;
+
+import com.jogamp.common.util.locks.RecursiveLock;
+
import jogamp.opengl.Debug;
/** A higher-level abstraction than {@link GLDrawable} which supplies
@@ -116,6 +120,28 @@ import jogamp.opengl.Debug;
-Djogl.screenchange.action=true Enable the {@link GLDrawable} reconfiguration
</PRE>
</p>
+ <h5><a name="locking">GLAutoDrawable Locking</a></h5>
+ GLAutoDrawable implementations perform locking in the following order:
+ <ol>
+ <li> {@link #getUpstreamLock()}.{@link RecursiveLock#lock() lock()}</li>
+ <li> {@link #getNativeSurface()}.{@link NativeSurface#lockSurface() lockSurface()} </li>
+ </ol>
+ and releases the locks accordingly:
+ <ol>
+ <li> {@link #getNativeSurface()}.{@link NativeSurface#unlockSurface() unlockSurface()} </li>
+ <li> {@link #getUpstreamLock()}.{@link RecursiveLock#unlock() unlock()}</li>
+ </ol>
+ Above <i>locking order</i> is mandatory to guarantee
+ atomicity of operation and to avoid race-conditions.
+ A custom implementation or user applications requiring exclusive access
+ shall follow the <i>locking order</i>.
+ See:
+ <ul>
+ <li>{@link #getUpstreamLock()}</li>
+ <li>{@link #invoke(boolean, GLRunnable)}</li>
+ <li>{@link #invoke(boolean, List)}</li>
+ </ul>
+ </p>
*/
public interface GLAutoDrawable extends GLDrawable {
/** Flag reflecting whether the {@link GLDrawable} reconfiguration will be issued in
@@ -139,19 +165,22 @@ public interface GLAutoDrawable extends GLDrawable {
/**
* Associate the new context, <code>newtCtx</code>, to this auto-drawable.
* <p>
- * The current context will be destroyed if <code>destroyPrevCtx</code> is <code>true</code>,
- * otherwise it will be dis-associated from this auto-drawable
- * via {@link GLContext#setGLDrawable(GLDrawable, boolean) setGLDrawable(null, true);} first.
- * </p>
- * <p>
- * The new context will be associated with this auto-drawable
- * via {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.
- * </p>
- * <p>
- * If the old or new context was current on this thread, it is being released before switching the association.
- * The new context will be made current afterwards, if it was current before.
- * However the user shall take extra care that no other thread
- * attempts to make this context current.
+ * Remarks:
+ * <ul>
+ * <li>The currently associated context will be destroyed if <code>destroyPrevCtx</code> is <code>true</code>,
+ * otherwise it will be disassociated from this auto-drawable
+ * via {@link GLContext#setGLDrawable(GLDrawable, boolean) setGLDrawable(null, true);} including {@link GL#glFinish() glFinish()}.</li>
+ * <li>The new context will be associated with this auto-drawable
+ * via {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.</li>
+ * <li>If the old context was current on this thread, it is being released after disassociating this auto-drawable.</li>
+ * <li>If the new context was current on this thread, it is being released before associating this auto-drawable
+ * and made current afterwards.</li>
+ * <li>Implementation may issue {@link #makeCurrent()} and {@link #release()} while drawable reassociation.</li>
+ * <li>The user shall take extra care of thread synchronization,
+ * i.e. lock the involved {@link GLAutoDrawable auto-drawable's}
+ * {@link GLAutoDrawable#getUpstreamLock() upstream-locks} and {@link GLAutoDrawable#getNativeSurface() surfaces}
+ * to avoid a race condition. See <a href="#locking">GLAutoDrawable Locking</a>.</li>
+ * </ul>
* </p>
*
* @param newCtx the new context, maybe <code>null</code> for dis-association.
@@ -200,6 +229,7 @@ public interface GLAutoDrawable extends GLDrawable {
/**
* Returns true if all added {@link GLEventListener} are initialized, otherwise false.
+ * @since 2.2
*/
boolean areAllGLEventListenerInitialized();
@@ -410,17 +440,28 @@ public interface GLAutoDrawable extends GLDrawable {
* The internal queue of {@link GLRunnable}'s is being flushed with {@link #destroy()}
* where all blocked callers are being notified.
* </p>
+ * <p>
+ * To avoid a deadlock situation which causes an {@link IllegalStateException} one should
+ * avoid issuing {@link #invoke(boolean, GLRunnable) invoke} while this <a href="#locking">GLAutoDrawable is being locked</a>.<br>
+ * Detected deadlock situations throwing an {@link IllegalStateException} are:
+ * <ul>
+ * <li>{@link #getAnimator() Animator} is running on another thread and waiting and is locked on current thread, but is not {@link #isThreadGLCapable() GL-Thread}</li>
+ * <li>No {@link #getAnimator() Animator} is running on another thread and is locked on current thread, but is not {@link #isThreadGLCapable() GL-Thread}</li>
+ * </ul>
+ * </p>
*
* @param wait if <code>true</code> block until execution of <code>glRunnable</code> is finished, otherwise return immediately w/o waiting
* @param glRunnable the {@link GLRunnable} to execute within {@link #display()}
* @return <code>true</code> if the {@link GLRunnable} has been processed or queued, otherwise <code>false</code>.
+ * @throws IllegalStateException in case of a detected deadlock situation ahead, see above.
*
* @see #setAnimator(GLAnimatorControl)
* @see #display()
* @see GLRunnable
* @see #invoke(boolean, List)
+ * @see #flushGLRunnables()
*/
- public boolean invoke(boolean wait, GLRunnable glRunnable);
+ public boolean invoke(boolean wait, GLRunnable glRunnable) throws IllegalStateException ;
/**
* Extends {@link #invoke(boolean, GLRunnable)} functionality
@@ -428,9 +469,23 @@ public interface GLAutoDrawable extends GLDrawable {
* @param wait if <code>true</code> block until execution of the last <code>glRunnable</code> is finished, otherwise return immediately w/o waiting
* @param glRunnables the {@link GLRunnable}s to execute within {@link #display()}
* @return <code>true</code> if the {@link GLRunnable}s has been processed or queued, otherwise <code>false</code>.
+ * @throws IllegalStateException in case of a detected deadlock situation ahead, see {@link #invoke(boolean, GLRunnable)}.
* @see #invoke(boolean, GLRunnable)
+ * @see #flushGLRunnables()
*/
- public boolean invoke(boolean wait, List<GLRunnable> glRunnables);
+ public boolean invoke(boolean wait, List<GLRunnable> glRunnables) throws IllegalStateException;
+
+ /**
+ * Flushes all {@link #invoke(boolean, GLRunnable) enqueued} {@link GLRunnable} of this {@link GLAutoDrawable}
+ * including notifying waiting executor.
+ * <p>
+ * The executor which might have been blocked until notified
+ * will be unblocked and all tasks removed from the queue.
+ * </p>
+ * @see #invoke(boolean, GLRunnable)
+ * @since 2.2
+ */
+ public void flushGLRunnables();
/** Destroys all resources associated with this GLAutoDrawable,
inclusive the GLContext.
@@ -556,4 +611,26 @@ public interface GLAutoDrawable extends GLDrawable {
*/
public Object getUpstreamWidget();
+ /**
+ * Returns the recursive lock object of the {@link #getUpstreamWidget() upstream widget}
+ * to synchronize multithreaded access on top of {@link NativeSurface#lockSurface()}.
+ * <p>
+ * See <a href="#locking">GLAutoDrawable Locking</a>.
+ * </p>
+ * @since 2.2
+ */
+ public RecursiveLock getUpstreamLock();
+
+ /**
+ * Indicates whether the current thread is capable of
+ * performing OpenGL-related work.
+ * <p>
+ * Implementation utilizes this knowledge to determine
+ * whether {@link #display()} performs the OpenGL commands on the current thread directly
+ * or spawns them on the dedicated OpenGL thread.
+ * </p>
+ * @since 2.2
+ */
+ public boolean isThreadGLCapable();
+
}
diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java
index d5d8792d8..e2498e6f1 100644
--- a/src/jogl/classes/javax/media/opengl/GLContext.java
+++ b/src/jogl/classes/javax/media/opengl/GLContext.java
@@ -48,6 +48,7 @@ import java.util.List;
import java.util.Set;
import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.NativeSurface;
import jogamp.opengl.Debug;
import jogamp.opengl.GLContextImpl;
@@ -107,6 +108,7 @@ public abstract class GLContext {
protected static final boolean FORCE_NO_FBO_SUPPORT = Debug.isPropertyDefined("jogl.fbo.force.none", true);
protected static final boolean FORCE_MIN_FBO_SUPPORT = Debug.isPropertyDefined("jogl.fbo.force.min", true);
+ protected static final boolean FORCE_NO_COLOR_RENDERBUFFER = Debug.isPropertyDefined("jogl.fbo.force.nocolorrenderbuffer", true);
/** Reflects property jogl.debug.DebugGL. If true, the debug pipeline is enabled at context creation. */
public static final boolean DEBUG_GL = Debug.isPropertyDefined("jogl.debug.DebugGL", true);
@@ -147,6 +149,8 @@ public abstract class GLContext {
protected static final VersionNumber Version800 = new VersionNumber(8, 0, 0);
+ private static final String S_EMPTY = "";
+
//
// Cached keys, bits [0..15]
//
@@ -204,7 +208,7 @@ public abstract class GLContext {
private final HashMap<String, Object> attachedObjects = new HashMap<String, Object>();
// RecursiveLock maintains a queue of waiting Threads, ensuring the longest waiting thread will be notified at unlock.
- protected final RecursiveLock lock = LockFactory.createRecursiveLock();
+ protected final RecursiveLock lock = LockFactory.createRecursiveLock(); // FIXME: Move to GLContextImpl when incr. minor version (incompatible change)
/** The underlying native OpenGL context */
protected volatile long contextHandle; // volatile: avoid locking for read-only access
@@ -249,6 +253,17 @@ public abstract class GLContext {
return GLContextShareSet.isShared(this);
}
+ /**
+ * Returns the shared master GLContext of this GLContext if shared, otherwise return <code>null</code>.
+ * <p>
+ * Returns this GLContext, if it is a shared master.
+ * </p>
+ * @since 2.2.1
+ */
+ public final GLContext getSharedMaster() {
+ return GLContextShareSet.getSharedMaster(this);
+ }
+
/** Returns a new list of created GLContext shared with this GLContext. */
public final List<GLContext> getCreatedShares() {
return GLContextShareSet.getCreatedShares(this);
@@ -282,15 +297,24 @@ public abstract class GLContext {
}
/**
- * Sets the read/write drawable for framebuffer operations.
+ * Sets the read/write drawable for framebuffer operations, i.e. reassociation of the context's drawable.
* <p>
* If the arguments reflect the current state of this context
* this method is a no-operation and returns the old and current {@link GLDrawable}.
* </p>
* <p>
- * If the context was current on this thread, it is being released before switching the drawable
- * and made current afterwards. However the user shall take extra care that not other thread
- * attempts to make this context current. Otherwise a race condition may happen.
+ * Remarks:
+ * <ul>
+ * <li>{@link GL#glFinish() glFinish()} is issued if context {@link #isCreated()} and a {@link #getGLDrawable() previous drawable} was bound before disassociation.</li>
+ * <li>If the context was current on this thread, it is being released before drawable reassociation
+ * and made current afterwards.</li>
+ * <li>Implementation may issue {@link #makeCurrent()} and {@link #release()} while drawable reassociation.</li>
+ * <li>The user shall take extra care of thread synchronization,
+ * i.e. lock the involved {@link GLDrawable#getNativeSurface() drawable's} {@link NativeSurface}s
+ * to avoid a race condition. In case {@link GLAutoDrawable auto-drawable's} are used,
+ * their {@link GLAutoDrawable#getUpstreamLock() upstream-lock} must be locked beforehand
+ * see <a href="GLAutoDrawable.html#locking">GLAutoDrawable Locking</a>.</li>
+ * </ul>
* </p>
* @param readWrite The read/write drawable for framebuffer operations, maybe <code>null</code> to remove association.
* @param setWriteOnly Only change the write-drawable, if <code>setWriteOnly</code> is <code>true</code> and
@@ -316,6 +340,9 @@ public abstract class GLContext {
* If the read-drawable has not been changed manually via {@link #setGLReadDrawable(GLDrawable)},
* it equals to the write-drawable (default).
* </p>
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
* @see #setGLDrawable(GLDrawable, boolean)
* @see #setGLReadDrawable(GLDrawable)
*/
@@ -354,6 +381,9 @@ public abstract class GLContext {
* If the read-drawable has not been changed manually via {@link #setGLReadDrawable(GLDrawable)},
* it equals to the write-drawable (default).
* </p>
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
* @see #isGLReadDrawableAvailable()
* @see #setGLReadDrawable(GLDrawable)
* @see #getGLReadDrawable()
@@ -792,8 +822,8 @@ public abstract class GLContext {
* <pre>
* #version 110
* ..
- * #version 150
- * #version 330
+ * #version 150 core
+ * #version 330 compatibility
* ...
* </pre>
* And for ES:
@@ -809,11 +839,20 @@ public abstract class GLContext {
*/
public final String getGLSLVersionString() {
if( ctxGLSLVersion.isZero() ) {
- return "";
+ return S_EMPTY;
}
final int minor = ctxGLSLVersion.getMinor();
- final String esSuffix = isGLES() && ctxGLSLVersion.compareTo(Version300) >= 0 ? " es" : "";
- return "#version " + ctxGLSLVersion.getMajor() + ( minor < 10 ? "0"+minor : minor ) + esSuffix + "\n" ;
+ final String profileOpt;
+ if( isGLES() ) {
+ profileOpt = ctxGLSLVersion.compareTo(Version300) >= 0 ? " es" : S_EMPTY;
+ } else if( isGLCoreProfile() ) {
+ profileOpt = ctxGLSLVersion.compareTo(Version150) >= 0 ? " core" : S_EMPTY;
+ } else if( isGLCompatibilityProfile() ) {
+ profileOpt = ctxGLSLVersion.compareTo(Version150) >= 0 ? " compatibility" : S_EMPTY;
+ } else {
+ throw new InternalError("Neither ES, Core nor Compat: "+this); // see validateProfileBits(..)
+ }
+ return "#version " + ctxGLSLVersion.getMajor() + ( minor < 10 ? "0"+minor : minor ) + profileOpt + "\n" ;
}
protected static final VersionNumber getStaticGLSLVersionNumber(final int glMajorVersion, final int glMinorVersion, final int ctxOptions) {
@@ -966,8 +1005,7 @@ public abstract class GLContext {
* @see GLProfile#isGL4bc()
*/
public final boolean isGL4bc() {
- return 0 != (ctxOptions & CTX_IS_ARB_CREATED) &&
- 0 != (ctxOptions & CTX_PROFILE_COMPAT) &&
+ return 0 != (ctxOptions & CTX_PROFILE_COMPAT) &&
ctxVersion.getMajor() >= 4;
}
@@ -976,8 +1014,7 @@ public abstract class GLContext {
* @see GLProfile#isGL4()
*/
public final boolean isGL4() {
- return 0 != (ctxOptions & CTX_IS_ARB_CREATED) &&
- 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)) &&
+ return 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)) &&
ctxVersion.getMajor() >= 4;
}
@@ -985,8 +1022,7 @@ public abstract class GLContext {
* Indicates whether this GLContext uses a GL4 core profile. <p>Includes [ GL4 ].</p>
*/
public final boolean isGL4core() {
- return 0 != ( ctxOptions & CTX_IS_ARB_CREATED ) &&
- 0 != ( ctxOptions & CTX_PROFILE_CORE ) &&
+ return 0 != ( ctxOptions & CTX_PROFILE_CORE ) &&
ctxVersion.getMajor() >= 4;
}
@@ -995,8 +1031,7 @@ public abstract class GLContext {
* @see GLProfile#isGL3bc()
*/
public final boolean isGL3bc() {
- return 0 != (ctxOptions & CTX_IS_ARB_CREATED) &&
- 0 != (ctxOptions & CTX_PROFILE_COMPAT) &&
+ return 0 != (ctxOptions & CTX_PROFILE_COMPAT) &&
ctxVersion.compareTo(Version310) >= 0 ;
}
@@ -1005,8 +1040,7 @@ public abstract class GLContext {
* @see GLProfile#isGL3()
*/
public final boolean isGL3() {
- return 0 != (ctxOptions & CTX_IS_ARB_CREATED) &&
- 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)) &&
+ return 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)) &&
ctxVersion.compareTo(Version310) >= 0 ;
}
@@ -1014,8 +1048,7 @@ public abstract class GLContext {
* Indicates whether this GLContext uses a GL3 core profile. <p>Includes [ GL4, GL3 ].</p>
*/
public final boolean isGL3core() {
- return 0 != ( ctxOptions & CTX_IS_ARB_CREATED ) &&
- 0 != ( ctxOptions & CTX_PROFILE_CORE ) &&
+ return 0 != ( ctxOptions & CTX_PROFILE_CORE ) &&
ctxVersion.compareTo(Version310) >= 0;
}
@@ -1024,8 +1057,7 @@ public abstract class GLContext {
*/
public final boolean isGLcore() {
return ( 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() >= 2 ) ||
- ( 0 != ( ctxOptions & CTX_IS_ARB_CREATED ) &&
- 0 != ( ctxOptions & CTX_PROFILE_CORE ) &&
+ ( 0 != ( ctxOptions & CTX_PROFILE_CORE ) &&
ctxVersion.compareTo(Version310) >= 0
) ;
}
@@ -1041,9 +1073,9 @@ public abstract class GLContext {
}
/**
- * Indicates whether this GLContext's native profile does not implement a default <i>vertex array object</i> (VAO),
- * starting w/ OpenGL 3.1 core and GLES3.
- * <p>Includes [ GL4, GL3, GLES3 ].</p>
+ * Indicates whether this GLContext's native profile does not implement a <i>default vertex array object</i> (VAO),
+ * starting w/ OpenGL 3.1 core.
+ * <p>Includes [ GL4, GL3 ].</p>
* <pre>
Due to GL 3.1 core spec: E.1. DEPRECATED AND REMOVED FEATURES (p 296),
GL 3.2 core spec: E.2. DEPRECATED AND REMOVED FEATURES (p 331)
@@ -1052,8 +1084,17 @@ public abstract class GLContext {
More clear is GL 4.3 core spec: 10.4 (p 307).
* </pre>
* <pre>
- GLES3 is included, since upcoming ES releases &gt; 3.0 may behave the same:
+ ES 3.x is <i>not</i> included here.
+ Due to it's ES 2.0 backward compatibility it still supports the following features:
+ <i>client side vertex arrays</i>
+ <i>default vertex array object</i>
+
+ Binding a custom VAO with ES 3.0 would cause <i>client side vertex arrays</i> via {@link GL2ES1#glVertexPointer(int, int, int, java.nio.Buffer) glVertexPointer}
+ to produce <code>GL_INVALID_OPERATION</code>.
+
+ However, they are marked <i>deprecated</i>:
GL ES 3.0 spec F.1. Legacy Features (p 322).
+ GL ES 3.1 spec F.1. Legacy Features (p 454).
* </pre>
* <p>
* If no default VAO is implemented in the native OpenGL profile,
@@ -1062,7 +1103,7 @@ public abstract class GLContext {
* @see #getDefaultVAO()
*/
public final boolean hasNoDefaultVAO() {
- return ( 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() >= 3 ) ||
+ return // ES 3.x not included, see above. ( 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() >= 3 ) ||
( 0 != ( ctxOptions & CTX_IS_ARB_CREATED ) &&
0 != ( ctxOptions & CTX_PROFILE_CORE ) &&
ctxVersion.compareTo(Version310) >= 0
@@ -1250,6 +1291,9 @@ public abstract class GLContext {
/**
* Return the framebuffer name bound to this context,
* see {@link GL#glBindFramebuffer(int, int)}.
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
*/
public abstract int getBoundFramebuffer(int target);
@@ -1260,6 +1304,9 @@ public abstract class GLContext {
* in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable
* is being used.
* </p>
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
*/
public abstract int getDefaultDrawFramebuffer();
@@ -1270,6 +1317,9 @@ public abstract class GLContext {
* in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable
* is being used.
* </p>
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
*/
public abstract int getDefaultReadFramebuffer();
@@ -1294,13 +1344,26 @@ public abstract class GLContext {
* Note-3: See {@link com.jogamp.opengl.util.GLDrawableUtil#swapBuffersBeforeRead(GLCapabilitiesImmutable) swapBuffersBeforeRead}
* for read-pixels and swap-buffers implications.
* </p>
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
*/
public abstract int getDefaultReadBuffer();
- /** Get the default pixel data type, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}. */
+ /**
+ * Get the default pixel data type, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}.
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
+ */
public abstract int getDefaultPixelDataType();
- /** Get the default pixel data format, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}. */
+ /**
+ * Get the default pixel data format, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}.
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
+ */
public abstract int getDefaultPixelDataFormat();
/**
diff --git a/src/jogl/classes/javax/media/opengl/GLDrawable.java b/src/jogl/classes/javax/media/opengl/GLDrawable.java
index 57883c8ac..5c881ab73 100644
--- a/src/jogl/classes/javax/media/opengl/GLDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLDrawable.java
@@ -60,8 +60,9 @@ public interface GLDrawable extends NativeSurfaceHolder {
* The GLContext <code>share</code> need not be associated with this
* GLDrawable and may be null if sharing of display lists and other
* objects is not desired. See the note in the overview
- * documentation on
- * <a href="../../../spec-overview.html#SHARING">context sharing</a>.
+ * documentation
+ * <a href="../../../overview-summary.html#SHARING">context sharing</a>
+ * as well as {@link GLSharedContextSetter}.
* </p>
*/
public GLContext createContext(GLContext shareWith);
@@ -174,17 +175,37 @@ public interface GLDrawable extends NativeSurfaceHolder {
public void swapBuffers() throws GLException;
/** Fetches the {@link GLCapabilitiesImmutable} corresponding to the chosen
- OpenGL capabilities (pixel format / visual / GLProfile) for this drawable.<br>
+ OpenGL capabilities (pixel format / visual / GLProfile) for this drawable.
+ <p>
+ This query only returns the chosen capabilities if {@link #isRealized()}.
+ </p>
+ <p>
On some platforms, the pixel format is not directly associated
with the drawable; a best attempt is made to return a reasonable
- value in this case. <br>
+ value in this case.
+ </p>
+ <p>
This object shall be directly associated to the attached {@link NativeSurface}'s
{@link AbstractGraphicsConfiguration}, and if changes are necessary,
they should reflect those as well.
+ </p>
@return The immutable queried instance.
+ @see #getRequestedGLCapabilities()
*/
public GLCapabilitiesImmutable getChosenGLCapabilities();
+ /** Fetches the {@link GLCapabilitiesImmutable} corresponding to the user requested
+ OpenGL capabilities (pixel format / visual / GLProfile) for this drawable.
+ <p>
+ If {@link #isRealized() realized}, {@link #getChosenGLCapabilities() the chosen capabilities}
+ reflect the actual selected OpenGL capabilities.
+ </p>
+ @return The immutable queried instance.
+ @see #getChosenGLCapabilities()
+ @since 2.2
+ */
+ public GLCapabilitiesImmutable getRequestedGLCapabilities();
+
/** Fetches the {@link GLProfile} for this drawable.
Returns the GLProfile object, no copy.
*/
diff --git a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java
index 82808a3cb..71568ee76 100644
--- a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java
+++ b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java
@@ -98,23 +98,6 @@ public abstract class GLDrawableFactory {
protected static final boolean DEBUG = Debug.debug("GLDrawable");
- /**
- * We have to disable support for ANGLE, the D3D ES2 emulation on Windows provided w/ Firefox and Chrome.
- * When run in the mentioned browsers, the eglInitialize(..) implementation crashes.
- * <p>
- * This can be overridden by explicitly enabling ANGLE on Windows by setting the property
- * <code>jogl.enable.ANGLE</code>.
- * </p>
- */
- protected static final boolean enableANGLE = Debug.isPropertyDefined("jogl.enable.ANGLE", true);
-
- /**
- * In case no OpenGL ES implementation is required
- * and if the running platform may have a buggy implementation,
- * setting the property <code>jogl.disable.opengles</code> disables querying a possible existing OpenGL ES implementation.
- */
- protected static final boolean disableOpenGLES = Debug.isPropertyDefined("jogl.disable.opengles", true);
-
private static volatile boolean isInit = false;
private static GLDrawableFactory eglFactory;
private static GLDrawableFactory nativeOSFactory;
@@ -179,7 +162,7 @@ public abstract class GLDrawableFactory {
}
tmp = null;
- if(!disableOpenGLES) {
+ if(!GLProfile.disableOpenGLES) {
try {
tmp = (GLDrawableFactory) ReflectionUtil.createInstance("jogamp.opengl.egl.EGLDrawableFactory", cl);
} catch (final Exception jre) {
@@ -222,7 +205,7 @@ public abstract class GLDrawableFactory {
System.err.println("GLDrawableFactory.shutdownAll["+(i+1)+"/"+gldfCount+"]: "+gldf.getClass().getName());
}
try {
- gldf.resetDisplayGamma();
+ gldf.resetAllDisplayGammaNoSync();
gldf.shutdownImpl();
} catch (final Throwable t) {
System.err.println("GLDrawableFactory.shutdownImpl: Caught "+t.getClass().getName()+" during factory shutdown #"+(i+1)+"/"+gldfCount+" "+gldf.getClass().getName());
@@ -259,7 +242,70 @@ public abstract class GLDrawableFactory {
protected abstract void shutdownImpl();
- public abstract void resetDisplayGamma();
+ /**
+ * Sets the gamma, brightness, and contrast of the display associated with the given <code>surface</code>.
+ * <p>
+ * This functionality is not available on all platforms and
+ * graphics hardware. Returns true if the settings were successfully
+ * changed, false if not. This method may return false for some
+ * values of the incoming arguments even on hardware which does
+ * support the underlying functionality. </p>
+ * <p>
+ * If this method returns true, the display settings will
+ * automatically be reset to their original values upon JVM exit
+ * (assuming the JVM does not crash); if the user wishes to change
+ * the display settings back to normal ahead of time,
+ * use {@link #resetDisplayGamma(NativeSurface)} or {@link #resetAllDisplayGamma()}.
+ * </p>
+ * <p>
+ * It is recommended to call {@link #resetDisplayGamma(NativeSurface)} or {@link #resetAllDisplayGamma()}
+ * before calling e.g. <code>System.exit()</code> from the application rather than
+ * rely on the shutdown hook functionality due to inevitable race
+ * conditions and unspecified behavior during JVM teardown.
+ * </p>
+ * <p>
+ * This method may be called multiple times during the application's
+ * execution, but calling {@link #resetDisplayGamma(NativeSurface)}
+ * will only reset the settings to the values
+ * before the first call to this method. </p>
+ *
+ * @param surface denominates the display device
+ * @param gamma The gamma value, typically > 1.0 (default values vary, but typically roughly 1.0)
+ * @param brightness The brightness value between -1.0 and 1.0, inclusive (default values vary, but typically 0)
+ * @param contrast The contrast, greater than 0.0 (default values vary, but typically 1)
+ *
+ * @return true if gamma settings were successfully changed, false if not
+ * @throws IllegalArgumentException if any of the parameters were out-of-bounds
+ * @see #resetDisplayGamma(NativeSurface)
+ * @see #resetAllDisplayGamma()
+ */
+ public abstract boolean setDisplayGamma(final NativeSurface surface, final float gamma, final float brightness, final float contrast) throws IllegalArgumentException;
+
+ /**
+ * Resets the gamma, brightness and contrast values of the display associated with the given <code>surface</code>
+ * to its original values before {@link #setDisplayGamma(NativeSurface, float, float, float) setDisplayGamma}
+ * was called the first time.
+ * <p>
+ * While it is not explicitly required that this method be called before
+ * exiting manually, calling it is recommended because of the inevitable
+ * unspecified behavior during JVM teardown.
+ * </p>
+ */
+ public abstract void resetDisplayGamma(final NativeSurface surface);
+
+ /**
+ * Resets the gamma, brightness and contrast values of all modified
+ * displays to their original values before {@link #setDisplayGamma(NativeSurface, float, float, float) setDisplayGamma}
+ * was called the first time.
+ * <p>
+ * While it is not explicitly required that this method be called before
+ * exiting manually, calling it is recommended because of the inevitable
+ * unspecified behavior during JVM teardown.
+ * </p>
+ */
+ public abstract void resetAllDisplayGamma();
+
+ protected abstract void resetAllDisplayGammaNoSync();
/**
* Retrieve the default <code>device</code> {@link AbstractGraphicsDevice#getConnection() connection},
diff --git a/src/jogl/classes/javax/media/opengl/GLException.java b/src/jogl/classes/javax/media/opengl/GLException.java
index 6a287c969..3f76a6299 100644
--- a/src/jogl/classes/javax/media/opengl/GLException.java
+++ b/src/jogl/classes/javax/media/opengl/GLException.java
@@ -41,7 +41,7 @@ package javax.media.opengl;
/** A generic exception for OpenGL errors used throughout the binding
as a substitute for {@link RuntimeException}. */
-
+@SuppressWarnings("serial")
public class GLException extends RuntimeException {
/** Constructs a GLException object. */
public GLException() {
@@ -65,4 +65,22 @@ public class GLException extends RuntimeException {
public GLException(final Throwable cause) {
super(cause);
}
+
+ /**
+ * Constructs a GLException object with the specified root
+ * cause with a decorating message including the current thread name.
+ * @since 2.2
+ */
+ public static GLException newGLException(final Throwable t) {
+ return new GLException("Caught "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName(), t);
+ }
+
+ /**
+ * Dumps a Throwable in a decorating message including the current thread name, and stack trace.
+ * @since 2.2
+ */
+ public static void dumpThrowable(final String additionalDescr, final Throwable t) {
+ System.err.println("Caught "+additionalDescr+" "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName());
+ t.printStackTrace();
+ }
}
diff --git a/src/jogl/classes/javax/media/opengl/GLFBODrawable.java b/src/jogl/classes/javax/media/opengl/GLFBODrawable.java
index a34fca0fa..524c77e9d 100644
--- a/src/jogl/classes/javax/media/opengl/GLFBODrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLFBODrawable.java
@@ -31,7 +31,10 @@ package javax.media.opengl;
import javax.media.nativewindow.NativeWindowException;
import com.jogamp.opengl.FBObject;
+import com.jogamp.opengl.FBObject.Colorbuffer;
+import com.jogamp.opengl.FBObject.ColorAttachment;
import com.jogamp.opengl.FBObject.TextureAttachment;
+import com.jogamp.opengl.GLRendererQuirks;
/**
* Platform-independent {@link GLDrawable} specialization,
@@ -62,12 +65,12 @@ import com.jogamp.opengl.FBObject.TextureAttachment;
* </p>
* <p>
* It would be possible to implement double buffering simply using
- * {@link TextureAttachment}s with one {@link FBObject framebuffer}.
+ * {@link Colorbuffer}s with one {@link FBObject framebuffer}.
* This would require mode selection and hence complicate the API. Besides, it would
* not support differentiation of read and write framebuffer and hence not be spec compliant.
* </p>
* <p>
- * Actual swapping of the {@link TextureAttachment texture}s and/or {@link FBObject framebuffer}
+ * Actual swapping of the {@link Colorbuffer}s and/or {@link FBObject framebuffer}
* is performed either in the {@link jogamp.opengl.GLContextImpl#contextMadeCurrent(boolean) context current hook}
* or when {@link jogamp.opengl.GLDrawableImpl#swapBuffersImpl(boolean) swapping buffers}, whatever comes first.
* </p>
@@ -75,19 +78,42 @@ import com.jogamp.opengl.FBObject.TextureAttachment;
public interface GLFBODrawable extends GLDrawable {
// public enum DoubleBufferMode { NONE, TEXTURE, FBO }; // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+ /** FBO Mode Bit: Use a {@link TextureAttachment} for the {@link #getColorbuffer(int) render colorbuffer}, see {@link #setFBOMode(int)}. */
+ public static final int FBOMODE_USE_TEXTURE = 1 << 0;
+
/**
* @return <code>true</code> if initialized, i.e. a {@link GLContext} is bound and made current once, otherwise <code>false</code>.
*/
public boolean isInitialized();
/**
+ * Set the FBO mode bits used for FBO creation.
+ * <p>
+ * Default value is: {@link #FBOMODE_USE_TEXTURE}.
+ * </p>
+ * <p>
+ * If {@link GLRendererQuirks#BuggyColorRenderbuffer} is set,
+ * {@link #FBOMODE_USE_TEXTURE} is always added at initialization.
+ * </p>
+ *
+ * @param modeBits custom FBO mode bits like {@link #FBOMODE_USE_TEXTURE}.
+ * @throws IllegalStateException if already initialized, see {@link #isInitialized()}.
+ */
+ void setFBOMode(final int modeBits) throws IllegalStateException;
+
+ /**
+ * @return the used FBO mode bits, mutable via {@link #setFBOMode(int)}
+ */
+ int getFBOMode();
+
+ /**
* Notify this instance about upstream size change
* to reconfigure the {@link FBObject}.
* @param gl GL context object bound to this drawable, will be made current during operation.
* A prev. current context will be make current after operation.
* @throws GLException if resize operation failed
*/
- void resetSize(GL gl) throws GLException;
+ void resetSize(final GL gl) throws GLException;
/**
* @return the used texture unit
@@ -98,7 +124,7 @@ public interface GLFBODrawable extends GLDrawable {
*
* @param unit the texture unit to be used
*/
- void setTextureUnit(int unit);
+ void setTextureUnit(final int unit);
/**
* Set the number of sample buffers if using MSAA
@@ -108,7 +134,7 @@ public interface GLFBODrawable extends GLDrawable {
* @param newSamples new sample size
* @throws GLException if resetting the FBO failed
*/
- void setNumSamples(GL gl, int newSamples) throws GLException;
+ void setNumSamples(final GL gl, final int newSamples) throws GLException;
/**
* @return the number of sample buffers if using MSAA, otherwise 0
@@ -124,9 +150,9 @@ public interface GLFBODrawable extends GLDrawable {
* Must be called before {@link #isInitialized() initialization}, otherwise an exception is thrown.
* </p>
* @return the new number of buffers (FBO) used, maybe different than the requested <code>bufferCount</code> (see above)
- * @throws GLException if already initialized, see {@link #isInitialized()}.
+ * @throws IllegalStateException if already initialized, see {@link #isInitialized()}.
*/
- int setNumBuffers(int bufferCount) throws GLException;
+ int setNumBuffers(final int bufferCount) throws IllegalStateException, GLException;
/**
* @return the number of buffers (FBO) being used. 1 if not using {@link GLCapabilities#getDoubleBuffered() double buffering},
@@ -162,19 +188,25 @@ public interface GLFBODrawable extends GLDrawable {
* @return the named {@link FBObject}
* @throws IllegalArgumentException if an illegal buffer name is being used
*/
- FBObject getFBObject(int bufferName) throws IllegalArgumentException;
+ FBObject getFBObject(final int bufferName) throws IllegalArgumentException;
/**
- * Returns the named texture buffer.
+ * Returns the named {@link Colorbuffer} instance.
* <p>
* If MSAA is being used, only the {@link GL#GL_FRONT} buffer is accessible
* and an exception is being thrown if {@link GL#GL_BACK} is being requested.
* </p>
+ * <p>
+ * Depending on the {@link #setFBOMode(int) fbo mode} the resulting {@link Colorbuffer}
+ * is either a {@link TextureAttachment} if {@link #FBOMODE_USE_TEXTURE} is set,
+ * otherwise a {@link ColorAttachment}.
+ * See {@link Colorbuffer#isTextureAttachment()}.
+ * </p>
* @param bufferName {@link GL#GL_FRONT} and {@link GL#GL_BACK} are valid buffer names
- * @return the named {@link TextureAttachment}
+ * @return the named {@link Colorbuffer}
* @throws IllegalArgumentException if using MSAA and {@link GL#GL_BACK} is requested or an illegal buffer name is being used
*/
- FBObject.TextureAttachment getTextureBuffer(int bufferName) throws IllegalArgumentException;
+ Colorbuffer getColorbuffer(final int bufferName) throws IllegalArgumentException;
/** Resizeable {@link GLFBODrawable} specialization */
public interface Resizeable extends GLFBODrawable {
diff --git a/src/jogl/classes/javax/media/opengl/GLOffscreenAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLOffscreenAutoDrawable.java
index a69480242..62d10d4cb 100644
--- a/src/jogl/classes/javax/media/opengl/GLOffscreenAutoDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLOffscreenAutoDrawable.java
@@ -39,6 +39,12 @@ import com.jogamp.opengl.FBObject;
* This class distinguishes itself from {@link GLAutoDrawable}
* with it's {@link #setSurfaceSize(int, int)} functionality.
* </p>
+ * <p>
+ * <a name="contextSharing"><h5>OpenGL Context Sharing</h5></a>
+ * To share a {@link GLContext} see the following note in the documentation overview:
+ * <a href="../../../overview-summary.html#SHARING">context sharing</a>
+ * as well as {@link GLSharedContextSetter}.
+ * </p>
*/
public interface GLOffscreenAutoDrawable extends GLAutoDrawable, GLSharedContextSetter {
diff --git a/src/jogl/classes/javax/media/opengl/GLProfile.java b/src/jogl/classes/javax/media/opengl/GLProfile.java
index 324fdee92..08712e488 100644
--- a/src/jogl/classes/javax/media/opengl/GLProfile.java
+++ b/src/jogl/classes/javax/media/opengl/GLProfile.java
@@ -44,6 +44,7 @@ import jogamp.opengl.DesktopGLDynamicLookupHelper;
import com.jogamp.common.GlueGenVersion;
import com.jogamp.common.jvm.JNILibLoaderBase;
import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.PropertyAccess;
import com.jogamp.common.util.ReflectionUtil;
import com.jogamp.common.util.VersionUtil;
import com.jogamp.common.util.cache.TempJarCache;
@@ -75,11 +76,70 @@ import java.util.Map;
*/
public class GLProfile {
- public static final boolean DEBUG = Debug.debug("GLProfile");
+ public static final boolean DEBUG;
+
+ /**
+ * In case no OpenGL ES profiles are required
+ * and if one platform may have a buggy implementation,
+ * setting the property <code>jogl.disable.opengles</code> disables querying possible existing OpenGL ES profiles.
+ */
+ public static final boolean disableOpenGLES;
+
+ /**
+ * In case no native OpenGL core profiles are required
+ * and if one platform may have a buggy implementation,
+ * setting the property <code>jogl.disable.openglcore</code> disables querying possible existing native OpenGL core profiles.
+ * <p>
+ * This exclusion is disabled for {@link Platform.OSType#MACOS}.
+ * </p>
+ */
+ public static final boolean disableOpenGLCore;
+
+ /**
+ * In case the implementation of the <i>ARB_create_context</i>
+ * context creation extension is buggy on one platform,
+ * setting the property <code>jogl.disable.openglarbcontext</code> disables utilizing it.
+ * <p>
+ * This exclusion is disabled for {@link Platform.OSType#MACOS}.
+ * </p>
+ */
+ public static final boolean disableOpenGLARBContext;
+
+ /**
+ * We have to disable support for ANGLE, the D3D ES2 emulation on Windows provided w/ Firefox and Chrome.
+ * When run in the mentioned browsers, the eglInitialize(..) implementation crashes.
+ * <p>
+ * This can be overridden by explicitly enabling ANGLE on Windows by setting the property
+ * <code>jogl.enable.ANGLE</code>.
+ * </p>
+ */
+ public static final boolean enableANGLE;
static {
// Also initializes TempJarCache if shall be used.
Platform.initSingleton();
+ final boolean isOSX = Platform.OSType.MACOS == Platform.getOSType();
+
+ DEBUG = Debug.debug("GLProfile");
+ disableOpenGLES = PropertyAccess.isPropertyDefined("jogl.disable.opengles", true);
+ disableOpenGLCore = PropertyAccess.isPropertyDefined("jogl.disable.openglcore", true) && !isOSX;
+ disableOpenGLARBContext = PropertyAccess.isPropertyDefined("jogl.disable.openglarbcontext", true) && !isOSX;
+ enableANGLE = PropertyAccess.isPropertyDefined("jogl.enable.ANGLE", true);
+ }
+
+ /**
+ * @return <code>true</code> if JOGL has been initialized, i.e. manually via {@link #initSingleton()} or implicit,
+ * otherwise returns <code>false</code>.
+ *
+ * @since 2.2.1
+ */
+ public static boolean isInitialized() {
+ initLock.lock();
+ try {
+ return initialized;
+ } finally {
+ initLock.unlock();
+ }
}
/**
@@ -425,7 +485,7 @@ public class GLProfile {
if(null != map) {
for (final Map.Entry<String,GLProfile> entry : map.entrySet()) {
- if( !GL_DEFAULT.equals(entry.getKey()) ) {
+ if( GL_DEFAULT != entry.getKey() ) {
if(useIndent) {
doIndent(sb.append(Platform.getNewline()), indent, indentCount);
}
@@ -468,44 +528,46 @@ public class GLProfile {
/** The desktop OpenGL compatibility profile 4.x, with x >= 0, ie GL2 plus GL4.<br>
<code>bc</code> stands for backward compatibility. */
- public static final String GL4bc = "GL4bc";
+ public static final String GL4bc = "GL4bc"; // Implicitly intern(), see Bug 1059
/** The desktop OpenGL core profile 4.x, with x >= 0 */
- public static final String GL4 = "GL4";
+ public static final String GL4 = "GL4"; // Implicitly intern(), see Bug 1059
/** The desktop OpenGL compatibility profile 3.x, with x >= 1, ie GL2 plus GL3.<br>
<code>bc</code> stands for backward compatibility. */
- public static final String GL3bc = "GL3bc";
+ public static final String GL3bc = "GL3bc"; // Implicitly intern(), see Bug 1059
/** The desktop OpenGL core profile 3.x, with x >= 1 */
- public static final String GL3 = "GL3";
+ public static final String GL3 = "GL3"; // Implicitly intern(), see Bug 1059
/** The desktop OpenGL profile 1.x up to 3.0 */
- public static final String GL2 = "GL2";
+ public static final String GL2 = "GL2"; // Implicitly intern(), see Bug 1059
/** The embedded OpenGL profile ES 1.x, with x >= 0 */
- public static final String GLES1 = "GLES1";
+ public static final String GLES1 = "GLES1"; // Implicitly intern(), see Bug 1059
/** The embedded OpenGL profile ES 2.x, with x >= 0 */
- public static final String GLES2 = "GLES2";
+ public static final String GLES2 = "GLES2"; // Implicitly intern(), see Bug 1059
/** The embedded OpenGL profile ES 3.x, with x >= 0 */
- public static final String GLES3 = "GLES3";
+ public static final String GLES3 = "GLES3"; // Implicitly intern(), see Bug 1059
/** The intersection of the desktop GL2 and embedded ES1 profile */
- public static final String GL2ES1 = "GL2ES1";
+ public static final String GL2ES1 = "GL2ES1"; // Implicitly intern(), see Bug 1059
/** The intersection of the desktop GL3, GL2 and embedded ES2 profile */
- public static final String GL2ES2 = "GL2ES2";
+ public static final String GL2ES2 = "GL2ES2"; // Implicitly intern(), see Bug 1059
/** The intersection of the desktop GL3 and GL2 profile */
- public static final String GL2GL3 = "GL2GL3";
+ public static final String GL2GL3 = "GL2GL3"; // Implicitly intern(), see Bug 1059
/** The intersection of the desktop GL4 and ES3 profile, available only if either ES3 or GL4 w/ <code>GL_ARB_ES3_compatibility</code> is available. */
- public static final String GL4ES3 = "GL4ES3";
+ public static final String GL4ES3 = "GL4ES3"; // Implicitly intern(), see Bug 1059
/** The default profile, used for the device default profile map */
- private static final String GL_DEFAULT = "GL_DEFAULT";
+ private static final String GL_DEFAULT = "GL_DEFAULT"; // Implicitly intern(), see Bug 1059
+ /** The default profile, used for the device default profile map */
+ private static final String GL_GL = "GL"; // Implicitly intern(), see Bug 1059
/**
* All GL Profiles in the order of default detection.
@@ -891,7 +953,7 @@ public class GLProfile {
public static GLProfile get(final AbstractGraphicsDevice device, String profile)
throws GLException
{
- if(null==profile || profile.equals("GL")) {
+ if(null==profile || profile == GL_GL) {
profile = GL_DEFAULT;
}
final HashMap<String /*GLProfile_name*/, GLProfile> glpMap = getProfileMap(device, true);
@@ -963,21 +1025,21 @@ public class GLProfile {
* This requires an EGL interface.
*/
public static boolean usesNativeGLES1(final String profileImpl) {
- return GLES1.equals(profileImpl);
+ return GLES1 == profileImpl;
}
/** Indicates whether the native OpenGL ES3 or ES2 profile is in use.
* This requires an EGL, ES3 or ES2 compatible interface.
*/
public static boolean usesNativeGLES2(final String profileImpl) {
- return GLES3.equals(profileImpl) || GLES2.equals(profileImpl);
+ return GLES3 == profileImpl || GLES2 == profileImpl;
}
/** Indicates whether the native OpenGL ES2 profile is in use.
* This requires an EGL, ES3 compatible interface.
*/
public static boolean usesNativeGLES3(final String profileImpl) {
- return GLES3.equals(profileImpl);
+ return GLES3 == profileImpl;
}
/** Indicates whether either of the native OpenGL ES profiles are in use. */
@@ -1529,7 +1591,7 @@ public class GLProfile {
@Override
public String toString() {
- return "GLProfile[" + getName() + "/" + getImplName() + "."+(this.isHardwareRasterizer?"hw":"sw")+"]";
+ return "GLProfile[" + getName() + "/" + getImplName() + "."+(this.isHardwareRasterizer?"hw":"sw")+(isCustom?".custom":"")+"]";
}
private static /*final*/ boolean isAWTAvailable;
@@ -1952,13 +2014,13 @@ public class GLProfile {
if( null != profileImpl ) {
final GLProfile glProfile;
if( profile.equals( profileImpl ) ) {
- glProfile = new GLProfile(profile, null, isHardwareRasterizer[0]);
+ glProfile = new GLProfile(profile, null, isHardwareRasterizer[0], false /* custom */);
} else {
final GLProfile _mglp = _mappedProfiles.get( profileImpl );
if( null == _mglp ) {
throw new InternalError("XXX0 profile["+i+"]: "+profile+" -> profileImpl "+profileImpl+" !!! not mapped ");
}
- glProfile = new GLProfile(profile, _mglp, isHardwareRasterizer[0]);
+ glProfile = new GLProfile(profile, _mglp, isHardwareRasterizer[0], false /* custom */);
}
_mappedProfiles.put(profile, glProfile);
if (DEBUG) {
@@ -1994,7 +2056,7 @@ public class GLProfile {
* Returns the profile implementation
*/
private static String computeProfileImpl(final AbstractGraphicsDevice device, final String profile, final boolean desktopCtxUndef, final boolean esCtxUndef, final boolean isHardwareRasterizer[]) {
- if (GL2ES1.equals(profile)) {
+ if (GL2ES1 == profile) {
final boolean es1HardwareRasterizer[] = new boolean[1];
final boolean gles1Available = hasGLES1Impl && ( esCtxUndef || GLContext.isGLES1Available(device, es1HardwareRasterizer) );
final boolean gles1HWAvailable = gles1Available && es1HardwareRasterizer[0] ;
@@ -2019,7 +2081,7 @@ public class GLProfile {
isHardwareRasterizer[0] = es1HardwareRasterizer[0];
return GLES1;
}
- } else if (GL2ES2.equals(profile)) {
+ } else if (GL2ES2 == profile) {
final boolean es2HardwareRasterizer[] = new boolean[1];
final boolean gles2Available = hasGLES3Impl && ( esCtxUndef || GLContext.isGLES2Available(device, es2HardwareRasterizer) );
final boolean gles2HWAvailable = gles2Available && es2HardwareRasterizer[0] ;
@@ -2061,7 +2123,7 @@ public class GLProfile {
isHardwareRasterizer[0] = es2HardwareRasterizer[0];
return GLES2;
}
- } else if (GL4ES3.equals(profile)) {
+ } else if (GL4ES3 == profile) {
final boolean gles3CompatAvail = GLContext.isGLES3CompatibleAvailable(device);
if( desktopCtxUndef || esCtxUndef || gles3CompatAvail ) {
final boolean es3HardwareRasterizer[] = new boolean[1];
@@ -2078,23 +2140,13 @@ public class GLProfile {
return GL4bc;
}
}
- if(GLContext.isGL3Available(device, isHardwareRasterizer)) {
- if(!gles3HWAvailable || isHardwareRasterizer[0]) {
- return GL3;
- }
- }
- if( desktopCtxUndef || GLContext.isGL3bcAvailable(device, isHardwareRasterizer)) {
- if(!gles3HWAvailable || isHardwareRasterizer[0]) {
- return GL3bc;
- }
- }
}
if(gles3Available) {
isHardwareRasterizer[0] = es3HardwareRasterizer[0];
return GLES3;
}
}
- } else if(GL2GL3.equals(profile)) {
+ } else if(GL2GL3 == profile) {
if(hasGL234Impl) {
if( GLContext.isGL4bcAvailable(device, isHardwareRasterizer)) {
return GL4bc;
@@ -2108,21 +2160,21 @@ public class GLProfile {
return GL2;
}
}
- } else if(GL4bc.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4bcAvailable(device, isHardwareRasterizer))) {
+ } else if(GL4bc == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4bcAvailable(device, isHardwareRasterizer))) {
return desktopCtxUndef ? GL4bc : GLContext.getAvailableGLProfileName(device, 4, GLContext.CTX_PROFILE_COMPAT);
- } else if(GL4.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4Available(device, isHardwareRasterizer))) {
+ } else if(GL4 == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4Available(device, isHardwareRasterizer))) {
return desktopCtxUndef ? GL4 : GLContext.getAvailableGLProfileName(device, 4, GLContext.CTX_PROFILE_CORE);
- } else if(GL3bc.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3bcAvailable(device, isHardwareRasterizer))) {
+ } else if(GL3bc == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3bcAvailable(device, isHardwareRasterizer))) {
return desktopCtxUndef ? GL3bc : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_COMPAT);
- } else if(GL3.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3Available(device, isHardwareRasterizer))) {
+ } else if(GL3 == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3Available(device, isHardwareRasterizer))) {
return desktopCtxUndef ? GL3 : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_CORE);
- } else if(GL2.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer))) {
+ } else if(GL2 == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer))) {
return desktopCtxUndef ? GL2 : GLContext.getAvailableGLProfileName(device, 2, GLContext.CTX_PROFILE_COMPAT);
- } else if(GLES3.equals(profile) && hasGLES3Impl && ( esCtxUndef || GLContext.isGLES3Available(device, isHardwareRasterizer))) {
+ } else if(GLES3 == profile && hasGLES3Impl && ( esCtxUndef || GLContext.isGLES3Available(device, isHardwareRasterizer))) {
return esCtxUndef ? GLES3 : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_ES);
- } else if(GLES2.equals(profile) && hasGLES3Impl && ( esCtxUndef || GLContext.isGLES2Available(device, isHardwareRasterizer))) {
+ } else if(GLES2 == profile && hasGLES3Impl && ( esCtxUndef || GLContext.isGLES2Available(device, isHardwareRasterizer))) {
return esCtxUndef ? GLES2 : GLContext.getAvailableGLProfileName(device, 2, GLContext.CTX_PROFILE_ES);
- } else if(GLES1.equals(profile) && hasGLES1Impl && ( esCtxUndef || GLContext.isGLES1Available(device, isHardwareRasterizer))) {
+ } else if(GLES1 == profile && hasGLES1Impl && ( esCtxUndef || GLContext.isGLES1Available(device, isHardwareRasterizer))) {
return esCtxUndef ? GLES1 : GLContext.getAvailableGLProfileName(device, 1, GLContext.CTX_PROFILE_ES);
}
return null;
@@ -2180,13 +2232,19 @@ public class GLProfile {
}
}
- private GLProfile(final String profile, final GLProfile profileImpl, final boolean isHardwareRasterizer) {
+ private GLProfile(final String profile, final GLProfile profileImpl, final boolean isHardwareRasterizer, final boolean isCustom) {
this.profile = profile;
this.profileImpl = profileImpl;
this.isHardwareRasterizer = isHardwareRasterizer;
+ this.isCustom = isCustom;
+ }
+
+ public static GLProfile createCustomGLProfile(final String profile, final GLProfile profileImpl) {
+ return new GLProfile(profile, profileImpl, profileImpl.isHardwareRasterizer, true);
}
private final GLProfile profileImpl;
private final String profile;
private final boolean isHardwareRasterizer;
+ private final boolean isCustom;
}
diff --git a/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java b/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java
index 679898dca..526967d69 100644
--- a/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java
+++ b/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java
@@ -35,9 +35,12 @@ package javax.media.opengl;
* and textures among OpenGL contexts is supported with this interface.
* </p>
* <p>
- * A <i>master</i> {@link GLContext} is the {@link GLContext} which is created first,
- * shared {@link GLContext} w/ this master are referred as slave {@link GLContext}
- * and controls the shared object's lifecycle, i.e. their construction and destruction.
+ * A <i>master</i> {@link GLContext} is the {@link GLContext} which is created first.
+ * Subsequent shared {@link GLContext} w/ the <i>master</i> are referred as <i>slave</i> {@link GLContext}.
+ * </p>
+ * <p>
+ * Implementations of this interface control the <i>slave's</i> {@link GLContext} and {@link GLAutoDrawable} realization,
+ * i.e. the <i>slave</i> {@link GLAutoDrawable} will not be realized before their associated <i>master</i>.
* </p>
* <p>
* Using the nearest or same {@link GLCapabilitiesImmutable#getVisualID(javax.media.nativewindow.VisualIDHolder.VIDType) visual ID}
@@ -50,12 +53,17 @@ package javax.media.opengl;
* At least this has been experienced w/ OSX 10.9.
* </p>
* <p>
- * Be aware that the <i>master</i> {@link GLContext} and related resources
- * <i>shall not</i> be destroyed before it's <i>slave</i> {@link GLContext} instances <i>while they are using them</i>.<br>
- * Otherwise the OpenGL driver implementation may crash w/ SIGSEGV, since using already destroyed resources,
- * e.g. OpenGL buffer objects, may not be validated by the driver!<br>
+ * In general, destroying a <i>master</i> {@link GLContext} before their shared <i>slaves</i>
+ * shall be permissible, i.e. the OpenGL driver needs to handle pending destruction of shared resources.
+ * This is confirmed to work properly on most platform/driver combinations,
+ * see unit test <code>com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT3</code> and similar.
* </p>
* <p>
+ * However, to avoid scenarios with buggy drivers, users <i>may not</i> destroy the
+ * <i>master</i> {@link GLContext} before its shared <i>slave</i> {@link GLContext} instances
+ * <i>as long as they are using them</i>.<br>
+ * Otherwise the OpenGL driver may crash w/ SIGSEGV, due to using already destroyed shared resources,
+ * if not handling the pending destruction of the latter!<br>
* Either proper lifecycle synchronization is implemented, e.g. by notifying the <i>slaves</i> about the loss of the shared resources,
* <i>or</i> the <i>slaves</i> validate whether the resources are still valid.
* </p>
diff --git a/src/jogl/classes/javax/media/opengl/Threading.java b/src/jogl/classes/javax/media/opengl/Threading.java
index 6c64cbe31..c8d8d0071 100644
--- a/src/jogl/classes/javax/media/opengl/Threading.java
+++ b/src/jogl/classes/javax/media/opengl/Threading.java
@@ -117,10 +117,36 @@ import jogamp.opengl.ThreadingImpl;
*/
public class Threading {
+ public static enum Mode {
+ /**
+ * Full multithreaded OpenGL,
+ * i.e. any {@link Threading#invoke(boolean, Runnable, Object) invoke}
+ * {@link Threading#invokeOnOpenGLThread(boolean, Runnable) commands}
+ * will be issued on the current thread immediately.
+ */
+ MT(0),
+
+ /** Single-Threaded OpenGL on AWT EDT */
+ ST_AWT(1),
+
+ /** Single-Threaded OpenGL on dedicated worker thread. */
+ ST_WORKER(2);
+
+ public final int id;
+
+ Mode(final int id){
+ this.id = id;
+ }
+ }
/** No reason to ever instantiate this class */
private Threading() {}
+ /** Returns the threading mode */
+ public static Mode getMode() {
+ return ThreadingImpl.getMode();
+ }
+
/** If an implementation of the javax.media.opengl APIs offers a
multithreading option but the default behavior is single-threading,
this API provides a mechanism for end users to disable single-threading
@@ -150,10 +176,14 @@ public class Threading {
return ThreadingImpl.isToolkitThread();
}
- /** Indicates whether the current thread is the single thread on
- which this implementation of the javax.media.opengl APIs
- performs all of its OpenGL-related work. This method should only
- be called if the single-thread model is in effect. */
+ /**
+ * Indicates whether the current thread is capable of
+ * performing OpenGL-related work.
+ * <p>
+ * Method always returns <code>true</code>
+ * if {@link #getMode()} == {@link Mode#MT} or {@link #isSingleThreaded()} == <code>false</code>.
+ * </p>
+ */
public static final boolean isOpenGLThread() throws GLException {
return ThreadingImpl.isOpenGLThread();
}
@@ -173,7 +203,7 @@ public class Threading {
}
/**
- * If {@link #isSingleThreaded()} <b>and</b> not {@link #isOpenGLThread()}
+ * If not {@link #isOpenGLThread()}
* <b>and</b> the <code>lock</code> is not being hold by this thread,
* invoke Runnable <code>r</code> on the OpenGL thread via {@link #invokeOnOpenGLThread(boolean, Runnable)}.
* <p>
@@ -186,7 +216,7 @@ public class Threading {
* @throws GLException
*/
public static final void invoke(final boolean wait, final Runnable r, final Object lock) throws GLException {
- if ( isSingleThreaded() && !isOpenGLThread() &&
+ if ( !isOpenGLThread() &&
( null == lock || !Thread.holdsLock(lock) ) ) {
invokeOnOpenGLThread(wait, r);
} else {
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
index 2d5e12429..563158a72 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
@@ -156,10 +156,12 @@ import jogamp.opengl.awt.AWTTilePainter;
* <li><pre>sun.awt.noerasebackground=true</pre></li>
* </ul>
*
+ * <p>
* <a name="contextSharing"><h5>OpenGL Context Sharing</h5></a>
* To share a {@link GLContext} see the following note in the documentation overview:
- * <a href="../../../spec-overview.html#SHARING">context sharing</a>
+ * <a href="../../../../overview-summary.html#SHARING">context sharing</a>
* as well as {@link GLSharedContextSetter}.
+ * </p>
*/
@SuppressWarnings("serial")
@@ -300,6 +302,12 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
@Override
+ public final RecursiveLock getUpstreamLock() { return lock; }
+
+ @Override
+ public final boolean isThreadGLCapable() { return Threading.isOpenGLThread(); }
+
+ @Override
public void setShallUseOffscreenLayer(final boolean v) {
shallUseOffscreenLayer = v;
}
@@ -834,65 +842,74 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private final Runnable setupPrintOnEDT = new Runnable() {
@Override
public void run() {
- if( !validateGLDrawable() ) {
- if(DEBUG) {
- System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, drawable not valid yet");
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( !validateGLDrawable() ) {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, drawable not valid yet");
+ }
+ printActive = false;
+ return; // not yet available ..
}
- printActive = false;
- return; // not yet available ..
- }
- if( !isVisible() ) {
- if(DEBUG) {
- System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, canvas not visible");
+ if( !isVisible() ) {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, canvas not visible");
+ }
+ printActive = false;
+ return; // not yet available ..
}
- printActive = false;
- return; // not yet available ..
- }
- sendReshape = false; // clear reshape flag
- printAnimator = helper.getAnimator();
- if( null != printAnimator ) {
- printAnimator.remove(GLCanvas.this);
- }
- printGLAD = GLCanvas.this; // _not_ default, shall be replaced by offscreen GLAD
- final GLCapabilities caps = (GLCapabilities)getChosenGLCapabilities().cloneMutable();
- final int printNumSamples = printAWTTiles.getNumSamples(caps);
- GLDrawable printDrawable = printGLAD.getDelegatedDrawable();
- final boolean reqNewGLADSamples = printNumSamples != caps.getNumSamples();
- final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() ||
- printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight();
- final boolean reqNewGLADOnscrn = caps.isOnscreen();
- // It is desired to use a new offscreen GLAD, however Bug 830 forbids this for AA onscreen context.
- // Bug 830: swapGLContextAndAllGLEventListener and onscreen MSAA w/ NV/GLX
- final boolean reqNewGLAD = !caps.getSampleBuffers() && ( reqNewGLADOnscrn || reqNewGLADSamples || reqNewGLADSize );
- if( DEBUG ) {
- System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ onscreen "+reqNewGLADOnscrn+", samples "+reqNewGLADSamples+", size "+reqNewGLADSize+"], "+
- ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+
- ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+
- ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+
- ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator);
- }
- if( reqNewGLAD ) {
- caps.setDoubleBuffered(false);
- caps.setOnscreen(false);
- if( printNumSamples != caps.getNumSamples() ) {
- caps.setSampleBuffers(0 < printNumSamples);
- caps.setNumSamples(printNumSamples);
+ sendReshape = false; // clear reshape flag
+ printAnimator = helper.getAnimator();
+ if( null != printAnimator ) {
+ printAnimator.remove(GLCanvas.this);
}
- final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
- printGLAD = factory.createOffscreenAutoDrawable(null, caps, null,
- printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE,
- printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE);
- GLDrawableUtil.swapGLContextAndAllGLEventListener(GLCanvas.this, printGLAD);
- printDrawable = printGLAD.getDelegatedDrawable();
- }
- printAWTTiles.setGLOrientation(printGLAD.isGLOriented(), printGLAD.isGLOriented());
- printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0);
- printAWTTiles.renderer.attachAutoDrawable(printGLAD);
- if( DEBUG ) {
- System.err.println("AWT print.setup "+printAWTTiles);
- System.err.println("AWT print.setup AA "+printNumSamples+", "+caps);
- System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD);
- System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable);
+ printGLAD = GLCanvas.this; // _not_ default, shall be replaced by offscreen GLAD
+ final GLCapabilitiesImmutable gladCaps = getChosenGLCapabilities();
+ final int printNumSamples = printAWTTiles.getNumSamples(gladCaps);
+ GLDrawable printDrawable = printGLAD.getDelegatedDrawable();
+ final boolean reqNewGLADSamples = printNumSamples != gladCaps.getNumSamples();
+ final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() ||
+ printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight();
+ final boolean reqNewGLADOnscrn = gladCaps.isOnscreen();
+
+ final GLCapabilities newGLADCaps = (GLCapabilities)gladCaps.cloneMutable();
+ newGLADCaps.setDoubleBuffered(false);
+ newGLADCaps.setOnscreen(false);
+ if( printNumSamples != newGLADCaps.getNumSamples() ) {
+ newGLADCaps.setSampleBuffers(0 < printNumSamples);
+ newGLADCaps.setNumSamples(printNumSamples);
+ }
+ final boolean reqNewGLADSafe = GLDrawableUtil.isSwapGLContextSafe(getRequestedGLCapabilities(), gladCaps, newGLADCaps);
+
+ final boolean reqNewGLAD = ( reqNewGLADOnscrn || reqNewGLADSamples || reqNewGLADSize ) && reqNewGLADSafe;
+
+ if( DEBUG ) {
+ System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ onscreen "+reqNewGLADOnscrn+", samples "+reqNewGLADSamples+", size "+reqNewGLADSize+", safe "+reqNewGLADSafe+"], "+
+ ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+
+ ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+
+ ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+
+ ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator);
+ }
+ if( reqNewGLAD ) {
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(newGLADCaps.getGLProfile());
+ printGLAD = factory.createOffscreenAutoDrawable(null, newGLADCaps, null,
+ printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE,
+ printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE);
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(GLCanvas.this, printGLAD);
+ printDrawable = printGLAD.getDelegatedDrawable();
+ }
+ printAWTTiles.setGLOrientation(printGLAD.isGLOriented(), printGLAD.isGLOriented());
+ printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0);
+ printAWTTiles.renderer.attachAutoDrawable(printGLAD);
+ if( DEBUG ) {
+ System.err.println("AWT print.setup "+printAWTTiles);
+ System.err.println("AWT print.setup AA "+printNumSamples+", "+newGLADCaps);
+ System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD);
+ System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable);
+ }
+ } finally {
+ _lock.unlock();
}
}
};
@@ -908,23 +925,29 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private final Runnable releasePrintOnEDT = new Runnable() {
@Override
public void run() {
- if( DEBUG ) {
- System.err.println("AWT print.release "+printAWTTiles);
- }
- printAWTTiles.dispose();
- printAWTTiles= null;
- if( printGLAD != GLCanvas.this ) {
- GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLCanvas.this);
- printGLAD.destroy();
- }
- printGLAD = null;
- if( null != printAnimator ) {
- printAnimator.add(GLCanvas.this);
- printAnimator = null;
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( DEBUG ) {
+ System.err.println("AWT print.release "+printAWTTiles);
+ }
+ printAWTTiles.dispose();
+ printAWTTiles= null;
+ if( printGLAD != GLCanvas.this ) {
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLCanvas.this);
+ printGLAD.destroy();
+ }
+ printGLAD = null;
+ if( null != printAnimator ) {
+ printAnimator.add(GLCanvas.this);
+ printAnimator = null;
+ }
+ sendReshape = true; // trigger reshape, i.e. gl-viewport and -listener - this component might got resized!
+ printActive = false;
+ display();
+ } finally {
+ _lock.unlock();
}
- sendReshape = true; // trigger reshape, i.e. gl-viewport and -listener - this component might got resized!
- printActive = false;
- display();
}
};
@@ -1040,16 +1063,21 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
@Override
- public boolean invoke(final boolean wait, final GLRunnable glRunnable) {
+ public boolean invoke(final boolean wait, final GLRunnable glRunnable) throws IllegalStateException {
return helper.invoke(this, wait, glRunnable);
}
@Override
- public boolean invoke(final boolean wait, final List<GLRunnable> glRunnables) {
+ public boolean invoke(final boolean wait, final List<GLRunnable> glRunnables) throws IllegalStateException {
return helper.invoke(this, wait, glRunnables);
}
@Override
+ public void flushGLRunnables() {
+ helper.flushGLRunnables();
+ }
+
+ @Override
public GLContext setContext(final GLContext newCtx, final boolean destroyPrevCtx) {
final RecursiveLock _lock = lock;
_lock.lock();
@@ -1137,6 +1165,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
return (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities();
}
+ @Override
public GLCapabilitiesImmutable getRequestedGLCapabilities() {
if( null == awtConfig ) {
return capsReqUser;
@@ -1222,26 +1251,32 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
animatorPaused = false;
}
+ GLException exceptionOnDisposeGL = null;
+
// OLS will be detached by disposeGL's context destruction below
if( null != context ) {
if( context.isCreated() ) {
- // Catch dispose GLExceptions by GLEventListener, just 'print' them
- // so we can continue with the destruction.
try {
helper.disposeGL(GLCanvas.this, context, true);
if(DEBUG) {
System.err.println(getThreadName()+": destroyOnEDTAction() - post ctx: "+context);
}
} catch (final GLException gle) {
- gle.printStackTrace();
+ exceptionOnDisposeGL = gle;
}
}
context = null;
}
+
+ Throwable exceptionOnUnrealize = null;
if( null != drawable ) {
- drawable.setRealized(false);
- if(DEBUG) {
- System.err.println(getThreadName()+": destroyOnEDTAction() - post drawable: "+drawable);
+ try {
+ drawable.setRealized(false);
+ if(DEBUG) {
+ System.err.println(getThreadName()+": destroyOnEDTAction() - post drawable: "+drawable);
+ }
+ } catch( final Throwable re ) {
+ exceptionOnUnrealize = re;
}
drawable = null;
}
@@ -1250,6 +1285,14 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
animator.resume();
}
+ // throw exception in order of occurrence ..
+ if( null != exceptionOnDisposeGL ) {
+ throw exceptionOnDisposeGL;
+ }
+ if( null != exceptionOnUnrealize ) {
+ throw GLException.newGLException(exceptionOnUnrealize);
+ }
+
if(DEBUG) {
System.err.println(getThreadName()+": dispose() - END, animator "+animator);
}
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
index 549b6e96f..5bc4c9a60 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
@@ -98,6 +98,8 @@ import jogamp.opengl.util.glsl.GLSLTextureRaster;
import com.jogamp.common.util.PropertyAccess;
import com.jogamp.common.util.awt.AWTEDTExecutor;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
import com.jogamp.nativewindow.awt.AWTPrintLifecycle;
import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol;
import com.jogamp.opengl.FBObject;
@@ -128,19 +130,19 @@ import com.jogamp.opengl.util.texture.TextureState;
using {@link GLDrawableFactory#createOffscreenDrawable(AbstractGraphicsDevice, GLCapabilitiesImmutable, GLCapabilitiesChooser, int, int) GLDrawableFactory.createOffscreenDrawable(..)}.<br/>
</p>
<p>
- <a name="verticalFlip">
- In case</a> the drawable {@link #isGLOriented()} and {@link #setSkipGLOrientationVerticalFlip(boolean) vertical flip is not skipped},
- this component performs the required vertical flip to bring the content from OpenGL's orientation into AWT's orientation.
+ <a name="verticalFlip">A vertical-flip is required</a>, if the drawable {@link #isGLOriented()} and {@link #setSkipGLOrientationVerticalFlip(boolean) vertical flip is not skipped}.<br>
+ In this case this component performs the required vertical flip to bring the content from OpenGL's orientation into AWT's orientation.<br>
+ In case <a href="#fboGLSLVerticalFlip">GLSL based vertical-flip</a> is not available,
+ the CPU intensive {@link System#arraycopy(Object, int, Object, int, int) System.arraycopy(..)} is used line by line.
See details about <a href="#fboGLSLVerticalFlip">FBO and GLSL vertical flipping</a>.
</p>
<p>
- The OpenGL path is concluded by copying the rendered pixels an {@link BufferedImage} via {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels(..)}
- for later Java2D composition.
+ For performance reasons, as well as for <a href="#bug842">GL state sideeffects</a>,
+ <b>{@link #setSkipGLOrientationVerticalFlip(boolean) skipping vertical flip} is highly recommended</b>!
</p>
<p>
- In case {@link #setSkipGLOrientationVerticalFlip(boolean) vertical-flip is not skipped} and <a href="#fboGLSLVerticalFlip">GLSL based vertical-flip</a> is not performed,
- {@link System#arraycopy(Object, int, Object, int, int) System.arraycopy(..)} is used line by line.
- This step causes more CPU load per frame and is not hardware-accelerated.
+ The OpenGL path is concluded by copying the rendered pixels an {@link BufferedImage} via {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels(..)}
+ for later Java2D composition.
</p>
<p>
Finally the Java2D compositioning takes place via via {@link Graphics#drawImage(java.awt.Image, int, int, int, int, java.awt.image.ImageObserver) Graphics.drawImage(...)}
@@ -151,7 +153,8 @@ import com.jogamp.opengl.util.texture.TextureState;
* </P>
*
<a name="fboGLSLVerticalFlip"><h5>FBO / GLSL Vertical Flip</h5></a>
- In case FBO is used and GLSL is available and {@link #setSkipGLOrientationVerticalFlip(boolean) vertical flip is not skipped}, a fragment shader is utilized
+ If <a href="#verticalFlip">vertical flip is required</a>,
+ FBO is used, GLSL is available and {@link #setSkipGLOrientationVerticalFlip(boolean) vertical flip is not skipped}, a fragment shader is utilized
to flip the FBO texture vertically. This hardware-accelerated step can be disabled via system property <code>jogl.gljpanel.noglsl</code>.
<p>
The FBO / GLSL code path uses one texture-unit and binds the FBO texture to it's active texture-target,
@@ -165,20 +168,23 @@ import com.jogamp.opengl.util.texture.TextureState;
The current gl-viewport is preserved.
</p>
<p>
- <i>Warning (Bug 842)</i>: Certain GL states other than viewport and texture (see above)
+ <a name="bug842"><i>Warning (Bug 842)</i></a>: Certain GL states other than viewport and texture (see above)
influencing rendering, will also influence the GLSL vertical flip, e.g. {@link GL#glFrontFace(int) glFrontFace}({@link GL#GL_CCW}).
It is recommended to reset those states to default when leaving the {@link GLEventListener#display(GLAutoDrawable)} method!
We may change this behavior in the future, i.e. preserve all influencing states.
</p>
+ <p>
<a name="contextSharing"><h5>OpenGL Context Sharing</h5></a>
To share a {@link GLContext} see the following note in the documentation overview:
- <a href="../../../spec-overview.html#SHARING">context sharing</a>
+ <a href="../../../../overview-summary.html#SHARING">context sharing</a>
as well as {@link GLSharedContextSetter}.
+ </p>
*/
@SuppressWarnings("serial")
public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol, AWTPrintLifecycle, GLSharedContextSetter, ScalableSurface {
private static final boolean DEBUG;
+ private static final boolean DEBUG_FRAMES;
private static final boolean DEBUG_VIEWPORT;
private static final boolean USE_GLSL_TEXTURE_RASTERIZER;
private static final boolean SKIP_VERTICAL_FLIP_DEFAULT;
@@ -195,6 +201,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
static {
Debug.initSingleton();
DEBUG = Debug.debug("GLJPanel");
+ DEBUG_FRAMES = PropertyAccess.isPropertyDefined("jogl.debug.GLJPanel.Frames", true);
DEBUG_VIEWPORT = PropertyAccess.isPropertyDefined("jogl.debug.GLJPanel.Viewport", true);
USE_GLSL_TEXTURE_RASTERIZER = !PropertyAccess.isPropertyDefined("jogl.gljpanel.noglsl", true);
SKIP_VERTICAL_FLIP_DEFAULT = PropertyAccess.isPropertyDefined("jogl.gljpanel.noverticalflip", true);
@@ -232,6 +239,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
return singleAWTGLPixelBufferProvider;
}
+ private final RecursiveLock lock = LockFactory.createRecursiveLock();
+
private final GLDrawableHelper helper;
private boolean autoSwapBufferMode;
@@ -241,10 +250,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
// Data used for either pbuffers or pixmap-based offscreen surfaces
//
private AWTGLPixelBufferProvider customPixelBufferProvider = null;
- /** Single buffered offscreen caps */
- private GLCapabilitiesImmutable offscreenCaps;
- private final GLProfile glProfile;
- private final GLDrawableFactoryImpl factory;
+ /** Requested single buffered offscreen caps */
+ private volatile GLCapabilitiesImmutable reqOffscreenCaps;
+ private volatile GLDrawableFactoryImpl factory;
private final GLCapabilitiesChooser chooser;
private int additionalCtxCreationFlags = 0;
@@ -349,10 +357,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
caps = new GLCapabilities(GLProfile.getDefault(GLProfile.getDefaultDevice()));
}
caps.setDoubleBuffered(false);
- offscreenCaps = caps;
+ reqOffscreenCaps = caps;
}
- this.glProfile = offscreenCaps.getGLProfile();
- this.factory = GLDrawableFactoryImpl.getFactoryImpl(glProfile);
+ this.factory = GLDrawableFactoryImpl.getFactoryImpl( reqOffscreenCaps.getGLProfile() ); // pre-fetch, reqOffscreenCaps may changed
this.chooser = chooser;
helper = new GLDrawableHelper();
@@ -432,6 +439,12 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
@Override
+ public final RecursiveLock getUpstreamLock() { return lock; }
+
+ @Override
+ public final boolean isThreadGLCapable() { return EventQueue.isDispatchThread(); }
+
+ @Override
public void display() {
if( isShowing || ( printActive && isVisible() ) ) {
if (EventQueue.isDispatchThread()) {
@@ -449,17 +462,19 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
}
- protected void dispose() {
+ protected void dispose(final Runnable post) {
if(DEBUG) {
System.err.println(getThreadName()+": GLJPanel.dispose() - start");
// Thread.dumpStack();
}
if (backend != null && backend.getContext() != null) {
- boolean animatorPaused = false;
+ final boolean animatorPaused;
final GLAnimatorControl animator = getAnimator();
if(null!=animator) {
animatorPaused = animator.pause();
+ } else {
+ animatorPaused = false;
}
if(backend.getContext().isCreated()) {
@@ -470,15 +485,14 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
backend.destroy();
isInitialized = false;
}
+ if( null != post ) {
+ post.run();
+ }
- if(animatorPaused) {
+ if( animatorPaused ) {
animator.resume();
}
}
- hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
- hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
- nativePixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
- nativePixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
if(DEBUG) {
System.err.println(getThreadName()+": GLJPanel.dispose() - stop");
@@ -522,28 +536,35 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
return;
}
- if( !isInitialized ) {
- initializeBackendImpl();
- }
-
- if (!isInitialized || printActive) {
- return;
- }
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( !isInitialized ) {
+ handleReshape = false;
+ initializeBackendImpl();
+ }
- // NOTE: must do this when the context is not current as it may
- // involve destroying the pbuffer (current context) and
- // re-creating it -- tricky to do properly while the context is
- // current
- if( !printActive ) {
- if (handleReshape) {
- handleReshape = false;
- sendReshape = handleReshape();
+ if (!isInitialized || printActive) {
+ return;
}
- if( isShowing ) {
- updater.setGraphics(g);
- backend.doPaintComponent(g);
+ // NOTE: must do this when the context is not current as it may
+ // involve destroying the pbuffer (current context) and
+ // re-creating it -- tricky to do properly while the context is
+ // current
+ if( !printActive ) {
+ if ( handleReshape ) {
+ handleReshape = false;
+ sendReshape = handleReshape();
+ }
+
+ if( isShowing ) {
+ updater.setGraphics(g);
+ backend.doPaintComponent(g);
+ }
}
+ } finally {
+ _lock.unlock();
}
}
@@ -622,7 +643,12 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
public void removeNotify() {
awtWindowClosingProtocol.removeClosingListener();
- dispose();
+ dispose(null);
+ hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+ nativePixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ nativePixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+
super.removeNotify();
}
@@ -643,17 +669,16 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
private void reshapeImpl(final int width, final int height) {
final int scaledWidth = width * hasPixelScale[0];
final int scaledHeight = height * hasPixelScale[1];
+ if( !printActive && ( scaledWidth != panelWidth || scaledHeight != panelHeight ) ) {
+ reshapeWidth = scaledWidth;
+ reshapeHeight = scaledHeight;
+ handleReshape = true;
+ }
if( DEBUG ) {
System.err.println(getThreadName()+": GLJPanel.reshape.0 "+this.getName()+" resize"+(printActive?"WithinPrint":"")+
" [ this "+getWidth()+"x"+getHeight()+", pixelScale "+getPixelScaleStr()+
", panel "+panelWidth+"x"+panelHeight +
- ", reshape: " +reshapeWidth+"x"+reshapeHeight +
- "] -> "+(printActive?"[skipped] ":"") + width+"x"+height+" * "+getPixelScaleStr()+" -> "+scaledWidth+"x"+scaledHeight);
- }
- if( !printActive ) {
- reshapeWidth = scaledWidth;
- reshapeHeight = scaledHeight;
- handleReshape = true;
+ "] -> "+(handleReshape?"":"[skipped] ") + width+"x"+height+" * "+getPixelScaleStr()+" -> "+scaledWidth+"x"+scaledHeight);
}
}
@@ -673,65 +698,78 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
private final Runnable setupPrintOnEDT = new Runnable() {
@Override
public void run() {
- if( !isInitialized ) {
- initializeBackendImpl();
- }
- if (!isInitialized) {
- if(DEBUG) {
- System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, drawable not valid yet");
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( !isInitialized ) {
+ initializeBackendImpl();
}
- printActive = false;
- return; // not yet available ..
- }
- if( !isVisible() ) {
- if(DEBUG) {
- System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, panel not visible");
+ if (!isInitialized) {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, drawable not valid yet");
+ }
+ printActive = false;
+ return; // not yet available ..
+ }
+ if( !isVisible() ) {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, panel not visible");
+ }
+ printActive = false;
+ return; // not yet available ..
+ }
+ sendReshape = false; // clear reshape flag
+ handleReshape = false; // ditto
+ printAnimator = helper.getAnimator();
+ if( null != printAnimator ) {
+ printAnimator.remove(GLJPanel.this);
}
- printActive = false;
- return; // not yet available ..
- }
- sendReshape = false; // clear reshape flag
- handleReshape = false; // ditto
- printAnimator = helper.getAnimator();
- if( null != printAnimator ) {
- printAnimator.remove(GLJPanel.this);
- }
- printGLAD = GLJPanel.this; // default: re-use
- final GLCapabilities caps = (GLCapabilities)getChosenGLCapabilities().cloneMutable();
- final int printNumSamples = printAWTTiles.getNumSamples(caps);
- GLDrawable printDrawable = printGLAD.getDelegatedDrawable();
- final boolean reqNewGLADSamples = printNumSamples != caps.getNumSamples();
- final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() ||
- printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight();
- final boolean reqNewGLAD = reqNewGLADSamples || reqNewGLADSize ;
- if( DEBUG ) {
- System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ samples "+reqNewGLADSamples+", size "+reqNewGLADSize+"], "+
- ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+
- ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+
- ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+
- ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator);
- }
- if( reqNewGLAD ) {
- caps.setDoubleBuffered(false);
- caps.setOnscreen(false);
- caps.setSampleBuffers(0 < printNumSamples);
- caps.setNumSamples(printNumSamples);
- final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
- printGLAD = factory.createOffscreenAutoDrawable(null, caps, null,
- printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE,
- printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE);
- GLDrawableUtil.swapGLContextAndAllGLEventListener(GLJPanel.this, printGLAD);
- printDrawable = printGLAD.getDelegatedDrawable();
- }
- printAWTTiles.setGLOrientation( !GLJPanel.this.skipGLOrientationVerticalFlip && printGLAD.isGLOriented(), printGLAD.isGLOriented() );
- printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0);
- printAWTTiles.renderer.attachAutoDrawable(printGLAD);
- if( DEBUG ) {
- System.err.println("AWT print.setup "+printAWTTiles);
- System.err.println("AWT print.setup AA "+printNumSamples+", "+caps);
- System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD);
- System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable);
+ printGLAD = GLJPanel.this; // default: re-use
+ final GLCapabilitiesImmutable gladCaps = getChosenGLCapabilities();
+ final int printNumSamples = printAWTTiles.getNumSamples(gladCaps);
+ GLDrawable printDrawable = printGLAD.getDelegatedDrawable();
+ final boolean reqNewGLADSamples = printNumSamples != gladCaps.getNumSamples();
+ final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() ||
+ printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight();
+
+ final GLCapabilities newGLADCaps = (GLCapabilities)gladCaps.cloneMutable();
+ newGLADCaps.setDoubleBuffered(false);
+ newGLADCaps.setOnscreen(false);
+ if( printNumSamples != newGLADCaps.getNumSamples() ) {
+ newGLADCaps.setSampleBuffers(0 < printNumSamples);
+ newGLADCaps.setNumSamples(printNumSamples);
+ }
+ final boolean reqNewGLADSafe = GLDrawableUtil.isSwapGLContextSafe(getRequestedGLCapabilities(), gladCaps, newGLADCaps);
+
+ final boolean reqNewGLAD = ( reqNewGLADSamples || reqNewGLADSize ) && reqNewGLADSafe;
+
+ if( DEBUG ) {
+ System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ samples "+reqNewGLADSamples+", size "+reqNewGLADSize+", safe "+reqNewGLADSafe+"], "+
+ ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+
+ ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+
+ ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+
+ ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator);
+ }
+ if( reqNewGLAD ) {
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(newGLADCaps.getGLProfile());
+ printGLAD = factory.createOffscreenAutoDrawable(null, newGLADCaps, null,
+ printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE,
+ printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE);
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(GLJPanel.this, printGLAD);
+ printDrawable = printGLAD.getDelegatedDrawable();
+ }
+ printAWTTiles.setGLOrientation( !GLJPanel.this.skipGLOrientationVerticalFlip && printGLAD.isGLOriented(), printGLAD.isGLOriented() );
+ printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0);
+ printAWTTiles.renderer.attachAutoDrawable(printGLAD);
+ if( DEBUG ) {
+ System.err.println("AWT print.setup "+printAWTTiles);
+ System.err.println("AWT print.setup AA "+printNumSamples+", "+newGLADCaps);
+ System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD);
+ System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable);
+ }
+ } finally {
+ _lock.unlock();
}
}
};
@@ -749,43 +787,49 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
private final Runnable releasePrintOnEDT = new Runnable() {
@Override
public void run() {
- if( DEBUG ) {
- System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0 "+printAWTTiles);
- }
- printAWTTiles.dispose();
- printAWTTiles= null;
- if( printGLAD != GLJPanel.this ) {
- GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLJPanel.this);
- printGLAD.destroy();
- }
- printGLAD = null;
- if( null != printAnimator ) {
- printAnimator.add(GLJPanel.this);
- printAnimator = null;
- }
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( DEBUG ) {
+ System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0 "+printAWTTiles);
+ }
+ printAWTTiles.dispose();
+ printAWTTiles= null;
+ if( printGLAD != GLJPanel.this ) {
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLJPanel.this);
+ printGLAD.destroy();
+ }
+ printGLAD = null;
+ if( null != printAnimator ) {
+ printAnimator.add(GLJPanel.this);
+ printAnimator = null;
+ }
- // trigger reshape, i.e. gl-viewport and -listener - this component might got resized!
- final int awtWidth = GLJPanel.this.getWidth();
- final int awtHeight= GLJPanel.this.getHeight();
- final int scaledAWTWidth = awtWidth * hasPixelScale[0];
- final int scaledAWTHeight= awtHeight * hasPixelScale[1];
- final GLDrawable drawable = GLJPanel.this.getDelegatedDrawable();
- if( scaledAWTWidth != panelWidth || scaledAWTHeight != panelHeight ||
- drawable.getSurfaceWidth() != panelWidth || drawable.getSurfaceHeight() != panelHeight ) {
- // -> !( awtSize == panelSize == drawableSize )
- if ( DEBUG ) {
- System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0: resizeWithinPrint panel " +panelWidth+"x"+panelHeight + " @ scale "+getPixelScaleStr()+
- ", draw "+drawable.getSurfaceWidth()+"x"+drawable.getSurfaceHeight()+
- " -> " + awtWidth+"x"+awtHeight+" * "+getPixelScaleStr()+" -> "+scaledAWTWidth+"x"+scaledAWTHeight);
+ // trigger reshape, i.e. gl-viewport and -listener - this component might got resized!
+ final int awtWidth = GLJPanel.this.getWidth();
+ final int awtHeight= GLJPanel.this.getHeight();
+ final int scaledAWTWidth = awtWidth * hasPixelScale[0];
+ final int scaledAWTHeight= awtHeight * hasPixelScale[1];
+ final GLDrawable drawable = GLJPanel.this.getDelegatedDrawable();
+ if( scaledAWTWidth != panelWidth || scaledAWTHeight != panelHeight ||
+ drawable.getSurfaceWidth() != panelWidth || drawable.getSurfaceHeight() != panelHeight ) {
+ // -> !( awtSize == panelSize == drawableSize )
+ if ( DEBUG ) {
+ System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0: resizeWithinPrint panel " +panelWidth+"x"+panelHeight + " @ scale "+getPixelScaleStr()+
+ ", draw "+drawable.getSurfaceWidth()+"x"+drawable.getSurfaceHeight()+
+ " -> " + awtWidth+"x"+awtHeight+" * "+getPixelScaleStr()+" -> "+scaledAWTWidth+"x"+scaledAWTHeight);
+ }
+ reshapeWidth = scaledAWTWidth;
+ reshapeHeight = scaledAWTHeight;
+ sendReshape = handleReshape(); // reshapeSize -> panelSize, backend reshape w/ GL reshape
+ } else {
+ sendReshape = true; // only GL reshape
}
- reshapeWidth = scaledAWTWidth;
- reshapeHeight = scaledAWTHeight;
- sendReshape = handleReshape(); // reshapeSize -> panelSize, backend reshape w/ GL reshape
- } else {
- sendReshape = true; // only GL reshape
+ printActive = false;
+ display();
+ } finally {
+ _lock.unlock();
}
- printActive = false;
- display();
}
};
@@ -927,22 +971,33 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
@Override
- public boolean invoke(final boolean wait, final GLRunnable glRunnable) {
+ public boolean invoke(final boolean wait, final GLRunnable glRunnable) throws IllegalStateException {
return helper.invoke(this, wait, glRunnable);
}
@Override
- public boolean invoke(final boolean wait, final List<GLRunnable> glRunnables) {
+ public boolean invoke(final boolean wait, final List<GLRunnable> glRunnables) throws IllegalStateException {
return helper.invoke(this, wait, glRunnables);
}
@Override
+ public void flushGLRunnables() {
+ helper.flushGLRunnables();
+ }
+
+ @Override
public GLContext createContext(final GLContext shareWith) {
- final Backend b = backend;
- if ( null == b ) {
- return null;
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final Backend b = backend;
+ if ( null == b ) {
+ return null;
+ }
+ return b.createContext(shareWith);
+ } finally {
+ _lock.unlock();
}
- return b.createContext(shareWith);
}
@Override
@@ -956,14 +1011,20 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
@Override
public GLContext setContext(final GLContext newCtx, final boolean destroyPrevCtx) {
- final Backend b = backend;
- if ( null == b ) {
- return null;
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final Backend b = backend;
+ if ( null == b ) {
+ return null;
+ }
+ final GLContext oldCtx = b.getContext();
+ GLDrawableHelper.switchContext(b.getDrawable(), oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags);
+ b.setContext(newCtx);
+ return oldCtx;
+ } finally {
+ _lock.unlock();
}
- final GLContext oldCtx = b.getContext();
- GLDrawableHelper.switchContext(b.getDrawable(), oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags);
- b.setContext(newCtx);
- return oldCtx;
}
@@ -1062,12 +1123,12 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
@Override
public int getSurfaceWidth() {
- return panelWidth; // FIXME HiDPI: Accurate or: getWidth() * hasPixelScale[0];
+ return panelWidth; // scaled surface width in pixel units, current as-from reshape
}
@Override
public int getSurfaceHeight() {
- return panelHeight; // FIXME HiDPI: Accurate or: getHeight() * hasPixelScale[1];
+ return panelHeight; // scaled surface height in pixel units, current as-from reshape
}
/**
@@ -1089,13 +1150,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
/**
- * Set skipping {@link #isGLOriented()} based vertical flip,
+ * Skip {@link #isGLOriented()} based vertical flip,
* which usually is required by the offscreen backend,
* see details about <a href="#verticalFlip">vertical flip</a>
* and <a href="#fboGLSLVerticalFlip">FBO / GLSL vertical flip</a>.
* <p>
* If set to <code>true</code>, user needs to flip the OpenGL rendered scene
- * <i>if {@link #isGLOriented()} == true</i>, e.g. via the PMV matrix.<br/>
+ * <i>if {@link #isGLOriented()} == true</i>, e.g. via the projection matrix.<br/>
* See constraints of {@link #isGLOriented()}.
* </p>
*/
@@ -1117,8 +1178,45 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
@Override
+ public final GLCapabilitiesImmutable getRequestedGLCapabilities() {
+ return reqOffscreenCaps;
+ }
+
+ /**
+ * Set a new requested {@link GLCapabilitiesImmutable} for this GLJPanel
+ * allowing reconfiguration.
+ * <p>
+ * Method shall be invoked from the {@link #isThreadGLCapable() AWT-EDT thread}.
+ * In case it is not invoked on the AWT-EDT thread, an attempt is made to do so.
+ * </p>
+ * <p>
+ * Method will dispose a previous {@link #isRealized() realized} GLContext and offscreen backend!
+ * </p>
+ * @param caps new capabilities.
+ */
+ public final void setRequestedGLCapabilities(final GLCapabilitiesImmutable caps) {
+ if( null == caps ) {
+ throw new IllegalArgumentException("null caps");
+ }
+ Threading.invoke(true,
+ new Runnable() {
+ @Override
+ public void run() {
+ dispose( new Runnable() {
+ @Override
+ public void run() {
+ // switch to new caps and re-init backend
+ // after actual dispose, but before resume animator
+ reqOffscreenCaps = caps;
+ initializeBackendImpl();
+ } } );
+ }
+ }, getTreeLock());
+ }
+
+ @Override
public final GLProfile getGLProfile() {
- return glProfile;
+ return reqOffscreenCaps.getGLProfile();
}
@Override
@@ -1209,12 +1307,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
if ( oglPipelineUsable() ) {
backend = new J2DOGLBackend();
} else {
- backend = new OffscreenBackend(glProfile, customPixelBufferProvider);
+ backend = new OffscreenBackend(customPixelBufferProvider);
}
isInitialized = false;
}
if (!isInitialized) {
+ this.factory = GLDrawableFactoryImpl.getFactoryImpl( reqOffscreenCaps.getGLProfile() ); // reqOffscreenCaps may have changed
backend.initialize();
}
return isInitialized;
@@ -1309,23 +1408,42 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
private final Runnable disposeAction = new Runnable() {
@Override
public void run() {
- if ( null != backend ) {
- final GLContext _context = backend.getContext();
- final boolean backendDestroy = !backend.isUsingOwnLifecycle();
- if( null != _context && _context.isCreated() ) {
- // Catch dispose GLExceptions by GLEventListener, just 'print' them
- // so we can continue with the destruction.
- try {
- helper.disposeGL(GLJPanel.this, _context, !backendDestroy);
- } catch (final GLException gle) {
- gle.printStackTrace();
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if ( null != backend ) {
+ final GLContext _context = backend.getContext();
+ final boolean backendDestroy = !backend.isUsingOwnLifecycle();
+
+ GLException exceptionOnDisposeGL = null;
+ if( null != _context && _context.isCreated() ) {
+ try {
+ helper.disposeGL(GLJPanel.this, _context, !backendDestroy);
+ } catch (final GLException gle) {
+ exceptionOnDisposeGL = gle;
+ }
+ }
+ Throwable exceptionBackendDestroy = null;
+ if ( backendDestroy ) {
+ try {
+ backend.destroy();
+ } catch( final Throwable re ) {
+ exceptionBackendDestroy = re;
+ }
+ backend = null;
+ isInitialized = false;
+ }
+
+ // throw exception in order of occurrence ..
+ if( null != exceptionOnDisposeGL ) {
+ throw exceptionOnDisposeGL;
+ }
+ if( null != exceptionBackendDestroy ) {
+ throw GLException.newGLException(exceptionBackendDestroy);
}
}
- if ( backendDestroy ) {
- backend.destroy();
- backend = null;
- isInitialized = false;
- }
+ } finally {
+ _lock.unlock();
}
}
};
@@ -1483,7 +1601,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
protected IntBuffer readBackIntsForCPUVFlip;
// Implementation using software rendering
- private volatile GLDrawableImpl offscreenDrawable; // volatile: avoid locking for read-only access
+ private volatile GLDrawable offscreenDrawable; // volatile: avoid locking for read-only access
private boolean offscreenIsFBO;
private FBObject fboFlipped;
private GLSLTextureRaster glslTextureRaster;
@@ -1495,7 +1613,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
// For saving/restoring of OpenGL state during ReadPixels
private final GLPixelStorageModes psm = new GLPixelStorageModes();
- OffscreenBackend(final GLProfile glp, final AWTGLPixelBufferProvider custom) {
+ OffscreenBackend(final AWTGLPixelBufferProvider custom) {
if(null == custom) {
pixelBufferProvider = getSingleAWTGLPixelBufferProvider();
} else {
@@ -1516,19 +1634,20 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
if(DEBUG) {
System.err.println(getThreadName()+": OffscreenBackend: initialize() - frameCount "+frameCount);
}
+ GLException glException = null;
try {
final GLContext[] shareWith = { null };
if( helper.isSharedGLContextPending(shareWith) ) {
return; // pending ..
}
- offscreenDrawable = (GLDrawableImpl) factory.createOffscreenDrawable(
+ offscreenDrawable = factory.createOffscreenDrawable(
null /* default platform device */,
- offscreenCaps,
+ reqOffscreenCaps,
chooser,
panelWidth, panelHeight);
updateWrappedSurfaceScale(offscreenDrawable);
offscreenDrawable.setRealized(true);
- if( DEBUG ) {
+ if( DEBUG_FRAMES ) {
offscreenDrawable.getNativeSurface().addSurfaceUpdatedListener(new SurfaceUpdatedListener() {
@Override
public final void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) {
@@ -1536,6 +1655,17 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
} } );
}
+ //
+ // Pre context configuration
+ //
+ flipVertical = !GLJPanel.this.skipGLOrientationVerticalFlip && offscreenDrawable.isGLOriented();
+ offscreenIsFBO = offscreenDrawable.getRequestedGLCapabilities().isFBO();
+ final boolean useGLSLFlip_pre = flipVertical && offscreenIsFBO && reqOffscreenCaps.getGLProfile().isGL2ES2() && USE_GLSL_TEXTURE_RASTERIZER;
+ if( offscreenIsFBO && !useGLSLFlip_pre ) {
+ // Texture attachment only required for GLSL vertical flip, hence simply use a color-renderbuffer attachment.
+ ((GLFBODrawable)offscreenDrawable).setFBOMode(0);
+ }
+
offscreenContext = (GLContextImpl) offscreenDrawable.createContext(shareWith[0]);
offscreenContext.setContextCreationFlags(additionalCtxCreationFlags);
if( GLContext.CONTEXT_NOT_CURRENT < offscreenContext.makeCurrent() ) {
@@ -1543,28 +1673,32 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
helper.setAutoSwapBufferMode(false); // we handle swap-buffers, see handlesSwapBuffer()
final GL gl = offscreenContext.getGL();
- flipVertical = !GLJPanel.this.skipGLOrientationVerticalFlip && offscreenDrawable.isGLOriented();
+ // Remedy for Bug 1020, i.e. OSX/Nvidia's FBO needs to be cleared before blitting,
+ // otherwise first MSAA frame lacks antialiasing.
+ // Clearing of FBO is performed within GLFBODrawableImpl.initialize(..):
+ // gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
final GLCapabilitiesImmutable chosenCaps = offscreenDrawable.getChosenGLCapabilities();
- offscreenIsFBO = chosenCaps.isFBO();
final boolean glslCompliant = !offscreenContext.hasRendererQuirk(GLRendererQuirks.GLSLNonCompliant);
- final boolean useGLSLFlip = flipVertical && offscreenIsFBO && gl.isGL2ES2() && USE_GLSL_TEXTURE_RASTERIZER && glslCompliant;
+ final boolean useGLSLFlip = useGLSLFlip_pre && gl.isGL2ES2() && glslCompliant;
if( DEBUG ) {
System.err.println(getThreadName()+": OffscreenBackend.initialize: useGLSLFlip "+useGLSLFlip+
" [flip "+flipVertical+", isFBO "+offscreenIsFBO+", isGL2ES2 "+gl.isGL2ES2()+
", noglsl "+!USE_GLSL_TEXTURE_RASTERIZER+", glslNonCompliant "+!glslCompliant+
- ", isGL2ES2 " + gl.isGL2ES2()+"]");
+ ", isGL2ES2 " + gl.isGL2ES2()+"\n "+offscreenDrawable+"]");
}
if( useGLSLFlip ) {
final GLFBODrawable fboDrawable = (GLFBODrawable) offscreenDrawable;
fboDrawable.setTextureUnit( GLJPanel.this.requestedTextureUnit );
try {
fboFlipped = new FBObject();
- fboFlipped.reset(gl, fboDrawable.getSurfaceWidth(), fboDrawable.getSurfaceHeight(), 0, false);
- fboFlipped.attachTexture2D(gl, 0, chosenCaps.getAlphaBits()>0);
+ fboFlipped.init(gl, panelWidth, panelHeight, 0);
+ fboFlipped.attachColorbuffer(gl, 0, chosenCaps.getAlphaBits()>0);
// fboFlipped.attachRenderbuffer(gl, Attachment.Type.DEPTH, 24);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT); // Bug 1020 (see above), cannot do in FBObject due to unknown 'first bind' state.
glslTextureRaster = new GLSLTextureRaster(fboDrawable.getTextureUnit(), true);
glslTextureRaster.init(gl.getGL2ES2());
- glslTextureRaster.reshape(gl.getGL2ES2(), 0, 0, fboDrawable.getSurfaceWidth(), fboDrawable.getSurfaceHeight());
+ glslTextureRaster.reshape(gl.getGL2ES2(), 0, 0, panelWidth, panelHeight);
} catch (final Exception ex) {
ex.printStackTrace();
if(null != glslTextureRaster) {
@@ -1584,6 +1718,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
} else {
isInitialized = false;
}
+ } catch( final GLException gle ) {
+ glException = gle;
} finally {
if( !isInitialized ) {
if(null != offscreenContext) {
@@ -1595,6 +1731,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
offscreenDrawable = null;
}
}
+ if( null != glException ) {
+ throw new GLException("Caught GLException: "+glException.getMessage(), glException);
+ }
}
}
@@ -1677,7 +1816,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
@Override
public final void postGL(final Graphics g, final boolean isDisplay) {
if (isDisplay) {
- if(DEBUG) {
+ if( DEBUG_FRAMES ) {
System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: - frameCount "+frameCount);
}
@@ -1772,15 +1911,15 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
// Must now copy pixels from offscreen context into surface
- if(DEBUG) {
+ if( DEBUG_FRAMES ) {
System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.readPixels: - frameCount "+frameCount);
}
// Save PACK modes, reset them to defaults and set alignment
psm.setPackAlignment(gl, alignment);
- if(gl.isGL2ES3()) {
+ if( gl.isGL2ES3() ) {
final GL2ES3 gl2es3 = gl.getGL2ES3();
- gl2es3.glPixelStorei(GL2ES3.GL_PACK_ROW_LENGTH, panelWidth);
+ psm.setPackRowLength(gl2es3, panelWidth);
gl2es3.glReadBuffer(gl2es3.getDefaultReadBuffer());
}
@@ -1789,19 +1928,19 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
final int[] usrViewport = new int[] { 0, 0, 0, 0 };
gl.glGetIntegerv(GL.GL_VIEWPORT, usrViewport, 0);
viewportChange = 0 != usrViewport[0] || 0 != usrViewport[1] ||
- offscreenDrawable.getSurfaceWidth() != usrViewport[2] || offscreenDrawable.getSurfaceHeight() != usrViewport[3];
+ panelWidth != usrViewport[2] || panelHeight != usrViewport[3];
if( DEBUG_VIEWPORT ) {
System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL: "+GLJPanel.this.getName()+" Viewport: change "+viewportChange+
", "+usrViewport[0]+"/"+usrViewport[1]+" "+usrViewport[2]+"x"+usrViewport[3]+
- " -> 0/0 "+offscreenDrawable.getSurfaceWidth()+"x"+offscreenDrawable.getSurfaceHeight());
+ " -> 0/0 "+panelWidth+"x"+panelHeight);
}
if( viewportChange ) {
- gl.glViewport(0, 0, offscreenDrawable.getSurfaceWidth(), offscreenDrawable.getSurfaceHeight());
+ gl.glViewport(0, 0, panelWidth, panelHeight);
}
// perform vert-flipping via OpenGL/FBO
final GLFBODrawable fboDrawable = (GLFBODrawable)offscreenDrawable;
- final FBObject.TextureAttachment fboTex = fboDrawable.getTextureBuffer(GL.GL_FRONT);
+ final FBObject.TextureAttachment fboTex = fboDrawable.getColorbuffer(GL.GL_FRONT).getTextureAttachment();
fboFlipped.bind(gl);
@@ -1863,7 +2002,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
helper.invokeGL(offscreenDrawable, offscreenContext, updaterDisplayAction, updaterInitAction);
if ( null != alignedImage ) {
- if( DEBUG ) {
+ if( DEBUG_FRAMES ) {
System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.doPaintComponent.drawImage: - frameCount "+frameCount);
}
// Draw resulting image in one shot
@@ -1879,7 +2018,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
@Override
public final boolean handleReshape() {
- GLDrawableImpl _drawable = offscreenDrawable;
+ GLDrawableImpl _drawable = (GLDrawableImpl)offscreenDrawable;
{
final GLDrawableImpl _drawableNew = GLDrawableHelper.resizeOffscreenDrawable(_drawable, offscreenContext, panelWidth, panelHeight);
if(_drawable != _drawableNew) {
@@ -1899,8 +2038,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
if( GLContext.CONTEXT_NOT_CURRENT < offscreenContext.makeCurrent() ) {
try {
final GL gl = offscreenContext.getGL();
- fboFlipped.reset(gl, _drawable.getSurfaceWidth(), _drawable.getSurfaceHeight(), 0, false);
- glslTextureRaster.reshape(gl.getGL2ES2(), 0, 0, _drawable.getSurfaceWidth(), _drawable.getSurfaceHeight());
+ fboFlipped.reset(gl, panelWidth, panelHeight, 0);
+ glslTextureRaster.reshape(gl.getGL2ES2(), 0, 0, panelWidth, panelHeight);
} finally {
offscreenContext.release();
}
@@ -2297,29 +2436,29 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
j2dContext.makeCurrent();
final GL gl = j2dContext.getGL();
- if ((getGLInteger(gl, GL.GL_RED_BITS) < offscreenCaps.getRedBits()) ||
- (getGLInteger(gl, GL.GL_GREEN_BITS) < offscreenCaps.getGreenBits()) ||
- (getGLInteger(gl, GL.GL_BLUE_BITS) < offscreenCaps.getBlueBits()) ||
+ if ((getGLInteger(gl, GL.GL_RED_BITS) < reqOffscreenCaps.getRedBits()) ||
+ (getGLInteger(gl, GL.GL_GREEN_BITS) < reqOffscreenCaps.getGreenBits()) ||
+ (getGLInteger(gl, GL.GL_BLUE_BITS) < reqOffscreenCaps.getBlueBits()) ||
// (getGLInteger(gl, GL.GL_ALPHA_BITS) < offscreenCaps.getAlphaBits()) ||
- (getGLInteger(gl, GL2.GL_ACCUM_RED_BITS) < offscreenCaps.getAccumRedBits()) ||
- (getGLInteger(gl, GL2.GL_ACCUM_GREEN_BITS) < offscreenCaps.getAccumGreenBits()) ||
- (getGLInteger(gl, GL2.GL_ACCUM_BLUE_BITS) < offscreenCaps.getAccumBlueBits()) ||
- (getGLInteger(gl, GL2.GL_ACCUM_ALPHA_BITS) < offscreenCaps.getAccumAlphaBits()) ||
+ (getGLInteger(gl, GL2.GL_ACCUM_RED_BITS) < reqOffscreenCaps.getAccumRedBits()) ||
+ (getGLInteger(gl, GL2.GL_ACCUM_GREEN_BITS) < reqOffscreenCaps.getAccumGreenBits()) ||
+ (getGLInteger(gl, GL2.GL_ACCUM_BLUE_BITS) < reqOffscreenCaps.getAccumBlueBits()) ||
+ (getGLInteger(gl, GL2.GL_ACCUM_ALPHA_BITS) < reqOffscreenCaps.getAccumAlphaBits()) ||
// (getGLInteger(gl, GL2.GL_DEPTH_BITS) < offscreenCaps.getDepthBits()) ||
- (getGLInteger(gl, GL.GL_STENCIL_BITS) < offscreenCaps.getStencilBits())) {
+ (getGLInteger(gl, GL.GL_STENCIL_BITS) < reqOffscreenCaps.getStencilBits())) {
if (DEBUG) {
System.err.println(getThreadName()+": GLJPanel: Falling back to pbuffer-based support because Java2D context insufficient");
System.err.println(" Available Required");
- System.err.println("GL_RED_BITS " + getGLInteger(gl, GL.GL_RED_BITS) + " " + offscreenCaps.getRedBits());
- System.err.println("GL_GREEN_BITS " + getGLInteger(gl, GL.GL_GREEN_BITS) + " " + offscreenCaps.getGreenBits());
- System.err.println("GL_BLUE_BITS " + getGLInteger(gl, GL.GL_BLUE_BITS) + " " + offscreenCaps.getBlueBits());
- System.err.println("GL_ALPHA_BITS " + getGLInteger(gl, GL.GL_ALPHA_BITS) + " " + offscreenCaps.getAlphaBits());
- System.err.println("GL_ACCUM_RED_BITS " + getGLInteger(gl, GL2.GL_ACCUM_RED_BITS) + " " + offscreenCaps.getAccumRedBits());
- System.err.println("GL_ACCUM_GREEN_BITS " + getGLInteger(gl, GL2.GL_ACCUM_GREEN_BITS) + " " + offscreenCaps.getAccumGreenBits());
- System.err.println("GL_ACCUM_BLUE_BITS " + getGLInteger(gl, GL2.GL_ACCUM_BLUE_BITS) + " " + offscreenCaps.getAccumBlueBits());
- System.err.println("GL_ACCUM_ALPHA_BITS " + getGLInteger(gl, GL2.GL_ACCUM_ALPHA_BITS) + " " + offscreenCaps.getAccumAlphaBits());
- System.err.println("GL_DEPTH_BITS " + getGLInteger(gl, GL.GL_DEPTH_BITS) + " " + offscreenCaps.getDepthBits());
- System.err.println("GL_STENCIL_BITS " + getGLInteger(gl, GL.GL_STENCIL_BITS) + " " + offscreenCaps.getStencilBits());
+ System.err.println("GL_RED_BITS " + getGLInteger(gl, GL.GL_RED_BITS) + " " + reqOffscreenCaps.getRedBits());
+ System.err.println("GL_GREEN_BITS " + getGLInteger(gl, GL.GL_GREEN_BITS) + " " + reqOffscreenCaps.getGreenBits());
+ System.err.println("GL_BLUE_BITS " + getGLInteger(gl, GL.GL_BLUE_BITS) + " " + reqOffscreenCaps.getBlueBits());
+ System.err.println("GL_ALPHA_BITS " + getGLInteger(gl, GL.GL_ALPHA_BITS) + " " + reqOffscreenCaps.getAlphaBits());
+ System.err.println("GL_ACCUM_RED_BITS " + getGLInteger(gl, GL2.GL_ACCUM_RED_BITS) + " " + reqOffscreenCaps.getAccumRedBits());
+ System.err.println("GL_ACCUM_GREEN_BITS " + getGLInteger(gl, GL2.GL_ACCUM_GREEN_BITS) + " " + reqOffscreenCaps.getAccumGreenBits());
+ System.err.println("GL_ACCUM_BLUE_BITS " + getGLInteger(gl, GL2.GL_ACCUM_BLUE_BITS) + " " + reqOffscreenCaps.getAccumBlueBits());
+ System.err.println("GL_ACCUM_ALPHA_BITS " + getGLInteger(gl, GL2.GL_ACCUM_ALPHA_BITS) + " " + reqOffscreenCaps.getAccumAlphaBits());
+ System.err.println("GL_DEPTH_BITS " + getGLInteger(gl, GL.GL_DEPTH_BITS) + " " + reqOffscreenCaps.getDepthBits());
+ System.err.println("GL_STENCIL_BITS " + getGLInteger(gl, GL.GL_STENCIL_BITS) + " " + reqOffscreenCaps.getStencilBits());
}
isInitialized = false;
backend = null;