aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/opengl/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl/util')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java12
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/Animator.java95
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java91
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java11
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java120
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java15
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java436
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLPixelStorageModes.java36
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java2
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/Gamma.java116
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java38
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java103
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java34
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java19
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java3
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java20
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java33
17 files changed, 787 insertions, 397 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
index 496fb88c0..62df3faca 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
@@ -41,12 +41,14 @@ import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+
import javax.swing.JComponent;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;
-
import javax.media.opengl.GLAutoDrawable;
+import com.jogamp.opengl.util.AnimatorBase.UncaughtAnimatorException;
+
/** Abstraction to factor out AWT dependencies from the Animator's
implementation in a way that still allows the FPSAnimator to pick
up this behavior if desired. */
@@ -61,7 +63,7 @@ class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl {
@Override
public void display(final ArrayList<GLAutoDrawable> drawables,
final boolean ignoreExceptions,
- final boolean printExceptions) {
+ final boolean printExceptions) throws UncaughtAnimatorException {
for (int i=0; i<drawables.size(); i++) {
final GLAutoDrawable drawable = drawables.get(i);
if (drawable instanceof JComponent) {
@@ -73,13 +75,13 @@ class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl {
} else {
try {
drawable.display();
- } catch (final RuntimeException e) {
+ } catch (final Throwable t) {
if (ignoreExceptions) {
if (printExceptions) {
- e.printStackTrace();
+ t.printStackTrace();
}
} else {
- throw(e);
+ throw new UncaughtAnimatorException(drawable, t);
}
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
index ae09d81a4..b38a42ee3 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
@@ -58,12 +58,12 @@ import javax.media.opengl.GLException;
* </p>
*/
public class Animator extends AnimatorBase {
- protected ThreadGroup threadGroup;
+ private ThreadGroup threadGroup;
private Runnable runnable;
private boolean runAsFastAsPossible;
- protected boolean isAnimating;
- protected boolean pauseIssued;
- protected volatile boolean stopIssued;
+ boolean isAnimating;
+ volatile boolean pauseIssued;
+ volatile boolean stopIssued;
/**
* Creates a new, empty Animator.
@@ -132,6 +132,9 @@ public class Animator extends AnimatorBase {
@Override
public void run() {
+ ThreadDeath caughtThreadDeath = null;
+ UncaughtAnimatorException caughtException = null;
+
try {
synchronized (Animator.this) {
if(DEBUG) {
@@ -147,7 +150,7 @@ public class Animator extends AnimatorBase {
synchronized (Animator.this) {
// Pause; Also don't consume CPU unless there is work to be done and not paused
boolean ectCleared = false;
- while (!stopIssued && (pauseIssued || drawablesEmpty)) {
+ while ( !stopIssued && ( pauseIssued || drawablesEmpty ) ) {
if( drawablesEmpty ) {
pauseIssued = true;
}
@@ -158,7 +161,13 @@ public class Animator extends AnimatorBase {
if ( exclusiveContext && !drawablesEmpty && !ectCleared ) {
ectCleared = true;
setDrawablesExclCtxState(false);
- display(); // propagate exclusive change!
+ try {
+ display(); // propagate exclusive context -> off!
+ } catch (final UncaughtAnimatorException dre) {
+ caughtException = dre;
+ stopIssued = true;
+ break; // end pause loop
+ }
}
isAnimating = false;
Animator.this.notifyAll();
@@ -180,38 +189,72 @@ public class Animator extends AnimatorBase {
// Resume from pause or drawablesEmpty,
// implies !pauseIssued and !drawablesEmpty
isAnimating = true;
- setDrawablesExclCtxState(exclusiveContext);
+ setDrawablesExclCtxState(exclusiveContext); // may re-enable exclusive context
Animator.this.notifyAll();
}
} // sync Animator.this
- if (!stopIssued) {
- display();
- }
- if (!stopIssued && !runAsFastAsPossible) {
- // Avoid swamping the CPU
- Thread.yield();
+ if ( !pauseIssued && !stopIssued ) {
+ try {
+ display();
+ } catch (final UncaughtAnimatorException dre) {
+ caughtException = dre;
+ stopIssued = true;
+ break; // end animation loop
+ }
+ if ( !runAsFastAsPossible ) {
+ // Avoid swamping the CPU
+ Thread.yield();
+ }
}
}
- } catch( final ThreadDeath td) {
+ } catch(final ThreadDeath td) {
if(DEBUG) {
System.err.println("Animator caught: "+td.getClass().getName()+": "+td.getMessage());
td.printStackTrace();
}
- } finally {
- if( exclusiveContext && !drawablesEmpty ) {
- setDrawablesExclCtxState(false);
- display(); // propagate exclusive change!
+ caughtThreadDeath = td;
+ }
+ if( exclusiveContext && !drawablesEmpty ) {
+ setDrawablesExclCtxState(false);
+ try {
+ display(); // propagate exclusive context -> off!
+ } catch (final UncaughtAnimatorException dre) {
+ if( null == caughtException ) {
+ caughtException = dre;
+ } else {
+ System.err.println("Animator.setExclusiveContextThread: caught: "+dre.getMessage());
+ dre.printStackTrace();
+ }
}
- synchronized (Animator.this) {
- if(DEBUG) {
- System.err.println("Animator stop on " + animThread.getName() + ": " + toString());
+ }
+ boolean flushGLRunnables = false;
+ boolean throwCaughtException = false;
+ synchronized (Animator.this) {
+ if(DEBUG) {
+ System.err.println("Animator stop on " + animThread.getName() + ": " + toString());
+ if( null != caughtException ) {
+ System.err.println("Animator caught: "+caughtException.getMessage());
+ caughtException.printStackTrace();
}
- stopIssued = false;
- pauseIssued = false;
- animThread = null;
- isAnimating = false;
- Animator.this.notifyAll();
}
+ stopIssued = false;
+ pauseIssued = false;
+ isAnimating = false;
+ if( null != caughtException ) {
+ flushGLRunnables = true;
+ throwCaughtException = !handleUncaughtException(caughtException);
+ }
+ animThread = null;
+ Animator.this.notifyAll();
+ }
+ if( flushGLRunnables ) {
+ flushGLRunnables();
+ }
+ if( throwCaughtException ) {
+ throw caughtException;
+ }
+ if( null != caughtThreadDeath ) {
+ throw caughtThreadDeath;
}
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
index a5bdb9350..bc159ef5c 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
@@ -67,9 +67,26 @@ public abstract class AnimatorBase implements GLAnimatorControl {
*/
public static final int MODE_EXPECT_AWT_RENDERING_THREAD = 1 << 0;
- public interface AnimatorImpl {
- void display(ArrayList<GLAutoDrawable> drawables, boolean ignoreExceptions, boolean printExceptions);
- boolean blockUntilDone(Thread thread);
+
+ @SuppressWarnings("serial")
+ public static class UncaughtAnimatorException extends RuntimeException {
+ final GLAutoDrawable drawable;
+ public UncaughtAnimatorException(final GLAutoDrawable drawable, final Throwable cause) {
+ super(cause);
+ this.drawable = drawable;
+ }
+ public final GLAutoDrawable getGLAutoDrawable() { return drawable; }
+ }
+
+ public static interface AnimatorImpl {
+ /**
+ * @param drawables
+ * @param ignoreExceptions
+ * @param printExceptions
+ * @throws UncaughtAnimatorException as caused by {@link GLAutoDrawable#display()}
+ */
+ void display(final ArrayList<GLAutoDrawable> drawables, final boolean ignoreExceptions, final boolean printExceptions) throws UncaughtAnimatorException;
+ boolean blockUntilDone(final Thread thread);
}
protected int modeBits;
@@ -83,6 +100,7 @@ public abstract class AnimatorBase implements GLAnimatorControl {
protected boolean printExceptions;
protected boolean exclusiveContext;
protected Thread userExclusiveContextThread;
+ protected UncaughtExceptionHandler uncaughtExceptionHandler;
protected FPSCounterImpl fpsCounter = new FPSCounterImpl();
private final static Class<?> awtAnimatorImplClazz;
@@ -313,11 +331,16 @@ public abstract class AnimatorBase implements GLAnimatorControl {
}
}
final Thread dECT = enable ? ( null != _exclusiveContextThread ? _exclusiveContextThread : animThread ) : null ;
+ UncaughtAnimatorException displayCaught = null;
if( propagateState ) {
setDrawablesExclCtxState(enable);
if( !enable ) {
if( Thread.currentThread() == getThread() || Thread.currentThread() == _exclusiveContextThread ) {
- display();
+ try {
+ display(); // propagate exclusive context -> off!
+ } catch (final UncaughtAnimatorException dre) {
+ displayCaught = dre;
+ }
} else {
final boolean resumed = isAnimating() ? false : resume();
int counter = 10;
@@ -338,6 +361,13 @@ public abstract class AnimatorBase implements GLAnimatorControl {
}
if(DEBUG) {
System.err.println("AnimatorBase.setExclusiveContextThread: all-GLAD Ok: "+validateDrawablesExclCtxState(dECT)+", "+this);
+ if( null != displayCaught ) {
+ System.err.println("AnimatorBase.setExclusiveContextThread: caught: "+displayCaught.getMessage());
+ displayCaught.printStackTrace();
+ }
+ }
+ if( null != displayCaught ) {
+ throw displayCaught;
}
return oldExclusiveContext;
}
@@ -412,7 +442,7 @@ public abstract class AnimatorBase implements GLAnimatorControl {
this to get the most optimized painting behavior for the set of
components this Animator manages, in particular when multiple
lightweight widgets are continually being redrawn. */
- protected final void display() {
+ protected final void display() throws UncaughtAnimatorException {
impl.display(drawables, ignoreExceptions, printExceptions);
fpsCounter.tickFPS();
}
@@ -482,7 +512,47 @@ public abstract class AnimatorBase implements GLAnimatorControl {
this.printExceptions = printExceptions;
}
- protected interface Condition {
+ @Override
+ public final UncaughtExceptionHandler getUncaughtExceptionHandler() {
+ return uncaughtExceptionHandler;
+ }
+
+ @Override
+ public final void setUncaughtExceptionHandler(final UncaughtExceptionHandler handler) {
+ uncaughtExceptionHandler = handler;
+ }
+
+ /**
+ * Should be called in case of an uncaught exception
+ * from within the animator thread, throws given exception if no handler has been installed.
+ * @return {@code true} if handled, otherwise {@code false}. In case of {@code false},
+ * caller needs to propagate the exception.
+ */
+ protected final synchronized boolean handleUncaughtException(final UncaughtAnimatorException ue) {
+ if( null != uncaughtExceptionHandler ) {
+ try {
+ uncaughtExceptionHandler.uncaughtException(this, ue.getGLAutoDrawable(), ue.getCause());
+ } catch (final Throwable t) { /* ignore intentionally */ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Should be called in case of an uncaught exception
+ * from within the animator thread to flush all animator.
+ * <p>
+ * The animator instance shall not be locked when calling this method!
+ * </p>
+ */
+ protected final void flushGLRunnables() {
+ for (int i=0; i<drawables.size(); i++) {
+ drawables.get(i).flushGLRunnables();
+ }
+ }
+
+ protected static interface Condition {
/**
* @return true if branching (continue waiting, action), otherwise false
*/
@@ -493,7 +563,8 @@ public abstract class AnimatorBase implements GLAnimatorControl {
* @param waitCondition method will wait until TO is reached or {@link Condition#eval() waitCondition.eval()} returns <code>false</code>.
* @param pollPeriod if <code>0</code>, method will wait until TO is reached or being notified.
* if &gt; <code>0</code>, method will wait for the given <code>pollPeriod</code> in milliseconds.
- * @return <code>true</code> if {@link Condition#eval() waitCondition.eval()} returned <code>false</code>, otherwise <code>false</code>.
+ * @return <code>true</code> if {@link Condition#eval() waitCondition.eval()} returned <code>false</code>
+ * or if {@link AnimatorImpl#blockUntilDone(Thread) non-blocking}. Otherwise returns <code>false</code>.
*/
protected final synchronized boolean finishLifecycleAction(final Condition waitCondition, long pollPeriod) {
/**
@@ -506,6 +577,7 @@ public abstract class AnimatorBase implements GLAnimatorControl {
final boolean blocking;
long remaining;
boolean nok;
+
if( impl.blockUntilDone(animThread) ) {
blocking = true;
remaining = TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION;
@@ -539,12 +611,13 @@ public abstract class AnimatorBase implements GLAnimatorControl {
nok = waitCondition.eval();
}
}
+ final boolean res = !nok || !blocking;
if(DEBUG || blocking && nok) { // Info only if DEBUG or ( blocking && not-ok ) ; !blocking possible if AWT
if( blocking && remaining<=0 && nok ) {
System.err.println("finishLifecycleAction(" + waitCondition.getClass().getName() + "): ++++++ timeout reached ++++++ " + getThreadName());
}
System.err.println("finishLifecycleAction(" + waitCondition.getClass().getName() + "): OK "+(!nok)+
- "- pollPeriod "+pollPeriod+", blocking "+blocking+
+ "- pollPeriod "+pollPeriod+", blocking "+blocking+" -> res "+res+
", waited " + (blocking ? ( TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION - remaining ) : 0 ) + "/" + TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION +
" - " + getThreadName());
System.err.println(" - "+toString());
@@ -552,7 +625,7 @@ public abstract class AnimatorBase implements GLAnimatorControl {
Thread.dumpStack();
}
}
- return !nok;
+ return res;
}
@Override
diff --git a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java
index 7fa4011f8..6b1485a6a 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java
@@ -34,8 +34,11 @@
package com.jogamp.opengl.util;
import java.util.ArrayList;
+
import javax.media.opengl.GLAutoDrawable;
+import com.jogamp.opengl.util.AnimatorBase.UncaughtAnimatorException;
+
/** Abstraction to factor out AWT dependencies from the Animator's
implementation in a way that still allows the FPSAnimator to pick
up this behavior if desired. */
@@ -44,18 +47,18 @@ class DefaultAnimatorImpl implements AnimatorBase.AnimatorImpl {
@Override
public void display(final ArrayList<GLAutoDrawable> drawables,
final boolean ignoreExceptions,
- final boolean printExceptions) {
+ final boolean printExceptions) throws UncaughtAnimatorException {
for (int i=0; i<drawables.size(); i++) {
final GLAutoDrawable drawable = drawables.get(i);
try {
drawable.display();
- } catch (final RuntimeException e) {
+ } catch (final Throwable t) {
if (ignoreExceptions) {
if (printExceptions) {
- e.printStackTrace();
+ t.printStackTrace();
}
} else {
- throw(e);
+ throw new UncaughtAnimatorException(drawable, t);
}
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
index 746b642c2..54d40f285 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
@@ -60,9 +60,9 @@ public class FPSAnimator extends AnimatorBase {
private MainTask task = null;
private int fps;
private final boolean scheduleAtFixedRate;
- private boolean isAnimating; // MainTask feedback
- private volatile boolean shouldRun; // MainTask trigger
- private volatile boolean shouldStop; // MainTask trigger
+ private boolean isAnimating; // MainTask feedback
+ private volatile boolean pauseIssued; // MainTask trigger
+ private volatile boolean stopIssued; // MainTask trigger
@Override
protected String getBaseName(final String prefix) {
@@ -124,8 +124,9 @@ public class FPSAnimator extends AnimatorBase {
public void start(final Timer timer) {
fpsCounter.resetFPSCounter();
- shouldRun = true;
- shouldStop = false;
+ pauseIssued = false;
+ stopIssued = false;
+ isAnimating = false;
justStarted = true;
alreadyStopped = false;
@@ -143,11 +144,13 @@ public class FPSAnimator extends AnimatorBase {
@Override
public final String toString() {
- return "Task[thread "+animThread+", stopped "+alreadyStopped+", paused "+alreadyPaused+" shouldRun "+shouldRun+", shouldStop "+shouldStop+" -- started "+isStarted()+", animating "+isAnimatingImpl()+", paused "+isPaused()+", drawable "+drawables.size()+", drawablesEmpty "+drawablesEmpty+"]";
+ return "Task[thread "+animThread+", stopped "+alreadyStopped+", paused "+alreadyPaused+" pauseIssued "+pauseIssued+", stopIssued "+stopIssued+" -- started "+isStarted()+", animating "+isAnimatingImpl()+", paused "+isPaused()+", drawable "+drawables.size()+", drawablesEmpty "+drawablesEmpty+"]";
}
@Override
public void run() {
+ UncaughtAnimatorException caughtException = null;
+
if( justStarted ) {
justStarted = false;
synchronized (FPSAnimator.this) {
@@ -157,59 +160,97 @@ public class FPSAnimator extends AnimatorBase {
}
isAnimating = true;
if( drawablesEmpty ) {
- shouldRun = false; // isAnimating:=false @ pause below
+ pauseIssued = true; // isAnimating:=false @ pause below
} else {
- shouldRun = true;
- setDrawablesExclCtxState(exclusiveContext);
- FPSAnimator.this.notifyAll();
+ pauseIssued = false;
+ setDrawablesExclCtxState(exclusiveContext); // may re-enable exclusive context
}
+ FPSAnimator.this.notifyAll(); // Wakes up 'waitForStartedCondition' sync -and resume from pause or drawablesEmpty
if(DEBUG) {
System.err.println("FPSAnimator P1:" + Thread.currentThread() + ": " + toString());
}
}
}
- if( shouldRun ) {
- display();
- } else if( shouldStop ) { // STOP
+ if( !pauseIssued && !stopIssued ) { // RUN
+ try {
+ display();
+ } catch (final UncaughtAnimatorException dre) {
+ caughtException = dre;
+ stopIssued = true;
+ }
+ } else if( pauseIssued && !stopIssued ) { // PAUSE
if(DEBUG) {
- System.err.println("FPSAnimator P4: "+alreadyStopped+", "+ Thread.currentThread() + ": " + toString());
+ System.err.println("FPSAnimator pausing: "+alreadyPaused+", "+ Thread.currentThread() + ": " + toString());
}
this.cancel();
- if( !alreadyStopped ) {
- alreadyStopped = true;
+ if( !alreadyPaused ) { // PAUSE
+ alreadyPaused = true;
if( exclusiveContext && !drawablesEmpty ) {
setDrawablesExclCtxState(false);
- display(); // propagate exclusive change!
+ try {
+ display(); // propagate exclusive context -> off!
+ } catch (final UncaughtAnimatorException dre) {
+ caughtException = dre;
+ stopIssued = true;
+ }
}
- synchronized (FPSAnimator.this) {
- if(DEBUG) {
- System.err.println("FPSAnimator stop " + Thread.currentThread() + ": " + toString());
+ if( null == caughtException ) {
+ synchronized (FPSAnimator.this) {
+ if(DEBUG) {
+ System.err.println("FPSAnimator pause " + Thread.currentThread() + ": " + toString());
+ }
+ isAnimating = false;
+ FPSAnimator.this.notifyAll();
}
- animThread = null;
- isAnimating = false;
- FPSAnimator.this.notifyAll();
}
}
- } else {
+ }
+ if( stopIssued ) { // STOP incl. immediate exception handling of 'displayCaught'
if(DEBUG) {
- System.err.println("FPSAnimator P5: "+alreadyPaused+", "+ Thread.currentThread() + ": " + toString());
+ System.err.println("FPSAnimator stopping: "+alreadyStopped+", "+ Thread.currentThread() + ": " + toString());
}
this.cancel();
- if( !alreadyPaused ) { // PAUSE
- alreadyPaused = true;
+ if( !alreadyStopped ) {
+ alreadyStopped = true;
if( exclusiveContext && !drawablesEmpty ) {
setDrawablesExclCtxState(false);
- display(); // propagate exclusive change!
+ try {
+ display(); // propagate exclusive context -> off!
+ } catch (final UncaughtAnimatorException dre) {
+ if( null == caughtException ) {
+ caughtException = dre;
+ } else {
+ System.err.println("FPSAnimator.setExclusiveContextThread: caught: "+dre.getMessage());
+ dre.printStackTrace();
+ }
+ }
}
+ boolean flushGLRunnables = false;
+ boolean throwCaughtException = false;
synchronized (FPSAnimator.this) {
if(DEBUG) {
- System.err.println("FPSAnimator pause " + Thread.currentThread() + ": " + toString());
+ System.err.println("FPSAnimator stop " + Thread.currentThread() + ": " + toString());
+ if( null != caughtException ) {
+ System.err.println("Animator caught: "+caughtException.getMessage());
+ caughtException.printStackTrace();
+ }
}
isAnimating = false;
+ if( null != caughtException ) {
+ flushGLRunnables = true;
+ throwCaughtException = !handleUncaughtException(caughtException);
+ }
+ animThread = null;
FPSAnimator.this.notifyAll();
}
+ if( flushGLRunnables ) {
+ flushGLRunnables();
+ }
+ if( throwCaughtException ) {
+ throw caughtException;
+ }
}
}
}
@@ -224,7 +265,7 @@ public class FPSAnimator extends AnimatorBase {
@Override
public final synchronized boolean isPaused() {
- return animThread != null && ( !shouldRun && !shouldStop ) ;
+ return animThread != null && pauseIssued;
}
static int timerNo = 0;
@@ -279,8 +320,7 @@ public class FPSAnimator extends AnimatorBase {
// start/resume case w/ drawablesEmpty
res = true;
} else {
- shouldRun = false;
- shouldStop = true;
+ stopIssued = true;
res = finishLifecycleAction(waitForStoppedCondition, POLLP_WAIT_FOR_FINISH_LIFECYCLE_ACTION);
}
@@ -306,7 +346,7 @@ public class FPSAnimator extends AnimatorBase {
@Override
public final synchronized boolean pause() {
- if ( !isStarted() || ( null != task && isPaused() ) ) {
+ if ( !isStarted() || pauseIssued ) {
return false;
}
if(DEBUG) {
@@ -317,7 +357,7 @@ public class FPSAnimator extends AnimatorBase {
// start/resume case w/ drawablesEmpty
res = true;
} else {
- shouldRun = false;
+ pauseIssued = true;
res = finishLifecycleAction(waitForPausedCondition, POLLP_WAIT_FOR_FINISH_LIFECYCLE_ACTION);
}
@@ -334,12 +374,12 @@ public class FPSAnimator extends AnimatorBase {
@Override
public boolean eval() {
// end waiting if stopped as well
- return isAnimating && isStarted();
+ return isStarted() && isAnimating;
} };
@Override
public final synchronized boolean resume() {
- if ( null != task || !isStarted() || !isPaused() ) {
+ if ( !isStarted() || !pauseIssued ) {
return false;
}
if(DEBUG) {
@@ -349,6 +389,14 @@ public class FPSAnimator extends AnimatorBase {
if( drawablesEmpty ) {
res = true;
} else {
+ if( null != task ) {
+ if( DEBUG ) {
+ System.err.println("FPSAnimator.resume() Ops: !pauseIssued, but task != null: "+toString());
+ Thread.dumpStack();
+ }
+ task.cancel();
+ task = null;
+ }
task = new MainTask();
task.start(timer);
res = finishLifecycleAction(waitForResumeCondition, POLLP_WAIT_FOR_FINISH_LIFECYCLE_ACTION);
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java
index 44be29957..d4ab4e4f4 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java
@@ -46,6 +46,7 @@ import javax.media.opengl.GL2;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GL2ES3;
import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLContext;
import javax.media.opengl.GLES2;
import javax.media.opengl.GLException;
@@ -372,25 +373,29 @@ public class GLBuffers extends Buffers {
if (pack) {
alignment = glGetInteger(gl, GL.GL_PACK_ALIGNMENT, tmp);
- if(gl.isGL2GL3()) {
+ if( gl.isGL2ES3() ) {
rowLength = glGetInteger(gl, GL2ES3.GL_PACK_ROW_LENGTH, tmp);
skipRows = glGetInteger(gl, GL2ES3.GL_PACK_SKIP_ROWS, tmp);
skipPixels = glGetInteger(gl, GL2ES3.GL_PACK_SKIP_PIXELS, tmp);
- if (depth > 1) {
+ if (depth > 1 && gl.isGL2GL3() && gl.getContext().getGLVersionNumber().compareTo(GLContext.Version120) >= 0 ) {
imageHeight = glGetInteger(gl, GL2GL3.GL_PACK_IMAGE_HEIGHT, tmp);
skipImages = glGetInteger(gl, GL2GL3.GL_PACK_SKIP_IMAGES, tmp);
}
}
} else {
alignment = glGetInteger(gl, GL.GL_UNPACK_ALIGNMENT, tmp);
- if(gl.isGL2GL3 ()) {
+ if( gl.isGL2ES3() ) {
rowLength = glGetInteger(gl, GL2ES2.GL_UNPACK_ROW_LENGTH, tmp);
skipRows = glGetInteger(gl, GL2ES2.GL_UNPACK_SKIP_ROWS, tmp);
skipPixels = glGetInteger(gl, GL2ES2.GL_UNPACK_SKIP_PIXELS, tmp);
- if (depth > 1) {
+ if( depth > 1 &&
+ ( gl.isGL3ES3() ||
+ ( gl.isGL2GL3() && gl.getContext().getGLVersionNumber().compareTo(GLContext.Version120) >= 0 )
+ )
+ ) {
imageHeight = glGetInteger(gl, GL2ES3.GL_UNPACK_IMAGE_HEIGHT, tmp);
skipImages = glGetInteger(gl, GL2ES3.GL_UNPACK_SKIP_IMAGES, tmp);
- }
+ }
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
index c74284299..956693c4a 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
@@ -28,6 +28,7 @@
package com.jogamp.opengl.util;
import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.NativeSurface;
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLBase;
@@ -36,7 +37,10 @@ import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLException;
+import javax.media.opengl.GLRunnable;
+import javax.media.opengl.Threading;
+import com.jogamp.common.util.locks.RecursiveLock;
import com.jogamp.opengl.GLEventListenerState;
import jogamp.opengl.Debug;
@@ -45,148 +49,298 @@ import jogamp.opengl.Debug;
* Providing utility functions dealing w/ {@link GLDrawable}s, {@link GLAutoDrawable} and their {@link GLEventListener}.
*/
public class GLDrawableUtil {
- protected static final boolean DEBUG = Debug.debug("GLDrawable");
-
- public static final boolean isAnimatorStartedOnOtherThread(final GLAnimatorControl animatorCtrl) {
- return ( null != animatorCtrl ) ? animatorCtrl.isStarted() && animatorCtrl.getThread() != Thread.currentThread() : false ;
- }
-
- public static final boolean isAnimatorStarted(final GLAnimatorControl animatorCtrl) {
- return ( null != animatorCtrl ) ? animatorCtrl.isStarted() : false ;
- }
-
- public static final boolean isAnimatorAnimatingOnOtherThread(final GLAnimatorControl animatorCtrl) {
- return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() && animatorCtrl.getThread() != Thread.currentThread() : false ;
- }
-
- public static final boolean isAnimatorAnimating(final GLAnimatorControl animatorCtrl) {
- return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() : false ;
- }
-
- /**
- * Moves the designated {@link GLEventListener} from {@link GLAutoDrawable} <code>src</code> to <code>dest</code>.
- * If <code>preserveInitState</code> is <code>true</code>, it's initialized state is preserved
- * and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued w/ the next {@link GLAutoDrawable#display()} call.
- * <p>
- * Note that it is only legal to pass <code>preserveInitState := true</code>,
- * if the {@link GLContext} of both <code>src</code> and <code>dest</code> are shared, or has itself moved from <code>src</code> to <code>dest</code>.
- * </p>
- * <p>
- * Also note that the caller is encouraged to pause an attached {@link GLAnimatorControl}.
- * </p>
- * @param src
- * @param dest
- * @param listener
- * @param preserveInitState
- */
- public static final void moveGLEventListener(final GLAutoDrawable src, final GLAutoDrawable dest, final GLEventListener listener, final boolean preserveInitState) {
- final boolean initialized = src.getGLEventListenerInitState(listener);
- src.removeGLEventListener(listener);
- dest.addGLEventListener(listener);
- if(preserveInitState && initialized) {
- dest.setGLEventListenerInitState(listener, true);
- dest.invoke(false, new GLEventListenerState.ReshapeGLEventListener(listener));
- } // else .. !init state is default
- }
-
- /**
- * Moves all {@link GLEventListener} from {@link GLAutoDrawable} <code>src</code> to <code>dest</code>.
- * If <code>preserveInitState</code> is <code>true</code>, it's initialized state is preserved
- * and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued w/ the next {@link GLAutoDrawable#display()} call.
- * <p>
- * Note that it is only legal to pass <code>preserveInitState := true</code>,
- * if the {@link GLContext} of both <code>src</code> and <code>dest</code> are shared, or has itself moved from <code>src</code> to <code>dest</code>.
- * </p>
- * <p>
- * Also note that the caller is encouraged to pause an attached {@link GLAnimatorControl}.
- * </p>
- * @param src
- * @param dest
- * @param listener
- * @param preserveInitState
- */
- public static final void moveAllGLEventListener(final GLAutoDrawable src, final GLAutoDrawable dest, final boolean preserveInitState) {
- for(int count = src.getGLEventListenerCount(); 0<count; count--) {
- final GLEventListener listener = src.getGLEventListener(0);
- moveGLEventListener(src, dest, listener, preserveInitState);
+ protected static final boolean DEBUG = Debug.debug("GLDrawable");
+
+ public static final boolean isAnimatorStartedOnOtherThread(final GLAnimatorControl animatorCtrl) {
+ return ( null != animatorCtrl ) ? animatorCtrl.isStarted() && animatorCtrl.getThread() != Thread.currentThread() : false ;
+ }
+
+ public static final boolean isAnimatorStarted(final GLAnimatorControl animatorCtrl) {
+ return ( null != animatorCtrl ) ? animatorCtrl.isStarted() : false ;
}
- }
-
- /**
- * Swaps the {@link GLContext} and all {@link GLEventListener} between {@link GLAutoDrawable} <code>a</code> and <code>b</code>,
- * while preserving it's initialized state, resets the GL-Viewport and issuing {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)}.
- * <p>
- * The {@link GLAutoDrawable} to {@link GLAnimatorControl} association
- * is also swapped.
- * </p>
- * <p>
- * If an {@link GLAnimatorControl} is being attached to {@link GLAutoDrawable} <code>a</code> or <code>b</code>
- * and the current thread is different than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
- * </p>
- * @param a
- * @param b
- * @throws GLException if the {@link AbstractGraphicsDevice} are incompatible w/ each other.
- */
- public static final void swapGLContextAndAllGLEventListener(final GLAutoDrawable a, final GLAutoDrawable b) {
- final GLEventListenerState gllsA = GLEventListenerState.moveFrom(a);
- final GLEventListenerState gllsB = GLEventListenerState.moveFrom(b);
-
- gllsA.moveTo(b);
- gllsB.moveTo(a);
- }
-
- /**
- * Swaps the {@link GLContext} of given {@link GLAutoDrawable}
- * and {@link GLAutoDrawable#disposeGLEventListener(GLEventListener, boolean) disposes}
- * each {@link GLEventListener} w/o removing it.
- * <p>
- * The GL-Viewport is reset and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued implicit.
- * </p>
- * <p>
- * If an {@link GLAnimatorControl} is being attached to GLAutoDrawable src or dest and the current thread is different
- * than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
- * </p>
- * @param src
- * @param dest
- */
- public static final void swapGLContext(final GLAutoDrawable src, final GLAutoDrawable dest) {
- final GLAnimatorControl aAnim = src.getAnimator();
- final GLAnimatorControl bAnim = dest.getAnimator();
- final boolean aIsPaused = isAnimatorAnimatingOnOtherThread(aAnim) && aAnim.pause();
- final boolean bIsPaused = isAnimatorAnimatingOnOtherThread(bAnim) && bAnim.pause();
-
- for(int i = src.getGLEventListenerCount() - 1; 0 <= i; i--) {
- src.disposeGLEventListener(src.getGLEventListener(i), false);
+
+ public static final boolean isAnimatorAnimatingOnOtherThread(final GLAnimatorControl animatorCtrl) {
+ return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() && animatorCtrl.getThread() != Thread.currentThread() : false ;
+ }
+
+ public static final boolean isAnimatorAnimating(final GLAnimatorControl animatorCtrl) {
+ return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() : false ;
}
- for(int i = dest.getGLEventListenerCount() - 1; 0 <= i; i--) {
- dest.disposeGLEventListener(dest.getGLEventListener(i), false);
+
+ /**
+ * {@link GLRunnable} to issue {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int)},
+ * returning <code>true</code> on {@link GLRunnable#run(GLAutoDrawable)}.
+ */
+ public static class ReshapeGLEventListener implements GLRunnable {
+ private final GLEventListener listener;
+ private final boolean displayAfterReshape;
+ /**
+ *
+ * @param listener
+ * @param displayAfterReshape <code>true</code> to issue {@link GLEventListener#display(GLAutoDrawable)}
+ * after {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int)},
+ * otherwise false.
+ */
+ public ReshapeGLEventListener(final GLEventListener listener, final boolean displayAfterReshape) {
+ this.listener = listener;
+ this.displayAfterReshape = displayAfterReshape;
+ }
+ @Override
+ public boolean run(final GLAutoDrawable drawable) {
+ listener.reshape(drawable, 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight());
+ if( displayAfterReshape ) {
+ listener.display(drawable);
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Moves the designated {@link GLEventListener} from {@link GLAutoDrawable} <code>src</code> to <code>dest</code>.
+ * If <code>preserveInitState</code> is <code>true</code>, it's initialized state is preserved
+ * and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued w/ the next {@link GLAutoDrawable#display()} call.
+ * <p>
+ * Note that it is only legal to pass <code>preserveInitState := true</code>,
+ * if the {@link GLContext} of both <code>src</code> and <code>dest</code> are shared, or has itself moved from <code>src</code> to <code>dest</code>.
+ * </p>
+ * <p>
+ * Also note that the caller is encouraged to pause an attached {@link GLAnimatorControl}.
+ * </p>
+ * @param src
+ * @param dest
+ * @param listener
+ * @param preserveInitState
+ */
+ public static final void moveGLEventListener(final GLAutoDrawable src, final GLAutoDrawable dest, final GLEventListener listener, final boolean preserveInitState) {
+ final boolean initialized = src.getGLEventListenerInitState(listener);
+ if( preserveInitState ) {
+ src.removeGLEventListener(listener);
+ dest.addGLEventListener(listener);
+ if( initialized ) {
+ dest.setGLEventListenerInitState(listener, true);
+ dest.invoke(false, new ReshapeGLEventListener(listener, true));
+ }
+ } else {
+ src.disposeGLEventListener(listener, true);
+ dest.addGLEventListener(listener);
+ }
+ }
+
+ /**
+ * Moves all {@link GLEventListener} from {@link GLAutoDrawable} <code>src</code> to <code>dest</code>.
+ * If <code>preserveInitState</code> is <code>true</code>, it's initialized state is preserved
+ * and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued w/ the next {@link GLAutoDrawable#display()} call.
+ * <p>
+ * Note that it is only legal to pass <code>preserveInitState := true</code>,
+ * if the {@link GLContext} of both <code>src</code> and <code>dest</code> are shared, or has itself moved from <code>src</code> to <code>dest</code>.
+ * </p>
+ * <p>
+ * Also note that the caller is encouraged to pause an attached {@link GLAnimatorControl}.
+ * </p>
+ * @param src
+ * @param dest
+ * @param listener
+ * @param preserveInitState
+ */
+ public static final void moveAllGLEventListener(final GLAutoDrawable src, final GLAutoDrawable dest, final boolean preserveInitState) {
+ for(int count = src.getGLEventListenerCount(); 0<count; count--) {
+ final GLEventListener listener = src.getGLEventListener(0);
+ moveGLEventListener(src, dest, listener, preserveInitState);
+ }
+ }
+
+ /**
+ * Return a heuristic value whether switching the {@link GLContext} is safe between {@lin GLAutoDrawable}s,
+ * i.e. via {@link #swapGLContext(GLAutoDrawable, GLAutoDrawable)} or {@link #swapGLContextAndAllGLEventListener(GLAutoDrawable, GLAutoDrawable)}.
+ * <p>
+ * Method currently returns <code>false</code> if:
+ * <ul>
+ * <li>Switching between on- and offscreen and one of the following is <code>true</code>:
+ * <ul>
+ * <li>{@link GLCapabilitiesImmutable#getSampleBuffers() MSAA is <i>used</i>} [1] in <code>chosenCapsA</code> or <code>chosenCapsB</code></li>
+ * <li>{@link GLCapabilitiesImmutable#getStereo() Stereo is <i>used</i>} in <code>chosenCapsA</code> or <code>chosenCapsB</code></li>
+ * <li>{@link GLCapabilitiesImmutable#getAccumAlphaBits() Accumulator Buffer is <i>requested</i>} [2] in <code>requestedCaps</code></li>
+ * </ul></li>
+ * </ul>
+ * Otherwise method returns <code>true</code>
+ * </p>
+ * <pre>
+ * [1] See Bug 830: swapGLContextAndAllGLEventListener and onscreen MSAA w/ NV/GLX
+ * On NVidia GPUs w/ it's proprietary driver context swapping does not work if MSAA is involved
+ * and when swapping on- to offscreen.
+ * </pre>
+ * <pre>
+ * [2] On AMD GPUs w/ it's proprietary driver, requesting an accumulator buffer leads to receive an accumulator buffer configuration,
+ * for which context swapping does not work when swapping on- to offscreen and vice-versa, i.e. cannot make context current.
+ * With AMD and Mesa drivers we only receive an accumulator buffer if requested,
+ * where on NVidia drivers all configurations contain the accumulator buffer.
+ * On both drivers, NVidia and Mesa, context swapping with accumulator buffer works.
+ * </pre>
+ * @param requestedCaps requested {@link GLCapabilitiesImmutable} which are intended for usage by both {@link GLAutoDrawable}s A and B
+ * @param chosenCapsA chosen {@link GLCapabilitiesImmutable} of {@link GLAutoDrawable} A, which {@link GLContext} is intended to be swapped
+ * @param chosenCapsB chosen {@link GLCapabilitiesImmutable} of {@link GLAutoDrawable} B, which {@link GLContext} is intended to be swapped
+ * @see #swapGLContext(GLAutoDrawable, GLAutoDrawable)
+ * @see #swapGLContextAndAllGLEventListener(GLAutoDrawable, GLAutoDrawable)
+ */
+ public static boolean isSwapGLContextSafe(final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesImmutable chosenCapsA, final GLCapabilitiesImmutable chosenCapsB) {
+ final boolean usingAccumulatorBuffer = requestedCaps.getAccumAlphaBits() > 0 ||
+ requestedCaps.getAccumRedBits() > 0 ||
+ requestedCaps.getAccumGreenBits() > 0 ||
+ requestedCaps.getAccumBlueBits() > 0;
+ if( ( chosenCapsA.isOnscreen() && !chosenCapsB.isOnscreen() || !chosenCapsA.isOnscreen() && chosenCapsB.isOnscreen() ) && // switching between on- and offscreen
+ (
+ ( chosenCapsA.getSampleBuffers() || chosenCapsB.getSampleBuffers() ) || // MSAA involved
+ ( chosenCapsA.getStereo() || chosenCapsB.getStereo() ) || // Stereo involved
+ usingAccumulatorBuffer // Using accumulator buffer
+ )
+ )
+ {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ /**
+ * Swaps the {@link GLContext} and all {@link GLEventListener} between {@link GLAutoDrawable} <code>a</code> and <code>b</code>,
+ * while preserving it's initialized state, resets the GL-Viewport and issuing {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)}.
+ * <p>
+ * The {@link GLAutoDrawable} to {@link GLAnimatorControl} association
+ * is also swapped.
+ * </p>
+ * <p>
+ * If an {@link GLAnimatorControl} is being attached to {@link GLAutoDrawable} <code>a</code> or <code>b</code>
+ * and the current thread is different than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
+ * </p>
+ * <p>
+ * During operation, both {@link GLAutoDrawable auto-drawable's}
+ * {@link GLAutoDrawable#getUpstreamLock() upstream-locks} and {@link GLAutoDrawable#getNativeSurface() surfaces} are locked,
+ * hence atomicity of operation is guaranteed,
+ * see <a href="../../../../javax/media/opengl/GLAutoDrawable.html#locking">GLAutoDrawable Locking</a>.
+ * </p>
+ * <p>
+ * Because of above mentioned locking, if this method is not performed
+ * on {@link GLAutoDrawable#isThreadGLCapable() a OpenGL capable thread} of <i>both</i>
+ * {@link GLAutoDrawable}s, it must be invoked on such an OpenGL capable thread,
+ * e.g. via {@link Threading#invokeOnOpenGLThread(boolean, Runnable)}.
+ * </p>
+ * @throws GLException if the {@link AbstractGraphicsDevice} are incompatible w/ each other.
+ * @see #isSwapGLContextSafe(GLCapabilitiesImmutable, GLCapabilitiesImmutable, GLCapabilitiesImmutable)
+ */
+ public static final void swapGLContextAndAllGLEventListener(final GLAutoDrawable a, final GLAutoDrawable b) {
+ final GLEventListenerState gllsA = GLEventListenerState.moveFrom(a, true);
+ final GLEventListenerState gllsB = GLEventListenerState.moveFrom(b, true);
+ final Runnable gllsAUnlockOp = gllsA.getUnlockSurfaceOp();
+ final Runnable gllsBUnlockOp = gllsB.getUnlockSurfaceOp();
+ try {
+ gllsA.moveTo(b, gllsBUnlockOp);
+ gllsB.moveTo(a, gllsAUnlockOp);
+ } finally {
+ // guarantee unlock in case of an exception
+ gllsBUnlockOp.run();
+ gllsAUnlockOp.run();
+ }
+ }
+
+ /**
+ * Swaps the {@link GLContext} of given {@link GLAutoDrawable}
+ * and {@link GLAutoDrawable#disposeGLEventListener(GLEventListener, boolean) disposes}
+ * each {@link GLEventListener} w/o removing it.
+ * <p>
+ * The GL-Viewport is reset and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued implicit.
+ * </p>
+ * <p>
+ * If an {@link GLAnimatorControl} is being attached to GLAutoDrawable src or dest and the current thread is different
+ * than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
+ * </p>
+ * <p>
+ * During operation, both {@link GLAutoDrawable auto-drawable's}
+ * {@link GLAutoDrawable#getUpstreamLock() upstream-locks} and {@link GLAutoDrawable#getNativeSurface() surfaces} are locked,
+ * hence atomicity of operation is guaranteed,
+ * see <a href="../../../../javax/media/opengl/GLAutoDrawable.html#locking">GLAutoDrawable Locking</a>.
+ * </p>
+ * <p>
+ * Because of above mentioned locking, if this method is not performed
+ * on {@link GLAutoDrawable#isThreadGLCapable() a OpenGL capable thread} of <i>both</i>
+ * {@link GLAutoDrawable}s, it must be invoked on such an OpenGL capable thread,
+ * e.g. via {@link Threading#invokeOnOpenGLThread(boolean, Runnable)}.
+ * </p>
+ * @param a
+ * @param b
+ * @see #isSwapGLContextSafe(GLCapabilitiesImmutable, GLCapabilitiesImmutable, GLCapabilitiesImmutable)
+ */
+ public static final void swapGLContext(final GLAutoDrawable a, final GLAutoDrawable b) {
+ final GLAnimatorControl aAnim = a.getAnimator();
+ final GLAnimatorControl bAnim = b.getAnimator();
+ final boolean aIsPaused = isAnimatorAnimatingOnOtherThread(aAnim) && aAnim.pause();
+ final boolean bIsPaused = isAnimatorAnimatingOnOtherThread(bAnim) && bAnim.pause();
+
+ final RecursiveLock aUpstreamLock = a.getUpstreamLock();
+ final RecursiveLock bUpstreamLock = b.getUpstreamLock();
+ aUpstreamLock.lock();
+ bUpstreamLock.lock();
+ try {
+ final NativeSurface aSurface = a.getNativeSurface();
+ final boolean aSurfaceLocked = NativeSurface.LOCK_SURFACE_NOT_READY < aSurface.lockSurface();
+ if( a.isRealized() && !aSurfaceLocked ) {
+ throw new GLException("Could not lock realized a surface "+a);
+ }
+ final NativeSurface bSurface = b.getNativeSurface();
+ final boolean bSurfaceLocked = NativeSurface.LOCK_SURFACE_NOT_READY < bSurface.lockSurface();
+ if( b.isRealized() && !bSurfaceLocked ) {
+ throw new GLException("Could not lock realized b surface "+b);
+ }
+ try {
+ for(int i = a.getGLEventListenerCount() - 1; 0 <= i; i--) {
+ a.disposeGLEventListener(a.getGLEventListener(i), false);
+ }
+ for(int i = b.getGLEventListenerCount() - 1; 0 <= i; i--) {
+ b.disposeGLEventListener(b.getGLEventListener(i), false);
+ }
+ b.setContext( a.setContext( b.getContext(), false ), false );
+
+ } finally {
+ if( bSurfaceLocked ) {
+ bSurface.unlockSurface();
+ }
+ if( aSurfaceLocked ) {
+ aSurface.unlockSurface();
+ }
+ }
+ } finally {
+ bUpstreamLock.unlock();
+ aUpstreamLock.unlock();
+ }
+ a.invoke(true, setViewport);
+ b.invoke(true, setViewport);
+ if(aIsPaused) { aAnim.resume(); }
+ if(bIsPaused) { bAnim.resume(); }
+ }
+
+ private static final GLRunnable setViewport = new GLRunnable() {
+ @Override
+ public boolean run(final GLAutoDrawable drawable) {
+ drawable.getGL().glViewport(0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight());
+ return false; // issue re-display w/ new viewport!
+ }
+ };
+
+ /**
+ * Determines whether the chosen {@link GLCapabilitiesImmutable}
+ * requires a {@link GLDrawable#swapBuffers() swap-buffers}
+ * before reading pixels.
+ * <p>
+ * Usually one uses the {@link GLBase#getDefaultReadBuffer() default-read-buffer}
+ * in which case {@link GLDrawable#swapBuffers() swap-buffers} shall happen <b>after</b> calling reading pixels, the default.
+ * </p>
+ * <p>
+ * However, <i>multisampling</i> offscreen {@link javax.media.opengl.GLFBODrawable}s
+ * utilize {@link GLDrawable#swapBuffers() swap-buffers} to <i>downsample</i>
+ * the multisamples into the readable sampling sink.
+ * In this case, we require {@link GLDrawable#swapBuffers() swap-buffers} <b>before</b> reading pixels.
+ * </p>
+ * @return chosenCaps.isFBO() && chosenCaps.getSampleBuffers()
+ */
+ public static final boolean swapBuffersBeforeRead(final GLCapabilitiesImmutable chosenCaps) {
+ return chosenCaps.isFBO() && chosenCaps.getSampleBuffers();
}
- dest.setContext( src.setContext( dest.getContext(), false ), false );
-
- src.invoke(true, GLEventListenerState.setViewport);
- dest.invoke(true, GLEventListenerState.setViewport);
-
- if(aIsPaused) { aAnim.resume(); }
- if(bIsPaused) { bAnim.resume(); }
- }
-
- /**
- * Determines whether the chosen {@link GLCapabilitiesImmutable}
- * requires a {@link GLDrawable#swapBuffers() swap-buffers}
- * before reading pixels.
- * <p>
- * Usually one uses the {@link GLBase#getDefaultReadBuffer() default-read-buffer}
- * in which case {@link GLDrawable#swapBuffers() swap-buffers} shall happen <b>after</b> calling reading pixels, the default.
- * </p>
- * <p>
- * However, <i>multisampling</i> offscreen {@link javax.media.opengl.GLFBODrawable}s
- * utilize {@link GLDrawable#swapBuffers() swap-buffers} to <i>downsample</i>
- * the multisamples into the readable sampling sink.
- * In this case, we require {@link GLDrawable#swapBuffers() swap-buffers} <b>before</b> reading pixels.
- * </p>
- * @return chosenCaps.isFBO() && chosenCaps.getSampleBuffers()
- */
- public static final boolean swapBuffersBeforeRead(final GLCapabilitiesImmutable chosenCaps) {
- return chosenCaps.isFBO() && chosenCaps.getSampleBuffers();
- }
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLPixelStorageModes.java b/src/jogl/classes/com/jogamp/opengl/util/GLPixelStorageModes.java
index 52612d224..290033e99 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLPixelStorageModes.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLPixelStorageModes.java
@@ -33,6 +33,7 @@ import javax.media.opengl.GL2;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GL2ES3;
import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLContext;
import javax.media.opengl.GLException;
/**
@@ -60,7 +61,7 @@ public class GLPixelStorageModes {
/**
* Sets the {@link GL#GL_PACK_ALIGNMENT}.
* <p>
- * Saves the PACK pixel storage modes if not saved yet, see {@link #savePack(GL)}.
+ * Saves the PACK pixel storage modes and {@link #resetPack(GL) resets} them if not saved yet, see {@link #savePack(GL)}.
* </p>
*/
public final void setPackAlignment(final GL gl, final int packAlignment) {
@@ -71,7 +72,7 @@ public class GLPixelStorageModes {
/**
* Sets the {@link GL#GL_UNPACK_ALIGNMENT}.
* <p>
- * Saves the UNPACK pixel storage modes if not saved yet, see {@link #saveUnpack(GL)}.
+ * Saves the UNPACK pixel storage modes and {@link #resetUnpack(GL) resets} them if not saved yet, see {@link #saveUnpack(GL)}.
* </p>
*/
public final void setUnpackAlignment(final GL gl, final int unpackAlignment) {
@@ -82,7 +83,7 @@ public class GLPixelStorageModes {
/**
* Sets the {@link GL#GL_PACK_ALIGNMENT} and {@link GL#GL_UNPACK_ALIGNMENT}.
* <p>
- * Saves the PACK and UNPACK pixel storage modes if not saved yet, see {@link #saveAll(GL)}.
+ * Saves the PACK and UNPACK pixel storage modes and resets them if not saved yet, see {@link #saveAll(GL)}.
* </p>
*/
public final void setAlignment(final GL gl, final int packAlignment, final int unpackAlignment) {
@@ -93,7 +94,7 @@ public class GLPixelStorageModes {
/**
* Sets the {@link GL2ES3#GL_PACK_ROW_LENGTH}.
* <p>
- * Saves the PACK pixel storage modes if not saved yet, see {@link #savePack(GL)}.
+ * Saves the PACK pixel storage modes and {@link #resetPack(GL) resets} them if not saved yet, see {@link #savePack(GL)}.
* </p>
*/
public final void setPackRowLength(final GL2ES3 gl, final int packRowLength) {
@@ -104,18 +105,18 @@ public class GLPixelStorageModes {
/**
* Sets the {@link GL2ES2#GL_UNPACK_ROW_LENGTH}.
* <p>
- * Saves the UNPACK pixel storage modes if not saved yet, see {@link #saveUnpack(GL)}.
+ * Saves the UNPACK pixel storage modes and {@link #resetUnpack(GL) resets} them if not saved yet, see {@link #saveUnpack(GL)}.
* </p>
*/
- public final void setUnpackRowLength(final GL2ES2 gl, final int unpackRowLength) {
+ public final void setUnpackRowLength(final GL2ES3 gl, final int unpackRowLength) {
saveUnpack(gl);
gl.glPixelStorei(GL2ES2.GL_UNPACK_ROW_LENGTH, unpackRowLength);
}
/**
- * Sets the {@link GL2ES3#GL_PACK_ROW_LENGTH} and {@link GL2ES2#GL_UNPACK_ROW_LENGTH}.
+ * Sets the {@link GL2ES3#GL_PACK_ROW_LENGTH} and {@link GL2ES2#GL_UNPACK_ROW_LENGTH} if {@link GL#isGL2ES3()}.
* <p>
- * Saves the PACK and UNPACK pixel storage modes if not saved yet, see {@link #saveAll(GL)}.
+ * Saves the PACK and UNPACK pixel storage modes and resets them if not saved yet, see {@link #saveAll(GL)}.
* </p>
*/
public final void setRowLength(final GL2ES3 gl, final int packRowLength, final int unpackRowLength) {
@@ -171,7 +172,7 @@ public class GLPixelStorageModes {
*/
public final void resetPack(final GL gl) {
// Compared w/ ES2, ES3 and GL3-core spec
- gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 4); // es2, es3, gl3
+ gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 4); // es2, es3, gl3
if( gl.isGL2ES3() ) {
gl.glPixelStorei(GL2ES3.GL_PACK_ROW_LENGTH, 0); // es3, gl3
gl.glPixelStorei(GL2ES3.GL_PACK_SKIP_ROWS, 0); // es3, gl3
@@ -179,8 +180,10 @@ public class GLPixelStorageModes {
if( gl.isGL2GL3() ) {
gl.glPixelStorei(GL2GL3.GL_PACK_SWAP_BYTES, GL.GL_FALSE); // gl3
gl.glPixelStorei(GL2GL3.GL_PACK_LSB_FIRST, GL.GL_FALSE); // gl3
- gl.glPixelStorei(GL2GL3.GL_PACK_IMAGE_HEIGHT, 0); // gl3
- gl.glPixelStorei(GL2GL3.GL_PACK_SKIP_IMAGES, 0); // gl3
+ if( gl.getContext().getGLVersionNumber().compareTo(GLContext.Version120) >= 0 ) {
+ gl.glPixelStorei(GL2GL3.GL_PACK_IMAGE_HEIGHT, 0); // gl3, GL_VERSION_1_2
+ gl.glPixelStorei(GL2GL3.GL_PACK_SKIP_IMAGES, 0); // gl3, GL_VERSION_1_2
+ }
}
}
}
@@ -242,16 +245,21 @@ public class GLPixelStorageModes {
*/
public final void resetUnpack(final GL gl) {
// Compared w/ ES2, ES3 and GL3-core spec
- gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 4); // es2, es3, gl3
+ gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 4); // es2, es3, gl3
if( gl.isGL2ES3() ) {
gl.glPixelStorei(GL2ES2.GL_UNPACK_ROW_LENGTH, 0); // es3, gl3
gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_ROWS, 0); // es3, gl3
gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_PIXELS, 0); // es3, gl3
- gl.glPixelStorei(GL2ES3.GL_UNPACK_IMAGE_HEIGHT, 0); // es3, gl3
- gl.glPixelStorei(GL2ES3.GL_UNPACK_SKIP_IMAGES, 0); // es3, gl3
if( gl.isGL2GL3() ) {
+ if( gl.getContext().getGLVersionNumber().compareTo(GLContext.Version120) >= 0 ) {
+ gl.glPixelStorei(GL2ES3.GL_UNPACK_IMAGE_HEIGHT, 0); // es3, gl3, GL_VERSION_1_2
+ gl.glPixelStorei(GL2ES3.GL_UNPACK_SKIP_IMAGES, 0); // es3, gl3, GL_VERSION_1_2
+ }
gl.glPixelStorei(GL2GL3.GL_UNPACK_SWAP_BYTES, GL.GL_FALSE); // gl3
gl.glPixelStorei(GL2GL3.GL_UNPACK_LSB_FIRST, GL.GL_FALSE); // gl3
+ } else {
+ gl.glPixelStorei(GL2ES3.GL_UNPACK_IMAGE_HEIGHT, 0); // es3, gl3, GL_VERSION_1_2
+ gl.glPixelStorei(GL2ES3.GL_UNPACK_SKIP_IMAGES, 0); // es3, gl3, GL_VERSION_1_2
}
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java b/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java
index abdb7c5f9..e84a1d874 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java
@@ -223,7 +223,7 @@ public class GLReadBufferUtil {
psm.setPackAlignment(gl, alignment);
if(gl.isGL2ES3()) {
final GL2ES3 gl2es3 = gl.getGL2ES3();
- gl2es3.glPixelStorei(GL2ES3.GL_PACK_ROW_LENGTH, width);
+ psm.setPackRowLength(gl2es3, width);
gl2es3.glReadBuffer(gl2es3.getDefaultReadBuffer());
}
readPixelBuffer.clear();
diff --git a/src/jogl/classes/com/jogamp/opengl/util/Gamma.java b/src/jogl/classes/com/jogamp/opengl/util/Gamma.java
index 4e44c997a..bab85e531 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/Gamma.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/Gamma.java
@@ -39,69 +39,79 @@
package com.jogamp.opengl.util;
-import javax.media.opengl.*;
-import jogamp.opengl.*;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLDrawableFactory;
-/** Provides control over the primary display's gamma, brightness and
- contrast controls via the hardware gamma ramp tables. Not
- supported on all platforms or graphics hardware. <P>
-
- Thanks to the LWJGL project for illustrating how to access gamma
- control on the various platforms.
-*/
+import com.jogamp.common.util.locks.RecursiveLock;
+/**
+ * Provides convenient wrapper for {@link GLDrawableFactory} control over
+ * individual display's gamma, brightness and contrast values
+ * via the hardware gamma ramp tables.
+ * <p>
+ * Not supported on all platforms or graphics hardware.
+ * </p>
+ * <p>
+ * Thanks to the LWJGL project for illustrating how to access gamma
+ * control on the various platforms.
+ * </p>
+ */
public class Gamma {
private Gamma() {}
/**
- * Sets the gamma, brightness, and contrast of the current main
- * display. 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>
- *
- * 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 resetDisplayGamma}(). It is recommended to
- * call {@link #resetDisplayGamma resetDisplayGamma} 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>
- *
- * This method may be called multiple times during the application's
- * execution, but calling {@link #resetDisplayGamma
- * resetDisplayGamma} will only reset the settings to the values
- * before the first call to this method. <P>
- *
- * @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
+ * Convenient wrapper for {@link GLDrawableFactory#setDisplayGamma(javax.media.nativewindow.NativeSurface, float, float, float)}.
+ * <p>
+ * Use {@link #setDisplayGamma(GLAutoDrawable, float, float, float)} in case of using an {#link GLAutoDrawable}.
+ * </p>
+ */
+ public static boolean setDisplayGamma(final GLDrawable drawable, final float gamma, final float brightness, final float contrast) throws IllegalArgumentException {
+ return GLDrawableFactory.getFactory(drawable.getGLProfile()).setDisplayGamma(drawable.getNativeSurface(), gamma, brightness, contrast);
+ }
+
+ /**
+ * Convenient wrapper for {@link GLDrawableFactory#setDisplayGamma(javax.media.nativewindow.NativeSurface, float, float, float)}
+ * locking {@link GLAutoDrawable#getUpstreamLock()} to ensure proper atomic operation.
+ */
+ public static boolean setDisplayGamma(final GLAutoDrawable drawable, final float gamma, final float brightness, final float contrast) throws IllegalArgumentException {
+ final RecursiveLock lock = drawable.getUpstreamLock();
+ lock.lock();
+ try {
+ return GLDrawableFactory.getFactory(drawable.getGLProfile()).setDisplayGamma(drawable.getNativeSurface(), gamma, brightness, contrast);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Convenient wrapper for {@link GLDrawableFactory#resetDisplayGamma(javax.media.nativewindow.NativeSurface)}.
+ * <p>
+ * Use {@link #resetDisplayGamma(GLAutoDrawable)} in case of using an {#link GLAutoDrawable}.
+ * </p>
+ */
+ public static void resetDisplayGamma(final GLDrawable drawable) {
+ GLDrawableFactory.getFactory(drawable.getGLProfile()).resetDisplayGamma(drawable.getNativeSurface());
+ }
+
+ /**
+ * Convenient wrapper for {@link GLDrawableFactory#resetDisplayGamma(javax.media.nativewindow.NativeSurface)}
+ * locking {@link GLAutoDrawable#getUpstreamLock()} to ensure proper atomic operation.
*/
- public static boolean setDisplayGamma(final GL gl, final float gamma, final float brightness, final float contrast) throws IllegalArgumentException {
- return GLDrawableFactoryImpl.getFactoryImpl(gl.getContext().getGLDrawable().getGLProfile()).setDisplayGamma(gamma, brightness, contrast);
+ public static void resetDisplayGamma(final GLAutoDrawable drawable) {
+ final RecursiveLock lock = drawable.getUpstreamLock();
+ lock.lock();
+ try {
+ GLDrawableFactory.getFactory(drawable.getGLProfile()).resetDisplayGamma(drawable.getNativeSurface());
+ } finally {
+ lock.unlock();
+ }
}
/**
- * Resets the gamma, brightness and contrast values for the primary
- * display to their original values before {@link #setDisplayGamma
- * setDisplayGamma} was called the first time. {@link
- * #setDisplayGamma setDisplayGamma} must be called before calling
- * this method or an unspecified exception will be thrown. While it
- * is not explicitly required that this method be called before
- * exiting, calling it is recommended because of the inevitable
- * unspecified behavior during JVM teardown.
+ * Convenient wrapper for {@link GLDrawableFactory#resetAllDisplayGamma()}.
*/
- public static void resetDisplayGamma(final GL gl) {
- GLDrawableFactoryImpl.getFactoryImpl(gl.getContext().getGLDrawable().getGLProfile()).resetDisplayGamma();
+ public static void resetAllDisplayGamma(final GLDrawable drawable) {
+ GLDrawableFactory.getFactory(drawable.getGLProfile()).resetAllDisplayGamma();
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
index 4fffd9fab..2ad102235 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
@@ -27,14 +27,13 @@
*/
package com.jogamp.opengl.util.av;
-import java.net.URI;
-
import javax.media.opengl.GL;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLException;
import jogamp.opengl.Debug;
+import com.jogamp.common.net.Uri;
import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureSequence;
import com.jogamp.opengl.util.TimeFrameI;
@@ -46,18 +45,18 @@ import com.jogamp.opengl.util.TimeFrameI;
* Audio maybe supported and played back internally or via an {@link AudioSink} implementation.
* </p>
* <p>
- * Audio and video streams can be selected or muted via {@link #initStream(URI, int, int, int)}
+ * Audio and video streams can be selected or muted via {@link #initStream(Uri, int, int, int)}
* using the appropriate <a href="#streamIDs">stream id</a>'s.
* </p>
* <p>
- * Camera input can be selected using the {@link #CameraInputScheme} URI.
+ * Camera input can be selected using the {@link #CameraInputScheme} Uri.
* </p>
*
* <a name="streamworker"><h5><i>StreamWorker</i> Decoding Thread</h5></a>
* <p>
* Most of the stream processing is performed on the decoding thread, a.k.a. <i>StreamWorker</i>:
* <ul>
- * <li>Stream initialization triggered by {@link #initStream(URI, int, int, int) initStream(..)} - User gets notified whether the stream has been initialized or not via {@link GLMediaEventListener#attributesChanged(GLMediaPlayer, int, long) attributesChanges(..)}.</li>
+ * <li>Stream initialization triggered by {@link #initStream(Uri, int, int, int) initStream(..)} - User gets notified whether the stream has been initialized or not via {@link GLMediaEventListener#attributesChanged(GLMediaPlayer, int, long) attributesChanges(..)}.</li>
* <li>Stream decoding - User gets notified of a new frame via {@link GLMediaEventListener#newFrameAvailable(GLMediaPlayer, com.jogamp.opengl.util.texture.TextureSequence.TextureFrame, long) newFrameAvailable(...)}.</li>
* <li>Caught <a href="#streamerror">exceptions on the decoding thread</a> are delivered as {@link StreamException}s.</li>
* </ul>
@@ -83,7 +82,7 @@ import com.jogamp.opengl.util.TimeFrameI;
* <p>
* <table border="1">
* <tr><th>Action</th> <th>{@link State} Before</th> <th>{@link State} After</th> <th>{@link GLMediaEventListener Event}</th></tr>
- * <tr><td>{@link #initStream(URI, int, int, int)}</td> <td>{@link State#Uninitialized Uninitialized}</td> <td>{@link State#Initialized Initialized}<sup><a href="#streamworker">1</a></sup>, {@link State#Uninitialized Uninitialized}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_INIT EVENT_CHANGE_INIT} or ( {@link GLMediaEventListener#EVENT_CHANGE_ERR EVENT_CHANGE_ERR} + {@link GLMediaEventListener#EVENT_CHANGE_UNINIT EVENT_CHANGE_UNINIT} )</td></tr>
+ * <tr><td>{@link #initStream(Uri, int, int, int)}</td> <td>{@link State#Uninitialized Uninitialized}</td> <td>{@link State#Initialized Initialized}<sup><a href="#streamworker">1</a></sup>, {@link State#Uninitialized Uninitialized}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_INIT EVENT_CHANGE_INIT} or ( {@link GLMediaEventListener#EVENT_CHANGE_ERR EVENT_CHANGE_ERR} + {@link GLMediaEventListener#EVENT_CHANGE_UNINIT EVENT_CHANGE_UNINIT} )</td></tr>
* <tr><td>{@link #initGL(GL)}</td> <td>{@link State#Initialized Initialized}</td> <td>{@link State#Paused Paused}, , {@link State#Uninitialized Uninitialized}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_PAUSE EVENT_CHANGE_PAUSE} or ( {@link GLMediaEventListener#EVENT_CHANGE_ERR EVENT_CHANGE_ERR} + {@link GLMediaEventListener#EVENT_CHANGE_UNINIT EVENT_CHANGE_UNINIT} )</td></tr>
* <tr><td>{@link #play()}</td> <td>{@link State#Paused Paused}</td> <td>{@link State#Playing Playing}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_PLAY EVENT_CHANGE_PLAY}</td></tr>
* <tr><td>{@link #pause(boolean)}</td> <td>{@link State#Playing Playing}</td> <td>{@link State#Paused Paused}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_PAUSE EVENT_CHANGE_PAUSE}</td></tr>
@@ -183,6 +182,9 @@ import com.jogamp.opengl.util.TimeFrameI;
* <!-- <tr><td> title </td><td colspan=3> url1 </td><td> url2 </td></tr>
* </table>
* </p>
+ * <p>
+ * Since 2.3.0 this interface uses {@link Uri} instead of {@link java.net.URI}.
+ * </p>
*/
public interface GLMediaPlayer extends TextureSequence {
public static final boolean DEBUG = Debug.debug("GLMediaPlayer");
@@ -200,10 +202,10 @@ public interface GLMediaPlayer extends TextureSequence {
public static final int STREAM_ID_AUTO = -1;
/**
- * {@link URI#getScheme() URI scheme} name {@value} for camera input. E.g. <code>camera:/0</code>
+ * {@link Uri#scheme Uri scheme} name {@value} for camera input. E.g. <code>camera:/0</code>
* for the 1st camera device.
* <p>
- * The {@link URI#getRawPath() URI path} is being used to identify the camera (<i>ID</i>),
+ * The {@link Uri#path Uri path} is being used to identify the camera (<i>ID</i>),
* where the root fwd-slash is being cut-off.
* </p>
* <p>
@@ -211,7 +213,7 @@ public interface GLMediaPlayer extends TextureSequence {
* ranging from [0..<i>max-number</i>].
* </p>
* <p>
- * The {@link URI#getRawQuery() URI query} is used to pass options to the camera
+ * The {@link Uri#query Uri query} is used to pass options to the camera
* using <i>;</i> as the separator. The latter avoids trouble w/ escaping.
* </p>
* <pre>
@@ -221,13 +223,13 @@ public interface GLMediaPlayer extends TextureSequence {
* camera://somewhere/<id>?size=640x480;rate=15
* </pre>
* <pre>
- * URI: [scheme:][//authority][path][?query][#fragment]
+ * Uri: [scheme:][//authority][path][?query][#fragment]
* w/ authority: [user-info@]host[:port]
* Note: 'path' starts w/ fwd slash
* </pre>
* </p>
*/
- public static final String CameraInputScheme = "camera";
+ public static final Uri.Encoded CameraInputScheme = Uri.Encoded.cast("camera");
/** Camera property {@value}, size as string, e.g. <code>1280x720</code>, <code>hd720</code>. May not be supported on all platforms. See {@link #CameraInputScheme}. */
public static final String CameraPropSizeS = "size";
/** Camera property {@value}. See {@link #CameraInputScheme}. */
@@ -361,8 +363,9 @@ public interface GLMediaPlayer extends TextureSequence {
* Ignored if video is muted.
* @throws IllegalStateException if not invoked in {@link State#Uninitialized}
* @throws IllegalArgumentException if arguments are invalid
+ * @since 2.3.0
*/
- public void initStream(URI streamLoc, int vid, int aid, int textureCount) throws IllegalStateException, IllegalArgumentException;
+ public void initStream(Uri streamLoc, int vid, int aid, int textureCount) throws IllegalStateException, IllegalArgumentException;
/**
* Returns the {@link StreamException} caught in the decoder thread, or <code>null</code> if none occured.
@@ -379,7 +382,7 @@ public interface GLMediaPlayer extends TextureSequence {
* <p>
* <a href="#lifecycle">Lifecycle</a>: {@link State#Initialized} -> {@link State#Paused} or {@link State#Initialized}
* </p>
- * Argument <code>gl</code> is ignored if video is muted, see {@link #initStream(URI, int, int, int)}.
+ * Argument <code>gl</code> is ignored if video is muted, see {@link #initStream(Uri, int, int, int)}.
*
* @param gl current GL object. Maybe <code>null</code>, for audio only.
* @throws IllegalStateException if not invoked in {@link State#Initialized}.
@@ -391,7 +394,7 @@ public interface GLMediaPlayer extends TextureSequence {
/**
* If implementation uses a {@link AudioSink}, it's instance will be returned.
* <p>
- * The {@link AudioSink} instance is available after {@link #initStream(URI, int, int, int)},
+ * The {@link AudioSink} instance is available after {@link #initStream(Uri, int, int, int)},
* if used by implementation.
* </p>
*/
@@ -536,8 +539,11 @@ public interface GLMediaPlayer extends TextureSequence {
@Override
public TextureSequence.TextureFrame getNextTexture(GL gl) throws IllegalStateException;
- /** Return the stream location, as set by {@link #initStream(URI, int, int, int)}. */
- public URI getURI();
+ /**
+ * Return the stream location, as set by {@link #initStream(Uri, int, int, int)}.
+ * @since 2.3.0
+ */
+ public Uri getUri();
/**
* <i>Warning:</i> Optional information, may not be supported by implementation.
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java
index 29dce40f5..8eed35ebb 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java
@@ -35,6 +35,7 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.StringReader;
+import java.net.URISyntaxException;
import java.net.URLConnection;
import java.nio.Buffer;
import java.nio.ByteBuffer;
@@ -46,12 +47,14 @@ import java.util.Set;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GL3;
+import javax.media.opengl.GL4;
import javax.media.opengl.GLES2;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLException;
import jogamp.opengl.Debug;
+import com.jogamp.common.net.Uri;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.util.IOUtil;
import com.jogamp.common.util.VersionNumber;
@@ -63,33 +66,62 @@ import com.jogamp.common.util.VersionNumber;
* {@link #create(GL2ES2, int, Class, String, String, String, boolean) here} and
* {@link #create(GL2ES2, int, int, Class, String, String[], String, String) here}.
* </p>
+ * <p>
+ * Support for {@link GL4#GL_TESS_CONTROL_SHADER} and {@link GL4#GL_TESS_EVALUATION_SHADER}
+ * was added since 2.2.1.
+ * </p>
*/
public class ShaderCode {
public static final boolean DEBUG_CODE = Debug.isPropertyDefined("jogl.debug.GLSLCode", true);
- /** Unique resource suffix for {@link GL2ES2#GL_VERTEX_SHADER} in source code: <code>vp</code> */
+ /** Unique resource suffix for {@link GL2ES2#GL_VERTEX_SHADER} in source code: <code>{@value}</code> */
public static final String SUFFIX_VERTEX_SOURCE = "vp" ;
- /** Unique resource suffix for {@link GL2ES2#GL_VERTEX_SHADER} in binary: <code>bvp</code> */
+ /** Unique resource suffix for {@link GL2ES2#GL_VERTEX_SHADER} in binary: <code>{@value}</code> */
public static final String SUFFIX_VERTEX_BINARY = "bvp" ;
- /** Unique resource suffix for {@link GL3#GL_GEOMETRY_SHADER} in source code: <code>gp</code> */
+ /** Unique resource suffix for {@link GL3#GL_GEOMETRY_SHADER} in source code: <code>{@value}</code> */
public static final String SUFFIX_GEOMETRY_SOURCE = "gp" ;
- /** Unique resource suffix for {@link GL3#GL_GEOMETRY_SHADER} in binary: <code>bgp</code> */
+ /** Unique resource suffix for {@link GL3#GL_GEOMETRY_SHADER} in binary: <code>{@value}</code> */
public static final String SUFFIX_GEOMETRY_BINARY = "bgp" ;
- /** Unique resource suffix for {@link GL2ES2#GL_FRAGMENT_SHADER} in source code: <code>fp</code> */
+ /**
+ * Unique resource suffix for {@link GL4#GL_TESS_CONTROL_SHADER} in source code: <code>{@value}</code>
+ * @since 2.2.1
+ */
+ public static final String SUFFIX_TESS_CONTROL_SOURCE = "tcp" ;
+
+ /**
+ * Unique resource suffix for {@link GL4#GL_TESS_CONTROL_SHADER} in binary: <code>{@value}</code>
+ * @since 2.2.1
+ */
+ public static final String SUFFIX_TESS_CONTROL_BINARY = "btcp" ;
+
+ /**
+ * Unique resource suffix for {@link GL4#GL_TESS_EVALUATION_SHADER} in source code: <code>{@value}</code>
+ * @since 2.2.1
+ */
+ public static final String SUFFIX_TESS_EVALUATION_SOURCE = "tep" ;
+
+ /**
+ * Unique resource suffix for {@link GL4#GL_TESS_EVALUATION_SHADER} in binary: <code>{@value}</code>
+ * @since 2.2.1
+ */
+ public static final String SUFFIX_TESS_EVALUATION_BINARY = "btep" ;
+
+ /** Unique resource suffix for {@link GL2ES2#GL_FRAGMENT_SHADER} in source code: <code>{@value}</code> */
public static final String SUFFIX_FRAGMENT_SOURCE = "fp" ;
- /** Unique resource suffix for {@link GL2ES2#GL_FRAGMENT_SHADER} in binary: <code>bfp</code> */
+ /** Unique resource suffix for {@link GL2ES2#GL_FRAGMENT_SHADER} in binary: <code>{@value}</code> */
public static final String SUFFIX_FRAGMENT_BINARY = "bfp" ;
- /** Unique relative path for binary shader resources for {@link GLES2#GL_NVIDIA_PLATFORM_BINARY_NV NVIDIA}: <code>nvidia</code> */
+ /** Unique relative path for binary shader resources for {@link GLES2#GL_NVIDIA_PLATFORM_BINARY_NV NVIDIA}: <code>{@value}</code> */
public static final String SUB_PATH_NVIDIA = "nvidia" ;
/**
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
+ * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}.
* @param count number of shaders
* @param source CharSequence array containing the shader sources, organized as <code>source[count][strings-per-shader]</code>.
* May be either an immutable <code>String</code> - or mutable <code>StringBuilder</code> array.
@@ -104,6 +136,8 @@ public class ShaderCode {
case GL2ES2.GL_VERTEX_SHADER:
case GL2ES2.GL_FRAGMENT_SHADER:
case GL3.GL_GEOMETRY_SHADER:
+ case GL4.GL_TESS_CONTROL_SHADER:
+ case GL4.GL_TESS_EVALUATION_SHADER:
break;
default:
throw new GLException("Unknown shader type: "+type);
@@ -122,7 +156,8 @@ public class ShaderCode {
}
/**
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
+ * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}.
* @param count number of shaders
* @param binary binary buffer containing the shader binaries,
*/
@@ -131,6 +166,8 @@ public class ShaderCode {
case GL2ES2.GL_VERTEX_SHADER:
case GL2ES2.GL_FRAGMENT_SHADER:
case GL3.GL_GEOMETRY_SHADER:
+ case GL4.GL_TESS_CONTROL_SHADER:
+ case GL4.GL_TESS_EVALUATION_SHADER:
break;
default:
throw new GLException("Unknown shader type: "+type);
@@ -148,7 +185,8 @@ public class ShaderCode {
* which location is resolved using the <code>context</code> class, see {@link #readShaderSource(Class, String)}.
*
* @param gl current GL object to determine whether a shader compiler is available. If null, no validation is performed.
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
+ * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}.
* @param count number of shaders
* @param context class used to help resolving the source location
* @param sourceFiles array of source locations, organized as <code>sourceFiles[count]</code>
@@ -192,7 +230,8 @@ public class ShaderCode {
* Creates a complete {@link ShaderCode} object while reading the shader binary of <code>binaryFile</code>,
* which location is resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}.
*
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
+ * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}.
* @param count number of shaders
* @param context class used to help resolving the source location
* @param binFormat a valid native binary format as they can be queried by {@link ShaderUtil#getShaderBinaryFormats(GL)}.
@@ -225,14 +264,21 @@ public class ShaderCode {
* <li>Source<ul>
* <li>{@link GL2ES2#GL_VERTEX_SHADER vertex}: {@link #SUFFIX_VERTEX_SOURCE}</li>
* <li>{@link GL2ES2#GL_FRAGMENT_SHADER fragment}: {@link #SUFFIX_FRAGMENT_SOURCE}</li>
- * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_SOURCE}</li></ul></li>
+ * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_SOURCE}</li>
+ * <li>{@link GL4#GL_TESS_CONTROL_SHADER tess-ctrl}: {@link #SUFFIX_TESS_CONTROL_SOURCE}</li>
+ * <li>{@link GL4#GL_TESS_EVALUATION_SHADER tess-eval}: {@link #SUFFIX_TESS_EVALUATION_SOURCE}</li>
+ * </ul></li>
* <li>Binary<ul>
* <li>{@link GL2ES2#GL_VERTEX_SHADER vertex}: {@link #SUFFIX_VERTEX_BINARY}</li>
* <li>{@link GL2ES2#GL_FRAGMENT_SHADER fragment}: {@link #SUFFIX_FRAGMENT_BINARY}</li>
- * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_BINARY}</li></ul></li>
+ * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_BINARY}</li>
+ * <li>{@link GL4#GL_TESS_CONTROL_SHADER tess-ctrl}: {@link #SUFFIX_TESS_CONTROL_BINARY}</li>
+ * <li>{@link GL4#GL_TESS_EVALUATION_SHADER tess-eval}: {@link #SUFFIX_TESS_EVALUATION_BINARY}</li>
+ * </ul></li>
* </ul>
* @param binary true for a binary resource, false for a source resource
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
+ * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}.
*
* @throws GLException if <code>type</code> is not supported
*
@@ -246,6 +292,10 @@ public class ShaderCode {
return binary?SUFFIX_FRAGMENT_BINARY:SUFFIX_FRAGMENT_SOURCE;
case GL3.GL_GEOMETRY_SHADER:
return binary?SUFFIX_GEOMETRY_BINARY:SUFFIX_GEOMETRY_SOURCE;
+ case GL4.GL_TESS_CONTROL_SHADER:
+ return binary?SUFFIX_TESS_CONTROL_BINARY:SUFFIX_TESS_CONTROL_SOURCE;
+ case GL4.GL_TESS_EVALUATION_SHADER:
+ return binary?SUFFIX_TESS_EVALUATION_BINARY:SUFFIX_TESS_EVALUATION_SOURCE;
default:
throw new GLException("illegal shader type: "+type);
}
@@ -324,7 +374,8 @@ public class ShaderCode {
*
* @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
* or to determine the shader binary format (if <code>binary</code> is used).
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
+ * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}.
* @param count number of shaders
* @param context class used to help resolving the source and binary location
* @param srcRoot relative <i>root</i> path for <code>srcBasenames</code> optional
@@ -430,7 +481,8 @@ public class ShaderCode {
*
* @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
* or to determine the shader binary format (if <code>binary</code> is used).
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
+ * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}.
* @param context class used to help resolving the source and binary location
* @param srcRoot relative <i>root</i> path for <code>basename</code> optional
* @param binRoot relative <i>root</i> path for <code>basename</code>
@@ -468,6 +520,10 @@ public class ShaderCode {
return "FRAGMENT_SHADER";
case GL3.GL_GEOMETRY_SHADER:
return "GEOMETRY_SHADER";
+ case GL4.GL_TESS_CONTROL_SHADER:
+ return "TESS_CONTROL_SHADER";
+ case GL4.GL_TESS_EVALUATION_SHADER:
+ return "TESS_EVALUATION_SHADER";
}
return "UNKNOWN_SHADER";
}
@@ -778,7 +834,8 @@ public class ShaderCode {
URLConnection nextConn = null;
// Try relative of current shader location
- nextConn = IOUtil.openURL(IOUtil.getRelativeOf(conn.getURL(), includeFile), "ShaderCode.relativeOf ");
+ final Uri relUri = Uri.valueOf( conn.getURL() ).getRelativeOf(new Uri.Encoded( includeFile, Uri.PATH_LEGAL ));
+ nextConn = IOUtil.openURL(relUri.toURL(), "ShaderCode.relativeOf ");
if (nextConn == null) {
// Try relative of class and absolute
nextConn = IOUtil.getResource(context, includeFile);
@@ -792,6 +849,8 @@ public class ShaderCode {
result.append(line + "\n");
}
}
+ } catch (final URISyntaxException e) {
+ throw new IOException(e);
} finally {
IOUtil.close(reader, false);
}
@@ -874,8 +933,12 @@ public class ShaderCode {
/** Default precision of {@link GL#isGLES3() ES3} for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader}: {@value #es3_default_precision_vp} */
public static final String es3_default_precision_vp = es2_default_precision_vp;
- /** Default precision of {@link GL#isGLES3() ES3} for {@link GL2ES2#GL_FRAGMENT_SHADER fragment-shader}: {@value #es3_default_precision_fp} */
- public static final String es3_default_precision_fp = es2_default_precision_fp;
+ /**
+ * Default precision of {@link GL#isGLES3() ES3} for {@link GL2ES2#GL_FRAGMENT_SHADER fragment-shader}: {@value #es3_default_precision_fp},
+ * same as for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader}, i.e {@link #es3_default_precision_vp},
+ * due to ES 3.x requirements of using same precision for uniforms!
+ */
+ public static final String es3_default_precision_fp = es3_default_precision_vp;
/** Default precision of GLSL &ge; 1.30 as required until &lt; 1.50 for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader} or {@link GL3#GL_GEOMETRY_SHADER geometry-shader}: {@value #gl3_default_precision_vp_gp}. See GLSL Spec 1.30-1.50 Section 4.5.3. */
public static final String gl3_default_precision_vp_gp = "\nprecision highp float;\nprecision highp int;\n";
@@ -956,6 +1019,8 @@ public class ShaderCode {
switch ( shaderType ) {
case GL2ES2.GL_VERTEX_SHADER:
case GL3.GL_GEOMETRY_SHADER:
+ case GL4.GL_TESS_CONTROL_SHADER:
+ case GL4.GL_TESS_EVALUATION_SHADER:
defaultPrecision = gl3_default_precision_vp_gp; break;
case GL2ES2.GL_FRAGMENT_SHADER:
defaultPrecision = gl3_default_precision_fp; break;
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java
index f113be2b2..1d629131e 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java
@@ -109,8 +109,7 @@ public abstract class CompileShader {
tmpFile.getAbsolutePath(),
outputFile.getAbsolutePath()
}); // , null, processorDir);
- new StreamMonitor(process.getInputStream());
- new StreamMonitor(process.getErrorStream());
+ new IOUtil.StreamMonitor( new InputStream[] { process.getInputStream(), process.getErrorStream() }, System.out, null );
process.waitFor();
// Delete the temporary file
// tmpFile.delete();
@@ -153,35 +152,4 @@ public abstract class CompileShader {
e.printStackTrace();
}
}
-
- private static class StreamMonitor implements Runnable {
- private final InputStream istream;
- public StreamMonitor(final InputStream stream) {
- istream = stream;
- new Thread(this, "Output Reader Thread").start();
- }
-
- @Override
- public void run()
- {
- final byte[] buffer = new byte[4096];
- try {
- int numRead = 0;
- do {
- numRead = istream.read(buffer);
- if (numRead > 0) {
- System.out.write(buffer, 0, numRead);
- System.out.flush();
- }
- } while (numRead >= 0);
- }
- catch (final IOException e) {
- try {
- istream.close();
- } catch (final IOException e2) {
- }
- // Should allow clean exit when process shuts down
- }
- }
- }
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java
index 0801b65fa..f70ebf928 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java
@@ -87,8 +87,7 @@ public class StereoClientRenderer implements GLEventListener {
private void initFBOs(final GL gl, final DimensionImmutable size) {
for(int i=0; i<fbos.length; i++) {
- fbos[i].detachAllColorbuffer(gl);
- fbos[i].reset(gl, size.getWidth(), size.getHeight(), numSamples, false);
+ fbos[i].init(gl, size.getWidth(), size.getHeight(), numSamples);
if( i>0 && fbos[i-1].getNumSamples() != fbos[i].getNumSamples()) {
throw new InternalError("sample size mismatch: \n\t0: "+fbos[i-1]+"\n\t1: "+fbos[i]);
}
@@ -96,19 +95,19 @@ public class StereoClientRenderer implements GLEventListener {
if(numSamples>0) {
fbos[i].attachColorbuffer(gl, 0, true); // MSAA requires alpha
- fbos[i].attachRenderbuffer(gl, Type.DEPTH, 24);
+ fbos[i].attachRenderbuffer(gl, Type.DEPTH, FBObject.DEFAULT_BITS);
final FBObject ssink = new FBObject();
{
- ssink.reset(gl, size.getWidth(), size.getHeight());
+ ssink.init(gl, size.getWidth(), size.getHeight(), 0);
ssink.attachTexture2D(gl, 0, false, magFilter, minFilter, GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE);
- ssink.attachRenderbuffer(gl, Attachment.Type.DEPTH, 24);
+ ssink.attachRenderbuffer(gl, Attachment.Type.DEPTH, FBObject.DEFAULT_BITS);
}
fbos[i].setSamplingSink(ssink);
fbos[i].resetSamplingSink(gl); // validate
- fboTexs[i] = fbos[i].getSamplingSink();
+ fboTexs[i] = fbos[i].getSamplingSink().getTextureAttachment();
} else {
fboTexs[i] = fbos[i].attachTexture2D(gl, 0, false, magFilter, minFilter, GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE);
- fbos[i].attachRenderbuffer(gl, Type.DEPTH, 24);
+ fbos[i].attachRenderbuffer(gl, Type.DEPTH, FBObject.DEFAULT_BITS);
}
fbos[i].unbind(gl);
System.err.println("FBO["+i+"]: "+fbos[i]);
@@ -119,15 +118,15 @@ public class StereoClientRenderer implements GLEventListener {
@SuppressWarnings("unused")
private void resetFBOs(final GL gl, final DimensionImmutable size) {
for(int i=0; i<fbos.length; i++) {
- fbos[i].reset(gl, size.getWidth(), size.getHeight(), numSamples, true);
+ fbos[i].reset(gl, size.getWidth(), size.getHeight(), numSamples);
if( i>0 && fbos[i-1].getNumSamples() != fbos[i].getNumSamples()) {
throw new InternalError("sample size mismatch: \n\t0: "+fbos[i-1]+"\n\t1: "+fbos[i]);
}
numSamples = fbos[i].getNumSamples();
if(numSamples>0) {
- fboTexs[i] = fbos[i].getSamplingSink();
+ fboTexs[i] = fbos[i].getSamplingSink().getTextureAttachment();
} else {
- fboTexs[i] = (TextureAttachment) fbos[i].getColorbuffer(0);
+ fboTexs[i] = fbos[i].getColorbuffer(0).getTextureAttachment();
}
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
index 2091d0843..d32c981a3 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
@@ -46,6 +46,9 @@ public interface StereoDevice {
// NOP
}
+ /** Return the factory used to create this device. */
+ public StereoDeviceFactory getFactory();
+
/** Disposes this {@link StereoDevice}. */
public void dispose();
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java
index 46ce82f03..c4180585c 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java
@@ -45,7 +45,25 @@ public abstract class StereoDeviceFactory {
private static final String GenericStereoDeviceClazzName = "jogamp.opengl.util.stereo.GenericStereoDeviceFactory";
private static final String isAvailableMethodName = "isAvailable";
- public static enum DeviceType { Default, Generic, OculusVR };
+ /** {@link StereoDevice} type used for {@link StereoDeviceFactory#createFactory(DeviceType) createFactory(type)}. */
+ public static enum DeviceType {
+ /**
+ * Auto selection of device in the following order:
+ * <ol>
+ * <li>{@link DeviceType#OculusVR}</li>
+ * <li>{@link DeviceType#Generic}</li>
+ * </ol>
+ */
+ Default,
+ /**
+ * Generic software implementation.
+ */
+ Generic,
+ /**
+ * OculusVR implementation.
+ */
+ OculusVR
+ };
public static StereoDeviceFactory createDefaultFactory() {
final ClassLoader cl = StereoDeviceFactory.class.getClassLoader();
diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java
index 19f2fc05b..6011afe7b 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java
@@ -60,7 +60,6 @@ import javax.media.nativewindow.util.DimensionImmutable;
import javax.media.nativewindow.util.PixelFormat;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
-import javax.media.opengl.GL2ES3;
import javax.media.opengl.GL2GL3;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLException;
@@ -69,6 +68,7 @@ import javax.media.opengl.GLProfile;
import jogamp.opengl.Debug;
import com.jogamp.common.util.IOUtil;
+import com.jogamp.opengl.util.GLPixelStorageModes;
import com.jogamp.opengl.util.PNGPixelRect;
import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes;
import com.jogamp.opengl.util.texture.spi.DDSImage;
@@ -575,6 +575,10 @@ public class TextureIO {
* when it is written to disk, regardless of whether the underlying
* file format supports multiple mipmaps in a given file.
*
+ * <p>
+ * Method required a {@link GL2GL3} {@link GLProfile#GL2GL3 profile}.
+ * </p>
+ *
* @throws IOException if an error occurred during writing or no
* suitable writer was found
* @throws GLException if no OpenGL context was current or an
@@ -590,7 +594,7 @@ public class TextureIO {
if (!_gl.isGL2GL3()) {
throw new GLException("Implementation only supports GL2GL3 (Use GLReadBufferUtil and the TextureData variant), have: " + _gl);
}
- final GL2GL3 gl = _gl.getGL2();
+ final GL2GL3 gl = _gl.getGL2GL3();
texture.bind(gl);
final int internalFormat = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2GL3.GL_TEXTURE_INTERNAL_FORMAT);
@@ -630,17 +634,8 @@ public class TextureIO {
}
// Fetch using glGetTexImage
- final int packAlignment = glGetInteger(gl, GL.GL_PACK_ALIGNMENT);
- final int packRowLength = glGetInteger(gl, GL2ES3.GL_PACK_ROW_LENGTH);
- final int packSkipRows = glGetInteger(gl, GL2ES3.GL_PACK_SKIP_ROWS);
- final int packSkipPixels = glGetInteger(gl, GL2ES3.GL_PACK_SKIP_PIXELS);
- final int packSwapBytes = glGetInteger(gl, GL2GL3.GL_PACK_SWAP_BYTES);
-
- gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
- gl.glPixelStorei(GL2ES3.GL_PACK_ROW_LENGTH, 0);
- gl.glPixelStorei(GL2ES3.GL_PACK_SKIP_ROWS, 0);
- gl.glPixelStorei(GL2ES3.GL_PACK_SKIP_PIXELS, 0);
- gl.glPixelStorei(GL2GL3.GL_PACK_SWAP_BYTES, 0);
+ final GLPixelStorageModes psm = new GLPixelStorageModes();
+ psm.setPackAlignment(gl, 1);
final ByteBuffer res = ByteBuffer.allocate((width + (2 * border)) *
(height + (2 * border)) *
@@ -651,11 +646,7 @@ public class TextureIO {
}
gl.glGetTexImage(GL.GL_TEXTURE_2D, 0, fetchedFormat, GL.GL_UNSIGNED_BYTE, res);
- gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, packAlignment);
- gl.glPixelStorei(GL2ES3.GL_PACK_ROW_LENGTH, packRowLength);
- gl.glPixelStorei(GL2ES3.GL_PACK_SKIP_ROWS, packSkipRows);
- gl.glPixelStorei(GL2ES3.GL_PACK_SKIP_PIXELS, packSkipPixels);
- gl.glPixelStorei(GL2GL3.GL_PACK_SWAP_BYTES, packSwapBytes);
+ psm.restore(gl);
data = new TextureData(gl.getGLProfile(), internalFormat, width, height, border, fetchedFormat, GL.GL_UNSIGNED_BYTE,
false, false, false, res, null);
@@ -1404,12 +1395,6 @@ public class TextureIO {
// Helper routines
//
- private static int glGetInteger(final GL gl, final int pname) {
- final int[] tmp = new int[1];
- gl.glGetIntegerv(pname, tmp, 0);
- return tmp[0];
- }
-
private static int glGetTexLevelParameteri(final GL2GL3 gl, final int target, final int level, final int pname) {
final int[] tmp = new int[1];
gl.glGetTexLevelParameteriv(target, 0, pname, tmp, 0);