From eed8508ae1132e5f45f788e9cb3f3d5a1050ac70 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Mon, 2 Jul 2012 19:42:52 +0200
Subject: GLAutoDrawable: Refine API doc; Use new abstract impl.
GLAutoDrawableBase (GLWindow, ..); Add new GLAutoDrawableDelegate.
- Refine API doc
- 'void setContext(GLContext)' -> 'GLContext setContext(GLContext)'
- Add note to createContext(GLContext) override
-Use new abstract impl. GLAutoDrawableBase, used by:
- GLWindow
- GLAutoDrawableDelegate
- GLPbufferImpl
- Add new GLAutoDrawableDelegate incl. unit test
---
.../classes/jogamp/opengl/GLAutoDrawableBase.java | 337 +++++++++++++++++++++
1 file changed, 337 insertions(+)
create mode 100644 src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
new file mode 100644
index 000000000..3f50fe420
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -0,0 +1,337 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package jogamp.opengl;
+
+import java.io.PrintStream;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.opengl.FPSCounter;
+import javax.media.opengl.GL;
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLAutoDrawableDelegate;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLProfile;
+import javax.media.opengl.GLRunnable;
+
+import com.jogamp.opengl.util.Animator;
+
+
+/**
+ * Abstract common code for GLAutoDrawable implementations.
+ *
+ * @see GLAutoDrawable
+ * @see GLAutoDrawableDelegate
+ * @see GLPBufferImpl
+ * @see GLWindow
+ */
+public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
+ public static final boolean DEBUG = Debug.debug("GLAutoDrawable");
+
+ protected final GLDrawableHelper helper = new GLDrawableHelper();
+ protected final FPSCounterImpl fpsCounter = new FPSCounterImpl();
+
+ protected GLDrawableImpl drawable;
+ protected GLContextImpl context;
+ protected int additionalCtxCreationFlags = 0;
+ protected boolean sendReshape = false;
+ protected boolean sendDestroy = false;
+
+ public GLAutoDrawableBase(GLDrawableImpl drawable, GLContextImpl context) {
+ this.drawable = drawable;
+ this.context = context;
+ resetFPSCounter();
+ }
+
+ /** Returns the delegated GLDrawable */
+ public final GLDrawable getDelegatedDrawable() { return drawable; }
+
+ protected void defaultRepaintOp() {
+ if( null != drawable && drawable.isRealized() ) {
+ if( !drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimating() ) {
+ display();
+ }
+ }
+ }
+
+ protected void defaultReshapeOp() {
+ if( null!=drawable ) {
+ if(DEBUG) {
+ System.err.println("GLAutoDrawableBase.sizeChanged: ("+Thread.currentThread().getName()+"): "+getWidth()+"x"+getHeight()+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle()));
+ }
+ sendReshape = true;
+ defaultRepaintOp();
+ }
+ }
+
+ //
+ // GLAutoDrawable
+ //
+
+ protected final Runnable defaultInitAction = new Runnable() {
+ @Override
+ public final void run() {
+ // Lock: Locked Surface/Window by MakeCurrent/Release
+ helper.init(GLAutoDrawableBase.this);
+ resetFPSCounter();
+ } };
+
+ protected final Runnable defaultDisplayAction = new Runnable() {
+ @Override
+ public final void run() {
+ // Lock: Locked Surface/Window by display _and_ MakeCurrent/Release
+ if (sendReshape) {
+ helper.reshape(GLAutoDrawableBase.this, 0, 0, getWidth(), getHeight());
+ sendReshape = false;
+ }
+ helper.display(GLAutoDrawableBase.this);
+ fpsCounter.tickFPS();
+ } };
+
+ @Override
+ public final GLContext getContext() {
+ return context;
+ }
+
+ @Override
+ public final GLContext setContext(GLContext newCtx) {
+ final GLContext oldCtx = context;
+ final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
+ context=(GLContextImpl)newCtx;
+ if(newCtxCurrent) {
+ context.makeCurrent();
+ }
+ return oldCtx;
+ }
+
+ @Override
+ public final GL getGL() {
+ if (context == null) {
+ return null;
+ }
+ return context.getGL();
+ }
+
+ @Override
+ public final GL setGL(GL gl) {
+ if (context != null) {
+ context.setGL(gl);
+ return gl;
+ }
+ return null;
+ }
+
+ @Override
+ public final void addGLEventListener(GLEventListener listener) {
+ helper.addGLEventListener(listener);
+ }
+
+ @Override
+ public final void addGLEventListener(int index, GLEventListener listener)
+ throws IndexOutOfBoundsException {
+ helper.addGLEventListener(index, listener);
+ }
+
+ @Override
+ public final void removeGLEventListener(GLEventListener listener) {
+ helper.removeGLEventListener(listener);
+ }
+
+ @Override
+ public final void setAnimator(GLAnimatorControl animatorControl)
+ throws GLException {
+ helper.setAnimator(animatorControl);
+ }
+
+ @Override
+ public final GLAnimatorControl getAnimator() {
+ return helper.getAnimator();
+ }
+
+ @Override
+ public final void invoke(boolean wait, GLRunnable glRunnable) {
+ helper.invoke(this, wait, glRunnable);
+ }
+
+ @Override
+ public final void setAutoSwapBufferMode(boolean enable) {
+ helper.setAutoSwapBufferMode(enable);
+ }
+
+ @Override
+ public final boolean getAutoSwapBufferMode() {
+ return helper.getAutoSwapBufferMode();
+ }
+
+ @Override
+ public final void setContextCreationFlags(int flags) {
+ additionalCtxCreationFlags = flags;
+ if(null != context) {
+ context.setContextCreationFlags(additionalCtxCreationFlags);
+ }
+ }
+
+ @Override
+ public final int getContextCreationFlags() {
+ return additionalCtxCreationFlags;
+ }
+
+ //
+ // FPSCounter
+ //
+
+ @Override
+ public final void setUpdateFPSFrames(int frames, PrintStream out) {
+ fpsCounter.setUpdateFPSFrames(frames, out);
+ }
+
+ @Override
+ public final void resetFPSCounter() {
+ fpsCounter.resetFPSCounter();
+ }
+
+ @Override
+ public final int getUpdateFPSFrames() {
+ return fpsCounter.getUpdateFPSFrames();
+ }
+
+ @Override
+ public final long getFPSStartTime() {
+ return fpsCounter.getFPSStartTime();
+ }
+
+ @Override
+ public final long getLastFPSUpdateTime() {
+ return fpsCounter.getLastFPSUpdateTime();
+ }
+
+ @Override
+ public final long getLastFPSPeriod() {
+ return fpsCounter.getLastFPSPeriod();
+ }
+
+ @Override
+ public final float getLastFPS() {
+ return fpsCounter.getLastFPS();
+ }
+
+ @Override
+ public final int getTotalFPSFrames() {
+ return fpsCounter.getTotalFPSFrames();
+ }
+
+ @Override
+ public final long getTotalFPSDuration() {
+ return fpsCounter.getTotalFPSDuration();
+ }
+
+ @Override
+ public final float getTotalFPS() {
+ return fpsCounter.getTotalFPS();
+ }
+
+ //
+ // GLDrawable delegation
+ //
+
+ @Override
+ public final GLContext createContext(final GLContext shareWith) {
+ if(drawable != null) {
+ final GLContext _ctx = drawable.createContext(shareWith);
+ _ctx.setContextCreationFlags(additionalCtxCreationFlags);
+ return _ctx;
+ }
+ return null;
+ }
+
+ @Override
+ public final boolean isRealized() {
+ return null != drawable ? drawable.isRealized() : false;
+ }
+
+ @Override
+ public int getWidth() {
+ return null != drawable ? drawable.getWidth() : 0;
+ }
+
+ @Override
+ public int getHeight() {
+ return null != drawable ? drawable.getHeight() : 0;
+ }
+
+ /**
+ * @param t the thread for which context release shall be skipped, usually the animation thread,
+ * ie. {@link Animator#getThread()}.
+ * @deprecated this is an experimental feature,
+ * intended for measuring performance in regards to GL context switch
+ */
+ @Deprecated
+ public void setSkipContextReleaseThread(Thread t) {
+ helper.setSkipContextReleaseThread(t);
+ }
+
+ /**
+ * @deprecated see {@link #setSkipContextReleaseThread(Thread)}
+ */
+ @Deprecated
+ public Thread getSkipContextReleaseThread() {
+ return helper.getSkipContextReleaseThread();
+ }
+
+ @Override
+ public final void swapBuffers() throws GLException {
+ if(drawable!=null && context != null) {
+ drawable.swapBuffers();
+ }
+ }
+
+ @Override
+ public final GLCapabilitiesImmutable getChosenGLCapabilities() {
+ return null != drawable ? drawable.getChosenGLCapabilities() : null;
+ }
+
+ @Override
+ public final GLProfile getGLProfile() {
+ return null != drawable ? drawable.getGLProfile() : null;
+ }
+
+ @Override
+ public final NativeSurface getNativeSurface() {
+ return null != drawable ? drawable.getNativeSurface() : null;
+ }
+
+ @Override
+ public final long getHandle() {
+ return null != drawable ? drawable.getHandle() : 0;
+ }
+}
--
cgit v1.2.3
From 9b35c57425b0a5f6b789b9b43a62a8b64be51d86 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Wed, 4 Jul 2012 18:02:11 +0200
Subject: GLAutoDrawable* refinement of abstraction / generalization - API
Change!
- GLAutoDrawable (compat change - recompile):
- 'void invoke(boolean wait, GLRunnable glRunnable)' -> 'boolean invoke(boolean wait, GLRunnable glRunnable)'
Allows notifying caller whether the task has been executed or at least enqueued.
- GLAutoDrawable add 'GLEventListener removeGLEventListener(int index)'
- This allow one to remove a specific GLEventListener and reusing it (return value).
- GLDrawableImpl remove 'destroy()' to favor 'setRealized(false)'
- Using more common code of GLAutoDrawableBase, i.e. GLPbufferImpl can use defaultDestroyOp().
- Removes redundancy of methods
- GLAutoDrawableBase/Delegate
- better 'default' names to emphasize it's purpose, adding API doc
- includes more generic functionality
- defaultWindowDestroyNotify()
- defaultDestroyOp()
- TestGLAutoDrawableDelegateNEWT demonstrates a simple example w/ all window events handled.
- Fix TestParenting01cSwingAWT's threading use (gl disturbance thread)
---
.../classes/com/jogamp/opengl/swt/GLCanvas.java | 46 ++++---
.../classes/javax/media/opengl/GLAutoDrawable.java | 52 +++++--
.../javax/media/opengl/GLAutoDrawableDelegate.java | 68 +++++++---
.../classes/javax/media/opengl/awt/GLCanvas.java | 43 +++---
.../classes/javax/media/opengl/awt/GLJPanel.java | 39 +++---
.../classes/jogamp/opengl/GLAutoDrawableBase.java | 83 ++++++++++--
.../classes/jogamp/opengl/GLDrawableHelper.java | 149 +++++++++++++++++----
src/jogl/classes/jogamp/opengl/GLDrawableImpl.java | 16 +--
src/jogl/classes/jogamp/opengl/GLPbufferImpl.java | 26 +---
src/jogl/classes/jogamp/opengl/GLRunnableTask.java | 39 +++++-
.../jogamp/opengl/egl/EGLPbufferDrawable.java | 5 -
.../opengl/macosx/cgl/MacOSXCGLDrawable.java | 3 +-
.../macosx/cgl/MacOSXCGLDrawableFactory.java | 2 +-
.../macosx/cgl/MacOSXPbufferCGLDrawable.java | 5 -
.../windows/wgl/WindowsBitmapWGLDrawable.java | 5 -
.../windows/wgl/WindowsDummyWGLDrawable.java | 15 ++-
.../windows/wgl/WindowsPbufferWGLDrawable.java | 5 -
.../opengl/windows/wgl/WindowsWGLDrawable.java | 16 +--
.../windows/wgl/WindowsWGLDrawableFactory.java | 2 +-
.../jogamp/opengl/x11/glx/X11DummyGLXDrawable.java | 16 ++-
.../opengl/x11/glx/X11GLXDrawableFactory.java | 2 +-
.../opengl/x11/glx/X11PbufferGLXDrawable.java | 5 -
.../opengl/x11/glx/X11PixmapGLXDrawable.java | 5 -
.../classes/com/jogamp/newt/opengl/GLWindow.java | 42 +-----
.../jogl/acore/TestGLAutoDrawableDelegateNEWT.java | 84 ++++++++----
.../newt/parenting/TestParenting01cSwingAWT.java | 112 +++++++++++-----
.../junit/newt/parenting/TestParenting02NEWT.java | 8 +-
27 files changed, 582 insertions(+), 311 deletions(-)
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
index 31b679077..62b496891 100644
--- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
+++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
@@ -107,7 +107,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
//private static final boolean useSWTThread = ThreadingImpl.getMode() != ThreadingImpl.WORKER;
/* GL Stuff */
- private final GLDrawableHelper drawableHelper = new GLDrawableHelper();
+ private final GLDrawableHelper helper = new GLDrawableHelper();
private volatile GLDrawable drawable; // volatile avoids locking all accessors. FIXME still need to sync destroy/display
private GLContext context;
@@ -130,7 +130,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
private final Runnable initAction = new Runnable() {
@Override
public void run() {
- drawableHelper.init(GLCanvas.this);
+ helper.init(GLCanvas.this);
}
};
@@ -143,10 +143,10 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
@Override
public void run() {
if (sendReshape) {
- drawableHelper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight());
+ helper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight());
sendReshape = false;
}
- drawableHelper.display(GLCanvas.this);
+ helper.display(GLCanvas.this);
}
};
@@ -154,7 +154,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
private final Runnable makeCurrentAndDisplayAction = new Runnable() {
@Override
public void run() {
- drawableHelper.invokeGL(drawable, context, displayAction, initAction);
+ helper.invokeGL(drawable, context, displayAction, initAction);
}
};
@@ -170,7 +170,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
private final Runnable makeCurrentAndSwapBuffersAction = new Runnable() {
@Override
public void run() {
- drawableHelper.invokeGL(drawable, context, swapBuffersAction, initAction);
+ helper.invokeGL(drawable, context, swapBuffersAction, initAction);
}
};
@@ -191,7 +191,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
private final Runnable disposeOnEDTGLAction = new Runnable() {
@Override
public void run() {
- drawableHelper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction);
+ helper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction);
}
};
@@ -266,7 +266,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
addPaintListener(new PaintListener() {
@Override
public void paintControl(final PaintEvent arg0) {
- if (!drawableHelper.isExternalAnimatorAnimating()) {
+ if (!helper.isExternalAnimatorAnimating()) {
display();
}
}
@@ -284,12 +284,12 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
@Override
public void addGLEventListener(final GLEventListener arg0) {
- drawableHelper.addGLEventListener(arg0);
+ helper.addGLEventListener(arg0);
}
@Override
public void addGLEventListener(final int arg0, final GLEventListener arg1) throws IndexOutOfBoundsException {
- drawableHelper.addGLEventListener(arg0, arg1);
+ helper.addGLEventListener(arg0, arg1);
}
/**
@@ -312,12 +312,12 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
@Override
public GLAnimatorControl getAnimator() {
- return drawableHelper.getAnimator();
+ return helper.getAnimator();
}
@Override
public boolean getAutoSwapBufferMode() {
- return drawableHelper.getAutoSwapBufferMode();
+ return helper.getAutoSwapBufferMode();
}
@Override
@@ -336,30 +336,34 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
}
@Override
- public void invoke(final boolean wait, final GLRunnable run) {
- /* Queue task for running during the next display(). */
- drawableHelper.invoke(this, wait, run);
+ public boolean invoke(final boolean wait, final GLRunnable run) {
+ return helper.invoke(this, wait, run);
}
@Override
public void removeGLEventListener(final GLEventListener arg0) {
- drawableHelper.removeGLEventListener(arg0);
+ helper.removeGLEventListener(arg0);
}
+ @Override
+ public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException {
+ return helper.removeGLEventListener(index);
+ }
+
@Override
public void setAnimator(final GLAnimatorControl arg0) throws GLException {
- drawableHelper.setAnimator(arg0);
+ helper.setAnimator(arg0);
}
@Override
public void setAutoSwapBufferMode(final boolean arg0) {
- drawableHelper.setAutoSwapBufferMode(arg0);
+ helper.setAutoSwapBufferMode(arg0);
}
@Override
public GLContext setContext(GLContext newCtx) {
final GLContext oldCtx = context;
- final boolean newCtxCurrent = drawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
+ final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
context=(GLContextImpl)newCtx;
if(newCtxCurrent) {
context.makeCurrent();
@@ -477,7 +481,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
if (Threading.isSingleThreaded() && !Threading.isOpenGLThread()) {
runInDesignatedGLThread(disposeOnEDTGLAction);
} else if (context.isCreated()) {
- drawableHelper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction);
+ helper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction);
}
}
@@ -537,7 +541,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
runInDesignatedGLThread(asyncAction);
} else {
/* Run in current thread... */
- drawableHelper.invokeGL(drawable, context, syncAction, initAction);
+ helper.invokeGL(drawable, context, syncAction, initAction);
}
}
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
index e4aaad23d..80d4f796c 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
@@ -165,16 +165,32 @@ public interface GLAutoDrawable extends GLDrawable {
* @param listener The GLEventListener object to be inserted
* @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1
*/
- public void addGLEventListener(int index, GLEventListener listener)
- throws IndexOutOfBoundsException;
+ public void addGLEventListener(int index, GLEventListener listener) throws IndexOutOfBoundsException;
- /** Removes a {@link GLEventListener} from this drawable. Note that
- if this is done from within a particular drawable's {@link
- GLEventListener} handler (reshape, display, etc.) that it is not
- guaranteed that all other listeners will be evaluated properly
- during this update cycle. */
+ /**
+ * Removes a {@link GLEventListener} from this drawable.
+ * Note that if this is done from within a particular drawable's
+ * {@link GLEventListener} handler (reshape, display, etc.) that it is not
+ * guaranteed that all other listeners will be evaluated properly
+ * during this update cycle.
+ * @param listener The GLEventListener object to be removed
+ */
public void removeGLEventListener(GLEventListener listener);
+ /**
+ * Removes a {@link GLEventListener} at the given index from this drawable.
+ * Note that if this is done from within a particular drawable's
+ * {@link GLEventListener} handler (reshape, display, etc.) that it is not
+ * guaranteed that all other listeners will be evaluated properly
+ * during this update cycle.
+ * @param index Position of the listener to be removed.
+ * Should be within (0 <= index && index < size()).
+ * An index value of -1 is interpreted as last listener, size()-1.
+ * @return The removed GLEventListener object
+ * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index < size()), or -1
+ */
+ public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException;
+
/**
*
* Registers the usage of an animator, an {@link javax.media.opengl.GLAnimatorControl} implementation.
@@ -221,14 +237,30 @@ public interface GLAutoDrawable extends GLDrawable {
*
* If an {@link GLAnimatorControl} is animating,
* no {@link #display()} call is issued, since the animator thread performs it.
- * If wait is true, the implementation waits until the GLRunnable is executed.
- *
+ *
+ *
+ * If wait is true the call blocks until the glRunnable
+ * has been executed.
+ *
+ * If wait is trueand
+ * {@link #isRealized()} returns falseor {@link #getContext()} returns null,
+ * the call is ignored and returns false.
+ * This helps avoiding deadlocking the caller.
+ *
+ *
+ * The internal queue of {@link GLRunnable}'s is being flushed with {@link #destroy()}
+ * where all blocked callers are being notified.
+ *
*
+ * @param wait if true block until execution of glRunnable is finished, otherwise return immediatly w/o waiting
+ * @param glRunnable the {@link GLRunnable} to execute within {@link #display()}
+ * @return true if the {@link GLRunnable} has been processed or queued, otherwise false.
+ *
* @see #setAnimator(GLAnimatorControl)
* @see #display()
* @see GLRunnable
*/
- public void invoke(boolean wait, GLRunnable glRunnable);
+ public boolean invoke(boolean wait, GLRunnable glRunnable);
/** Destroys all resources associated with this GLAutoDrawable,
inclusive the GLContext.
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
index 992bf9fee..89d5cc4cb 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
@@ -28,6 +28,9 @@
package javax.media.opengl;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+
import jogamp.opengl.Debug;
import jogamp.opengl.GLAutoDrawableBase;
import jogamp.opengl.GLContextImpl;
@@ -39,11 +42,16 @@ import jogamp.opengl.GLDrawableImpl;
* utilizing already created created {@link GLDrawable} and {@link GLContext} instances.
*
* Since no native windowing system events are being processed, it is recommended
- * to handle at least {@link com.jogamp.newt.event.WindowListener#windowResized(com.jogamp.newt.event.WindowEvent) resize},
- * {@link com.jogamp.newt.event.WindowListener#windowDestroyNotify(com.jogamp.newt.event.WindowEvent) destroy-notify}
- * and maybe {@link com.jogamp.newt.event.WindowListener#windowRepaint(com.jogamp.newt.event.WindowUpdateEvent) repaint}.
- * The latter is only required if no {@link GLAnimatorControl} is being used.
- *
+ * to handle at least:
+ *
+ *
{@link com.jogamp.newt.event.WindowListener#windowRepaint(com.jogamp.newt.event.WindowUpdateEvent) repaint} using {@link #defaultWindowRepaintOp()}
+ *
{@link com.jogamp.newt.event.WindowListener#windowResized(com.jogamp.newt.event.WindowEvent) resize} using {@link #defaultWindowResizedOp()}
+ *
{@link com.jogamp.newt.event.WindowListener#windowDestroyNotify(com.jogamp.newt.event.WindowEvent) destroy-notify} using {@link #defaultWindowDestroyNotifyOp()}
+ *
+ *
+ *
+ * See example {@link com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateNEWT TestGLAutoDrawableDelegateNEWT}.
+ *
*/
public class GLAutoDrawableDelegate extends GLAutoDrawableBase {
public static final boolean DEBUG = Debug.debug("GLAutoDrawableDelegate");
@@ -52,36 +60,64 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase {
super((GLDrawableImpl)drawable, (GLContextImpl)context);
}
- public void defaultRepaintOp() {
- super.defaultRepaintOp();
+ //
+ // make protected methods accessible
+ //
+
+ public void defaultWindowRepaintOp() {
+ super.defaultWindowRepaintOp();
+ }
+
+ public void defaultWindowResizedOp() {
+ super.defaultWindowResizedOp();
}
- public void defaultReshapeOp() {
- super.defaultReshapeOp();
+ public void defaultWindowDestroyNotifyOp() {
+ super.defaultWindowDestroyNotifyOp();
}
//
// Complete GLAutoDrawable
//
+ private RecursiveLock lock = LockFactory.createRecursiveLock(); // instance wide lock
+
/**
* {@inheritDoc}
*
- * This implementation simply removes references to drawable and context.
+ * This implementation calls {@link #defaultDestroyOp()}.
+ *
+ *
+ * User still needs to destroy the upstream window, which details are hidden from this aspect.
*
*/
@Override
public void destroy() {
- drawable = null;
- context = null;
+ lock.lock();
+ try {
+ defaultDestroyOp();
+ } finally {
+ lock.unlock();
+ }
}
@Override
public void display() {
- if( null == drawable || !drawable.isRealized() || null == context ) { return; }
-
- // surface is locked/unlocked implicit by context's makeCurrent/release
- helper.invokeGL(drawable, context, defaultDisplayAction, defaultInitAction);
+ if( sendDestroy ) {
+ sendDestroy=false;
+ destroy();
+ return;
+ }
+
+ lock.lock(); // sync: context/drawable could been recreated/destroyed while animating
+ try {
+ if( null != drawable && drawable.isRealized() && null != context ) {
+ // surface is locked/unlocked implicit by context's makeCurrent/release
+ helper.invokeGL(drawable, context, defaultDisplayAction, defaultInitAction);
+ }
+ } finally {
+ lock.unlock();
+ }
}
//
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
index 8c6e594b5..3161f898d 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
@@ -153,7 +153,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private static final boolean DEBUG = Debug.debug("GLCanvas");
- private final GLDrawableHelper drawableHelper = new GLDrawableHelper();
+ private final GLDrawableHelper helper = new GLDrawableHelper();
private AWTGraphicsConfiguration awtConfig;
private volatile GLDrawable drawable; // volatile avoids locking all accessors. FIXME still need to sync destroy/display
private GLContextImpl context;
@@ -510,7 +510,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
(int) ((getHeight() + bounds.getHeight()) / 2));
return;
}
- if( ! this.drawableHelper.isAnimatorAnimating() ) {
+ if( ! this.helper.isAnimatorAnimating() ) {
display();
}
}
@@ -670,38 +670,43 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@Override
public void addGLEventListener(GLEventListener listener) {
- drawableHelper.addGLEventListener(listener);
+ helper.addGLEventListener(listener);
}
@Override
- public void addGLEventListener(int index, GLEventListener listener) {
- drawableHelper.addGLEventListener(index, listener);
+ public void addGLEventListener(int index, GLEventListener listener) throws IndexOutOfBoundsException {
+ helper.addGLEventListener(index, listener);
}
@Override
public void removeGLEventListener(GLEventListener listener) {
- drawableHelper.removeGLEventListener(listener);
+ helper.removeGLEventListener(listener);
}
+ @Override
+ public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException {
+ return helper.removeGLEventListener(index);
+ }
+
@Override
public void setAnimator(GLAnimatorControl animatorControl) {
- drawableHelper.setAnimator(animatorControl);
+ helper.setAnimator(animatorControl);
}
@Override
public GLAnimatorControl getAnimator() {
- return drawableHelper.getAnimator();
+ return helper.getAnimator();
}
@Override
- public void invoke(boolean wait, GLRunnable glRunnable) {
- drawableHelper.invoke(this, wait, glRunnable);
+ public boolean invoke(boolean wait, GLRunnable glRunnable) {
+ return helper.invoke(this, wait, glRunnable);
}
@Override
public GLContext setContext(GLContext newCtx) {
final GLContext oldCtx = context;
- final boolean newCtxCurrent = drawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
+ final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
context=(GLContextImpl)newCtx;
if(newCtxCurrent) {
context.makeCurrent();
@@ -736,12 +741,12 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@Override
public void setAutoSwapBufferMode(boolean onOrOff) {
- drawableHelper.setAutoSwapBufferMode(onOrOff);
+ helper.setAutoSwapBufferMode(onOrOff);
}
@Override
public boolean getAutoSwapBufferMode() {
- return drawableHelper.getAutoSwapBufferMode();
+ return helper.getAutoSwapBufferMode();
}
@Override
@@ -849,7 +854,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private final Runnable disposeOnEDTAction = new Runnable() {
@Override
public void run() {
- drawableHelper.disposeGL(GLCanvas.this, drawable, context, postDisposeAction);
+ helper.disposeGL(GLCanvas.this, drawable, context, postDisposeAction);
}
};
@@ -897,7 +902,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private final Runnable initAction = new Runnable() {
@Override
public void run() {
- drawableHelper.init(GLCanvas.this);
+ helper.init(GLCanvas.this);
}
};
@@ -910,11 +915,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
// Note: we ignore the given x and y within the parent component
// since we are drawing directly into this heavyweight component.
- drawableHelper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight());
+ helper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight());
sendReshape = false;
}
- drawableHelper.display(GLCanvas.this);
+ helper.display(GLCanvas.this);
}
};
@@ -931,14 +936,14 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private final Runnable displayOnEDTAction = new Runnable() {
@Override
public void run() {
- drawableHelper.invokeGL(drawable, context, displayAction, initAction);
+ helper.invokeGL(drawable, context, displayAction, initAction);
}
};
private final Runnable swapBuffersOnEDTAction = new Runnable() {
@Override
public void run() {
- drawableHelper.invokeGL(drawable, context, swapBuffersAction, initAction);
+ helper.invokeGL(drawable, context, swapBuffersAction, initAction);
}
};
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
index c6c7cf9a1..cd18c5098 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
@@ -125,7 +125,7 @@ import com.jogamp.opengl.util.GLBuffers;
public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol {
private static final boolean DEBUG = Debug.debug("GLJPanel");
- private GLDrawableHelper drawableHelper = new GLDrawableHelper();
+ private GLDrawableHelper helper = new GLDrawableHelper();
private volatile boolean isInitialized;
// Data used for either pbuffers or pixmap-based offscreen surfaces
@@ -413,32 +413,37 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
@Override
public void addGLEventListener(GLEventListener listener) {
- drawableHelper.addGLEventListener(listener);
+ helper.addGLEventListener(listener);
}
@Override
public void addGLEventListener(int index, GLEventListener listener) {
- drawableHelper.addGLEventListener(index, listener);
+ helper.addGLEventListener(index, listener);
}
@Override
public void removeGLEventListener(GLEventListener listener) {
- drawableHelper.removeGLEventListener(listener);
+ helper.removeGLEventListener(listener);
}
+ @Override
+ public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException {
+ return helper.removeGLEventListener(index);
+ }
+
@Override
public void setAnimator(GLAnimatorControl animatorControl) {
- drawableHelper.setAnimator(animatorControl);
+ helper.setAnimator(animatorControl);
}
@Override
public GLAnimatorControl getAnimator() {
- return drawableHelper.getAnimator();
+ return helper.getAnimator();
}
@Override
- public void invoke(boolean wait, GLRunnable glRunnable) {
- drawableHelper.invoke(this, wait, glRunnable);
+ public boolean invoke(boolean wait, GLRunnable glRunnable) {
+ return helper.invoke(this, wait, glRunnable);
}
@Override
@@ -461,7 +466,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
return null;
}
final GLContext oldCtx = backend.getContext();
- final boolean newCtxCurrent = drawableHelper.switchContext(backend.getDrawable(), oldCtx, newCtx, additionalCtxCreationFlags);
+ final boolean newCtxCurrent = helper.switchContext(backend.getDrawable(), oldCtx, newCtx, additionalCtxCreationFlags);
backend.setContext(newCtx);
if(newCtxCurrent) {
newCtx.makeCurrent();
@@ -662,13 +667,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
if (!backend.preGL(g)) {
return;
}
- drawableHelper.init(GLJPanel.this);
+ helper.init(GLJPanel.this);
backend.postGL(g, false);
}
@Override
public void dispose(GLAutoDrawable drawable) {
- drawableHelper.dispose(GLJPanel.this);
+ helper.dispose(GLJPanel.this);
}
@Override
@@ -680,11 +685,11 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
if (DEBUG) {
System.err.println(getThreadName()+": GLJPanel.display: reshape(" + viewportX + "," + viewportY + " " + panelWidth + "x" + panelHeight + ")");
}
- drawableHelper.reshape(GLJPanel.this, viewportX, viewportY, panelWidth, panelHeight);
+ helper.reshape(GLJPanel.this, viewportX, viewportY, panelWidth, panelHeight);
sendReshape = false;
}
- drawableHelper.display(GLJPanel.this);
+ helper.display(GLJPanel.this);
backend.postGL(g, true);
}
@@ -716,7 +721,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
private final Runnable disposeAction = new Runnable() {
@Override
public void run() {
- drawableHelper.disposeGL(GLJPanel.this, backend.getDrawable(), backend.getContext(), postDisposeAction);
+ helper.disposeGL(GLJPanel.this, backend.getDrawable(), backend.getContext(), postDisposeAction);
}
};
@@ -1035,7 +1040,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
if (offscreenDrawable != null) {
final AbstractGraphicsDevice adevice = offscreenDrawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice();
- offscreenDrawable.destroy();
+ offscreenDrawable.setRealized(false);
offscreenDrawable = null;
if(null != adevice) {
adevice.close();
@@ -1094,7 +1099,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
@Override
protected void doPaintComponentImpl() {
- drawableHelper.invokeGL(offscreenDrawable, offscreenContext, updaterDisplayAction, updaterInitAction);
+ helper.invokeGL(offscreenDrawable, offscreenContext, updaterDisplayAction, updaterInitAction);
}
@Override
@@ -1711,7 +1716,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
((Java2DGLContext) joglContext).setGraphics(g);
}
- drawableHelper.invokeGL(joglDrawable, joglContext, updaterDisplayAction, updaterInitAction);
+ helper.invokeGL(joglDrawable, joglContext, updaterDisplayAction, updaterInitAction);
}
} finally {
j2dContext.release();
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index 3f50fe420..5c6d7446a 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -31,6 +31,8 @@ package jogamp.opengl;
import java.io.PrintStream;
import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.WindowClosingProtocol;
+import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode;
import javax.media.opengl.FPSCounter;
import javax.media.opengl.GL;
import javax.media.opengl.GLAnimatorControl;
@@ -76,7 +78,8 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
/** Returns the delegated GLDrawable */
public final GLDrawable getDelegatedDrawable() { return drawable; }
- protected void defaultRepaintOp() {
+ /** Default implementation to handle repaint events from the windowing system */
+ protected void defaultWindowRepaintOp() {
if( null != drawable && drawable.isRealized() ) {
if( !drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimating() ) {
display();
@@ -84,16 +87,74 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
}
- protected void defaultReshapeOp() {
+ /** Default implementation to handle resize events from the windowing system */
+ protected void defaultWindowResizedOp() {
if( null!=drawable ) {
if(DEBUG) {
System.err.println("GLAutoDrawableBase.sizeChanged: ("+Thread.currentThread().getName()+"): "+getWidth()+"x"+getHeight()+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle()));
}
sendReshape = true;
- defaultRepaintOp();
+ defaultWindowRepaintOp();
}
}
-
+
+ /** Default implementation to handle destroy notifications from the windowing system */
+ protected void defaultWindowDestroyNotifyOp() {
+ final NativeSurface ns = getNativeSurface();
+ final boolean shallClose;
+ if(ns instanceof WindowClosingProtocol) {
+ shallClose = WindowClosingMode.DISPOSE_ON_CLOSE == ((WindowClosingProtocol)ns).getDefaultCloseOperation();
+ } else {
+ shallClose = true;
+ }
+ if( shallClose ) {
+ // Is an animator thread perform rendering?
+ if (helper.isExternalAnimatorRunning()) {
+ // Pause animations before initiating safe destroy.
+ final GLAnimatorControl ctrl = helper.getAnimator();
+ final boolean isPaused = ctrl.pause();
+ destroy();
+ if(isPaused) {
+ ctrl.resume();
+ }
+ } else if (null != ns && ns.isSurfaceLockedByOtherThread()) {
+ // surface is locked by another thread
+ // Flag that destroy should be performed on the next
+ // attempt to display.
+ sendDestroy = true;
+ } else {
+ // Without an external thread animating or locking the
+ // surface, we are safe.
+ destroy ();
+ }
+ }
+ }
+
+ /**
+ * Default implementation to destroys the drawable and context of this GLAutoDrawable:
+ *
+ *
issues the GLEventListener dispose call, if drawable and context are valid
+ *
destroys the GLContext, if valid
+ *
destroys the GLDrawable, if valid
+ *
+ */
+ protected void defaultDestroyOp() {
+ if( null != drawable && drawable.isRealized() ) {
+ if( null != context && context.isCreated() ) {
+ // Catch dispose GLExceptions by GLEventListener, just 'print' them
+ // so we can continue with the destruction.
+ try {
+ helper.disposeGL(this, drawable, context, null);
+ } catch (GLException gle) {
+ gle.printStackTrace();
+ }
+ }
+ drawable.setRealized(false);
+ }
+ context = null;
+ drawable = null;
+ }
+
//
// GLAutoDrawable
//
@@ -157,8 +218,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
@Override
- public final void addGLEventListener(int index, GLEventListener listener)
- throws IndexOutOfBoundsException {
+ public final void addGLEventListener(int index, GLEventListener listener) throws IndexOutOfBoundsException {
helper.addGLEventListener(index, listener);
}
@@ -166,7 +226,12 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
public final void removeGLEventListener(GLEventListener listener) {
helper.removeGLEventListener(listener);
}
-
+
+ @Override
+ public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException {
+ return helper.removeGLEventListener(index);
+ }
+
@Override
public final void setAnimator(GLAnimatorControl animatorControl)
throws GLException {
@@ -179,8 +244,8 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
@Override
- public final void invoke(boolean wait, GLRunnable glRunnable) {
- helper.invoke(this, wait, glRunnable);
+ public final boolean invoke(boolean wait, GLRunnable glRunnable) {
+ return helper.invoke(this, wait, glRunnable);
}
@Override
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
index e7651eaab..0c01aa676 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
@@ -61,13 +61,13 @@ public class GLDrawableHelper {
private static final boolean PERF_STATS = Debug.isPropertyDefined("jogl.debug.GLDrawable.PerfStats", true);
protected static final boolean DEBUG = GLDrawableImpl.DEBUG;
- private Object listenersLock = new Object();
- private ArrayList listeners;
- private HashSet listenersToBeInit;
+ private final Object listenersLock = new Object();
+ private final ArrayList listeners = new ArrayList();
+ private final HashSet listenersToBeInit = new HashSet();
+ private final Object glRunnablesLock = new Object();
+ private volatile ArrayList glRunnables = new ArrayList();
private boolean autoSwapBufferMode;
private Thread skipContextReleaseThread;
- private Object glRunnablesLock = new Object();
- private ArrayList glRunnables;
private GLAnimatorControl animatorCtrl;
public GLDrawableHelper() {
@@ -76,13 +76,13 @@ public class GLDrawableHelper {
public final void reset() {
synchronized(listenersLock) {
- listeners = new ArrayList();
- listenersToBeInit = new HashSet();
+ listeners.clear();
+ listenersToBeInit.clear();
}
autoSwapBufferMode = true;
skipContextReleaseThread = null;
synchronized(glRunnablesLock) {
- glRunnables = new ArrayList();
+ glRunnables.clear();
}
animatorCtrl = null;
}
@@ -105,6 +105,46 @@ public class GLDrawableHelper {
return sb.toString();
}
+ /**
+ * Associate a new context to the drawable and also propagates the context/drawable switch by
+ * calling {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.
+ *
+ * If the old context's drawable was an {@link GLAutoDrawable}, it's reference to the given drawable
+ * is being cleared by calling
+ * {@link GLAutoDrawable#setContext(GLContext) ((GLAutoDrawable)oldCtx.getGLDrawable()).setContext(null)}.
+ *
+ *
+ * If the old or new context was current on this thread, it is being released before switching the drawable.
+ *
+ *
+ * @param drawable the drawable which context is changed
+ * @param newCtx the new context
+ * @param oldCtx the old context
+ * @return true if the newt context was current, otherwise false
+ *
+ * @see GLAutoDrawable#setContext(GLContext)
+ */
+ public final boolean switchContext(GLDrawable drawable, GLContext oldCtx, GLContext newCtx, int additionalCtxCreationFlags) {
+ if(null != oldCtx && oldCtx.isCurrent()) {
+ oldCtx.release();
+ }
+ final boolean newCtxCurrent;
+ if(null!=newCtx) {
+ newCtxCurrent = newCtx.isCurrent();
+ if(newCtxCurrent) {
+ newCtx.release();
+ }
+ newCtx.setContextCreationFlags(additionalCtxCreationFlags);
+ newCtx.setGLDrawable(drawable, true); // propagate context/drawable switch
+ } else {
+ newCtxCurrent = false;
+ }
+ if(null!=oldCtx && oldCtx.getGLDrawable() instanceof GLAutoDrawable) {
+ ((GLAutoDrawable)oldCtx.getGLDrawable()).setContext(null);
+ }
+ return newCtxCurrent;
+ }
+
public final void addGLEventListener(GLEventListener listener) {
addGLEventListener(-1, listener);
}
@@ -128,6 +168,16 @@ public class GLDrawableHelper {
}
}
+ public final GLEventListener removeGLEventListener(int index)
+ throws IndexOutOfBoundsException {
+ synchronized(listenersLock) {
+ if(0>index) {
+ index = listeners.size()-1;
+ }
+ return listeners.remove(index);
+ }
+ }
+
/**
* Issues {@link javax.media.opengl.GLEventListener#dispose(javax.media.opengl.GLAutoDrawable)}
* to all listeners.
@@ -144,18 +194,19 @@ public class GLDrawableHelper {
}
}
}
-
- private boolean init(GLEventListener l, GLAutoDrawable drawable, boolean sendReshape) {
+
+ private final boolean init(GLEventListener l, GLAutoDrawable drawable, boolean sendReshape) {
if(listenersToBeInit.remove(l)) {
l.init(drawable);
if(sendReshape) {
- reshape(l, drawable, 0, 0, drawable.getWidth(), drawable.getHeight(), true /* setViewport */, false);
+ reshape(l, drawable, 0, 0, drawable.getWidth(), drawable.getHeight(), true /* setViewport */, false /* checkInit */);
}
return true;
}
return false;
}
+ /** The default init action to be called once after ctx is being created @ 1st makeCurrent(). */
public final void init(GLAutoDrawable drawable) {
synchronized(listenersLock) {
for (int i=0; i < listeners.size(); i++) {
@@ -166,7 +217,7 @@ public class GLDrawableHelper {
// hence the must always be initialized unconditional.
listenersToBeInit.add(listener);
- if ( ! init( listener, drawable, false ) ) {
+ if ( ! init( listener, drawable, true /* sendReshape */) ) {
throw new GLException("GLEventListener "+listener+" already initialized: "+drawable);
}
}
@@ -179,24 +230,26 @@ public class GLDrawableHelper {
displayImpl(drawable);
}
}
- private void displayImpl(GLAutoDrawable drawable) {
+ private final void displayImpl(GLAutoDrawable drawable) {
synchronized(listenersLock) {
for (int i=0; i < listeners.size(); i++) {
final GLEventListener listener = listeners.get(i) ;
// GLEventListener may need to be init,
// in case this one is added after the realization of the GLAutoDrawable
- init( listener, drawable, true ) ;
+ init( listener, drawable, true /* sendReshape */) ;
listener.display(drawable);
}
}
}
- private void reshape(GLEventListener listener, GLAutoDrawable drawable,
- int x, int y, int width, int height, boolean setViewport, boolean checkInit) {
+ private final void reshape(GLEventListener listener, GLAutoDrawable drawable,
+ int x, int y, int width, int height, boolean setViewport, boolean checkInit) {
if(checkInit) {
// GLEventListener may need to be init,
- // in case this one is added after the realization of the GLAutoDrawable
- init( listener, drawable, false ) ;
+ // in case this one is added after the realization of the GLAutoDrawable
+ synchronized(listenersLock) {
+ init( listener, drawable, false /* sendReshape */) ;
+ }
}
if(setViewport) {
drawable.getGL().glViewport(x, y, width, height);
@@ -212,27 +265,50 @@ public class GLDrawableHelper {
}
}
- private boolean execGLRunnables(GLAutoDrawable drawable) {
+ private final boolean execGLRunnables(GLAutoDrawable drawable) {
boolean res = true;
- if(glRunnables.size()>0) {
+ if(glRunnables.size()>0) { // volatile OK
// swap one-shot list asap
- ArrayList _glRunnables = null;
+ final ArrayList _glRunnables;
synchronized(glRunnablesLock) {
if(glRunnables.size()>0) {
_glRunnables = glRunnables;
- glRunnables = new ArrayList();
+ glRunnables = new ArrayList();
+ } else {
+ _glRunnables = null;
}
}
if(null!=_glRunnables) {
for (int i=0; i < _glRunnables.size(); i++) {
- res = _glRunnables.get(i).run(drawable) && res;
+ res = _glRunnables.get(i).run(drawable) && res;
}
}
}
return res;
}
+ public final void flushGLRunnables() {
+ if(glRunnables.size()>0) { // volatile OK
+ // swap one-shot list asap
+ final ArrayList _glRunnables;
+ synchronized(glRunnablesLock) {
+ if(glRunnables.size()>0) {
+ _glRunnables = glRunnables;
+ glRunnables = new ArrayList();
+ } else {
+ _glRunnables = null;
+ }
+ }
+
+ if(null!=_glRunnables) {
+ for (int i=0; i < _glRunnables.size(); i++) {
+ _glRunnables.get(i).flush();
+ }
+ }
+ }
+ }
+
public final void setAnimator(GLAnimatorControl animator) throws GLException {
synchronized(glRunnablesLock) {
if(animatorCtrl!=animator && null!=animator && null!=animatorCtrl) {
@@ -264,10 +340,28 @@ public class GLDrawableHelper {
return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() : false ;
}
- public final void invoke(GLAutoDrawable drawable, boolean wait, GLRunnable glRunnable) {
- if( null == drawable || null == glRunnable ) {
- return;
+ /**
+ *
+ * If wait is true the call blocks until the glRunnable
+ * has been executed.
+ *
+ * If wait is trueand
+ * {@link GLDrawable#isRealized()} returns falseor {@link GLAutoDrawable#getContext()} returns null,
+ * the call is ignored and returns false.
+ * This helps avoiding deadlocking the caller.
+ *
+ *
+ * @param drawable the {@link GLAutoDrawable} to be used
+ * @param wait if true block until execution of glRunnable is finished, otherwise return immediatly w/o waiting
+ * @param glRunnable the {@link GLRunnable} to execute within {@link #display()}
+ * @return true if the {@link GLRunnable} has been processed or queued, otherwise false.
+ */
+ public final boolean invoke(GLAutoDrawable drawable, boolean wait, GLRunnable glRunnable) {
+ if( null == glRunnable || null == drawable ||
+ wait && ( !drawable.isRealized() || null==drawable.getContext() ) ) {
+ return false;
}
+
Throwable throwable = null;
GLRunnableTask rTask = null;
Object rTaskLock = new Object();
@@ -299,6 +393,7 @@ public class GLDrawableHelper {
}
}
}
+ return true;
}
public final void setAutoSwapBufferMode(boolean enable) {
@@ -439,6 +534,7 @@ public class GLDrawableHelper {
try {
if(isDisposeAction) {
context.destroy();
+ flushGLRunnables();
} else if( GLContext.CONTEXT_NOT_CURRENT != res ) {
context.release();
}
@@ -526,6 +622,7 @@ public class GLDrawableHelper {
try {
if(isDisposeAction) {
context.destroy();
+ flushGLRunnables();
ctxDestroyed = true;
} else if( res != GLContext.CONTEXT_NOT_CURRENT &&
(null == skipContextReleaseThread || currentThread != skipContextReleaseThread) ) {
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java
index b3884830a..58a4ac6b4 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java
@@ -70,20 +70,6 @@ public abstract class GLDrawableImpl implements GLDrawable {
return (GLDrawableFactoryImpl) getFactory();
}
- /** For offscreen GLDrawables (pbuffers and "pixmap" drawables),
- indicates that native resources should be reclaimed. */
- public void destroy() {
- surface.getGraphicsConfiguration().getScreen().getDevice().lock();
- try {
- destroyImpl();
- } finally {
- surface.getGraphicsConfiguration().getScreen().getDevice().unlock();
- }
- }
- protected void destroyImpl() {
- throw new GLException("Should not call this (should only be called for offscreen GLDrawables)");
- }
-
@Override
public final void swapBuffers() throws GLException {
if( !realized ) {
@@ -164,7 +150,7 @@ public abstract class GLDrawableImpl implements GLDrawable {
AbstractGraphicsDevice aDevice = surface.getGraphicsConfiguration().getScreen().getDevice();
if(realizedArg) {
if(NativeSurface.LOCK_SURFACE_NOT_READY >= lockSurface()) {
- throw new GLException("GLDrawableImpl.setRealized(true): already realized, but surface not ready (lockSurface)");
+ throw new GLException("GLDrawableImpl.setRealized(true): Surface not ready (lockSurface)");
}
} else {
aDevice.lock();
diff --git a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
index d98b41bdc..a8277fd71 100644
--- a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
@@ -40,7 +40,6 @@
package jogamp.opengl;
-import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawableFactory;
@@ -114,36 +113,19 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer {
@Override
public void destroy() {
- if(drawable.isRealized()) {
- final AbstractGraphicsDevice adevice = drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice();
-
- if (null != context && context.isCreated()) {
- try {
- helper.disposeGL(GLPbufferImpl.this, drawable, context, null);
- } catch (GLException gle) {
- gle.printStackTrace();
- }
- context = null;
- // drawableHelper.reset();
- }
- drawable.destroy();
- drawable = null;
-
- if(null != adevice) {
- adevice.close();
- }
- }
+ defaultDestroyOp();
}
@Override
public GLDrawableFactory getFactory() {
- return drawable.getFactory();
+ return drawable.getFactory();
}
@Override
public void display() {
- if( null == drawable || !drawable.isRealized() || null == context ) { return; }
+ if( null != drawable && drawable.isRealized() && null != context ) {
helper.invokeGL(drawable, context, defaultDisplayAction, initAction);
+ }
}
//----------------------------------------------------------------------
diff --git a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java
index 448f68423..244a3fd79 100644
--- a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java
+++ b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java
@@ -39,7 +39,8 @@ public class GLRunnableTask implements GLRunnable {
GLRunnable runnable;
Object notifyObject;
boolean catchExceptions;
- boolean isExecuted;
+ volatile boolean isExecuted;
+ volatile boolean isFlushed;
Throwable runnableException;
@@ -48,6 +49,7 @@ public class GLRunnableTask implements GLRunnable {
this.notifyObject = notifyObject ;
this.catchExceptions = catchExceptions;
isExecuted = false;
+ isFlushed = false;
}
public boolean run(GLAutoDrawable drawable) {
@@ -84,8 +86,41 @@ public class GLRunnableTask implements GLRunnable {
}
return res;
}
-
+
+ /**
+ * Simply flush this task and notify a waiting executor.
+ * The executor which might have been blocked until notified
+ * will be unblocked and the task removed from the queue.
+ *
+ * @see #isFlushed()
+ * @see #isInQueue()
+ */
+ public void flush() {
+ if(!isExecuted() && null != notifyObject) {
+ synchronized (notifyObject) {
+ isFlushed=true;
+ notifyObject.notifyAll();
+ }
+ }
+ }
+
+ /**
+ * @return !{@link #isExecuted()} && !{@link #isFlushed()}
+ */
+ public boolean isInQueue() { return !isExecuted && !isFlushed; }
+
+ /**
+ * @return whether this task has been executed.
+ * @see #isInQueue()
+ */
public boolean isExecuted() { return isExecuted; }
+
+ /**
+ * @return whether this task has been flushed.
+ * @see #isInQueue()
+ */
+ public boolean isFlushed() { return isFlushed; }
+
public Throwable getThrowable() { return runnableException; }
}
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java
index f18b8cd02..b2217c095 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java
@@ -55,11 +55,6 @@ public class EGLPbufferDrawable extends EGLDrawable {
super(factory, target);
}
- @Override
- protected void destroyImpl() {
- setRealized(false);
- }
-
@Override
protected long createSurface(long eglDpy, long eglNativeCfg, long surfaceHandle) {
final AbstractGraphicsConfiguration config = getNativeSurface().getGraphicsConfiguration();
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java
index cae60702b..257635b8c 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java
@@ -151,8 +151,7 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl {
if (haveSetOpenGLMode) {
throw new GLException("Can't switch between using NSOpenGLPixelBuffer and CGLPBufferObj more than once");
}
-
- destroyImpl();
+ setRealized(false);
if (DEBUG) {
System.err.println("MacOSXCGLDrawable: Switching context mode " + openGLMode + " -> " + mode);
}
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java
index 6bdabbf59..4e9d18fed 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java
@@ -250,7 +250,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl {
}
}
}
- drawable.destroy();
+ drawable.setRealized(false);
}
}
sr = new SharedResource(sharedDevice, madeCurrent, hasNPOTTextures, hasRECTTextures, hasAppleFloatPixels);
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java
index 33021c521..242cea068 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java
@@ -79,11 +79,6 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable {
super(factory, target, false);
}
- @Override
- protected void destroyImpl() {
- setRealized(false);
- }
-
@Override
protected void setRealizedImpl() {
if(realized) {
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java
index dc3b58cfa..296d53ce3 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java
@@ -61,11 +61,6 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable {
super(factory, target, false);
}
- @Override
- protected void destroyImpl() {
- setRealized(false);
- }
-
@Override
protected void setRealizedImpl() {
if(realized) {
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java
index 244c1553f..05d6d9862 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java
@@ -70,7 +70,7 @@ public class WindowsDummyWGLDrawable extends WindowsWGLDrawable {
System.err.println("WindowsDummyWGLDrawable: "+config);
}
} catch (Throwable t) {
- destroyImpl();
+ setRealized(false);
throw new GLException(t);
} finally {
unlockSurface();
@@ -96,11 +96,14 @@ public class WindowsDummyWGLDrawable extends WindowsWGLDrawable {
}
@Override
- protected void destroyImpl() {
- if (handleHwndLifecycle && hwnd != 0) {
- GDI.ShowWindow(hwnd, GDI.SW_HIDE);
- GDIUtil.DestroyDummyWindow(hwnd);
- hwnd = 0;
+ protected void setRealizedImpl() {
+ super.setRealizedImpl();
+ if(!realized) {
+ if (handleHwndLifecycle && hwnd != 0) {
+ GDI.ShowWindow(hwnd, GDI.SW_HIDE);
+ GDIUtil.DestroyDummyWindow(hwnd);
+ hwnd = 0;
+ }
}
}
}
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java
index 762bea3b1..b00c796ec 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java
@@ -66,11 +66,6 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable {
super(factory, target, false);
}
- @Override
- protected void destroyImpl() {
- setRealized(false);
- }
-
@Override
protected void setRealizedImpl() {
if(realized) {
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java
index ddcb898a9..ca7886e7f 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java
@@ -62,15 +62,13 @@ public abstract class WindowsWGLDrawable extends GLDrawableImpl {
@Override
protected void setRealizedImpl() {
- if(!realized) {
- return; // nothing todo ..
- }
-
- NativeSurface ns = getNativeSurface();
- WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration)ns.getGraphicsConfiguration();
- config.updateGraphicsConfiguration(getFactory(), ns, null);
- if (DEBUG) {
- System.err.println("WindowsWGLDrawable.setRealized(true): "+config);
+ if(realized) {
+ NativeSurface ns = getNativeSurface();
+ WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration)ns.getGraphicsConfiguration();
+ config.updateGraphicsConfiguration(getFactory(), ns, null);
+ if (DEBUG) {
+ System.err.println("WindowsWGLDrawable.setRealized(true): "+config);
+ }
}
}
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java
index 054e1fe90..176d27a71 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java
@@ -373,7 +373,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl {
}
if (null != sr.drawable) {
- sr.drawable.destroy();
+ sr.drawable.setRealized(false);
sr.drawable = null;
}
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java
index 65f65a2ec..8914e2db9 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java
@@ -86,13 +86,17 @@ public class X11DummyGLXDrawable extends X11OnscreenGLXDrawable {
public int getHeight() {
return 1;
}
-
+
+
@Override
- protected void destroyImpl() {
- if(0!=dummyWindow) {
- destroyHandle();
- X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration();
- X11Lib.DestroyDummyWindow(config.getScreen().getDevice().getHandle(), dummyWindow);
+ protected void setRealizedImpl() {
+ super.setRealizedImpl();
+ if(!realized) {
+ if(0!=dummyWindow) {
+ destroyHandle();
+ X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration();
+ X11Lib.DestroyDummyWindow(config.getScreen().getDevice().getHandle(), dummyWindow);
+ }
}
}
}
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java
index 77af0d698..9a563bdb8 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java
@@ -304,7 +304,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl {
if (null != sr.drawable) {
// may cause JVM SIGSEGV:
- sr.drawable.destroy();
+ sr.drawable.setRealized(false);
sr.drawable = null;
}
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java
index 29003ef52..cdf81ebd3 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java
@@ -58,11 +58,6 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable {
super(factory, target, false);
}
- @Override
- protected void destroyImpl() {
- setRealized(false);
- }
-
@Override
protected void setRealizedImpl() {
if(realized) {
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java
index 18aa780b6..1e7b89828 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java
@@ -58,11 +58,6 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable {
super(factory, target, false);
}
- @Override
- protected void destroyImpl() {
- setRealized(false);
- }
-
@Override
protected void setRealizedImpl() {
if(realized) {
diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
index 6a328ed07..96baab3ae 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
@@ -53,7 +53,6 @@ import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLEventListener;
-import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
import jogamp.newt.WindowImpl;
@@ -109,37 +108,17 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
window.addWindowListener(new WindowAdapter() {
@Override
public void windowRepaint(WindowUpdateEvent e) {
- defaultRepaintOp();
+ defaultWindowRepaintOp();
}
@Override
public void windowResized(WindowEvent e) {
- defaultReshapeOp();
+ defaultWindowResizedOp();
}
@Override
public void windowDestroyNotify(WindowEvent e) {
- if( WindowClosingMode.DISPOSE_ON_CLOSE == GLWindow.this.getDefaultCloseOperation() ) {
- // Is an animator thread perform rendering?
- if (GLWindow.this.helper.isExternalAnimatorRunning()) {
- // Pause animations before initiating safe destroy.
- final GLAnimatorControl ctrl = GLWindow.this.helper.getAnimator();
- boolean isPaused = ctrl.pause();
- destroy();
- if(isPaused) {
- ctrl.resume();
- }
- } else if (GLWindow.this.window.isWindowLockedByOtherThread()) {
- // Window is locked by another thread
- // Flag that destroy should be performed on the next
- // attempt to display.
- sendDestroy = true;
- } else {
- // Without an external thread animating or locking the
- // surface, we are safe.
- destroy ();
- }
- }
+ defaultWindowDestroyNotifyOp();
}
});
this.window.setLifecycleHook(new GLLifecycleHook());
@@ -453,20 +432,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
//e1.printStackTrace();
}
- if( window.isNativeValid() && null != drawable && drawable.isRealized() ) {
- if( null != context && context.isCreated() ) {
- // Catch dispose GLExceptions by GLEventListener, just 'print' them
- // so we can continue with the destruction.
- try {
- helper.disposeGL(GLWindow.this, drawable, context, null);
- } catch (GLException gle) {
- gle.printStackTrace();
- }
- }
- drawable.setRealized(false);
- }
- context = null;
- drawable = null;
+ defaultDestroyOp();
if(Window.DEBUG_IMPLEMENTATION) {
System.err.println("GLWindow.destroy() "+Thread.currentThread()+", fin");
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java
index be9ae223b..a2d060a8c 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2012 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -30,60 +30,95 @@ package com.jogamp.opengl.test.junit.jogl.acore;
import java.io.IOException;
-import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLAutoDrawableDelegate;
import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
+import org.junit.Assert;
import org.junit.Test;
+import com.jogamp.newt.NewtFactory;
+import com.jogamp.newt.Window;
import com.jogamp.newt.event.WindowAdapter;
import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.event.WindowListener;
import com.jogamp.newt.event.WindowUpdateEvent;
import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
-import com.jogamp.opengl.test.junit.util.NEWTGLContext;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
import com.jogamp.opengl.test.junit.util.QuitAdapter;
import com.jogamp.opengl.test.junit.util.UITestCase;
+/**
+ * Demonstrates a full featured custom GLAutoDrawable implementation
+ * utilizing {@link GLAutoDrawableDelegate}.
+ */
public class TestGLAutoDrawableDelegateNEWT extends UITestCase {
- @Test
- public void test01() throws GLException, InterruptedException {
- final NEWTGLContext.WindowContext winctx = NEWTGLContext.createOnscreenWindow(
- new GLCapabilities(GLProfile.getGL2ES2()), 640, 480, false);
- winctx.context.release();
+ /** Note: Creates a full featured GLAutoDrawable w/ all window events connected. */
+ private GLAutoDrawable createGLAutoDrawable(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException {
+ final Window window = NewtFactory.createWindow(caps);
+ Assert.assertNotNull(window);
+ window.setPosition(x, y);
+ window.setSize(width, height);
+ window.setVisible(true);
+ Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true));
+ Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true));
+
+ GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
+ GLDrawable drawable = factory.createGLDrawable(window);
+ Assert.assertNotNull(drawable);
+
+ drawable.setRealized(true);
+ Assert.assertTrue(drawable.isRealized());
+
+ GLContext context = drawable.createContext(null);
+ Assert.assertNotNull(context);
+
+ int res = context.makeCurrent();
+ Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res);
+ context.release();
+
+ final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context) {
+ @Override
+ public void destroy() {
+ super.destroy(); // destroys drawable/context
+ window.destroy(); // destroys the actual window
+ }
+ };
- final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(winctx.drawable, winctx.context);
- glad.addGLEventListener(new GearsES2(1));
-
// add basic window interaction
- winctx.window.addWindowListener(new WindowAdapter() {
+ window.addWindowListener(new WindowAdapter() {
@Override
public void windowRepaint(WindowUpdateEvent e) {
- glad.defaultRepaintOp();
+ glad.defaultWindowRepaintOp();
}
@Override
public void windowResized(WindowEvent e) {
- glad.defaultReshapeOp();
+ glad.defaultWindowResizedOp();
}
@Override
public void windowDestroyNotify(WindowEvent e) {
- final GLAnimatorControl ctrl = glad.getAnimator();
- boolean isPaused = ctrl.pause();
- glad.destroy();
- NEWTGLContext.destroyWindow(winctx);
- if(isPaused) {
- ctrl.resume();
- }
+ glad.defaultWindowDestroyNotifyOp();
}
});
+ window.addWindowListener(wl);
+ return glad;
+ }
+
+ @Test
+ public void test01() throws GLException, InterruptedException {
final QuitAdapter quitAdapter = new QuitAdapter();
- winctx.window.addWindowListener(quitAdapter);
-
+ GLAutoDrawable glad = createGLAutoDrawable(new GLCapabilities(GLProfile.getGL2ES2()), 0, 0, 640, 480, quitAdapter);
+ glad.addGLEventListener(new GearsES2(1));
+
final Animator animator = new Animator(glad);
animator.setUpdateFPSFrames(60, null);
animator.start();
@@ -93,7 +128,8 @@ public class TestGLAutoDrawableDelegateNEWT extends UITestCase {
}
animator.stop();
- NEWTGLContext.destroyWindow(winctx);
+
+ glad.destroy();
}
static long duration = 2000; // ms
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java
index 22ed7c6fd..41c69336c 100644
--- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java
@@ -66,6 +66,57 @@ public class TestParenting01cSwingAWT extends UITestCase {
glCaps = new GLCapabilities(null);
}
+ static class GLDisturbanceAction implements Runnable {
+ public boolean isRunning = false;
+ private volatile boolean shallStop = false;
+ private final GLAutoDrawable glad;
+ private final GLRunnable glRunnable;
+
+ public GLDisturbanceAction(GLAutoDrawable glad) {
+ this.glad = glad;
+ this.glRunnable = new GLRunnableDummy();
+ }
+
+ public void waitUntilRunning() {
+ synchronized(this) {
+ while(!isRunning) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) { e.printStackTrace(); }
+ }
+ }
+ }
+
+ public void stopAndWaitUntilDone() {
+ shallStop = true;
+ synchronized(this) {
+ while(isRunning) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) { e.printStackTrace(); }
+ }
+ }
+ }
+
+ public void run() {
+ synchronized(this) {
+ isRunning = true;
+ this.notifyAll();
+ System.out.println("$");
+ }
+ while(!shallStop) {
+ try {
+ glad.invoke(true, glRunnable);
+ Thread.sleep(100);
+ } catch (Throwable t) {}
+ }
+ synchronized(this) {
+ isRunning = false;
+ this.notifyAll();
+ }
+ }
+ }
+
@Test
public void testWindowParenting01CreateVisibleDestroy1() throws InterruptedException, InvocationTargetException {
/**
@@ -84,22 +135,9 @@ public class TestParenting01cSwingAWT extends UITestCase {
animator1.setUpdateFPSFrames(1, null);
animator1.start();
- final GLWindow _glWindow1 = glWindow1;
- final GLRunnable _glRunnable = new GLRunnableDummy();
- Thread disturbanceThread = new Thread(new Runnable() {
- public void run() {
- System.out.println("$");
- while(true)
- {
- try {
- _glWindow1.invoke(true, _glRunnable);
- Thread.sleep(100);
- } catch (Throwable t) {}
- }
- }
- });
- disturbanceThread.start();
-
+ final GLDisturbanceAction disturbanceAction = new GLDisturbanceAction(glWindow1);
+ new Thread(disturbanceAction).start();
+ disturbanceAction.waitUntilRunning();
final NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow1);
Assert.assertNotNull(newtCanvasAWT);
@@ -175,6 +213,7 @@ public class TestParenting01cSwingAWT extends UITestCase {
} });
Assert.assertEquals(true, glWindow1.isNativeValid());
+ disturbanceAction.stopAndWaitUntilDone();
glWindow1.destroy();
Assert.assertEquals(false, glWindow1.isNativeValid());
}
@@ -192,26 +231,33 @@ public class TestParenting01cSwingAWT extends UITestCase {
glWindow1.setTitle("testWindowParenting01CreateVisibleDestroy");
GLEventListener demo1 = new RedSquareES2();
setDemoFields(demo1, glWindow1, false);
+ /*
+ glWindow1.addGLEventListener(new GLEventListener() {
+ @Override
+ public void init(GLAutoDrawable drawable) {
+ System.err.println("XXX init");
+ }
+ @Override
+ public void dispose(GLAutoDrawable drawable) {
+ System.err.println("XXX dispose");
+ // Thread.dumpStack();
+ }
+ @Override
+ public void display(GLAutoDrawable drawable) {}
+ @Override
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+ System.err.println("XXX reshape");
+ // Thread.dumpStack();
+ }
+ }); */
glWindow1.addGLEventListener(demo1);
Animator animator1 = new Animator(glWindow1);
animator1.setUpdateFPSFrames(1, null);
animator1.start();
-
- final GLWindow _glWindow1 = glWindow1;
- final GLRunnable _glRunnable = new GLRunnableDummy();
- Thread disturbanceThread = new Thread(new Runnable() {
- public void run() {
- System.out.println("$");
- while(true)
- {
- try {
- _glWindow1.invoke(true, _glRunnable);
- Thread.sleep(100);
- } catch (Throwable t) {}
- }
- }
- });
- disturbanceThread.start();
+
+ final GLDisturbanceAction disturbanceAction = new GLDisturbanceAction(glWindow1);
+ new Thread(disturbanceAction).start();
+ disturbanceAction.waitUntilRunning();
final NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow1);
Assert.assertNotNull(newtCanvasAWT);
@@ -298,6 +344,8 @@ public class TestParenting01cSwingAWT extends UITestCase {
animator1.stop();
Assert.assertEquals(false, animator1.isAnimating());
+ disturbanceAction.stopAndWaitUntilDone();
+
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
jFrame1.setVisible(false);
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java
index bc3988338..8e2c73e9d 100644
--- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java
@@ -111,8 +111,8 @@ public class TestParenting02NEWT extends UITestCase {
Assert.assertEquals(height,glWindow1.getHeight());
glWindow1.setTitle("testWindowParenting01NewtOnNewtParentChildDraw - PARENT");
glWindow1.setPosition(x,y);
- glWindow1.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo)));
- glWindow1.addWindowListener(new TraceWindowAdapter());
+ //glWindow1.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo)));
+ //glWindow1.addWindowListener(new TraceWindowAdapter());
GLEventListener demo1 = new RedSquareES2();
setDemoFields(demo1, window1, glWindow1, false);
@@ -132,8 +132,8 @@ public class TestParenting02NEWT extends UITestCase {
//Assert.assertEquals(height/2,glWindow2.getHeight());
glWindow2.setTitle("testWindowParenting01NewtOnNewtParentChildDraw - CHILD");
glWindow2.setPosition(glWindow1.getWidth()/2, glWindow1.getHeight()/2);
- glWindow2.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo)));
- glWindow2.addWindowListener(new TraceWindowAdapter(new WindowAction(eventFifo)));
+ //glWindow2.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo)));
+ //glWindow2.addWindowListener(new TraceWindowAdapter(new WindowAction(eventFifo)));
// glWindow2.addMouseListener(new TraceMouseAdapter());
GLEventListener demo2 = new GearsES2();
--
cgit v1.2.3
From 4b5a0f6557d7152ec770bc13ad3c494449de0529 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Sun, 22 Jul 2012 04:16:55 +0200
Subject: Fix Bug 606 - New AWT threading implementation breaks .. ; Fix
GLAutoDrawable multi-threading w/ proper pattern (hope so)
Considering code changes and remarks:
3ed491213f8f7f05d7b9866b50d764370d8ff5f6
1a91ec5c8b6fd9d9db7bc115569c369fe7b38e9b
3334a924309a9361a448d69bc707d4cce416b430
4f27bcecf7484dc041551f52a5c49e2884cb3867
It seems necessary to have
- recursive locking employed for all semantic actions which changes drawable & context (and the Window resource)
- to avoid deadlock, we have to ensure the locked code segment will not spawn
off to another thread, or a thread holds the lock, spawns of an action requiring the lock. .. sure
- other read-only methods (flags, ..) shall at least utilize a safe local copy of a volatile field
if further use to produce the result is necessary.
- flags like sendReshape require to be volatile to guarantee it's being processed
Patch impacts: AWT/SWT GLCanvas, GLAutoDrawableBase [and it's specializations]
and hopefully closes any loopholes of missing a cache hit, etc.
If you review this and find optimizations, i.e. removing a lock due to semantics etc,
don't hold back and discuss it, please.
---
.../classes/com/jogamp/opengl/swt/GLCanvas.java | 172 ++++++-----
.../javax/media/opengl/GLAutoDrawableDelegate.java | 44 ++-
.../classes/javax/media/opengl/awt/GLCanvas.java | 317 +++++++++++----------
.../classes/jogamp/opengl/GLAutoDrawableBase.java | 249 +++++++++++-----
.../classes/jogamp/opengl/GLDrawableHelper.java | 17 +-
src/jogl/classes/jogamp/opengl/GLPbufferImpl.java | 29 +-
.../classes/com/jogamp/newt/opengl/GLWindow.java | 36 +--
src/newt/classes/jogamp/newt/WindowImpl.java | 99 +++----
.../jogl/acore/TestGLAutoDrawableDelegateNEWT.java | 10 +-
.../acore/TestGLContextDrawableSwitchNEWT.java | 10 +-
.../jogl/acore/TestGLContextSurfaceLockNEWT.java | 92 ++++--
11 files changed, 649 insertions(+), 426 deletions(-)
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
index 0d9d3ddf5..64ee1c1ad 100644
--- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
+++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
@@ -63,25 +63,13 @@ import org.eclipse.swt.widgets.Shell;
import com.jogamp.common.GlueGenVersion;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.VersionUtil;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
import com.jogamp.nativewindow.swt.SWTAccessor;
import com.jogamp.opengl.JoglVersion;
/**
* Native SWT Canvas implementing GLAutoDrawable
- *
- * FIXME: If this instance runs in multithreading mode, see {@link Threading#isSingleThreaded()} (impossible),
- * proper recursive locking is required for drawable/context @ destroy and display.
- * Recreation etc could pull those instances while animating!
- * Simply locking before using drawable/context offthread
- * would allow a deadlock situation!
- *
- *
- * NOTE: [MT-0] Methods utilizing [volatile] drawable/context are not synchronized.
- In case any of the methods are called outside of a locked state
- extra care should be added. Maybe we shall expose locking facilities to the user.
- However, since the user shall stick to the GLEventListener model while utilizing
- GLAutoDrawable implementations, she is safe due to the implicit locked state.
- *
*/
public class GLCanvas extends Canvas implements GLAutoDrawable {
@@ -97,8 +85,9 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
//private static final boolean useSWTThread = ThreadingImpl.getMode() != ThreadingImpl.WORKER;
/* GL Stuff */
+ private final RecursiveLock lock = LockFactory.createRecursiveLock();
private final GLDrawableHelper helper = new GLDrawableHelper();
- private volatile GLDrawable drawable; // volatile avoids locking all accessors. FIXME still need to sync destroy/display
+ private volatile GLDrawable drawable; // volatile: avoid locking for read-only access
private GLContext context;
/* Native window surface */
@@ -112,7 +101,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
private final GLCapabilitiesImmutable glCapsRequested;
/* Flag indicating whether an unprocessed reshape is pending. */
- private volatile boolean sendReshape;
+ private volatile boolean sendReshape; // volatile: maybe written by WindowManager thread w/o locking
/*
* Invokes init(...) on all GLEventListeners. Assumes context is current when run.
@@ -141,10 +130,16 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
};
/* Action to make specified context current prior to running displayAction */
- private final Runnable makeCurrentAndDisplayAction = new Runnable() {
+ private final Runnable makeCurrentAndDisplayOnEDTAction = new Runnable() {
@Override
public void run() {
- helper.invokeGL(drawable, context, displayAction, initAction);
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ helper.invokeGL(drawable, context, displayAction, initAction);
+ } finally {
+ _lock.unlock();
+ }
}
};
@@ -157,10 +152,16 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
};
/* Swaps buffers, making the GLContext current first */
- private final Runnable makeCurrentAndSwapBuffersAction = new Runnable() {
+ private final Runnable makeCurrentAndSwapBuffersOnEDTAction = new Runnable() {
@Override
public void run() {
- helper.invokeGL(drawable, context, swapBuffersAction, initAction);
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ helper.invokeGL(drawable, context, swapBuffersAction, initAction);
+ } finally {
+ _lock.unlock();
+ }
}
};
@@ -181,16 +182,33 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
private final Runnable disposeOnEDTGLAction = new Runnable() {
@Override
public void run() {
- helper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction);
- }
- };
-
- private final Runnable disposeGraphicsDeviceAction = new Runnable() {
- @Override
- public void run() {
- if (null != device) {
- device.close();
- device = null;
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if (null != drawable && null != context) {
+ boolean animatorPaused = false;
+ final GLAnimatorControl animator = getAnimator();
+ if (null != animator) {
+ animatorPaused = animator.pause();
+ }
+
+ if(context.isCreated()) {
+ helper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction);
+ }
+
+ if (animatorPaused) {
+ animator.resume();
+ }
+ }
+ // SWT is owner of the device handle, not us.
+ // Hence close() operation is a NOP.
+ if (null != device) {
+ device.close();
+ device = null;
+ }
+ SWTAccessor.setRealized(GLCanvas.this, false); // unrealize ..
+ } finally {
+ _lock.unlock();
}
}
};
@@ -229,7 +247,8 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
clientArea = GLCanvas.this.getClientArea();
- /* Get the nativewindow-Graphics Device associated with this control (which is determined by the parent Composite) */
+ /* Get the nativewindow-Graphics Device associated with this control (which is determined by the parent Composite).
+ * Note: SWT is owner of the native handle, hence no closing operation will be a NOP. */
device = SWTAccessor.getDevice(this);
/* Since we have no means of querying the screen index yet, assume 0. Good choice due to Xinerama alike settings anyways. */
final int screenIdx = 0;
@@ -345,7 +364,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
@Override
public void display() {
- runInGLThread(makeCurrentAndDisplayAction);
+ runInGLThread(makeCurrentAndDisplayOnEDTAction);
}
@Override
@@ -370,7 +389,8 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
@Override
public GL getGL() {
- return (null == context) ? null : context.getGL();
+ final GLContext _context = context;
+ return (null == _context) ? null : _context.getGL();
}
@Override
@@ -400,27 +420,35 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
@Override
public GLContext setContext(GLContext newCtx) {
- final GLContext oldCtx = context;
- final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
- context=(GLContextImpl)newCtx;
- if(newCtxCurrent) {
- context.makeCurrent();
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final GLContext oldCtx = context;
+ final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
+ context=(GLContextImpl)newCtx;
+ if(newCtxCurrent) {
+ context.makeCurrent();
+ }
+ return oldCtx;
+ } finally {
+ _lock.unlock();
}
- return oldCtx;
}
@Override
public void setContextCreationFlags(final int arg0) {
additionalCtxCreationFlags = arg0;
- if(null != context) {
- context.setContextCreationFlags(additionalCtxCreationFlags);
+ final GLContext _context = context;
+ if(null != _context) {
+ _context.setContextCreationFlags(additionalCtxCreationFlags);
}
}
@Override
public GL setGL(final GL arg0) {
- if (null != context) {
- context.setGL(arg0);
+ final GLContext _context = context;
+ if (null != _context) {
+ _context.setGL(arg0);
return arg0;
}
return null;
@@ -428,12 +456,18 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
@Override
public GLContext createContext(final GLContext shareWith) {
- if(drawable != null) {
- final GLContext _ctx = drawable.createContext(shareWith);
- _ctx.setContextCreationFlags(additionalCtxCreationFlags);
- return _ctx;
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if(drawable != null) {
+ final GLContext _ctx = drawable.createContext(shareWith);
+ _ctx.setContextCreationFlags(additionalCtxCreationFlags);
+ return _ctx;
+ }
+ return null;
+ } finally {
+ _lock.unlock();
}
- return null;
}
@Override
@@ -452,7 +486,8 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
@Override
public GLDrawableFactory getFactory() {
- return (drawable != null) ? drawable.getFactory() : null;
+ final GLDrawable _drawable = drawable;
+ return (_drawable != null) ? _drawable.getFactory() : null;
}
@Override
@@ -462,17 +497,20 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
@Override
public long getHandle() {
- return (drawable != null) ? drawable.getHandle() : 0;
+ final GLDrawable _drawable = drawable;
+ return (_drawable != null) ? _drawable.getHandle() : 0;
}
@Override
public NativeSurface getNativeSurface() {
- return (drawable != null) ? drawable.getNativeSurface() : null;
+ final GLDrawable _drawable = drawable;
+ return (_drawable != null) ? _drawable.getNativeSurface() : null;
}
@Override
public boolean isRealized() {
- return (drawable != null) ? drawable.isRealized() : false;
+ final GLDrawable _drawable = drawable;
+ return (_drawable != null) ? _drawable.isRealized() : false;
}
@Override
@@ -482,41 +520,19 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
@Override
public void swapBuffers() throws GLException {
- runInGLThread(makeCurrentAndSwapBuffersAction);
+ runInGLThread(makeCurrentAndSwapBuffersOnEDTAction);
}
// FIXME: API of update() method ?
@Override
public void update() {
- // FIXME: display();
+ // FIXME: display(); ?
}
@Override
public void dispose() {
- if (null != drawable && null != context) { // drawable is volatile!
- boolean animatorPaused = false;
- final GLAnimatorControl animator = getAnimator();
- if (null != animator) {
- // can't remove us from animator for recreational addNotify()
- animatorPaused = animator.pause();
- }
-
- if(context.isCreated()) {
- runInGLThread(disposeOnEDTGLAction);
- }
-
- if (animatorPaused) {
- animator.resume();
- }
- }
- final Display display = getDisplay();
-
- if (display.getThread() == Thread.currentThread()) {
- disposeGraphicsDeviceAction.run();
- } else {
- display.syncExec(disposeGraphicsDeviceAction);
- }
- super.dispose();
+ runInGLThread(disposeOnEDTGLAction);
+ super.dispose();
}
/**
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
index 1f6166719..76959f3f4 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
@@ -67,18 +67,18 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase {
}
//
- // make protected methods accessible
+ // expose default methods
//
- public void defaultWindowRepaintOp() {
+ public final void windowRepaintOp() {
super.defaultWindowRepaintOp();
}
- public void defaultWindowResizedOp() {
+ public final void windowResizedOp() {
super.defaultWindowResizedOp();
}
- public void defaultWindowDestroyNotifyOp() {
+ public final void windowDestroyNotifyOp() {
super.defaultWindowDestroyNotifyOp();
}
@@ -89,6 +89,9 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase {
private final RecursiveLock lock = LockFactory.createRecursiveLock(); // instance wide lock
private final Object upstreamWidget;
+ @Override
+ protected final RecursiveLock getLock() { return lock; }
+
@Override
public final Object getUpstreamWidget() {
return upstreamWidget;
@@ -97,39 +100,21 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase {
/**
* {@inheritDoc}
*
- * This implementation calls {@link #defaultDestroyOp()}.
+ * This implementation calls {@link #defaultDestroy()}.
*
*
* User still needs to destroy the upstream window, which details are hidden from this aspect.
+ * This can be performed by overriding {@link #destroyImplInLock()}.
*
- * FIXME: If this instance runs in multithreading mode, see {@link Threading#isSingleThreaded()} (default: single-thread),
- * proper recursive locking is required for drawable/context @ destroy and display.
- * Recreation etc could pull those instances while animating!
- * Simply locking before using drawable/context offthread
- * would allow a deadlock situation!
- *
- *
- * NOTE: [MT-0] Methods utilizing [volatile] drawable/context are not synchronized.
- In case any of the methods are called outside of a locked state
- extra care should be added. Maybe we shall expose locking facilities to the user.
- However, since the user shall stick to the GLEventListener model while utilizing
- GLAutoDrawable implementations, she is safe due to the implicit locked state.
- *
*/
@SuppressWarnings("serial")
@@ -153,11 +141,12 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private static final boolean DEBUG = Debug.debug("GLCanvas");
+ private final RecursiveLock lock = LockFactory.createRecursiveLock();
private final GLDrawableHelper helper = new GLDrawableHelper();
private AWTGraphicsConfiguration awtConfig;
- private volatile GLDrawable drawable; // volatile avoids locking all accessors. FIXME still need to sync destroy/display
+ private volatile GLDrawable drawable; // volatile: avoid locking for read-only access
private GLContextImpl context;
- private boolean sendReshape = false;
+ private volatile boolean sendReshape = false; // volatile: maybe written by EDT w/o locking
// copy of the cstr args, mainly for recreation
private GLCapabilitiesImmutable capsReqUser;
@@ -278,8 +267,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@Override
public final boolean isOffscreenLayerSurfaceEnabled() {
- if(null != drawable) {
- return ((JAWTWindow)drawable.getNativeSurface()).isOffscreenLayerSurfaceEnabled();
+ final GLDrawable _drawable = drawable;
+ if(null != _drawable) {
+ return ((JAWTWindow)_drawable.getNativeSurface()).isOffscreenLayerSurfaceEnabled();
}
return false;
}
@@ -398,12 +388,18 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@Override
public GLContext createContext(final GLContext shareWith) {
- if(drawable != null) {
- final GLContext _ctx = drawable.createContext(shareWith);
- _ctx.setContextCreationFlags(additionalCtxCreationFlags);
- return _ctx;
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if(drawable != null) {
+ final GLContext _ctx = drawable.createContext(shareWith);
+ _ctx.setContextCreationFlags(additionalCtxCreationFlags);
+ return _ctx;
+ }
+ return null;
+ } finally {
+ _lock.unlock();
}
- return null;
}
@Override
@@ -412,7 +408,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@Override
public boolean isRealized() {
- return (null != drawable) ? drawable.isRealized() : false;
+ final GLDrawable _drawable = drawable;
+ return ( null != _drawable ) ? _drawable.isRealized() : false;
}
@Override
@@ -427,50 +424,13 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@Override
public void display() {
- if( !validateGLDrawable() ) {
- if(DEBUG) {
- System.err.println(getThreadName()+": Info: GLCanvas display - skipped GL render, drawable not valid yet");
- }
- return; // not yet available ..
- }
Threading.invoke(true, displayOnEDTAction, getTreeLock());
-
awtWindowClosingProtocol.addClosingListenerOneShot();
}
private void dispose(boolean regenerate) {
- final GLAnimatorControl animator = getAnimator();
- if(DEBUG) {
- System.err.println(getThreadName()+": Info: dispose("+regenerate+") - START, hasContext " +
- (null!=context) + ", hasDrawable " + (null!=drawable)+", "+animator);
- Thread.dumpStack();
- }
-
- if(null!=drawable && null!=context) { // drawable is volatile!
- boolean animatorPaused = false;
- if(null!=animator) {
- // can't remove us from animator for recreational addNotify()
- animatorPaused = animator.pause();
- }
-
- disposeRegenerate=regenerate;
-
- if(context.isCreated()) {
- Threading.invoke(true, disposeOnEDTAction, getTreeLock());
- }
-
- if(animatorPaused) {
- animator.resume();
- }
- }
-
- if(!regenerate) {
- disposeAbstractGraphicsDevice();
- }
-
- if(DEBUG) {
- System.err.println(getThreadName()+": dispose("+regenerate+") - END, "+animator);
- }
+ disposeRegenerate=regenerate;
+ Threading.invoke(true, disposeOnEDTAction, getTreeLock());
}
/**
@@ -530,43 +490,49 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@SuppressWarnings("deprecation")
@Override
public void addNotify() {
- if(DEBUG) {
- System.err.println(getThreadName()+": Info: addNotify - start, bounds: "+this.getBounds());
- Thread.dumpStack();
- }
-
- /**
- * 'super.addNotify()' determines the GraphicsConfiguration,
- * while calling this class's overriden 'getGraphicsConfiguration()' method
- * after which it creates the native peer.
- * Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration
- * is being used in getGraphicsConfiguration().
- * This code order also allows recreation, ie re-adding the GLCanvas.
- */
- awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device);
- if(null==awtConfig) {
- throw new GLException("Error: NULL AWTGraphicsConfiguration");
- }
-
- // before native peer is valid: X11
- disableBackgroundErase();
-
- // issues getGraphicsConfiguration() and creates the native peer
- super.addNotify();
-
- // after native peer is valid: Windows
- disableBackgroundErase();
-
- if (!Beans.isDesignTime()) {
- createDrawableAndContext();
- }
-
- // init drawable by paint/display makes the init sequence more equal
- // for all launch flavors (applet/javaws/..)
- // validateGLDrawable();
-
- if(DEBUG) {
- System.err.println(getThreadName()+": Info: addNotify - end: peer: "+getPeer());
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: addNotify - start, bounds: "+this.getBounds());
+ Thread.dumpStack();
+ }
+
+ /**
+ * 'super.addNotify()' determines the GraphicsConfiguration,
+ * while calling this class's overriden 'getGraphicsConfiguration()' method
+ * after which it creates the native peer.
+ * Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration
+ * is being used in getGraphicsConfiguration().
+ * This code order also allows recreation, ie re-adding the GLCanvas.
+ */
+ awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device);
+ if(null==awtConfig) {
+ throw new GLException("Error: NULL AWTGraphicsConfiguration");
+ }
+
+ // before native peer is valid: X11
+ disableBackgroundErase();
+
+ // issues getGraphicsConfiguration() and creates the native peer
+ super.addNotify();
+
+ // after native peer is valid: Windows
+ disableBackgroundErase();
+
+ if (!Beans.isDesignTime()) {
+ createDrawableAndContext();
+ }
+
+ // init drawable by paint/display makes the init sequence more equal
+ // for all launch flavors (applet/javaws/..)
+ // validateGLDrawable();
+
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: addNotify - end: peer: "+getPeer());
+ }
+ } finally {
+ _lock.unlock();
}
}
@@ -585,23 +551,24 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
private boolean validateGLDrawable() {
- boolean realized = false;
- if (!Beans.isDesignTime()) {
- if ( null != drawable ) { // OK: drawable is volatile
- realized = drawable.isRealized();
- if ( !realized && 0 < drawable.getWidth() * drawable.getHeight() ) {
- // make sure drawable realization happens on AWT EDT, due to AWTTree lock
- AWTEDTExecutor.singleton.invoke(true, setRealizedOnEDTAction);
- realized = true;
- sendReshape=true; // ensure a reshape is being send ..
- if(DEBUG) {
- System.err.println(getThreadName()+": Realized Drawable: "+drawable.toString());
- Thread.dumpStack();
- }
+ final GLDrawable _drawable = drawable;
+ if ( null != _drawable ) {
+ if( _drawable.isRealized() ) {
+ return true;
+ }
+ if (!Beans.isDesignTime() &&
+ 0 < _drawable.getWidth() * _drawable.getHeight() ) {
+ // make sure drawable realization happens on AWT EDT, due to AWTTree lock
+ AWTEDTExecutor.singleton.invoke(true, setRealizedOnEDTAction);
+ sendReshape=true; // ensure a reshape is being send ..
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Realized Drawable: "+_drawable.toString());
+ Thread.dumpStack();
}
+ return true;
}
}
- return realized;
+ return false;
}
private Runnable setRealizedOnEDTAction = new Runnable() {
@Override
@@ -633,9 +600,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
try {
dispose(false);
} finally {
- context=null;
- drawable=null;
- awtConfig=null;
super.removeNotify();
}
}
@@ -655,7 +619,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@Override
public void reshape(int x, int y, int width, int height) {
super.reshape(x, y, width, height);
- if(null != drawable && drawable.isRealized() && !drawable.getChosenGLCapabilities().isOnscreen()) {
+ final GLDrawable _drawable = drawable;
+ if(null != _drawable && _drawable.isRealized() && !_drawable.getChosenGLCapabilities().isOnscreen()) {
dispose(true);
} else {
sendReshape = true;
@@ -710,13 +675,19 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@Override
public GLContext setContext(GLContext newCtx) {
- final GLContext oldCtx = context;
- final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
- context=(GLContextImpl)newCtx;
- if(newCtxCurrent) {
- context.makeCurrent();
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final GLContext oldCtx = context;
+ final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
+ context=(GLContextImpl)newCtx;
+ if(newCtxCurrent) {
+ context.makeCurrent();
+ }
+ return oldCtx;
+ } finally {
+ _lock.unlock();
}
- return oldCtx;
}
@Override
@@ -729,15 +700,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
if (Beans.isDesignTime()) {
return null;
}
- GLContext ctx = getContext();
- return (ctx == null) ? null : ctx.getGL();
+ final GLContext _context = context;
+ return (_context == null) ? null : _context.getGL();
}
@Override
public GL setGL(GL gl) {
- GLContext ctx = getContext();
- if (ctx != null) {
- ctx.setGL(gl);
+ final GLContext _context = context;
+ if (_context != null) {
+ _context.setGL(gl);
return gl;
}
return null;
@@ -762,8 +733,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@Override
public void setContextCreationFlags(int flags) {
additionalCtxCreationFlags = flags;
- if(null != context) {
- context.setContextCreationFlags(additionalCtxCreationFlags);
+ final GLContext _context = context;
+ if(null != _context) {
+ _context.setContextCreationFlags(additionalCtxCreationFlags);
}
}
@@ -796,26 +768,30 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@Override
public NativeSurface getNativeSurface() {
- return (null != drawable) ? drawable.getNativeSurface() : null;
+ final GLDrawable _drawable = drawable;
+ return (null != _drawable) ? _drawable.getNativeSurface() : null;
}
@Override
public long getHandle() {
- return (null != drawable) ? drawable.getHandle() : 0;
+ final GLDrawable _drawable = drawable;
+ return (null != _drawable) ? _drawable.getHandle() : 0;
}
@Override
public GLDrawableFactory getFactory() {
- return (null != drawable) ? drawable.getFactory() : null;
+ final GLDrawable _drawable = drawable;
+ return (null != _drawable) ? _drawable.getFactory() : null;
}
@Override
public String toString() {
- final int dw = (null!=drawable) ? drawable.getWidth() : -1;
- final int dh = (null!=drawable) ? drawable.getHeight() : -1;
+ final GLDrawable _drawable = drawable;
+ final int dw = (null!=_drawable) ? _drawable.getWidth() : -1;
+ final int dh = (null!=_drawable) ? _drawable.getHeight() : -1;
return "AWT-GLCanvas[Realized "+isRealized()+
- ",\n\t"+((null!=drawable)?drawable.getClass().getName():"null-drawable")+
+ ",\n\t"+((null!=_drawable)?_drawable.getClass().getName():"null-drawable")+
",\n\tFactory "+getFactory()+
",\n\thandle 0x"+Long.toHexString(getHandle())+
",\n\tDrawable size "+dw+"x"+dh+
@@ -829,7 +805,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
//
private boolean disposeRegenerate;
- private final Runnable postDisposeAction = new Runnable() {
+ private final Runnable postDisposeOnEDTAction = new Runnable() {
@Override
public void run() {
context=null;
@@ -859,7 +835,47 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private final Runnable disposeOnEDTAction = new Runnable() {
@Override
public void run() {
- helper.disposeGL(GLCanvas.this, drawable, context, postDisposeAction);
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final GLAnimatorControl animator = getAnimator();
+
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: dispose("+disposeRegenerate+") - START, hasContext " +
+ (null!=context) + ", hasDrawable " + (null!=drawable)+", "+animator);
+ Thread.dumpStack();
+ }
+
+ if(null!=drawable && null!=context) {
+ boolean animatorPaused = false;
+ if(null!=animator) {
+ // can't remove us from animator for recreational addNotify()
+ animatorPaused = animator.pause();
+ }
+
+ if(context.isCreated()) {
+ helper.disposeGL(GLCanvas.this, drawable, context, postDisposeOnEDTAction);
+ }
+
+ if(animatorPaused) {
+ animator.resume();
+ }
+ }
+
+ if(!disposeRegenerate) {
+ if(null != awtConfig) {
+ disposeAbstractGraphicsDevice();
+ }
+ awtConfig=null;
+ }
+
+ if(DEBUG) {
+ System.err.println(getThreadName()+": dispose("+disposeRegenerate+") - END, "+animator);
+ }
+
+ } finally {
+ _lock.unlock();
+ }
}
};
@@ -879,7 +895,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
if(DEBUG) {
System.err.println(getThreadName()+": GLCanvas.dispose(false): closed GraphicsDevice: "+adeviceMsg+", result: "+closed);
}
- awtConfig=null;
}
}
};
@@ -890,7 +905,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
*
* @see #chooseGraphicsConfiguration(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, java.awt.GraphicsDevice)
*/
- void disposeAbstractGraphicsDevice() {
+ private void disposeAbstractGraphicsDevice() {
if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) {
disposeAbstractGraphicsDeviceAction.run();
} else {
@@ -941,14 +956,30 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private final Runnable displayOnEDTAction = new Runnable() {
@Override
public void run() {
- helper.invokeGL(drawable, context, displayAction, initAction);
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( validateGLDrawable() ) {
+ helper.invokeGL(drawable, context, displayAction, initAction);
+ } else if(DEBUG) {
+ System.err.println(getThreadName()+": Info: GLCanvas display - skipped GL render, drawable not valid yet");
+ }
+ } finally {
+ _lock.unlock();
+ }
}
};
private final Runnable swapBuffersOnEDTAction = new Runnable() {
@Override
public void run() {
- helper.invokeGL(drawable, context, swapBuffersAction, initAction);
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ helper.invokeGL(drawable, context, swapBuffersAction, initAction);
+ } finally {
+ _lock.unlock();
+ }
}
};
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index 5c6d7446a..fe6d0fd76 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -46,6 +46,7 @@ import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
import javax.media.opengl.GLRunnable;
+import com.jogamp.common.util.locks.RecursiveLock;
import com.jogamp.opengl.util.Animator;
@@ -63,11 +64,11 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
protected final GLDrawableHelper helper = new GLDrawableHelper();
protected final FPSCounterImpl fpsCounter = new FPSCounterImpl();
- protected GLDrawableImpl drawable;
+ protected volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access
protected GLContextImpl context;
protected int additionalCtxCreationFlags = 0;
- protected boolean sendReshape = false;
- protected boolean sendDestroy = false;
+ protected volatile boolean sendReshape = false; // volatile: maybe written by WindowManager thread w/o locking
+ protected volatile boolean sendDestroy = false; // volatile: maybe written by WindowManager thread w/o locking
public GLAutoDrawableBase(GLDrawableImpl drawable, GLContextImpl context) {
this.drawable = drawable;
@@ -75,31 +76,47 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
resetFPSCounter();
}
+ protected abstract RecursiveLock getLock();
+
/** Returns the delegated GLDrawable */
public final GLDrawable getDelegatedDrawable() { return drawable; }
/** Default implementation to handle repaint events from the windowing system */
- protected void defaultWindowRepaintOp() {
- if( null != drawable && drawable.isRealized() ) {
- if( !drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimating() ) {
+ protected final void defaultWindowRepaintOp() {
+ final GLDrawable _drawable = drawable;
+ if( null != _drawable && _drawable.isRealized() ) {
+ if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimating() ) {
display();
}
- }
+ }
}
/** Default implementation to handle resize events from the windowing system */
- protected void defaultWindowResizedOp() {
- if( null!=drawable ) {
+ protected final void defaultWindowResizedOp() {
+ final GLDrawable _drawable = drawable;
+ if( null!=_drawable ) {
if(DEBUG) {
System.err.println("GLAutoDrawableBase.sizeChanged: ("+Thread.currentThread().getName()+"): "+getWidth()+"x"+getHeight()+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle()));
}
- sendReshape = true;
- defaultWindowRepaintOp();
+ sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock
+ if( _drawable.isRealized() ) {
+ if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimating() ) {
+ display();
+ }
+ }
}
}
- /** Default implementation to handle destroy notifications from the windowing system */
- protected void defaultWindowDestroyNotifyOp() {
+ /**
+ * Default implementation to handle destroy notifications from the windowing system.
+ *
+ *
+ * If the {@link NativeSurface} does not implement {@link WindowClosingProtocol}
+ * or {@link WindowClosingMode#DISPOSE_ON_CLOSE} is enabled (default),
+ * {@link #defaultDestroy()} is being called.
+ *
+ */
+ protected final void defaultWindowDestroyNotifyOp() {
final NativeSurface ns = getNativeSurface();
final boolean shallClose;
if(ns instanceof WindowClosingProtocol) {
@@ -108,27 +125,66 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
shallClose = true;
}
if( shallClose ) {
- // Is an animator thread perform rendering?
- if (helper.isExternalAnimatorRunning()) {
- // Pause animations before initiating safe destroy.
- final GLAnimatorControl ctrl = helper.getAnimator();
- final boolean isPaused = ctrl.pause();
- destroy();
- if(isPaused) {
- ctrl.resume();
- }
- } else if (null != ns && ns.isSurfaceLockedByOtherThread()) {
- // surface is locked by another thread
- // Flag that destroy should be performed on the next
- // attempt to display.
- sendDestroy = true;
- } else {
- // Without an external thread animating or locking the
- // surface, we are safe.
- destroy ();
- }
+ destroyAvoidAwareOfLocking();
}
}
+
+ /**
+ * Calls {@link #destroy()}
+ * directly if the following requirements are met:
+ *
+ *
An {@link GLAnimatorControl} is bound (see {@link #getAnimator()}) and running on another thread.
+ * Here we pause the animation while issuing the destruction.
+ *
Surface is not locked by another thread (considered anonymous).
+ *
+ *
+ * Otherwise destroy is being flagged to be called within the next
+ * call of display().
+ *
+ *
+ * This method is being used to avoid deadlock if
+ * destruction is desired by other threads, e.g. the window manager.
+ *
+ * @see #defaultWindowDestroyNotifyOp()
+ * @see #defaultDisplay()
+ */
+ protected final void destroyAvoidAwareOfLocking() {
+ final NativeSurface ns = getNativeSurface();
+
+ final GLAnimatorControl ctrl = helper.getAnimator();
+
+ // Is an animator thread perform rendering?
+ if ( helper.isAnimatorRunningOnOtherThread() ) {
+ // Pause animations before initiating safe destroy.
+ final boolean isPaused = ctrl.pause();
+ destroy();
+ if(isPaused) {
+ ctrl.resume();
+ }
+ } else if (null != ns && ns.isSurfaceLockedByOtherThread()) {
+ // surface is locked by another thread
+ // Flag that destroy should be performed on the next
+ // attempt to display.
+ sendDestroy = true; // async, but avoiding deadlock
+ } else {
+ // Without an external thread animating or locking the
+ // surface, we are safe.
+ destroy();
+ }
+ }
+
+ /**
+ * Calls {@link #destroyImplInLock()} while claiming the lock.
+ */
+ protected final void defaultDestroy() {
+ final RecursiveLock lock = getLock();
+ lock.lock();
+ try {
+ destroyImplInLock();
+ } finally {
+ lock.unlock();
+ }
+ }
/**
* Default implementation to destroys the drawable and context of this GLAutoDrawable:
@@ -137,24 +193,42 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
*
destroys the GLContext, if valid
*
destroys the GLDrawable, if valid
*
+ *
Method assumes the lock is being hold.
+ *
Override it to extend it to destroy your resources, i.e. the actual window.
+ * In such case call super.destroyImplInLock first.
*/
- protected void defaultDestroyOp() {
- if( null != drawable && drawable.isRealized() ) {
- if( null != context && context.isCreated() ) {
+ protected void destroyImplInLock() {
+ final GLContext _context = context;
+ final GLDrawable _drawable = drawable;
+ if( null != _drawable && _drawable.isRealized() ) {
+ if( null != _context && _context.isCreated() ) {
// Catch dispose GLExceptions by GLEventListener, just 'print' them
// so we can continue with the destruction.
try {
- helper.disposeGL(this, drawable, context, null);
+ helper.disposeGL(this, _drawable, _context, null);
} catch (GLException gle) {
gle.printStackTrace();
}
}
- drawable.setRealized(false);
+ _drawable.setRealized(false);
}
context = null;
drawable = null;
}
+ public final void defaultSwapBuffers() throws GLException {
+ final RecursiveLock _lock = getLock();
+ _lock.lock();
+ try {
+ if(drawable!=null && context != null) {
+ drawable.swapBuffers();
+ helper.invokeGL(drawable, context, defaultSwapAction, defaultInitAction);
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+
//
// GLAutoDrawable
//
@@ -179,6 +253,30 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
fpsCounter.tickFPS();
} };
+ protected final void defaultDisplay() {
+ if( sendDestroy ) {
+ sendDestroy=false;
+ destroy();
+ return;
+ }
+ final RecursiveLock _lock = getLock();
+ _lock.lock();
+ try {
+ if( null != context ) {
+ // surface is locked/unlocked implicit by context's makeCurrent/release
+ helper.invokeGL(drawable, context, defaultDisplayAction, defaultInitAction);
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+
+ protected final Runnable defaultSwapAction = new Runnable() {
+ @Override
+ public final void run() {
+ drawable.swapBuffers();
+ } } ;
+
@Override
public final GLContext getContext() {
return context;
@@ -186,27 +284,35 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
@Override
public final GLContext setContext(GLContext newCtx) {
- final GLContext oldCtx = context;
- final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
- context=(GLContextImpl)newCtx;
- if(newCtxCurrent) {
- context.makeCurrent();
+ final RecursiveLock lock = getLock();
+ lock.lock();
+ try {
+ final GLContext oldCtx = context;
+ final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
+ context=(GLContextImpl)newCtx;
+ if(newCtxCurrent) {
+ context.makeCurrent();
+ }
+ return oldCtx;
+ } finally {
+ lock.unlock();
}
- return oldCtx;
}
@Override
public final GL getGL() {
- if (context == null) {
+ final GLContext _context = context;
+ if (_context == null) {
return null;
}
- return context.getGL();
+ return _context.getGL();
}
@Override
public final GL setGL(GL gl) {
- if (context != null) {
- context.setGL(gl);
+ final GLContext _context = context;
+ if (_context != null) {
+ _context.setGL(gl);
return gl;
}
return null;
@@ -261,8 +367,9 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
@Override
public final void setContextCreationFlags(int flags) {
additionalCtxCreationFlags = flags;
- if(null != context) {
- context.setContextCreationFlags(additionalCtxCreationFlags);
+ final GLContext _context = context;
+ if(null != _context) {
+ _context.setContextCreationFlags(additionalCtxCreationFlags);
}
}
@@ -331,27 +438,36 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
@Override
public final GLContext createContext(final GLContext shareWith) {
- if(drawable != null) {
- final GLContext _ctx = drawable.createContext(shareWith);
- _ctx.setContextCreationFlags(additionalCtxCreationFlags);
- return _ctx;
+ final RecursiveLock lock = getLock();
+ lock.lock();
+ try {
+ if(drawable != null) {
+ final GLContext _ctx = drawable.createContext(shareWith);
+ _ctx.setContextCreationFlags(additionalCtxCreationFlags);
+ return _ctx;
+ }
+ return null;
+ } finally {
+ lock.unlock();
}
- return null;
}
@Override
public final boolean isRealized() {
- return null != drawable ? drawable.isRealized() : false;
+ final GLDrawable _drawable = drawable;
+ return null != _drawable ? _drawable.isRealized() : false;
}
@Override
public int getWidth() {
- return null != drawable ? drawable.getWidth() : 0;
+ final GLDrawable _drawable = drawable;
+ return null != _drawable ? _drawable.getWidth() : 0;
}
@Override
public int getHeight() {
- return null != drawable ? drawable.getHeight() : 0;
+ final GLDrawable _drawable = drawable;
+ return null != _drawable ? _drawable.getHeight() : 0;
}
/**
@@ -373,30 +489,27 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
return helper.getSkipContextReleaseThread();
}
- @Override
- public final void swapBuffers() throws GLException {
- if(drawable!=null && context != null) {
- drawable.swapBuffers();
- }
- }
-
@Override
public final GLCapabilitiesImmutable getChosenGLCapabilities() {
- return null != drawable ? drawable.getChosenGLCapabilities() : null;
+ final GLDrawable _drawable = drawable;
+ return null != _drawable ? _drawable.getChosenGLCapabilities() : null;
}
@Override
public final GLProfile getGLProfile() {
- return null != drawable ? drawable.getGLProfile() : null;
+ final GLDrawable _drawable = drawable;
+ return null != _drawable ? _drawable.getGLProfile() : null;
}
@Override
public final NativeSurface getNativeSurface() {
- return null != drawable ? drawable.getNativeSurface() : null;
+ final GLDrawable _drawable = drawable;
+ return null != _drawable ? _drawable.getNativeSurface() : null;
}
@Override
public final long getHandle() {
- return null != drawable ? drawable.getHandle() : 0;
+ final GLDrawable _drawable = drawable;
+ return null != _drawable ? _drawable.getHandle() : 0;
}
}
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
index 0c01aa676..090c5fe69 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
@@ -189,8 +189,9 @@ public class GLDrawableHelper {
*/
public final void dispose(GLAutoDrawable drawable) {
synchronized(listenersLock) {
- for (int i=0; i < listeners.size(); i++) {
- listeners.get(i).dispose(drawable);
+ final ArrayList _listeners = listeners;
+ for (int i=0; i < _listeners.size(); i++) {
+ _listeners.get(i).dispose(drawable);
}
}
}
@@ -209,8 +210,9 @@ public class GLDrawableHelper {
/** The default init action to be called once after ctx is being created @ 1st makeCurrent(). */
public final void init(GLAutoDrawable drawable) {
synchronized(listenersLock) {
- for (int i=0; i < listeners.size(); i++) {
- final GLEventListener listener = listeners.get(i) ;
+ final ArrayList _listeners = listeners;
+ for (int i=0; i < _listeners.size(); i++) {
+ final GLEventListener listener = _listeners.get(i) ;
// If make current ctx, invoked by invokGL(..), results in a new ctx, init gets called.
// This may happen not just for initial setup, but for ctx recreation due to resource change (drawable/window),
@@ -232,8 +234,9 @@ public class GLDrawableHelper {
}
private final void displayImpl(GLAutoDrawable drawable) {
synchronized(listenersLock) {
- for (int i=0; i < listeners.size(); i++) {
- final GLEventListener listener = listeners.get(i) ;
+ final ArrayList _listeners = listeners;
+ for (int i=0; i < _listeners.size(); i++) {
+ final GLEventListener listener = _listeners.get(i) ;
// GLEventListener may need to be init,
// in case this one is added after the realization of the GLAutoDrawable
init( listener, drawable, true /* sendReshape */) ;
@@ -324,7 +327,7 @@ public class GLDrawableHelper {
}
}
- public final boolean isExternalAnimatorRunning() {
+ public final boolean isAnimatorRunningOnOtherThread() {
return ( null != animatorCtrl ) ? animatorCtrl.isStarted() && animatorCtrl.getThread() != Thread.currentThread() : false ;
}
diff --git a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
index bbc28e283..6b64120fe 100644
--- a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
@@ -42,10 +42,14 @@ package jogamp.opengl;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
import javax.media.opengl.GLPbuffer;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+
/** Platform-independent class exposing pbuffer functionality to
applications. This class is not exposed in the public API as it
would probably add no value; however it implements the GLDrawable
@@ -101,7 +105,7 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer {
//
// GLDrawable delegation
//
-
+
@Override
public final void setRealized(boolean realized) {
}
@@ -109,6 +113,10 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer {
//
// GLAutoDrawable completion
//
+ private final RecursiveLock lock = LockFactory.createRecursiveLock(); // instance wide lock
+
+ @Override
+ protected final RecursiveLock getLock() { return lock; }
@Override
public final Object getUpstreamWidget() {
@@ -117,7 +125,7 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer {
@Override
public void destroy() {
- defaultDestroyOp();
+ defaultDestroy();
}
@Override
@@ -126,12 +134,23 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer {
}
@Override
- public void display() {
- if( null != drawable && drawable.isRealized() && null != context ) {
- helper.invokeGL(drawable, context, defaultDisplayAction, initAction);
+ public final void display() {
+ final RecursiveLock _lock = lock;
+ _lock.lock(); // sync: context/drawable could been recreated/destroyed while animating
+ try {
+ if( null != context ) {
+ helper.invokeGL(drawable, context, defaultDisplayAction, initAction);
+ }
+ } finally {
+ _lock.unlock();
}
}
+ @Override
+ public final void swapBuffers() throws GLException {
+ defaultSwapBuffers();
+ }
+
//----------------------------------------------------------------------
// Internals only below this point
//
diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
index 32d44502f..2205aec8e 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
@@ -53,6 +53,7 @@ import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
import jogamp.newt.WindowImpl;
@@ -62,6 +63,7 @@ import jogamp.opengl.GLDrawableImpl;
import com.jogamp.common.GlueGenVersion;
import com.jogamp.common.util.VersionUtil;
+import com.jogamp.common.util.locks.RecursiveLock;
import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.Screen;
import com.jogamp.newt.Window;
@@ -87,13 +89,6 @@ import com.jogamp.opengl.JoglVersion;
* you can inject {@link javax.media.opengl.GLRunnable} objects
* via {@link #invoke(boolean, javax.media.opengl.GLRunnable)} to the OpenGL command stream.
*
- *
- * NOTE: [MT-0] Methods utilizing [volatile] drawable/context are not synchronized.
- In case any of the methods are called outside of a locked state
- extra care should be added. Maybe we shall expose locking facilities to the user.
- However, since the user shall stick to the GLEventListener model while utilizing
- GLAutoDrawable implementations, she is safe due to the implicit locked state.
- *
*/
public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Window, NEWTEventConsumer, FPSCounter {
private final WindowImpl window;
@@ -437,7 +432,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
//e1.printStackTrace();
}
- defaultDestroyOp();
+ destroyImplInLock();
if(Window.DEBUG_IMPLEMENTATION) {
System.err.println("GLWindow.destroy() "+WindowImpl.getThreadName()+", fin");
@@ -515,6 +510,11 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
private GLContext sharedContext = null;
+ @Override
+ protected final RecursiveLock getLock() {
+ return window.getLock();
+ }
+
/**
* Specifies an {@link javax.media.opengl.GLContext OpenGL context} to share with.
* At native creation, {@link #setVisible(boolean) setVisible(true)},
@@ -537,19 +537,18 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
return;
}
- window.lockWindow(); // sync: context/drawable could have been recreated/destroyed while animating
+ final RecursiveLock lock = window.getLock();
+ lock.lock(); // sync: context/drawable could have been recreated/destroyed while animating
try {
- if( null == context && 0 display
+ setVisible(true);
}
} finally {
- window.unlockWindow();
+ lock.unlock();
}
}
@@ -559,7 +558,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
private GLDrawableFactory factory;
@Override
- public GLDrawableFactory getFactory() {
+ public final GLDrawableFactory getFactory() {
return factory;
}
@@ -567,6 +566,11 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
public final void setRealized(boolean realized) {
}
+ @Override
+ public final void swapBuffers() throws GLException {
+ defaultSwapBuffers();
+ }
+
//----------------------------------------------------------------------
// NEWTEventConsumer
//
diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java
index 002144b2f..b12e42680 100644
--- a/src/newt/classes/jogamp/newt/WindowImpl.java
+++ b/src/newt/classes/jogamp/newt/WindowImpl.java
@@ -564,9 +564,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
@Override
public final int lockSurface() throws NativeWindowException, RuntimeException {
- windowLock.lock();
- surfaceLock.lock();
- int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ?
+ final RecursiveLock _wlock = windowLock;
+ final RecursiveLock _slock = surfaceLock;
+ _wlock.lock();
+ _slock.lock();
+ int res = _slock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ?
if ( LOCK_SURFACE_NOT_READY == res ) {
try {
@@ -583,8 +585,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
} finally {
if (LOCK_SURFACE_NOT_READY >= res) {
- surfaceLock.unlock();
- windowLock.unlock();
+ _slock.unlock();
+ _wlock.unlock();
}
}
}
@@ -593,10 +595,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
@Override
public final void unlockSurface() {
- surfaceLock.validateLocked();
- windowLock.validateLocked();
+ final RecursiveLock _slock = surfaceLock;
+ final RecursiveLock _wlock = windowLock;
+ _slock.validateLocked();
+ _wlock.validateLocked();
- if (surfaceLock.getHoldCount() == 1) {
+ if (_slock.getHoldCount() == 1) {
final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
try {
unlockSurfaceImpl();
@@ -604,8 +608,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
adevice.unlock();
}
}
- surfaceLock.unlock();
- windowLock.unlock();
+ _slock.unlock();
+ _wlock.unlock();
}
@Override
@@ -618,21 +622,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
return surfaceLock.getOwner();
}
- public final void lockWindow() {
- windowLock.lock();
- }
- public final void unlockWindow() {
- windowLock.unlock();
+ public final RecursiveLock getLock() {
+ return windowLock;
}
- public final boolean isWindowLockedByOtherThread() {
- return windowLock.isLockedByOtherThread();
- }
-
- public final Thread getWindowLockOwner() {
- return windowLock.getOwner();
- }
-
public long getSurfaceHandle() {
return windowHandle; // default: return window handle
}
@@ -670,11 +663,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
public Point getLocationOnScreen(Point storage) {
if(isNativeValid()) {
Point d;
- windowLock.lock();
+ final RecursiveLock _lock = windowLock;
+ _lock.lock();
try {
d = getLocationOnScreenImpl(0, 0);
} finally {
- windowLock.unlock();
+ _lock.unlock();
}
if(null!=d) {
if(null!=storage) {
@@ -717,7 +711,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
boolean nativeWindowCreated = false;
boolean madeVisible = false;
- windowLock.lock();
+ final RecursiveLock _lock = windowLock;
+ _lock.lock();
try {
if(null!=lifecycleHook) {
lifecycleHook.resetCounter();
@@ -739,7 +734,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
madeVisible = nativeWindowCreated;
}
// always flag visible, allowing a retry ..
- WindowImpl.this.visible = true;
+ WindowImpl.this.visible = true;
} else if(WindowImpl.this.visible != visible) {
if(isNativeValid()) {
setVisibleImpl(visible, getX(), getY(), getWidth(), getHeight());
@@ -766,7 +761,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
System.err.println("Window setVisible: END ("+getThreadName()+") "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+WindowImpl.this.visible+", nativeWindowCreated: "+nativeWindowCreated+", madeVisible: "+madeVisible);
}
} finally {
- windowLock.unlock();
+ _lock.unlock();
}
if( nativeWindowCreated || madeVisible ) {
sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener
@@ -801,7 +796,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
public final void run() {
boolean recreate = false;
- windowLock.lock();
+ final RecursiveLock _lock = windowLock;
+ _lock.lock();
try {
if ( !isFullscreen() && ( getWidth() != width || getHeight() != height ) ) {
recreate = isNativeValid() && !getGraphicsConfiguration().getChosenCapabilities().isOnscreen();
@@ -842,7 +838,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(recreate) {
screen.removeReference(); // bring back ref-count
}
- windowLock.unlock();
+ _lock.unlock();
}
}
}
@@ -863,7 +859,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(null!=lifecycleHook) {
lifecycleHook.destroyActionPreLock();
}
- windowLock.lock();
+ final RecursiveLock _lock = windowLock;
+ _lock.lock();
try {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window DestroyAction() "+getThreadName());
@@ -917,7 +914,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
hasFocus = false;
parentWindowHandle = 0;
- windowLock.unlock();
+ _lock.unlock();
}
if(animatorPaused) {
lifecycleHook.resumeRenderingAction();
@@ -1002,8 +999,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
int width = getWidth();
int height = getHeight();
boolean wasVisible;
-
- windowLock.lock();
+
+ final RecursiveLock _lock = windowLock;
+ _lock.lock();
try {
if(isNativeValid()) {
// force recreation if offscreen, since it may become onscreen
@@ -1220,7 +1218,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
System.err.println("Window.reparentWindow: END-1 ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+ Display.hashCodeNullSafe(parentWindow)+" "+x+"/"+y+" "+width+"x"+height);
}
} finally {
- windowLock.unlock();
+ _lock.unlock();
}
if(wasVisible) {
switch (operation) {
@@ -1245,7 +1243,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
private class ReparentActionRecreate implements Runnable {
public final void run() {
- windowLock.lock();
+ final RecursiveLock _lock = windowLock;
+ _lock.lock();
try {
visible = true;
if(DEBUG_IMPLEMENTATION) {
@@ -1253,7 +1252,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
setVisible(true); // native creation
} finally {
- windowLock.unlock();
+ _lock.unlock();
}
}
}
@@ -1291,7 +1290,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
public final void run() {
- windowLock.lock();
+ final RecursiveLock _lock = windowLock;
+ _lock.lock();
try {
if(WindowImpl.this.undecorated != undecorated) {
// set current state
@@ -1311,7 +1311,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
} finally {
- windowLock.unlock();
+ _lock.unlock();
}
sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener
}
@@ -1333,7 +1333,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
public final void run() {
- windowLock.lock();
+ final RecursiveLock _lock = windowLock;
+ _lock.lock();
try {
if(WindowImpl.this.alwaysOnTop != alwaysOnTop) {
// set current state
@@ -1353,7 +1354,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
} finally {
- windowLock.unlock();
+ _lock.unlock();
}
sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener
}
@@ -1545,7 +1546,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
"\n, ParentWindow "+parentWindow+
"\n, ParentWindowHandle "+toHexString(parentWindowHandle)+" ("+(0!=getParentWindowHandle())+")"+
"\n, WindowHandle "+toHexString(getWindowHandle())+
- "\n, SurfaceHandle "+toHexString(getSurfaceHandle())+ " (lockedExt window "+isWindowLockedByOtherThread()+", surface "+isSurfaceLockedByOtherThread()+")"+
+ "\n, SurfaceHandle "+toHexString(getSurfaceHandle())+ " (lockedExt window "+windowLock.isLockedByOtherThread()+", surface "+isSurfaceLockedByOtherThread()+")"+
"\n, Pos "+getX()+"/"+getY()+" (auto "+autoPosition()+"), size "+getWidth()+"x"+getHeight()+
"\n, Visible "+isVisible()+", focus "+hasFocus()+
"\n, Undecorated "+undecorated+" ("+isUndecorated()+")"+
@@ -1675,7 +1676,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
public final void run() {
- windowLock.lock();
+ final RecursiveLock _lock = windowLock;
+ _lock.lock();
try {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window setPosition: "+getX()+"/"+getY()+" -> "+x+"/"+y+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle));
@@ -1689,7 +1691,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
} finally {
- windowLock.unlock();
+ _lock.unlock();
}
}
}
@@ -1718,7 +1720,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
public boolean fsOn() { return fullscreen; }
public final void run() {
- windowLock.lock();
+ final RecursiveLock _lock = windowLock;
+ _lock.lock();
try {
// set current state
WindowImpl.this.fullscreen = fullscreen;
@@ -1795,7 +1798,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
} finally {
- windowLock.unlock();
+ _lock.unlock();
}
sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener
}
@@ -1917,7 +1920,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
// special repaint treatment
case WindowEvent.EVENT_WINDOW_REPAINT:
// queue repaint event in case window is locked, ie in operation
- if( null != getWindowLockOwner() ) {
+ if( null != windowLock.getOwner() ) {
// make sure only one repaint event is queued
if(!repaintQueued) {
repaintQueued=true;
@@ -1936,7 +1939,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
// common treatment
case WindowEvent.EVENT_WINDOW_RESIZED:
// queue event in case window is locked, ie in operation
- if( null != getWindowLockOwner() ) {
+ if( null != windowLock.getOwner() ) {
final boolean discardTO = QUEUED_EVENT_TO <= System.currentTimeMillis()-e.getWhen();
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.consumeEvent: "+Thread.currentThread().getName()+" - queued "+e+", discard-to "+discardTO);
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java
index eb716677d..426b7734f 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java
@@ -87,8 +87,8 @@ public class TestGLAutoDrawableDelegateNEWT extends UITestCase {
final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context, window) {
@Override
- public void destroy() {
- super.destroy(); // destroys drawable/context
+ protected void destroyImplInLock() {
+ super.destroyImplInLock(); // destroys drawable/context
window.destroy(); // destroys the actual window
}
};
@@ -97,15 +97,15 @@ public class TestGLAutoDrawableDelegateNEWT extends UITestCase {
window.addWindowListener(new WindowAdapter() {
@Override
public void windowRepaint(WindowUpdateEvent e) {
- glad.defaultWindowRepaintOp();
+ glad.windowRepaintOp();
}
@Override
public void windowResized(WindowEvent e) {
- glad.defaultWindowResizedOp();
+ glad.windowResizedOp();
}
@Override
public void windowDestroyNotify(WindowEvent e) {
- glad.defaultWindowDestroyNotifyOp();
+ glad.windowDestroyNotifyOp();
}
});
window.addWindowListener(wl);
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
index 06aa29b4f..92b4c5238 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
@@ -90,8 +90,8 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, null, window) {
@Override
- public void destroy() {
- super.destroy(); // destroys drawable/context
+ protected void destroyImplInLock() {
+ super.destroyImplInLock();
window.destroy(); // destroys the actual window
}
};
@@ -100,15 +100,15 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
window.addWindowListener(new WindowAdapter() {
@Override
public void windowRepaint(WindowUpdateEvent e) {
- glad.defaultWindowRepaintOp();
+ glad.windowRepaintOp();
}
@Override
public void windowResized(WindowEvent e) {
- glad.defaultWindowResizedOp();
+ glad.windowResizedOp();
}
@Override
public void windowDestroyNotify(WindowEvent e) {
- glad.defaultWindowDestroyNotifyOp();
+ glad.windowDestroyNotifyOp();
}
});
window.addWindowListener(wl);
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java
index 78988c0e5..b3516d6b4 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java
@@ -33,9 +33,9 @@ import java.io.IOException;
import javax.media.nativewindow.NativeSurface;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
-import org.junit.Assert;
import org.junit.Test;
import com.jogamp.newt.opengl.GLWindow;
@@ -69,7 +69,7 @@ public class TestGLContextSurfaceLockNEWT extends UITestCase {
}
public void run() {
- System.err.println("Animatr "+id+": PRE: "+Thread.currentThread().getName());
+ System.err.println("Animatr "+id+", count "+frameCount+": PRE: "+Thread.currentThread().getName());
for(int c=0; c
Date: Fri, 3 Aug 2012 01:38:37 +0300
Subject: Fix X11 Display Connection leak w/ new GLAutoDrawableBase code when
used w/ offscreen drawables, reported by Mark Raynsford
New common GLAutoDrawableBase missed to close the AbstractGraphicsDevice
in case it has been created and dedicated for the passed GLDrawable.
This detailed knowledge is only known to the creator, hence it is passed
in the constructor and is being passed through all specializations.
Further more the new X11/GLX impl. of GLDrawableFactory's
'createMutableSurfaceImpl' always creates it's own private X11 display connection
to avoid locking / threading issues. Since the old implementation reused the
shared display connection which is prone to threading issues, this bug was not visible before.
Also fixed the unit test TestNEWTCloseX11DisplayBug565,
now correctly validating that no display connection is left over
after a new cycle of create/destroy of onscreen and offscreen drawables.
---
make/scripts/tests.sh | 6 ++--
.../com/jogamp/opengl/OffscreenAutoDrawable.java | 13 ++++++--
.../javax/media/opengl/GLAutoDrawableDelegate.java | 14 +++++---
.../classes/jogamp/opengl/GLAutoDrawableBase.java | 39 ++++++++++++++++------
.../jogamp/opengl/GLDrawableFactoryImpl.java | 2 +-
src/jogl/classes/jogamp/opengl/GLPbufferImpl.java | 4 +--
.../classes/jogamp/nativewindow/x11/X11Util.java | 2 +-
.../classes/com/jogamp/newt/opengl/GLWindow.java | 2 +-
.../test/junit/jogl/acore/TestFBODrawableNEWT.java | 2 +-
.../jogl/acore/TestGLAutoDrawableDelegateNEWT.java | 2 +-
.../acore/TestGLContextDrawableSwitchNEWT.java | 2 +-
.../jogl/acore/TestNEWTCloseX11DisplayBug565.java | 8 ++---
12 files changed, 64 insertions(+), 32 deletions(-)
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index af6218968..43d04c6bd 100755
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -61,7 +61,7 @@ function jrun() {
#D_ARGS="-Djogl.debug=all -Dnativewindow.debug=all -Dnewt.debug=all"
#D_ARGS="-Djogl.debug=all -Dnativewindow.debug=all -Dnewt.debug=all -Djogamp.debug.Lock"
#D_ARGS="-Djogl.debug=all -Dnativewindow.debug=all"
- D_ARGS="-Dnewt.debug.Window"
+ #D_ARGS="-Dnewt.debug.Window"
#D_ARGS="-Djogl.debug.GLDrawable"
#D_ARGS="-Djogl.debug.EGLDrawableFactory.DontQuery -Djogl.debug.GLDrawable"
#D_ARGS="-Djogl.debug.EGLDrawableFactory.QueryNativeTK -Djogl.debug.GLDrawable"
@@ -217,7 +217,7 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestElektronenMultipliziererNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFloatUtil01MatrixMatrixMultNOUI $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestNEWTCloseX11DisplayBug565 $*
+testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestNEWTCloseX11DisplayBug565 $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestMainVersionGLWindowNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestShutdownCompleteNEWT $*
@@ -328,7 +328,7 @@ function testawtswt() {
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting03AWT $*
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04AWT $*
#testawtswt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01aSWT $*
-testawtswt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT $*
+#testawtswt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT $*
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParentingFocusTraversal01AWT $*
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParentingOffscreenLayer01GLCanvasAWT $*
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParentingOffscreenLayer02NewtCanvasAWT $*
diff --git a/src/jogl/classes/com/jogamp/opengl/OffscreenAutoDrawable.java b/src/jogl/classes/com/jogamp/opengl/OffscreenAutoDrawable.java
index 1ea8595c6..8450ffdb0 100644
--- a/src/jogl/classes/com/jogamp/opengl/OffscreenAutoDrawable.java
+++ b/src/jogl/classes/com/jogamp/opengl/OffscreenAutoDrawable.java
@@ -28,6 +28,7 @@
package com.jogamp.opengl;
+import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.opengl.GLAutoDrawableDelegate;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
@@ -45,8 +46,16 @@ import jogamp.opengl.GLFBODrawableImpl;
*/
public class OffscreenAutoDrawable extends GLAutoDrawableDelegate {
- public OffscreenAutoDrawable(GLDrawable drawable, GLContext context, Object upstreamWidget) {
- super(drawable, context, upstreamWidget);
+ /**
+ * @param drawable a valid {@link GLDrawable}, may not be realized yet.
+ * @param context a valid {@link GLContext}, may not be made current (created) yet.
+ * @param ownDevice pass true if {@link AbstractGraphicsDevice#close()} shall be issued,
+ * otherwise pass false. Closing the device is required in case
+ * the drawable is created w/ it's own new instance, e.g. offscreen drawables,
+ * and no further lifecycle handling is applied.
+ */
+ public OffscreenAutoDrawable(GLDrawable drawable, GLContext context, boolean ownDevice) {
+ super(drawable, context, null, ownDevice);
}
/**
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
index 76959f3f4..67e81270d 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
@@ -28,6 +28,8 @@
package javax.media.opengl;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+
import com.jogamp.common.util.locks.LockFactory;
import com.jogamp.common.util.locks.RecursiveLock;
@@ -57,12 +59,16 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase {
public static final boolean DEBUG = Debug.debug("GLAutoDrawableDelegate");
/**
- * @param drawable
- * @param context
+ * @param drawable a valid {@link GLDrawable}, may not be realized yet.
+ * @param context a valid {@link GLContext}, may not be made current (created) yet.
* @param upstreamWidget optional UI element holding this instance, see {@link #getUpstreamWidget()}.
+ * @param ownDevice pass true if {@link AbstractGraphicsDevice#close()} shall be issued,
+ * otherwise pass false. Closing the device is required in case
+ * the drawable is created w/ it's own new instance, e.g. offscreen drawables,
+ * and no further lifecycle handling is applied.
*/
- public GLAutoDrawableDelegate(GLDrawable drawable, GLContext context, Object upstreamWidget) {
- super((GLDrawableImpl)drawable, (GLContextImpl)context);
+ public GLAutoDrawableDelegate(GLDrawable drawable, GLContext context, Object upstreamWidget, boolean ownDevice) {
+ super((GLDrawableImpl)drawable, (GLContextImpl)context, ownDevice);
this.upstreamWidget = null;
}
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index fe6d0fd76..cc4e1b434 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -30,6 +30,8 @@ package jogamp.opengl;
import java.io.PrintStream;
+import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.WindowClosingProtocol;
import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode;
@@ -66,13 +68,23 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
protected volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access
protected GLContextImpl context;
+ protected final boolean ownDevice;
protected int additionalCtxCreationFlags = 0;
protected volatile boolean sendReshape = false; // volatile: maybe written by WindowManager thread w/o locking
protected volatile boolean sendDestroy = false; // volatile: maybe written by WindowManager thread w/o locking
- public GLAutoDrawableBase(GLDrawableImpl drawable, GLContextImpl context) {
+ /**
+ * @param drawable a valid {@link GLDrawableImpl}, may not be realized yet.
+ * @param context a valid {@link GLContextImpl}, may not be made current (created) yet.
+ * @param ownDevice pass true if {@link AbstractGraphicsDevice#close()} shall be issued,
+ * otherwise pass false. Closing the device is required in case
+ * the drawable is created w/ it's own new instance, e.g. offscreen drawables,
+ * and no further lifecycle handling is applied.
+ */
+ public GLAutoDrawableBase(GLDrawableImpl drawable, GLContextImpl context, boolean ownDevice) {
this.drawable = drawable;
this.context = context;
+ this.ownDevice = ownDevice;
resetFPSCounter();
}
@@ -174,7 +186,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
/**
- * Calls {@link #destroyImplInLock()} while claiming the lock.
+ * Calls {@link #destroyImplInLock()} while claiming the lock.
*/
protected final void defaultDestroy() {
final RecursiveLock lock = getLock();
@@ -200,17 +212,22 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
protected void destroyImplInLock() {
final GLContext _context = context;
final GLDrawable _drawable = drawable;
- if( null != _drawable && _drawable.isRealized() ) {
- if( null != _context && _context.isCreated() ) {
- // Catch dispose GLExceptions by GLEventListener, just 'print' them
- // so we can continue with the destruction.
- try {
- helper.disposeGL(this, _drawable, _context, null);
- } catch (GLException gle) {
- gle.printStackTrace();
+ if( null != _drawable ) {
+ if( _drawable.isRealized() ) {
+ if( null != _context && _context.isCreated() ) {
+ // Catch dispose GLExceptions by GLEventListener, just 'print' them
+ // so we can continue with the destruction.
+ try {
+ helper.disposeGL(this, _drawable, _context, null);
+ } catch (GLException gle) {
+ gle.printStackTrace();
+ }
}
+ _drawable.setRealized(false);
+ }
+ if( ownDevice ) {
+ _drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice().close();
}
- _drawable.setRealized(false);
}
context = null;
drawable = null;
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java
index f092288fb..f7808294b 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java
@@ -245,7 +245,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
if(null==drawable) {
throw new GLException("Could not create Pbuffer drawable for: "+device+", "+capsChosen+", "+width+"x"+height);
}
- return new GLPbufferImpl( drawable, shareWith);
+ return new GLPbufferImpl( drawable, shareWith, true);
}
//---------------------------------------------------------------------------
diff --git a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
index 6b64120fe..32f4cb696 100644
--- a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
@@ -58,8 +58,8 @@ import com.jogamp.common.util.locks.RecursiveLock;
public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer {
private int floatMode;
- public GLPbufferImpl(GLDrawableImpl pbufferDrawable, GLContext sharedContext) {
- super(pbufferDrawable, null); // drawable := pbufferDrawable
+ public GLPbufferImpl(GLDrawableImpl pbufferDrawable, GLContext sharedContext, boolean ownDevice) {
+ super(pbufferDrawable, null, ownDevice); // drawable := pbufferDrawable
GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)
drawable.getNativeSurface().getGraphicsConfiguration().getChosenCapabilities();
diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
index fcc374751..7b46a1df0 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
@@ -255,7 +255,7 @@ public class X11Util {
*/
public static int shutdown(boolean realXCloseOpenAndPendingDisplays, boolean verbose) {
int num=0;
- if(DEBUG||verbose||pendingDisplayList.size() > 0) {
+ if(DEBUG || verbose || openDisplayMap.size() > 0 || pendingDisplayList.size() > 0) {
System.err.println("X11Util.Display: Shutdown (close open / pending Displays: "+realXCloseOpenAndPendingDisplays+
", open (no close attempt): "+openDisplayMap.size()+"/"+openDisplayList.size()+
", pending (not closed, marked uncloseable): "+pendingDisplayList.size()+")");
diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
index d662a743a..0fc1b4e89 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
@@ -97,7 +97,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
* Constructor. Do not call this directly -- use {@link #create()} instead.
*/
protected GLWindow(Window window) {
- super(null, null);
+ super(null, null, false);
this.window = (WindowImpl) window;
this.window.setHandleDestroyNotify(false);
window.addWindowListener(new WindowAdapter() {
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBODrawableNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBODrawableNEWT.java
index 1a33845b3..7977347a7 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBODrawableNEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBODrawableNEWT.java
@@ -167,7 +167,7 @@ public class TestFBODrawableNEWT extends UITestCase {
final FBObject.RenderAttachment depthA = fbo.getDepthAttachment();
Assert.assertNotNull(depthA);
- final OffscreenAutoDrawable glad = new OffscreenAutoDrawable(fboDrawable, context, null);
+ final OffscreenAutoDrawable glad = new OffscreenAutoDrawable(fboDrawable, context, true);
glad.addGLEventListener(demo);
glad.addGLEventListener(new GLEventListener() {
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java
index 426b7734f..96d9b2e28 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java
@@ -85,7 +85,7 @@ public class TestGLAutoDrawableDelegateNEWT extends UITestCase {
Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res);
context.release();
- final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context, window) {
+ final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context, window, false) {
@Override
protected void destroyImplInLock() {
super.destroyImplInLock(); // destroys drawable/context
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
index 92b4c5238..cece4c6d5 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
@@ -88,7 +88,7 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
drawable.setRealized(true);
Assert.assertTrue(drawable.isRealized());
- final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, null, window) {
+ final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, null, window, false) {
@Override
protected void destroyImplInLock() {
super.destroyImplInLock();
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNEWTCloseX11DisplayBug565.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNEWTCloseX11DisplayBug565.java
index e14d5b800..33a9b7799 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNEWTCloseX11DisplayBug565.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNEWTCloseX11DisplayBug565.java
@@ -43,10 +43,10 @@ public class TestNEWTCloseX11DisplayBug565 {
if(NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(false)) {
final int openD = X11Util.getOpenDisplayConnectionNumber() - open0;
- if(openD>1) {
+ if( openD > 0) {
X11Util.dumpOpenDisplayConnections();
X11Util.dumpPendingDisplayConnections();
- Assert.assertTrue("More than 1 new open display connections", false);
+ Assert.assertEquals("New display connection didn't close", 0, openD);
}
}
}
@@ -86,10 +86,10 @@ public class TestNEWTCloseX11DisplayBug565 {
if(NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(false)) {
final int openD = X11Util.getOpenDisplayConnectionNumber() - open0;
- if(openD>1) {
+ if(openD > 0) {
X11Util.dumpOpenDisplayConnections();
X11Util.dumpPendingDisplayConnections();
- Assert.assertTrue("More than 1 new open display connections", false);
+ Assert.assertEquals("New display connection didn't close", 0, openD);
}
}
}
--
cgit v1.2.3
From 4dd44b985fe0541be3a3bcd9045d201ed3ca2cc5 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Sat, 15 Sep 2012 16:54:52 +0200
Subject: Seamless Integration of an FBObject based GLFBODrawable as
GLOffscreenAutoDrawable.FBO and as an OffscreenLayerSurface's drawable (OSX)
- Fix Bugs 569 and 599
Summary:
=========
The new FBObject based GLFBODrawable implementation allows the seamless utilization of
FBO offscreen rendering in single buffer, double buffer and MSAA mode.
The GLFBODrawable uses a parent drawable based on a
dummy surface to allow a GLOffscreenAutoDrawable.FBO creation
or a mutable surface supporting an existing offscreen layer surface (OSX CALayer).
Offscreen GLDrawable's and GLOffscreenAutoDrawable's can be selected via the
GLCapabilities. If simply !onscreen is selected in the caps instance w/o enabling FBO, PBuffer or Bitmap,
the factory will automatically choose regarding availability:
FBO > PBuffer > Bitmap
Double buffering is supported in MSAA more (intrinsic) and explicit in non MSAA.
It is preferred when delivering resources (texture id's or framebuffer names)
to a shared GLContext.
This is demonstrated in (emulates our OSX CALayer implementation):
TestFBOOffThreadSharedContextMix2DemosES2NEWT,
TestFBOOnThreadSharedContext1DemoES2NEWT
and with the OSX JAWT OffscreenLayerSurface itself. FBO is the preferred choice.
+++
Offscreen drawables can be resized while maintaining a bound GLContext (e.g. w/ GLAutoDrawable).
Previously both, drawable and context, needed to be destroyed and recreated at offscreen resize.
Common implementation in GLDrawableHelper is used in the implementations
(NEWT's GLWindow, AWT GLCanvas, SWT GLCanvas).
+++
Tested:
=======
Manually run all unit tests on:
- Linux x86_64 NVidia/AMD/Mesa3d(ES)
- OSX x86_64 NVidia
- Windows x86_64 NVidia
- Android arm Mali-400/Tegra-2
No regressions.
Disclaimer:
===========
This feature is committed almost in one patch.
Both previous commits were introducing / fixing the capabilities behavior:
90d45928186f2be99999461cfe45f76a783cc961
9036376b7806a5fc61590bf49404eb71830de92f
I have to appologize for the huge size and impact (files and platforms) of this commit
however, I could not find a better way to inject this feature in one sane piece.
NativeWindow Details:
=====================
Complete decoupling of platform impl. detail of surfaces
implementing ProxySurface. Used to generalize dummy surfaces and EGL surfaces
on top of a native platform surface.
- ProxySurface.UpstreamSurfaceHook -> UpstreamSurfaceHook
- abstract class ProxySurface -> interface ProxySurface + ProxySurfaceImpl
- Misc. implementations
JOGL Details:
=====================
FBOObject: API Change / Simplification & Usability
- Removed reference counter to remove complexity, allow user to choose.
- Add 'dispose' flag for detachColorbuffer(..), allowing to keep attachment alive
- Fix equals operation of Attachment
- Check pre-exising GL errors
- Interface Colobuffer gets lifecycle methods
- Add static factory methods to create Attachments w/o FBObject instance
- Reset:
- Clip min size to 1
- Keep alive samplingSink, i.e. don't issue resetMSAATexture2DSink(..).
It gets called at syncFramebuffer()/use(..) later on before actual usage.
This allows the consumer to utilize the GL_FRONT buffer until (e.g.) swap.
- misc bugfixes
GLOffscreenAutoDrawable: API Change
- Reloc and interfacing
- class com.jogamp.opengl.OffscreenAutoDrawable -> javax.media.opengl.*
interfaces GLOffscreenAutoDrawable extends GLAutoDrawable
GLOffscreenAutoDrawable.FBO extends GLOffscreenAutoDrawable, GLFBODrawable
- Added general implementation and FBO specialization
- Replacing GLPBuffer (deprecated) .. usable for any offscreen GLDrawable via factory
GLAutoDrawable:
- Add 'GLDrawable getDelegatedDrawable()'
- Refine documentation of setContext(..), remove disclaimer and fixme tags
GLDrawableFactory:
- Refine API doc and it's selection mechanism for offscreen.
- Add createOffscreenDrawable(..)
- Add createOffscreenAutoDrawable(..)
- Add canCreateFBO(..)
- Mark createGLPbuffer(..) deprectated
Mark GLPBuffer deprecated
New: GLFBODrawable extends GLDrawable
GLCanvas (AWT and SWT): Add offscreen resize support w/o GLContext recreation
GLAutoDrawableBase .. GLWindow:
- Add offscreen resize support w/o GLContext recreation
- Remove double swapBuffer call
-
GLBase/GLContext:
- Add:
- boolean hasBasicFBOSupport()
- boolean hasFullFBOSupport()
- int getMaxRenderbufferSamples()
- boolean isTextureFormatBGRA8888Available()
GLContext: Fix version detection and hasGLSL()
- Version detection in setGLFunctionAvailability(..)
- Query GL_VERSION ASAP and parse it and compare w/ given major/minor
- Use parsed version if valid and lower than given _or_ given is invalid.
- Use validated version for caching (procaddr, ..), version number, etc.
- Fix hasGLSL()
Since 'isGL2ES2()' is true if 'isGL2()'
and the latter simply alows GL 1.*, we confine the result to a GL >= 2.0
on desktops. FIXME: May consider GL 1.5 w/ extensions.
- return isGL2ES2();
+ return isGLES2() ||
+ isGL3() ||
+ isGL2() && ctxMajorVersion>1 ;
GLDrawableImpl:
- Add 'associateContext(GLContext, boolean)' allowing impl.
to have a (weak) reference list of bound context.
This is was pulled up from the OSX specific drawable impl.
- swapBuffersImpl() -> swapBuffersImpl(boolean doubleBuffered)
and call it regardless of single buffering.
This is required to propagate this event to impl. properly,
i.e. FBODrawable requires a swap notification.
- Clarify 'contextMadeCurrent(..)' protocol
GLDrawableHelper:
- Add resize and recreate offscreen drawable util method
- Simplify required init/reshape calls for GLEventListener
-
GLGraphicsConfigurationUtil:
- fixWinAttribBitsAndHwAccel: Reflect sharede context hw-accel bits
- OSX has no offscreen bitmap, use pbuffer
- use proper offscreen auto selection if offscreen and no modes are set
EGL Context/Drawable/DrawableFactory: Abstract native platform code out of base classes
- Use EGLWrappedSurface w/ UpstreamSurfaceHook to handle upstream (X11, WGL, ..)
lifecycle - in case the EGL resource is hooked up on it.
Invisible dummy surfaces: All platforms
- size is now reduced to 64x64 and decoupled of actual generic mutable size
- fix device lifecycle, no more leaks
+++
OSX
====
Enable support for GLFBODrawableImpl in offscreen CALayer mode
- NSOpenGLImpl: hooks to calayer native code
- calayer code:
- allows pbuffer and texures (FBO)
- decouple size and draw calls avoiding flickering
- enable auto resize of calayer tree
MacOSXCGLContext:
- NSOpenGLImpl:
- Fix false pbuffer 'usage', validate the pointer
- If !pbuffer, copy other window mode bits of caps
-
MacOSXCGLGraphicsConfiguration:
- Only assume pbuffer if !onscreen
- Remove reference of native pixelformat pointer
Native code:
- use 'respondsToSelector:' query before calling 'new' methods
avoiding an error message where unsuported (prev. OSX versions)
- if monitor refresh-rate is queried 0, set to default 60hz
- add missing NSAutoreleasePool decoration
+++
Android / NEWT:
===============
Issue setVisible(..) w/o wait, i.e. queue on EDT,
@Android surfaceChanged() callback. Otherwise we could deadlock:
setVisible(..) -> EDT -> setVisibleImpl(..) -> 'GL-display'.
the latter may may cause havoc while Android-EDT is blocked [until it's return].
---
doc/TODO.txt | 12 -
make/build-jogl.xml | 2 +-
.../config/jogl/gl-impl-CustomJavaCode-common.java | 20 +
make/scripts/java-win64-dbg.bat | 4 +-
make/scripts/tests-x64.bat | 45 +-
make/scripts/tests.sh | 50 +-
make/stub_includes/opengl/macosx-window-system.h | 11 +-
src/jogl/classes/com/jogamp/opengl/FBObject.java | 882 +++++++++++++--------
.../com/jogamp/opengl/GLAutoDrawableDelegate.java | 189 +++++
.../classes/com/jogamp/opengl/GLExtensions.java | 3 +
.../com/jogamp/opengl/OffscreenAutoDrawable.java | 112 ---
.../classes/com/jogamp/opengl/swt/GLCanvas.java | 41 +-
.../classes/javax/media/opengl/GLAutoDrawable.java | 38 +-
.../javax/media/opengl/GLAutoDrawableDelegate.java | 144 ----
src/jogl/classes/javax/media/opengl/GLBase.java | 38 +
src/jogl/classes/javax/media/opengl/GLContext.java | 97 ++-
.../javax/media/opengl/GLDrawableFactory.java | 128 ++-
.../classes/javax/media/opengl/GLFBODrawable.java | 173 ++++
.../media/opengl/GLOffscreenAutoDrawable.java | 63 ++
src/jogl/classes/javax/media/opengl/GLPbuffer.java | 6 +-
.../classes/javax/media/opengl/awt/GLCanvas.java | 119 +--
.../classes/javax/media/opengl/awt/GLJPanel.java | 13 +-
.../classes/jogamp/opengl/GLAutoDrawableBase.java | 76 +-
src/jogl/classes/jogamp/opengl/GLContextImpl.java | 175 ++--
.../jogamp/opengl/GLDrawableFactoryImpl.java | 127 +--
.../classes/jogamp/opengl/GLDrawableHelper.java | 185 ++++-
src/jogl/classes/jogamp/opengl/GLDrawableImpl.java | 80 +-
.../classes/jogamp/opengl/GLFBODrawableImpl.java | 496 ++++++++++--
.../jogamp/opengl/GLGraphicsConfigurationUtil.java | 28 +-
.../jogamp/opengl/GLOffscreenAutoDrawableImpl.java | 123 +++
src/jogl/classes/jogamp/opengl/GLPbufferImpl.java | 31 +-
src/jogl/classes/jogamp/opengl/egl/EGLContext.java | 6 -
.../classes/jogamp/opengl/egl/EGLDrawable.java | 135 ++--
.../jogamp/opengl/egl/EGLDrawableFactory.java | 163 +---
.../opengl/egl/EGLDummyUpstreamSurfaceHook.java | 49 ++
.../jogamp/opengl/egl/EGLExternalContext.java | 11 -
.../jogamp/opengl/egl/EGLGLCapabilities.java | 5 +-
.../opengl/egl/EGLGraphicsConfiguration.java | 9 +-
.../jogamp/opengl/egl/EGLOnscreenContext.java | 11 -
.../jogamp/opengl/egl/EGLOnscreenDrawable.java | 4 +-
.../jogamp/opengl/egl/EGLPbufferContext.java | 10 -
.../jogamp/opengl/egl/EGLPbufferDrawable.java | 8 +-
.../jogamp/opengl/egl/EGLUpstreamSurfaceHook.java | 145 +++-
.../jogamp/opengl/egl/EGLWrappedSurface.java | 26 +
.../jogamp/opengl/macosx/cgl/MacOSXCGLContext.java | 716 ++++++++++-------
.../opengl/macosx/cgl/MacOSXCGLDrawable.java | 48 +-
.../macosx/cgl/MacOSXCGLDrawableFactory.java | 71 +-
.../macosx/cgl/MacOSXCGLGraphicsConfiguration.java | 21 +-
.../cgl/MacOSXCGLGraphicsConfigurationFactory.java | 2 +-
.../macosx/cgl/MacOSXExternalCGLContext.java | 7 +-
.../macosx/cgl/MacOSXOnscreenCGLDrawable.java | 4 +-
.../opengl/macosx/cgl/MacOSXPbufferCGLContext.java | 1 +
.../macosx/cgl/MacOSXPbufferCGLDrawable.java | 42 +-
.../windows/wgl/WindowsExternalWGLContext.java | 4 +-
.../windows/wgl/WindowsExternalWGLDrawable.java | 4 +-
.../opengl/windows/wgl/WindowsWGLDrawable.java | 43 +-
.../windows/wgl/WindowsWGLDrawableFactory.java | 58 +-
.../wgl/WindowsWGLGraphicsConfiguration.java | 29 +-
.../WindowsWGLGraphicsConfigurationFactory.java | 28 +-
.../opengl/x11/glx/X11ExternalGLXContext.java | 4 +-
.../opengl/x11/glx/X11ExternalGLXDrawable.java | 5 +-
.../jogamp/opengl/x11/glx/X11GLXDrawable.java | 7 +-
.../opengl/x11/glx/X11GLXDrawableFactory.java | 63 +-
.../x11/glx/X11GLXGraphicsConfiguration.java | 6 +-
.../glx/X11GLXGraphicsConfigurationFactory.java | 6 +-
.../opengl/x11/glx/X11PbufferGLXDrawable.java | 17 +-
.../macosx/MacOSXWindowSystemInterface-calayer.m | 665 ++++++++++++++++
.../macosx/MacOSXWindowSystemInterface-pbuffer.m | 494 ------------
.../native/macosx/MacOSXWindowSystemInterface.m | 40 +-
.../DelegatedUpstreamSurfaceHookMutableSize.java | 39 +
...elegatedUpstreamSurfaceHookWithSurfaceSize.java | 54 ++
.../UpstreamSurfaceHookMutableSize.java | 45 ++
.../com/jogamp/nativewindow/WrappedSurface.java | 78 --
.../com/jogamp/nativewindow/awt/JAWTWindow.java | 99 ++-
.../jogamp/nativewindow/egl/EGLGraphicsDevice.java | 4 +-
.../javax/media/nativewindow/NativeSurface.java | 5 +-
.../media/nativewindow/OffscreenLayerSurface.java | 3 +
.../javax/media/nativewindow/ProxySurface.java | 266 ++-----
.../media/nativewindow/UpstreamSurfaceHook.java | 52 ++
.../jogamp/nativewindow/ProxySurfaceImpl.java | 326 ++++++++
.../jogamp/nativewindow/WrappedSurface.java | 95 +++
.../nativewindow/jawt/macosx/MacOSXJAWTWindow.java | 84 +-
.../macosx/OSXDummyUpstreamSurfaceHook.java | 56 ++
.../jogamp/nativewindow/macosx/OSXUtil.java | 15 +
.../windows/GDIDummyUpstreamSurfaceHook.java | 50 ++
.../jogamp/nativewindow/windows/GDISurface.java | 34 +-
.../x11/X11DummyUpstreamSurfaceHook.java | 60 ++
src/nativewindow/native/macosx/OSXmisc.m | 189 +++--
.../classes/com/jogamp/newt/awt/NewtCanvasAWT.java | 9 +
.../classes/com/jogamp/newt/opengl/GLWindow.java | 25 +-
.../classes/com/jogamp/newt/swt/NewtCanvasSWT.java | 3 +
src/newt/classes/jogamp/newt/OffscreenWindow.java | 31 +-
src/newt/classes/jogamp/newt/WindowImpl.java | 34 +-
.../jogamp/newt/driver/android/WindowDriver.java | 2 +-
.../jogamp/newt/driver/macosx/WindowDriver.java | 24 +-
src/newt/native/MacWindow.m | 49 +-
.../test/android/MovieCubeActivityLauncher0.java | 2 +
.../android/NEWTGraphUI1pActivityLauncher.java | 22 +-
.../jogl/acore/TestFBOAutoDrawableDeadlockAWT.java | 128 +++
.../jogl/acore/TestFBOAutoDrawableFactoryNEWT.java | 375 +++++++++
.../test/junit/jogl/acore/TestFBODrawableNEWT.java | 272 -------
.../test/junit/jogl/acore/TestFBOMRTNEWT01.java | 2 +-
.../junit/jogl/acore/TestFBOMix2DemosES2NEWT.java | 2 +-
...tFBOOffThreadSharedContextMix2DemosES2NEWT.java | 298 +++++++
.../TestFBOOnThreadSharedContext1DemoES2NEWT.java | 273 +++++++
.../jogl/acore/TestGLAutoDrawableDelegateNEWT.java | 152 ----
...estGLAutoDrawableDelegateOnOffscrnCapsNEWT.java | 384 +++++++++
.../TestGLAutoDrawableFactoryOffscrnCapsNEWT.java | 317 ++++++++
...TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java | 328 ++++++++
...estGLAutoDrawableGLWindowOnOffscrnCapsNEWT.java | 351 ++++++++
...LAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT.java | 300 +++++++
.../junit/jogl/acore/TestGLCapabilities01NEWT.java | 266 -------
.../acore/TestGLContextDrawableSwitchNEWT.java | 22 +-
.../junit/jogl/acore/TestGLDrawable01NEWT.java | 171 ----
.../jogl/acore/TestGLExtensionQueryOffscreen.java | 19 +-
.../jogl/acore/TestNEWTCloseX11DisplayBug565.java | 46 +-
.../acore/TestOffscreenLayer01GLCanvasAWT.java | 236 ++++++
.../acore/TestOffscreenLayer02NewtCanvasAWT.java | 233 ++++++
.../junit/jogl/acore/TestPBufferDeadlockAWT.java | 2 +
.../junit/jogl/acore/TestSharedContextListAWT.java | 20 +-
.../jogl/acore/TestSharedContextListNEWT.java | 20 +-
.../jogl/acore/TestSharedContextListNEWT2.java | 14 +-
.../jogl/acore/TestSharedContextNewtAWTBug523.java | 17 +-
.../jogl/acore/TestSharedContextVBOES1NEWT.java | 20 +-
.../jogl/acore/TestSharedContextVBOES2NEWT.java | 20 +-
.../jogl/acore/TestSharedContextVBOES2NEWT2.java | 14 +-
.../awt/TestBug461FBOSupersamplingSwingAWT.java | 159 ++++
.../TestBug461OffscreenSupersamplingSwingAWT.java | 157 ----
.../TestBug461PBufferSupersamplingSwingAWT.java | 159 ++++
.../junit/jogl/caps/TestMultisampleES1AWT.java | 2 +-
.../junit/jogl/caps/TestMultisampleES1NEWT.java | 2 +-
.../junit/jogl/caps/TestMultisampleES2NEWT.java | 2 +-
.../opengl/test/junit/jogl/demos/es1/GearsES1.java | 6 +
.../test/junit/jogl/demos/es1/RedSquareES1.java | 19 +-
.../test/junit/jogl/demos/es2/FBOMix2DemosES2.java | 5 +-
.../opengl/test/junit/jogl/demos/es2/GearsES2.java | 17 +-
.../test/junit/jogl/demos/es2/Mix2TexturesES2.java | 216 +++++
.../test/junit/jogl/demos/es2/RedSquareES2.java | 21 +-
.../junit/jogl/demos/es2/awt/TestGearsES2AWT.java | 27 +-
.../opengl/test/junit/jogl/demos/gl2/Gears.java | 13 +-
.../jogl/demos/gl2/awt/TestGLJPanelAWTBug450.java | 2 +-
.../test/junit/jogl/offscreen/ReadBufferBase.java | 2 +-
.../test/junit/jogl/swt/TestNewtCanvasSWTGLn.java | 2 +-
.../junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java | 2 +-
.../TestGLReadBufferUtilTextureIOWrite01AWT.java | 4 +-
.../TestGLReadBufferUtilTextureIOWrite01NEWT.java | 16 +-
.../TestGLReadBufferUtilTextureIOWrite02AWT.java | 2 +-
.../TestGLReadBufferUtilTextureIOWrite02NEWT.java | 2 +-
.../util/texture/TestPNGTextureFromFileAWT.java | 2 +-
.../util/texture/TestPNGTextureFromFileNEWT.java | 2 +-
.../test/junit/newt/TestFocus01SwingAWTRobot.java | 21 +-
.../test/junit/newt/TestFocus02SwingAWTRobot.java | 16 +-
.../opengl/test/junit/newt/TestWindows01NEWT.java | 1 -
.../parenting/NewtAWTReparentingKeyAdapter.java | 2 +-
.../TestParentingOffscreenLayer01GLCanvasAWT.java | 211 -----
...TestParentingOffscreenLayer02NewtCanvasAWT.java | 221 ------
.../opengl/test/junit/util/AWTRobotUtil.java | 39 +-
.../opengl/test/junit/util/NEWTGLContext.java | 4 +-
.../jogamp/opengl/test/junit/util/UITestCase.java | 109 ++-
159 files changed, 9357 insertions(+), 4643 deletions(-)
create mode 100644 src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java
delete mode 100644 src/jogl/classes/com/jogamp/opengl/OffscreenAutoDrawable.java
delete mode 100644 src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
create mode 100644 src/jogl/classes/javax/media/opengl/GLFBODrawable.java
create mode 100644 src/jogl/classes/javax/media/opengl/GLOffscreenAutoDrawable.java
create mode 100644 src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java
create mode 100644 src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java
create mode 100644 src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java
create mode 100644 src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m
delete mode 100644 src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m
create mode 100644 src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java
create mode 100644 src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java
create mode 100644 src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java
delete mode 100644 src/nativewindow/classes/com/jogamp/nativewindow/WrappedSurface.java
create mode 100644 src/nativewindow/classes/javax/media/nativewindow/UpstreamSurfaceHook.java
create mode 100644 src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java
create mode 100644 src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java
create mode 100644 src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java
create mode 100644 src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java
create mode 100644 src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableDeadlockAWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableFactoryNEWT.java
delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBODrawableNEWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOffThreadSharedContextMix2DemosES2NEWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOnThreadSharedContext1DemoES2NEWT.java
delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateOnOffscrnCapsNEWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryOffscrnCapsNEWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT.java
delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLCapabilities01NEWT.java
delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDrawable01NEWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer01GLCanvasAWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug461FBOSupersamplingSwingAWT.java
delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug461OffscreenSupersamplingSwingAWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug461PBufferSupersamplingSwingAWT.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/Mix2TexturesES2.java
delete mode 100644 src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingOffscreenLayer01GLCanvasAWT.java
delete mode 100644 src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingOffscreenLayer02NewtCanvasAWT.java
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/doc/TODO.txt b/doc/TODO.txt
index 20a7a9071..0ce1fd3ac 100644
--- a/doc/TODO.txt
+++ b/doc/TODO.txt
@@ -1,13 +1,6 @@
Version 2.0:
-- Fix ES2 detection if it fails (no egl pbuffer on nokia es2) ?
- SIGG slides / video
-- FBO Drawable w/ given NativeSurface - and OSX w/ JAWT
- - Bug 569
- - Bug 599
-
-- cleanup jocl build/jar/demos
-- clean up . in jar names in all docs and tutorials
- ES3 / GL 4.3
@@ -15,11 +8,6 @@ Version 2.0:
WIP:
-- GLPbuffer -> GLOffscreenAutoDrawable
- - GLPbuffer GLDrawableFactory.createPbuffer() ->
- GLOffscreenAutoDrawable GLDrawableFactory.createOffsceenAutoDrawable()
- - Mark both deprecated!
-
- Optimize/Fix NIO caching of glMapBuffer/glUnmapBuffer
- optimize the NIO caching, i.e. memory range, incr. reference count
- _remove_ the cached object w/ decr. ref count, remove object
diff --git a/make/build-jogl.xml b/make/build-jogl.xml
index 40859845c..a72d6c77c 100644
--- a/make/build-jogl.xml
+++ b/make/build-jogl.xml
@@ -1375,7 +1375,7 @@
-
+
diff --git a/make/config/jogl/gl-impl-CustomJavaCode-common.java b/make/config/jogl/gl-impl-CustomJavaCode-common.java
index b05ba2643..283a4e623 100644
--- a/make/config/jogl/gl-impl-CustomJavaCode-common.java
+++ b/make/config/jogl/gl-impl-CustomJavaCode-common.java
@@ -50,6 +50,26 @@
return null;
}
+ @Override
+ public final boolean hasBasicFBOSupport() {
+ return _context.hasBasicFBOSupport();
+ }
+
+ @Override
+ public final boolean hasFullFBOSupport() {
+ return _context.hasFullFBOSupport();
+ }
+
+ @Override
+ public final int getMaxRenderbufferSamples() {
+ return _context.getMaxRenderbufferSamples();
+ }
+
+ @Override
+ public final boolean isTextureFormatBGRA8888Available() {
+ return _context.isTextureFormatBGRA8888Available();
+ }
+
@Override
public final GLContext getContext() {
return _context;
diff --git a/make/scripts/java-win64-dbg.bat b/make/scripts/java-win64-dbg.bat
index 510ebf4dc..b63438534 100755
--- a/make/scripts/java-win64-dbg.bat
+++ b/make/scripts/java-win64-dbg.bat
@@ -30,13 +30,15 @@ REM set D_ARGS="-Djogl.debug.ExtensionAvailabilityCache" "-Djogl.debug=all" "-Dn
REM set D_ARGS="-Djogl.debug=all" "-Dnewt.debug=all" "-Dnativewindow.debug=all" "-Djogamp.debug.NativeLibrary=true"
REM set D_ARGS="-Djogl.debug.GLContext" "-Djogl.debug.ExtensionAvailabilityCache" "-Djogamp.debug.ProcAddressHelper=true"
REM set D_ARGS="-Djogl.debug.GraphicsConfiguration"
+REM set D_ARGS="-Djogl.debug.GLContext" "-Djogl.debug.GLDrawable" "-Dnativewindow.debug.GraphicsConfiguration"
REM set D_ARGS="-Djogamp.debug.JNILibLoader=true" "-Djogamp.debug.NativeLibrary=true" "-Djogamp.debug.NativeLibrary.Lookup=true" "-Djogl.debug.GLProfile=true"
REM set D_ARGS="-Djogl.debug=all" "-Dnewt.debug=all" "-Dnativewindow.debug=all" "-Djogamp.debug.Lock" "-Djogamp.debug.Lock.TraceLock"
-set D_ARGS="-Djogl.debug=all" "-Dnativewindow.debug=all"
+REM set D_ARGS="-Djogl.debug=all" "-Dnativewindow.debug=all"
REM set D_ARGS="-Djogl.debug=all"
REM set D_ARGS="-Djogl.debug.GLCanvas" "-Djogl.debug.Animator" "-Djogl.debug.GLContext" "-Djogl.debug.GLContext.TraceSwitch" "-Djogl.debug.DebugGL" "-Djogl.debug.TraceGL"
REM set D_ARGS="-Djogl.debug.GLCanvas" "-Djogl.debug.Animator" "-Djogl.debug.GLContext" "-Djogl.debug.GLContext.TraceSwitch" "-Djogl.windows.useWGLVersionOf5WGLGDIFuncSet"
REM set D_ARGS="-Djogl.debug.GLCanvas" "-Djogl.debug.Animator" "-Djogl.debug.GLContext" "-Djogl.debug.GLContext.TraceSwitch"
+set D_ARGS="-Dnewt.debug.Window"
REM set D_ARGS="-Dnewt.debug.Window" "-Dnewt.debug.Display"
REM set D_ARGS="-Djogl.debug.GLDebugMessageHandler" "-Djogl.debug.DebugGL" "-Djogl.debug.TraceGL"
REM set D_ARGS="-Djogl.debug.DebugGL" "-Djogl.debug.GLDebugMessageHandler" "-Djogl.debug.GLSLCode"
diff --git a/make/scripts/tests-x64.bat b/make/scripts/tests-x64.bat
index 22cce49aa..a4207b696 100755
--- a/make/scripts/tests-x64.bat
+++ b/make/scripts/tests-x64.bat
@@ -1,9 +1,9 @@
REM scripts\java-win64-dbg.bat jogamp.newt.awt.opengl.VersionApplet
REM scripts\java-win64-dbg.bat com.jogamp.newt.opengl.GLWindow
REM scripts\java-win64-dbg.bat javax.media.opengl.awt.GLCanvas
-REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLCapabilities01NEWT $*
-scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestShutdownCompleteNEWT $*
-REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestShutdownCompleteAWT $*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLCapabilities01NEWT %*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestShutdownCompleteNEWT %*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestShutdownCompleteAWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestMainVersionGLWindowNEWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.offscreen.TestOffscreen01GLPBufferNEWT -time 5000
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.awt.TestAWT01GLn
@@ -40,13 +40,13 @@ REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestP
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting03bAWT -time 100000
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParentingFocusTraversal01AWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParentingOffscreenLayer01AWT %*
-REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting01aSWT $*
-REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting04AWT $*
-REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT $*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting01aSWT %*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting04AWT %*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT %*
-REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTAccessor03AWTGLn $*
-REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn $*
-REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTGLn $*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTAccessor03AWTGLn %*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn %*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTGLn %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestWindows01NEWT
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestGLWindows01NEWT
@@ -73,9 +73,9 @@ REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.caps.TestMultis
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.awt.TestBug461OffscreenSupersamplingSwingAWT
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.glsl.TestShaderCompilationBug459AWT
-REM scripts\java-win64.bat com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol01AWT $*
-REM scripts\java-win64.bat com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol02NEWT $*
-REM scripts\java-win64.bat com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol03NewtAWT $*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol01AWT %*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol02NEWT %*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol03NewtAWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWT01GLn %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWT02GLn %*
@@ -96,16 +96,25 @@ REM scripts\java-win64.bat com.jogamp.opengl.test.junit.graph.demos.GPUTextNewtD
REM scripts\java-win64.bat com.jogamp.opengl.test.junit.graph.demos.GPURegionNewtDemo01
REM scripts\java-win64.bat com.jogamp.opengl.test.junit.graph.demos.GPURegionNewtDemo02
-REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug00NEWT $*
-REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug01NEWT $*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug00NEWT %*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug01NEWT %*
-REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGPUMemSec01NEWT $*
-REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGPUMemSec01NEWT $*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGPUMemSec01NEWT %*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGPUMemSec01NEWT %*
REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestMapBuffer01NEWT
+scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOffscrnCapsNEWT $*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT $*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT $*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableFactoryOffscrnCapsNEWT $*
+
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestFBOAutoDrawableFactoryNEWT $*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestFBOAutoDrawableOffThreadSharedContextES2NEWT $*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestFBOMix2DemosES2NEWT $*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestFBOMRTNEWT01 $*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestFBOAutoDrawableDeadlockAWT $*
+REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.awt.TestBug461FBOSupersamplingSwingAWT
REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.glsl.TestRulerNEWT01
-REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestFBODrawableNEWT %*
-REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.glsl.TestFBOMRTNEWT01 %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestElektronenMultipliziererNEWT %*
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index ce04ae4dc..d2e2db375 100755
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -32,7 +32,7 @@ MOSX=0
MOSX_MT=0
uname -a | grep -i Darwin && MOSX=1
if [ $MOSX -eq 1 ] ; then
- #export NSZombieEnabled=YES
+ export NSZombieEnabled=YES
MOSX_MT=1
fi
@@ -56,11 +56,13 @@ function jrun() {
#D_ARGS="-Djogl.disable.opengles"
#D_ARGS="-Djogl.debug.DebugGL -Djogl.debug.GLSLCode -Dnewt.debug.Window.MouseEvent"
#D_ARGS="-Djogl.debug.TraceGL -Djogl.debug.DebugGL -Djogl.debug.GLSLCode"
+ #D_ARGS="-Djogl.debug.FBObject -Djogl.debug.GLContext -Djogl.debug.GLDrawable -Djogl.debug.GLCanvas -Dnewt.debug.Window"
#D_ARGS="-Djogl.debug.FBObject"
#D_ARGS="-Dnativewindow.debug.GraphicsConfiguration -Djogl.debug.GLDrawable -Djogl.debug.GLContext -Djogl.debug.FBObject"
#D_ARGS="-Djogl.debug.GLContext.NoProfileAliasing"
#D_ARGS="-Djogamp.debug=all -Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all"
- #D_ARGS="-Djogl.debug=all -Dnativewindow.debug=all -Dnewt.debug=all"
+ #D_ARGS="-Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all"
+ #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLDrawable -Dnativewindow.debug.GraphicsConfiguration"
#D_ARGS="-Djogl.fbo.force.none"
#D_ARGS="-Djogl.debug=all -Dnativewindow.debug=all -Dnewt.debug=all -Djogamp.debug.Lock"
#D_ARGS="-Djogl.debug=all"
@@ -208,7 +210,7 @@ function testawtswt() {
}
#
-# newt (testnoawt and testawt)
+# core/newt (testnoawt and testawt)
#
#testnoawt com.jogamp.nativewindow.NativeWindowVersion $*
#testnoawt com.jogamp.opengl.JoglVersion $*
@@ -237,6 +239,26 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBODrawableNEWT $*
+testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOffscrnCapsNEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT $*
+#testawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT $*
+#testawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableFactoryOffscrnCapsNEWT $*
+
+#testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer01GLCanvasAWT $*
+#testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer02NewtCanvasAWT $*
+
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOAutoDrawableFactoryNEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOffThreadSharedContextMix2DemosES2NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOnThreadSharedContext1DemoES2NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOMix2DemosES2NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOMRTNEWT01 $*
+#testawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOAutoDrawableDeadlockAWT $*
+#testawt com.jogamp.opengl.test.junit.jogl.awt.TestBug461FBOSupersamplingSwingAWT
+
+#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
+#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT $*
+
#testnoawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT $*
#testnoawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting02NEWT $*
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01cSwingAWT $*
@@ -331,10 +353,8 @@ function testawtswt() {
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting03AWT $*
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04AWT $*
#testawtswt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01aSWT $*
-testawtswt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT $*
+#testawtswt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT $*
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParentingFocusTraversal01AWT $*
-#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParentingOffscreenLayer01GLCanvasAWT $*
-#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParentingOffscreenLayer02NewtCanvasAWT $*
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestTranslucentParentingAWT $*
#testawt com.jogamp.opengl.test.junit.newt.TestCloseNewtAWT
#testawt com.jogamp.opengl.test.junit.jogl.caps.TestMultisampleES1AWT $*
@@ -376,24 +396,6 @@ testawtswt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestGLSLShaderState02NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestRulerNEWT01 $*
-#
-# FBO / ..
-#
-
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBODrawableNEWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDrawable00NEWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDrawable01NEWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDrawable01bNEWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDrawable02NEWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOMix2DemosES2NEWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBODrawableMix2DemosES2NEWT $*
-#testawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOAutoDrawableDeadlockAWT $*
-#testawt com.jogamp.opengl.test.junit.jogl.awt.TestBug461FBOSupersamplingSwingAWT
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOMRTNEWT01 $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateNEWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
-
#
# Graph
#
diff --git a/make/stub_includes/opengl/macosx-window-system.h b/make/stub_includes/opengl/macosx-window-system.h
index 47b51a509..c627f67de 100644
--- a/make/stub_includes/opengl/macosx-window-system.h
+++ b/make/stub_includes/opengl/macosx-window-system.h
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
typedef int Bool;
@@ -51,12 +52,13 @@ NSOpenGLPixelBuffer* createPBuffer(int renderTarget, int internalFormat, int wid
Bool destroyPBuffer(NSOpenGLPixelBuffer* pBuffer);
void setContextPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer);
void setContextTextureImageToPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer, GLenum colorBuffer);
+Bool isNSOpenGLPixelBuffer(uint64_t object);
-// NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSView* view, Bool opaque);
-NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* pbuffer, Bool opaque, int texWidth, int texHeight);
+NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* p, uint32_t texID, Bool opaque, int texWidth, int texHeight);
void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval);
void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_micros);
-void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* glLayer);
+void flushNSOpenGLLayerPBuffer(NSOpenGLLayer* layer);
+void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* layer, NSOpenGLPixelBuffer* p, uint32_t texID, int texWidth, int texHeight);
void releaseNSOpenGLLayer(NSOpenGLLayer *glLayer);
void* getProcAddress(const char *procName);
@@ -67,6 +69,3 @@ void setSwapInterval(NSOpenGLContext* ctx, int interval);
Bool setGammaRamp(int tableSize, float* redRamp, float* greenRamp, float* blueRamp);
void resetGammaRamp();
-/* returns the screen refresh rate in Hz */
-int getScreenRefreshRate(int scrn_idx);
-
diff --git a/src/jogl/classes/com/jogamp/opengl/FBObject.java b/src/jogl/classes/com/jogamp/opengl/FBObject.java
index 8a6495e6b..cc0af29a9 100644
--- a/src/jogl/classes/com/jogamp/opengl/FBObject.java
+++ b/src/jogl/classes/com/jogamp/opengl/FBObject.java
@@ -35,6 +35,7 @@ import javax.media.opengl.GL;
import javax.media.opengl.GL2GL3;
import javax.media.opengl.GL3;
import javax.media.opengl.GLBase;
+import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
@@ -61,55 +62,33 @@ public class FBObject {
protected static final boolean DEBUG = Debug.debug("FBObject");
private static final boolean forceMinimumFBOSupport = Debug.isPropertyDefined("jogl.fbo.force.min", true);
+ private static enum DetachAction { NONE, DISPOSE, RECREATE };
+
/**
- * Returns true if basic FBO support is available, otherwise false.
- *
- * Basic FBO is supported if the context is either GL-ES >= 2.0, GL >= core 3.0 or implements the extensions
- * ARB_ES2_compatibility, ARB_framebuffer_object, EXT_framebuffer_object or OES_framebuffer_object.
- *
- *
- * Basic FBO support may only include one color attachment and no multisampling,
- * as well as limited internal formats for renderbuffer.
- *
- * @see GLContext#hasFBO()
- */
- public static final boolean supportsBasicFBO(GL gl) {
- return gl.getContext().hasFBO();
- }
-
- /**
- * Returns true if full FBO support is available, otherwise false.
- *
- * Full FBO is supported if the context is either GL >= core 3.0 or implements the extensions
- * ARB_framebuffer_object, or all of
- * EXT_framebuffer_object, EXT_framebuffer_multisample,
- * EXT_framebuffer_blit, GL_EXT_packed_depth_stencil.
- *
- *
- * Full FBO support includes multiple color attachments and multisampling.
- *
+ * Marker interface, denotes a color buffer attachment.
+ *
Always an instance of {@link Attachment}.
+ *
Either an instance of {@link ColorAttachment} or {@link TextureAttachment}.
*/
- public static final boolean supportsFullFBO(GL gl) {
- return !forceMinimumFBOSupport &&
- ( gl.isGL3() || // GL >= 3.0
- gl.isExtensionAvailable(GLExtensions.ARB_framebuffer_object) || // ARB_framebuffer_object
-
- ( gl.isExtensionAvailable(GLExtensions.EXT_framebuffer_object) && // All EXT_framebuffer_object*
- gl.isExtensionAvailable(GLExtensions.EXT_framebuffer_multisample) &&
- gl.isExtensionAvailable(GLExtensions.EXT_framebuffer_blit) &&
- gl.isExtensionAvailable(GLExtensions.EXT_packed_depth_stencil)
- )
- ) ;
- }
-
- public static final int getMaxSamples(GL gl) {
- if( supportsFullFBO(gl) ) {
- int[] val = new int[] { 0 } ;
- gl.glGetIntegerv(GL2GL3.GL_MAX_SAMPLES, val, 0);
- return val[0];
- } else {
- return 0;
- }
+ public static interface Colorbuffer {
+ /**
+ * Initializes the color buffer and set it's parameter, if uninitialized, i.e. name is zero.
+ * @return true if newly initialized, otherwise false.
+ * @throws GLException if buffer generation or setup fails. The just created buffer name will be deleted in this case.
+ */
+ public boolean initialize(GL gl) throws GLException;
+
+ /**
+ * Releases the color buffer if initialized, i.e. name is not zero.
+ * @throws GLException if buffer release fails.
+ */
+ public void free(GL gl) throws GLException;
+
+ /**
+ * Writes the internal format to the given GLCapabilities object.
+ * @param caps the destination for format bits
+ * @param rgba8Avail whether rgba8 is available
+ */
+ public void formatToGLCapabilities(GLCapabilities caps, boolean rgba8Avail);
}
/** Common super class of all attachments */
@@ -155,21 +134,89 @@ public class FBObject {
private int name;
- /** true if resource is initialized by {@link #initialize(GL)}, hence {@link #free(GL)} is allowed to free the GL resources. */
- protected boolean resourceOwner;
-
- private int initCounter;
-
protected Attachment(Type type, int iFormat, int width, int height, int name) {
this.type = type;
this.format = iFormat;
this.width = width;
this.height = height;
this.name = name;
- this.resourceOwner = false;
- this.initCounter = 0;
}
+ /**
+ * Writes the internal format to the given GLCapabilities object.
+ * @param caps the destination for format bits
+ * @param rgba8Avail whether rgba8 is available
+ */
+ public final void formatToGLCapabilities(GLCapabilities caps, boolean rgba8Avail) {
+ final int _format;
+ switch(format) {
+ case GL.GL_RGBA:
+ _format = rgba8Avail ? GL.GL_RGBA8 : GL.GL_RGBA4;
+ break;
+ case GL.GL_RGB:
+ _format = rgba8Avail ? GL.GL_RGB8 : GL.GL_RGB565;
+ break;
+ default:
+ _format = format;
+ }
+ switch(_format) {
+ case GL.GL_RGBA4:
+ caps.setRedBits(4);
+ caps.setGreenBits(4);
+ caps.setBlueBits(4);
+ caps.setAlphaBits(4);
+ break;
+ case GL.GL_RGB5_A1:
+ caps.setRedBits(5);
+ caps.setGreenBits(5);
+ caps.setBlueBits(5);
+ caps.setAlphaBits(1);
+ break;
+ case GL.GL_RGB565:
+ caps.setRedBits(5);
+ caps.setGreenBits(6);
+ caps.setBlueBits(5);
+ caps.setAlphaBits(0);
+ break;
+ case GL.GL_RGB8:
+ caps.setRedBits(8);
+ caps.setGreenBits(8);
+ caps.setBlueBits(8);
+ caps.setAlphaBits(0);
+ break;
+ case GL.GL_RGBA8:
+ caps.setRedBits(8);
+ caps.setGreenBits(8);
+ caps.setBlueBits(8);
+ caps.setAlphaBits(8);
+ break;
+ case GL.GL_DEPTH_COMPONENT16:
+ caps.setDepthBits(16);
+ break;
+ case GL.GL_DEPTH_COMPONENT24:
+ caps.setDepthBits(24);
+ break;
+ case GL.GL_DEPTH_COMPONENT32:
+ caps.setDepthBits(32);
+ break;
+ case GL.GL_STENCIL_INDEX1:
+ caps.setStencilBits(1);
+ break;
+ case GL.GL_STENCIL_INDEX4:
+ caps.setStencilBits(4);
+ break;
+ case GL.GL_STENCIL_INDEX8:
+ caps.setStencilBits(8);
+ break;
+ case GL.GL_DEPTH24_STENCIL8:
+ caps.setDepthBits(24);
+ caps.setStencilBits(8);
+ break;
+ default:
+ throw new IllegalArgumentException("format invalid: 0x"+Integer.toHexString(format));
+ }
+ }
+
/** width of attachment */
public final int getWidth() { return width; }
/** height of attachment */
@@ -180,45 +227,31 @@ public class FBObject {
public final int getName() { return name; }
/* pp */ final void setName(int n) { name = n; }
- public final int getInitCounter() { return initCounter; }
-
/**
- * Initializes the attachment buffer and set it's parameter, if uninitialized, i.e. name is zero.
- *
Implementation employs an initialization counter, hence it can be paired recursively with {@link #free(GL)}.
- * @throws GLException if buffer generation or setup fails. The just created buffer name will be deleted in this case.
- */
- public void initialize(GL gl) throws GLException {
- initCounter++;
- /*
- super.initialize(gl);
- if(1 == getInitCounter() && 0 == getName() ) {
+ * Initializes the attachment and set it's parameter, if uninitialized, i.e. name is zero.
+ *
+ final boolean init = 0 == name;
+ if( init ) {
do init ..
- freeResources = true; // if all OK
}
- */
- }
+ return init;
+ *
+ * @return true if newly initialized, otherwise false.
+ * @throws GLException if buffer generation or setup fails. The just created buffer name will be deleted in this case.
+ */
+ public abstract boolean initialize(GL gl) throws GLException;
/**
- * Releases the attachment buffer if initialized, i.e. name is zero.
- *
Implementation employs an initialization counter, hence it can be paired recursively with {@link #initialize(GL)}.
- * @throws GLException if buffer release fails.
- */
- public void free(GL gl) throws GLException {
- /*
- if(1 == getInitCounter() && freeResources && .. ) {
+ * Releases the attachment if initialized, i.e. name is not zero.
+ *
+ * @throws GLException if buffer release fails.
+ */
+ public abstract void free(GL gl) throws GLException;
/**
*
@@ -232,9 +265,9 @@ public class FBObject {
if( ! ( o instanceof Attachment ) ) return false;
final Attachment a = (Attachment)o;
return type == a.type &&
- format == a.format ||
- width == a.width ||
- height== a.height ||
+ format == a.format &&
+ width == a.width &&
+ height== a.height &&
name == a.name ;
}
@@ -259,8 +292,7 @@ public class FBObject {
public String toString() {
return getClass().getSimpleName()+"[type "+type+", format 0x"+Integer.toHexString(format)+", "+width+"x"+height+
- ", name 0x"+Integer.toHexString(name)+", obj 0x"+Integer.toHexString(objectHashCode())+
- ", resOwner "+resourceOwner+", initCount "+initCounter+"]";
+ ", name 0x"+Integer.toHexString(name)+", obj 0x"+Integer.toHexString(objectHashCode())+"]";
}
public static Type getType(int attachmentPoint, int maxColorAttachments) {
@@ -277,7 +309,7 @@ public class FBObject {
}
}
}
-
+
/** Other renderbuffer attachment which maybe a colorbuffer, depth or stencil. */
public static class RenderAttachment extends Attachment {
private int samples;
@@ -339,14 +371,13 @@ public class FBObject {
}
@Override
- public void initialize(GL gl) throws GLException {
- super.initialize(gl);
- if( 1 == getInitCounter() && 0 == getName() ) {
+ public boolean initialize(GL gl) throws GLException {
+ final boolean init = 0 == getName();
+ if( init ) {
+ int glerr = checkPreGLError(gl);
+
final int[] name = new int[] { -1 };
gl.glGenRenderbuffers(1, name, 0);
- if( 0 == name[0] ) {
- throw new GLException("null renderbuffer, "+this);
- }
setName(name[0]);
gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, getName());
@@ -355,43 +386,37 @@ public class FBObject {
} else {
gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, format, getWidth(), getHeight());
}
- int glerr = gl.glGetError();
+ glerr = gl.glGetError();
if(GL.GL_NO_ERROR != glerr) {
gl.glDeleteRenderbuffers(1, name, 0);
setName(0);
throw new GLException("GL Error 0x"+Integer.toHexString(glerr)+" while creating "+this);
}
- resourceOwner = true;
if(DEBUG) {
System.err.println("Attachment.init: "+this);
}
}
+ return init;
}
@Override
public void free(GL gl) {
- if(1 == getInitCounter() && resourceOwner && 0 != getName() ) {
- final int[] name = new int[] { getName() };
+ final int[] name = new int[] { getName() };
+ if( 0 != name[0] ) {
gl.glDeleteRenderbuffers(1, name, 0);
+ setName(0);
+ if(DEBUG) {
+ System.err.println("Attachment.free: "+this);
+ }
}
- super.free(gl);
}
public String toString() {
return getClass().getSimpleName()+"[type "+type+", format 0x"+Integer.toHexString(format)+", samples "+samples+", "+getWidth()+"x"+getHeight()+
- ", name 0x"+Integer.toHexString(getName())+", obj 0x"+Integer.toHexString(objectHashCode())+
- ", resOwner "+resourceOwner+", initCount "+getInitCounter()+"]";
+ ", name 0x"+Integer.toHexString(getName())+", obj 0x"+Integer.toHexString(objectHashCode())+"]";
}
}
- /**
- * Marker interface, denotes a color buffer attachment.
- *
Always an instance of {@link Attachment}.
- *
Either an instance of {@link ColorAttachment} or {@link TextureAttachment}.
- */
- public static interface Colorbuffer {
- }
-
/** Color render buffer attachment */
public static class ColorAttachment extends RenderAttachment implements Colorbuffer {
public ColorAttachment(int iFormat, int samples, int width, int height, int name) {
@@ -444,9 +469,11 @@ public class FBObject {
* @throws GLException if texture generation and setup fails. The just created texture name will be deleted in this case.
*/
@Override
- public void initialize(GL gl) throws GLException {
- super.initialize(gl);
- if( 1 == getInitCounter() && 0 == getName() ) {
+ public boolean initialize(GL gl) throws GLException {
+ final boolean init = 0 == getName();
+ if( init ) {
+ int glerr = checkPreGLError(gl);
+
final int[] name = new int[] { -1 };
gl.glGenTextures(1, name, 0);
if(0 == name[0]) {
@@ -468,31 +495,111 @@ public class FBObject {
if( 0 < wrapT ) {
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, wrapT);
}
- int glerr = gl.glGetError();
+ glerr = gl.glGetError();
if(GL.GL_NO_ERROR != glerr) {
gl.glDeleteTextures(1, name, 0);
setName(0);
throw new GLException("GL Error 0x"+Integer.toHexString(glerr)+" while creating "+this);
}
- resourceOwner = true;
- }
- if(DEBUG) {
- System.err.println("Attachment.init: "+this);
+ if(DEBUG) {
+ System.err.println("Attachment.init: "+this);
+ }
}
+ return init;
}
@Override
public void free(GL gl) {
- if(1 == getInitCounter() && resourceOwner && 0 != getName() ) {
- final int[] name = new int[] { getName() };
+ final int[] name = new int[] { getName() };
+ if( 0 != name[0] ) {
gl.glDeleteTextures(1, name, 0);
+ setName(0);
+ if(DEBUG) {
+ System.err.println("Attachment.free: "+this);
+ }
}
- super.free(gl);
+ }
+ }
+
+ /**
+ * Creates a color {@link TextureAttachment}, i.e. type {@link Type#COLOR_TEXTURE},
+ * selecting the texture data type and format automatically.
+ *
+ *
Using default min/mag filter {@link GL#GL_NEAREST} and default wrapS/wrapT {@link GL#GL_CLAMP_TO_EDGE}.
+ *
+ * @param glp the chosen {@link GLProfile}
+ * @param alpha set to true if you request alpha channel, otherwise false;
+ * @param width texture width
+ * @param height texture height
+ * @return the created and uninitialized color {@link TextureAttachment}
+ */
+ public static final TextureAttachment createColorTextureAttachment(GLProfile glp, boolean alpha, int width, int height) {
+ return createColorTextureAttachment(glp, alpha, width, height, GL.GL_NEAREST, GL.GL_NEAREST, GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE);
+ }
+
+ /**
+ * Creates a color {@link TextureAttachment}, i.e. type {@link Type#COLOR_TEXTURE},
+ * selecting the texture data type and format automatically.
+ *
+ * @param glp the chosen {@link GLProfile}
+ * @param alpha set to true if you request alpha channel, otherwise false;
+ * @param width texture width
+ * @param height texture height
+ * @param magFilter if > 0 value for {@link GL#GL_TEXTURE_MAG_FILTER}
+ * @param minFilter if > 0 value for {@link GL#GL_TEXTURE_MIN_FILTER}
+ * @param wrapS if > 0 value for {@link GL#GL_TEXTURE_WRAP_S}
+ * @param wrapT if > 0 value for {@link GL#GL_TEXTURE_WRAP_T}
+ * @return the created and uninitialized color {@link TextureAttachment}
+ */
+ public static final TextureAttachment createColorTextureAttachment(GLProfile glp, boolean alpha, int width, int height,
+ int magFilter, int minFilter, int wrapS, int wrapT) {
+ final int textureInternalFormat, textureDataFormat, textureDataType;
+ if(glp.isGLES()) {
+ textureInternalFormat = alpha ? GL.GL_RGBA : GL.GL_RGB;
+ textureDataFormat = alpha ? GL.GL_RGBA : GL.GL_RGB;
+ textureDataType = GL.GL_UNSIGNED_BYTE;
+ } else {
+ textureInternalFormat = alpha ? GL.GL_RGBA8 : GL.GL_RGB8;
+ textureDataFormat = alpha ? GL.GL_BGRA : GL.GL_RGB;
+ textureDataType = alpha ? GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV : GL.GL_UNSIGNED_BYTE;
+ }
+ return createColorTextureAttachment(textureInternalFormat, width, height, textureDataFormat, textureDataType, magFilter, minFilter, wrapS, wrapT);
+ }
+
+ /**
+ * Creates a color {@link TextureAttachment}, i.e. type {@link Type#COLOR_TEXTURE}.
+ *
+ * @param internalFormat internalFormat parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)}
+ * @param width texture width
+ * @param height texture height
+ * @param dataFormat format parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)}
+ * @param dataType type parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)}
+ * @param magFilter if > 0 value for {@link GL#GL_TEXTURE_MAG_FILTER}
+ * @param minFilter if > 0 value for {@link GL#GL_TEXTURE_MIN_FILTER}
+ * @param wrapS if > 0 value for {@link GL#GL_TEXTURE_WRAP_S}
+ * @param wrapT if > 0 value for {@link GL#GL_TEXTURE_WRAP_T}
+ * @return the created and uninitialized color {@link TextureAttachment}
+ */
+ public static final TextureAttachment createColorTextureAttachment(int internalFormat, int width, int height, int dataFormat, int dataType,
+ int magFilter, int minFilter, int wrapS, int wrapT) {
+ return new TextureAttachment(Type.COLOR_TEXTURE, internalFormat, width, height, dataFormat, dataType,
+ magFilter, minFilter, wrapS, wrapT, 0 /* name */);
+ }
+
+ private static boolean hasAlpha(int format) {
+ switch(format) {
+ case GL.GL_RGBA8:
+ case GL.GL_RGBA4:
+ case GL.GL_RGBA:
+ case GL.GL_BGRA:
+ case 4:
+ return true;
+ default:
+ return false;
}
}
private boolean initialized;
- private boolean basicFBOSupport;
private boolean fullFBOSupport;
private boolean rgba8Avail;
private boolean depth24Avail;
@@ -523,6 +630,9 @@ public class FBObject {
//
private final void validateColorAttachmentPointRange(int point) {
+ if(!initialized) {
+ throw new GLException("FBO not initialized");
+ }
if(maxColorAttachments != colorAttachmentPoints.length) {
throw new InternalError("maxColorAttachments "+maxColorAttachments+", array.lenght "+colorAttachmentPoints);
}
@@ -621,7 +731,6 @@ public class FBObject {
this.initialized = false;
// TBD @ init
- this.basicFBOSupport = false;
this.fullFBOSupport = false;
this.rgba8Avail = false;
this.depth24Avail = false;
@@ -657,14 +766,11 @@ public class FBObject {
private void init(GL gl, int width, int height, int samples) throws GLException {
if(initialized) {
throw new GLException("FBO already initialized");
- }
- fullFBOSupport = supportsFullFBO(gl);
-
- if( !fullFBOSupport && !supportsBasicFBO(gl) ) {
+ }
+ if( !gl.hasBasicFBOSupport() ) {
throw new GLException("FBO not supported w/ context: "+gl.getContext()+", "+this);
}
-
- basicFBOSupport = true;
+ fullFBOSupport = gl.hasFullFBOSupport();
rgba8Avail = gl.isGL2GL3() || gl.isExtensionAvailable(GLExtensions.OES_rgb8_rgba8);
depth24Avail = fullFBOSupport || gl.isExtensionAvailable(GLExtensions.OES_depth24);
@@ -680,10 +786,7 @@ public class FBObject {
int val[] = new int[1];
- int glerr = gl.glGetError();
- if(DEBUG && GL.GL_NO_ERROR != glerr) {
- System.err.println("FBObject.init-preexisting.0 GL Error 0x"+Integer.toHexString(glerr));
- }
+ int glerr = checkPreGLError(gl);
int realMaxColorAttachments = 1;
maxColorAttachments = 1;
@@ -703,16 +806,7 @@ public class FBObject {
colorAttachmentPoints = new Colorbuffer[maxColorAttachments];
colorAttachmentCount = 0;
- maxSamples = 0;
- if(fullFBOSupport) {
- gl.glGetIntegerv(GL2GL3.GL_MAX_SAMPLES, val, 0);
- glerr = gl.glGetError();
- if(GL.GL_NO_ERROR == glerr) {
- maxSamples = val[0];
- } else if(DEBUG) {
- System.err.println("FBObject.init-GL_MAX_SAMPLES query GL Error 0x"+Integer.toHexString(glerr));
- }
- }
+ maxSamples = gl.getMaxRenderbufferSamples();
if(!forceMinimumFBOSupport) {
gl.glGetIntegerv(GL.GL_MAX_TEXTURE_SIZE, val, 0);
maxTextureSize = val[0];
@@ -733,10 +827,9 @@ public class FBObject {
this.samples = samples <= maxSamples ? samples : maxSamples;
if(DEBUG) {
- System.err.println("FBObject "+width+"x"+height+", "+samples+" -> "+samples+" samples");
- System.err.println("basicFBOSupport: "+basicFBOSupport);
+ System.err.println("FBObject "+width+"x"+height+", "+samples+" -> "+this.samples+" samples");
System.err.println("fullFBOSupport: "+fullFBOSupport);
- System.err.println("maxColorAttachments: "+maxColorAttachments+"/"+realMaxColorAttachments);
+ System.err.println("maxColorAttachments: "+maxColorAttachments+"/"+realMaxColorAttachments+" [capped/real]");
System.err.println("maxSamples: "+maxSamples);
System.err.println("maxTextureSize: "+maxTextureSize);
System.err.println("maxRenderbufferSize: "+maxRenderbufferSize);
@@ -761,12 +854,8 @@ public class FBObject {
throw new GLException("size "+width+"x"+height+" exceeds on of the maxima [texture "+maxTextureSize+", renderbuffer "+maxRenderbufferSize+"]");
}
- if(null != samplesSink) {
- // init sampling sink
- samplesSink.reset(gl, width, height);
- resetMSAATexture2DSink(gl);
- }
-
+ resetMSAATexture2DSink(gl);
+
// generate fbo ..
gl.glGenFramebuffers(1, val, 0);
fbName = val[0];
@@ -780,7 +869,8 @@ public class FBObject {
if(!gl.glIsFramebuffer(fbName)) {
checkNoError(gl, GL.GL_INVALID_VALUE, "FBObject Init.isFB"); // throws GLException
}
- bound = true;
+ bound = true;
+ samplesSinkDirty = true;
initialized = true;
updateStatus(gl);
@@ -797,7 +887,7 @@ public class FBObject {
* to match the new given parameters.
*
*
- * Currently incompatibility and hence recreation is given if
+ * Incompatibility and hence recreation is forced if
* the size or sample count doesn't match for subsequent calls.
*
*
@@ -820,17 +910,17 @@ public class FBObject {
* to match the new given parameters.
*
*
- * Currently incompatibility and hence recreation is given if
- * the size or sample count doesn't match for subsequent calls.
+ * Currently incompatibility and hence recreation of the attachments will be performed
+ * if the size or sample count doesn't match for subsequent calls.
*
*
*
Leaves the FBO bound state untouched
*
* @param gl the current GL context
- * @param newWidth
- * @param newHeight
+ * @param newWidth the new width, it's minimum is capped to 1
+ * @param newHeight the new height, it's minimum is capped to 1
* @param newSamples if > 0, MSAA will be used, otherwise no multisampling. Will be capped to {@link #getMaxSamples()}.
- * @throws GLException in case of an error
+ * @throws GLException in case of an error, i.e. size too big, etc ..
*/
public final void reset(GL gl, int newWidth, int newHeight, int newSamples) {
if(!initialized) {
@@ -841,13 +931,15 @@ public class FBObject {
newSamples = newSamples <= maxSamples ? newSamples : maxSamples; // clamp
if( newWidth != width || newHeight != height || newSamples != samples ) {
+ if(0>=newWidth) { newWidth = 1; }
+ if(0>=newHeight) { newHeight = 1; }
if(newWidth > 2 + maxTextureSize || newHeight> 2 + maxTextureSize ||
newWidth > maxRenderbufferSize || newHeight> maxRenderbufferSize ) {
throw new GLException("size "+width+"x"+height+" exceeds on of the maxima [texture "+maxTextureSize+", renderbuffer "+maxRenderbufferSize+"]");
}
if(DEBUG) {
- System.err.println("FBObject.reset - START - "+this);
+ System.err.println("FBObject.reset - START - "+width+"x"+height+", "+samples+" -> "+newWidth+"x"+newHeight+", "+newSamples+"; "+this);
}
final boolean wasBound = isBound();
@@ -856,11 +948,18 @@ public class FBObject {
height = newHeight;
samples = newSamples;
detachAllImpl(gl, true , true);
- resetMSAATexture2DSink(gl);
- if(wasBound) {
- bind(gl);
- } else {
+ /**
+ * Postpone reset of samplesSink until syncFramebuffer,
+ * issued at use(..) method (swapBuffer usually initiates it).
+ * This allows another thread to still use the 'samplesSinkTexture'
+ * until swapBuffer happens and does not invalidate the GL_FRONT
+ * FBO (framebuffer & texture).
+ resetMSAATexture2DSink(gl);
+ */
+ samplesSinkDirty = true;
+
+ if(!wasBound) {
unbind(gl);
}
@@ -870,6 +969,28 @@ public class FBObject {
}
}
+ /**
+ * Writes the internal format of the attachments to the given GLCapabilities object.
+ * @param caps the destination for format bits
+ */
+ public final void formatToGLCapabilities(GLCapabilities caps) {
+ caps.setSampleBuffers(samples > 0);
+ caps.setNumSamples(samples);
+ caps.setDepthBits(0);
+ caps.setStencilBits(0);
+
+ final Colorbuffer cb = samples > 0 ? getSamplingSink() : getColorbuffer(0);
+ if(null != cb) {
+ cb.formatToGLCapabilities(caps, rgba8Avail);
+ }
+ if(null != depth) {
+ depth.formatToGLCapabilities(caps, rgba8Avail);
+ }
+ if(null != stencil && stencil != depth) {
+ stencil.formatToGLCapabilities(caps, rgba8Avail);
+ }
+ }
+
/**
* Note that the status may reflect an incomplete state during transition of attachments.
* @return The FB status. {@link GL.GL_FRAMEBUFFER_COMPLETE} if ok, otherwise return GL FBO error state or -1
@@ -954,6 +1075,15 @@ public class FBObject {
}
}
+ private static int checkPreGLError(GL gl) {
+ int glerr = gl.glGetError();
+ if(DEBUG && GL.GL_NO_ERROR != glerr) {
+ System.err.println("Pre-existing GL error: 0x"+Integer.toHexString(glerr));
+ Thread.dumpStack();
+ }
+ return glerr;
+ }
+
private final boolean checkNoError(GL gl, int err, String exceptionMessage) throws GLException {
if(GL.GL_NO_ERROR != err) {
if(null != gl) {
@@ -974,7 +1104,7 @@ public class FBObject {
}
/**
- * Attaches a Texture2D Color Buffer to this FBO's instance at the given attachment point,
+ * Attaches a {@link Colorbuffer}, i.e. {@link TextureAttachment}, to this FBO's instance at the given attachment point,
* selecting the texture data type and format automatically.
*
*
Using default min/mag filter {@link GL#GL_NEAREST} and default wrapS/wrapT {@link GL#GL_CLAMP_TO_EDGE}.
@@ -986,13 +1116,15 @@ public class FBObject {
* @param alpha set to true if you request alpha channel, otherwise false;
* @return TextureAttachment instance describing the new attached texture colorbuffer if bound and configured successfully, otherwise GLException is thrown
* @throws GLException in case the texture colorbuffer couldn't be allocated or MSAA has been chosen
+ * @see #createColorTextureAttachment(GLProfile, boolean, int, int)
*/
public final TextureAttachment attachTexture2D(GL gl, int attachmentPoint, boolean alpha) throws GLException {
- return attachTexture2D(gl, attachmentPoint, alpha, GL.GL_NEAREST, GL.GL_NEAREST, GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE);
+ return (TextureAttachment)attachColorbuffer(gl, attachmentPoint,
+ createColorTextureAttachment(gl.getGLProfile(), alpha, width, height));
}
/**
- * Attaches a Texture2D Color Buffer to this FBO's instance at the given attachment point,
+ * Attaches a {@link Colorbuffer}, i.e. {@link TextureAttachment}, to this FBO's instance at the given attachment point,
* selecting the texture data type and format automatically.
*
*
Leaves the FBO bound.
@@ -1006,23 +1138,15 @@ public class FBObject {
* @param wrapT if > 0 value for {@link GL#GL_TEXTURE_WRAP_T}
* @return TextureAttachment instance describing the new attached texture colorbuffer if bound and configured successfully, otherwise GLException is thrown
* @throws GLException in case the texture colorbuffer couldn't be allocated or MSAA has been chosen
+ * @see #createColorTextureAttachment(GLProfile, boolean, int, int, int, int, int, int)
*/
public final TextureAttachment attachTexture2D(GL gl, int attachmentPoint, boolean alpha, int magFilter, int minFilter, int wrapS, int wrapT) throws GLException {
- final int textureInternalFormat, textureDataFormat, textureDataType;
- if(gl.isGLES()) {
- textureInternalFormat = alpha ? GL.GL_RGBA : GL.GL_RGB;
- textureDataFormat = alpha ? GL.GL_RGBA : GL.GL_RGB;
- textureDataType = GL.GL_UNSIGNED_BYTE;
- } else {
- textureInternalFormat = alpha ? GL.GL_RGBA8 : GL.GL_RGB8;
- textureDataFormat = alpha ? GL.GL_BGRA : GL.GL_RGB;
- textureDataType = alpha ? GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV : GL.GL_UNSIGNED_BYTE;
- }
- return attachTexture2D(gl, attachmentPoint, textureInternalFormat, textureDataFormat, textureDataType, magFilter, minFilter, wrapS, wrapT);
+ return (TextureAttachment)attachColorbuffer(gl, attachmentPoint,
+ createColorTextureAttachment(gl.getGLProfile(), alpha, width, height, magFilter, minFilter, wrapS, wrapT));
}
/**
- * Attaches a Texture2D Color Buffer to this FBO's instance at the given attachment point.
+ * Attaches a {@link Colorbuffer}, i.e. {@link TextureAttachment}, to this FBO's instance at the given attachment point.
*
*
Leaves the FBO bound.
*
@@ -1037,66 +1161,33 @@ public class FBObject {
* @param wrapT if > 0 value for {@link GL#GL_TEXTURE_WRAP_T}
* @return TextureAttachment instance describing the new attached texture colorbuffer if bound and configured successfully, otherwise GLException is thrown
* @throws GLException in case the texture colorbuffer couldn't be allocated or MSAA has been chosen
+ * @see #createColorTextureAttachment(int, int, int, int, int, int, int, int, int)
*/
public final TextureAttachment attachTexture2D(GL gl, int attachmentPoint,
int internalFormat, int dataFormat, int dataType,
int magFilter, int minFilter, int wrapS, int wrapT) throws GLException {
- return attachTexture2D(gl, attachmentPoint,
- new TextureAttachment(Type.COLOR_TEXTURE, internalFormat, width, height, dataFormat, dataType,
- magFilter, minFilter, wrapS, wrapT, 0 /* name */));
+ return (TextureAttachment)attachColorbuffer(gl, attachmentPoint,
+ createColorTextureAttachment(internalFormat, width, height, dataFormat, dataType, magFilter, minFilter, wrapS, wrapT));
}
/**
- * Attaches a Texture2D Color Buffer to this FBO's instance at the given attachment point.
+ * Creates a {@link ColorAttachment}, selecting the format automatically.
*
- *
- * In case the passed TextureAttachment texA is uninitialized, i.e. it's texture name is zero,
- * a new texture name is generated and setup w/ the texture parameter.
- * Otherwise, i.e. texture name is not zero, the passed TextureAttachment texA is
- * considered complete and assumed matching this FBO requirement. A GL error may occur is the latter is untrue.
- *
- *
- *
Leaves the FBO bound.
- *
- * @param gl the current GL context
- * @param attachmentPoint the color attachment point ranging from [0..{@link #getMaxColorAttachments()}-1]
- * @param texA the to be attached {@link TextureAttachment}. Maybe complete or uninitialized, see above.
- * @return the passed TextureAttachment texA instance describing the new attached texture colorbuffer if bound and configured successfully, otherwise GLException is thrown
- * @throws GLException in case the texture colorbuffer couldn't be allocated or MSAA has been chosen
+ * @param alpha set to true if you request alpha channel, otherwise false;
+ * @return uninitialized ColorAttachment instance describing the new attached colorbuffer
*/
- public final TextureAttachment attachTexture2D(GL gl, int attachmentPoint, TextureAttachment texA) throws GLException {
- validateAddColorAttachment(attachmentPoint, texA);
-
- if(samples>0) {
- removeColorAttachment(attachmentPoint, texA);
- throw new GLException("Texture2D not supported w/ MSAA. If you have enabled MSAA with exisiting texture attachments, you may want to detach them via detachAllTexturebuffer(gl).");
- }
-
- texA.initialize(gl);
- addColorAttachment(attachmentPoint, texA);
-
- bind(gl);
-
- // Set up the color buffer for use as a renderable texture:
- gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER,
- GL.GL_COLOR_ATTACHMENT0 + attachmentPoint,
- GL.GL_TEXTURE_2D, texA.getName(), 0);
-
- if(!ignoreStatus) {
- updateStatus(gl);
- if(!isStatusValid()) {
- detachColorbuffer(gl, attachmentPoint);
- throw new GLException("attachTexture2D "+texA+" at "+attachmentPoint+" failed "+getStatusString()+", "+this);
- }
- }
- if(DEBUG) {
- System.err.println("FBObject.attachTexture2D: "+this);
+ public final ColorAttachment createColorAttachment(boolean alpha) {
+ final int internalFormat;
+ if( rgba8Avail ) {
+ internalFormat = alpha ? GL.GL_RGBA8 : GL.GL_RGB8 ;
+ } else {
+ internalFormat = alpha ? GL.GL_RGBA4 : GL.GL_RGB565;
}
- return texA;
+ return new ColorAttachment(internalFormat, samples, width, height, 0);
}
-
+
/**
- * Attaches a Color Buffer to this FBO's instance at the given attachment point,
+ * Attaches a {@link Colorbuffer}, i.e. {@link ColorAttachment}, to this FBO's instance at the given attachment point,
* selecting the format automatically.
*
*
Leaves the FBO bound.
@@ -1106,19 +1197,14 @@ public class FBObject {
* @param alpha set to true if you request alpha channel, otherwise false;
* @return ColorAttachment instance describing the new attached colorbuffer if bound and configured successfully, otherwise GLException is thrown
* @throws GLException in case the colorbuffer couldn't be allocated
+ * @see #createColorAttachment(boolean)
*/
public final ColorAttachment attachColorbuffer(GL gl, int attachmentPoint, boolean alpha) throws GLException {
- final int internalFormat;
- if( rgba8Avail ) {
- internalFormat = alpha ? GL.GL_RGBA8 : GL.GL_RGB8 ;
- } else {
- internalFormat = alpha ? GL.GL_RGBA4 : GL.GL_RGB565;
- }
- return attachColorbuffer(gl, attachmentPoint, internalFormat);
+ return (ColorAttachment) attachColorbuffer(gl, attachmentPoint, createColorAttachment(alpha));
}
/**
- * Attaches a Color Buffer to this FBO's instance at the given attachment point.
+ * Attaches a {@link Colorbuffer}, i.e. {@link ColorAttachment}, to this FBO's instance at the given attachment point.
*
*
Leaves the FBO bound.
*
@@ -1135,46 +1221,80 @@ public class FBObject {
throw new IllegalArgumentException("colorformat invalid: 0x"+Integer.toHexString(internalFormat)+", "+this);
}
- return attachColorbuffer(gl, attachmentPoint, new ColorAttachment(internalFormat, samples, width, height, 0));
+ return (ColorAttachment) attachColorbuffer(gl, attachmentPoint, new ColorAttachment(internalFormat, samples, width, height, 0));
}
/**
- * Attaches a Color Buffer to this FBO's instance at the given attachment point.
+ * Attaches a {@link Colorbuffer}, i.e. {@link ColorAttachment} or {@link TextureAttachment},
+ * to this FBO's instance at the given attachment point.
*
+ *
+ * If {@link Colorbuffer} is a {@link TextureAttachment} and is uninitialized, i.e. it's texture name is zero,
+ * a new texture name is generated and setup w/ the texture parameter.
+ * Otherwise, i.e. texture name is not zero, the passed TextureAttachment texA is
+ * considered complete and assumed matching this FBO requirement. A GL error may occur is the latter is untrue.
+ *
+ *
*
Leaves the FBO bound.
*
* @param gl
* @param attachmentPoint the color attachment point ranging from [0..{@link #getMaxColorAttachments()}-1]
- * @param colA the template for the new {@link ColorAttachment}
- * @return ColorAttachment instance describing the new attached colorbuffer if bound and configured successfully, otherwise GLException is thrown
- * @throws GLException in case the colorbuffer couldn't be allocated
+ * @param colbuf the to be attached {@link Colorbuffer}
+ * @return newly attached {@link Colorbuffer} instance if bound and configured successfully, otherwise GLException is thrown
+ * @throws GLException in case the colorbuffer couldn't be allocated or MSAA has been chosen in case of a {@link TextureAttachment}
*/
- public final ColorAttachment attachColorbuffer(GL gl, int attachmentPoint, ColorAttachment colA) throws GLException {
- validateAddColorAttachment(attachmentPoint, colA);
-
- colA.initialize(gl);
- addColorAttachment(attachmentPoint, colA);
+ public final Colorbuffer attachColorbuffer(GL gl, int attachmentPoint, Colorbuffer colbuf) throws GLException {
+ validateAddColorAttachment(attachmentPoint, colbuf);
- bind(gl);
+ final boolean initializedColorbuf = colbuf.initialize(gl);
+ addColorAttachment(attachmentPoint, colbuf);
- // Attach the color buffer
- gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER,
- GL.GL_COLOR_ATTACHMENT0 + attachmentPoint,
- GL.GL_RENDERBUFFER, colA.getName());
+ bind(gl);
- if(!ignoreStatus) {
- updateStatus(gl);
- if(!isStatusValid()) {
- detachColorbuffer(gl, attachmentPoint);
- throw new GLException("attachColorbuffer "+colA+" at "+attachmentPoint+" failed "+getStatusString()+", "+this);
+ if(colbuf instanceof TextureAttachment) {
+ final TextureAttachment texA = (TextureAttachment) colbuf;
+
+ if(samples>0) {
+ removeColorAttachment(attachmentPoint, texA);
+ if(initializedColorbuf) {
+ texA.free(gl);
+ }
+ throw new GLException("Texture2D not supported w/ MSAA. If you have enabled MSAA with exisiting texture attachments, you may want to detach them via detachAllTexturebuffer(gl).");
+ }
+
+ // Set up the color buffer for use as a renderable texture:
+ gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER,
+ GL.GL_COLOR_ATTACHMENT0 + attachmentPoint,
+ GL.GL_TEXTURE_2D, texA.getName(), 0);
+
+ if(!ignoreStatus) {
+ updateStatus(gl);
+ if(!isStatusValid()) {
+ detachColorbuffer(gl, attachmentPoint, true);
+ throw new GLException("attachTexture2D "+texA+" at "+attachmentPoint+" failed "+getStatusString()+", "+this);
+ }
+ }
+ } else if(colbuf instanceof ColorAttachment) {
+ final ColorAttachment colA = (ColorAttachment) colbuf;
+
+ // Attach the color buffer
+ gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER,
+ GL.GL_COLOR_ATTACHMENT0 + attachmentPoint,
+ GL.GL_RENDERBUFFER, colA.getName());
+
+ if(!ignoreStatus) {
+ updateStatus(gl);
+ if(!isStatusValid()) {
+ detachColorbuffer(gl, attachmentPoint, true);
+ throw new GLException("attachColorbuffer "+colA+" at "+attachmentPoint+" failed "+getStatusString()+", "+this);
+ }
}
}
if(DEBUG) {
- System.err.println("FBObject.attachColorbuffer: "+this);
+ System.err.println("FBObject.attachColorbuffer: [attachmentPoint "+attachmentPoint+", colbuf "+colbuf+"]: "+this);
}
- return colA;
+ return colbuf;
}
-
/**
* Attaches one depth, stencil or packed-depth-stencil buffer to this FBO's instance,
@@ -1355,33 +1475,39 @@ public class FBObject {
if(!ignoreStatus) {
updateStatus(gl);
if( !isStatusValid() ) {
- detachRenderbuffer(gl, atype);
+ detachRenderbuffer(gl, atype, true);
throw new GLException("renderbuffer attachment failed: "+this.getStatusString());
}
}
if(DEBUG) {
- System.err.println("FBObject.attachRenderbuffer: "+this);
- }
+ System.err.println("FBObject.attachRenderbuffer: [attachmentType "+atype+"]: "+this);
+ }
}
/**
+ * Detaches a {@link Colorbuffer}, i.e. {@link ColorAttachment} or {@link TextureAttachment}.
*
Leaves the FBO bound!
+ *
* @param gl
- * @param ca
+ * @param attachmentPoint
+ * @param dispose true if the Colorbuffer shall be disposed
+ * @return the detached Colorbuffer
* @throws IllegalArgumentException
*/
- public final void detachColorbuffer(GL gl, int attachmentPoint) throws IllegalArgumentException {
- if(null == detachColorbufferImpl(gl, attachmentPoint, false)) {
+ public final Colorbuffer detachColorbuffer(GL gl, int attachmentPoint, boolean dispose) throws IllegalArgumentException {
+ final Colorbuffer res = detachColorbufferImpl(gl, attachmentPoint, dispose ? DetachAction.DISPOSE : DetachAction.NONE);
+ if(null == res) {
throw new IllegalArgumentException("ColorAttachment at "+attachmentPoint+", not attached, "+this);
}
if(DEBUG) {
- System.err.println("FBObject.detachColorbuffer: [attachmentPoint "+attachmentPoint+"]: "+this);
+ System.err.println("FBObject.detachColorbuffer: [attachmentPoint "+attachmentPoint+", dispose "+dispose+"]: "+res+", "+this);
}
+ return res;
}
- private final Colorbuffer detachColorbufferImpl(GL gl, int attachmentPoint, boolean recreate) {
- final Colorbuffer colbuf = colorAttachmentPoints[attachmentPoint]; // shortcut, don't validate here
+ private final Colorbuffer detachColorbufferImpl(GL gl, int attachmentPoint, DetachAction detachAction) {
+ Colorbuffer colbuf = colorAttachmentPoints[attachmentPoint]; // shortcut, don't validate here
if(null == colbuf) {
return null;
@@ -1389,6 +1515,8 @@ public class FBObject {
bind(gl);
+ removeColorAttachment(attachmentPoint, colbuf);
+
if(colbuf instanceof TextureAttachment) {
final TextureAttachment texA = (TextureAttachment) colbuf;
if( 0 != texA.getName() ) {
@@ -1397,11 +1525,22 @@ public class FBObject {
GL.GL_TEXTURE_2D, 0, 0);
gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
}
- texA.free(gl);
- removeColorAttachment(attachmentPoint, texA);
- if(recreate) {
- texA.setSize(width, height);
- attachTexture2D(gl, attachmentPoint, texA);
+ switch(detachAction) {
+ case DISPOSE:
+ texA.free(gl);
+ break;
+ case RECREATE:
+ texA.free(gl);
+ if(samples == 0) {
+ // stay non MSAA
+ texA.setSize(width, height);
+ } else {
+ // switch to MSAA
+ colbuf = createColorAttachment(hasAlpha(texA.format));
+ }
+ attachColorbuffer(gl, attachmentPoint, colbuf);
+ break;
+ default:
}
} else if(colbuf instanceof ColorAttachment) {
final ColorAttachment colA = (ColorAttachment) colbuf;
@@ -1410,12 +1549,30 @@ public class FBObject {
GL.GL_COLOR_ATTACHMENT0+attachmentPoint,
GL.GL_RENDERBUFFER, 0);
}
- colA.free(gl);
- removeColorAttachment(attachmentPoint, colbuf);
- if(recreate) {
- colA.setSize(width, height);
- colA.setSamples(samples);
- attachColorbuffer(gl, attachmentPoint, colA);
+ switch(detachAction) {
+ case DISPOSE:
+ colA.free(gl);
+ break;
+ case RECREATE:
+ colA.free(gl);
+ if(samples > 0) {
+ // stay MSAA
+ colA.setSize(width, height);
+ colA.setSamples(samples);
+ } else {
+ // switch to non MSAA
+ if(null != samplesSinkTexture) {
+ colbuf = createColorTextureAttachment(samplesSinkTexture.format, width, height,
+ samplesSinkTexture.dataFormat, samplesSinkTexture.dataType,
+ samplesSinkTexture.magFilter, samplesSinkTexture.minFilter,
+ samplesSinkTexture.wrapS, samplesSinkTexture.wrapT);
+ } else {
+ colbuf = createColorTextureAttachment(gl.getGLProfile(), true, width, height);
+ }
+ }
+ attachColorbuffer(gl, attachmentPoint, colbuf);
+ break;
+ default:
}
}
return colbuf;
@@ -1424,10 +1581,14 @@ public class FBObject {
/**
*
* @param gl
+ * @param dispose true if the Colorbuffer shall be disposed
* @param reqAType {@link Type#DEPTH}, {@link Type#DEPTH} or {@link Type#DEPTH_STENCIL}
*/
- public final void detachRenderbuffer(GL gl, Attachment.Type atype) throws IllegalArgumentException {
- detachRenderbufferImpl(gl, atype, false);
+ public final void detachRenderbuffer(GL gl, Attachment.Type atype, boolean dispose) throws IllegalArgumentException {
+ detachRenderbufferImpl(gl, atype, dispose ? DetachAction.DISPOSE : DetachAction.NONE);
+ if(DEBUG) {
+ System.err.println("FBObject.detachRenderbuffer: [attachmentType "+atype+", dispose "+dispose+"]: "+this);
+ }
}
public final boolean isDepthStencilPackedFormat() {
@@ -1439,7 +1600,7 @@ public class FBObject {
return res;
}
- private final void detachRenderbufferImpl(GL gl, Attachment.Type atype, boolean recreate) throws IllegalArgumentException {
+ private final void detachRenderbufferImpl(GL gl, Attachment.Type atype, DetachAction detachAction) throws IllegalArgumentException {
switch ( atype ) {
case DEPTH:
case STENCIL:
@@ -1485,8 +1646,14 @@ public class FBObject {
if( 0 != depth.getName() ) {
gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
}
- depth.free(gl);
- if(!recreate) {
+ switch(detachAction) {
+ case DISPOSE:
+ case RECREATE:
+ depth.free(gl);
+ break;
+ default:
+ }
+ if(DetachAction.RECREATE != detachAction) {
depth = null;
}
break;
@@ -1495,8 +1662,14 @@ public class FBObject {
if(0 != stencil.getName()) {
gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
}
- stencil.free(gl);
- if(!recreate) {
+ switch(detachAction) {
+ case DISPOSE:
+ case RECREATE:
+ stencil.free(gl);
+ break;
+ default:
+ }
+ if(DetachAction.RECREATE != detachAction) {
stencil = null;
}
break;
@@ -1506,9 +1679,15 @@ public class FBObject {
gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
}
- depth.free(gl);
- stencil.free(gl);
- if(!recreate) {
+ switch(detachAction) {
+ case DISPOSE:
+ case RECREATE:
+ depth.free(gl);
+ stencil.free(gl);
+ break;
+ default:
+ }
+ if(DetachAction.RECREATE != detachAction) {
depth = null;
stencil = null;
}
@@ -1516,14 +1695,15 @@ public class FBObject {
default:
throw new InternalError("XXX");
}
- if(recreate) {
+ if(DetachAction.RECREATE == detachAction) {
attachRenderbufferImpl2(gl, action, format);
}
}
}
/**
- * Detaches all {@link ColorAttachment}s, {@link TextureAttachment}s and {@link RenderAttachment}s.
+ * Detaches all {@link ColorAttachment}s, {@link TextureAttachment}s and {@link RenderAttachment}s
+ * and disposes them.
*
Leaves the FBO bound!
*
* An attached sampling sink texture will be detached as well, see {@link #getSamplingSink()}.
@@ -1538,7 +1718,8 @@ public class FBObject {
}
/**
- * Detaches all {@link ColorAttachment}s and {@link TextureAttachment}s.
+ * Detaches all {@link ColorAttachment}s and {@link TextureAttachment}s
+ * and disposes them.
*
Leaves the FBO bound!
*
* An attached sampling sink texture will be detached as well, see {@link #getSamplingSink()}.
@@ -1553,7 +1734,7 @@ public class FBObject {
}
/**
- * Detaches all {@link TextureAttachment}s
+ * Detaches all {@link TextureAttachment}s and disposes them.
*
Leaves the FBO bound!
*
* An attached sampling sink texture will be detached as well, see {@link #getSamplingSink()}.
@@ -1566,30 +1747,33 @@ public class FBObject {
}
for(int i=0; i reset
try {
for(int i=0; i0 ) {
throw new InternalError("Non zero ColorAttachments "+this);
}
if(detachNonColorbuffer) {
- detachRenderbufferImpl(gl, Attachment.Type.DEPTH_STENCIL, recreate);
+ detachRenderbufferImpl(gl, Attachment.Type.DEPTH_STENCIL, recreate ? DetachAction.RECREATE : DetachAction.DISPOSE);
}
if(ignoreStatus) { // post validate
updateStatus(gl);
@@ -1651,14 +1835,22 @@ public class FBObject {
}
private final void resetMSAATexture2DSink(GL gl) throws GLException {
+ if(null == samplesSink ) {
+ return; // this is the sample sink!
+ }
if(0 == samples) {
// MSAA off
- if(null != samplesSink) {
+ if(samplesSink.initialized) {
+ // cleanup
samplesSink.detachAll(gl);
}
return;
}
+ if(!samplesSink.initialized) {
+ samplesSink.init(gl, width, height, 0);
+ }
+
boolean sampleSinkSizeMismatch = sampleSinkSizeMismatch();
boolean sampleSinkTexMismatch = sampleSinkTexMismatch();
boolean sampleSinkDepthStencilMismatch = sampleSinkDepthStencilMismatch();
@@ -1692,7 +1884,7 @@ public class FBObject {
samplesSinkTexture = samplesSink.attachTexture2D(gl, 0, true);
} else if( 0 == samplesSinkTexture.getName() ) {
samplesSinkTexture.setSize(width, height);
- samplesSink.attachTexture2D(gl, 0, samplesSinkTexture);
+ samplesSink.attachColorbuffer(gl, 0, samplesSinkTexture);
}
if( sampleSinkDepthStencilMismatch ) {
@@ -1768,6 +1960,17 @@ public class FBObject {
bound = false;
}
}
+
+ /**
+ * Method simply marks this FBO unbound w/o interfering w/ the bound framebuffer as perfomed by {@link #unbind(GL)}.
+ *
+ * Only use this method if a subsequent {@link #unbind(GL)}, {@link #use(GL, TextureAttachment)} or {@link #bind(GL)}
+ * follows on any FBO.
+ *
+ */
+ public final void markUnbound() {
+ bound = false;
+ }
/**
* Returns true if framebuffer object is bound via {@link #bind(GL)}, otherwise false.
@@ -1785,49 +1988,54 @@ public class FBObject {
public final boolean isBound() { return bound; }
/**
- * Samples the multisampling colorbuffer (msaa-buffer) to it's sink {@link #getSamplingSink()}.
- *
- *
The operation is skipped, if no multisampling is used or
- * the msaa-buffer has not been flagged dirty by a previous call of {@link #bind(GL)},
- * see {@link #isSamplingBufferDirty()}
- *
- *
If full FBO is supported, sets the read and write framebuffer individually to default after sampling, hence not disturbing
- * an optional operating MSAA FBO, see {@link GLBase#getDefaultReadFramebuffer()} and {@link GLBase#getDefaultDrawFramebuffer()}
- *
- *
In case you intend to employ {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels(..)}
+ * If multisampling is being used and flagged dirty by a previous call of {@link #bind(GL)} or after initialization,
+ * the msaa-buffers are sampled to it's sink {@link #getSamplingSink()}.
+ *
+ * Method also updates the sampling sink configuration (if used). Hence it is recommended to call this
+ * method after your have initialized the FBO and attached renderbuffer etc for the 1st time.
+ * Method is called automatically by {@link #use(GL, TextureAttachment)}.
+ *
+ *
+ * Methos always resets the framebuffer binding to default in the end.
+ * If full FBO is supported, sets the read and write framebuffer individually to default after sampling, hence not disturbing
+ * an optional operating MSAA FBO, see {@link GLBase#getDefaultReadFramebuffer()} and {@link GLBase#getDefaultDrawFramebuffer()}
+ *
+ *
+ * In case you use this FBO w/o the {@link GLFBODrawable} and intend to employ {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels(..)}
* you may want to call {@link GL#glBindFramebuffer(int, int) glBindFramebuffer}({@link GL2GL3#GL_READ_FRAMEBUFFER}, {@link #getReadFramebuffer()});
*
- *
*
Leaves the FBO unbound.
*
* @param gl the current GL context
* @param ta {@link TextureAttachment} to use, prev. attached w/ {@link #attachTexture2D(GL, int, boolean, int, int, int, int) attachTexture2D(..)}
* @throws IllegalArgumentException
*/
- public final void syncSamplingBuffer(GL gl) {
- unbind(gl);
+ public final void syncFramebuffer(GL gl) {
+ markUnbound();
if(samples>0 && samplesSinkDirty) {
samplesSinkDirty = false;
resetMSAATexture2DSink(gl);
gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, fbName);
gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, samplesSink.getWriteFramebuffer());
- ((GL2GL3)gl).glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, // since MSAA is supported, ugly cast is OK
+ ((GL2GL3)gl).glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, // since MSAA is supported, casting to GL2GL3 is OK
GL.GL_COLOR_BUFFER_BIT, GL.GL_NEAREST);
- if(fullFBOSupport) {
- // default read/draw buffers, may utilize GLContext/GLDrawable override of
- // GLContext.getDefaultDrawFramebuffer() and GLContext.getDefaultReadFramebuffer()
- gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, 0);
- gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, 0);
- } else {
- gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); // default draw buffer
- }
+ }
+ if(fullFBOSupport) {
+ // default read/draw buffers, may utilize GLContext/GLDrawable override of
+ // GLContext.getDefaultDrawFramebuffer() and GLContext.getDefaultReadFramebuffer()
+ gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, 0);
+ gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, 0);
+ } else {
+ gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); // default draw buffer
}
}
/**
* Bind the given texture colorbuffer.
*
- *
If multisampling is being used, {@link #syncSamplingBuffer(GL)} is being called.
+ *
If using multiple texture units, ensure you call {@link GL#glActiveTexture(int)} first!
+ *
+ *
{@link #syncFramebuffer(GL)} is being called
*
*
Leaves the FBO unbound!
*
@@ -1837,11 +2045,7 @@ public class FBObject {
*/
public final void use(GL gl, TextureAttachment ta) throws IllegalArgumentException {
if(null == ta) { throw new IllegalArgumentException("null TextureAttachment, this: "+toString()); }
- if(samples > 0 && samplesSinkTexture == ta) {
- syncSamplingBuffer(gl);
- } else {
- unbind(gl);
- }
+ syncFramebuffer(gl);
gl.glBindTexture(GL.GL_TEXTURE_2D, ta.getName()); // use it ..
}
@@ -1855,14 +2059,8 @@ public class FBObject {
gl.glBindTexture(GL.GL_TEXTURE_2D, 0); // don't use it
}
- /**
- * Returns true if basic or full FBO is supported, otherwise false.
- * @param full true for full FBO supported query, otherwise false for basic FBO support query.
- * @see #supportsFullFBO(GL)
- * @see #supportsBasicFBO(GL)
- * @throws GLException if {@link #init(GL)} hasn't been called.
- */
- public final boolean supportsFBO(boolean full) throws GLException { checkInitialized(); return full ? fullFBOSupport : basicFBOSupport; }
+ /** @see GL#hasFullFBOSupport() */
+ public final boolean hasFullFBOSupport() throws GLException { checkInitialized(); return this.fullFBOSupport; }
/**
* Returns true if renderbuffer accepts internal format {@link GL#GL_RGB8} and {@link GL#GL_RGBA8}, otherwise false.
@@ -1878,7 +2076,7 @@ public class FBObject {
public final boolean supportsDepth(int bits) throws GLException {
checkInitialized();
switch(bits) {
- case 16: return basicFBOSupport;
+ case 16: return true;
case 24: return depth24Avail;
case 32: return depth32Avail;
default: return false;
@@ -1913,11 +2111,11 @@ public class FBObject {
*/
public final int getMaxColorAttachments() throws GLException { checkInitialized(); return maxColorAttachments; }
- /**
- * Returns the maximum number of samples for multisampling. Maybe zero if multisampling is not supported.
- * @throws GLException if {@link #init(GL)} hasn't been called.
- */
- public final int getMaxSamples() throws GLException { checkInitialized(); return maxSamples; }
+ public final int getMaxTextureSize() throws GLException { checkInitialized(); return this.maxTextureSize; }
+ public final int getMaxRenderbufferSize() throws GLException { checkInitialized(); return this.maxRenderbufferSize; }
+
+ /** @see GL#getMaxRenderbufferSamples() */
+ public final int getMaxSamples() throws GLException { checkInitialized(); return this.maxSamples; }
/**
* Returns true if this instance has been initialized with {@link #reset(GL, int, int)}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java
new file mode 100644
index 000000000..38a8deef8
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java
@@ -0,0 +1,189 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl;
+
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.WindowClosingProtocol;
+import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLException;
+
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+
+import jogamp.opengl.GLAutoDrawableBase;
+import jogamp.opengl.GLContextImpl;
+import jogamp.opengl.GLDrawableImpl;
+
+
+/**
+ * Fully functional {@link GLAutoDrawable} implementation
+ * utilizing already created created {@link GLDrawable} and {@link GLContext} instances.
+ *
+ * Since no native windowing system events are being processed, it is recommended
+ * to handle at least:
+ *
+ *
{@link com.jogamp.newt.event.WindowListener#windowRepaint(com.jogamp.newt.event.WindowUpdateEvent) repaint} using {@link #windowRepaintOp()}
+ *
{@link com.jogamp.newt.event.WindowListener#windowResized(com.jogamp.newt.event.WindowEvent) resize} using {@link #windowResizedOp()}
+ *
{@link com.jogamp.newt.event.WindowListener#windowDestroyNotify(com.jogamp.newt.event.WindowEvent) destroy-notify} using {@link #windowDestroyNotifyOp()}
+ *
+ *
+ *
+ * See example {@link com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateNEWT TestGLAutoDrawableDelegateNEWT}.
+ *
+ */
+public class GLAutoDrawableDelegate extends GLAutoDrawableBase implements GLAutoDrawable {
+ /**
+ * @param drawable a valid and already realized {@link GLDrawable}
+ * @param context a valid {@link GLContext}, may not be made current (created) yet.
+ * @param upstreamWidget optional UI element holding this instance, see {@link #getUpstreamWidget()}.
+ * @param ownDevice pass true if {@link AbstractGraphicsDevice#close()} shall be issued,
+ * otherwise pass false. Closing the device is required in case
+ * the drawable is created w/ it's own new instance, e.g. offscreen drawables,
+ * and no further lifecycle handling is applied.
+ * @param lock optional custom {@link RecursiveLock}.
+ */
+ public GLAutoDrawableDelegate(GLDrawable drawable, GLContext context, Object upstreamWidget, boolean ownDevice, RecursiveLock lock) {
+ super((GLDrawableImpl)drawable, (GLContextImpl)context, ownDevice);
+ if(null == drawable) {
+ throw new IllegalArgumentException("null drawable");
+ }
+ if(null == context) {
+ throw new IllegalArgumentException("null context");
+ }
+ if(!drawable.isRealized()) {
+ throw new IllegalArgumentException("drawable not realized");
+ }
+ this.upstreamWidget = upstreamWidget;
+ this.lock = ( null != lock ) ? lock : LockFactory.createRecursiveLock() ;
+ }
+
+ //
+ // expose default methods
+ //
+
+ /** Default implementation to handle repaint events from the windowing system */
+ public final void windowRepaintOp() {
+ super.defaultWindowRepaintOp();
+ }
+
+ /** Implementation to handle resize events from the windowing system. All required locks are being claimed. */
+ public final void windowResizedOp(int newWidth, int newHeight) {
+ super.defaultWindowResizedOp(newWidth, newHeight);
+ }
+
+ /**
+ * Implementation to handle destroy notifications from the windowing system.
+ *
+ *
+ * If the {@link NativeSurface} does not implement {@link WindowClosingProtocol}
+ * or {@link WindowClosingMode#DISPOSE_ON_CLOSE} is enabled (default),
+ * a thread safe destruction is being induced.
+ *
+ */
+ public final void windowDestroyNotifyOp() {
+ super.defaultWindowDestroyNotifyOp();
+ }
+
+ //
+ // Complete GLAutoDrawable
+ //
+
+ private Object upstreamWidget;
+ private final RecursiveLock lock;
+
+ @Override
+ protected final RecursiveLock getLock() { return lock; }
+
+ @Override
+ public final Object getUpstreamWidget() {
+ return upstreamWidget;
+ }
+
+ /**
+ * Set the upstream UI toolkit object.
+ * @see #getUpstreamWidget()
+ */
+ public final void setUpstreamWidget(Object newUpstreamWidget) {
+ upstreamWidget = newUpstreamWidget;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This implementation calls {@link #defaultDestroy()}.
+ *
+ *
+ * User still needs to destroy the upstream window, which details are hidden from this aspect.
+ * This can be performed by overriding {@link #destroyImplInLock()}.
+ *
+ */
+ @Override
+ public final void destroy() {
+ defaultDestroy();
+ }
+
+ @Override
+ protected void destroyImplInLock() {
+ super.destroyImplInLock();
+ }
+
+ @Override
+ public void display() {
+ defaultDisplay();
+ }
+
+ //
+ // GLDrawable delegation
+ //
+
+ @Override
+ public final GLDrawableFactory getFactory() {
+ return drawable.getFactory();
+ }
+
+ @Override
+ public final void setRealized(boolean realized) {
+ }
+
+ @Override
+ public final void swapBuffers() throws GLException {
+ defaultSwapBuffers();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName()+"[ \n\tHelper: " + helper + ", \n\tDrawable: " + drawable +
+ ", \n\tContext: " + context + ", \n\tUpstreamWidget: "+upstreamWidget+ /** ", \n\tFactory: "+factory+ */ "]";
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLExtensions.java b/src/jogl/classes/com/jogamp/opengl/GLExtensions.java
index f7e25fa01..cf81b85ee 100644
--- a/src/jogl/classes/com/jogamp/opengl/GLExtensions.java
+++ b/src/jogl/classes/com/jogamp/opengl/GLExtensions.java
@@ -72,6 +72,9 @@ public class GLExtensions {
public static final String OES_EGL_image_external = "GL_OES_EGL_image_external";
+ public static final String ARB_gpu_shader_fp64 = "GL_ARB_gpu_shader_fp64";
+ public static final String ARB_shader_objects = "GL_ARB_shader_objects";
+
//
// Aliased GLX/WGL/.. extensions
//
diff --git a/src/jogl/classes/com/jogamp/opengl/OffscreenAutoDrawable.java b/src/jogl/classes/com/jogamp/opengl/OffscreenAutoDrawable.java
deleted file mode 100644
index 4caea03b2..000000000
--- a/src/jogl/classes/com/jogamp/opengl/OffscreenAutoDrawable.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Copyright 2012 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
-
-package com.jogamp.opengl;
-
-import javax.media.nativewindow.AbstractGraphicsDevice;
-import javax.media.opengl.GLAutoDrawableDelegate;
-import javax.media.opengl.GLContext;
-import javax.media.opengl.GLDrawable;
-import javax.media.opengl.GLException;
-
-import jogamp.opengl.GLFBODrawableImpl;
-
-/**
- * Platform-independent class exposing FBO offscreen functionality to
- * applications.
- *
- * This class distinguishes itself from {@link GLAutoDrawableDelegate}
- * with it's {@link #setSize(int, int)} functionality.
- *
- */
-public class OffscreenAutoDrawable extends GLAutoDrawableDelegate {
-
- /**
- * @param drawable a valid {@link GLDrawable}, may not be realized yet.
- * @param context a valid {@link GLContext}, may not be made current (created) yet.
- * @param ownDevice pass true if {@link AbstractGraphicsDevice#close()} shall be issued,
- * otherwise pass false. Closing the device is required in case
- * the drawable is created w/ it's own new instance, e.g. offscreen drawables,
- * and no further lifecycle handling is applied.
- */
- public OffscreenAutoDrawable(GLDrawable drawable, GLContext context, boolean ownDevice) {
- super(drawable, context, null, ownDevice);
- }
-
- /**
- * Attempts to resize this offscreen auto drawable, if supported
- * by the underlying {@link GLDrawable).
- * @param newWidth
- * @param newHeight
- * @return true if resize was executed, otherwise false.
- * @throws GLException in case of an error during the resize operation
- */
- public boolean setSize(int newWidth, int newHeight) throws GLException {
- boolean done = false;
- if(drawable instanceof GLFBODrawableImpl) {
- Throwable tFBO = null;
- Throwable tGL = null;
- context.makeCurrent();
- try {
- ((GLFBODrawableImpl)drawable).setSize(context.getGL(), newWidth, newHeight);
- done = true;
- } catch (Throwable t) {
- tFBO = t;
- } finally {
- try {
- context.release();
- } catch (Throwable t) {
- tGL = t;
- }
- }
- if(null != tFBO) {
- throw new GLException("OffscreenAutoDrawable.setSize(..) GLFBODrawableImpl.setSize(..) exception", tFBO);
- }
- if(null != tGL) {
- throw new GLException("OffscreenAutoDrawable.setSize(..) GLContext.release() exception", tGL);
- }
- }
- if(done) {
- this.defaultWindowResizedOp();
- return true;
- }
- return false;
- }
-
- /**
- * If the underlying {@link GLDrawable} is an FBO implementation
- * and contains an {#link FBObject}, the same is returned.
- * Otherwise returns null.
- */
- public FBObject getFBObject() {
- if(drawable instanceof GLFBODrawableImpl) {
- return ((GLFBODrawableImpl)drawable).getFBObject();
- }
- return null;
- }
-}
diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
index 8d237162c..02f62daec 100644
--- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
+++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
@@ -30,6 +30,7 @@ package com.jogamp.opengl.swt;
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
import javax.media.opengl.GL;
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
@@ -48,6 +49,7 @@ import javax.media.opengl.Threading;
import jogamp.opengl.Debug;
import jogamp.opengl.GLContextImpl;
import jogamp.opengl.GLDrawableHelper;
+import jogamp.opengl.GLDrawableImpl;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
@@ -97,8 +99,8 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
private final GLCapabilitiesImmutable capsRequested;
private final GLCapabilitiesChooser capsChooser;
- private volatile GLDrawable drawable; // volatile: avoid locking for read-only access
- private GLContext context;
+ private volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access
+ private GLContextImpl context;
/* Native window surface */
private AbstractGraphicsDevice device;
@@ -319,7 +321,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
}
});
}
- private final ProxySurface.UpstreamSurfaceHook swtCanvasUpStreamHook = new ProxySurface.UpstreamSurfaceHook() {
+ private final UpstreamSurfaceHook swtCanvasUpStreamHook = new UpstreamSurfaceHook() {
@Override
public final void create(ProxySurface s) { /* nop */ }
@@ -349,7 +351,27 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
( nClientArea.width != oClientArea.width || nClientArea.height != oClientArea.height )
) {
clientArea = nClientArea; // write back new value
- sendReshape = true; // Mark for OpenGL reshape next time the control is painted
+
+ GLDrawableImpl _drawable = drawable;
+ if( null != _drawable ) {
+ if(DEBUG) {
+ System.err.println("GLCanvas.sizeChanged: ("+Thread.currentThread().getName()+"): "+nClientArea.width+"x"+nClientArea.height+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle()));
+ }
+ if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final GLDrawableImpl _drawableNew = GLDrawableHelper.resizeOffscreenDrawable(_drawable, context, nClientArea.width, nClientArea.height);
+ if(_drawable != _drawableNew) {
+ // write back
+ drawable = _drawableNew;
+ }
+ } finally {
+ _lock.unlock();
+ }
+ sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock
+ }
+ }
}
}
@@ -391,10 +413,10 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
if(null != proxySurface) {
/* Associate a GL surface with the proxy */
- drawable = glFactory.createGLDrawable(proxySurface);
+ drawable = (GLDrawableImpl) glFactory.createGLDrawable(proxySurface);
drawable.setRealized(true);
- context = drawable.createContext(shareWith);
+ context = (GLContextImpl) drawable.createContext(shareWith);
}
} finally {
_lock.unlock();
@@ -455,6 +477,11 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
return helper.getAutoSwapBufferMode();
}
+ @Override
+ public final GLDrawable getDelegatedDrawable() {
+ return drawable;
+ }
+
@Override
public GLContext getContext() {
return null != drawable ? context : null;
@@ -502,7 +529,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
_lock.lock();
try {
final GLContext oldCtx = context;
- final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
+ final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
context=(GLContextImpl)newCtx;
if(newCtxCurrent) {
context.makeCurrent();
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
index 0b2c664fe..38f1746f9 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
@@ -114,6 +114,12 @@ public interface GLAutoDrawable extends GLDrawable {
* where you drag the window to another monitor. */
public static final boolean SCREEN_CHANGE_ACTION_ENABLED = Debug.getBooleanProperty("jogl.screenchange.action", true);
+ /**
+ * If the implementation uses delegation, return the delegated {@link GLDrawable} instance,
+ * otherwise return this instance.
+ */
+ public GLDrawable getDelegatedDrawable();
+
/**
* Returns the context associated with this drawable. The returned
* context will be synchronized.
@@ -124,23 +130,31 @@ public interface GLAutoDrawable extends GLDrawable {
/**
* Associate a new context to this drawable and also propagates the context/drawable switch by
* calling {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.
- * drawable might be an inner GLDrawable instance if using such a delegation pattern,
- * or this GLAutoDrawable itself.
- *
- * If the old context's drawable was an {@link GLAutoDrawable}, it's reference to the given drawable
- * is being cleared by calling
- * {@link GLAutoDrawable#setContext(GLContext) ((GLAutoDrawable)oldCtx.getGLDrawable()).setContext(null)}.
- *
+ * drawable might be an inner GLDrawable instance if using a delegation pattern,
+ * or this GLAutoDrawable instance.
*
* If the old or new context was current on this thread, it is being released before switching the drawable.
* The new context will be made current afterwards, if it was current before.
- * However the user shall take extra care that not other thread
- * attempts to make this context current. Otherwise a race condition may happen.
+ * However the user shall take extra care that no other thread
+ * attempts to make this context current.
+ *
+ *
+ * Be aware that the old context is still bound to the drawable,
+ * and that one context can only be bound to one drawable at one time!
*
*
- * Disclaimer: Even though the API may allows this functionality in theory, your mileage may vary
- * switching the drawable of an already established GLContext, i.e. which is already made current once.
- * FIXME: Validate functionality!
+ * In case you do not intend to use the old context anymore, i.e.
+ * not assigning it to another drawable, it shall be
+ * destroyed before setting the new context, i.e.:
+ *
+ * This is required, since a context must have a valid drawable at all times
+ * and this API shall not restrict the user in any way.
*
*
* @param newCtx the new context
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
deleted file mode 100644
index 67e81270d..000000000
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * Copyright 2012 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
-
-package javax.media.opengl;
-
-import javax.media.nativewindow.AbstractGraphicsDevice;
-
-import com.jogamp.common.util.locks.LockFactory;
-import com.jogamp.common.util.locks.RecursiveLock;
-
-import jogamp.opengl.Debug;
-import jogamp.opengl.GLAutoDrawableBase;
-import jogamp.opengl.GLContextImpl;
-import jogamp.opengl.GLDrawableImpl;
-
-
-/**
- * Fully functional {@link GLAutoDrawable} implementation
- * utilizing already created created {@link GLDrawable} and {@link GLContext} instances.
- *
- * Since no native windowing system events are being processed, it is recommended
- * to handle at least:
- *
- *
{@link com.jogamp.newt.event.WindowListener#windowRepaint(com.jogamp.newt.event.WindowUpdateEvent) repaint} using {@link #defaultWindowRepaintOp()}
- *
{@link com.jogamp.newt.event.WindowListener#windowResized(com.jogamp.newt.event.WindowEvent) resize} using {@link #defaultWindowResizedOp()}
- *
{@link com.jogamp.newt.event.WindowListener#windowDestroyNotify(com.jogamp.newt.event.WindowEvent) destroy-notify} using {@link #defaultWindowDestroyNotifyOp()}
- *
- *
- *
- * See example {@link com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateNEWT TestGLAutoDrawableDelegateNEWT}.
- *
- */
-public class GLAutoDrawableDelegate extends GLAutoDrawableBase {
- public static final boolean DEBUG = Debug.debug("GLAutoDrawableDelegate");
-
- /**
- * @param drawable a valid {@link GLDrawable}, may not be realized yet.
- * @param context a valid {@link GLContext}, may not be made current (created) yet.
- * @param upstreamWidget optional UI element holding this instance, see {@link #getUpstreamWidget()}.
- * @param ownDevice pass true if {@link AbstractGraphicsDevice#close()} shall be issued,
- * otherwise pass false. Closing the device is required in case
- * the drawable is created w/ it's own new instance, e.g. offscreen drawables,
- * and no further lifecycle handling is applied.
- */
- public GLAutoDrawableDelegate(GLDrawable drawable, GLContext context, Object upstreamWidget, boolean ownDevice) {
- super((GLDrawableImpl)drawable, (GLContextImpl)context, ownDevice);
- this.upstreamWidget = null;
- }
-
- //
- // expose default methods
- //
-
- public final void windowRepaintOp() {
- super.defaultWindowRepaintOp();
- }
-
- public final void windowResizedOp() {
- super.defaultWindowResizedOp();
- }
-
- public final void windowDestroyNotifyOp() {
- super.defaultWindowDestroyNotifyOp();
- }
-
- //
- // Complete GLAutoDrawable
- //
-
- private final RecursiveLock lock = LockFactory.createRecursiveLock(); // instance wide lock
- private final Object upstreamWidget;
-
- @Override
- protected final RecursiveLock getLock() { return lock; }
-
- @Override
- public final Object getUpstreamWidget() {
- return upstreamWidget;
- }
-
- /**
- * {@inheritDoc}
- *
- * This implementation calls {@link #defaultDestroy()}.
- *
- *
- * User still needs to destroy the upstream window, which details are hidden from this aspect.
- * This can be performed by overriding {@link #destroyImplInLock()}.
- *
- */
- @Override
- public final void destroy() {
- defaultDestroy();
- }
-
- @Override
- public void display() {
- defaultDisplay();
- }
-
- //
- // GLDrawable delegation
- //
-
- @Override
- public final GLDrawableFactory getFactory() {
- return drawable.getFactory();
- }
-
- @Override
- public final void setRealized(boolean realized) {
- }
-
- @Override
- public final void swapBuffers() throws GLException {
- defaultSwapBuffers();
- }
-
-}
diff --git a/src/jogl/classes/javax/media/opengl/GLBase.java b/src/jogl/classes/javax/media/opengl/GLBase.java
index f5831a72d..9bcee819a 100644
--- a/src/jogl/classes/javax/media/opengl/GLBase.java
+++ b/src/jogl/classes/javax/media/opengl/GLBase.java
@@ -273,6 +273,42 @@ public interface GLBase {
*/
public boolean isExtensionAvailable(String glExtensionName);
+ /**
+ * Returns true if basic FBO support is available, otherwise false.
+ *
+ * Basic FBO is supported if the context is either GL-ES >= 2.0, GL >= core 3.0 or implements the extensions
+ * GL_ARB_ES2_compatibility, GL_ARB_framebuffer_object, GL_EXT_framebuffer_object or GL_OES_framebuffer_object.
+ *
+ *
+ * Basic FBO support may only include one color attachment and no multisampling,
+ * as well as limited internal formats for renderbuffer.
+ *
+ * @see GLContext#hasBasicFBOSupport()
+ */
+ public boolean hasBasicFBOSupport();
+
+ /**
+ * Returns true if full FBO support is available, otherwise false.
+ *
+ * Full FBO is supported if the context is either GL >= core 3.0 or implements the extensions
+ * ARB_framebuffer_object, or all of
+ * EXT_framebuffer_object, EXT_framebuffer_multisample,
+ * EXT_framebuffer_blit, GL_EXT_packed_depth_stencil.
+ *
+ *
+ * Full FBO support includes multiple color attachments and multisampling.
+ *
+ * @see GLContext#hasFullFBOSupport()
+ */
+ public boolean hasFullFBOSupport();
+
+ /**
+ * Returns the maximum number of FBO RENDERBUFFER samples
+ * if {@link #hasFullFBOSupport() full FBO is supported}, otherwise false.
+ * @see GLContext#getMaxRenderbufferSamples()
+ */
+ public int getMaxRenderbufferSamples();
+
/**
* Returns true if the GL context supports non power of two (NPOT) textures,
* otherwise false.
@@ -284,6 +320,8 @@ public interface GLBase {
*/
public boolean isNPOTTextureAvailable();
+ public boolean isTextureFormatBGRA8888Available();
+
/** Provides a platform-independent way to specify the minimum swap
interval for buffer swaps. An argument of 0 disables
sync-to-vertical-refresh completely, while an argument of 1
diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java
index c2f94b9af..a5e639c74 100644
--- a/src/jogl/classes/javax/media/opengl/GLContext.java
+++ b/src/jogl/classes/javax/media/opengl/GLContext.java
@@ -96,6 +96,9 @@ public abstract class GLContext {
*/
public static final boolean PROFILE_ALIASING = !Debug.isPropertyDefined("jogl.debug.GLContext.NoProfileAliasing", true);
+ 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);
+
public static final boolean DEBUG = Debug.debug("GLContext");
public static final boolean TRACE_SWITCH = Debug.isPropertyDefined("jogl.debug.GLContext.TraceSwitch", true);
@@ -127,9 +130,9 @@ public abstract class GLContext {
/** GL_ARB_ES2_compatibility implementation related: Context is compatible w/ ES2. Not a cache key. See {@link #isGLES2Compatible()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */
protected static final int CTX_IMPL_ES2_COMPAT = 1 << 8;
- /** Context supports basic FBO, details see {@link #hasFBO()}.
+ /** Context supports basic FBO, details see {@link #hasBasicFBOSupport()}.
* Not a cache key.
- * @see #hasFBO()
+ * @see #hasBasicFBOSupport()
* @see #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)
*/
protected static final int CTX_IMPL_FBO = 1 << 9;
@@ -178,11 +181,6 @@ public abstract class GLContext {
* 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.
*
- *
- * Disclaimer: Even though the API may allows this functionality in theory, your mileage may vary
- * switching the drawable of an already established GLContext, i.e. which is already made current once.
- * FIXME: Validate functionality!
- *
* @param readWrite the read/write drawable for framebuffer operations.
* @param setWriteOnly if true and if the current read-drawable differs
* from the write-drawable ({@link #setGLReadDrawable(GLDrawable)}),
@@ -603,12 +601,23 @@ public abstract class GLContext {
/**
* @return true if impl. is a hardware rasterizer, otherwise false.
+ * @see #isHardwareRasterizer(AbstractGraphicsDevice, GLProfile)
* @see GLProfile#isHardwareRasterizer()
*/
public final boolean isHardwareRasterizer() {
return 0 == ( ctxOptions & CTX_IMPL_ACCEL_SOFT ) ;
}
+ /**
+ * @return true if context supports GLSL, i.e. is either {@link #isGLES2()}, {@link #isGL3()} or {@link #isGL2()} and major-version > 1.
+ * @see GLProfile#hasGLSL()
+ */
+ public final boolean hasGLSL() {
+ return isGLES2() ||
+ isGL3() ||
+ isGL2() && ctxMajorVersion>1 ;
+ }
+
/**
* Returns true if basic FBO support is available, otherwise false.
*
@@ -620,21 +629,54 @@ public abstract class GLContext {
* as well as limited internal formats for renderbuffer.
*
* @see #CTX_IMPL_FBO
- * @see com.jogamp.opengl.FBObject#supportsBasicFBO(GL)
- * @see com.jogamp.opengl.FBObject#supportsFullFBO(GL)
*/
- public final boolean hasFBO() {
+ public final boolean hasBasicFBOSupport() {
return 0 != ( ctxOptions & CTX_IMPL_FBO ) ;
}
+ /**
+ * Returns true if full FBO support is available, otherwise false.
+ *
+ * Full FBO is supported if the context is either GL >= core 3.0 or implements the extensions
+ * ARB_framebuffer_object, or all of
+ * EXT_framebuffer_object, EXT_framebuffer_multisample,
+ * EXT_framebuffer_blit, GL_EXT_packed_depth_stencil.
+ *
+ *
+ * Full FBO support includes multiple color attachments and multisampling.
+ *
+ */
+ public final boolean hasFullFBOSupport() {
+ return !FORCE_MIN_FBO_SUPPORT && hasBasicFBOSupport() &&
+ ( isGL3() || // GL >= 3.0
+ isExtensionAvailable(GLExtensions.ARB_framebuffer_object) || // ARB_framebuffer_object
+ ( isExtensionAvailable(GLExtensions.EXT_framebuffer_object) && // All EXT_framebuffer_object*
+ isExtensionAvailable(GLExtensions.EXT_framebuffer_multisample) &&
+ isExtensionAvailable(GLExtensions.EXT_framebuffer_blit) &&
+ isExtensionAvailable(GLExtensions.EXT_packed_depth_stencil)
+ )
+ ) ;
+ }
+
/**
- * @return true if context supports GLSL
- * @see GLProfile#hasGLSL()
+ * Returns the maximum number of FBO RENDERBUFFER samples
+ * if {@link #hasFullFBOSupport() full FBO is supported}, otherwise false.
*/
- public final boolean hasGLSL() {
- return isGL2ES2() ;
+ public final int getMaxRenderbufferSamples() {
+ if( hasFullFBOSupport() ) {
+ final GL gl = getGL();
+ final int[] val = new int[] { 0 } ;
+ gl.glGetIntegerv(GL2GL3.GL_MAX_SAMPLES, val, 0);
+ final int glerr = gl.glGetError();
+ if(GL.GL_NO_ERROR == glerr) {
+ return val[0];
+ } else if(DEBUG) {
+ System.err.println("GLContext.getMaxRenderbufferSamples: GL_MAX_SAMPLES query GL Error 0x"+Integer.toHexString(glerr));
+ }
+ }
+ return 0;
}
-
+
/** Note: The GL impl. may return a const value, ie {@link GLES2#isNPOTTextureAvailable()} always returns true. */
public boolean isNPOTTextureAvailable() {
return isGL3() || isGLES2Compatible() || isExtensionAvailable(GLExtensions.ARB_texture_non_power_of_two);
@@ -1014,6 +1056,9 @@ public abstract class GLContext {
validateProfileBits(profile, "profile");
validateProfileBits(resCtp, "resCtp");
+ if(FORCE_NO_FBO_SUPPORT) {
+ resCtp &= ~CTX_IMPL_FBO ;
+ }
if(DEBUG) {
System.err.println("GLContext.mapAvailableGLVersion: "+device+": "+getGLVersion(reqMajor, 0, profile, null)+" -> "+getGLVersion(resMajor, resMinor, resCtp, null));
// Thread.dumpStack();
@@ -1197,17 +1242,35 @@ public abstract class GLContext {
* FBO feature is implemented in OpenGL, hence it is {@link GLProfile} dependent.
*
*
- * FBO support is queried as described in {@link #hasFBO()}.
+ * FBO support is queried as described in {@link #hasBasicFBOSupport()}.
*
*
* @param device the device to request whether FBO is available for
* @param glp {@link GLProfile} to check for FBO capabilities
- * @see GLContext#hasFBO()
+ * @see GLContext#hasBasicFBOSupport()
*/
public static final boolean isFBOAvailable(AbstractGraphicsDevice device, GLProfile glp) {
return 0 != ( CTX_IMPL_FBO & getAvailableContextProperties(device, glp) );
}
+ /**
+ * @return 1 if using a hardware rasterizer, 0 if using a software rasterizer and -1 if not determined yet.
+ * @see GLContext#isHardwareRasterizer()
+ * @see GLProfile#isHardwareRasterizer()
+ */
+ public static final int isHardwareRasterizer(AbstractGraphicsDevice device, GLProfile glp) {
+ final int r;
+ final int ctp = getAvailableContextProperties(device, glp);
+ if(0 == ctp) {
+ r = -1;
+ } else if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctp ) ) {
+ r = 1;
+ } else {
+ r = 0;
+ }
+ return r;
+ }
+
/**
* @param device the device to request whether the profile is available for
* @param reqMajor Key Value either 1, 2, 3 or 4
diff --git a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java
index 9fd895c1f..b6e7b0576 100644
--- a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java
+++ b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java
@@ -48,13 +48,16 @@ import java.util.List;
import com.jogamp.common.JogampRuntimeException;
import com.jogamp.common.util.ReflectionUtil;
+import com.jogamp.opengl.GLAutoDrawableDelegate;
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.AbstractGraphicsScreen;
+import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.ProxySurface;
-import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook;
+import javax.media.nativewindow.UpstreamSurfaceHook;
import jogamp.opengl.Debug;
@@ -373,44 +376,63 @@ public abstract class GLDrawableFactory {
// Methods to create high-level objects
/**
- * Returns a GLDrawable according to it's chosen Capabilities,
+ * Returns a GLDrawable according to it's chosen {@link GLCapabilitiesImmutable},
* which determines pixel format, on- and offscreen incl. PBuffer type.
*
- * The native platform's chosen Capabilties are referenced within the target
- * NativeSurface's AbstractGraphicsConfiguration.
- *
- * In case target's {@link javax.media.nativewindow.Capabilities#isOnscreen()} is true,
- * an onscreen GLDrawable will be realized.
+ * The chosen {@link GLCapabilitiesImmutable} are referenced within the target
+ * {@link NativeSurface}'s {@link AbstractGraphicsConfiguration}.
+ *
*
- * In case target's {@link javax.media.nativewindow.Capabilities#isOnscreen()} is false,
- * either a Pbuffer drawable is created if target's {@link javax.media.opengl.GLCapabilities#isPBuffer()} is true,
- * or a simple pixmap/bitmap drawable is created. The latter is unlikely to be hardware accelerated.
+ * An onscreen GLDrawable is created if {@link CapabilitiesImmutable#isOnscreen() caps.isOnscreen()} is true.
+ *
*
- *
+ * A FBO drawable is created if both {@link GLCapabilitiesImmutable#isFBO() caps.isFBO()}
+ * and {@link GLContext#isFBOAvailable(AbstractGraphicsDevice, GLProfile) canCreateFBO(device, caps.getGLProfile())} is true.
+ *
+ *
+ * A Pbuffer drawable is created if both {@link GLCapabilitiesImmutable#isPBuffer() caps.isPBuffer()}
+ * and {@link #canCreateGLPbuffer(AbstractGraphicsDevice) canCreateGLPbuffer(device)} is true.
+ *
+ *
+ * If not onscreen and neither FBO nor Pbuffer is available,
+ * a simple pixmap/bitmap drawable/surface is created, which is unlikely to be hardware accelerated.
+ *
+ *
* @throws IllegalArgumentException if the passed target is null
* @throws GLException if any window system-specific errors caused
* the creation of the GLDrawable to fail.
*
+ * @see #canCreateGLPbuffer(AbstractGraphicsDevice)
+ * @see GLContext#isFBOAvailable(AbstractGraphicsDevice, GLProfile)
+ * @see javax.media.opengl.GLCapabilities#isOnscreen()
+ * @see javax.media.opengl.GLCapabilities#isFBO()
+ * @see javax.media.opengl.GLCapabilities#isPBuffer()
* @see javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen)
*/
public abstract GLDrawable createGLDrawable(NativeSurface target)
throws IllegalArgumentException, GLException;
-
+
/**
- * Creates a Offscreen GLDrawable incl it's offscreen {@link javax.media.nativewindow.NativeSurface} with the given capabilites and dimensions.
+ * Creates an {@link GLOffscreenAutoDrawable} incl it's offscreen {@link javax.media.nativewindow.NativeSurface} with the given capabilites and dimensions.
*
- * It's {@link AbstractGraphicsConfiguration} is properly set according to the given {@link GLCapabilitiesImmutable}, see below.
+ * The {@link GLOffscreenAutoDrawable}'s {@link GLDrawable} is realized and it's {@link GLContext} assigned but not yet made current.
*
*
- * A FBO drawable is created if both {@link javax.media.opengl.GLCapabilities#isFBO() caps.isFBO()}
+ * In case the passed {@link GLCapabilitiesImmutable} contains default values, i.e.
+ * {@link GLCapabilitiesImmutable#isOnscreen() caps.isOnscreen()} == true,
+ * it is auto-configured. The latter will set offscreen and also FBO or Pbuffer, whichever is available in that order.
+ *
+ *
+ * A FBO based auto drawable, {@link GLOffscreenAutoDrawable.FBO}, is created if both {@link GLCapabilitiesImmutable#isFBO() caps.isFBO()}
* and {@link GLContext#isFBOAvailable(AbstractGraphicsDevice, GLProfile) canCreateFBO(device, caps.getGLProfile())} is true.
*
*
- * A Pbuffer drawable is created if both {@link javax.media.opengl.GLCapabilities#isPBuffer() caps.isPBuffer()}
- * and {@link #canCreateGLPbuffer(javax.media.nativewindow.AbstractGraphicsDevice) canCreateGLPbuffer(device)} is true.
+ * A Pbuffer based auto drawable is created if both {@link GLCapabilitiesImmutable#isPBuffer() caps.isPBuffer()}
+ * and {@link #canCreateGLPbuffer(AbstractGraphicsDevice) canCreateGLPbuffer(device)} is true.
*
*
- * If neither FBO nor Pbuffer is available, a simple pixmap/bitmap drawable/surface is created, which is unlikely to be hardware accelerated.
+ * If neither FBO nor Pbuffer is available,
+ * a simple pixmap/bitmap auto drawable is created, which is unlikely to be hardware accelerated.
*
*
* @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be null for the platform's default device.
@@ -418,17 +440,55 @@ public abstract class GLDrawableFactory {
* @param chooser the custom chooser, may be null for default
* @param width the requested offscreen width
* @param height the requested offscreen height
+ * @return the created and initialized offscreen {@link GLOffscreenAutoDrawable} instance
*
- * @return the created offscreen GLDrawable
+ * @throws GLException if any window system-specific errors caused
+ * the creation of the Offscreen to fail.
+ *
+ * @see #createOffscreenDrawable(AbstractGraphicsDevice, GLCapabilitiesImmutable, GLCapabilitiesChooser, int, int)
+ */
+ public abstract GLOffscreenAutoDrawable createOffscreenAutoDrawable(AbstractGraphicsDevice device,
+ GLCapabilitiesImmutable caps,
+ GLCapabilitiesChooser chooser,
+ int width, int height,
+ GLContext shareWith) throws GLException;
+ /**
+ * Creates a offscreen {@link GLDrawable} incl it's offscreen {@link javax.media.nativewindow.NativeSurface} with the given capabilites and dimensions.
+ *
+ * In case the passed {@link GLCapabilitiesImmutable} contains default values, i.e.
+ * {@link GLCapabilitiesImmutable#isOnscreen() caps.isOnscreen()} == true,
+ * it is auto-configured. The latter will set offscreen and also FBO or Pbuffer, whichever is available in that order.
+ *
+ *
+ * A resizeable FBO drawable, {@link GLFBODrawable.Resizeable}, is created if both {@link GLCapabilitiesImmutable#isFBO() caps.isFBO()}
+ * and {@link GLContext#isFBOAvailable(AbstractGraphicsDevice, GLProfile) canCreateFBO(device, caps.getGLProfile())} is true.
+ *
+ *
+ * A Pbuffer drawable is created if both {@link GLCapabilitiesImmutable#isPBuffer() caps.isPBuffer()}
+ * and {@link #canCreateGLPbuffer(AbstractGraphicsDevice) canCreateGLPbuffer(device)} is true.
+ *
+ *
+ * If neither FBO nor Pbuffer is available,
+ * a simple pixmap/bitmap drawable is created, which is unlikely to be hardware accelerated.
+ *
+ *
+ * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be null for the platform's default device.
+ * @param caps the requested GLCapabilties
+ * @param chooser the custom chooser, may be null for default
+ * @param width the requested offscreen width
+ * @param height the requested offscreen height
+ *
+ * @return the created offscreen {@link GLDrawable}
*
* @throws GLException if any window system-specific errors caused
* the creation of the Offscreen to fail.
+ *
+ * @see #createOffscreenAutoDrawable(AbstractGraphicsDevice, GLCapabilitiesImmutable, GLCapabilitiesChooser, int, int, GLContext)
*/
public abstract GLDrawable createOffscreenDrawable(AbstractGraphicsDevice device,
- GLCapabilitiesImmutable capabilities,
+ GLCapabilitiesImmutable caps,
GLCapabilitiesChooser chooser,
- int width, int height)
- throws GLException;
+ int width, int height) throws GLException;
/**
* Creates a proxy {@link NativeSurface} w/ defined surface handle, i.e. a {@link WrappedSurface} or {@link GDISurface} instance.
@@ -458,6 +518,21 @@ public abstract class GLDrawableFactory {
long windowHandle,
GLCapabilitiesImmutable caps, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream);
+ /**
+ * Returns true if it is possible to create an framebuffer object (FBO).
+ *
+ * FBO feature is implemented in OpenGL, hence it is {@link GLProfile} dependent.
+ *
+ *
+ * FBO support is queried as described in {@link GLContext#hasBasicFBOSupport()}.
+ *
+ *
+ * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be null for the platform's default device.
+ * @param glp {@link GLProfile} to check for FBO capabilities
+ * @see GLContext#hasBasicFBOSupport()
+ */
+ public abstract boolean canCreateFBO(AbstractGraphicsDevice device, GLProfile glp);
+
/**
* Returns true if it is possible to create a GLPbuffer. Some older
* graphics cards do not have this capability.
@@ -467,7 +542,10 @@ public abstract class GLDrawableFactory {
public abstract boolean canCreateGLPbuffer(AbstractGraphicsDevice device);
/**
- * Creates a GLPbuffer with the given capabilites and dimensions.
+ * Creates a GLPbuffer {@link GLAutoDrawable} with the given capabilites and dimensions.
+ *
+ * The GLPbuffer drawable is realized and initialized eagerly.
+ *
*
* See the note in the overview documentation on
* context sharing.
@@ -479,10 +557,12 @@ public abstract class GLDrawableFactory {
* @param initialHeight initial height of pbuffer
* @param shareWith a shared GLContext this GLPbuffer shall use
*
- * @return the new {@link GLPbuffer} specific {@link GLAutoDrawable}
+ * @return the created and initialized {@link GLPbuffer} instance
*
* @throws GLException if any window system-specific errors caused
* the creation of the GLPbuffer to fail.
+ *
+ * @deprecated {@link GLPbuffer} is deprecated, use {@link #createOffscreenAutoDrawable(AbstractGraphicsDevice, GLCapabilitiesImmutable, GLCapabilitiesChooser, int, int, GLContext)}
*/
public abstract GLPbuffer createGLPbuffer(AbstractGraphicsDevice device,
GLCapabilitiesImmutable capabilities,
diff --git a/src/jogl/classes/javax/media/opengl/GLFBODrawable.java b/src/jogl/classes/javax/media/opengl/GLFBODrawable.java
new file mode 100644
index 000000000..45fd3b686
--- /dev/null
+++ b/src/jogl/classes/javax/media/opengl/GLFBODrawable.java
@@ -0,0 +1,173 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package javax.media.opengl;
+
+import javax.media.nativewindow.NativeWindowException;
+
+import com.jogamp.opengl.FBObject;
+import com.jogamp.opengl.FBObject.TextureAttachment;
+
+/**
+ * Platform-independent {@link GLDrawable} specialization,
+ * exposing {@link FBObject} functionality.
+ *
+ *
+ * A {@link GLFBODrawable} is uninitialized until a {@link GLContext} is bound
+ * and made current the first time.
+ *
+ *
+ *
+ * MSAA is used if {@link GLCapabilitiesImmutable#getNumSamples() requested}.
+ *
+ *
+ * Double buffering is used if {@link GLCapabilitiesImmutable#getDoubleBuffered() requested}.
+ *
+ *
+ * In MSAA mode, it always uses the implicit 2nd {@link FBObject framebuffer} {@link FBObject#getSamplingSinkFBO() sink}.
+ * Hence double buffering is always the case w/ MSAA.
+ *
+ *
+ * In non MSAA a second explicit {@link FBObject framebuffer} is being used.
+ * This method allows compliance w/ the spec, i.e. read and draw framebuffer selection
+ * and double buffer usage for e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels(..)}.
+ * This method also allows usage of both textures seperately.
+ *
+ *
+ * It would be possible to implement double buffering simply using
+ * {@link FBObject.TextureAttachment texture attachment}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.
+ *
+ *
+ * Actual swapping of the {@link FBObject.TextureAttachment texture}s or {@link FBObject framebuffer}
+ * is performed either in the {@link #contextMadeCurrent(boolean) context current hook}
+ * or when {@link #swapBuffersImpl(boolean) swapping buffers}, whatever comes first.
+ *
+ */
+public interface GLFBODrawable extends GLDrawable {
+ // public enum DoubleBufferMode { NONE, TEXTURE, FBO }; // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+
+ /**
+ * @return true if initialized, i.e. a {@link GLContext} is bound and made current once, otherwise false.
+ */
+ public boolean isInitialized();
+
+ /**
+ * 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;
+
+ /**
+ * @return the used texture unit
+ */
+ int getTextureUnit();
+
+ /**
+ *
+ * @param unit the texture unit to be used
+ */
+ void setTextureUnit(int unit);
+
+ /**
+ * Set a new sample size
+ * @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.
+ * @param newSamples new sample size
+ * @throws GLException if resetting the FBO failed
+ */
+ void setNumSamples(GL gl, int newSamples) throws GLException;
+
+ /**
+ * @return the number of sample buffers if using MSAA, otherwise 0
+ */
+ int getNumSamples();
+
+ /**
+ * @return the used {@link DoubleBufferMode}
+ */
+ // DoubleBufferMode getDoubleBufferMode(); // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+
+ /**
+ * Sets the {@link DoubleBufferMode}. Must be called before {@link #isInitialized() initialization},
+ * otherwise an exception is thrown.
+ *
+ * This call has no effect is MSAA is selected, since MSAA always forces the mode to {@link DoubleBufferMode#FBO FBO}.
+ * Also setting the mode to {@link DoubleBufferMode#NONE NONE} where double buffering is {@link GLCapabilitiesImmutable#getDoubleBuffered() requested}
+ * or setting a double buffering mode w/o {@link GLCapabilitiesImmutable#getDoubleBuffered() request} will be ignored.
+ *
+ *
+ * Since {@link DoubleBufferMode#TEXTURE TEXTURE} mode is currently not implemented, this method has no effect.
+ *
+ * @throws GLException if already initialized, see {@link #isInitialized()}.
+ */
+ // void setDoubleBufferMode(DoubleBufferMode mode) throws GLException; // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+
+ /**
+ * If MSAA is being used and {@link GL#GL_FRONT} is requested,
+ * the internal {@link FBObject} {@link FBObject#getSamplingSinkFBO() sample sink} is being returned.
+ *
+ * @param bufferName {@link GL#GL_FRONT} and {@link GL#GL_BACK} are valid buffer names
+ * @return the named {@link FBObject}
+ * @throws IllegalArgumentException if an illegal buffer name is being used
+ */
+ FBObject getFBObject(int bufferName) throws IllegalArgumentException;
+
+ /**
+ * Returns the named texture buffer.
+ *
+ * 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.
+ *
+ * @param bufferName {@link GL#GL_FRONT} and {@link GL#GL_BACK} are valid buffer names
+ * @return the named {@link TextureAttachment}
+ * @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;
+
+ /** Resizeable {@link GLFBODrawable} specialization */
+ public interface Resizeable extends GLFBODrawable {
+ /**
+ * Resize this drawable.
+ *
+ * This drawable is being locked during operation.
+ *
+ * @param context the {@link GLContext} bound to this drawable, will be made current during operation
+ * A prev. current context will be make current after operation.
+ * @param newWidth
+ * @param newHeight
+ * @throws NativeWindowException in case the surface could no be locked
+ * @throws GLException in case an error during the resize operation occurred
+ */
+ void setSize(GLContext context, int newWidth, int newHeight) throws NativeWindowException, GLException;
+ }
+}
diff --git a/src/jogl/classes/javax/media/opengl/GLOffscreenAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLOffscreenAutoDrawable.java
new file mode 100644
index 000000000..6fe76a3f4
--- /dev/null
+++ b/src/jogl/classes/javax/media/opengl/GLOffscreenAutoDrawable.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package javax.media.opengl;
+
+import javax.media.nativewindow.NativeWindowException;
+
+import com.jogamp.opengl.FBObject;
+
+/**
+ * Platform-independent {@link GLAutoDrawable} specialization,
+ * exposing offscreen functionality.
+ *
+ * This class distinguishes itself from {@link GLAutoDrawable}
+ * with it's {@link #setSize(int, int)} functionality.
+ *
+ */
+public interface GLOffscreenAutoDrawable extends GLAutoDrawable {
+
+ /**
+ * Resize this auto drawable.
+ * @param newWidth
+ * @param newHeight
+ * @throws NativeWindowException in case the surface could no be locked
+ * @throws GLException in case of an error during the resize operation
+ */
+ void setSize(int newWidth, int newHeight) throws NativeWindowException, GLException;
+
+ /**
+ * Set the upstream UI toolkit object.
+ * @see #getUpstreamWidget()
+ */
+ void setUpstreamWidget(Object newUpstreamWidget);
+
+ /** {@link FBObject} based {@link GLOffscreenAutoDrawable} specialization */
+ public interface FBO extends GLOffscreenAutoDrawable, GLFBODrawable {
+ }
+}
diff --git a/src/jogl/classes/javax/media/opengl/GLPbuffer.java b/src/jogl/classes/javax/media/opengl/GLPbuffer.java
index 273a992cf..de7731a3b 100644
--- a/src/jogl/classes/javax/media/opengl/GLPbuffer.java
+++ b/src/jogl/classes/javax/media/opengl/GLPbuffer.java
@@ -45,7 +45,11 @@ package javax.media.opengl;
contains experimental methods for accessing the pbuffer's contents
as a texture map and enabling rendering to floating-point frame
buffers. These methods are not guaranteed to be supported on all
- platforms and may be deprecated in a future release. */
+ platforms and may be deprecated in a future release.
+
+ @deprecated Use {@link GLOffscreenAutoDrawable} w/ {@link GLCapabilities#setFBO(boolean)}
+ via {@link GLDrawableFactory#createOffscreenAutoDrawable(javax.media.nativewindow.AbstractGraphicsDevice, GLCapabilitiesImmutable, GLCapabilitiesChooser, int, int, GLContext) GLDrawableFactory.createOffscreenAutoDrawable(..)}.
+ */
public interface GLPbuffer extends GLAutoDrawable {
/** Indicates the GL_APPLE_float_pixels extension is being used for this pbuffer. */
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
index 033591fe3..329cf9e3f 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
@@ -98,6 +98,7 @@ import jogamp.common.awt.AWTEDTExecutor;
import jogamp.opengl.Debug;
import jogamp.opengl.GLContextImpl;
import jogamp.opengl.GLDrawableHelper;
+import jogamp.opengl.GLDrawableImpl;
// FIXME: Subclasses need to call resetGLFunctionAvailability() on their
// context whenever the displayChanged() function is called on our
@@ -109,6 +110,16 @@ import jogamp.opengl.GLDrawableHelper;
interfaces when adding a heavyweight doesn't work either because
of Z-ordering or LayoutManager problems.
*
+ *
+ *
+ * {@link OffscreenLayerOption#setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)}
+ * maybe called to use an offscreen drawable (FBO or PBuffer) allowing
+ * the underlying JAWT mechanism to composite the image, if supported.
+ *
+ * {@link OffscreenLayerOption#setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)}
+ * is being called if {@link GLCapabilitiesImmutable#isOnscreen()} is false.
+ *
*
* To avoid any conflicts with a potential Java2D OpenGL context,
@@ -145,7 +156,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private final RecursiveLock lock = LockFactory.createRecursiveLock();
private final GLDrawableHelper helper = new GLDrawableHelper();
private AWTGraphicsConfiguration awtConfig;
- private volatile GLDrawable drawable; // volatile: avoid locking for read-only access
+ private volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access
private volatile JAWTWindow jawtWindow; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle
private GLContextImpl context;
private volatile boolean sendReshape = false; // volatile: maybe written by EDT w/o locking
@@ -237,6 +248,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
// don't allow the user to change data
capsReqUser = (GLCapabilitiesImmutable) capsReqUser.cloneMutable();
}
+ if(!capsReqUser.isOnscreen()) {
+ setShallUseOffscreenLayer(true); // trigger offscreen layer - if supported
+ }
if(null==device) {
GraphicsConfiguration gc = super.getGraphicsConfiguration();
@@ -451,11 +465,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
/** Overridden to cause OpenGL rendering to be performed during
repaint cycles. Subclasses which override this method must call
super.paint() in their paint() method in order to function
- properly.
-
- Overrides:
-
paint in class java.awt.Component
*/
- @Override
+ properly.
+ */
+ @Override
public void paint(Graphics g) {
if (Beans.isDesignTime()) {
// Make GLCanvas behave better in NetBeans GUI builder
@@ -544,7 +556,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer);
jawtWindow.lockSurface();
try {
- drawable = GLDrawableFactory.getFactory(capsReqUser.getGLProfile()).createGLDrawable(jawtWindow);
+ drawable = (GLDrawableImpl) GLDrawableFactory.getFactory(capsReqUser.getGLProfile()).createGLDrawable(jawtWindow);
context = (GLContextImpl) drawable.createContext(shareWith);
context.setContextCreationFlags(additionalCtxCreationFlags);
} finally {
@@ -561,13 +573,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
if (!Beans.isDesignTime() &&
0 < _drawable.getWidth() * _drawable.getHeight() ) {
// make sure drawable realization happens on AWT EDT, due to AWTTree lock
- AWTEDTExecutor.singleton.invoke(true, setRealizedOnEDTAction);
- sendReshape=true; // ensure a reshape is being send ..
- if(DEBUG) {
- System.err.println(getThreadName()+": Realized Drawable: "+_drawable.toString());
- Thread.dumpStack();
+ AWTEDTExecutor.singleton.invoke(getTreeLock(), true, setRealizedOnEDTAction);
+ if( _drawable.isRealized() ) {
+ sendReshape=true; // ensure a reshape is being send ..
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Realized Drawable: "+_drawable.toString());
+ Thread.dumpStack();
+ }
+ return true;
}
- return true;
}
}
return false;
@@ -575,7 +589,10 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private Runnable setRealizedOnEDTAction = new Runnable() {
@Override
public void run() {
- drawable.setRealized(true);
+ final GLDrawable _drawable = drawable;
+ if ( null != _drawable && 0 < _drawable.getWidth() * _drawable.getHeight() ) {
+ _drawable.setRealized(true);
+ }
} };
/**
Overridden to track when this component is removed from a
@@ -620,22 +637,37 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
@SuppressWarnings("deprecation")
@Override
public void reshape(int x, int y, int width, int height) {
- super.reshape(x, y, width, height);
- final GLDrawable _drawable = drawable;
- if(null != _drawable && _drawable.isRealized() && !_drawable.getChosenGLCapabilities().isOnscreen()) {
- dispose(true);
- } else {
- sendReshape = true;
+ synchronized (getTreeLock()) { // super.reshape(..) claims tree lock, so we do extend it's lock over reshape
+ super.reshape(x, y, width, height);
+
+ GLDrawableImpl _drawable = drawable;
+ if( null != _drawable ) {
+ if(DEBUG) {
+ System.err.println("GLCanvas.sizeChanged: ("+Thread.currentThread().getName()+"): "+width+"x"+height+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle()));
+ }
+ if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final GLDrawableImpl _drawableNew = GLDrawableHelper.resizeOffscreenDrawable(_drawable, context, width, height);
+ if(_drawable != _drawableNew) {
+ // write back
+ drawable = _drawableNew;
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+ sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock
+ }
}
}
- /** Overrides:
-
update in class java.awt.Component
*/
/**
* Overridden from Canvas to prevent the AWT's clearing of the
* canvas from interfering with the OpenGL rendering.
*/
- @Override
+ @Override
public void update(Graphics g) {
paint(g);
}
@@ -681,7 +713,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
_lock.lock();
try {
final GLContext oldCtx = context;
- final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
+ final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
context=(GLContextImpl)newCtx;
if(newCtxCurrent) {
context.makeCurrent();
@@ -692,6 +724,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
}
+ @Override
+ public final GLDrawable getDelegatedDrawable() {
+ return drawable;
+ }
+
@Override
public GLContext getContext() {
return context;
@@ -866,7 +903,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
if(!disposeRegenerate) {
if(null != awtConfig) {
- disposeAbstractGraphicsDevice();
+ AWTEDTExecutor.singleton.invoke(getTreeLock(), true, disposeAbstractGraphicsDeviceActionOnEDT);
}
awtConfig=null;
}
@@ -881,7 +918,13 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
};
- private final Runnable disposeAbstractGraphicsDeviceAction = new Runnable() {
+ /**
+ * Disposes the AbstractGraphicsDevice within EDT,
+ * since resources created (X11: Display), must be destroyed in the same thread, where they have been created.
+ *
+ * @see #chooseGraphicsConfiguration(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, java.awt.GraphicsDevice)
+ */
+ private final Runnable disposeAbstractGraphicsDeviceActionOnEDT = new Runnable() {
@Override
public void run() {
if(null != awtConfig) {
@@ -900,27 +943,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
}
};
-
- /**
- * Disposes the AbstractGraphicsDevice within EDT,
- * since resources created (X11: Display), must be destroyed in the same thread, where they have been created.
- *
- * @see #chooseGraphicsConfiguration(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, java.awt.GraphicsDevice)
- */
- private void disposeAbstractGraphicsDevice() {
- if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) {
- disposeAbstractGraphicsDeviceAction.run();
- } else {
- try {
- EventQueue.invokeAndWait(disposeAbstractGraphicsDeviceAction);
- } catch (InvocationTargetException e) {
- throw new GLException(e.getTargetException());
- } catch (InterruptedException e) {
- throw new GLException(e);
- }
- }
- }
-
+
private final Runnable initAction = new Runnable() {
@Override
public void run() {
@@ -1046,7 +1069,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
* @param device
* @return the chosen AWTGraphicsConfiguration
*
- * @see #disposeAbstractGraphicsDevice()
+ * @see #disposeAbstractGraphicsDeviceActionOnEDT
*/
private AWTGraphicsConfiguration chooseGraphicsConfiguration(final GLCapabilitiesImmutable capsChosen,
final GLCapabilitiesImmutable capsRequested,
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
index acb8f2183..6d4a5861f 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
@@ -121,7 +121,7 @@ import com.jogamp.opengl.util.GLBuffers;
*
*/
-@SuppressWarnings("serial")
+@SuppressWarnings({ "serial", "deprecation" })
public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol {
private static final boolean DEBUG = Debug.debug("GLJPanel");
@@ -396,7 +396,6 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
their reshape() method in order to function properly.
reshape in class java.awt.Component
*/
- @SuppressWarnings("deprecation")
@Override
public void reshape(int x, int y, int width, int height) {
super.reshape(x, y, width, height);
@@ -471,7 +470,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
return null;
}
final GLContext oldCtx = backend.getContext();
- final boolean newCtxCurrent = helper.switchContext(backend.getDrawable(), oldCtx, newCtx, additionalCtxCreationFlags);
+ final boolean newCtxCurrent = GLDrawableHelper.switchContext(backend.getDrawable(), oldCtx, newCtx, additionalCtxCreationFlags);
backend.setContext(newCtx);
if(newCtxCurrent) {
newCtx.makeCurrent();
@@ -480,6 +479,14 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
+ @Override
+ public final GLDrawable getDelegatedDrawable() {
+ if (backend == null) {
+ return null;
+ }
+ return backend.getDrawable();
+ }
+
@Override
public GLContext getContext() {
if (backend == null) {
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index cc4e1b434..07029f143 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -30,16 +30,15 @@ package jogamp.opengl;
import java.io.PrintStream;
-import javax.media.nativewindow.AbstractGraphicsConfiguration;
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.WindowClosingProtocol;
import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode;
import javax.media.opengl.FPSCounter;
import javax.media.opengl.GL;
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
-import javax.media.opengl.GLAutoDrawableDelegate;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
@@ -49,6 +48,7 @@ import javax.media.opengl.GLProfile;
import javax.media.opengl.GLRunnable;
import com.jogamp.common.util.locks.RecursiveLock;
+import com.jogamp.opengl.GLAutoDrawableDelegate;
import com.jogamp.opengl.util.Animator;
@@ -61,38 +61,36 @@ import com.jogamp.opengl.util.Animator;
* @see GLWindow
*/
public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
- public static final boolean DEBUG = Debug.debug("GLAutoDrawable");
+ public static final boolean DEBUG = GLDrawableImpl.DEBUG;
protected final GLDrawableHelper helper = new GLDrawableHelper();
protected final FPSCounterImpl fpsCounter = new FPSCounterImpl();
protected volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access
protected GLContextImpl context;
- protected final boolean ownDevice;
+ protected final boolean ownsDevice;
protected int additionalCtxCreationFlags = 0;
protected volatile boolean sendReshape = false; // volatile: maybe written by WindowManager thread w/o locking
protected volatile boolean sendDestroy = false; // volatile: maybe written by WindowManager thread w/o locking
/**
- * @param drawable a valid {@link GLDrawableImpl}, may not be realized yet.
- * @param context a valid {@link GLContextImpl}, may not be made current (created) yet.
- * @param ownDevice pass true if {@link AbstractGraphicsDevice#close()} shall be issued,
- * otherwise pass false. Closing the device is required in case
- * the drawable is created w/ it's own new instance, e.g. offscreen drawables,
- * and no further lifecycle handling is applied.
+ * @param drawable upstream {@link GLDrawableImpl} instance, may be null for lazy initialization
+ * @param context upstream {@link GLContextImpl} instance, may be null for lazy initialization
+ * @param ownsDevice pass true if {@link AbstractGraphicsDevice#close()} shall be issued,
+ * otherwise pass false. Closing the device is required in case
+ * the drawable is created w/ it's own new instance, e.g. offscreen drawables,
+ * and no further lifecycle handling is applied.
*/
- public GLAutoDrawableBase(GLDrawableImpl drawable, GLContextImpl context, boolean ownDevice) {
+ public GLAutoDrawableBase(GLDrawableImpl drawable, GLContextImpl context, boolean ownsDevice) {
this.drawable = drawable;
this.context = context;
- this.ownDevice = ownDevice;
+ this.ownsDevice = ownsDevice;
resetFPSCounter();
}
+ /** Returns the recursive lock object of the upstream implementation, which synchronizes multithreaded access. */
protected abstract RecursiveLock getLock();
- /** Returns the delegated GLDrawable */
- public final GLDrawable getDelegatedDrawable() { return drawable; }
-
/** Default implementation to handle repaint events from the windowing system */
protected final void defaultWindowRepaintOp() {
final GLDrawable _drawable = drawable;
@@ -103,29 +101,43 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
}
- /** Default implementation to handle resize events from the windowing system */
- protected final void defaultWindowResizedOp() {
- final GLDrawable _drawable = drawable;
+ /** Default implementation to handle resize events from the windowing system. All required locks are being claimed. */
+ protected final void defaultWindowResizedOp(int newWidth, int newHeight) throws NativeWindowException, GLException {
+ GLDrawableImpl _drawable = drawable;
if( null!=_drawable ) {
if(DEBUG) {
- System.err.println("GLAutoDrawableBase.sizeChanged: ("+Thread.currentThread().getName()+"): "+getWidth()+"x"+getHeight()+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle()));
+ System.err.println("GLAutoDrawableBase.sizeChanged: ("+Thread.currentThread().getName()+"): "+newWidth+"x"+newHeight+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle()));
+ }
+ if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) {
+ final RecursiveLock _lock = getLock();
+ _lock.lock();
+ try {
+ final GLDrawableImpl _drawableNew = GLDrawableHelper.resizeOffscreenDrawable(_drawable, context, newWidth, newHeight);
+ if(_drawable != _drawableNew) {
+ // write back
+ _drawable = _drawableNew;
+ drawable = _drawableNew;
+ }
+ } finally {
+ _lock.unlock();
+ }
}
sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock
if( _drawable.isRealized() ) {
if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimating() ) {
display();
}
- }
+ }
}
}
-
+
/**
* Default implementation to handle destroy notifications from the windowing system.
*
*
* If the {@link NativeSurface} does not implement {@link WindowClosingProtocol}
* or {@link WindowClosingMode#DISPOSE_ON_CLOSE} is enabled (default),
- * {@link #defaultDestroy()} is being called.
+ * a thread safe destruction is being induced.
*
*/
protected final void defaultWindowDestroyNotifyOp() {
@@ -174,7 +186,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
ctrl.resume();
}
} else if (null != ns && ns.isSurfaceLockedByOtherThread()) {
- // surface is locked by another thread
+ // Surface is locked by another thread.
// Flag that destroy should be performed on the next
// attempt to display.
sendDestroy = true; // async, but avoiding deadlock
@@ -225,7 +237,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
_drawable.setRealized(false);
}
- if( ownDevice ) {
+ if( ownsDevice ) {
_drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice().close();
}
}
@@ -238,7 +250,6 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
_lock.lock();
try {
if(drawable!=null && context != null) {
- drawable.swapBuffers();
helper.invokeGL(drawable, context, defaultSwapAction, defaultInitAction);
}
} finally {
@@ -276,7 +287,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
destroy();
return;
}
- final RecursiveLock _lock = getLock();
+ final RecursiveLock _lock = getLock();
_lock.lock();
try {
if( null != context ) {
@@ -294,6 +305,11 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
drawable.swapBuffers();
} } ;
+ @Override
+ public final GLDrawable getDelegatedDrawable() {
+ return drawable;
+ }
+
@Override
public final GLContext getContext() {
return context;
@@ -305,7 +321,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
lock.lock();
try {
final GLContext oldCtx = context;
- final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
+ final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
context=(GLContextImpl)newCtx;
if(newCtxCurrent) {
context.makeCurrent();
@@ -529,4 +545,10 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
final GLDrawable _drawable = drawable;
return null != _drawable ? _drawable.getHandle() : 0;
}
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName()+"[ \n\tHelper: " + helper + ", \n\tDrawable: " + drawable +
+ ", \n\tContext: " + context + /** ", \n\tWindow: "+window+ ", \n\tFactory: "+factory+ */ "]";
+ }
}
diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java
index e82756022..050c619fd 100644
--- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java
@@ -47,6 +47,7 @@ import java.util.Map;
import com.jogamp.common.os.DynamicLookupHelper;
import com.jogamp.common.util.ReflectionUtil;
+import com.jogamp.common.util.VersionNumber;
import com.jogamp.gluegen.runtime.FunctionAddressResolver;
import com.jogamp.gluegen.runtime.ProcAddressTable;
import com.jogamp.gluegen.runtime.opengl.GLNameResolver;
@@ -85,6 +86,7 @@ public abstract class GLContextImpl extends GLContext {
private String glRenderer;
private String glRendererLowerCase;
+ private String glVersion;
// Tracks creation and initialization of buffer objects to avoid
// repeated glGet calls upon glMapBuffer operations
@@ -126,6 +128,9 @@ public abstract class GLContextImpl extends GLContext {
GLContextShareSet.synchronizeBufferObjectSharing(shareWith, this);
this.drawable = drawable;
+ if(null != drawable) {
+ drawable.associateContext(this, true);
+ }
this.drawableRead = drawable;
this.glDebugHandler = new GLDebugMessageHandler(this);
@@ -205,8 +210,10 @@ public abstract class GLContextImpl extends GLContext {
if(!setWriteOnly || drawableRead==drawable) { // if !setWriteOnly || !explicitReadDrawable
drawableRead = (GLDrawableImpl) readWrite;
}
- final GLDrawable old = drawable;
+ final GLDrawableImpl old = drawable;
+ old.associateContext(this, false);
drawable = (GLDrawableImpl) readWrite ;
+ drawable.associateContext(this, true);
if(lockHeld) {
makeCurrent();
}
@@ -272,7 +279,7 @@ public abstract class GLContextImpl extends GLContext {
if( actualRelease ) {
if( !inDestruction ) {
try {
- drawable.contextMadeCurrent(this, false);
+ contextMadeCurrent(false);
} catch (Throwable t) {
drawableContextMadeCurrentException = t;
}
@@ -331,7 +338,8 @@ public abstract class GLContextImpl extends GLContext {
makeCurrent();
}
try {
- drawable.contextRealized(this, false);
+ contextRealized(false);
+ drawable.associateContext(this, false);
} catch (Throwable t) {
drawableContextRealizedException = t;
}
@@ -514,19 +522,17 @@ public abstract class GLContextImpl extends GLContext {
gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) );
}
- drawable.contextRealized(this, true);
+ contextRealized(true);
if(DEBUG || TRACE_SWITCH) {
System.err.println(getThreadName() +": GLContext.ContextSwitch: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+" - switch - CONTEXT_CURRENT_NEW - "+lock);
}
- } else {
- drawable.contextMadeCurrent(this, true);
-
- if(TRACE_SWITCH) {
- System.err.println(getThreadName() +": GLContext.ContextSwitch: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+" - switch - CONTEXT_CURRENT - "+lock);
- }
+ } else if(TRACE_SWITCH) {
+ System.err.println(getThreadName() +": GLContext.ContextSwitch: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+" - switch - CONTEXT_CURRENT - "+lock);
}
+ contextMadeCurrent(true);
+
/* FIXME: refactor dependence on Java 2D / JOGL bridge
// Try cleaning up any stale server-side OpenGL objects
@@ -608,6 +614,20 @@ public abstract class GLContextImpl extends GLContext {
}
protected abstract void makeCurrentImpl() throws GLException;
+ /**
+ * @see GLDrawableImpl#contextRealized(GLContext, boolean)
+ */
+ protected void contextRealized(boolean realized) {
+ drawable.contextRealized(this, realized);
+ }
+
+ /**
+ * @see GLDrawableImpl#contextMadeCurrent(GLContext, boolean)
+ */
+ protected void contextMadeCurrent(boolean current) {
+ drawable.contextMadeCurrent(this, current);
+ }
+
/**
* Platform dependent entry point for context creation.
*
@@ -934,52 +954,43 @@ public abstract class GLContextImpl extends GLContext {
/**
* If major > 0 || minor > 0 : Use passed values, determined at creation time
- * If major==0 && minor == 0 : Use GL_VERSION
* Otherwise .. don't touch ..
*/
private final void setContextVersion(int major, int minor, int ctp, boolean setVersionString) {
- if (0==ctp) {
+ if ( 0 == ctp ) {
throw new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctp));
}
- if(major>0 || minor>0) {
- if (!GLContext.isValidGLVersion(major, minor)) {
- GLException e = new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctp));
- throw e;
- }
- ctxMajorVersion = major;
- ctxMinorVersion = minor;
- ctxOptions = ctp;
- if(setVersionString) {
- ctxVersionString = getGLVersion(ctxMajorVersion, ctxMinorVersion, ctxOptions, getGL().glGetString(GL.GL_VERSION));
- }
- return;
+
+ if (!GLContext.isValidGLVersion(major, minor)) {
+ throw new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctp));
}
-
- if(major==0 && minor==0) {
- String versionStr = getGL().glGetString(GL.GL_VERSION);
- if(null==versionStr) {
- throw new GLException("GL_VERSION is NULL: "+this);
- }
- ctxOptions = ctp;
-
- // Set version
- GLVersionNumber version = new GLVersionNumber(versionStr);
+ ctxMajorVersion = major;
+ ctxMinorVersion = minor;
+ ctxOptions = ctp;
+ if(setVersionString) {
+ ctxVersionString = getGLVersion(ctxMajorVersion, ctxMinorVersion, ctxOptions, getGL().glGetString(GL.GL_VERSION));
+ }
+ }
+
+ private static final VersionNumber getGLVersionNumber(int ctp, String glVersionStr) {
+ if( null != glVersionStr ) {
+ final GLVersionNumber version = new GLVersionNumber(glVersionStr);
if (version.isValid()) {
- ctxMajorVersion = version.getMajor();
- ctxMinorVersion = version.getMinor();
- // We cannot promote a non ARB context to >= 3.1,
- // reduce it to 3.0 then.
- if ( ( ctxMajorVersion>3 || ctxMajorVersion==3 && ctxMinorVersion>=1 )
- && 0 == (ctxOptions & CTX_IS_ARB_CREATED) ) {
- ctxMajorVersion = 3;
- ctxMinorVersion = 0;
- }
- if(setVersionString) {
- ctxVersionString = getGLVersion(ctxMajorVersion, ctxMinorVersion, ctxOptions, versionStr);
- }
- return;
+ int major = version.getMajor();
+ int minor = version.getMinor();
+ // We cannot promote a non ARB context to >= 3.1,
+ // reduce it to 3.0 then.
+ if ( 0 == (ctp & CTX_IS_ARB_CREATED) &&
+ ( major > 3 || major == 3 && minor >= 1 ) ) {
+ major = 3;
+ minor = 0;
+ }
+ if ( GLContext.isValidGLVersion(major, minor) ) {
+ return new VersionNumber(major, minor, 0);
+ }
}
}
+ return null;
}
//----------------------------------------------------------------------
@@ -1019,14 +1030,18 @@ public abstract class GLContextImpl extends GLContext {
/**
* Pbuffer support; given that this is a GLContext associated with a
* pbuffer, binds this pbuffer to its texture target.
+ * @throws GLException if not implemented (default)
+ * @deprecated use FBO/GLOffscreenAutoDrawable instead of pbuffer
*/
- public abstract void bindPbufferToTexture();
+ public void bindPbufferToTexture() { throw new GLException("not implemented"); }
/**
* Pbuffer support; given that this is a GLContext associated with a
* pbuffer, releases this pbuffer from its texture target.
+ * @throws GLException if not implemented (default)
+ * @deprecated use FBO/GLOffscreenAutoDrawable instead of pbuffer
*/
- public abstract void releasePbufferFromTexture();
+ public void releasePbufferFromTexture() { throw new GLException("not implemented"); }
public abstract ByteBuffer glAllocateMemoryNV(int arg0, float arg1, float arg2, float arg3);
@@ -1064,7 +1079,7 @@ public abstract class GLContextImpl extends GLContext {
table.reset(getDrawableImpl().getGLDynamicLookupHelper() );
}
- private final boolean initGLRendererStrings() {
+ private final boolean initGLRendererAndGLVersionStrings() {
final GLDynamicLookupHelper glDynLookupHelper = getDrawableImpl().getGLDynamicLookupHelper();
final long _glGetString = glDynLookupHelper.dynamicLookupFunction("glGetString");
if(0 == _glGetString) {
@@ -1083,14 +1098,27 @@ public abstract class GLContextImpl extends GLContext {
Thread.dumpStack();
}
return false;
- } else {
- glRenderer = _glRenderer;
- glRendererLowerCase = glRenderer.toLowerCase();
- return true;
}
+ glRenderer = _glRenderer;
+ glRendererLowerCase = glRenderer.toLowerCase();
+
+ final String _glVersion = glGetStringInt(GL.GL_VERSION, _glGetString);
+ if(null == _glVersion) {
+ // FIXME
+ if(DEBUG) {
+ System.err.println("Warning: GL_VERSION is NULL.");
+ Thread.dumpStack();
+ }
+ return false;
+ }
+ glVersion = _glVersion;
+ return true;
}
}
+ protected final String getGLVersionString() {
+ return glVersion;
+ }
protected final String getGLRendererString(boolean lowerCase) {
return lowerCase ? glRendererLowerCase : glRenderer;
}
@@ -1128,17 +1156,44 @@ public abstract class GLContextImpl extends GLContext {
final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration();
final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice();
- if( !initGLRendererStrings() && DEBUG) {
- System.err.println("Warning: intialization of GL renderer strings failed. "+adevice+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null));
+ {
+ final boolean initGLRendererAndGLVersionStringsOK = initGLRendererAndGLVersionStrings();
+ if(DEBUG) {
+ if( !initGLRendererAndGLVersionStringsOK ) {
+ System.err.println("Warning: setGLFunctionAvailability: intialization of GL renderer strings failed. "+adevice+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null));
+ } else {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Given "+adevice+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion));
+ }
+ }
}
if(!isCurrentContextHardwareRasterizer()) {
ctxProfileBits |= GLContext.CTX_IMPL_ACCEL_SOFT;
}
-
+
+ // Pick the version from the GL-version string,
+ // if smaller _or_ given major == 0.
+ final VersionNumber glVersionNumber;
+ {
+ final VersionNumber setGLVersionNumber = new VersionNumber(major, minor, 0);
+ final VersionNumber strGLVersionNumber = getGLVersionNumber(ctxProfileBits, glVersion);
+ if( null != strGLVersionNumber && ( strGLVersionNumber.compareTo(setGLVersionNumber) <= 0 || 0 == major ) ) {
+ glVersionNumber = strGLVersionNumber;
+ major = glVersionNumber.getMajor();
+ minor = glVersionNumber.getMinor();
+ } else {
+ glVersionNumber = setGLVersionNumber;
+ }
+ }
+ if ( !GLContext.isValidGLVersion(major, minor) ) {
+ throw new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctxProfileBits)+", "+glVersion+", "+glVersionNumber);
+ }
+ if( 2 > major ) { // there is no ES2-compat for a profile w/ major < 2
+ ctxProfileBits &= ~GLContext.CTX_IMPL_ES2_COMPAT;
+ }
contextFQN = getContextFQN(adevice, major, minor, ctxProfileBits);
if (DEBUG) {
- System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.0 FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null));
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.0 validated FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion) + ", "+glVersionNumber);
}
//
@@ -1201,6 +1256,10 @@ public abstract class GLContextImpl extends GLContext {
ctxProfileBits |= CTX_IMPL_FBO;
}
+ if(FORCE_NO_FBO_SUPPORT) {
+ ctxProfileBits &= ~CTX_IMPL_FBO ;
+ }
+
//
// Set GL Version (complete w/ version string)
//
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java
index e1e253d35..4f965f620 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java
@@ -48,18 +48,21 @@ import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.OffscreenLayerSurface;
import javax.media.nativewindow.ProxySurface;
import javax.media.nativewindow.MutableSurface;
-import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook;
-import javax.media.opengl.GLCapabilities;
+import javax.media.nativewindow.UpstreamSurfaceHook;
import javax.media.opengl.GLCapabilitiesChooser;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
+import javax.media.opengl.GLFBODrawable;
+import javax.media.opengl.GLOffscreenAutoDrawable;
import javax.media.opengl.GLPbuffer;
import javax.media.opengl.GLProfile;
import com.jogamp.nativewindow.MutableGraphicsConfiguration;
+import com.jogamp.nativewindow.DelegatedUpstreamSurfaceHookWithSurfaceSize;
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
/** Extends GLDrawableFactory with a few methods for handling
@@ -67,6 +70,7 @@ import com.jogamp.nativewindow.MutableGraphicsConfiguration;
Independent Bitmaps on Windows, pixmaps on X11). Direct access to
these GLDrawables is not supplied directly to end users, though
they may be instantiated by the GLJPanel implementation. */
+@SuppressWarnings("deprecation")
public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
protected static final boolean DEBUG = GLDrawableImpl.DEBUG;
@@ -141,55 +145,53 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(target, true);
if(null != ols) {
// layered surface -> Offscreen/[FBO|PBuffer]
- final GLCapabilities chosenCapsMod = (GLCapabilities) chosenCaps.cloneMutable();
- chosenCapsMod.setOnscreen(false);
- chosenCapsMod.setDoubleBuffered(false);
- /* if( isFBOAvailable ) { // FIXME JAU: FBO n/a yet
- chosenCapsMod.setFBO(true);
- } else */
- if( canCreateGLPbuffer(adevice) ) {
- chosenCapsMod.setPBuffer(true);
- } else {
- chosenCapsMod.setFBO(false);
- chosenCapsMod.setPBuffer(false);
+ final boolean isPbufferAvailable = canCreateGLPbuffer(adevice) ;
+ if(!isPbufferAvailable && !isFBOAvailable) {
+ throw new GLException("Neither FBO nor Pbuffer is available for "+target);
}
+ final GLCapabilitiesImmutable chosenCapsMod = GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(chosenCaps, isFBOAvailable, isPbufferAvailable);
config.setChosenCapabilities(chosenCapsMod);
+ ols.setChosenCapabilities(chosenCapsMod);
if(DEBUG) {
- System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable -> Offscreen-Layer: "+target);
+ System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable -> Offscreen-Layer");
+ System.err.println("chosenCaps: "+chosenCaps);
+ System.err.println("chosenCapsMod: "+chosenCapsMod);
+ System.err.println("OffscreenLayerSurface: **** "+ols);
+ System.err.println("Target: **** "+target);
+ Thread.dumpStack();
}
if( ! ( target instanceof MutableSurface ) ) {
throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen layered surface: "+target);
}
- if( ((GLCapabilitiesImmutable)config.getRequestedCapabilities()).isFBO() && isFBOAvailable ) {
- // FIXME JAU: Need to revise passed MutableSurface to work w/ FBO ..
- final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(target);
- result = new GLFBODrawableImpl(this, dummyDrawable, target, target.getWidth(), target.getHeight(), 0 /* textureUnit */);
+ if( chosenCapsMod.isFBO() && isFBOAvailable ) {
+ // target surface is already a native one
+ result = createFBODrawableImpl(target, chosenCapsMod, 0);
} else {
result = createOffscreenDrawableImpl(target);
}
} else if(chosenCaps.isOnscreen()) {
// onscreen
+ final GLCapabilitiesImmutable chosenCapsMod = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(chosenCaps);
+ config.setChosenCapabilities(chosenCapsMod);
if(DEBUG) {
System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable: "+target);
}
result = createOnscreenDrawableImpl(target);
} else {
// offscreen
- final GLCapabilitiesImmutable reqCaps = (GLCapabilitiesImmutable)config.getRequestedCapabilities();
if(DEBUG) {
- System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable, FBO req / chosen - avail, PBuffer: "+reqCaps.isFBO()+" / "+chosenCaps.isFBO()+" - "+isFBOAvailable+", "+chosenCaps.isPBuffer()+": "+target);
+ System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable, FBO chosen / avail, PBuffer: "+
+ chosenCaps.isFBO()+" / "+isFBOAvailable+", "+chosenCaps.isPBuffer()+": "+target);
}
if( ! ( target instanceof MutableSurface ) ) {
- throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen: "+target);
+ throw new IllegalArgumentException("Passed NativeSurface must implement MutableSurface for offscreen: "+target);
}
- if( reqCaps.isFBO() && isFBOAvailable ) {
- // FIXME JAU: Need to revise passed MutableSurface to work w/ FBO ..
- final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(target);
- result = new GLFBODrawableImpl(this, dummyDrawable, target, target.getWidth(), target.getHeight(), 0 /* textureUnit */);
+ if( chosenCaps.isFBO() && isFBOAvailable ) {
+ // need to hook-up a native dummy surface since source may not have
+ final ProxySurface dummySurface = createDummySurfaceImpl(adevice, true, chosenCaps, null, 64, 64);
+ dummySurface.setUpstreamSurfaceHook(new DelegatedUpstreamSurfaceHookWithSurfaceSize(dummySurface.getUpstreamSurfaceHook(), target));
+ result = createFBODrawableImpl(dummySurface, chosenCaps, 0);
} else {
- final GLCapabilities chosenCapsMod = (GLCapabilities) chosenCaps.cloneMutable();
- chosenCapsMod.setDoubleBuffered(false);
- config.setChosenCapabilities(chosenCapsMod);
result = createOffscreenDrawableImpl(target);
}
}
@@ -211,7 +213,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
//---------------------------------------------------------------------------
//
- // PBuffer Offscreen GLDrawable construction
+ // PBuffer Offscreen GLAutoDrawable construction
//
@Override
@@ -239,7 +241,8 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
GLDrawableImpl drawable = null;
device.lock();
try {
- drawable = (GLDrawableImpl) createGLDrawable( createMutableSurfaceImpl(device, true, capsChosen, capsRequested, chooser, width, height, null) );
+ drawable = createOffscreenDrawableImpl( createMutableSurfaceImpl(device, true, capsChosen, capsRequested, chooser,
+ new UpstreamSurfaceHookMutableSize(width, height) ) );
if(null != drawable) {
drawable.setRealized(true);
}
@@ -247,10 +250,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
device.unlock();
}
- if(null==drawable) {
- throw new GLException("Could not create Pbuffer drawable for: "+device+", "+capsChosen+", "+width+"x"+height);
- }
- return new GLPbufferImpl( drawable, shareWith, true);
+ return new GLPbufferImpl( drawable, (GLContextImpl) drawable.createContext(shareWith) );
}
//---------------------------------------------------------------------------
@@ -258,6 +258,29 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
// Offscreen GLDrawable construction
//
+ public final boolean canCreateFBO(AbstractGraphicsDevice deviceReq, GLProfile glp) {
+ AbstractGraphicsDevice device = getOrCreateSharedDevice(deviceReq);
+ if(null == device) {
+ throw new GLException("No shared device for requested: "+deviceReq);
+ }
+ return GLContext.isFBOAvailable(device, glp);
+ }
+
+ @Override
+ public GLOffscreenAutoDrawable createOffscreenAutoDrawable(AbstractGraphicsDevice deviceReq,
+ GLCapabilitiesImmutable capsRequested,
+ GLCapabilitiesChooser chooser,
+ int width, int height,
+ GLContext shareWith) {
+ final GLDrawable drawable = createOffscreenDrawable( deviceReq, capsRequested, chooser, width, height );
+ drawable.setRealized(true);
+ final GLContext context = drawable.createContext(shareWith);
+ if(drawable instanceof GLFBODrawableImpl) {
+ return new GLOffscreenAutoDrawableImpl.FBOImpl( (GLFBODrawableImpl)drawable, context, null, null );
+ }
+ return new GLOffscreenAutoDrawableImpl( drawable, context, null, null);
+ }
+
@Override
public GLDrawable createOffscreenDrawable(AbstractGraphicsDevice deviceReq,
GLCapabilitiesImmutable capsRequested,
@@ -274,10 +297,13 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
final GLCapabilitiesImmutable capsChosen = GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(capsRequested,
GLContext.isFBOAvailable(device, capsRequested.getGLProfile()),
canCreateGLPbuffer(device));
+
if( capsChosen.isFBO() ) {
device.lock();
try {
- return createFBODrawableImpl(device, capsRequested, chooser, width, height);
+ final ProxySurface dummySurface = createDummySurfaceImpl(device, true, capsRequested, null, width, height);
+ final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(dummySurface);
+ return new GLFBODrawableImpl.ResizeableImpl(this, dummyDrawable, dummySurface, capsChosen, 0);
} finally {
device.unlock();
}
@@ -285,20 +311,17 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
device.lock();
try {
- return createOffscreenDrawableImpl( createMutableSurfaceImpl(device, true, capsChosen, capsRequested, chooser, width, height, null) );
+ return createOffscreenDrawableImpl( createMutableSurfaceImpl(device, true, capsChosen, capsRequested, chooser,
+ new UpstreamSurfaceHookMutableSize(width, height) ) );
} finally {
device.unlock();
}
}
- /** Creates a platform independent offscreen FBO GLDrawable implementation */
- protected GLDrawable createFBODrawableImpl(AbstractGraphicsDevice device, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser,
- int initialWidth, int initialHeight) {
- final GLCapabilitiesImmutable dummyCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(requestedCaps);
- final NativeSurface dummySurface = createDummySurfaceImpl(device, true, dummyCaps, null, 64, 64);
+ /** Creates a platform independent FBO offscreen GLDrawable */
+ protected GLFBODrawable createFBODrawableImpl(NativeSurface dummySurface, GLCapabilitiesImmutable fboCaps, int textureUnit) {
final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(dummySurface);
-
- return new GLFBODrawableImpl(this, dummyDrawable, dummySurface, initialWidth, initialHeight, 0 /* textureUnit */);
+ return new GLFBODrawableImpl(this, dummyDrawable, dummySurface, fboCaps, textureUnit);
}
/** Creates a platform dependent offscreen pbuffer/pixmap GLDrawable implementation */
@@ -318,15 +341,13 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
* @param capsChosen
* @param capsRequested
* @param chooser the custom chooser, may be null for default
- * @param width the initial width
- * @param height the initial height
- * @param lifecycleHook optional control of the surface's lifecycle
+ * @param upstreamHook surface size information and optional control of the surface's lifecycle
* @return the created {@link MutableSurface} instance w/o defined surface handle
*/
protected abstract ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice device, boolean createNewDevice,
GLCapabilitiesImmutable capsChosen,
GLCapabilitiesImmutable capsRequested,
- GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook);
+ GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook);
/**
* A dummy surface is not visible on screen and will not be used to render directly to,
@@ -341,9 +362,9 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
* @param width the initial width
* @param height the initial height
*
- * @return the created {@link MutableSurface} instance w/o defined surface handle
+ * @return the created {@link ProxySurface} instance w/o defined surface handle but platform specific {@link UpstreamSurfaceHook}.
*/
- public NativeSurface createDummySurface(AbstractGraphicsDevice deviceReq, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser,
+ public ProxySurface createDummySurface(AbstractGraphicsDevice deviceReq, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser,
int width, int height) {
final AbstractGraphicsDevice device = getOrCreateSharedDevice(deviceReq);
if(null == device) {
@@ -369,9 +390,11 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory {
* otherwise device instance is used as-is.
* @param requestedCaps
* @param chooser the custom chooser, may be null for default
- * @param width the initial width
- * @param height the initial height
- * @return the created {@link MutableSurface} instance w/o defined surface handle
+ * @param width the initial width as returned by {@link NativeSurface#getWidth()}, not the actual dummy surface width.
+ * The latter is platform specific and small
+ * @param height the initial height as returned by {@link NativeSurface#getHeight()}, not the actual dummy surface height,
+ * The latter is platform specific and small
+ * @return the created {@link ProxySurface} instance w/o defined surface handle but platform specific {@link UpstreamSurfaceHook}.
*/
public abstract ProxySurface createDummySurfaceImpl(AbstractGraphicsDevice device, boolean createNewDevice,
GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height);
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
index 090c5fe69..bdf0b6d74 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
@@ -43,12 +43,19 @@ package jogamp.opengl;
import java.util.ArrayList;
import java.util.HashSet;
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLException;
+import javax.media.opengl.GLFBODrawable;
import javax.media.opengl.GLRunnable;
import com.jogamp.opengl.util.Animator;
@@ -108,24 +115,27 @@ public class GLDrawableHelper {
/**
* Associate a new context to the drawable and also propagates the context/drawable switch by
* calling {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.
- *
- * If the old context's drawable was an {@link GLAutoDrawable}, it's reference to the given drawable
- * is being cleared by calling
- * {@link GLAutoDrawable#setContext(GLContext) ((GLAutoDrawable)oldCtx.getGLDrawable()).setContext(null)}.
- *
*
* If the old or new context was current on this thread, it is being released before switching the drawable.
*
+ *
+ * Be aware that the old context is still bound to the drawable,
+ * and that one context can only bound to one drawable at one time!
+ *
+ *
+ * No locking is being performed on the drawable, caller is required to take care of it.
+ *
*
* @param drawable the drawable which context is changed
- * @param newCtx the new context
* @param oldCtx the old context
- * @return true if the newt context was current, otherwise false
+ * @param newCtx the new context
+ * @param newCtxCreationFlags additional creation flags if newCtx is not null and not been created yet, see {@link GLContext#setContextCreationFlags(int)}
+ * @return true if the new context was current, otherwise false
*
* @see GLAutoDrawable#setContext(GLContext)
*/
- public final boolean switchContext(GLDrawable drawable, GLContext oldCtx, GLContext newCtx, int additionalCtxCreationFlags) {
- if(null != oldCtx && oldCtx.isCurrent()) {
+ public static final boolean switchContext(GLDrawable drawable, GLContext oldCtx, GLContext newCtx, int newCtxCreationFlags) {
+ if( null != oldCtx && oldCtx.isCurrent() ) {
oldCtx.release();
}
final boolean newCtxCurrent;
@@ -134,17 +144,135 @@ public class GLDrawableHelper {
if(newCtxCurrent) {
newCtx.release();
}
- newCtx.setContextCreationFlags(additionalCtxCreationFlags);
+ newCtx.setContextCreationFlags(newCtxCreationFlags);
newCtx.setGLDrawable(drawable, true); // propagate context/drawable switch
} else {
newCtxCurrent = false;
}
- if(null!=oldCtx && oldCtx.getGLDrawable() instanceof GLAutoDrawable) {
- ((GLAutoDrawable)oldCtx.getGLDrawable()).setContext(null);
- }
return newCtxCurrent;
}
+ /**
+ * If the drawable is not realized, OP is a NOP.
+ *
+ *
release context if current
+ *
destroy old drawable
+ *
create new drawable
+ *
attach new drawable to context
+ *
make context current, if it was current
+ *
+ *
+ * No locking is being performed, caller is required to take care of it.
+ *
+ * The {@link GLDrawableImpl}'s {@link NativeSurface} is being locked during operation.
+ * In case the holder is an auto drawable or similar, it's lock shall be claimed by the caller.
+ *
+ *
+ * May recreate the drawable via {@link #recreateGLDrawable(GLDrawableImpl, GLContext)}
+ * in case of a a pbuffer- or pixmap-drawable.
+ *
+ * Offscreen resize operation is validated w/ drawable size in the end.
+ * An exception is thrown if not successful.
+ *
+ *
+ * @param drawable
+ * @param context
+ * @param newWidth the new width, it's minimum is capped to 1
+ * @param newHeight the new height, it's minimum is capped to 1
+ * @return the new drawable in case of an pbuffer/pixmap drawable, otherwise the passed drawable is being returned.
+ * @throws NativeWindowException is drawable is not offscreen or it's surface lock couldn't be claimed
+ * @throws GLException may be thrown a resize operation
+ */
+ public static final GLDrawableImpl resizeOffscreenDrawable(GLDrawableImpl drawable, GLContext context, int newWidth, int newHeight)
+ throws NativeWindowException, GLException
+ {
+ if(drawable.getChosenGLCapabilities().isOnscreen()) {
+ throw new NativeWindowException("Drawable is not offscreen: "+drawable);
+ }
+ final NativeSurface ns = drawable.getNativeSurface();
+ final int lockRes = ns.lockSurface();
+ if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) {
+ throw new NativeWindowException("Could not lock surface of drawable: "+drawable);
+ }
+ try {
+ if(0>=newWidth) { newWidth = 1; }
+ if(0>=newHeight) { newHeight = 1; }
+ // propagate new size
+ if(ns instanceof ProxySurface) {
+ final ProxySurface ps = (ProxySurface) ns;
+ final UpstreamSurfaceHook ush = ps.getUpstreamSurfaceHook();
+ if(ush instanceof UpstreamSurfaceHook.MutableSize) {
+ ((UpstreamSurfaceHook.MutableSize)ush).setSize(newWidth, newHeight);
+ } else if(DEBUG) { // we have to assume UpstreamSurfaceHook contains the new size already, hence size check @ bottom
+ System.err.println("GLDrawableHelper.resizeOffscreenDrawable: Drawable's offscreen ProxySurface n.a. UpstreamSurfaceHook.MutableSize, but "+ush.getClass().getName()+": "+ush);
+ }
+ } else if(DEBUG) { // we have to assume surface contains the new size already, hence size check @ bottom
+ System.err.println("GLDrawableHelper.resizeOffscreenDrawable: Drawable's offscreen surface n.a. ProxySurface, but "+ns.getClass().getName()+": "+ns);
+ }
+ if(drawable instanceof GLFBODrawable) {
+ if( null != context && context.isCreated() ) {
+ ((GLFBODrawable) drawable).resetSize(context.getGL());
+ }
+ } else {
+ drawable = GLDrawableHelper.recreateGLDrawable(drawable, context);
+ }
+ } finally {
+ ns.unlockSurface();
+ }
+ if(drawable.getWidth() != newWidth || drawable.getHeight() != newHeight) {
+ throw new InternalError("Incomplete resize operation: expected "+newWidth+"x"+newHeight+", has: "+drawable);
+ }
+ return drawable;
+ }
+
public final void addGLEventListener(GLEventListener listener) {
addGLEventListener(-1, listener);
}
@@ -196,15 +324,11 @@ public class GLDrawableHelper {
}
}
- private final boolean init(GLEventListener l, GLAutoDrawable drawable, boolean sendReshape) {
- if(listenersToBeInit.remove(l)) {
- l.init(drawable);
- if(sendReshape) {
- reshape(l, drawable, 0, 0, drawable.getWidth(), drawable.getHeight(), true /* setViewport */, false /* checkInit */);
- }
- return true;
+ private final void init(GLEventListener l, GLAutoDrawable drawable, boolean sendReshape) {
+ l.init(drawable);
+ if(sendReshape) {
+ reshape(l, drawable, 0, 0, drawable.getWidth(), drawable.getHeight(), true /* setViewport */, false /* checkInit */);
}
- return false;
}
/** The default init action to be called once after ctx is being created @ 1st makeCurrent(). */
@@ -214,14 +338,11 @@ public class GLDrawableHelper {
for (int i=0; i < _listeners.size(); i++) {
final GLEventListener listener = _listeners.get(i) ;
- // If make current ctx, invoked by invokGL(..), results in a new ctx, init gets called.
+ // If make ctx current, invoked by invokGL(..), results in a new ctx, init gets called.
// This may happen not just for initial setup, but for ctx recreation due to resource change (drawable/window),
- // hence the must always be initialized unconditional.
- listenersToBeInit.add(listener);
-
- if ( ! init( listener, drawable, true /* sendReshape */) ) {
- throw new GLException("GLEventListener "+listener+" already initialized: "+drawable);
- }
+ // hence it must be called unconditional, always.
+ listenersToBeInit.remove(listener); // remove if exist, avoiding dbl init
+ init( listener, drawable, true /* sendReshape */);
}
}
}
@@ -239,7 +360,9 @@ public class GLDrawableHelper {
final GLEventListener listener = _listeners.get(i) ;
// GLEventListener may need to be init,
// in case this one is added after the realization of the GLAutoDrawable
- init( listener, drawable, true /* sendReshape */) ;
+ if( listenersToBeInit.remove(listener) ) {
+ init( listener, drawable, true /* sendReshape */) ;
+ }
listener.display(drawable);
}
}
@@ -251,7 +374,9 @@ public class GLDrawableHelper {
// GLEventListener may need to be init,
// in case this one is added after the realization of the GLAutoDrawable
synchronized(listenersLock) {
- init( listener, drawable, false /* sendReshape */) ;
+ if( listenersToBeInit.remove(listener) ) {
+ init( listener, drawable, false /* sendReshape */) ;
+ }
}
}
if(setViewport) {
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java
index abf2bf557..311690f1d 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java
@@ -43,6 +43,7 @@ package jogamp.opengl;
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.ProxySurface;
+import javax.media.opengl.GL;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
@@ -76,31 +77,46 @@ public abstract class GLDrawableImpl implements GLDrawable {
if( !realized ) {
return; // destroyed already
}
- final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)surface.getGraphicsConfiguration().getChosenCapabilities();
- if ( caps.getDoubleBuffered() ) {
- if(!surface.surfaceSwap()) {
- int lockRes = lockSurface(); // it's recursive, so it's ok within [makeCurrent .. release]
- if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) {
- return;
+ int lockRes = lockSurface(); // it's recursive, so it's ok within [makeCurrent .. release]
+ if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) {
+ return;
+ }
+ try {
+ if (NativeSurface.LOCK_SURFACE_CHANGED == lockRes) {
+ updateHandle();
+ }
+ final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)surface.getGraphicsConfiguration().getChosenCapabilities();
+ if ( caps.getDoubleBuffered() ) {
+ if(!surface.surfaceSwap()) {
+ swapBuffersImpl(true);
}
- try {
- if (NativeSurface.LOCK_SURFACE_CHANGED == lockRes) {
- updateHandle();
- }
- swapBuffersImpl();
- } finally {
- unlockSurface();
+ } else {
+ final GLContext ctx = GLContext.getCurrent();
+ if(null!=ctx && ctx.getGLDrawable()==this) {
+ ctx.getGL().glFlush();
}
+ swapBuffersImpl(false);
}
- } else {
- GLContext ctx = GLContext.getCurrent();
- if(null!=ctx && ctx.getGLDrawable()==this) {
- ctx.getGL().glFinish();
- }
- }
+ } finally {
+ unlockSurface();
+ }
surface.surfaceUpdated(this, surface, System.currentTimeMillis());
}
- protected abstract void swapBuffersImpl();
+
+ /**
+ * Platform and implementation depending surface swap.
+ *
The surface is locked.
+ *
+ * If doubleBuffered is true,
+ * an actual platform dependent surface swap shall be executed.
+ *
+ *
+ * If doubleBuffered is false,
+ * {@link GL#glFlush()} has been called already and
+ * the implementation may execute implementation specific code.
+ *
+ */
+ protected abstract void swapBuffersImpl(boolean doubleBuffered);
public final static String toHexString(long hex) {
return "0x" + Long.toHexString(hex);
@@ -181,6 +197,9 @@ public abstract class GLDrawableImpl implements GLDrawable {
System.err.println(getThreadName() + ": setRealized: "+getClass().getName()+" "+this.realized+" == "+realizedArg);
}
}
+ /**
+ * Platform specific realization of drawable
+ */
protected abstract void setRealizedImpl();
/**
@@ -189,7 +208,7 @@ public abstract class GLDrawableImpl implements GLDrawable {
* If realized is true, the context has just been created and made current.
*
*
- * If realized is false, the context is still current and will be release and destroyed after this method returns.
+ * If realized is false, the context is still current and will be released and destroyed after this method returns.
*
*
* @see #contextMadeCurrent(GLContext, boolean)
@@ -199,18 +218,27 @@ public abstract class GLDrawableImpl implements GLDrawable {
/**
* Callback for special implementations, allowing GLContext to trigger GL related lifecycle: makeCurrent, release.
*
- * Will not be called if {@link #contextRealized(GLContext, boolean)} has been triggered.
- *
- *
* If current is true, the context has just been made current.
*
*
* If current is false, the context is still current and will be release after this method returns.
*
+ *
+ * Note: Will also be called after {@link #contextRealized(GLContext, boolean) contextRealized(ctx, true)}
+ * but not at context destruction, i.e. {@link #contextRealized(GLContext, boolean) contextRealized(ctx, false)}.
+ *
* @see #contextRealized(GLContext, boolean)
*/
protected void contextMadeCurrent(GLContext glc, boolean current) { }
+ /**
+ * Callback for special implementations, allowing to associate bound context to this drawable (bound == true)
+ * or to remove such association (bound == false).
+ * @param ctx the just bounded or unbounded context
+ * @param bound if true create an association, otherwise remove it
+ */
+ protected void associateContext(GLContext ctx, boolean bound) { }
+
/** Callback for special implementations, allowing GLContext to fetch a custom default render framebuffer. Defaults to zero.*/
protected int getDefaultDrawFramebuffer() { return 0; }
/** Callback for special implementations, allowing GLContext to fetch a custom default read framebuffer. Defaults to zero. */
@@ -245,8 +273,8 @@ public abstract class GLDrawableImpl implements GLDrawable {
public String toString() {
return getClass().getSimpleName()+"[Realized "+isRealized()+
",\n\tFactory "+getFactory()+
- ",\n\thandle "+toHexString(getHandle())+
- ",\n\tWindow "+getNativeSurface()+"]";
+ ",\n\tHandle "+toHexString(getHandle())+
+ ",\n\tSurface "+getNativeSurface()+"]";
}
protected static String getThreadName() {
diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java
index 03bc26cbc..de45466f3 100644
--- a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java
@@ -1,142 +1,476 @@
package jogamp.opengl;
import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
import javax.media.opengl.GL;
-import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLException;
+import javax.media.opengl.GLFBODrawable;
import com.jogamp.nativewindow.MutableGraphicsConfiguration;
import com.jogamp.opengl.FBObject;
import com.jogamp.opengl.FBObject.Attachment;
+import com.jogamp.opengl.FBObject.Colorbuffer;
import com.jogamp.opengl.FBObject.TextureAttachment;
/**
- * Offscreen GLDrawable implementation using framebuffer object (FBO)
- * as it's offscreen rendering mechanism.
+ * {@link FBObject} offscreen GLDrawable implementation, i.e. {@link GLFBODrawable}.
+ *
+ * It utilizes the context lifecycle hook {@link #contextRealized(GLContext, boolean)}
+ * to initialize the {@link FBObject} instance.
+ *
+ *
+ * It utilizes the context current hook {@link #contextMadeCurrent(GLContext, boolean) contextMadeCurrent(context, true)}
+ * to {@link FBObject#bind(GL) bind} the FBO.
+ *
+ * See {@link GLFBODrawable} for double buffering details.
*
* @see GLDrawableImpl#contextRealized(GLContext, boolean)
* @see GLDrawableImpl#contextMadeCurrent(GLContext, boolean)
* @see GLDrawableImpl#getDefaultDrawFramebuffer()
* @see GLDrawableImpl#getDefaultReadFramebuffer()
*/
-public class GLFBODrawableImpl extends GLDrawableImpl {
- final GLDrawableImpl parent;
- final FBObject fbo;
- int texUnit;
- int samplesTexUnit = 0;
- int width=0, height=0, samples=0;
-
- protected GLFBODrawableImpl(GLDrawableFactoryImpl factory, GLDrawableImpl parent,
- NativeSurface surface, int initialWidth, int initialHeight, int textureUnit) {
+public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable {
+ protected static final boolean DEBUG = GLDrawableImpl.DEBUG || Debug.debug("FBObject");
+
+ private final GLDrawableImpl parent;
+
+ private boolean initialized;
+ private int texUnit;
+ private int samples;
+
+ private FBObject[] fbos;
+ private int fboIBack; // points to GL_BACK buffer
+ private int fboIFront; // points to GL_FRONT buffer
+ private FBObject pendingFBOReset = null;
+ private boolean fboBound;
+ private static final int bufferCount = 2; // number of FBOs for double buffering. TODO: Possible to configure!
+
+ // private DoubleBufferMode doubleBufferMode; // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+
+ private SwapBufferContext swapBufferContext;
+
+ public static interface SwapBufferContext {
+ public void swapBuffers(boolean doubleBuffered);
+ }
+
+ protected GLFBODrawableImpl(GLDrawableFactoryImpl factory, GLDrawableImpl parent, NativeSurface surface,
+ GLCapabilitiesImmutable fboCaps, int textureUnit) {
super(factory, surface, false);
+ this.initialized = false;
+
+ // Replace the chosen caps of dummy-surface w/ it's clone and copied values of orig FBO caps request.
+ // The dummy-surface has already been configured, hence value replace is OK
+ // and due to cloning, the native GLCapability portion is being preserved.
+ final MutableGraphicsConfiguration msConfig = (MutableGraphicsConfiguration) surface.getGraphicsConfiguration();
+ final GLCapabilities fboCapsNative = (GLCapabilities) msConfig.getChosenCapabilities().cloneMutable();
+ fboCapsNative.copyFrom(fboCaps);
+ msConfig.setChosenCapabilities(fboCapsNative);
+
this.parent = parent;
this.texUnit = textureUnit;
- final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities();
- this.width = initialWidth;
- this.height = initialHeight;
- this.samples = caps.getNumSamples();
- this.fbo = new FBObject();
+ this.samples = fboCaps.getNumSamples();
+
+ // default .. // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+ // this.doubleBufferMode = ( samples > 0 || fboCaps.getDoubleBuffered() ) ? DoubleBufferMode.FBO : DoubleBufferMode.NONE ;
+
+ this.swapBufferContext = null;
}
- @Override
- protected void contextRealized(GLContext glc, boolean realized) {
- final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities();
- final GL gl = glc.getGL();
- if(realized) {
- fbo.reset(gl, width, height, samples);
- samples = fbo.getNumSamples(); // update, maybe capped
+ private final void initialize(boolean realize, GL gl) {
+ if(realize) {
+ final int maxSamples = gl.getMaxRenderbufferSamples();
+ samples = samples <= maxSamples ? samples : maxSamples;
+
+ final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities();
+ final int fbosN;
if(samples > 0) {
- fbo.attachColorbuffer(gl, 0, caps.getAlphaBits()>0);
+ fbosN = 1;
+ } else if( caps.getDoubleBuffered() ) {
+ fbosN = bufferCount;
} else {
- fbo.attachTexture2D(gl, 0, caps.getAlphaBits()>0);
+ fbosN = 1;
}
- if( caps.getStencilBits() > 0 ) {
- fbo.attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24);
- } else {
- fbo.attachRenderbuffer(gl, Attachment.Type.DEPTH, 24);
+
+ fbos = new FBObject[fbosN];
+ fboIBack = 0; // head
+ fboIFront = fbos.length - 1; // tail
+
+ for(int i=0; i 0) {
+ fbos[i].attachColorbuffer(gl, 0, caps.getAlphaBits()>0);
+ } else {
+ fbos[i].attachTexture2D(gl, 0, caps.getAlphaBits()>0);
+ }
+ if( caps.getStencilBits() > 0 ) {
+ fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24);
+ } else {
+ fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH, 24);
+ }
}
- } else if(null != fbo) {
- fbo.destroy(gl);
- }
- }
-
- @Override
- protected void contextMadeCurrent(GLContext glc, boolean current) {
- final GL gl = glc.getGL();
- if(current) {
- fbo.bind(gl);
+ fbos[fboIFront].syncFramebuffer(gl);
+ fboBound = false;
+ final GLCapabilities fboCapsNative = (GLCapabilities) surface.getGraphicsConfiguration().getChosenCapabilities();
+ fbos[0].formatToGLCapabilities(fboCapsNative);
+ fboCapsNative.setDoubleBuffered( fboCapsNative.getDoubleBuffered() || samples > 0 );
+
+ initialized = true;
} else {
- fbo.unbind(gl);
- final TextureAttachment attachment = samples > 0 ? fbo.getSamplingSink() : (TextureAttachment) fbo.getColorbuffer(0) ;
- if(null == attachment) {
- throw new GLException("Null texture colorbuffer, samples "+samples+", "+fbo.toString());
- }
- gl.glActiveTexture(GL.GL_TEXTURE0 + texUnit);
- fbo.use(gl, attachment );
- if( samples > 0) {
- gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, fbo.getReadFramebuffer());
+ initialized = false;
+
+ for(int i=0; i "+newSamples);
+ }
+ initialize(false, gl);
+ samples = newSamples;
+ initialize(true, gl);
+ } else {
+ if(DEBUG) {
+ System.err.println("GLFBODrawableImpl.reset(): simple reconfig: "+samples+" -> "+newSamples);
+ }
+ final int nWidth = getWidth();
+ final int nHeight = getHeight();
+ samples = newSamples;
+ pendingFBOReset = ( 1 < fbos.length ) ? fbos[fboIFront] : null; // pending-front reset only w/ double buffering (or zero samples)
+ for(int i=0; i 0 ? fbos[fboIFront].getSamplingSink() : fbos[fboIFront].getColorbuffer(0);
+ final TextureAttachment texAttachment;
+ if(colorbuffer instanceof TextureAttachment) {
+ texAttachment = (TextureAttachment) colorbuffer;
+ } else {
+ if(null == colorbuffer) {
+ throw new GLException("Front colorbuffer is null: samples "+samples+", "+this);
+ } else {
+ throw new GLException("Front colorbuffer is not a texture: "+colorbuffer.getClass().getName()+": samples "+samples+", "+colorbuffer+", "+this);
+ }
+ }
+ gl.glActiveTexture(GL.GL_TEXTURE0 + texUnit);
+ fbos[fboIFront].use(gl, texAttachment);
+
+ /* Included in above use command:
+ gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, fbos[fboIBack].getDrawFramebuffer());
+ gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, fbos[fboIFront].getReadFramebuffer());
+ } */
+
+ if(DEBUG) {
+ System.err.println("Post FBO swap(X): fboI back "+fboIBack+", front "+fboIFront+", num "+fbos.length);
+ }
}
+ //
+ // GLFBODrawable
+ //
+
+ @Override
+ public final boolean isInitialized() {
+ return initialized;
+ }
+
@Override
- public int getHeight() {
- return height;
+ public final void resetSize(GL gl) throws GLException {
+ reset(gl, samples);
}
+
+ @Override
+ public final int getTextureUnit() { return texUnit; }
+
+ @Override
+ public final void setTextureUnit(int u) { texUnit = u; }
+
+ @Override
+ public final int getNumSamples() { return samples; }
+
+ @Override
+ public void setNumSamples(GL gl, int newSamples) throws GLException {
+ if(samples != newSamples) {
+ reset(gl, newSamples);
+ }
+ }
+
+ /** // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+ @Override
+ public final DoubleBufferMode getDoubleBufferMode() {
+ return doubleBufferMode;
+ }
+
+ @Override
+ public final void setDoubleBufferMode(DoubleBufferMode mode) throws GLException {
+ if(initialized) {
+ throw new GLException("Not allowed past initialization: "+this);
+ }
+ final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities();
+ if(0 == samples && caps.getDoubleBuffered() && DoubleBufferMode.NONE != mode) {
+ doubleBufferMode = mode;
+ }
+ } */
+
+ @Override
+ public FBObject getFBObject(int bufferName) throws IllegalArgumentException {
+ if(!initialized) {
+ return null;
+ }
+ final FBObject res;
+ switch(bufferName) {
+ case GL.GL_FRONT:
+ if( samples > 0 ) {
+ res = fbos[0].getSamplingSinkFBO();
+ } else {
+ res = fbos[fboIFront];
+ }
+ break;
+ case GL.GL_BACK:
+ res = fbos[fboIBack];
+ break;
+ default:
+ throw new IllegalArgumentException(illegalBufferName+toHexString(bufferName));
+ }
+ return res;
+ }
+
+ @Override
+ public final TextureAttachment getTextureBuffer(int bufferName) throws IllegalArgumentException {
+ if(!initialized) {
+ return null;
+ }
+ final TextureAttachment res;
+ switch(bufferName) {
+ case GL.GL_FRONT:
+ if( samples > 0 ) {
+ res = fbos[0].getSamplingSink();
+ } else {
+ res = (TextureAttachment) fbos[fboIFront].getColorbuffer(0);
+ }
+ break;
+ case GL.GL_BACK:
+ if( samples > 0 ) {
+ throw new IllegalArgumentException("Cannot access GL_BACK buffer of MSAA FBO: "+this);
+ } else {
+ res = (TextureAttachment) fbos[fboIBack].getColorbuffer(0);
+ }
+ break;
+ default:
+ throw new IllegalArgumentException(illegalBufferName+toHexString(bufferName));
+ }
+ return res;
+ }
+ private static final String illegalBufferName = "Only GL_FRONT and GL_BACK buffer are allowed, passed ";
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName()+"[Initialized "+initialized+", realized "+isRealized()+", texUnit "+texUnit+", samples "+samples+
+ ",\n\tFactory "+getFactory()+
+ ",\n\tHandle "+toHexString(getHandle())+
+ ",\n\tCaps "+surface.getGraphicsConfiguration().getChosenCapabilities()+
+ ",\n\tfboI back "+fboIBack+", front "+fboIFront+", num "+(initialized ? fbos.length : 0)+
+ ",\n\tFBO front read "+getDefaultReadFramebuffer()+", "+getFBObject(GL.GL_FRONT)+
+ ",\n\tFBO back write "+getDefaultDrawFramebuffer()+", "+getFBObject(GL.GL_BACK)+
+ ",\n\tSurface "+getNativeSurface()+
+ "]";
+ }
+
+ public static class ResizeableImpl extends GLFBODrawableImpl implements GLFBODrawable.Resizeable {
+ protected ResizeableImpl(GLDrawableFactoryImpl factory, GLDrawableImpl parent, ProxySurface surface,
+ GLCapabilitiesImmutable fboCaps, int textureUnit) {
+ super(factory, parent, surface, fboCaps, textureUnit);
+ }
+
+ @Override
+ public final void setSize(GLContext context, int newWidth, int newHeight) throws NativeWindowException, GLException {
+ if(DEBUG) {
+ System.err.println("GLFBODrawableImpl.ResizeableImpl setSize: ("+Thread.currentThread().getName()+"): "+newWidth+"x"+newHeight+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle()));
+ }
+ int lockRes = lockSurface();
+ if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) {
+ throw new NativeWindowException("Could not lock surface: "+this);
+ }
+ try {
+ // propagate new size
+ final ProxySurface ps = (ProxySurface) getNativeSurface();
+ final UpstreamSurfaceHook ush = ps.getUpstreamSurfaceHook();
+ if(ush instanceof UpstreamSurfaceHook.MutableSize) {
+ ((UpstreamSurfaceHook.MutableSize)ush).setSize(newWidth, newHeight);
+ } else {
+ throw new InternalError("GLFBODrawableImpl.ResizableImpl's ProxySurface doesn't hold a UpstreamSurfaceHookMutableSize but "+ush.getClass().getName()+", "+ps+", ush");
+ }
+ if( null != context && context.isCreated() ) {
+ resetSize(context.getGL());
+ }
+ } finally {
+ unlockSurface();
+ }
+ }
+ }
}
diff --git a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java
index 768fc6892..79f96b64a 100644
--- a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java
+++ b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java
@@ -28,8 +28,12 @@
package jogamp.opengl;
+import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+
+import com.jogamp.common.os.Platform;
public class GLGraphicsConfigurationUtil {
public static final String NV_coverage_sample = "NV_coverage_sample";
@@ -119,26 +123,34 @@ public class GLGraphicsConfigurationUtil {
return getExclusiveWinAttributeBits(caps.isOnscreen(), caps.isFBO(), caps.isPBuffer(), caps.isBitmap());
}
- public static final GLCapabilities setWinAttributeBits(GLCapabilities caps, int winattrbits) {
+ public static final GLCapabilities fixWinAttribBitsAndHwAccel(AbstractGraphicsDevice device, int winattrbits, GLCapabilities caps) {
caps.setBitmap ( 0 != ( BITMAP_BIT & winattrbits ) );
caps.setPBuffer ( 0 != ( PBUFFER_BIT & winattrbits ) );
caps.setFBO ( 0 != ( FBO_BIT & winattrbits ) );
// we reflect availability semantics, hence setting onscreen at last (maybe overwritten above)!
- caps.setOnscreen( 0 != ( WINDOW_BIT & winattrbits ) );
- return caps;
- }
+ caps.setOnscreen( 0 != ( WINDOW_BIT & winattrbits ) );
+ final int accel = GLContext.isHardwareRasterizer( device, caps.getGLProfile() );
+ if(0 == accel && caps.getHardwareAccelerated() ) {
+ caps.setHardwareAccelerated(false);
+ }
+
+ return caps;
+ }
+
public static GLCapabilitiesImmutable fixGLCapabilities(GLCapabilitiesImmutable capsRequested, boolean fboAvailable, boolean pbufferAvailable)
{
if( !capsRequested.isOnscreen() ) {
return fixOffscreenGLCapabilities(capsRequested, fboAvailable, pbufferAvailable);
- }
+ } /* we maintain the offscreen mode flags in onscreen mode - else {
+ return fixOnscreenGLCapabilities(capsRequested);
+ } */
return capsRequested;
}
public static GLCapabilitiesImmutable fixOnscreenGLCapabilities(GLCapabilitiesImmutable capsRequested)
{
- if( !capsRequested.isOnscreen() ) {
+ if( !capsRequested.isOnscreen() || capsRequested.isFBO() || capsRequested.isPBuffer() || capsRequested.isBitmap() ) {
// fix caps ..
final GLCapabilities caps2 = (GLCapabilities) capsRequested.cloneMutable();
caps2.setBitmap (false);
@@ -157,9 +169,11 @@ public class GLGraphicsConfigurationUtil {
public static GLCapabilitiesImmutable fixOffscreenGLCapabilities(GLCapabilitiesImmutable capsRequested, boolean fboAvailable, boolean pbufferAvailable) {
final boolean auto = !capsRequested.isFBO() && !capsRequested.isPBuffer() && !capsRequested.isBitmap() ;
+
+ final boolean requestedPBuffer = capsRequested.isPBuffer() || Platform.getOSType() == Platform.OSType.MACOS ; // no native bitmap for OSX
final boolean useFBO = fboAvailable && ( auto || capsRequested.isFBO() ) ;
- final boolean usePbuffer = !useFBO && pbufferAvailable && ( auto || capsRequested.isPBuffer() ) ;
+ final boolean usePbuffer = !useFBO && pbufferAvailable && ( auto || requestedPBuffer ) ;
final boolean useBitmap = !useFBO && !usePbuffer && ( auto || capsRequested.isBitmap() ) ;
if( capsRequested.isOnscreen() ||
diff --git a/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java
new file mode 100644
index 000000000..7701f209f
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java
@@ -0,0 +1,123 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package jogamp.opengl;
+
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.opengl.GL;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLOffscreenAutoDrawable;
+
+import com.jogamp.common.util.locks.RecursiveLock;
+import com.jogamp.opengl.FBObject;
+import com.jogamp.opengl.GLAutoDrawableDelegate;
+
+import jogamp.opengl.GLFBODrawableImpl;
+
+public class GLOffscreenAutoDrawableImpl extends GLAutoDrawableDelegate implements GLOffscreenAutoDrawable {
+
+ /**
+ * @param drawable a valid and already realized {@link GLDrawable}
+ * @param context a valid {@link GLContext}, may not be made current (created) yet.
+ * @param upstreamWidget optional UI element holding this instance, see {@link #getUpstreamWidget()}.
+ * @param lock optional upstream lock, may be null
+ */
+ public GLOffscreenAutoDrawableImpl(GLDrawable drawable, GLContext context, Object upstreamWidget, RecursiveLock lock) {
+ super(drawable, context, upstreamWidget, true, lock);
+ }
+
+ @Override
+ public void setSize(int newWidth, int newHeight) throws NativeWindowException, GLException {
+ this.defaultWindowResizedOp(newWidth, newHeight);
+ }
+
+ public static class FBOImpl extends GLOffscreenAutoDrawableImpl implements GLOffscreenAutoDrawable.FBO {
+ /**
+ * @param drawable a valid and already realized {@link GLDrawable}
+ * @param context a valid {@link GLContext}, may not be made current (created) yet.
+ * @param upstreamWidget optional UI element holding this instance, see {@link #getUpstreamWidget()}.
+ * @param lock optional upstream lock, may be null
+ */
+ public FBOImpl(GLFBODrawableImpl drawable, GLContext context, Object upstreamWidget, RecursiveLock lock) {
+ super(drawable, context, upstreamWidget, lock);
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return ((GLFBODrawableImpl)drawable).isInitialized();
+ }
+
+ @Override
+ public final int getTextureUnit() {
+ return ((GLFBODrawableImpl)drawable).getTextureUnit();
+ }
+
+ @Override
+ public final void setTextureUnit(int unit) {
+ ((GLFBODrawableImpl)drawable).setTextureUnit(unit);
+ }
+
+ @Override
+ public final int getNumSamples() {
+ return ((GLFBODrawableImpl)drawable).getNumSamples();
+ }
+
+ @Override
+ public final void setNumSamples(GL gl, int newSamples) throws GLException {
+ ((GLFBODrawableImpl)drawable).setNumSamples(gl, newSamples);
+ windowRepaintOp();
+ }
+
+ /** // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+ @Override
+ public DoubleBufferMode getDoubleBufferMode() {
+ return ((GLFBODrawableImpl)drawable).getDoubleBufferMode();
+ }
+
+ @Override
+ public void setDoubleBufferMode(DoubleBufferMode mode) throws GLException {
+ ((GLFBODrawableImpl)drawable).setDoubleBufferMode(mode);
+ } */
+
+ @Override
+ public final FBObject getFBObject(int bufferName) {
+ return ((GLFBODrawableImpl)drawable).getFBObject(bufferName);
+ }
+
+ public final FBObject.TextureAttachment getTextureBuffer(int bufferName) {
+ return ((GLFBODrawableImpl)drawable).getTextureBuffer(bufferName);
+ }
+
+ @Override
+ public void resetSize(GL gl) throws GLException {
+ ((GLFBODrawableImpl)drawable).resetSize(gl);
+ }
+ }
+}
diff --git a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
index 32f4cb696..b438131bc 100644
--- a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
@@ -40,9 +40,6 @@
package jogamp.opengl;
-import javax.media.opengl.GLCapabilitiesImmutable;
-import javax.media.opengl.GLContext;
-import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
import javax.media.opengl.GLPbuffer;
@@ -50,36 +47,18 @@ import javax.media.opengl.GLPbuffer;
import com.jogamp.common.util.locks.LockFactory;
import com.jogamp.common.util.locks.RecursiveLock;
-/** Platform-independent class exposing pbuffer functionality to
- applications. This class is not exposed in the public API as it
- would probably add no value; however it implements the GLDrawable
- interface so can be interacted with via its display() method. */
-
+@SuppressWarnings("deprecation")
public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer {
private int floatMode;
- public GLPbufferImpl(GLDrawableImpl pbufferDrawable, GLContext sharedContext, boolean ownDevice) {
- super(pbufferDrawable, null, ownDevice); // drawable := pbufferDrawable
-
- GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)
- drawable.getNativeSurface().getGraphicsConfiguration().getChosenCapabilities();
- if(caps.isOnscreen()) {
- if(caps.isPBuffer()) {
- throw new IllegalArgumentException("Error: Given drawable is Onscreen and Pbuffer: "+pbufferDrawable);
- }
- throw new IllegalArgumentException("Error: Given drawable is Onscreen: "+pbufferDrawable);
- } else {
- if(!caps.isPBuffer()) {
- throw new IllegalArgumentException("Error: Given drawable is not Pbuffer: "+pbufferDrawable);
- }
- }
- context = (GLContextImpl) drawable.createContext(sharedContext);
+ public GLPbufferImpl(GLDrawableImpl pbufferDrawable, GLContextImpl pbufferContext) {
+ super(pbufferDrawable, pbufferContext, true); // drawable := pbufferDrawable, context := pbufferContext
}
//
// pbuffer specifics
- //
-
+ //
+
@Override
public void bindTexture() {
// Doesn't make much sense to try to do this on the event dispatch
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java
index 03d0d650f..06953a8e1 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java
@@ -282,12 +282,6 @@ public abstract class EGLContext extends GLContextImpl {
return EGL.eglSwapInterval(drawable.getNativeSurface().getDisplayHandle(), interval);
}
- @Override
- public abstract void bindPbufferToTexture();
-
- @Override
- public abstract void releasePbufferFromTexture();
-
//
// Accessible ..
//
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java
index 0dba4bb09..167eebf3a 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java
@@ -36,7 +36,8 @@
package jogamp.opengl.egl;
-import javax.media.nativewindow.MutableSurface;
+import java.nio.IntBuffer;
+
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.ProxySurface;
@@ -46,10 +47,10 @@ import javax.media.opengl.GLException;
import jogamp.opengl.GLDrawableImpl;
import jogamp.opengl.GLDynamicLookupHelper;
+import com.jogamp.common.nio.Buffers;
import com.jogamp.nativewindow.egl.EGLGraphicsDevice;
public abstract class EGLDrawable extends GLDrawableImpl {
- private boolean ownEGLSurface = false; // for destruction
protected EGLDrawable(EGLDrawableFactory factory, NativeSurface component) throws GLException {
super(factory, component, false);
@@ -58,21 +59,14 @@ public abstract class EGLDrawable extends GLDrawableImpl {
@Override
public abstract GLContext createContext(GLContext shareWith);
- protected abstract long createSurface(EGLGraphicsConfiguration config, long nativeSurfaceHandle);
+ protected abstract long createSurface(EGLGraphicsConfiguration config, int width, int height, long nativeSurfaceHandle);
- private final void recreateSurface() {
- final EGLGraphicsConfiguration eglConfig = (EGLGraphicsConfiguration) surface.getGraphicsConfiguration();
- final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) eglConfig.getScreen().getDevice();
- if(DEBUG) {
- System.err.println(getThreadName() + ": createSurface using "+eglConfig);
- }
- if( EGL.EGL_NO_SURFACE != surface.getSurfaceHandle() ) {
- EGL.eglDestroySurface(eglDevice.getHandle(), surface.getSurfaceHandle());
- }
+ private final long createEGLSurface() {
+ final EGLWrappedSurface eglws = (EGLWrappedSurface) surface;
+ final EGLGraphicsConfiguration eglConfig = (EGLGraphicsConfiguration) eglws.getGraphicsConfiguration();
+ final NativeSurface upstreamSurface = eglws.getUpstreamSurface();
- final EGLUpstreamSurfaceHook upstreamHook = (EGLUpstreamSurfaceHook) ((ProxySurface)surface).getUpstreamSurfaceHook();
- final NativeSurface upstreamSurface = upstreamHook.getUpstreamSurface();
- long eglSurface = createSurface(eglConfig, upstreamSurface.getSurfaceHandle());
+ long eglSurface = createSurface(eglConfig, eglws.getWidth(), eglws.getHeight(), upstreamSurface.getSurfaceHandle());
int eglError0;
if (EGL.EGL_NO_SURFACE == eglSurface) {
@@ -86,7 +80,7 @@ public abstract class EGLDrawable extends GLDrawableImpl {
if(DEBUG) {
System.err.println(getThreadName() + ": Info: Creation of window surface w/ surface handle failed: "+eglConfig+", error "+toHexString(eglError0)+", retry w/ windowHandle");
}
- eglSurface = createSurface(eglConfig, nw.getWindowHandle());
+ eglSurface = createSurface(eglConfig, eglws.getWidth(), eglws.getHeight(), nw.getWindowHandle());
if (EGL.EGL_NO_SURFACE == eglSurface) {
eglError0 = EGL.eglGetError();
}
@@ -99,34 +93,53 @@ public abstract class EGLDrawable extends GLDrawableImpl {
if (EGL.EGL_NO_SURFACE == eglSurface) {
throw new GLException("Creation of window surface failed: "+eglConfig+", "+surface+", error "+toHexString(eglError0));
}
-
if(DEBUG) {
- System.err.println(getThreadName() + ": setSurface using component: handle "+toHexString(surface.getSurfaceHandle())+" -> "+toHexString(eglSurface));
+ System.err.println(getThreadName() + ": createEGLSurface handle "+toHexString(eglSurface));
}
-
- ((MutableSurface)surface).setSurfaceHandle(eglSurface);
+ return eglSurface;
}
@Override
protected final void updateHandle() {
- if(ownEGLSurface) {
- recreateSurface();
+ final EGLWrappedSurface eglws = (EGLWrappedSurface) surface;
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": updateHandle of "+eglws);
+ }
+ if( eglws.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ if( EGL.EGL_NO_SURFACE != eglws.getSurfaceHandle() ) {
+ throw new InternalError("Set surface but claimed to be invalid: "+eglws);
+ }
+ eglws.setSurfaceHandle( createEGLSurface() );
+ } else if( EGL.EGL_NO_SURFACE == eglws.getSurfaceHandle() ) {
+ throw new InternalError("Nil surface but claimed to be valid: "+eglws);
+ }
+ }
+
+ protected void destroyHandle() {
+ final EGLWrappedSurface eglws = (EGLWrappedSurface) surface;
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": destroyHandle of "+eglws);
+ }
+ if( EGL.EGL_NO_SURFACE == eglws.getSurfaceHandle() ) {
+ throw new InternalError("Nil surface but claimed to be valid: "+eglws);
+ }
+ final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) eglws.getGraphicsConfiguration().getScreen().getDevice();
+ if( eglws.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ EGL.eglDestroySurface(eglDevice.getHandle(), eglws.getSurfaceHandle());
+ eglws.setSurfaceHandle(EGL.EGL_NO_SURFACE);
}
}
- protected static boolean isValidEGLSurface(EGLGraphicsDevice eglDevice, NativeSurface surface) {
- final long eglDisplayHandle = eglDevice.getHandle();
- if (EGL.EGL_NO_DISPLAY == eglDisplayHandle) {
- throw new GLException("Invalid EGL display in EGLGraphicsDevice "+eglDevice);
+ protected static boolean isValidEGLSurface(long eglDisplayHandle, long surfaceHandle) {
+ if( 0 == surfaceHandle ) {
+ return false;
}
- boolean eglSurfaceValid = 0 != surface.getSurfaceHandle();
- if(eglSurfaceValid) {
- int[] tmp = new int[1];
- eglSurfaceValid = EGL.eglQuerySurface(eglDisplayHandle, surface.getSurfaceHandle(), EGL.EGL_CONFIG_ID, tmp, 0);
- if(!eglSurfaceValid) {
- if(DEBUG) {
- System.err.println(getThreadName() + ": EGLDrawable.isValidEGLSurface eglQuerySuface failed: "+toHexString(EGL.eglGetError())+", "+surface);
- }
+ final IntBuffer val = Buffers.newDirectIntBuffer(1);
+ final boolean eglSurfaceValid = EGL.eglQuerySurface(eglDisplayHandle, surfaceHandle, EGL.EGL_CONFIG_ID, val);
+ if( !eglSurfaceValid ) {
+ final int eglErr = EGL.eglGetError();
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": EGLDrawable.isValidEGLSurface eglQuerySuface failed: error "+toHexString(eglErr)+", "+toHexString(surfaceHandle));
}
}
return eglSurfaceValid;
@@ -134,55 +147,19 @@ public abstract class EGLDrawable extends GLDrawableImpl {
@Override
protected final void setRealizedImpl() {
- final EGLGraphicsConfiguration eglConfig = (EGLGraphicsConfiguration) surface.getGraphicsConfiguration();
- final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) eglConfig.getScreen().getDevice();
- if (realized) {
- final boolean eglSurfaceValid = isValidEGLSurface(eglDevice, surface);
- if(eglSurfaceValid) {
- // surface holds valid EGLSurface
- if(DEBUG) {
- System.err.println(getThreadName() + ": EGLDrawable.setRealizedImpl re-using component's EGLSurface: handle "+toHexString(surface.getSurfaceHandle()));
- }
- ownEGLSurface=false;
- } else {
- // EGLSurface is ours - subsequent updateHandle() will issue recreateSurface();
- // However .. let's validate the surface object first
- if( ! (surface instanceof ProxySurface) ) {
- throw new InternalError("surface not ProxySurface: "+surface.getClass().getName()+", "+surface);
- }
- final ProxySurface.UpstreamSurfaceHook upstreamHook = ((ProxySurface)surface).getUpstreamSurfaceHook();
- if( null == upstreamHook ) {
- throw new InternalError("null upstreamHook of: "+surface);
- }
- if( ! (upstreamHook instanceof EGLUpstreamSurfaceHook) ) {
- throw new InternalError("upstreamHook not EGLUpstreamSurfaceHook: Surface: "+surface.getClass().getName()+", "+surface+"; UpstreamHook: "+upstreamHook.getClass().getName()+", "+upstreamHook);
- }
- if( null == ((EGLUpstreamSurfaceHook)upstreamHook).getUpstreamSurface() ) {
- throw new InternalError("null upstream surface");
- }
- ownEGLSurface=true;
- if(DEBUG) {
- System.err.println(getThreadName() + ": EGLDrawable.setRealizedImpl owning EGLSurface");
- }
- }
- } else if (ownEGLSurface && surface.getSurfaceHandle() != EGL.EGL_NO_SURFACE) {
- if(DEBUG) {
- System.err.println(getThreadName() + ": EGLDrawable.setRealized(false): ownSurface "+ownEGLSurface+", "+eglDevice+", eglSurface: "+toHexString(surface.getSurfaceHandle()));
- }
- // Destroy the window surface
- if (!EGL.eglDestroySurface(eglDevice.getHandle(), surface.getSurfaceHandle())) {
- throw new GLException("Error destroying window surface (eglDestroySurface)");
- }
- ((MutableSurface)surface).setSurfaceHandle(EGL.EGL_NO_SURFACE);
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": EGLDrawable.setRealized("+realized+"): NOP - "+surface);
}
}
@Override
- protected final void swapBuffersImpl() {
- final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice();
- // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers()
- if(!EGL.eglSwapBuffers(eglDevice.getHandle(), surface.getSurfaceHandle())) {
- throw new GLException("Error swapping buffers, eglError "+toHexString(EGL.eglGetError())+", "+this);
+ protected final void swapBuffersImpl(boolean doubleBuffered) {
+ if(doubleBuffered) {
+ final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice();
+ // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers()
+ if(!EGL.eglSwapBuffers(eglDevice.getHandle(), surface.getSurfaceHandle())) {
+ throw new GLException("Error swapping buffers, eglError "+toHexString(EGL.eglGetError())+", "+this);
+ }
}
}
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java
index 292eb17c8..e98d69140 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java
@@ -52,8 +52,7 @@ import javax.media.nativewindow.MutableSurface;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.ProxySurface;
-import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook;
-import javax.media.nativewindow.VisualIDHolder.VIDType;
+import javax.media.nativewindow.UpstreamSurfaceHook;
import javax.media.nativewindow.VisualIDHolder;
import javax.media.opengl.GL;
import javax.media.opengl.GLCapabilities;
@@ -65,6 +64,7 @@ import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
+import jogamp.nativewindow.WrappedSurface;
import jogamp.opengl.Debug;
import jogamp.opengl.GLDrawableFactoryImpl;
import jogamp.opengl.GLDrawableImpl;
@@ -76,10 +76,11 @@ import com.jogamp.common.nio.Buffers;
import com.jogamp.common.nio.PointerBuffer;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.ReflectionUtil;
-import com.jogamp.nativewindow.WrappedSurface;
import com.jogamp.nativewindow.egl.EGLGraphicsDevice;
public class EGLDrawableFactory extends GLDrawableFactoryImpl {
+ protected static final boolean DEBUG = GLDrawableFactoryImpl.DEBUG;
+
/* package */ static final boolean QUERY_EGL_ES = !Debug.isPropertyDefined("jogl.debug.EGLDrawableFactory.DontQuery", true);
/* package */ static final boolean QUERY_EGL_ES_NATIVE_TK = Debug.isPropertyDefined("jogl.debug.EGLDrawableFactory.QueryNativeTK", true);
@@ -112,7 +113,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl {
} catch (JogampRuntimeException jre) { /* n/a .. */ }
}
- defaultDevice = new EGLGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT);
+ defaultDevice = new EGLGraphicsDevice();
// FIXME: Probably need to move EGL from a static model
// to a dynamic one, where there can be 2 instances
@@ -310,6 +311,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl {
try {
final GLCapabilities reqCapsAny = new GLCapabilities(glp);
reqCapsAny.setRedBits(5); reqCapsAny.setGreenBits(5); reqCapsAny.setBlueBits(5); reqCapsAny.setAlphaBits(0);
+ reqCapsAny.setDoubleBuffered(false);
final GLCapabilitiesImmutable reqCapsPBuffer = GLGraphicsConfigurationUtil.fixGLPBufferGLCapabilities(reqCapsAny);
final List availablePBufferCapsL = getAvailableEGLConfigs(sharedEGLDevice, reqCapsPBuffer);
hasPBuffer[0] = availablePBufferCapsL.size() > 0;
@@ -324,18 +326,20 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl {
} else {
final List capsAnyL = getAvailableEGLConfigs(eglDevice, reqCapsAny);
if(capsAnyL.size() > 0) {
- final GLCapabilitiesImmutable caps = capsAnyL.get(0);
- EGLContext.mapStaticGLESVersion(eglDevice, caps);
+ final GLCapabilitiesImmutable chosenCaps = capsAnyL.get(0);
+ EGLContext.mapStaticGLESVersion(eglDevice, chosenCaps);
if(eglDevice != adevice) {
- EGLContext.mapStaticGLESVersion(adevice, caps);
+ EGLContext.mapStaticGLESVersion(adevice, chosenCaps);
}
+ final EGLGraphicsDevice adeviceEGLDevice = new EGLGraphicsDevice(adevice.getHandle(), EGL.EGL_NO_DISPLAY, adevice.getConnection(), adevice.getUnitID(), null);
+ EGLContext.mapStaticGLESVersion(adeviceEGLDevice, chosenCaps);
success = true;
}
if(DEBUG) {
System.err.println("EGLDrawableFactory.isEGLContextAvailable() no pbuffer config available, detected !pbuffer config: "+success);
EGLGraphicsConfigurationFactory.printCaps("!PBufferCaps", capsAnyL, System.err);
}
- }
+ }
} else {
surface = desktopFactory.createDummySurface(adevice, reqCapsAny, null, 64, 64); // X11, WGL, .. dummy window
upstreamSurface = ( surface instanceof ProxySurface ) ? (ProxySurface)surface : null ;
@@ -361,6 +365,8 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl {
if(eglDevice != adevice) {
context.mapCurrentAvailableGLVersion(adevice);
}
+ final EGLGraphicsDevice adeviceEGLDevice = new EGLGraphicsDevice(adevice.getHandle(), EGL.EGL_NO_DISPLAY, adevice.getConnection(), adevice.getUnitID(), null);
+ context.mapCurrentAvailableGLVersion(adeviceEGLDevice);
success = true;
} else {
// Oops .. something is wrong
@@ -538,70 +544,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl {
if (target == null) {
throw new IllegalArgumentException("Null target");
}
- return new EGLOnscreenDrawable(this, getEGLSurface(target));
+ return new EGLOnscreenDrawable(this, EGLWrappedSurface.get(target));
}
- protected static NativeSurface getEGLSurface(NativeSurface surface) {
- AbstractGraphicsConfiguration aConfig = surface.getGraphicsConfiguration();
- AbstractGraphicsDevice aDevice = aConfig.getScreen().getDevice();
- if( aDevice instanceof EGLGraphicsDevice && aConfig instanceof EGLGraphicsConfiguration ) {
- if(surface instanceof WrappedSurface) {
- // already wrapped surface - no wrapped recursion
- if(DEBUG) {
- System.err.println(getThreadName() + ": getEGLSurface - already wrapped surface - use as-is: "+surface);
- }
- return surface;
- }
- if(EGLDrawable.isValidEGLSurface((EGLGraphicsDevice)aDevice, surface)) {
- // already in native EGL format
- if(DEBUG) {
- System.err.println(getThreadName() + ": getEGLSurface - already valid EGL surface - use as-is: "+surface);
- }
- return surface;
- }
- }
- // create EGL instance out of platform native types
- final EGLGraphicsDevice eglDevice;
- if( aDevice instanceof EGLGraphicsDevice ) {
- eglDevice = (EGLGraphicsDevice) aDevice;
- if(DEBUG) {
- System.err.println(getThreadName() + ": getEGLSurface - Reusing eglDevice: "+eglDevice);
- }
- if(0 == eglDevice.getHandle()) {
- eglDevice.open();
- }
- } else {
- eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(surface);
- }
- final AbstractGraphicsScreen eglScreen = new DefaultGraphicsScreen(eglDevice, aConfig.getScreen().getIndex());
- final GLCapabilitiesImmutable capsRequested = (GLCapabilitiesImmutable) aConfig.getRequestedCapabilities();
- final EGLGraphicsConfiguration eglConfig;
- if( aConfig instanceof EGLGraphicsConfiguration ) {
- // Config is already in EGL type - reuse ..
- final EGLGLCapabilities capsChosen = (EGLGLCapabilities) aConfig.getChosenCapabilities();
- if( 0 == capsChosen.getEGLConfig() ) {
- // 'refresh' the native EGLConfig handle
- capsChosen.setEGLConfig(EGLGraphicsConfiguration.EGLConfigId2EGLConfig(eglDevice.getHandle(), capsChosen.getEGLConfigID()));
- if( 0 == capsChosen.getEGLConfig() ) {
- throw new GLException("Refreshing native EGLConfig handle failed with error "+EGLContext.toHexString(EGL.eglGetError())+": "+eglDevice+", "+capsChosen+" of "+aConfig);
- }
- }
- eglConfig = new EGLGraphicsConfiguration(eglScreen, capsChosen, capsRequested, null);
- if(DEBUG) {
- System.err.println(getThreadName() + ": getEGLSurface - Reusing chosenCaps: "+eglConfig);
- }
- } else {
- eglConfig = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(
- capsRequested, capsRequested, null, eglScreen, aConfig.getVisualID(VIDType.NATIVE), false);
-
- if (null == eglConfig) {
- throw new GLException("Couldn't create EGLGraphicsConfiguration from "+eglScreen);
- } else if(DEBUG) {
- System.err.println(getThreadName() + ": getEGLSurface - Chosen eglConfig: "+eglConfig);
- }
- }
- return new WrappedSurface(eglConfig, EGL.EGL_NO_SURFACE, surface.getWidth(), surface.getHeight(), new EGLUpstreamSurfaceHook(surface));
- }
static String getThreadName() { return Thread.currentThread().getName(); }
@Override
@@ -615,7 +560,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl {
throw new GLException("Non pbuffer not yet implemented");
}
// PBuffer GLDrawable Creation
- return new EGLPbufferDrawable(this, getEGLSurface(target));
+ return new EGLPbufferDrawable(this, EGLWrappedSurface.get(target));
}
@Override
@@ -628,20 +573,24 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl {
@Override
protected ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice,
GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested,
- GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook) {
+ GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) {
+ final boolean ownDevice;
final EGLGraphicsDevice device;
- if(createNewDevice) {
- final EGLGraphicsDevice eglDeviceReq = (EGLGraphicsDevice) deviceReq;
- device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(eglDeviceReq.getNativeDisplayID(), deviceReq.getConnection(), deviceReq.getUnitID());
+ if(createNewDevice || ! ( deviceReq instanceof EGLGraphicsDevice ) ) {
+ final long nativeDisplayID = ( deviceReq instanceof EGLGraphicsDevice) ?
+ ( (EGLGraphicsDevice) deviceReq ).getNativeDisplayID() : deviceReq.getHandle() ;
+ device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(nativeDisplayID, deviceReq.getConnection(), deviceReq.getUnitID());
+ ownDevice = true;
} else {
device = (EGLGraphicsDevice) deviceReq;
+ ownDevice = false;
}
final DefaultGraphicsScreen screen = new DefaultGraphicsScreen(device, 0);
final EGLGraphicsConfiguration config = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen, VisualIDHolder.VID_UNDEFINED, false);
if(null == config) {
throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen);
}
- return new WrappedSurface(config, 0, width, height, lifecycleHook);
+ return new WrappedSurface(config, 0, upstreamHook, ownDevice);
}
@Override
@@ -649,54 +598,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl {
GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height) {
final GLCapabilitiesImmutable chosenCaps =
GLGraphicsConfigurationUtil.fixDoubleBufferedGLCapabilities(
- GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(requestedCaps, false, canCreateGLPbuffer(deviceReq)),
- false);
- return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, width, height, dummySurfaceLifecycleHook);
+ GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(requestedCaps, false, canCreateGLPbuffer(deviceReq)), false);
+ return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, new EGLDummyUpstreamSurfaceHook(width, height));
}
- private static final ProxySurface.UpstreamSurfaceHook dummySurfaceLifecycleHook = new ProxySurface.UpstreamSurfaceHook() {
- @Override
- public final void create(ProxySurface s) {
- if( EGL.EGL_NO_SURFACE == s.getSurfaceHandle() ) {
- final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice();
- if(0 == eglDevice.getHandle()) {
- eglDevice.open();
- s.setImplBitfield(ProxySurface.OWN_DEVICE);
- }
- createPBufferSurfaceImpl(s, false);
- if(DEBUG) {
- System.err.println("EGLDrawableFactory.dummySurfaceLifecycleHook.create: "+s);
- }
- }
- }
- @Override
- public final void destroy(ProxySurface s) {
- if( EGL.EGL_NO_SURFACE != s.getSurfaceHandle() ) {
- final EGLGraphicsConfiguration config = (EGLGraphicsConfiguration) s.getGraphicsConfiguration();
- final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) config.getScreen().getDevice();
- EGL.eglDestroySurface(eglDevice.getHandle(), s.getSurfaceHandle());
- s.setSurfaceHandle(EGL.EGL_NO_SURFACE);
- if( 0 != ( ProxySurface.OWN_DEVICE & s.getImplBitfield() ) ) {
- eglDevice.close();
- }
- if(DEBUG) {
- System.err.println("EGLDrawableFactory.dummySurfaceLifecycleHook.create: "+s);
- }
- }
- }
- @Override
- public final int getWidth(ProxySurface s) {
- return s.initialWidth;
- }
- @Override
- public final int getHeight(ProxySurface s) {
- return s.initialHeight;
- }
- @Override
- public String toString() {
- return "EGLSurfaceLifecycleHook[]";
- }
-
- };
/**
* @param ms {@link MutableSurface} which dimensions and config are being used to create the pbuffer surface.
@@ -705,7 +609,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl {
* @return the passed {@link MutableSurface} which now has the EGL pbuffer surface set as it's handle
*/
protected static MutableSurface createPBufferSurfaceImpl(MutableSurface ms, boolean useTexture) {
- final EGLGraphicsConfiguration config = (EGLGraphicsConfiguration) ms.getGraphicsConfiguration();
+ return null;
+ }
+ protected static long createPBufferSurfaceImpl(EGLGraphicsConfiguration config, int width, int height, boolean useTexture) {
final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) config.getScreen().getDevice();
final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities();
final int texFormat;
@@ -720,15 +626,14 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl {
System.out.println("Pbuffer config: " + config);
}
- final int[] attrs = EGLGraphicsConfiguration.CreatePBufferSurfaceAttribList(ms.getWidth(), ms.getHeight(), texFormat);
+ final int[] attrs = EGLGraphicsConfiguration.CreatePBufferSurfaceAttribList(width, height, texFormat);
final long surf = EGL.eglCreatePbufferSurface(eglDevice.getHandle(), config.getNativeConfig(), attrs, 0);
if (EGL.EGL_NO_SURFACE==surf) {
- throw new GLException("Creation of window surface (eglCreatePbufferSurface) failed, dim "+ms.getWidth()+"x"+ms.getHeight()+", error 0x"+Integer.toHexString(EGL.eglGetError()));
+ throw new GLException("Creation of window surface (eglCreatePbufferSurface) failed, dim "+width+"x"+height+", "+eglDevice+", "+config+", error 0x"+Integer.toHexString(EGL.eglGetError()));
} else if(DEBUG) {
System.err.println("PBuffer setSurface result: eglSurface 0x"+Long.toHexString(surf));
}
- ms.setSurfaceHandle(surf);
- return ms;
+ return surf;
}
@Override
@@ -737,7 +642,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl {
final EGLGraphicsDevice device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(eglDeviceReq.getNativeDisplayID(), deviceReq.getConnection(), deviceReq.getUnitID());
final DefaultGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx);
final EGLGraphicsConfiguration cfg = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen, VisualIDHolder.VID_UNDEFINED, false);
- return new WrappedSurface(cfg, windowHandle, 0, 0, upstream);
+ return new WrappedSurface(cfg, windowHandle, upstream, true);
}
@Override
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java b/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java
new file mode 100644
index 000000000..b172d4f35
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java
@@ -0,0 +1,49 @@
+package jogamp.opengl.egl;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
+import com.jogamp.nativewindow.egl.EGLGraphicsDevice;
+
+public class EGLDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize {
+ /**
+ * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)},
+ * not the actual dummy surface width.
+ * The latter is platform specific and small
+ * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)},
+ * not the actual dummy surface height,
+ * The latter is platform specific and small
+ */
+ public EGLDummyUpstreamSurfaceHook(int width, int height) {
+ super(width, height);
+ }
+
+ @Override
+ public final void create(ProxySurface s) {
+ final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice();
+ if(0 == eglDevice.getHandle()) {
+ eglDevice.open();
+ s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
+ if( EGL.EGL_NO_SURFACE == s.getSurfaceHandle() ) {
+ s.setSurfaceHandle( EGLDrawableFactory.createPBufferSurfaceImpl((EGLGraphicsConfiguration)s.getGraphicsConfiguration(), 64, 64, false) );
+ s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE);
+ }
+
+ @Override
+ public final void destroy(ProxySurface s) {
+ if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice();
+ if( EGL.EGL_NO_SURFACE == s.getSurfaceHandle() ) {
+ throw new InternalError("Owns upstream surface, but no EGL surface: "+s);
+ }
+ EGL.eglDestroySurface(eglDevice.getHandle(), s.getSurfaceHandle());
+ s.setSurfaceHandle(EGL.EGL_NO_SURFACE);
+ s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ }
+}
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java
index 585638d21..84bd705db 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java
@@ -79,15 +79,4 @@ public class EGLExternalContext extends EGLContext {
@Override
protected void destroyImpl() throws GLException {
}
-
- @Override
- public void bindPbufferToTexture() {
- throw new GLException("Should not call this");
- }
-
- @Override
- public void releasePbufferFromTexture() {
- throw new GLException("Should not call this");
- }
-
}
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java b/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java
index e513a86cf..f857c6b5c 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java
@@ -57,8 +57,8 @@ public class EGLGLCapabilities extends GLCapabilities {
this.eglcfg = eglcfg;
this.eglcfgid = eglcfgid;
if(!isCompatible(glp, renderableType)) {
- throw new GLException("Incompatible "+glp+
- " with EGL-RenderableType["+renderableTypeToString(null, renderableType)+"]");
+ throw new GLException("Requested GLProfile "+glp+
+ " not compatible with EGL-RenderableType["+renderableTypeToString(null, renderableType)+"]");
}
this.renderableType = renderableType;
this.nativeVisualID = visualID;
@@ -131,6 +131,7 @@ public class EGLGLCapabilities extends GLCapabilities {
sink = new StringBuilder();
}
boolean first=true;
+ sink.append("0x").append(Integer.toHexString(renderableType)).append(": ");
if(0 != (renderableType & EGL.EGL_OPENGL_BIT)) {
sink.append("GL"); first=false;
}
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java
index 8ee98072f..7bf201238 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java
@@ -211,6 +211,13 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple
if(null == glp) {
glp = EGLGLCapabilities.getCompatible(device, rType);
}
+ if(!EGLGLCapabilities.isCompatible(glp, rType)) {
+ if(DEBUG) {
+ System.err.println("config "+toHexString(config)+": Requested GLProfile "+glp+
+ " not compatible with EGL-RenderableType["+EGLGLCapabilities.renderableTypeToString(null, rType)+"]");
+ }
+ return null;
+ }
caps = new EGLGLCapabilities(config, cfgID, visualID, glp, rType);
} catch (GLException gle) {
if(DEBUG) {
@@ -288,7 +295,7 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple
return null;
}
- return (EGLGLCapabilities) GLGraphicsConfigurationUtil.setWinAttributeBits(caps, drawableTypeBits);
+ return (EGLGLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, caps);
}
public static int[] GLCapabilities2AttribList(GLCapabilitiesImmutable caps) {
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java
index eae47fa92..325ad6142 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java
@@ -41,16 +41,5 @@ public class EGLOnscreenContext extends EGLContext {
public EGLOnscreenContext(EGLOnscreenDrawable drawable, GLContext shareWith) {
super(drawable, shareWith);
}
-
- @Override
- public void bindPbufferToTexture() {
- throw new GLException("Should not call this");
- }
-
- @Override
- public void releasePbufferFromTexture() {
- throw new GLException("Should not call this");
- }
-
}
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java
index d54057775..6440cf1e5 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java
@@ -54,8 +54,8 @@ public class EGLOnscreenDrawable extends EGLDrawable {
}
@Override
- protected long createSurface(EGLGraphicsConfiguration config, long nativeSurfaceHandle) {
+ protected long createSurface(EGLGraphicsConfiguration config, int width, int height, long nativeSurfaceHandle) {
return EGL.eglCreateWindowSurface(config.getScreen().getDevice().getHandle(), config.getNativeConfig(), nativeSurfaceHandle, null);
- }
+ }
}
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java
index 7175d516f..bb9eeb892 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java
@@ -46,15 +46,5 @@ public class EGLPbufferContext extends EGLContext {
public int getFloatingPointMode() {
return 0; // FIXME ??
}
-
- @Override
- public void bindPbufferToTexture() {
- throw new GLException("Not yet implemented");
- }
-
- @Override
- public void releasePbufferFromTexture() {
- throw new GLException("Not yet implemented");
- }
}
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java
index 4a36625bd..eb7e320c8 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java
@@ -52,12 +52,8 @@ public class EGLPbufferDrawable extends EGLDrawable {
}
@Override
- protected long createSurface(EGLGraphicsConfiguration config, long nativeSurfaceHandle) {
- final MutableSurface ms = (MutableSurface)getNativeSurface();
- if(config != ms.getGraphicsConfiguration()) {
- throw new InternalError("Not same: "+config.hashCode()+", "+ms.getGraphicsConfiguration()+": "+config+", "+ms.getGraphicsConfiguration());
- }
- return EGLDrawableFactory.createPBufferSurfaceImpl(ms, useTexture).getSurfaceHandle();
+ protected long createSurface(EGLGraphicsConfiguration config, int width, int height, long nativeSurfaceHandle) {
+ return EGLDrawableFactory.createPBufferSurfaceImpl(config, width, height, false);
}
@Override
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java
index 42c6e100e..342c4c417 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java
@@ -1,38 +1,163 @@
package jogamp.opengl.egl;
+import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.AbstractGraphicsScreen;
+import javax.media.nativewindow.DefaultGraphicsScreen;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+import javax.media.nativewindow.VisualIDHolder.VIDType;
+import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLException;
import com.jogamp.nativewindow.egl.EGLGraphicsDevice;
-public class EGLUpstreamSurfaceHook implements ProxySurface.UpstreamSurfaceHook {
+public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize {
+ protected static final boolean DEBUG = EGLDrawableFactory.DEBUG;
private final NativeSurface upstreamSurface;
+ private final UpstreamSurfaceHook.MutableSize upstreamSurfaceHookMutableSize;
public EGLUpstreamSurfaceHook(NativeSurface upstream) {
upstreamSurface = upstream;
+ if(upstreamSurface instanceof ProxySurface) {
+ final UpstreamSurfaceHook ush = ((ProxySurface)upstreamSurface).getUpstreamSurfaceHook();
+ if(ush instanceof UpstreamSurfaceHook.MutableSize) {
+ // offscreen NativeSurface w/ MutableSize (default)
+ upstreamSurfaceHookMutableSize = (UpstreamSurfaceHook.MutableSize) ush;
+ } else {
+ upstreamSurfaceHookMutableSize = null;
+ }
+ } else {
+ upstreamSurfaceHookMutableSize = null;
+ }
}
public final NativeSurface getUpstreamSurface() { return upstreamSurface; }
+ static String getThreadName() { return Thread.currentThread().getName(); }
+
+ public final void setSize(int width, int height) {
+ if(null != upstreamSurfaceHookMutableSize) {
+ upstreamSurfaceHookMutableSize.setSize(width, height);
+ }
+ }
+
@Override
public final void create(ProxySurface surface) {
+ final String dbgPrefix;
+ if(DEBUG) {
+ dbgPrefix = getThreadName() + ": EGLUpstreamSurfaceHook.create("+surface.getClass().getSimpleName()+"): ";
+ System.err.println(dbgPrefix+this);
+ } else {
+ dbgPrefix = null;
+ }
+
if(upstreamSurface instanceof ProxySurface) {
+ // propagate createNotify(..) so upstreamSurface will be created
((ProxySurface)upstreamSurface).createNotify();
- if(NativeSurface.LOCK_SURFACE_NOT_READY >= upstreamSurface.lockSurface()) {
- throw new GLException("Could not lock: "+upstreamSurface);
+ }
+
+ // lock upstreamSurface, so it can be used in case EGLDisplay is derived from it!
+ if(NativeSurface.LOCK_SURFACE_NOT_READY >= upstreamSurface.lockSurface()) {
+ throw new GLException("Could not lock: "+upstreamSurface);
+ }
+ try {
+ evalUpstreamSurface(dbgPrefix, surface);
+ } finally {
+ upstreamSurface.unlockSurface();
+ }
+ }
+
+ private final void evalUpstreamSurface(String dbgPrefix, ProxySurface surface) {
+ //
+ // evaluate nature of upstreamSurface, may create EGL instances if required
+ //
+
+ boolean isEGLSurfaceValid = true; // assume yes
+
+ final AbstractGraphicsConfiguration aConfig = upstreamSurface.getGraphicsConfiguration();
+ final AbstractGraphicsDevice aDevice = aConfig.getScreen().getDevice();
+
+ final EGLGraphicsDevice eglDevice;
+ if( aDevice instanceof EGLGraphicsDevice ) {
+ eglDevice = (EGLGraphicsDevice) aDevice;
+ if(DEBUG) {
+ System.err.println(dbgPrefix+"Reusing eglDevice: "+eglDevice);
+ }
+ if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) {
+ eglDevice.open();
+ isEGLSurfaceValid = false;
+ surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
+ } else {
+ eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface);
+ isEGLSurfaceValid = false;
+ surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
+
+ final GLCapabilitiesImmutable capsRequested = (GLCapabilitiesImmutable) aConfig.getRequestedCapabilities();
+ final EGLGraphicsConfiguration eglConfig;
+ if( aConfig instanceof EGLGraphicsConfiguration ) {
+ // Config is already in EGL type - reuse ..
+ final EGLGLCapabilities capsChosen = (EGLGLCapabilities) aConfig.getChosenCapabilities();
+ if( !isEGLSurfaceValid || !EGLGraphicsConfiguration.isEGLConfigValid(eglDevice.getHandle(), capsChosen.getEGLConfig()) ) {
+ // 'refresh' the native EGLConfig handle
+ capsChosen.setEGLConfig(EGLGraphicsConfiguration.EGLConfigId2EGLConfig(eglDevice.getHandle(), capsChosen.getEGLConfigID()));
+ if( 0 == capsChosen.getEGLConfig() ) {
+ throw new GLException("Refreshing native EGLConfig handle failed with error "+EGLContext.toHexString(EGL.eglGetError())+": "+eglDevice+", "+capsChosen+" of "+aConfig);
+ }
+ final AbstractGraphicsScreen eglScreen = new DefaultGraphicsScreen(eglDevice, aConfig.getScreen().getIndex());
+ eglConfig = new EGLGraphicsConfiguration(eglScreen, capsChosen, capsRequested, null);
+ if(DEBUG) {
+ System.err.println(dbgPrefix+"Refreshing eglConfig: "+eglConfig);
+ }
+ isEGLSurfaceValid = false;
+ } else {
+ eglConfig = (EGLGraphicsConfiguration) aConfig;
+ if(DEBUG) {
+ System.err.println(dbgPrefix+"Reusing eglConfig: "+eglConfig);
+ }
+ }
+ } else {
+ final AbstractGraphicsScreen eglScreen = new DefaultGraphicsScreen(eglDevice, aConfig.getScreen().getIndex());
+ eglConfig = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(
+ capsRequested, capsRequested, null, eglScreen, aConfig.getVisualID(VIDType.NATIVE), false);
+
+ if (null == eglConfig) {
+ throw new GLException("Couldn't create EGLGraphicsConfiguration from "+eglScreen);
+ } else if(DEBUG) {
+ System.err.println(dbgPrefix+"Chosen eglConfig: "+eglConfig);
}
+ isEGLSurfaceValid = false;
}
- final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice();
- eglDevice.open();
+ surface.setGraphicsConfiguration(eglConfig);
+
+ if(isEGLSurfaceValid) {
+ isEGLSurfaceValid = EGLDrawable.isValidEGLSurface(eglDevice.getHandle(), upstreamSurface.getSurfaceHandle());
+ }
+ if(isEGLSurfaceValid) {
+ surface.setSurfaceHandle(upstreamSurface.getSurfaceHandle());
+ surface.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ if(DEBUG) {
+ System.err.println(dbgPrefix+"Fin: Already valid EGL surface - use as-is: "+upstreamSurface);
+ }
+ } else {
+ surface.setSurfaceHandle(EGL.EGL_NO_SURFACE);
+ surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); // create/destroy in EGLDrawable
+ if(DEBUG) {
+ System.err.println(dbgPrefix+"Fin: EGL surface n/a - TBD: "+upstreamSurface);
+ }
+ }
}
@Override
public final void destroy(ProxySurface surface) {
- final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice();
- eglDevice.close();
+ if(EGLDrawableFactory.DEBUG) {
+ System.err.println("EGLUpstreamSurfaceHook.destroy("+surface.getClass().getSimpleName()+"): "+this);
+ }
+ surface.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
if(upstreamSurface instanceof ProxySurface) {
- upstreamSurface.unlockSurface();
((ProxySurface)upstreamSurface).destroyNotify();
}
}
@@ -49,8 +174,8 @@ public class EGLUpstreamSurfaceHook implements ProxySurface.UpstreamSurfaceHook
@Override
public String toString() {
- final String us_s = null != upstreamSurface ? ( upstreamSurface.getClass().getName() + ": " + upstreamSurface ) : "nil";
- return "EGLUpstreamSurfaceHook[upstream: "+us_s+"]";
+ final String us_s = null != upstreamSurface ? ( upstreamSurface.getClass().getName() + ": 0x" + Long.toHexString(upstreamSurface.getSurfaceHandle()) ) : "nil";
+ return "EGLUpstreamSurfaceHook[ "+ upstreamSurface.getWidth() + "x" + upstreamSurface.getHeight() + ", " + us_s+ "]";
}
}
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java b/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java
new file mode 100644
index 000000000..b36303392
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java
@@ -0,0 +1,26 @@
+package jogamp.opengl.egl;
+
+import javax.media.nativewindow.NativeSurface;
+
+import jogamp.nativewindow.WrappedSurface;
+
+public class EGLWrappedSurface extends WrappedSurface {
+
+ public static EGLWrappedSurface get(NativeSurface surface) {
+ if(surface instanceof EGLWrappedSurface) {
+ return (EGLWrappedSurface)surface;
+ }
+ return new EGLWrappedSurface(surface);
+ }
+
+ public EGLWrappedSurface(NativeSurface surface) {
+ super(surface.getGraphicsConfiguration(), EGL.EGL_NO_SURFACE, new EGLUpstreamSurfaceHook(surface), false /* tbd in UpstreamSurfaceHook */);
+ if(EGLDrawableFactory.DEBUG) {
+ System.err.println("EGLWrappedSurface.ctor(): "+this);
+ }
+ }
+
+ public final NativeSurface getUpstreamSurface() {
+ return ((EGLUpstreamSurfaceHook)super.getUpstreamSurfaceHook()).getUpstreamSurface();
+ }
+}
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
index 55aea3a98..ec29558d1 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
@@ -49,6 +49,7 @@ import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.OffscreenLayerSurface;
import javax.media.nativewindow.ProxySurface;
+import javax.media.opengl.GL;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
@@ -58,6 +59,7 @@ import javax.media.opengl.GLProfile;
import jogamp.nativewindow.macosx.OSXUtil;
import jogamp.opengl.GLContextImpl;
import jogamp.opengl.GLDrawableImpl;
+import jogamp.opengl.GLFBODrawableImpl;
import jogamp.opengl.GLGraphicsConfigurationUtil;
import jogamp.opengl.macosx.cgl.MacOSXCGLDrawable.GLBackendType;
@@ -76,9 +78,11 @@ public abstract class MacOSXCGLContext extends GLContextImpl
boolean isNSContext();
long create(long share, int ctp, int major, int minor);
boolean destroy(long ctx);
+ boolean contextRealized(boolean realized);
boolean copyImpl(long src, int mask);
boolean makeCurrent(long ctx);
boolean release(long ctx);
+ boolean detachPBuffer();
boolean setSwapInterval(int interval);
boolean swapBuffers();
}
@@ -279,7 +283,24 @@ public abstract class MacOSXCGLContext extends GLContextImpl
throw new GLException("Error destroying OpenGL Context: "+this);
}
}
+
+ @Override
+ protected void contextRealized(boolean realized) {
+ // context stuff depends on drawable stuff
+ if(realized) {
+ super.contextRealized(true); // 1) init drawable stuff
+ impl.contextRealized(true); // 2) init context stuff
+ } else {
+ impl.contextRealized(false); // 1) free context stuff
+ super.contextRealized(false); // 2) free drawable stuff
+ }
+ }
+
+ /* pp */ void detachPBuffer() {
+ impl.detachPBuffer();
+ }
+
@Override
protected void copyImpl(GLContext source, int mask) throws GLException {
if( isNSContext() != ((MacOSXCGLContext)source).isNSContext() ) {
@@ -365,16 +386,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl
throw new GLException("Should not call this");
}
- @Override
- public void bindPbufferToTexture() {
- throw new GLException("Should not call this");
- }
-
- @Override
- public void releasePbufferFromTexture() {
- throw new GLException("Should not call this");
- }
-
// Support for "mode switching" as described in MacOSXCGLDrawable
public void setOpenGLMode(GLBackendType mode) {
if (mode == openGLMode) {
@@ -421,323 +432,486 @@ public abstract class MacOSXCGLContext extends GLContextImpl
// NSOpenGLContext-based implementation
class NSOpenGLImpl implements GLBackendImpl {
- long nsOpenGLLayer = 0;
- long nsOpenGLLayerPFmt = 0;
- float screenVSyncTimeout; // microSec
- int vsyncTimeout; // microSec - for nsOpenGLLayer mode
-
- @Override
- public boolean isNSContext() { return true; }
-
- @Override
- public long create(long share, int ctp, int major, int minor) {
- long ctx = 0;
- final long nsViewHandle;
- if(drawable instanceof MacOSXCGLDrawable) {
- // we allow null here! (special pbuffer case)
- nsViewHandle = ((MacOSXCGLDrawable)MacOSXCGLContext.this.drawable).getNSViewHandle();
- } else {
- // we only allow a valid NSView here
- final long aHandle = drawable.getHandle();
- if( OSXUtil.isNSView(aHandle) ) {
- nsViewHandle = aHandle;
- } else {
- throw new RuntimeException("Anonymous drawable instance's handle not of type NSView: "+drawable.getClass().getName()+", "+drawable);
- }
- }
- final NativeSurface surface = drawable.getNativeSurface();
- final MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) surface.getGraphicsConfiguration();
- final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true);
-
- boolean allowIncompleteView = null != backingLayerHost;
- if( !allowIncompleteView && surface instanceof ProxySurface ) {
- allowIncompleteView = 0 != ( ProxySurface.INVISIBLE_WINDOW & ((ProxySurface)surface).getImplBitfield() ) ;
- }
- final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities();
- long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(chosenCaps, ctp, major, minor);
- if (pixelFormat == 0) {
- if(DEBUG) {
- System.err.println("Unable to allocate pixel format with requested GLCapabilities: "+chosenCaps);
- }
- return 0;
- }
- config.setChosenPixelFormat(pixelFormat);
- int sRefreshRate = CGL.getScreenRefreshRate(drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getIndex());
- screenVSyncTimeout = 1000000f / sRefreshRate;
- if(DEBUG) {
- System.err.println("NS create OSX>=lion "+isLionOrLater);
- System.err.println("NS create allowIncompleteView: "+allowIncompleteView);
- System.err.println("NS create backingLayerHost: "+backingLayerHost);
- System.err.println("NS create share: "+share);
- System.err.println("NS create chosenCaps: "+chosenCaps);
- System.err.println("NS create pixelFormat: "+toHexString(pixelFormat));
- System.err.println("NS create drawable native-handle: "+toHexString(drawable.getHandle()));
- System.err.println("NS create drawable NSView-handle: "+toHexString(nsViewHandle));
- System.err.println("NS create screen refresh-rate: "+sRefreshRate+" hz, "+screenVSyncTimeout+" micros");
- // Thread.dumpStack();
- }
- try {
- int[] viewNotReady = new int[1];
- // Try to allocate a context with this
- ctx = CGL.createContext(share,
- nsViewHandle, allowIncompleteView,
- pixelFormat,
- chosenCaps.isBackgroundOpaque(),
- viewNotReady, 0);
- if (0 == ctx) {
- if(DEBUG) {
- System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady[0]));
- }
- return 0;
- }
+ private OffscreenLayerSurface backingLayerHost = null;
+ private long nsOpenGLLayer = 0;
+ private long nsOpenGLLayerPFmt = 0;
+ private float screenVSyncTimeout; // microSec
+ private int vsyncTimeout; // microSec - for nsOpenGLLayer mode
+ private int lastWidth=0, lastHeight=0; // allowing to detect size change
+ private long lastPBufferHandle = 0; // allowing to detect pbuffer recreation
+
+ @Override
+ public boolean isNSContext() { return true; }
+
+ @Override
+ public long create(long share, int ctp, int major, int minor) {
+ long ctx = 0;
+ final NativeSurface surface = drawable.getNativeSurface();
+ final MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) surface.getGraphicsConfiguration();
+ final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities();
+ final long nsViewHandle;
+ final boolean isPBuffer;
+ final boolean isFBO;
+ if(drawable instanceof GLFBODrawableImpl) {
+ nsViewHandle = 0;
+ isPBuffer = false;
+ isFBO = true;
+ if(DEBUG) {
+ System.err.println("NS create GLFBODrawableImpl drawable: isFBO "+isFBO+", isPBuffer "+isPBuffer+", "+drawable.getClass().getName()+",\n\t"+drawable);
+ }
+ } else if(drawable instanceof MacOSXCGLDrawable) {
+ // we allow null here! (special pbuffer case)
+ nsViewHandle = ((MacOSXCGLDrawable)MacOSXCGLContext.this.drawable).getNSViewHandle();
+ isPBuffer = CGL.isNSOpenGLPixelBuffer(drawable.getHandle());
+ isFBO = false;
+ if(DEBUG) {
+ System.err.println("NS create MacOSXCGLDrawable drawable handle isFBO "+isFBO+", isPBuffer "+isPBuffer+", "+drawable.getClass().getName()+",\n\t"+drawable);
+ }
+ } else {
+ // we only allow a valid NSView here
+ final long drawableHandle = drawable.getHandle();
+ final boolean isNSView = OSXUtil.isNSView(drawableHandle);
+ final boolean isNSWindow = OSXUtil.isNSWindow(drawableHandle);
+ isPBuffer = CGL.isNSOpenGLPixelBuffer(drawableHandle);
+ isFBO = false;
- if (!chosenCaps.isPBuffer() && !chosenCaps.isBackgroundOpaque()) {
- // Set the context opacity
- CGL.setContextOpacity(ctx, 0);
+ if(DEBUG) {
+ System.err.println("NS create Anonymous drawable handle "+toHexString(drawableHandle)+": isNSView "+isNSView+", isNSWindow "+isNSWindow+", isFBO "+isFBO+", isPBuffer "+isPBuffer+", "+drawable.getClass().getName()+",\n\t"+drawable);
+ }
+ if( isNSView ) {
+ nsViewHandle = drawableHandle;
+ } else if( isNSWindow ) {
+ nsViewHandle = OSXUtil.GetNSView(drawableHandle);
+ } else if( isPBuffer ) {
+ nsViewHandle = 0;
+ } else {
+ throw new RuntimeException("Anonymous drawable instance's handle neither NSView, NSWindow nor PBuffer: "+toHexString(drawableHandle)+", "+drawable.getClass().getName()+",\n\t"+drawable);
+ }
}
+ backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true);
+ boolean allowIncompleteView = null != backingLayerHost;
+ if( !allowIncompleteView && surface instanceof ProxySurface ) {
+ allowIncompleteView = ((ProxySurface)surface).containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE );
+ }
+ long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(chosenCaps, ctp, major, minor);
+ if (pixelFormat == 0) {
+ if(DEBUG) {
+ System.err.println("Unable to allocate pixel format with requested GLCapabilities: "+chosenCaps);
+ }
+ return 0;
+ }
GLCapabilities fixedCaps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(chosenCaps.getGLProfile(), pixelFormat);
- fixedCaps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(fixedCaps, chosenCaps.isBackgroundOpaque());
- if(!fixedCaps.isPBuffer()) {
+ if(chosenCaps.isOnscreen() || !fixedCaps.isPBuffer()) {
// not handled, so copy them
fixedCaps.setFBO(chosenCaps.isFBO());
+ fixedCaps.setPBuffer(chosenCaps.isPBuffer());
fixedCaps.setBitmap(chosenCaps.isBitmap());
fixedCaps.setOnscreen(chosenCaps.isOnscreen());
}
- config.setChosenCapabilities(fixedCaps);
+ fixedCaps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(fixedCaps, chosenCaps.isBackgroundOpaque());
+ int sRefreshRate = OSXUtil.GetScreenRefreshRate(drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getIndex());
+ screenVSyncTimeout = 1000000f / sRefreshRate;
if(DEBUG) {
+ System.err.println("NS create OSX>=lion "+isLionOrLater);
+ System.err.println("NS create allowIncompleteView: "+allowIncompleteView);
+ System.err.println("NS create backingLayerHost: "+backingLayerHost);
+ System.err.println("NS create share: "+share);
+ System.err.println("NS create drawable type: "+drawable.getClass().getName());
+ System.err.println("NS create drawable handle: isPBuffer "+isPBuffer+", isFBO "+isFBO);
+ System.err.println("NS create pixelFormat: "+toHexString(pixelFormat));
+ System.err.println("NS create chosenCaps: "+chosenCaps);
System.err.println("NS create fixedCaps: "+fixedCaps);
+ System.err.println("NS create drawable native-handle: "+toHexString(drawable.getHandle()));
+ System.err.println("NS create drawable NSView-handle: "+toHexString(nsViewHandle));
+ System.err.println("NS create screen refresh-rate: "+sRefreshRate+" hz, "+screenVSyncTimeout+" micros");
+ // Thread.dumpStack();
}
if(fixedCaps.isPBuffer()) {
- // Must now associate the pbuffer with our newly-created context
- CGL.setContextPBuffer(ctx, drawable.getHandle());
+ if(!isPBuffer) {
+ throw new InternalError("fixedCaps is PBuffer, handle not: "+drawable);
+ }
+ } else {
+ if(isPBuffer) {
+ throw new InternalError("handle is PBuffer, fixedCaps not: "+drawable);
+ }
}
- //
- // handled layered surface
- //
+ config.setChosenCapabilities(fixedCaps);
+ /**
if(null != backingLayerHost) {
- nsOpenGLLayerPFmt = pixelFormat;
- pixelFormat = 0;
- final int texWidth, texHeight;
- if(drawable instanceof MacOSXPbufferCGLDrawable) {
- final MacOSXPbufferCGLDrawable osxPDrawable = (MacOSXPbufferCGLDrawable)drawable;
- texWidth = osxPDrawable.getTextureWidth();
- texHeight = osxPDrawable.getTextureHeight();
- } else {
- texWidth = drawable.getWidth();
- texHeight = drawable.getHeight();
+ backingLayerHost.setChosenCapabilities(fixedCaps);
+ } */
+
+ try {
+ int[] viewNotReady = new int[1];
+ // Try to allocate a context with this
+ ctx = CGL.createContext(share,
+ nsViewHandle, allowIncompleteView,
+ pixelFormat,
+ chosenCaps.isBackgroundOpaque(),
+ viewNotReady, 0);
+ if (0 == ctx) {
+ if(DEBUG) {
+ System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady[0]));
+ }
+ return 0;
}
- if(0>=texWidth || 0>=texHeight || !drawable.isRealized()) {
- throw new GLException("Drawable not realized yet or invalid texture size, texSize "+texWidth+"x"+texHeight+", "+drawable);
+
+ if(null != backingLayerHost) {
+ nsOpenGLLayerPFmt = pixelFormat;
+ pixelFormat = 0;
}
- nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, nsOpenGLLayerPFmt, drawable.getHandle(), fixedCaps.isBackgroundOpaque(), texWidth, texHeight);
- if (DEBUG) {
- System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", texSize "+texWidth+"x"+texHeight+", "+drawable);
+
+ if (chosenCaps.isOnscreen() && !chosenCaps.isBackgroundOpaque()) {
+ // Set the context opacity
+ CGL.setContextOpacity(ctx, 0);
+ }
+ } finally {
+ if(0!=pixelFormat) {
+ CGL.deletePixelFormat(pixelFormat);
+ pixelFormat = 0;
}
- backingLayerHost.attachSurfaceLayer(nsOpenGLLayer);
- setSwapInterval(1); // enabled per default in layered surface
- }
- } finally {
- if(0!=pixelFormat) {
- CGL.deletePixelFormat(pixelFormat);
- }
- }
- return ctx;
- }
-
- @Override
- public boolean destroy(long ctx) {
- if(0 != nsOpenGLLayer) {
- final NativeSurface surface = drawable.getNativeSurface();
- if (DEBUG) {
- System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer));
- }
- final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(surface, true);
- if(null != ols && ols.isSurfaceLayerAttached()) {
- // still having a valid OLS attached to surface (parent OLS could have been removed)
- ols.detachSurfaceLayer();
}
- CGL.releaseNSOpenGLLayer(nsOpenGLLayer);
- CGL.deletePixelFormat(nsOpenGLLayerPFmt);
- nsOpenGLLayerPFmt = 0;
- nsOpenGLLayer = 0;
+ return ctx;
}
- return CGL.deleteContext(ctx, true);
- }
-
- @Override
- public boolean copyImpl(long src, int mask) {
- CGL.copyContext(contextHandle, src, mask);
- return true;
- }
- @Override
- public boolean makeCurrent(long ctx) {
- final long cglCtx = CGL.getCGLContext(ctx);
- if(0 == cglCtx) {
- throw new InternalError("Null CGLContext for: "+this);
+ @Override
+ public boolean destroy(long ctx) {
+ lastPBufferHandle = 0;
+ return CGL.deleteContext(ctx, true);
}
- int err = CGL.CGLLockContext(cglCtx);
- if(CGL.kCGLNoError == err) {
- return CGL.makeCurrentContext(ctx);
- } else if(DEBUG) {
- System.err.println("NSGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this);
+
+ @Override
+ public boolean contextRealized(boolean realized) {
+ if( realized ) {
+ if( null != backingLayerHost ) {
+ //
+ // handled layered surface
+ //
+ final GLCapabilitiesImmutable chosenCaps = drawable.getChosenGLCapabilities();
+ final long ctx = MacOSXCGLContext.this.getHandle();
+ final int texID;
+ final long drawableHandle = drawable.getHandle();
+ if(drawable instanceof GLFBODrawableImpl) {
+ final GLFBODrawableImpl fbod = (GLFBODrawableImpl)drawable;
+ texID = fbod.getTextureBuffer(GL.GL_FRONT).getName();
+ fbod.setSwapBufferContext(new GLFBODrawableImpl.SwapBufferContext() {
+ public void swapBuffers(boolean doubleBuffered) {
+ MacOSXCGLContext.NSOpenGLImpl.this.swapBuffers();
+ } } ) ;
+ lastPBufferHandle = 0;
+ } else if( chosenCaps.isPBuffer() && CGL.isNSOpenGLPixelBuffer(drawableHandle) ) {
+ texID = 0;
+ lastPBufferHandle = drawableHandle;
+ } else {
+ throw new GLException("BackingLayerHost w/ unknown handle (!FBO, !PBuffer): "+drawable);
+ }
+ lastWidth = drawable.getWidth();
+ lastHeight = drawable.getHeight();
+ if(0>=lastWidth || 0>=lastHeight || !drawable.isRealized()) {
+ throw new GLException("Drawable not realized yet or invalid texture size, texSize "+lastWidth+"x"+lastHeight+", "+drawable);
+ }
+ nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, nsOpenGLLayerPFmt, lastPBufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight);
+ if (DEBUG) {
+ System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+" w/ pbuffer "+toHexString(lastPBufferHandle)+", texID "+texID+", texSize "+lastWidth+"x"+lastHeight+", "+drawable);
+ }
+ backingLayerHost.attachSurfaceLayer(nsOpenGLLayer);
+ setSwapInterval(1); // enabled per default in layered surface
+ } else {
+ lastWidth = drawable.getWidth();
+ lastHeight = drawable.getHeight();
+ }
+ } else {
+ if( 0 != nsOpenGLLayer ) {
+ final NativeSurface surface = drawable.getNativeSurface();
+ if (DEBUG) {
+ System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", "+drawable);
+ }
+ final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(surface, true);
+ if(null != ols && ols.isSurfaceLayerAttached()) {
+ // still having a valid OLS attached to surface (parent OLS could have been removed)
+ ols.detachSurfaceLayer();
+ }
+ CGL.releaseNSOpenGLLayer(nsOpenGLLayer);
+ nsOpenGLLayer = 0;
+ }
+ if(0 != nsOpenGLLayerPFmt) {
+ CGL.deletePixelFormat(nsOpenGLLayerPFmt);
+ nsOpenGLLayerPFmt = 0;
+ }
+ lastPBufferHandle = 0;
+ }
+ backingLayerHost = null;
+ return true;
}
- return false;
- }
- @Override
- public boolean release(long ctx) {
- try {
- gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze
- } catch (GLException gle) {
- if(DEBUG) {
- System.err.println("MacOSXCGLContext.NSOpenGLImpl.release: INFO: glFlush() catched exception:");
- gle.printStackTrace();
+ private final void validatePBufferConfig(long ctx) {
+ final GLCapabilitiesImmutable chosenCaps = drawable.getChosenGLCapabilities();
+ final long drawableHandle = drawable.getHandle();
+ if(chosenCaps.isPBuffer() && CGL.isNSOpenGLPixelBuffer(drawableHandle) && lastPBufferHandle != drawableHandle) {
+ // Must associate the pbuffer with our newly-created context
+ lastPBufferHandle = drawableHandle;
+ if(0 != drawableHandle) {
+ CGL.setContextPBuffer(ctx, drawableHandle);
+ }
+ if(DEBUG) {
+ System.err.println("NS.validateDrawableConfig bind pbuffer "+toHexString(drawableHandle)+" -> ctx "+toHexString(ctx));
+ }
}
}
- final boolean res = CGL.clearCurrentContext(ctx);
- final long cglCtx = CGL.getCGLContext(ctx);
- if(0 == cglCtx) {
- throw new InternalError("Null CGLContext for: "+this);
+
+ /** Returns true if size has been updated, otherwise false (same size). */
+ private final boolean validateDrawableSizeConfig(long ctx) {
+ final int width = drawable.getWidth();
+ final int height = drawable.getHeight();
+ if( lastWidth != width || lastHeight != height ) {
+ lastWidth = drawable.getWidth();
+ lastHeight = drawable.getHeight();
+ if(DEBUG) {
+ System.err.println("NS.validateDrawableConfig size changed");
+ }
+ return true;
+ }
+ return false;
}
- final int err = CGL.CGLUnlockContext(cglCtx);
- if(DEBUG && CGL.kCGLNoError != err) {
- System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err)+": "+this);
+
+ @Override
+ public boolean copyImpl(long src, int mask) {
+ CGL.copyContext(contextHandle, src, mask);
+ return true;
}
- return res && CGL.kCGLNoError == err;
- }
- @Override
- public boolean setSwapInterval(int interval) {
- if(0 != nsOpenGLLayer) {
- CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, interval);
- vsyncTimeout = interval * (int)screenVSyncTimeout;
- if(DEBUG) { System.err.println("NS setSwapInterval: "+vsyncTimeout+" micros"); }
+ @Override
+ public boolean makeCurrent(long ctx) {
+ final long cglCtx = CGL.getCGLContext(ctx);
+ if(0 == cglCtx) {
+ throw new InternalError("Null CGLContext for: "+this);
+ }
+ int err = CGL.CGLLockContext(cglCtx);
+ if(CGL.kCGLNoError == err) {
+ validatePBufferConfig(ctx); // required to handle pbuffer change ASAP
+ return CGL.makeCurrentContext(ctx);
+ } else if(DEBUG) {
+ System.err.println("NSGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean release(long ctx) {
+ try {
+ gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze
+ } catch (GLException gle) {
+ if(DEBUG) {
+ System.err.println("MacOSXCGLContext.NSOpenGLImpl.release: INFO: glFlush() catched exception:");
+ gle.printStackTrace();
+ }
+ }
+ final boolean res = CGL.clearCurrentContext(ctx);
+ final long cglCtx = CGL.getCGLContext(ctx);
+ if(0 == cglCtx) {
+ throw new InternalError("Null CGLContext for: "+this);
+ }
+ final int err = CGL.CGLUnlockContext(cglCtx);
+ if(DEBUG && CGL.kCGLNoError != err) {
+ System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err)+": "+this);
+ }
+ return res && CGL.kCGLNoError == err;
}
- CGL.setSwapInterval(contextHandle, interval);
- return true;
- }
- @Override
- public boolean swapBuffers() {
- if( 0 != nsOpenGLLayer ) {
- // If v-sync is disabled, frames will be drawn as quickly as possible
- // w/o delay but in sync w/ CALayer. Otherwise wait until next swap interval (v-sync).
- CGL.waitUntilNSOpenGLLayerIsReady(nsOpenGLLayer, vsyncTimeout);
+ @Override
+ public boolean detachPBuffer() {
+ if(0 != lastPBufferHandle) {
+ lastPBufferHandle = 0;
+ if(0 != nsOpenGLLayer) {
+ CGL.flushNSOpenGLLayerPBuffer(nsOpenGLLayer); // notify invalid pbuffer
+ }
+ // CGL.setContextPBuffer(contextHandle, 0); // doesn't work, i.e. not taking nil
+ }
+ return true;
}
- if(CGL.flushBuffer(contextHandle)) {
+
+ @Override
+ public boolean setSwapInterval(int interval) {
if(0 != nsOpenGLLayer) {
- // trigger CALayer to update
- CGL.setNSOpenGLLayerNeedsDisplay(nsOpenGLLayer);
+ CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, interval);
+ vsyncTimeout = interval * (int)screenVSyncTimeout + 1000; // +1ms
+ if(DEBUG) { System.err.println("NS setSwapInterval: "+vsyncTimeout+" micros"); }
}
+ CGL.setSwapInterval(contextHandle, interval);
return true;
}
- return false;
- }
+
+ private int skipSync=0;
+
+ @Override
+ public boolean swapBuffers() {
+ final boolean res;
+ if( 0 != nsOpenGLLayer ) {
+ if( validateDrawableSizeConfig(contextHandle) ) {
+ // skip wait-for-vsync for a few frames if size has changed,
+ // allowing to update the texture IDs ASAP.
+ skipSync = 10;
+ }
+
+ final int texID;
+ final boolean valid;
+ if(drawable instanceof GLFBODrawableImpl) {
+ texID = ((GLFBODrawableImpl)drawable).getTextureBuffer(GL.GL_FRONT).getName();
+ valid = 0 != texID;
+ } else {
+ texID = 0;
+ valid = 0 != lastPBufferHandle;
+ }
+ if(valid) {
+ if(0 == skipSync) {
+ // If v-sync is disabled, frames will be drawn as quickly as possible
+ // w/o delay but in sync w/ CALayer. Otherwise wait until next swap interval (v-sync).
+ CGL.waitUntilNSOpenGLLayerIsReady(nsOpenGLLayer, vsyncTimeout);
+ } else {
+ skipSync--;
+ }
+ res = CGL.flushBuffer(contextHandle);
+ if(res) {
+ // trigger CALayer to update incl. possible surface change
+ CGL.setNSOpenGLLayerNeedsDisplay(nsOpenGLLayer, lastPBufferHandle, texID, lastWidth, lastHeight);
+ }
+ } else {
+ res = true;
+ }
+ } else {
+ res = CGL.flushBuffer(contextHandle);
+ }
+ return res;
+ }
+
}
class CGLImpl implements GLBackendImpl {
- @Override
- public boolean isNSContext() { return false; }
-
- @Override
- public long create(long share, int ctp, int major, int minor) {
- long ctx = 0;
- MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration();
- GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities();
- long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2CGLPixelFormat(chosenCaps, ctp, major, minor);
- if (pixelFormat == 0) {
- throw new GLException("Unable to allocate pixel format with requested GLCapabilities");
- }
- config.setChosenPixelFormat(pixelFormat);
- try {
- // Create new context
- PointerBuffer ctxPB = PointerBuffer.allocateDirect(1);
- if (DEBUG) {
- System.err.println("Share context for CGL-based pbuffer context is " + toHexString(share));
+ @Override
+ public boolean isNSContext() { return false; }
+
+ @Override
+ public long create(long share, int ctp, int major, int minor) {
+ long ctx = 0;
+ MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration();
+ GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities();
+ long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2CGLPixelFormat(chosenCaps, ctp, major, minor);
+ if (pixelFormat == 0) {
+ throw new GLException("Unable to allocate pixel format with requested GLCapabilities");
}
- int res = CGL.CGLCreateContext(pixelFormat, share, ctxPB);
- if (res != CGL.kCGLNoError) {
- throw new GLException("Error code " + res + " while creating context");
- }
- if(chosenCaps.isPBuffer()) {
- // Attach newly-created context to the pbuffer
- res = CGL.CGLSetPBuffer(ctxPB.get(0), drawable.getHandle(), 0, 0, 0);
+ try {
+ // Create new context
+ PointerBuffer ctxPB = PointerBuffer.allocateDirect(1);
+ if (DEBUG) {
+ System.err.println("Share context for CGL-based pbuffer context is " + toHexString(share));
+ }
+ int res = CGL.CGLCreateContext(pixelFormat, share, ctxPB);
if (res != CGL.kCGLNoError) {
- throw new GLException("Error code " + res + " while attaching context to pbuffer");
+ throw new GLException("Error code " + res + " while creating context");
}
- }
- ctx = ctxPB.get(0);
- if(0!=ctx) {
- if(DEBUG) {
- GLCapabilitiesImmutable caps0 = MacOSXCGLGraphicsConfiguration.CGLPixelFormat2GLCapabilities(pixelFormat);
- System.err.println("NS created: "+caps0);
+ ctx = ctxPB.get(0);
+
+ if (0 != ctx) {
+ GLCapabilities fixedCaps = MacOSXCGLGraphicsConfiguration.CGLPixelFormat2GLCapabilities(pixelFormat);
+ fixedCaps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(fixedCaps, chosenCaps.isBackgroundOpaque());
+ if(chosenCaps.isOnscreen() || !fixedCaps.isPBuffer()) {
+ // not handled, so copy them
+ fixedCaps.setFBO(chosenCaps.isFBO());
+ fixedCaps.setPBuffer(chosenCaps.isPBuffer());
+ fixedCaps.setBitmap(chosenCaps.isBitmap());
+ fixedCaps.setOnscreen(chosenCaps.isOnscreen());
+ }
+ config.setChosenCapabilities(fixedCaps);
+ if(DEBUG) {
+ System.err.println("CGL create fixedCaps: "+fixedCaps);
+ }
+ if(fixedCaps.isPBuffer()) {
+ // Must now associate the pbuffer with our newly-created context
+ res = CGL.CGLSetPBuffer(ctx, drawable.getHandle(), 0, 0, 0);
+ if (res != CGL.kCGLNoError) {
+ throw new GLException("Error code " + res + " while attaching context to pbuffer");
+ }
+ }
}
+ } finally {
+ CGL.CGLDestroyPixelFormat(pixelFormat);
}
- } finally {
- CGL.CGLDestroyPixelFormat(pixelFormat);
+ return ctx;
}
- return ctx;
- }
- @Override
- public boolean destroy(long ctx) {
- return CGL.CGLDestroyContext(ctx) == CGL.kCGLNoError;
- }
+ @Override
+ public boolean destroy(long ctx) {
+ return CGL.CGLDestroyContext(ctx) == CGL.kCGLNoError;
+ }
- @Override
- public boolean copyImpl(long src, int mask) {
- CGL.CGLCopyContext(src, contextHandle, mask);
- return true;
- }
+ @Override
+ public boolean contextRealized(boolean realized) {
+ return true;
+ }
+
+ @Override
+ public boolean copyImpl(long src, int mask) {
+ CGL.CGLCopyContext(src, contextHandle, mask);
+ return true;
+ }
- @Override
- public boolean makeCurrent(long ctx) {
- int err = CGL.CGLLockContext(ctx);
- if(CGL.kCGLNoError == err) {
- err = CGL.CGLSetCurrentContext(ctx);
+ @Override
+ public boolean makeCurrent(long ctx) {
+ int err = CGL.CGLLockContext(ctx);
if(CGL.kCGLNoError == err) {
- return true;
+ err = CGL.CGLSetCurrentContext(ctx);
+ if(CGL.kCGLNoError == err) {
+ return true;
+ } else if(DEBUG) {
+ System.err.println("CGL: Could not make context current: err 0x"+Integer.toHexString(err)+": "+this);
+ }
} else if(DEBUG) {
- System.err.println("CGL: Could not make context current: err 0x"+Integer.toHexString(err)+": "+this);
+ System.err.println("CGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this);
}
- } else if(DEBUG) {
- System.err.println("CGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this);
+ return false;
}
- return false;
- }
- @Override
- public boolean release(long ctx) {
- try {
- gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze
- } catch (GLException gle) {
- if(DEBUG) {
- System.err.println("MacOSXCGLContext.CGLImpl.release: INFO: glFlush() catched exception:");
- gle.printStackTrace();
+ @Override
+ public boolean release(long ctx) {
+ try {
+ gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze
+ } catch (GLException gle) {
+ if(DEBUG) {
+ System.err.println("MacOSXCGLContext.CGLImpl.release: INFO: glFlush() catched exception:");
+ gle.printStackTrace();
+ }
}
+ int err = CGL.CGLSetCurrentContext(0);
+ if(DEBUG && CGL.kCGLNoError != err) {
+ System.err.println("CGL: Could not release current context: err 0x"+Integer.toHexString(err)+": "+this);
+ }
+ int err2 = CGL.CGLUnlockContext(ctx);
+ if(DEBUG && CGL.kCGLNoError != err2) {
+ System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err2)+": "+this);
+ }
+ return CGL.kCGLNoError == err && CGL.kCGLNoError == err2;
+ }
+
+ @Override
+ public boolean detachPBuffer() {
+ /* Doesn't work, i.e. not taking NULL
+ final int res = CGL.CGLSetPBuffer(contextHandle, 0, 0, 0, 0);
+ if (res != CGL.kCGLNoError) {
+ throw new GLException("Error code " + res + " while detaching context from pbuffer");
+ } */
+ return true;
}
- int err = CGL.CGLSetCurrentContext(0);
- if(DEBUG && CGL.kCGLNoError != err) {
- System.err.println("CGL: Could not release current context: err 0x"+Integer.toHexString(err)+": "+this);
+
+ @Override
+ public boolean setSwapInterval(int interval) {
+ int[] lval = new int[] { interval } ;
+ CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0);
+ return true;
}
- int err2 = CGL.CGLUnlockContext(ctx);
- if(DEBUG && CGL.kCGLNoError != err2) {
- System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err2)+": "+this);
+ @Override
+ public boolean swapBuffers() {
+ return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle);
}
- return CGL.kCGLNoError == err && CGL.kCGLNoError == err2;
- }
-
- @Override
- public boolean setSwapInterval(int interval) {
- int[] lval = new int[] { interval } ;
- CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0);
- return true;
- }
- @Override
- public boolean swapBuffers() {
- return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle);
- }
}
}
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java
index af767f0c3..cc727c8e1 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java
@@ -42,10 +42,10 @@ package jogamp.opengl.macosx.cgl;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import javax.media.nativewindow.NativeSurface;
+import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
@@ -92,7 +92,7 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl {
this.id = id;
}
}
- private List> createdContexts = new ArrayList>();
+ /* pp */ List> createdContexts = new ArrayList>();
private boolean haveSetOpenGLMode = false;
private GLBackendType openGLMode = GLBackendType.NSOPENGL;
@@ -110,26 +110,42 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl {
return GLBackendType.NSOPENGL == openGLMode ? getHandle() : 0;
}
- protected void registerContext(MacOSXCGLContext ctx) {
+ @Override
+ protected void associateContext(GLContext ctx, boolean bound) {
// NOTE: we need to keep track of the created contexts in order to
// implement swapBuffers() because of how Mac OS X implements its
// OpenGL window interface
synchronized (createdContexts) {
- createdContexts.add(new WeakReference(ctx));
- }
+ if(bound) {
+ createdContexts.add(new WeakReference((MacOSXCGLContext)ctx));
+ } else {
+ for(int i=0; i ref = createdContexts.get(i);
+ final MacOSXCGLContext _ctx = ref.get();
+ if( _ctx == null || _ctx == ctx) {
+ createdContexts.remove(i);
+ } else {
+ i++;
+ }
+ }
+ }
+ }
}
+
@Override
- protected final void swapBuffersImpl() {
- // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers()
- synchronized (createdContexts) {
- for (Iterator> iter = createdContexts.iterator(); iter.hasNext(); ) {
- WeakReference ref = iter.next();
- MacOSXCGLContext ctx = ref.get();
- if (ctx != null) {
- ctx.swapBuffers();
- } else {
- iter.remove();
- }
+ protected final void swapBuffersImpl(boolean doubleBuffered) {
+ if(doubleBuffered) {
+ synchronized (createdContexts) {
+ for(int i=0; i ref = createdContexts.get(i);
+ final MacOSXCGLContext ctx = ref.get();
+ if (ctx != null) {
+ ctx.swapBuffers();
+ i++;
+ } else {
+ createdContexts.remove(i);
+ }
+ }
}
}
}
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java
index 591fafc68..e174d38f4 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java
@@ -51,7 +51,7 @@ import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.DefaultGraphicsScreen;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.ProxySurface;
-import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook;
+import javax.media.nativewindow.UpstreamSurfaceHook;
import javax.media.opengl.GL;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesChooser;
@@ -61,7 +61,8 @@ import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
-import jogamp.nativewindow.macosx.OSXUtil;
+import jogamp.nativewindow.WrappedSurface;
+import jogamp.nativewindow.macosx.OSXDummyUpstreamSurfaceHook;
import jogamp.opengl.DesktopGLDynamicLookupHelper;
import jogamp.opengl.GLContextImpl;
import jogamp.opengl.GLDrawableFactoryImpl;
@@ -71,7 +72,7 @@ import jogamp.opengl.GLGraphicsConfigurationUtil;
import com.jogamp.common.JogampRuntimeException;
import com.jogamp.common.util.ReflectionUtil;
-import com.jogamp.nativewindow.WrappedSurface;
+import com.jogamp.nativewindow.MutableGraphicsConfiguration;
import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice;
import com.jogamp.opengl.GLExtensions;
@@ -320,9 +321,14 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl {
@Override
protected GLDrawableImpl createOffscreenDrawableImpl(NativeSurface target) {
- AbstractGraphicsConfiguration config = target.getGraphicsConfiguration();
- GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities();
+ final MutableGraphicsConfiguration config = (MutableGraphicsConfiguration) target.getGraphicsConfiguration();
+ final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities();
if(!caps.isPBuffer()) {
+ // Actual implementation is using PBuffer ...
+ final GLCapabilities modCaps = (GLCapabilities) caps.cloneMutable();
+ modCaps.setPBuffer(true);
+ modCaps.setBitmap(false);
+ config.setChosenCapabilities(modCaps);
return new MacOSXOffscreenCGLDrawable(this, target);
}
return new MacOSXPbufferCGLDrawable(this, target);
@@ -336,7 +342,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl {
@Override
protected ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice,
GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested,
- GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook) {
+ GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) {
final MacOSXGraphicsDevice device;
if(createNewDevice) {
device = new MacOSXGraphicsDevice(deviceReq.getUnitID());
@@ -348,68 +354,23 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl {
if(null == config) {
throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen);
}
- return new WrappedSurface(config, 0, width, height, lifecycleHook);
+ return new WrappedSurface(config, 0, upstreamHook, createNewDevice);
}
@Override
public final ProxySurface createDummySurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice,
GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height) {
final GLCapabilitiesImmutable chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(requestedCaps);
- return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, width, height, dummySurfaceLifecycleHook);
+ return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser,
+ new OSXDummyUpstreamSurfaceHook(width, height));
}
- private static final ProxySurface.UpstreamSurfaceHook dummySurfaceLifecycleHook = new ProxySurface.UpstreamSurfaceHook() {
- long nsWindow = 0;
- @Override
- public final void create(ProxySurface s) {
- if(0 == nsWindow && 0 == s.getSurfaceHandle()) {
- nsWindow = OSXUtil.CreateNSWindow(0, 0, s.getWidth(), s.getHeight());
- if(0 == nsWindow) {
- throw new GLException("Error NS window 0");
- }
- long nsView = OSXUtil.GetNSView(nsWindow);
- if(0 == nsView) {
- throw new GLException("Error NS view 0");
- }
- s.setSurfaceHandle(nsView);
- s.setImplBitfield(ProxySurface.INVISIBLE_WINDOW);
- if(DEBUG) {
- System.err.println("MacOSXCGLDrawableFactory.dummySurfaceLifecycleHook.create: "+s);
- }
- }
- }
- @Override
- public final void destroy(ProxySurface s) {
- if(0 != nsWindow && 0 != s.getSurfaceHandle()) {
- OSXUtil.DestroyNSWindow(nsWindow);
- nsWindow = 0;
- s.setSurfaceHandle(0);
- if(DEBUG) {
- System.err.println("MacOSXCGLDrawableFactory.dummySurfaceLifecycleHook.destroy: "+s);
- }
- }
- }
- @Override
- public final int getWidth(ProxySurface s) {
- return s.initialWidth;
- }
- @Override
- public final int getHeight(ProxySurface s) {
- return s.initialHeight;
- }
-
- @Override
- public String toString() {
- return "MacOSXLSurfaceLifecycleHook[]";
- }
-
- };
@Override
protected ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream) {
final MacOSXGraphicsDevice device = new MacOSXGraphicsDevice(deviceReq.getUnitID());
final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx);
final MacOSXCGLGraphicsConfiguration config = MacOSXCGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen, true);
- return new WrappedSurface(config, windowHandle, 0, 0, upstream);
+ return new WrappedSurface(config, windowHandle, upstream, true);
}
@Override
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java
index 149927160..8866c7ce6 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java
@@ -51,23 +51,16 @@ import com.jogamp.common.nio.PointerBuffer;
import com.jogamp.nativewindow.MutableGraphicsConfiguration;
public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable {
- long pixelformat;
MacOSXCGLGraphicsConfiguration(AbstractGraphicsScreen screen,
- GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested,
- long pixelformat) {
+ GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested) {
super(screen, capsChosen, capsRequested);
- this.pixelformat=pixelformat;
}
public Object clone() {
return super.clone();
}
- void setChosenPixelFormat(long pixelformat) {
- this.pixelformat=pixelformat;
- }
-
protected static List getAvailableCapabilities(MacOSXCGLDrawableFactory factory, AbstractGraphicsDevice device) {
MacOSXCGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateOSXSharedResource(device);
if(null == sharedResource) {
@@ -114,11 +107,11 @@ public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration
break;
case CGL.kCGLPFAColorFloat:
- ivalues[idx] = caps.getPbufferFloatingPointBuffers() ? 1 : 0;
+ ivalues[idx] = ( !caps.isOnscreen() && caps.isPBuffer() && caps.getPbufferFloatingPointBuffers() ) ? 1 : 0;
break;
case CGL.NSOpenGLPFAPixelBuffer:
- ivalues[idx] = caps.isPBuffer() ? 1 : 0;
+ ivalues[idx] = ( !caps.isOnscreen() && caps.isPBuffer() ) ? 1 : 0;
break;
case CGL.NSOpenGLPFADoubleBuffer:
@@ -188,11 +181,11 @@ public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration
attrs[i++] = CGL.kCGLPFAOpenGLProfile;
attrs[i++] = MacOSXCGLContext.GLProfile2CGLOGLProfileValue(ctp, major, minor);
}
- if(caps.isPBuffer()) {
+ if(!caps.isOnscreen() && caps.isPBuffer()) {
attrs[i++] = CGL.kCGLPFAPBuffer;
- }
- if (caps.getPbufferFloatingPointBuffers()) {
- attrs[i++] = CGL.kCGLPFAColorFloat;
+ if (caps.getPbufferFloatingPointBuffers()) {
+ attrs[i++] = CGL.kCGLPFAColorFloat;
+ }
}
if (caps.getDoubleBuffered()) {
attrs[i++] = CGL.kCGLPFADoubleBuffer;
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java
index 13faf7090..43a9d0d1a 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java
@@ -96,6 +96,6 @@ public class MacOSXCGLGraphicsConfigurationFactory extends GLGraphicsConfigurati
capsChosen = GLGraphicsConfigurationUtil.fixGLCapabilities( capsChosen, GLContext.isFBOAvailable(device, capsChosen.getGLProfile()), factory.canCreateGLPbuffer(device) );
- return new MacOSXCGLGraphicsConfiguration(absScreen, (GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested, 0);
+ return new MacOSXCGLGraphicsConfiguration(absScreen, (GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested);
}
}
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java
index 6be9e386d..65ed5fc15 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java
@@ -49,8 +49,8 @@ import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
-import com.jogamp.nativewindow.WrappedSurface;
+import jogamp.nativewindow.WrappedSurface;
import jogamp.opengl.GLContextImpl;
import jogamp.opengl.GLContextShareSet;
import jogamp.opengl.macosx.cgl.MacOSXCGLDrawable.GLBackendType;
@@ -62,7 +62,6 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext {
private MacOSXExternalCGLContext(Drawable drawable, boolean isNSContext, long handle) {
super(drawable, null);
setOpenGLMode(isNSContext ? GLBackendType.NSOPENGL : GLBackendType.CGL );
- drawable.registerContext(this);
this.contextHandle = handle;
GLContextShareSet.contextCreated(this);
setGLFunctionAvailability(false, 0, 0, CTX_PROFILE_COMPAT);
@@ -108,13 +107,13 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext {
}
AbstractGraphicsScreen aScreen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_MACOSX);
- MacOSXCGLGraphicsConfiguration cfg = new MacOSXCGLGraphicsConfiguration(aScreen, caps, caps, pixelFormat);
+ MacOSXCGLGraphicsConfiguration cfg = new MacOSXCGLGraphicsConfiguration(aScreen, caps, caps);
if(0 == currentDrawable) {
// set a fake marker stating a valid drawable
currentDrawable = 1;
}
- WrappedSurface ns = new WrappedSurface(cfg, currentDrawable, 64, 64, null);
+ WrappedSurface ns = new WrappedSurface(cfg, currentDrawable, 64, 64, true);
return new MacOSXExternalCGLContext(new Drawable(factory, ns), isNSContext, contextHandle);
}
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java
index b1e283ebc..ec9628004 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java
@@ -52,9 +52,7 @@ public class MacOSXOnscreenCGLDrawable extends MacOSXCGLDrawable {
@Override
public GLContext createContext(GLContext shareWith) {
- final MacOSXOnscreenCGLContext ctx= new MacOSXOnscreenCGLContext(this, shareWith);
- registerContext(ctx);
- return ctx;
+ return new MacOSXOnscreenCGLContext(this, shareWith);
}
}
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java
index 88886ddd2..7e2d8cf10 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java
@@ -39,6 +39,7 @@ import javax.media.opengl.GLPbuffer;
import jogamp.opengl.GLContextImpl;
+@SuppressWarnings("deprecation")
public class MacOSXPbufferCGLContext extends MacOSXCGLContext {
// State for render-to-texture and render-to-texture-rectangle support
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java
index 8f2f386af..668e463a2 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java
@@ -40,6 +40,8 @@
package jogamp.opengl.macosx.cgl;
+import java.lang.ref.WeakReference;
+
import javax.media.nativewindow.DefaultGraphicsConfiguration;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.MutableSurface;
@@ -70,9 +72,6 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable {
// private int textureTarget; // e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_NV
// private int texture; // actual texture object
- // Note that we can not store this in the NativeSurface because the
- // semantic is that contains an NSView
- protected long pBuffer;
protected int pBufferTexTarget, pBufferTexWidth, pBufferTexHeight;
public MacOSXPbufferCGLDrawable(GLDrawableFactory factory, NativeSurface target) {
@@ -90,9 +89,7 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable {
@Override
public GLContext createContext(GLContext shareWith) {
- final MacOSXPbufferCGLContext ctx = new MacOSXPbufferCGLContext(this, shareWith);
- registerContext(ctx);
- return ctx;
+ return new MacOSXPbufferCGLContext(this, shareWith);
}
@Override
@@ -101,27 +98,34 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable {
return 0;
}
- @Override
- public long getHandle() {
- return pBuffer;
- }
-
protected int getTextureTarget() { return pBufferTexTarget; }
protected int getTextureWidth() { return pBufferTexWidth; }
protected int getTextureHeight() { return pBufferTexHeight; }
protected void destroyPbuffer() {
- if (this.pBuffer != 0) {
- NativeSurface ns = getNativeSurface();
+ final MutableSurface ms = (MutableSurface) getNativeSurface();
+ final long pBuffer = ms.getSurfaceHandle();
+ if (0 != pBuffer) {
+ synchronized (createdContexts) {
+ for(int i=0; i ref = createdContexts.get(i);
+ final MacOSXCGLContext ctx = ref.get();
+ if (ctx != null) {
+ ctx.detachPBuffer();
+ i++;
+ } else {
+ createdContexts.remove(i);
+ }
+ }
+ }
impl.destroy(pBuffer);
- this.pBuffer = 0;
- ((MutableSurface)ns).setSurfaceHandle(0);
+ ms.setSurfaceHandle(0);
}
}
private void createPbuffer() {
- final NativeSurface ns = getNativeSurface();
- final DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ns.getGraphicsConfiguration();
+ final MutableSurface ms = (MutableSurface) getNativeSurface();
+ final DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ms.getGraphicsConfiguration();
final GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities();
final GLProfile glProfile = capabilities.getGLProfile();
MacOSXCGLDrawableFactory.SharedResource sr = ((MacOSXCGLDrawableFactory)factory).getOrCreateOSXSharedResource(config.getScreen().getDevice());
@@ -161,7 +165,7 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable {
}
}
- pBuffer = impl.create(pBufferTexTarget, internalFormat, getWidth(), getHeight());
+ final long pBuffer = impl.create(pBufferTexTarget, internalFormat, getWidth(), getHeight());
if(DEBUG) {
System.err.println("MacOSXPbufferCGLDrawable tex: target "+toHexString(pBufferTexTarget)+
", pbufferSize "+getWidth()+"x"+getHeight()+
@@ -174,7 +178,7 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable {
throw new GLException("pbuffer creation error: CGL.createPBuffer() failed");
}
- ((MutableSurface)ns).setSurfaceHandle(pBuffer);
+ ms.setSurfaceHandle(pBuffer);
}
@Override
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java
index 96c1187d3..f6cc2956d 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java
@@ -50,8 +50,8 @@ import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
-import com.jogamp.nativewindow.WrappedSurface;
+import jogamp.nativewindow.WrappedSurface;
import jogamp.nativewindow.windows.GDI;
import jogamp.opengl.GLContextShareSet;
@@ -102,7 +102,7 @@ public class WindowsExternalWGLContext extends WindowsWGLContext {
System.err.println("WindowsExternalWGLContext valid hdc/pfd, retrieved cfg: " + cfg);
}
}
- return new WindowsExternalWGLContext(new Drawable(factory, new WrappedSurface(cfg, hdc, 64, 64, null)), ctx, cfg);
+ return new WindowsExternalWGLContext(new Drawable(factory, new WrappedSurface(cfg, hdc, 64, 64, true)), ctx, cfg);
}
@Override
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java
index 15bd005dc..f8c237c9e 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java
@@ -49,10 +49,10 @@ import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
+import jogamp.nativewindow.WrappedSurface;
import jogamp.nativewindow.windows.GDI;
import jogamp.nativewindow.windows.GDIUtil;
-import com.jogamp.nativewindow.WrappedSurface;
public class WindowsExternalWGLDrawable extends WindowsWGLDrawable {
@@ -72,7 +72,7 @@ public class WindowsExternalWGLDrawable extends WindowsWGLDrawable {
final AbstractGraphicsScreen aScreen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_WINDOWS);
final WindowsWGLGraphicsConfiguration cfg = WindowsWGLGraphicsConfiguration.createFromExternal(factory, hdc, pfdID, glp, aScreen, true);
- return new WindowsExternalWGLDrawable(factory, new WrappedSurface(cfg, hdc, 64, 64, null));
+ return new WindowsExternalWGLDrawable(factory, new WrappedSurface(cfg, hdc, 64, 64, true));
}
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java
index ca7886e7f..3b3f0c123 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java
@@ -73,27 +73,28 @@ public abstract class WindowsWGLDrawable extends GLDrawableImpl {
}
@Override
- protected final void swapBuffersImpl() {
- // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers()
- final long t0;
- if (PROFILING) {
- t0 = System.currentTimeMillis();
- } else {
- t0 = 0;
- }
-
- if (!WGLUtil.SwapBuffers(getHandle()) && (GDI.GetLastError() != GDI.ERROR_SUCCESS)) {
- throw new GLException("Error swapping buffers");
- }
-
- if (PROFILING) {
- profilingSwapBuffersTime += System.currentTimeMillis() - t0;
- if (++profilingSwapBuffersTicks == PROFILING_TICKS) {
- System.err.println("SwapBuffers calls: " + profilingSwapBuffersTime + " ms / " + PROFILING_TICKS + " calls (" +
- ((float) profilingSwapBuffersTime / (float) PROFILING_TICKS) + " ms/call)");
- profilingSwapBuffersTime = 0;
- profilingSwapBuffersTicks = 0;
- }
+ protected final void swapBuffersImpl(boolean doubleBuffered) {
+ if(doubleBuffered) {
+ final long t0;
+ if (PROFILING) {
+ t0 = System.currentTimeMillis();
+ } else {
+ t0 = 0;
+ }
+
+ if (!WGLUtil.SwapBuffers(getHandle()) && (GDI.GetLastError() != GDI.ERROR_SUCCESS)) {
+ throw new GLException("Error swapping buffers");
+ }
+
+ if (PROFILING) {
+ profilingSwapBuffersTime += System.currentTimeMillis() - t0;
+ if (++profilingSwapBuffersTicks == PROFILING_TICKS) {
+ System.err.println("SwapBuffers calls: " + profilingSwapBuffersTime + " ms / " + PROFILING_TICKS + " calls (" +
+ ((float) profilingSwapBuffersTime / (float) PROFILING_TICKS) + " ms/call)");
+ profilingSwapBuffersTime = 0;
+ profilingSwapBuffersTicks = 0;
+ }
+ }
}
}
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java
index 7ea487523..91d5c225a 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java
@@ -52,7 +52,7 @@ import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.DefaultGraphicsScreen;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.ProxySurface;
-import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook;
+import javax.media.nativewindow.UpstreamSurfaceHook;
import javax.media.opengl.GL;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesChooser;
@@ -62,9 +62,10 @@ import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
+import jogamp.nativewindow.WrappedSurface;
import jogamp.nativewindow.windows.GDI;
+import jogamp.nativewindow.windows.GDIDummyUpstreamSurfaceHook;
import jogamp.nativewindow.windows.GDISurface;
-import jogamp.nativewindow.windows.GDIUtil;
import jogamp.nativewindow.windows.RegisteredClassFactory;
import jogamp.opengl.DesktopGLDynamicLookupHelper;
import jogamp.opengl.GLContextImpl;
@@ -79,7 +80,6 @@ import com.jogamp.common.nio.PointerBuffer;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.ReflectionUtil;
import com.jogamp.common.util.VersionNumber;
-import com.jogamp.nativewindow.WrappedSurface;
import com.jogamp.nativewindow.windows.WindowsGraphicsDevice;
import com.jogamp.opengl.GLExtensions;
@@ -541,7 +541,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl {
@Override
protected final ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice,
GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested,
- GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook) {
+ GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) {
final WindowsGraphicsDevice device;
if(createNewDevice) {
device = new WindowsGraphicsDevice(deviceReq.getConnection(), deviceReq.getUnitID());
@@ -553,7 +553,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl {
if(null == config) {
throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen);
}
- return new WrappedSurface(config, 0, width, height, lifecycleHook);
+ return new WrappedSurface(config, 0, upstreamHook, createNewDevice);
}
@Override
@@ -571,57 +571,15 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl {
if(null == config) {
throw new GLException("Choosing GraphicsConfiguration failed w/ "+requestedCaps+" on "+screen);
}
- return new GDISurface(config, 0, width, height, dummySurfaceLifecycleHook);
- }
- private static final ProxySurface.UpstreamSurfaceHook dummySurfaceLifecycleHook = new ProxySurface.UpstreamSurfaceHook() {
- @Override
- public final void create(ProxySurface s) {
- final GDISurface ms = (GDISurface)s;
- if(0 == ms.getWindowHandle()) {
- final long windowHandle = GDIUtil.CreateDummyWindow(0, 0, s.getWidth(), s.getHeight());
- if(0 == windowHandle) {
- throw new GLException("Error windowHandle 0, werr: "+GDI.GetLastError());
- }
- ms.setWindowHandle(windowHandle);
- if(DEBUG) {
- System.err.println("WindowsWGLDrawableFactory.dummySurfaceLifecycleHook.create: "+ms);
- }
- }
- }
- @Override
- public final void destroy(ProxySurface s) {
- final GDISurface ms = (GDISurface)s;
- if(0 != ms.getWindowHandle()) {
- GDI.ShowWindow(ms.getWindowHandle(), GDI.SW_HIDE);
- GDIUtil.DestroyDummyWindow(ms.getWindowHandle());
- ms.setWindowHandle(0);
- if(DEBUG) {
- System.err.println("WindowsWGLDrawableFactory.dummySurfaceLifecycleHook.destroy: "+ms);
- }
- }
- }
- @Override
- public final int getWidth(ProxySurface s) {
- return s.initialWidth;
- }
- @Override
- public final int getHeight(ProxySurface s) {
- return s.initialHeight;
- }
-
- @Override
- public String toString() {
- return "GDISurfaceLifecycleHook[]";
- }
- };
-
+ return new GDISurface(config, 0, new GDIDummyUpstreamSurfaceHook(width, height), createNewDevice);
+ }
@Override
protected final ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream) {
final WindowsGraphicsDevice device = new WindowsGraphicsDevice(deviceReq.getConnection(), deviceReq.getUnitID());
final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx);
final WindowsWGLGraphicsConfiguration cfg = WindowsWGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen);
- return new GDISurface(cfg, windowHandle, 0, 0, upstream);
+ return new GDISurface(cfg, windowHandle, upstream, true);
}
@Override
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java
index 4d1069e6b..058f4e336 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java
@@ -107,7 +107,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio
if(hasARB) {
caps = wglARBPFID2GLCapabilities(sharedResource, device, glp, hdc, pfdID, GLGraphicsConfigurationUtil.ALL_BITS);
} else {
- caps = PFD2GLCapabilities(glp, hdc, pfdID, GLGraphicsConfigurationUtil.ALL_BITS);
+ caps = PFD2GLCapabilities(device, glp, hdc, pfdID, GLGraphicsConfigurationUtil.ALL_BITS);
}
if(null==caps) {
throw new GLException("Couldn't choose Capabilities by: HDC 0x"+Long.toHexString(hdc)+
@@ -325,7 +325,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio
throw new GLException("wglARBPFID2GLCapabilities: Error getting pixel format attributes for pixel format " + pfdID +
" of device context " + toHexString(hdc) + ", werr " + GDI.GetLastError());
}
- return AttribList2GLCapabilities(glp, hdc, pfdID, iattributes, niattribs, iresults, winattrbits);
+ return AttribList2GLCapabilities(device, glp, hdc, pfdID, iattributes, niattribs, iresults, winattrbits);
}
static int[] wglChoosePixelFormatARB(WindowsWGLDrawableFactory.SharedResource sharedResource, AbstractGraphicsDevice device,
@@ -390,7 +390,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio
for(int i = 0; i= 1 &&
((WindowsWGLContext)sharedResource.getContext()).getWGLExt().wglGetPixelFormatAttribivARB(hdc, pfdIDs[i], 0, niattribs, iattributes, 0, iresults, 0) ) {
- final GLCapabilitiesImmutable caps = AttribList2GLCapabilities(glp, hdc, pfdIDs[i], iattributes, niattribs, iresults, winattrbits);
+ final GLCapabilitiesImmutable caps = AttribList2GLCapabilities(device, glp, hdc, pfdIDs[i], iattributes, niattribs, iresults, winattrbits);
if(null != caps) {
bucket.add(caps);
if(DEBUG) {
@@ -398,7 +398,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio
System.err.println("wglARBPFIDs2GLCapabilities: bucket["+i+" -> "+j+"]: "+caps);
}
} else if(DEBUG) {
- GLCapabilitiesImmutable skipped = AttribList2GLCapabilities(glp, hdc, pfdIDs[i], iattributes, niattribs, iresults, GLGraphicsConfigurationUtil.ALL_BITS);
+ GLCapabilitiesImmutable skipped = AttribList2GLCapabilities(device, glp, hdc, pfdIDs[i], iattributes, niattribs, iresults, GLGraphicsConfigurationUtil.ALL_BITS);
System.err.println("wglARBPFIDs2GLCapabilities: bucket["+i+" -> skip]: pfdID "+pfdIDs[i]+", "+skipped+", winattr "+GLGraphicsConfigurationUtil.winAttributeBits2String(null, winattrbits).toString());
}
} else if (DEBUG) {
@@ -616,9 +616,9 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio
return val;
}
- static WGLGLCapabilities AttribList2GLCapabilities(final GLProfile glp,
- final long hdc, final int pfdID, final int[] iattribs,
- final int niattribs, final int[] iresults, final int winattrmask) {
+ static WGLGLCapabilities AttribList2GLCapabilities(final AbstractGraphicsDevice device,
+ final GLProfile glp, final long hdc, final int pfdID,
+ final int[] iattribs, final int niattribs, final int[] iresults, final int winattrmask) {
final int allDrawableTypeBits = AttribList2DrawableTypeBits(iattribs, niattribs, iresults);
int drawableTypeBits = winattrmask & allDrawableTypeBits;
@@ -637,7 +637,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio
}
final WGLGLCapabilities res = new WGLGLCapabilities(pfd, pfdID, glp);
res.setValuesByARB(iattribs, niattribs, iresults);
- return (WGLGLCapabilities) GLGraphicsConfigurationUtil.setWinAttributeBits(res, drawableTypeBits);
+ return (WGLGLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, res);
}
//
@@ -672,7 +672,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio
return val;
}
- static WGLGLCapabilities PFD2GLCapabilities(final GLProfile glp, final long hdc, final int pfdID, final int winattrmask) {
+ static WGLGLCapabilities PFD2GLCapabilities(AbstractGraphicsDevice device, final GLProfile glp, final long hdc, final int pfdID, final int winattrmask) {
PIXELFORMATDESCRIPTOR pfd = createPixelFormatDescriptor(hdc, pfdID);
if(null == pfd) {
return null;
@@ -689,21 +689,22 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio
final WGLGLCapabilities res = new WGLGLCapabilities(pfd, pfdID, glp);
res.setValuesByGDI();
- return (WGLGLCapabilities) GLGraphicsConfigurationUtil.setWinAttributeBits(res, drawableTypeBits );
+ return (WGLGLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, res);
}
- static WGLGLCapabilities PFD2GLCapabilitiesNoCheck(final GLProfile glp, final long hdc, final int pfdID) {
+ static WGLGLCapabilities PFD2GLCapabilitiesNoCheck(AbstractGraphicsDevice device, final GLProfile glp, final long hdc, final int pfdID) {
PIXELFORMATDESCRIPTOR pfd = createPixelFormatDescriptor(hdc, pfdID);
- return PFD2GLCapabilitiesNoCheck(glp, pfd, pfdID);
+ return PFD2GLCapabilitiesNoCheck(device, glp, pfd, pfdID);
}
- static WGLGLCapabilities PFD2GLCapabilitiesNoCheck(GLProfile glp, PIXELFORMATDESCRIPTOR pfd, int pfdID) {
+ static WGLGLCapabilities PFD2GLCapabilitiesNoCheck(AbstractGraphicsDevice device, GLProfile glp, PIXELFORMATDESCRIPTOR pfd, int pfdID) {
if(null == pfd) {
return null;
}
final WGLGLCapabilities res = new WGLGLCapabilities(pfd, pfdID, glp);
res.setValuesByGDI();
- return (WGLGLCapabilities) GLGraphicsConfigurationUtil.setWinAttributeBits(res, PFD2DrawableTypeBits(pfd));
+
+ return (WGLGLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, PFD2DrawableTypeBits(pfd), res);
}
static PIXELFORMATDESCRIPTOR GLCapabilities2PFD(GLCapabilitiesImmutable caps, PIXELFORMATDESCRIPTOR pfd) {
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java
index 41c9bba02..d2d1dafc8 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java
@@ -113,13 +113,14 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat
}
protected static List getAvailableCapabilities(WindowsWGLDrawableFactory factory, AbstractGraphicsDevice device) {
- WindowsWGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateSharedResource(device);
+ final WindowsWGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateSharedResource(device);
if(null == sharedResource) {
throw new GLException("Shared resource for device n/a: "+device);
}
- GLDrawableImpl sharedDrawable = sharedResource.getDrawable();
- GLCapabilitiesImmutable capsChosen = sharedDrawable.getChosenGLCapabilities();
- GLContext sharedContext = sharedResource.getContext();
+ final GLDrawableImpl sharedDrawable = sharedResource.getDrawable();
+ final GLContext sharedContext = sharedResource.getContext();
+ final GLProfile glp = GLProfile.getDefault(device);
+
List availableCaps = null;
if ( sharedResource.needsCurrentContext4ARBPFDQueries() ) {
@@ -135,10 +136,10 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat
throw new GLException("Error: HDC is null");
}
if (sharedResource.hasARBPixelFormat()) {
- availableCaps = WindowsWGLGraphicsConfigurationFactory.getAvailableGLCapabilitiesARB(sharedResource, sharedResource.getDevice(), capsChosen.getGLProfile(), hdc);
+ availableCaps = WindowsWGLGraphicsConfigurationFactory.getAvailableGLCapabilitiesARB(sharedResource, sharedResource.getDevice(), glp, hdc);
}
if( null == availableCaps || availableCaps.isEmpty() ) {
- availableCaps = getAvailableGLCapabilitiesGDI(device, capsChosen.getGLProfile(), hdc);
+ availableCaps = getAvailableGLCapabilitiesGDI(device, glp, hdc);
}
} finally {
if ( sharedResource.needsCurrentContext4ARBPFDQueries() ) {
@@ -165,7 +166,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat
int numFormats = pformats.length;
List bucket = new ArrayList(numFormats);
for (int i = 0; i < numFormats; i++) {
- final GLCapabilitiesImmutable caps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(glProfile, hdc, pformats[i], GLGraphicsConfigurationUtil.ALL_BITS);
+ final GLCapabilitiesImmutable caps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(device, glProfile, hdc, pformats[i], GLGraphicsConfigurationUtil.ALL_BITS);
if(null != caps) {
bucket.add(caps);
}
@@ -439,7 +440,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat
private static boolean updateGraphicsConfigurationGDI(WindowsWGLGraphicsConfiguration config, CapabilitiesChooser chooser, long hdc,
boolean extHDC, int[] pformats) {
GLCapabilitiesImmutable capsChosen = (GLCapabilitiesImmutable) config.getChosenCapabilities();
- if(capsChosen.isPBuffer()) {
+ if( !capsChosen.isOnscreen() && capsChosen.isPBuffer() ) {
if (DEBUG) {
System.err.println("updateGraphicsConfigurationGDI: no pbuffer supported on GDI: " + capsChosen);
}
@@ -454,6 +455,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat
System.err.println("updateGraphicsConfigurationGDI: capsChosen "+capsChosen+", "+GLGraphicsConfigurationUtil.winAttributeBits2String(null, winattrmask).toString());
}
+ AbstractGraphicsDevice device = config.getScreen().getDevice();
int pfdID; // chosen or preset PFD ID
WGLGLCapabilities pixelFormatCaps = null; // chosen or preset PFD ID's caps
boolean pixelFormatSet = false; // indicates a preset PFD ID [caps]
@@ -468,7 +470,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat
+ ", pixelformat " + pfdID);
}
pixelFormatSet = true;
- pixelFormatCaps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(glProfile, hdc, pfdID, winattrmask);
+ pixelFormatCaps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(device, glProfile, hdc, pfdID, winattrmask);
if(null == pixelFormatCaps) {
throw new GLException("Could not map PFD2GLCaps w/ already chosen pfdID "+pfdID);
}
@@ -480,7 +482,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat
List availableCaps = new ArrayList();
for (int i = 0; i < pformats.length; i++) {
- final GLCapabilitiesImmutable caps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(glProfile, hdc, pformats[i], winattrmask);
+ final GLCapabilitiesImmutable caps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(device, glProfile, hdc, pformats[i], winattrmask);
if(null != caps) {
availableCaps.add(caps);
if(DEBUG) {
@@ -488,7 +490,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat
System.err.println("updateGraphicsConfigurationGDI: availableCaps["+i+" -> "+j+"]: "+caps);
}
} else if(DEBUG) {
- GLCapabilitiesImmutable skipped = WindowsWGLGraphicsConfiguration.PFD2GLCapabilitiesNoCheck(glProfile, hdc, pformats[i]);
+ GLCapabilitiesImmutable skipped = WindowsWGLGraphicsConfiguration.PFD2GLCapabilitiesNoCheck(device, glProfile, hdc, pformats[i]);
System.err.println("updateGraphicsConfigurationGDI: availableCaps["+i+" -> skip]: pfdID "+pformats[i]+", "+skipped);
}
}
@@ -505,8 +507,8 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat
recommendedIndex--)
{ /* nop */ }
if(DEBUG && 0 > recommendedIndex) {
- final GLCapabilitiesImmutable reqPFDCaps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilitiesNoCheck(glProfile, pfd, pfdID);
- final GLCapabilitiesImmutable chosenCaps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(glProfile, hdc, pfdID, winattrmask);
+ final GLCapabilitiesImmutable reqPFDCaps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilitiesNoCheck(device, glProfile, pfd, pfdID);
+ final GLCapabilitiesImmutable chosenCaps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(device, glProfile, hdc, pfdID, winattrmask);
System.err.println("Chosen PFDID "+pfdID+", but not found in available caps (use given pfdIDs "+givenPFormats+", reqPFDCaps "+reqPFDCaps+", chosenCaps: "+chosenCaps);
}
}
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java
index 1f3edbd8a..03a0eefbf 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java
@@ -48,10 +48,10 @@ import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
+import jogamp.nativewindow.WrappedSurface;
import jogamp.opengl.GLContextImpl;
import jogamp.opengl.GLContextShareSet;
-import com.jogamp.nativewindow.WrappedSurface;
import com.jogamp.nativewindow.x11.X11GraphicsScreen;
public class X11ExternalGLXContext extends X11GLXContext {
@@ -105,7 +105,7 @@ public class X11ExternalGLXContext extends X11GLXContext {
cfg = X11GLXGraphicsConfiguration.create(glp, x11Screen, val[0]);
}
- final WrappedSurface ns = new WrappedSurface(cfg, drawable, w, h, null);
+ final WrappedSurface ns = new WrappedSurface(cfg, drawable, w, h, true);
return new X11ExternalGLXContext(new Drawable(factory, ns), ctx);
}
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java
index 8652e2d4a..ac78c6f4a 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java
@@ -45,7 +45,8 @@ import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
-import com.jogamp.nativewindow.WrappedSurface;
+import jogamp.nativewindow.WrappedSurface;
+
import com.jogamp.nativewindow.x11.X11GraphicsScreen;
@@ -87,7 +88,7 @@ public class X11ExternalGLXDrawable extends X11GLXDrawable {
System.err.println("X11ExternalGLXDrawable: WARNING: forcing GLX_RGBA_TYPE for newly created contexts (current 0x"+Integer.toHexString(val[0])+")");
}
}
- return new X11ExternalGLXDrawable(factory, new WrappedSurface(cfg, drawable, w, h, null));
+ return new X11ExternalGLXDrawable(factory, new WrappedSurface(cfg, drawable, w, h, true));
}
@Override
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java
index e9912ce9d..8c642777d 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java
@@ -69,9 +69,10 @@ public abstract class X11GLXDrawable extends GLDrawableImpl {
}
@Override
- protected final void swapBuffersImpl() {
- // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers()
- GLX.glXSwapBuffers(getNativeSurface().getDisplayHandle(), getHandle());
+ protected final void swapBuffersImpl(boolean doubleBuffered) {
+ if(doubleBuffered) {
+ GLX.glXSwapBuffers(getNativeSurface().getDisplayHandle(), getHandle());
+ }
}
//---------------------------------------------------------------------------
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java
index bc3e5b793..fb11f8bba 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java
@@ -49,7 +49,7 @@ import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.ProxySurface;
-import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook;
+import javax.media.nativewindow.UpstreamSurfaceHook;
import javax.media.nativewindow.VisualIDHolder;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesChooser;
@@ -59,6 +59,8 @@ import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
+import jogamp.nativewindow.WrappedSurface;
+import jogamp.nativewindow.x11.X11DummyUpstreamSurfaceHook;
import jogamp.nativewindow.x11.X11Lib;
import jogamp.nativewindow.x11.X11Util;
import jogamp.opengl.DesktopGLDynamicLookupHelper;
@@ -70,7 +72,6 @@ import jogamp.opengl.GLGraphicsConfigurationUtil;
import jogamp.opengl.SharedResourceRunner;
import com.jogamp.common.util.VersionNumber;
-import com.jogamp.nativewindow.WrappedSurface;
import com.jogamp.nativewindow.x11.X11GraphicsDevice;
import com.jogamp.nativewindow.x11.X11GraphicsScreen;
@@ -505,7 +506,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl {
protected final ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice,
GLCapabilitiesImmutable capsChosen,
GLCapabilitiesImmutable capsRequested,
- GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook) {
+ GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) {
final X11GraphicsDevice device;
if(createNewDevice) {
// Null X11 locking, due to private non-shared Display handle
@@ -518,65 +519,15 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl {
if(null == config) {
throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen);
}
- return new WrappedSurface( config, 0, width, height, lifecycleHook);
+ return new WrappedSurface(config, 0, upstreamHook, createNewDevice);
}
@Override
public final ProxySurface createDummySurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice,
GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height) {
final GLCapabilitiesImmutable chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(requestedCaps);
- return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, width, height, dummySurfaceLifecycleHook);
+ return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, new X11DummyUpstreamSurfaceHook(width, height));
}
- private static final ProxySurface.UpstreamSurfaceHook dummySurfaceLifecycleHook = new ProxySurface.UpstreamSurfaceHook() {
- @Override
- public final void create(ProxySurface s) {
- if( 0 == s.getSurfaceHandle() ) {
- final X11GLXGraphicsConfiguration cfg = (X11GLXGraphicsConfiguration) s.getGraphicsConfiguration();
- final X11GraphicsScreen screen = (X11GraphicsScreen) cfg.getScreen();
- final X11GraphicsDevice device = (X11GraphicsDevice) screen.getDevice();
- if(0 == device.getHandle()) {
- device.open();
- s.setImplBitfield(ProxySurface.OWN_DEVICE);
- }
- final long windowHandle = X11Lib.CreateDummyWindow(device.getHandle(), screen.getIndex(), cfg.getXVisualID(), s.getWidth(), s.getHeight());
- if(0 == windowHandle) {
- throw new GLException("Creating dummy window failed w/ "+cfg+", "+s.getWidth()+"x"+s.getHeight());
- }
- s.setSurfaceHandle(windowHandle);
- if(DEBUG) {
- System.err.println("X11GLXDrawableFactory.dummySurfaceLifecycleHook.create: "+s);
- }
- }
- }
- @Override
- public final void destroy(ProxySurface s) {
- if(0 != s.getSurfaceHandle()) {
- final X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) s.getGraphicsConfiguration();
- final X11GraphicsDevice device = (X11GraphicsDevice) config.getScreen().getDevice();
- X11Lib.DestroyDummyWindow(device.getHandle(), s.getSurfaceHandle());
- s.setSurfaceHandle(0);
- if( 0 != ( ProxySurface.OWN_DEVICE & s.getImplBitfield() ) ) {
- device.close();
- }
- if(DEBUG) {
- System.err.println("X11GLXDrawableFactory.dummySurfaceLifecycleHook.destroy: "+s);
- }
- }
- }
- @Override
- public final int getWidth(ProxySurface s) {
- return s.initialWidth;
- }
- @Override
- public final int getHeight(ProxySurface s) {
- return s.initialHeight;
- }
- @Override
- public String toString() {
- return "X11SurfaceLifecycleHook[]";
- }
- };
-
@Override
protected final ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream) {
@@ -593,7 +544,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl {
if(DEBUG) {
System.err.println("X11GLXDrawableFactory.createProxySurfaceImpl 0x"+Long.toHexString(windowHandle)+": "+cfg);
}
- return new WrappedSurface(cfg, windowHandle, 0, 0, upstream);
+ return new WrappedSurface(cfg, windowHandle, upstream, true);
}
@Override
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java
index 866fcbbe4..96c3c4123 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java
@@ -307,7 +307,7 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem
return null; // no RGBA -> color index not supported
}
- X11GLCapabilities res = new X11GLCapabilities(visualInfo, fbcfg, fbcfgid, glp);
+ final X11GLCapabilities res = new X11GLCapabilities(visualInfo, fbcfg, fbcfgid, glp);
if (isMultisampleAvailable) {
res.setSampleBuffers(glXGetFBConfig(display, fbcfg, GLX.GLX_SAMPLE_BUFFERS, tmp, 0) != 0);
res.setNumSamples (glXGetFBConfig(display, fbcfg, GLX.GLX_SAMPLES, tmp, 0));
@@ -342,7 +342,7 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem
res.setPbufferFloatingPointBuffers(glXGetFBConfig(display, fbcfg, GLXExt.GLX_FLOAT_COMPONENTS_NV, tmp, 0) != GL.GL_FALSE);
} catch (Exception e) {}
- return (X11GLCapabilities) GLGraphicsConfigurationUtil.setWinAttributeBits(res, drawableTypeBits);
+ return (X11GLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, res);
}
private static String glXGetFBConfigErrorCode(int err) {
@@ -462,7 +462,7 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem
res.setAccumBlueBits (glXGetConfig(display, info, GLX.GLX_ACCUM_BLUE_SIZE, tmp, 0));
res.setAccumAlphaBits(glXGetConfig(display, info, GLX.GLX_ACCUM_ALPHA_SIZE, tmp, 0));
- return (X11GLCapabilities) GLGraphicsConfigurationUtil.setWinAttributeBits(res, drawableTypeBits);
+ return (X11GLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, res);
}
private static String glXGetConfigErrorCode(int err) {
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java
index 8086cd26a..431706e24 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java
@@ -129,9 +129,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF
}
final X11GraphicsScreen sharedScreen = (X11GraphicsScreen) sharedResource.getScreen();
final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(sharedScreen.getDevice());
- final X11GLXDrawable sharedDrawable = (X11GLXDrawable) sharedResource.getDrawable();
- final GLCapabilitiesImmutable capsChosen = sharedDrawable.getChosenGLCapabilities();
- final GLProfile glp = capsChosen.getGLProfile();
+ final GLProfile glp = GLProfile.getDefault(device);
List availableCaps = null;
@@ -217,7 +215,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF
X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory();
capsChosen = GLGraphicsConfigurationUtil.fixGLCapabilities( capsChosen, GLContext.isFBOAvailable(x11Device, capsChosen.getGLProfile()), factory.canCreateGLPbuffer(x11Device) );
- boolean usePBuffer = capsChosen.isPBuffer();
+ boolean usePBuffer = !capsChosen.isOnscreen() && capsChosen.isPBuffer();
X11GLXGraphicsConfiguration res = null;
if( factory.isGLXVersionGreaterEqualOneThree(x11Device) ) {
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java
index e1fe2f27e..bba2b3513 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java
@@ -81,10 +81,11 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable {
}
private void createPbuffer() {
- X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) getNativeSurface().getGraphicsConfiguration();
- AbstractGraphicsScreen aScreen = config.getScreen();
- AbstractGraphicsDevice aDevice = aScreen.getDevice();
- long display = aDevice.getHandle();
+ final MutableSurface ms = (MutableSurface) getNativeSurface();
+ final X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) ms.getGraphicsConfiguration();
+ final AbstractGraphicsScreen aScreen = config.getScreen();
+ final AbstractGraphicsDevice aDevice = aScreen.getDevice();
+ final long display = aDevice.getHandle();
if (DEBUG) {
System.out.println("Pbuffer config: " + config);
@@ -94,8 +95,6 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable {
throw new GLException("Null display");
}
- NativeSurface ns = getNativeSurface();
-
GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities();
if (chosenCaps.getPbufferRenderToTexture()) {
@@ -111,9 +110,9 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable {
int[] iattributes = new int[7];
iattributes[niattribs++] = GLX.GLX_PBUFFER_WIDTH;
- iattributes[niattribs++] = ns.getWidth();
+ iattributes[niattribs++] = ms.getWidth();
iattributes[niattribs++] = GLX.GLX_PBUFFER_HEIGHT;
- iattributes[niattribs++] = ns.getHeight();
+ iattributes[niattribs++] = ms.getHeight();
iattributes[niattribs++] = GLX.GLX_LARGEST_PBUFFER; // exact
iattributes[niattribs++] = 0;
iattributes[niattribs++] = 0;
@@ -125,7 +124,7 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable {
}
// Set up instance variables
- ((MutableSurface)ns).setSurfaceHandle(pbuffer);
+ ms.setSurfaceHandle(pbuffer);
if (DEBUG) {
System.err.println("Created pbuffer " + this);
diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m
new file mode 100644
index 000000000..63323b76d
--- /dev/null
+++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m
@@ -0,0 +1,665 @@
+#import "MacOSXWindowSystemInterface.h"
+#import
+#import
+#include "timespec.h"
+
+//
+// CADisplayLink only available on iOS >= 3.1, sad, since it's convenient.
+// Use CVDisplayLink otherwise.
+//
+// #define HAS_CADisplayLink 1
+//
+
+// lock/sync debug output
+//
+// #define DBG_SYNC 1
+//
+#ifdef DBG_SYNC
+ // #define SYNC_PRINT(...) NSLog(@ ## __VA_ARGS__)
+ #define SYNC_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr)
+#else
+ #define SYNC_PRINT(...)
+#endif
+
+// fps debug output
+//
+// #define DBG_PERF 1
+
+@interface MyNSOpenGLLayer: NSOpenGLLayer
+{
+@private
+ GLfloat gl_texCoords[8];
+
+@protected
+ NSOpenGLContext* parentCtx;
+ NSOpenGLPixelFormat* parentPixelFmt;
+ volatile NSOpenGLPixelBuffer* pbuffer;
+ volatile GLuint textureID;
+ volatile int texWidth;
+ volatile int texHeight;
+#ifdef HAS_CADisplayLink
+ CADisplayLink* displayLink;
+#else
+ CVDisplayLinkRef displayLink;
+#endif
+ int tc;
+ struct timespec tStart;
+@public
+ struct timespec lastWaitTime;
+ GLint swapInterval;
+ GLint swapIntervalCounter;
+ pthread_mutex_t renderLock;
+ pthread_cond_t renderSignal;
+ volatile Bool shallDraw;
+ volatile int newTexWidth;
+ volatile int newTexHeight;
+}
+
+- (id) setupWithContext: (NSOpenGLContext*) parentCtx
+ pixelFormat: (NSOpenGLPixelFormat*) pfmt
+ pbuffer: (NSOpenGLPixelBuffer*) p
+ texIDArg: (GLuint) texID
+ opaque: (Bool) opaque
+ texWidth: (int) texWidth
+ texHeight: (int) texHeight;
+
+- (Bool) validateTexSizeWithNewSize;
+- (Bool) validateTexSize: (int) _texWidth texHeight: (int) _texHeight;
+- (void) setTextureID: (int) _texID;
+
+- (void) validatePBuffer: (NSOpenGLPixelBuffer*) p;
+
+- (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat;
+- (void)disableAnimation;
+- (void)pauseAnimation:(Bool)pause;
+- (void)deallocPBuffer;
+- (void)releaseLayer;
+- (void)dealloc;
+- (void)setSwapInterval:(int)interval;
+- (void)tick;
+- (void)waitUntilRenderSignal: (long) to_micros;
+- (Bool)isGLSourceValid;
+
+@end
+
+#ifndef HAS_CADisplayLink
+
+static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink,
+ const CVTimeStamp *inNow,
+ const CVTimeStamp *inOutputTime,
+ CVOptionFlags flagsIn,
+ CVOptionFlags *flagsOut,
+ void *displayLinkContext)
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ MyNSOpenGLLayer* l = (MyNSOpenGLLayer*)displayLinkContext;
+ pthread_mutex_lock(&l->renderLock);
+ if( 0 < l->swapInterval ) {
+ l->swapIntervalCounter++;
+ if( l->swapIntervalCounter >= l->swapInterval ) {
+ SYNC_PRINT("", (int)l->swapIntervalCounter, l->swapInterval);
+ l->swapIntervalCounter = 0;
+ pthread_cond_signal(&l->renderSignal); // wake up vsync
+ }
+ }
+ pthread_mutex_unlock(&l->renderLock);
+ [pool release];
+ return kCVReturnSuccess;
+}
+
+#endif
+
+static const GLfloat gl_verts[] = {
+ -1.0, -1.0,
+ -1.0, 1.0,
+ 1.0, 1.0,
+ 1.0, -1.0
+};
+
+@implementation MyNSOpenGLLayer
+
+- (id) setupWithContext: (NSOpenGLContext*) _parentCtx
+ pixelFormat: (NSOpenGLPixelFormat*) _parentPixelFmt
+ pbuffer: (NSOpenGLPixelBuffer*) p
+ texIDArg: (GLuint) texID
+ opaque: (Bool) opaque
+ texWidth: (int) _texWidth
+ texHeight: (int) _texHeight;
+{
+ pthread_mutexattr_t renderLockAttr;
+ pthread_mutexattr_init(&renderLockAttr);
+ pthread_mutexattr_settype(&renderLockAttr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&renderLock, &renderLockAttr); // recursive
+ pthread_cond_init(&renderSignal, NULL); // no attribute
+
+ {
+ int i;
+ for(i=0; i<8; i++) {
+ gl_texCoords[i] = 0.0f;
+ }
+ }
+ parentCtx = _parentCtx;
+ parentPixelFmt = _parentPixelFmt;
+ swapInterval = 1; // defaults to on (as w/ new GL profiles)
+ swapIntervalCounter = 0;
+ timespec_now(&lastWaitTime);
+ shallDraw = NO;
+ newTexWidth = _texWidth;
+ newTexHeight = _texHeight;
+ [self validateTexSizeWithNewSize];
+ [self setTextureID: texID];
+
+ pbuffer = p;
+ if(NULL != pbuffer) {
+ [pbuffer retain];
+ }
+
+ {
+ // no animations for add/remove/swap sublayers etc
+ // doesn't work: [self removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition]
+ [self removeAllAnimations];
+ }
+
+ // instantiate a deactivated displayLink
+#ifdef HAS_CADisplayLink
+ displayLink = [[CVDisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)] retain];
+#else
+ CVReturn cvres;
+ {
+ int allDisplaysMask = 0;
+ int virtualScreen, accelerated, displayMask;
+ for (virtualScreen = 0; virtualScreen < [parentPixelFmt numberOfVirtualScreens]; virtualScreen++) {
+ [parentPixelFmt getValues:&displayMask forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:virtualScreen];
+ [parentPixelFmt getValues:&accelerated forAttribute:NSOpenGLPFAAccelerated forVirtualScreen:virtualScreen];
+ if (accelerated) {
+ allDisplaysMask |= displayMask;
+ }
+ }
+ cvres = CVDisplayLinkCreateWithOpenGLDisplayMask(allDisplaysMask, &displayLink);
+ if(kCVReturnSuccess != cvres) {
+ DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkCreateWithOpenGLDisplayMask %X failed: %d\n", self, allDisplaysMask, cvres);
+ displayLink = NULL;
+ }
+ }
+ if(NULL != displayLink) {
+ cvres = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [parentCtx CGLContextObj], [parentPixelFmt CGLPixelFormatObj]);
+ if(kCVReturnSuccess != cvres) {
+ DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: %d\n", self, cvres);
+ displayLink = NULL;
+ }
+ }
+ if(NULL != displayLink) {
+ cvres = CVDisplayLinkSetOutputCallback(displayLink, renderMyNSOpenGLLayer, self);
+ if(kCVReturnSuccess != cvres) {
+ DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetOutputCallback failed: %d\n", self, cvres);
+ displayLink = NULL;
+ }
+ }
+#endif
+ [self pauseAnimation: YES];
+
+ [self removeAllAnimations];
+ [self setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
+ [self setNeedsDisplayOnBoundsChange: YES];
+
+ [self setOpaque: opaque ? YES : NO];
+
+ if(NULL != pbuffer) {
+ DBG_PRINT("MyNSOpenGLLayer::init (pbuffer) %p, ctx %p, pfmt %p, pbuffer %p, opaque %d, pbuffer %dx%d -> tex %dx%d, bounds: %lf/%lf %lfx%lf (refcnt %d)\n",
+ self, parentCtx, parentPixelFmt, pbuffer, opaque, [pbuffer pixelsWide], [pbuffer pixelsHigh], texWidth, texHeight,
+ lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, (int)[self retainCount]);
+ } else {
+ DBG_PRINT("MyNSOpenGLLayer::init (texture) %p, ctx %p, pfmt %p, opaque %d, tex[id %d, %dx%d], bounds: %lf/%lf %lfx%lf (refcnt %d)\n",
+ self, parentCtx, parentPixelFmt, opaque, (int)textureID, texWidth, texHeight,
+ lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, (int)[self retainCount]);
+ }
+ return self;
+}
+
+- (Bool) validateTexSizeWithNewSize
+{
+ return [self validateTexSize: newTexWidth texHeight: newTexHeight];
+}
+
+- (Bool) validateTexSize: (int) _texWidth texHeight: (int) _texHeight
+{
+ if(_texHeight != texHeight || _texWidth != texWidth) {
+ texWidth = _texWidth;
+ texHeight = _texHeight;
+ CGRect lRect = [self bounds];
+ lRect.origin.x = 0;
+ lRect.origin.y = 0;
+ lRect.size.width = texWidth;
+ lRect.size.height = texHeight;
+ [self setFrame: lRect];
+
+ GLfloat texCoordWidth, texCoordHeight;
+ if(NULL != pbuffer) {
+ GLenum textureTarget = [pbuffer textureTarget] ;
+ GLsizei pwidth = [pbuffer pixelsWide];
+ GLsizei pheight = [pbuffer pixelsHigh];
+ if( GL_TEXTURE_2D == textureTarget ) {
+ texCoordWidth = (GLfloat)pwidth /(GLfloat)texWidth ;
+ texCoordHeight = (GLfloat)pheight/(GLfloat)texHeight ;
+ } else {
+ texCoordWidth = pwidth;
+ texCoordHeight = pheight;
+ }
+ } else {
+ texCoordWidth = (GLfloat)1.0f;
+ texCoordHeight = (GLfloat)1.0f;
+ }
+ gl_texCoords[3] = texCoordHeight;
+ gl_texCoords[5] = texCoordHeight;
+ gl_texCoords[4] = texCoordWidth;
+ gl_texCoords[6] = texCoordWidth;
+ return YES;
+ } else {
+ return NO;
+ }
+}
+
+- (void) setTextureID: (int) _texID
+{
+ textureID = _texID;
+}
+
+- (void) validatePBuffer: (NSOpenGLPixelBuffer*) p
+{
+ if( pbuffer != p ) {
+ DBG_PRINT("MyNSOpenGLLayer::validatePBuffer.0 %p, pbuffer %p, (refcnt %d)\n", self, p, (int)[self retainCount]);
+
+ SYNC_PRINT("{PB-nil}");
+
+ [self deallocPBuffer];
+
+ pbuffer = p;
+ if(NULL != pbuffer) {
+ [pbuffer retain];
+ }
+ [self setTextureID: 0];
+
+ shallDraw = NO;
+ }
+}
+
+/**
+- (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask
+{
+ DBG_PRINT("MyNSOpenGLLayer::openGLPixelFormatForDisplayMask: %p (refcnt %d) - parent-pfmt %p -> new-pfmt %p\n",
+ self, (int)[self retainCount], parentPixelFmt, parentPixelFmt);
+ return parentPixelFmt;
+} */
+
+- (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat
+{
+ NSOpenGLContext * nctx = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:parentCtx];
+ DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat: %p (refcnt %d) - pfmt %p, parent %p -> new-ctx %p\n",
+ self, (int)[self retainCount], pixelFormat, parentCtx, nctx);
+ return nctx;
+}
+
+- (void)disableAnimation
+{
+ DBG_PRINT("MyNSOpenGLLayer::disableAnimation: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink);
+ pthread_mutex_lock(&renderLock);
+ [self setAsynchronous: NO];
+ if(NULL != displayLink) {
+#ifdef HAS_CADisplayLink
+ [displayLink setPaused: YES];
+ [displayLink release];
+#else
+ CVDisplayLinkStop(displayLink);
+ CVDisplayLinkRelease(displayLink);
+#endif
+ displayLink = NULL;
+ }
+ pthread_mutex_unlock(&renderLock);
+}
+
+- (void)deallocPBuffer
+{
+ if(NULL != pbuffer) {
+ NSOpenGLContext* context = [self openGLContext];
+ if(NULL!=context) {
+ [context makeCurrentContext];
+
+ DBG_PRINT("MyNSOpenGLLayer::deallocPBuffer (with ctx) %p (refcnt %d) - context %p, pbuffer %p, texID %d\n", self, (int)[self retainCount], context, pbuffer, (int)texureID);
+
+ if( 0 != textureID ) {
+ glDeleteTextures(1, &textureID);
+ }
+ [pbuffer release];
+
+ [context clearDrawable];
+ } else {
+ DBG_PRINT("MyNSOpenGLLayer::deallocPBuffer (w/o ctx) %p (refcnt %d) - context %p, pbuffer %p, texID %d\n", self, (int)[self retainCount], context, pbuffer, (int)texureID);
+ }
+ pbuffer = NULL;
+ [self setTextureID: 0];
+ }
+}
+
+- (void)releaseLayer
+{
+ DBG_PRINT("MyNSOpenGLLayer::releaseLayer.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
+ pthread_mutex_lock(&renderLock);
+ [self disableAnimation];
+ [self deallocPBuffer];
+ [self release];
+ DBG_PRINT("MyNSOpenGLLayer::releaseLayer.X: %p (refcnt %d)\n", self, (int)[self retainCount]);
+ pthread_mutex_unlock(&renderLock);
+}
+
+- (void)dealloc
+{
+ DBG_PRINT("MyNSOpenGLLayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]);
+ // NSLog(@"MyNSOpenGLLayer::dealloc: %@",[NSThread callStackSymbols]);
+
+ pthread_mutex_lock(&renderLock);
+ [self disableAnimation];
+ [self deallocPBuffer];
+ pthread_mutex_unlock(&renderLock);
+ pthread_cond_destroy(&renderSignal);
+ pthread_mutex_destroy(&renderLock);
+ [super dealloc];
+ DBG_PRINT("MyNSOpenGLLayer::dealloc.X %p\n", self);
+}
+
+- (Bool)isGLSourceValid
+{
+ return NULL != pbuffer || 0 != textureID ;
+}
+
+- (void)resizeWithOldSuperlayerSize:(CGSize)size
+ {
+ CGRect lRectS = [[self superlayer] bounds];
+
+ DBG_PRINT("MyNSOpenGLLayer::resizeWithOldSuperlayerSize: %p, texSize %dx%d, bounds: %lfx%lf -> %lfx%lf (refcnt %d)\n",
+ self, texWidth, texHeight, size.width, size.height, lRectS.size.width, lRectS.size.height, (int)[self retainCount]);
+
+ newTexWidth = lRectS.size.width;
+ newTexHeight = lRectS.size.height;
+ shallDraw = YES;
+ SYNC_PRINT("", newTexWidth, newTexHeight);
+
+ [super resizeWithOldSuperlayerSize: size];
+}
+
+- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat
+ forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
+{
+ SYNC_PRINT(" %d>", (int)shallDraw);
+ return shallDraw;
+}
+
+- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat
+ forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
+{
+ pthread_mutex_unlock(&renderLock);
+ SYNC_PRINT("<* ");
+ // NSLog(@"MyNSOpenGLLayer::DRAW: %@",[NSThread callStackSymbols]);
+
+ if( shallDraw && ( NULL != pbuffer || 0 != textureID ) ) {
+ [context makeCurrentContext];
+
+ GLenum textureTarget;
+
+ Bool texSizeChanged = [self validateTexSizeWithNewSize];
+
+ if( NULL != pbuffer ) {
+ if( texSizeChanged && 0 != textureID ) {
+ glDeleteTextures(1, &textureID);
+ [self setTextureID: 0];
+ }
+ textureTarget = [pbuffer textureTarget];
+ if( 0 == textureID ) {
+ glGenTextures(1, &textureID);
+ glBindTexture(textureTarget, textureID);
+ glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ } else {
+ glBindTexture(textureTarget, textureID);
+ }
+ [context setTextureImageToPixelBuffer: pbuffer colorBuffer: GL_FRONT];
+ } else {
+ textureTarget = GL_TEXTURE_2D;
+ glBindTexture(textureTarget, textureID);
+ }
+ SYNC_PRINT(" %d*>", (int)textureID);
+
+ glEnable(textureTarget);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, gl_verts);
+ glTexCoordPointer(2, GL_FLOAT, 0, gl_texCoords);
+
+ glDrawArrays(GL_QUADS, 0, 4);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glDisable(textureTarget);
+ glBindTexture(textureTarget, 0);
+
+ [context clearDrawable];
+
+ [super drawInOpenGLContext: context pixelFormat: pixelFormat forLayerTime: timeInterval displayTime: timeStamp];
+
+ } else {
+ // glClear(GL_COLOR_BUFFER_BIT);
+ // glBlitFramebuffer(0, 0, texWidth, texHeight,
+ // 0, 0, texWidth, texHeight,
+ // GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ SYNC_PRINT(" 0*>");
+ }
+
+ #ifdef DBG_PERF
+ [self tick];
+ #endif
+ shallDraw = NO;
+
+ if( 0 >= swapInterval ) {
+ pthread_cond_signal(&renderSignal); // wake up !vsync
+ SYNC_PRINT("");
+ }
+ SYNC_PRINT("<$>\n");
+ pthread_mutex_unlock(&renderLock);
+}
+
+- (void)pauseAnimation:(Bool)pause
+{
+ DBG_PRINT("MyNSOpenGLLayer::pauseAnimation: %d\n", (int)pause);
+ [self setAsynchronous: NO];
+ if(pause) {
+ if(NULL != displayLink) {
+ #ifdef HAS_CADisplayLink
+ [displayLink setPaused: YES];
+ #else
+ CVDisplayLinkStop(displayLink);
+ #endif
+ }
+ } else {
+ if(NULL != displayLink) {
+ #ifdef HAS_CADisplayLink
+ [displayLink setPaused: NO];
+ [displayLink setFrameInterval: swapInterval];
+ #else
+ CVDisplayLinkStart(displayLink);
+ #endif
+ }
+ }
+ tc = 0;
+ timespec_now(&tStart);
+}
+
+- (void)setSwapInterval:(int)interval
+{
+ /**
+ * v-sync doesn't works w/ NSOpenGLLayer's context .. well :(
+ * Using CVDisplayLink .. see setSwapInterval() below.
+ *
+ GLint si;
+ [context getValues: &si forParameter: NSOpenGLCPSwapInterval];
+ if(si != swapInterval) {
+ DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p setSwapInterval: %d -> %d\n", self, si, swapInterval);
+ [context setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval];
+ }
+ */
+
+ pthread_mutex_lock(&renderLock);
+ DBG_PRINT("MyNSOpenGLLayer::setSwapInterval.0: %d - displayLink %p\n", interval, displayLink);
+ swapInterval = interval;
+ swapIntervalCounter = 0;
+ pthread_mutex_unlock(&renderLock);
+
+ if(0 < swapInterval) {
+ [self pauseAnimation: NO];
+ } else {
+ [self pauseAnimation: YES];
+ }
+ DBG_PRINT("MyNSOpenGLLayer::setSwapInterval.X: %d\n", interval);
+}
+
+-(void)tick
+{
+ tc++;
+ if(tc%60==0) {
+ struct timespec t1, td;
+ timespec_now(&t1);
+ timespec_subtract(&td, &t1, &tStart);
+ long td_ms = timespec_milliseconds(&td);
+ fprintf(stderr, "NSOpenGLLayer: %ld ms / %d frames, %ld ms / frame, %f fps\n",
+ td_ms, tc, td_ms/tc, (tc * 1000.0) / (float)td_ms );
+ fflush(NULL);
+ }
+}
+
+- (void)waitUntilRenderSignal: (long) to_micros
+{
+ BOOL ready = NO;
+ int wr = 0;
+ pthread_mutex_lock(&renderLock);
+ SYNC_PRINT("{W %ld us", to_micros);
+ do {
+ if(0 >= swapInterval) {
+ ready = YES;
+ }
+ if(NO == ready) {
+ #ifdef DBG_SYNC
+ struct timespec t0, t1, td, td2;
+ timespec_now(&t0);
+ #endif
+ if(0 < to_micros) {
+ struct timespec to_abs = lastWaitTime;
+ timespec_addmicros(&to_abs, to_micros);
+ #ifdef DBG_SYNC
+ timespec_subtract(&td, &to_abs, &t0);
+ fprintf(stderr, ", (%ld) / ", timespec_milliseconds(&td));
+ #endif
+ wr = pthread_cond_timedwait(&renderSignal, &renderLock, &to_abs);
+ #ifdef DBG_SYNC
+ timespec_now(&t1);
+ timespec_subtract(&td, &t1, &t0);
+ timespec_subtract(&td2, &t1, &lastWaitTime);
+ fprintf(stderr, "(%ld) / (%ld) ms", timespec_milliseconds(&td), timespec_milliseconds(&td2));
+ #endif
+ } else {
+ pthread_cond_wait (&renderSignal, &renderLock);
+ #ifdef DBG_SYNC
+ timespec_now(&t1);
+ timespec_subtract(&td, &t1, &t0);
+ timespec_subtract(&td2, &t1, &lastWaitTime);
+ fprintf(stderr, "(%ld) / (%ld) ms", timespec_milliseconds(&td), timespec_milliseconds(&td2));
+ #endif
+ }
+ ready = YES;
+ }
+ } while (NO == ready && 0 == wr) ;
+ SYNC_PRINT("-%d-%d-%d}", shallDraw, wr, ready);
+ timespec_now(&lastWaitTime);
+ pthread_mutex_unlock(&renderLock);
+}
+
+@end
+
+NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* p, uint32_t texID, Bool opaque, int texWidth, int texHeight) {
+ // This simply crashes after dealloc() has been called .. ie. ref-count -> 0 too early ?
+ // However using alloc/init, actual dealloc happens at JAWT destruction, hence too later IMHO.
+ // return [[MyNSOpenGLLayer layer] setupWithContext:ctx pixelFormat: fmt pbuffer: p texIDArg: (GLuint)texID
+ // opaque: opaque texWidth: texWidth texHeight: texHeight];
+
+ return [[[MyNSOpenGLLayer alloc] init] setupWithContext:ctx pixelFormat: fmt pbuffer: p texIDArg: (GLuint)texID
+ opaque: opaque texWidth: texWidth texHeight: texHeight];
+}
+
+void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval) {
+ MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ [l setSwapInterval: interval];
+ [pool release];
+}
+
+void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_micros) {
+ MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ [l waitUntilRenderSignal: to_micros];
+ [pool release];
+}
+
+void flushNSOpenGLLayerPBuffer(NSOpenGLLayer* layer) {
+ MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ pthread_mutex_lock(&l->renderLock);
+ [l validatePBuffer:0];
+ pthread_mutex_unlock(&l->renderLock);
+
+ [pool release];
+}
+
+void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* layer, NSOpenGLPixelBuffer* p, uint32_t texID, int texWidth, int texHeight) {
+ MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ Bool shallDraw;
+
+ pthread_mutex_lock(&l->renderLock);
+ [l validatePBuffer:p];
+ // l->newTexWidth = texWidth;
+ // l->newTexHeight = texHeight;
+ [l setTextureID: texID];
+ shallDraw = [l isGLSourceValid];
+ l->shallDraw = shallDraw;
+ pthread_mutex_unlock(&l->renderLock);
+
+ SYNC_PRINT("", texWidth, texHeight, l->newTexWidth, l->newTexHeight, (int)shallDraw);
+ if(shallDraw) {
+ if ( [NSThread isMainThread] == YES ) {
+ [l setNeedsDisplay];
+ } else {
+ // don't wait - using doublebuffering
+ [l performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
+ }
+ }
+ // DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l);
+ [pool release];
+}
+
+void releaseNSOpenGLLayer(NSOpenGLLayer* layer) {
+ MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.0: %p\n", l);
+
+ if ( [NSThread isMainThread] == YES ) {
+ [l releaseLayer];
+ } else {
+ [l performSelectorOnMainThread:@selector(releaseLayer) withObject:nil waitUntilDone:NO];
+ }
+
+ DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.X: %p\n", l);
+ [pool release];
+}
+
diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m
deleted file mode 100644
index b81b43e54..000000000
--- a/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m
+++ /dev/null
@@ -1,494 +0,0 @@
-#import "MacOSXWindowSystemInterface.h"
-#import
-#import
-#include "timespec.h"
-
-//
-// CADisplayLink only available on iOS >= 3.1, sad, since it's convenient.
-// Use CVDisplayLink otherwise.
-//
-// #define HAS_CADisplayLink 1
-//
-
-// lock/sync debug output
-//
-// #define DBG_SYNC 1
-//
-#ifdef DBG_SYNC
- // #define SYNC_PRINT(...) NSLog(@ ## __VA_ARGS__)
- #define SYNC_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr)
-#else
- #define SYNC_PRINT(...)
-#endif
-
-// fps debug output
-//
-// #define DBG_PERF 1
-
-@interface MyNSOpenGLLayer: NSOpenGLLayer
-{
-@protected
- NSOpenGLPixelBuffer* pbuffer;
- int texWidth;
- int texHeight;
- GLuint textureID;
-#ifdef HAS_CADisplayLink
- CADisplayLink* displayLink;
-#else
- CVDisplayLinkRef displayLink;
-#endif
- int tc;
- struct timespec t0;
-@public
- struct timespec lastWaitTime;
- GLint swapInterval;
- GLint swapIntervalCounter;
- pthread_mutex_t renderLock;
- pthread_cond_t renderSignal;
- BOOL shallDraw;
-}
-
-- (id) setupWithContext: (NSOpenGLContext*) ctx
- pixelFormat: (NSOpenGLPixelFormat*) pfmt
- pbuffer: (NSOpenGLPixelBuffer*) p
- opaque: (Bool) opaque
- texWidth: (int) texWidth
- texHeight: (int) texHeight;
-
-- (void)deallocTex;
-- (void)disableAnimation;
-- (void)releaseLayer;
-- (void)dealloc;
-- (int)getSwapInterval;
-- (void)setSwapInterval:(int)interval;
-- (void)tick;
-
-@end
-
-#ifndef HAS_CADisplayLink
-
-static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink,
- const CVTimeStamp *inNow,
- const CVTimeStamp *inOutputTime,
- CVOptionFlags flagsIn,
- CVOptionFlags *flagsOut,
- void *displayLinkContext)
-{
- NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
- MyNSOpenGLLayer* l = (MyNSOpenGLLayer*)displayLinkContext;
- pthread_mutex_lock(&l->renderLock);
- #ifdef DBG_PERF
- [l tick];
- #endif
- if(0 < l->swapInterval) {
- l->swapIntervalCounter++;
- if(l->swapIntervalCounter>=l->swapInterval) {
- l->swapIntervalCounter = 0;
- pthread_cond_signal(&l->renderSignal);
- SYNC_PRINT("S");
- }
- }
- pthread_mutex_unlock(&l->renderLock);
- [pool release];
- return kCVReturnSuccess;
-}
-
-#endif
-
-@implementation MyNSOpenGLLayer
-
-- (id) setupWithContext: (NSOpenGLContext*) _ctx
- pixelFormat: (NSOpenGLPixelFormat*) _fmt
- pbuffer: (NSOpenGLPixelBuffer*) p
- opaque: (Bool) opaque
- texWidth: (int) _texWidth
- texHeight: (int) _texHeight;
-{
- pthread_mutexattr_t renderLockAttr;
- pthread_mutexattr_init(&renderLockAttr);
- pthread_mutexattr_settype(&renderLockAttr, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&renderLock, &renderLockAttr); // recursive
- pthread_cond_init(&renderSignal, NULL); // no attribute
-
- textureID = 0;
- swapInterval = 1; // defaults to on (as w/ new GL profiles)
- swapIntervalCounter = 0;
- timespec_now(&lastWaitTime);
- shallDraw = NO;
- texWidth = _texWidth;
- texHeight = _texHeight;
- pbuffer = p;
- [pbuffer retain];
-
- {
- CGRect lRect = CGRectMake(0, 0, texWidth, texHeight);
- [self setFrame:lRect];
-
- // no animations for add/remove/swap sublayers etc
- // doesn't work: [self removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition]
- [self removeAllAnimations];
- }
-
- // instantiate a deactivated displayLink
-#ifdef HAS_CADisplayLink
- displayLink = [[CVDisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)] retain];
- [displayLink setPaused: YES];
-#else
- CVReturn cvres;
- {
- int allDisplaysMask = 0;
- int virtualScreen, accelerated, displayMask;
- for (virtualScreen = 0; virtualScreen < [_fmt numberOfVirtualScreens]; virtualScreen++) {
- [_fmt getValues:&displayMask forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:virtualScreen];
- [_fmt getValues:&accelerated forAttribute:NSOpenGLPFAAccelerated forVirtualScreen:virtualScreen];
- if (accelerated) {
- allDisplaysMask |= displayMask;
- }
- }
- cvres = CVDisplayLinkCreateWithOpenGLDisplayMask(allDisplaysMask, &displayLink);
- if(kCVReturnSuccess != cvres) {
- DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkCreateWithOpenGLDisplayMask %X failed: %d\n", self, allDisplaysMask, cvres);
- displayLink = NULL;
- }
- }
- if(NULL != displayLink) {
- cvres = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [_ctx CGLContextObj], [_fmt CGLPixelFormatObj]);
- if(kCVReturnSuccess != cvres) {
- DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: %d\n", self, cvres);
- displayLink = NULL;
- }
- }
- if(NULL != displayLink) {
- cvres = CVDisplayLinkSetOutputCallback(displayLink, renderMyNSOpenGLLayer, self);
- if(kCVReturnSuccess != cvres) {
- DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetOutputCallback failed: %d\n", self, cvres);
- displayLink = NULL;
- }
- }
- if(NULL != displayLink) {
- CVDisplayLinkStop(displayLink);
- }
-#endif
- [self setAsynchronous: YES];
-
- [self setNeedsDisplayOnBoundsChange: YES];
-
- [self setOpaque: opaque ? YES : NO];
-
- CGRect lRect = [self frame];
- DBG_PRINT("MyNSOpenGLLayer::init %p, ctx %p, pfmt %p, pbuffer %p, opaque %d, pbuffer %dx%d -> tex %dx%d, frame: %lf/%lf %lfx%lf (refcnt %d)\n",
- self, _ctx, _fmt, pbuffer, opaque, [pbuffer pixelsWide], [pbuffer pixelsHigh], texWidth, texHeight,
- lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, (int)[self retainCount]);
- return self;
-}
-
-- (void)disableAnimation
-{
- DBG_PRINT("MyNSOpenGLLayer::disableAnimation: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink);
- pthread_mutex_lock(&renderLock);
- [self setAsynchronous: NO];
- if(NULL != displayLink) {
-#ifdef HAS_CADisplayLink
- [displayLink setPaused: YES];
- [displayLink release];
-#else
- CVDisplayLinkStop(displayLink);
- CVDisplayLinkRelease(displayLink);
-#endif
- displayLink = NULL;
- }
- pthread_mutex_unlock(&renderLock);
-}
-
-- (void)deallocTex
-{
- pthread_mutex_lock(&renderLock);
- NSOpenGLContext* context = [self openGLContext];
- DBG_PRINT("MyNSOpenGLLayer::deallocTex %p (refcnt %d) - context %p, pbuffer %p\n", self, (int)[self retainCount], context, pbuffer);
- if(NULL != pbuffer) {
- if(NULL!=context) {
- [context makeCurrentContext];
- if(0 != textureID) {
- glDeleteTextures(1, &textureID);
- textureID = 0;
- }
- [context clearDrawable];
- }
- [pbuffer release];
- pbuffer = NULL;
- }
- pthread_mutex_unlock(&renderLock);
-}
-
-- (void)releaseLayer
-{
- DBG_PRINT("MyNSOpenGLLayer::releaseLayer.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
- pthread_mutex_lock(&renderLock);
- [self disableAnimation];
- [self deallocTex];
- [self release];
- DBG_PRINT("MyNSOpenGLLayer::releaseLayer.X: %p (refcnt %d)\n", self, (int)[self retainCount]);
- pthread_mutex_unlock(&renderLock);
-}
-
-- (void)dealloc
-{
- DBG_PRINT("MyNSOpenGLLayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]);
- // NSLog(@"MyNSOpenGLLayer::dealloc: %@",[NSThread callStackSymbols]);
-
- [self disableAnimation];
- [self deallocTex];
- pthread_cond_destroy(&renderSignal);
- pthread_mutex_destroy(&renderLock);
- [super dealloc];
- DBG_PRINT("MyNSOpenGLLayer::dealloc.X %p\n", self);
-}
-
-- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat
- forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
-{
- // assume both methods 'canDrawInOpenGLContext' and 'drawInOpenGLContext'
- // are called from the same thread subsequently
- pthread_mutex_lock(&renderLock);
- Bool res = NULL != pbuffer && YES == shallDraw;
- if(!res) {
- SYNC_PRINT("0");
- pthread_mutex_unlock(&renderLock);
- } else {
- SYNC_PRINT("1");
- }
- return res;
-}
-
-- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat
- forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
-{
- [context makeCurrentContext];
-
- GLenum textureTarget = [pbuffer textureTarget];
- GLfloat texCoordWidth, texCoordHeight;
- {
- GLsizei pwidth = [pbuffer pixelsWide];
- GLsizei pheight = [pbuffer pixelsHigh];
- texCoordWidth = textureTarget == GL_TEXTURE_2D ? (GLfloat)pwidth /(GLfloat)texWidth : pwidth;
- texCoordHeight = textureTarget == GL_TEXTURE_2D ? (GLfloat)pheight/(GLfloat)texHeight : pheight;
- }
- Bool texCreated = 0 == textureID;
-
- if(texCreated) {
- glGenTextures(1, &textureID);
-
- CGRect lRect = [self frame];
- DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p, pbuffer %p %dx%d -> tex %dx%d [%fx%f] id 0x%X target 0x%X, frame: %lf/%lf %lfx%lf (refcnt %d)\n",
- self, pbuffer, [pbuffer pixelsWide], [pbuffer pixelsHigh], texWidth, texHeight, texCoordWidth, texCoordHeight, textureID, textureTarget,
- lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, (int)[self retainCount]);
- }
-
- glBindTexture(textureTarget, textureID);
-
- /**
- if(texCreated) {
- // proper tex size setup
- glTexImage2D(textureTarget, 0, GL_RGB, texWidth, texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
- } */
-
- [context setTextureImageToPixelBuffer: pbuffer colorBuffer: GL_FRONT];
-
- glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glEnable(textureTarget);
-
- static GLfloat verts[] = {
- -1.0, -1.0,
- -1.0, 1.0,
- 1.0, 1.0,
- 1.0, -1.0
- };
-
- GLfloat tex[] = {
- 0.0, 0.0,
- 0.0, texCoordHeight,
- texCoordWidth, texCoordHeight,
- texCoordWidth, 0.0
- };
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, verts);
- glTexCoordPointer(2, GL_FLOAT, 0, tex);
-
- glDrawArrays(GL_QUADS, 0, 4);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
- glDisable(textureTarget);
- glBindTexture(textureTarget, 0);
-
- [super drawInOpenGLContext: context pixelFormat: pixelFormat forLayerTime: timeInterval displayTime: timeStamp];
- shallDraw = NO;
- if(0 >= swapInterval) {
- pthread_cond_signal(&renderSignal); // just to wake up
- SYNC_PRINT("s");
- }
- SYNC_PRINT("$");
- pthread_mutex_unlock(&renderLock);
-}
-
-- (int)getSwapInterval
-{
- return swapInterval;
-}
-
-- (void)setSwapInterval:(int)interval
-{
- /**
- * v-sync doesn't works w/ NSOpenGLLayer's context .. well :(
- * Using CVDisplayLink .. see setSwapInterval() below.
- *
- GLint si;
- [context getValues: &si forParameter: NSOpenGLCPSwapInterval];
- if(si != swapInterval) {
- DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p setSwapInterval: %d -> %d\n", self, si, swapInterval);
- [context setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval];
- }
- } */
-
- pthread_mutex_lock(&renderLock);
- DBG_PRINT("MyNSOpenGLLayer::setSwapInterval.0: %d - displayLink %p\n", interval, displayLink);
- swapInterval = interval;
- swapIntervalCounter = 0;
- pthread_mutex_unlock(&renderLock);
-
- if(NULL!=displayLink) {
- if(0 < swapInterval) {
- tc = 0;
- timespec_now(&t0);
-
- [self setAsynchronous: NO];
- #ifdef HAS_CADisplayLink
- [displayLink setPaused: NO];
- [displayLink setFrameInterval: interval];
- #else
- DBG_PRINT("MyNSOpenGLLayer::setSwapInterval.1.b.1\n");
- CVDisplayLinkStart(displayLink);
- DBG_PRINT("MyNSOpenGLLayer::setSwapInterval.1.b.X\n");
- #endif
- } else {
- #ifdef HAS_CADisplayLink
- [displayLink setPaused: YES];
- #else
- DBG_PRINT("MyNSOpenGLLayer::setSwapInterval.0.b.1\n");
- CVDisplayLinkStop(displayLink);
- DBG_PRINT("MyNSOpenGLLayer::setSwapInterval.0.b.X\n");
- #endif
- [self setAsynchronous: YES];
- }
- }
- DBG_PRINT("MyNSOpenGLLayer::setSwapInterval.X: %d\n", interval);
-}
-
--(void)tick
-{
- tc++;
- if(tc%60==0) {
- struct timespec t1, td;
- timespec_now(&t1);
- timespec_subtract(&td, &t1, &t0);
- long td_ms = timespec_milliseconds(&td);
- fprintf(stderr, "NSOpenGLLayer: %ld ms / %d frames, %ld ms / frame, %f fps\n",
- td_ms, tc, td_ms/tc, (tc * 1000.0) / (float)td_ms );
- fflush(NULL);
- }
-}
-
-@end
-
-NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* p, Bool opaque, int texWidth, int texHeight) {
- // This simply crashes after dealloc() has been called .. ie. ref-count -> 0 too early ?
- // However using alloc/init, actual dealloc happens at JAWT destruction, hence too later IMHO.
- // return [[MyNSOpenGLLayer layer] setupWithContext:ctx pixelFormat: fmt pbuffer: p opaque: opaque texWidth: texWidth texHeight: texHeight];
-
- return [[[MyNSOpenGLLayer alloc] init] setupWithContext:ctx pixelFormat: fmt pbuffer: p opaque: opaque texWidth: texWidth texHeight: texHeight];
-}
-
-void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval) {
- MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
- [l setSwapInterval: interval];
-}
-
-void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_micros) {
- MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
- BOOL ready = NO;
- int wr = 0;
- pthread_mutex_lock(&l->renderLock);
- SYNC_PRINT("{");
- do {
- if([l getSwapInterval] <= 0) {
- ready = !l->shallDraw;
- }
- if(NO == ready) {
- if(0 < to_micros) {
- #ifdef DBG_SYNC
- struct timespec t0, t1, td, td2;
- timespec_now(&t0);
- #endif
- struct timespec to_abs = l->lastWaitTime;
- timespec_addmicros(&to_abs, to_micros);
- #ifdef DBG_SYNC
- timespec_subtract(&td, &to_abs, &t0);
- fprintf(stderr, "(%ld) / ", timespec_milliseconds(&td));
- #endif
- wr = pthread_cond_timedwait(&l->renderSignal, &l->renderLock, &to_abs);
- #ifdef DBG_SYNC
- timespec_now(&t1);
- timespec_subtract(&td, &t1, &t0);
- timespec_subtract(&td2, &t1, &l->lastWaitTime);
- fprintf(stderr, "(%ld) / (%ld) ms", timespec_milliseconds(&td), timespec_milliseconds(&td2));
- #endif
- } else {
- pthread_cond_wait (&l->renderSignal, &l->renderLock);
- }
- ready = !l->shallDraw;
- }
- } while (NO == ready && 0 == wr) ;
- SYNC_PRINT("-%d}", ready);
- timespec_now(&l->lastWaitTime);
- pthread_mutex_unlock(&l->renderLock);
-}
-
-void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* layer) {
- MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
- NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
- pthread_mutex_lock(&l->renderLock);
- l->shallDraw = YES;
- if ( [NSThread isMainThread] == YES ) {
- [l setNeedsDisplay];
- } else {
- // can't wait, otherwise we may deadlock AWT
- [l performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
- }
- SYNC_PRINT(".");
- pthread_mutex_unlock(&l->renderLock);
- // DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l);
- [pool release];
-}
-
-void releaseNSOpenGLLayer(NSOpenGLLayer* layer) {
- MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
- NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
- DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.0: %p\n", l);
-
- if ( [NSThread isMainThread] == YES ) {
- [l releaseLayer];
- } else {
- [l performSelectorOnMainThread:@selector(releaseLayer) withObject:nil waitUntilDone:NO];
- }
-
- DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.X: %p\n", l);
- [pool release];
-}
-
diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m
index f774f8f4a..becd41bb2 100644
--- a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m
+++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m
@@ -696,6 +696,11 @@ void setContextTextureImageToPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer*
[pool release];
}
+Bool isNSOpenGLPixelBuffer(uint64_t object) {
+ NSObject *nsObj = (NSObject*) (intptr_t) object;
+ return [nsObj isMemberOfClass:[NSOpenGLPixelBuffer class]];
+}
+
#include
Bool imagesInitialized = false;
static char libGLStr[] = "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib";
@@ -746,38 +751,3 @@ void resetGammaRamp() {
CGDisplayRestoreColorSyncSettings();
}
-/***
- * The following static functions are copied out of NEWT's OSX impl.
- * May need to push code to NativeWindow, to remove duplication.
- */
-static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx) {
- NSArray *screens = [NSScreen screens];
- if(screen_idx<0) screen_idx=0;
- if(screen_idx>=[screens count]) screen_idx=0;
- return (NSScreen *) [screens objectAtIndex: screen_idx];
-}
-static CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) {
- // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?!
- NSDictionary * dict = [screen deviceDescription];
- NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"];
- // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size
- return (CGDirectDisplayID) [val integerValue];
-}
-static long GetDictionaryLong(CFDictionaryRef theDict, const void* key)
-{
- long value = 0;
- CFNumberRef numRef;
- numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
- if (numRef != NULL)
- CFNumberGetValue(numRef, kCFNumberLongType, &value);
- return value;
-}
-#define CGDDGetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate)
-
-int getScreenRefreshRate(int scrn_idx) {
- NSScreen *screen = NewtScreen_getNSScreenByIndex(scrn_idx);
- CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen);
- CFDictionaryRef mode = CGDisplayCurrentMode(display);
- return CGDDGetModeRefreshRate(mode);
-}
-
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java
new file mode 100644
index 000000000..22c95f3dd
--- /dev/null
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java
@@ -0,0 +1,39 @@
+package com.jogamp.nativewindow;
+
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+public class DelegatedUpstreamSurfaceHookMutableSize extends UpstreamSurfaceHookMutableSize {
+ final UpstreamSurfaceHook upstream;
+
+ /**
+ * @param upstream optional upstream UpstreamSurfaceHook used for {@link #create(ProxySurface)} and {@link #destroy(ProxySurface)}.
+ * @param width initial width
+ * @param height initial height
+ */
+ public DelegatedUpstreamSurfaceHookMutableSize(UpstreamSurfaceHook upstream, int width, int height) {
+ super(width, height);
+ this.upstream = upstream;
+ }
+
+ @Override
+ public final void create(ProxySurface s) {
+ if(null != upstream) {
+ upstream.create(s);
+ }
+ }
+
+ @Override
+ public final void destroy(ProxySurface s) {
+ if(null != upstream) {
+ upstream.destroy(s);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName()+"[ "+ width + "x" + height + ", " + upstream + "]";
+ }
+
+}
+
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java
new file mode 100644
index 000000000..85e24582c
--- /dev/null
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java
@@ -0,0 +1,54 @@
+package com.jogamp.nativewindow;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+public class DelegatedUpstreamSurfaceHookWithSurfaceSize implements UpstreamSurfaceHook {
+ final UpstreamSurfaceHook upstream;
+ final NativeSurface surface;
+
+ /**
+ * @param upstream optional upstream UpstreamSurfaceHook used for {@link #create(ProxySurface)} and {@link #destroy(ProxySurface)}.
+ * @param surface mandatory {@link NativeSurface} used for {@link #getWidth(ProxySurface)} and {@link #getHeight(ProxySurface)}
+ */
+ public DelegatedUpstreamSurfaceHookWithSurfaceSize(UpstreamSurfaceHook upstream, NativeSurface surface) {
+ this.upstream = upstream;
+ this.surface = surface;
+ if(null == surface) {
+ throw new IllegalArgumentException("given surface is null");
+ }
+ }
+
+ @Override
+ public final void create(ProxySurface s) {
+ if(null != upstream) {
+ upstream.create(s);
+ }
+ }
+
+ @Override
+ public final void destroy(ProxySurface s) {
+ if(null != upstream) {
+ upstream.destroy(s);
+ }
+ }
+
+ @Override
+ public final int getWidth(ProxySurface s) {
+ return surface.getWidth();
+ }
+
+ @Override
+ public final int getHeight(ProxySurface s) {
+ return surface.getHeight();
+ }
+
+ @Override
+ public String toString() {
+ final String us_s = null != surface ? ( surface.getClass().getName() + ": 0x" + Long.toHexString(surface.getSurfaceHandle()) + " " +surface.getWidth() + "x" + surface.getHeight() ) : "nil";
+ return getClass().getSimpleName()+"["+upstream+", "+us_s+"]";
+ }
+
+}
+
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java
new file mode 100644
index 000000000..29c540ac4
--- /dev/null
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java
@@ -0,0 +1,45 @@
+package com.jogamp.nativewindow;
+
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+public class UpstreamSurfaceHookMutableSize implements UpstreamSurfaceHook.MutableSize {
+ int width, height;
+
+ /**
+ * @param width initial width
+ * @param height initial height
+ */
+ public UpstreamSurfaceHookMutableSize(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public final void setSize(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public final int getWidth(ProxySurface s) {
+ return width;
+ }
+
+ @Override
+ public final int getHeight(ProxySurface s) {
+ return height;
+ }
+ @Override
+ public void create(ProxySurface s) { /* nop */ }
+
+ @Override
+ public void destroy(ProxySurface s) { /* nop */ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName()+"[ "+ width + "x" + height + "]";
+ }
+
+}
+
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/com/jogamp/nativewindow/WrappedSurface.java
deleted file mode 100644
index b7f6ba45d..000000000
--- a/src/nativewindow/classes/com/jogamp/nativewindow/WrappedSurface.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * Copyright 2010 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
-
-package com.jogamp.nativewindow;
-
-import javax.media.nativewindow.AbstractGraphicsConfiguration;
-import javax.media.nativewindow.ProxySurface;
-
-public class WrappedSurface extends ProxySurface {
- protected long surfaceHandle;
-
- public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, int initialWidth, int initialHeight, UpstreamSurfaceHook upstream) {
- super(cfg, initialWidth, initialHeight, upstream);
- surfaceHandle=handle;
- }
-
- @Override
- protected void invalidateImpl() {
- surfaceHandle = 0;
- }
-
- @Override
- public final long getSurfaceHandle() {
- return surfaceHandle;
- }
-
- @Override
- public final void setSurfaceHandle(long surfaceHandle) {
- this.surfaceHandle=surfaceHandle;
- }
-
- @Override
- protected final int lockSurfaceImpl() {
- return LOCK_SUCCESS;
- }
-
- @Override
- protected final void unlockSurfaceImpl() {
- }
-
- @Override
- public String toString() {
- final UpstreamSurfaceHook ush = getUpstreamSurfaceHook();
- final String ush_s = null != ush ? ( ush.getClass().getName() + ": " + ush ) : "nil";
-
- return "WrappedSurface[config " + getPrivateGraphicsConfiguration()+
- ", displayHandle 0x" + Long.toHexString(getDisplayHandle()) +
- ", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle()) +
- ", size " + getWidth() + "x" + getHeight() +
- ", surfaceLock "+surfaceLock+
- ", upstreamSurfaceHook "+ush_s+"]";
- }
-}
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java
index d4b927cf1..a62d08ccf 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java
@@ -39,12 +39,14 @@ package com.jogamp.nativewindow.awt;
import com.jogamp.common.util.locks.LockFactory;
import com.jogamp.common.util.locks.RecursiveLock;
+import com.jogamp.nativewindow.MutableGraphicsConfiguration;
import java.awt.Component;
import java.awt.Container;
import java.applet.Applet;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.NativeWindowException;
@@ -110,21 +112,6 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
this.offscreenSurfaceLayer = 0;
}
- @Override
- public void setShallUseOffscreenLayer(boolean v) {
- shallUseOffscreenLayer = v;
- }
-
- @Override
- public final boolean getShallUseOffscreenLayer() {
- return shallUseOffscreenLayer;
- }
-
- @Override
- public final boolean isOffscreenLayerSurfaceEnabled() {
- return isOffscreenLayerSurface;
- }
-
protected synchronized void invalidate() {
invalidateNative();
jawt = null;
@@ -136,26 +123,29 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
}
protected abstract void invalidateNative();
- protected final void updateBounds(JAWT_Rectangle jawtBounds) {
- if(DEBUG) {
- final Rectangle jb = new Rectangle(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight());
- if(!bounds.equals(jb)) {
+ protected final boolean updateBounds(JAWT_Rectangle jawtBounds) {
+ final Rectangle jb = new Rectangle(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight());
+ final boolean changed = !bounds.equals(jb);
+
+ if(changed) {
+ if(DEBUG) {
System.err.println("JAWTWindow.updateBounds: "+bounds+" -> "+jb);
Thread.dumpStack();
}
+ bounds.setX(jawtBounds.getX());
+ bounds.setY(jawtBounds.getY());
+ bounds.setWidth(jawtBounds.getWidth());
+ bounds.setHeight(jawtBounds.getHeight());
+
+ if(component instanceof Container) {
+ java.awt.Insets contInsets = ((Container)component).getInsets();
+ insets.setLeftWidth(contInsets.left);
+ insets.setRightWidth(contInsets.right);
+ insets.setTopHeight(contInsets.top);
+ insets.setBottomHeight(contInsets.bottom);
+ }
}
- bounds.setX(jawtBounds.getX());
- bounds.setY(jawtBounds.getY());
- bounds.setWidth(jawtBounds.getWidth());
- bounds.setHeight(jawtBounds.getHeight());
-
- if(component instanceof Container) {
- java.awt.Insets contInsets = ((Container)component).getInsets();
- insets.setLeftWidth(contInsets.left);
- insets.setRightWidth(contInsets.right);
- insets.setTopHeight(contInsets.top);
- insets.setBottomHeight(contInsets.bottom);
- }
+ return changed;
}
/** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */
@@ -181,9 +171,29 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
return jawt;
}
- /**
- * {@inheritDoc}
- */
+ //
+ // OffscreenLayerOption
+ //
+
+ @Override
+ public void setShallUseOffscreenLayer(boolean v) {
+ shallUseOffscreenLayer = v;
+ }
+
+ @Override
+ public final boolean getShallUseOffscreenLayer() {
+ return shallUseOffscreenLayer;
+ }
+
+ @Override
+ public final boolean isOffscreenLayerSurfaceEnabled() {
+ return isOffscreenLayerSurface;
+ }
+
+ //
+ // OffscreenLayerSurface
+ //
+
@Override
public final void attachSurfaceLayer(final long layerHandle) throws NativeWindowException {
if( !isOffscreenLayerSurfaceEnabled() ) {
@@ -205,9 +215,6 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
}
protected abstract void attachSurfaceLayerImpl(final long layerHandle);
- /**
- * {@inheritDoc}
- */
@Override
public final void detachSurfaceLayer() throws NativeWindowException {
if( !isOffscreenLayerSurfaceEnabled() ) {
@@ -232,11 +239,21 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
}
protected abstract void detachSurfaceLayerImpl(final long layerHandle);
+ protected final long getAttachedSurfaceLayer() {
+ return offscreenSurfaceLayer;
+ }
+
@Override
public final boolean isSurfaceLayerAttached() {
return 0 != offscreenSurfaceLayer;
}
+ @Override
+ public final void setChosenCapabilities(CapabilitiesImmutable caps) {
+ ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps);
+ getPrivateGraphicsConfiguration().setChosenCapabilities(caps);
+ }
+
//
// SurfaceUpdateListener
//
@@ -381,7 +398,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
public final AbstractGraphicsConfiguration getGraphicsConfiguration() {
return config.getNativeGraphicsConfiguration();
}
-
+
@Override
public final long getDisplayHandle() {
return getGraphicsConfiguration().getScreen().getDevice().getHandle();
@@ -393,13 +410,13 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
}
@Override
- public int getWidth() {
+ public final int getWidth() {
return component.getWidth();
}
@Override
- public int getHeight() {
- return component.getHeight();
+ public final int getHeight() {
+ return component.getHeight();
}
//
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java
index 40042ec81..b824350ff 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java
@@ -67,8 +67,8 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl
* Note that this is not an open connection, ie no native display handle exist.
* This constructor exist to setup a default device connection/unit.
*/
- public EGLGraphicsDevice(String connection, int unitID) {
- super(NativeWindowFactory.TYPE_EGL, connection, unitID);
+ public EGLGraphicsDevice() {
+ super(NativeWindowFactory.TYPE_EGL, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT);
this.nativeDisplayID[0] = 0 ; // EGL.EGL_DEFAULT_DISPLAY
this.eglLifecycleCallback = null;
}
diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java
index cec7d4ec3..27462ae70 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java
@@ -124,8 +124,11 @@ public interface NativeSurface extends SurfaceUpdatedListener {
/**
* Provide a mechanism to utilize custom (pre-) swap surface
* code. This method is called before the render toolkit (e.g. JOGL)
- * swaps the buffer/surface. The implementation may itself apply the swapping,
+ * swaps the buffer/surface if double buffering is enabled.
+ *
+ * The implementation may itself apply the swapping,
* in which case true shall be returned.
+ *
*
* @return true if this method completed swapping the surface,
* otherwise false, in which case eg the GLDrawable
diff --git a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java
index f7dbc6c27..f9800109c 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java
@@ -50,4 +50,7 @@ public interface OffscreenLayerSurface {
/** Returns true if a surface layer is attached, otherwise false. */
public boolean isSurfaceLayerAttached();
+ /** Sets the capabilities of this instance, allowing upstream API's to refine it, i.e. OpenGL related settings. */
+ public void setChosenCapabilities(CapabilitiesImmutable caps);
+
}
diff --git a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java
index 7fc9789c2..395fdc818 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2012 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -29,242 +29,82 @@
package javax.media.nativewindow;
import jogamp.nativewindow.Debug;
-import jogamp.nativewindow.SurfaceUpdatedHelper;
-import com.jogamp.common.util.locks.LockFactory;
-import com.jogamp.common.util.locks.RecursiveLock;
-
-public abstract class ProxySurface implements NativeSurface, MutableSurface {
+/**
+ * Provides a mutable {@link NativeSurface}, i.e. {@link MutableSurface}, while allowing an
+ * {@link UpstreamSurfaceHook} to influence the lifecycle and information.
+ *
+ * @see UpstreamSurfaceHook
+ * @see MutableSurface
+ * @see NativeSurface
+ */
+public interface ProxySurface extends MutableSurface {
public static final boolean DEBUG = Debug.debug("ProxySurface");
/**
- * Implementation specific bitvalue stating the upstream's {@link AbstractGraphicsDevice} is owned by this {@link ProxySurface}.
- * @see #setImplBitfield(int)
- * @see #getImplBitfield()
+ * Implementation specific bit-value stating this {@link ProxySurface} owns the upstream's surface handle
+ * @see #addUpstreamOptionBits(int)
+ * @see #getUpstreamOptionBits()
*/
- public static final int OWN_DEVICE = 1 << 7;
+ public static final int OPT_PROXY_OWNS_UPSTREAM_SURFACE = 1 << 6;
+
+ /**
+ * Implementation specific bit-value stating this {@link ProxySurface} owns the upstream's {@link AbstractGraphicsDevice}.
+ * @see #addUpstreamOptionBits(int)
+ * @see #getUpstreamOptionBits()
+ */
+ public static final int OPT_PROXY_OWNS_UPSTREAM_DEVICE = 1 << 7;
/**
* Implementation specific bitvalue stating the upstream's {@link NativeSurface} is an invisible window, i.e. maybe incomplete.
- * @see #setImplBitfield(int)
- * @see #getImplBitfield()
+ * @see #addUpstreamOptionBits(int)
+ * @see #getUpstreamOptionBits()
*/
- public static final int INVISIBLE_WINDOW = 1 << 8;
+ public static final int OPT_UPSTREAM_WINDOW_INVISIBLE = 1 << 8;
- /** Interface allowing upstream caller to pass lifecycle actions and size info to a {@link ProxySurface} instance. */
- public interface UpstreamSurfaceHook {
- /** called within {@link ProxySurface#createNotify()} within lock, before using surface. */
- public void create(ProxySurface s);
- /** called within {@link ProxySurface#destroyNotify()} within lock, before clearing fields. */
- public void destroy(ProxySurface s);
+ /** Allow redefining the AbstractGraphicsConfiguration */
+ public void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg);
- /** Returns the width of the upstream surface */
- public int getWidth(ProxySurface s);
- /** Returns the height of the upstream surface */
- public int getHeight(ProxySurface s);
- }
+ /** Returns the set {@link UpstreamSurfaceHook}, or null if not set. */
+ public UpstreamSurfaceHook getUpstreamSurfaceHook();
- private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper();
- private final AbstractGraphicsConfiguration config; // control access due to delegation
- private final UpstreamSurfaceHook upstream;
- public final int initialWidth;
- public final int initialHeight;
- private long surfaceHandle_old;
- protected RecursiveLock surfaceLock = LockFactory.createRecursiveLock();
- protected long displayHandle;
- protected int scrnIndex;
- protected int implBitfield;
-
/**
- * @param cfg the {@link AbstractGraphicsConfiguration} to be used
- * @param initialWidth the initial width
- * @param initialHeight the initial height
+ * Sets the {@link UpstreamSurfaceHook} and returns the previous value.
*/
- protected ProxySurface(AbstractGraphicsConfiguration cfg, int initialWidth, int initialHeight, UpstreamSurfaceHook upstream) {
- if(null == cfg) {
- throw new IllegalArgumentException("null config");
- }
- this.config = cfg;
- this.upstream = upstream;
- this.initialWidth = initialWidth;
- this.initialHeight = initialHeight;
- this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle();
- this.surfaceHandle_old = 0;
- this.implBitfield = 0;
- }
-
- public final UpstreamSurfaceHook getUpstreamSurfaceHook() { return upstream; }
+ public void setUpstreamSurfaceHook(UpstreamSurfaceHook hook);
+
+ /**
+ * Enables or disables the {@link UpstreamSurfaceHook} lifecycle functions
+ * {@link UpstreamSurfaceHook#create(ProxySurface)} and {@link UpstreamSurfaceHook#destroy(ProxySurface)}.
+ *
+ * Use this for small code blocks where the native resources shall not change,
+ * i.e. resizing a derived (OpenGL) drawable.
+ *
+ */
+ public void enableUpstreamSurfaceHookLifecycle(boolean enable);
/**
- * If a valid {@link UpstreamSurfaceHook} instance is passed in the
- * {@link ProxySurface#ProxySurface(AbstractGraphicsConfiguration, int, int, UpstreamSurfaceHook) constructor},
* {@link UpstreamSurfaceHook#create(ProxySurface)} is being issued and the proxy surface/window handles shall be set.
*/
- public void createNotify() {
- if(null != upstream) {
- upstream.create(this);
- }
- this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle();
- this.surfaceHandle_old = 0;
- }
+ public void createNotify();
/**
- * If a valid {@link UpstreamSurfaceHook} instance is passed in the
- * {@link ProxySurface#ProxySurface(AbstractGraphicsConfiguration, int, int, UpstreamSurfaceHook) constructor},
- * {@link UpstreamSurfaceHook#destroy(ProxySurface)} is being issued and all fields are cleared.
+ * {@link UpstreamSurfaceHook#destroy(ProxySurface)} is being issued and all proxy surface/window handles shall be cleared.
*/
- public void destroyNotify() {
- if(null != upstream) {
- upstream.destroy(this);
- invalidateImpl();
- }
- this.displayHandle = 0;
- this.surfaceHandle_old = 0;
- }
+ public void destroyNotify();
- /**
- * Must be overridden by implementations allowing having a {@link UpstreamSurfaceHook} being passed.
- * @see #destroyNotify()
- */
- protected void invalidateImpl() {
- throw new InternalError("UpstreamSurfaceHook given, but required method not implemented.");
- }
+ public StringBuilder getUpstreamOptionBits(StringBuilder sink);
+ public int getUpstreamOptionBits();
- @Override
- public final long getDisplayHandle() {
- return displayHandle;
- }
-
- protected final AbstractGraphicsConfiguration getPrivateGraphicsConfiguration() {
- return config;
- }
-
- @Override
- public final AbstractGraphicsConfiguration getGraphicsConfiguration() {
- return config.getNativeGraphicsConfiguration();
- }
-
- @Override
- public final int getScreenIndex() {
- return getGraphicsConfiguration().getScreen().getIndex();
- }
-
- @Override
- public abstract long getSurfaceHandle();
-
- @Override
- public abstract void setSurfaceHandle(long surfaceHandle);
+ /** Returns true if the give bit-mask v is set in this instance upstream-option-bits, otherwise false.*/
+ public boolean containsUpstreamOptionBits(int v);
- @Override
- public final int getWidth() {
- if(null != upstream) {
- return upstream.getWidth(this);
- }
- return initialWidth;
- }
-
- @Override
- public final int getHeight() {
- if(null != upstream) {
- return upstream.getHeight(this);
- }
- return initialHeight;
- }
-
- @Override
- public boolean surfaceSwap() {
- return false;
- }
-
- @Override
- public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
- surfaceUpdatedHelper.addSurfaceUpdatedListener(l);
- }
-
- @Override
- public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
- surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l);
- }
-
- @Override
- public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
- surfaceUpdatedHelper.removeSurfaceUpdatedListener(l);
- }
-
- @Override
- public void surfaceUpdated(Object updater, NativeSurface ns, long when) {
- surfaceUpdatedHelper.surfaceUpdated(updater, ns, when);
- }
-
- @Override
- public int lockSurface() throws NativeWindowException, RuntimeException {
- surfaceLock.lock();
- int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ?
-
- if ( LOCK_SURFACE_NOT_READY == res ) {
- try {
- final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
- adevice.lock();
- try {
- res = lockSurfaceImpl();
- if(LOCK_SUCCESS == res && surfaceHandle_old != getSurfaceHandle()) {
- res = LOCK_SURFACE_CHANGED;
- if(DEBUG) {
- System.err.println("ProxySurface: surface change 0x"+Long.toHexString(surfaceHandle_old)+" -> 0x"+Long.toHexString(getSurfaceHandle()));
- // Thread.dumpStack();
- }
- }
- } finally {
- if (LOCK_SURFACE_NOT_READY >= res) {
- adevice.unlock();
- }
- }
- } finally {
- if (LOCK_SURFACE_NOT_READY >= res) {
- surfaceLock.unlock();
- }
- }
- }
- return res;
- }
-
- @Override
- public final void unlockSurface() {
- surfaceLock.validateLocked();
- surfaceHandle_old = getSurfaceHandle();
-
- if (surfaceLock.getHoldCount() == 1) {
- final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
- try {
- unlockSurfaceImpl();
- } finally {
- adevice.unlock();
- }
- }
- surfaceLock.unlock();
- }
-
- protected abstract int lockSurfaceImpl();
-
- protected abstract void unlockSurfaceImpl() ;
-
- public final void validateSurfaceLocked() {
- surfaceLock.validateLocked();
- }
-
- @Override
- public final boolean isSurfaceLockedByOtherThread() {
- return surfaceLock.isLockedByOtherThread();
- }
-
- @Override
- public final Thread getSurfaceLockOwner() {
- return surfaceLock.getOwner();
- }
+ /** Add the given bit-mask to this instance upstream-option-bits using bit-or w/ v.*/
+ public void addUpstreamOptionBits(int v);
- @Override
- public abstract String toString();
+ /** Clear the given bit-mask from this instance upstream-option-bits using bit-and w/ ~v*/
+ public void clearUpstreamOptionBits(int v);
- public int getImplBitfield() { return implBitfield; }
- public void setImplBitfield(int v) { implBitfield=v; }
+ public StringBuilder toString(StringBuilder sink);
+ public String toString();
}
diff --git a/src/nativewindow/classes/javax/media/nativewindow/UpstreamSurfaceHook.java b/src/nativewindow/classes/javax/media/nativewindow/UpstreamSurfaceHook.java
new file mode 100644
index 000000000..6fe2e5364
--- /dev/null
+++ b/src/nativewindow/classes/javax/media/nativewindow/UpstreamSurfaceHook.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package javax.media.nativewindow;
+
+/**
+ * Interface allowing upstream caller to pass lifecycle actions and size info
+ * to a {@link ProxySurface} instance.
+ */
+public interface UpstreamSurfaceHook {
+ /** called within {@link ProxySurface#createNotify()} within lock, before using surface. */
+ public void create(ProxySurface s);
+ /** called within {@link ProxySurface#destroyNotify()} within lock, before clearing fields. */
+ public void destroy(ProxySurface s);
+
+ /** Returns the width of the upstream surface, used if {@link ProxySurface#UPSTREAM_PROVIDES_SIZE} is set. */
+ public int getWidth(ProxySurface s);
+ /** Returns the height of the upstream surface, used if {@link ProxySurface#UPSTREAM_PROVIDES_SIZE} is set. */
+ public int getHeight(ProxySurface s);
+
+ /**
+ * {@link UpstreamSurfaceHook} w/ mutable size, allowing it's {@link ProxySurface} user to resize.
+ */
+ public interface MutableSize extends UpstreamSurfaceHook {
+ public void setSize(int width, int height);
+ }
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java
new file mode 100644
index 000000000..63f56cbae
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java
@@ -0,0 +1,326 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package jogamp.nativewindow;
+
+import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.SurfaceUpdatedListener;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+
+public abstract class ProxySurfaceImpl implements ProxySurface {
+ private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper();
+ protected long displayHandle; // convenient ref of config.screen.device.handle
+ private AbstractGraphicsConfiguration config; // control access due to delegation
+ private UpstreamSurfaceHook upstream;
+ private long surfaceHandle_old;
+ private RecursiveLock surfaceLock = LockFactory.createRecursiveLock();
+ private int implBitfield;
+ private boolean upstreamSurfaceHookLifecycleEnabled;
+
+ /**
+ * @param cfg the {@link AbstractGraphicsConfiguration} to be used
+ * @param upstream the {@link UpstreamSurfaceHook} to be used
+ * @param ownsDevice true if this {@link ProxySurface} instance
+ * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice},
+ * otherwise false. Owning the device implies closing it at {@link #destroyNotify()}.
+ */
+ protected ProxySurfaceImpl(AbstractGraphicsConfiguration cfg, UpstreamSurfaceHook upstream, boolean ownsDevice) {
+ if(null == cfg) {
+ throw new IllegalArgumentException("null AbstractGraphicsConfiguration");
+ }
+ if(null == upstream) {
+ throw new IllegalArgumentException("null UpstreamSurfaceHook");
+ }
+ this.config = cfg;
+ this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle();
+ this.upstream = upstream;
+ this.surfaceHandle_old = 0;
+ this.implBitfield = 0;
+ this.upstreamSurfaceHookLifecycleEnabled = true;
+ if(ownsDevice) {
+ addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
+ }
+
+ @Override
+ public final UpstreamSurfaceHook getUpstreamSurfaceHook() { return upstream; }
+
+ @Override
+ public void setUpstreamSurfaceHook(UpstreamSurfaceHook hook) {
+ if(null == hook) {
+ throw new IllegalArgumentException("null UpstreamSurfaceHook");
+ }
+ upstream = hook;
+ }
+
+ @Override
+ public final void enableUpstreamSurfaceHookLifecycle(boolean enable) {
+ upstreamSurfaceHookLifecycleEnabled = enable;
+ }
+
+ @Override
+ public void createNotify() {
+ if(upstreamSurfaceHookLifecycleEnabled) {
+ upstream.create(this);
+ }
+ this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle();
+ this.surfaceHandle_old = 0;
+ }
+
+ @Override
+ public void destroyNotify() {
+ if(upstreamSurfaceHookLifecycleEnabled) {
+ upstream.destroy(this);
+ if( containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ) ) {
+ final AbstractGraphicsDevice aDevice = getGraphicsConfiguration().getScreen().getDevice();
+ aDevice.close();
+ clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
+ invalidateImpl();
+ }
+ this.displayHandle = 0;
+ this.surfaceHandle_old = 0;
+ }
+
+ /**
+ * Must be overridden by implementations allowing having a {@link UpstreamSurfaceHook} being passed.
+ * @see #destroyNotify()
+ */
+ protected void invalidateImpl() {
+ throw new InternalError("UpstreamSurfaceHook given, but required method not implemented.");
+ }
+
+ @Override
+ public final long getDisplayHandle() {
+ return displayHandle;
+ }
+
+ protected final AbstractGraphicsConfiguration getPrivateGraphicsConfiguration() {
+ return config;
+ }
+
+ @Override
+ public final AbstractGraphicsConfiguration getGraphicsConfiguration() {
+ return config.getNativeGraphicsConfiguration();
+ }
+
+ @Override
+ public final void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg) {
+ config = cfg;
+ }
+
+ @Override
+ public final int getScreenIndex() {
+ return getGraphicsConfiguration().getScreen().getIndex();
+ }
+
+ @Override
+ public abstract long getSurfaceHandle();
+
+ @Override
+ public abstract void setSurfaceHandle(long surfaceHandle);
+
+ @Override
+ public final int getWidth() {
+ return upstream.getWidth(this);
+ }
+
+ @Override
+ public final int getHeight() {
+ return upstream.getHeight(this);
+ }
+
+ @Override
+ public boolean surfaceSwap() {
+ return false;
+ }
+
+ @Override
+ public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
+ surfaceUpdatedHelper.addSurfaceUpdatedListener(l);
+ }
+
+ @Override
+ public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
+ surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l);
+ }
+
+ @Override
+ public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
+ surfaceUpdatedHelper.removeSurfaceUpdatedListener(l);
+ }
+
+ @Override
+ public void surfaceUpdated(Object updater, NativeSurface ns, long when) {
+ surfaceUpdatedHelper.surfaceUpdated(updater, ns, when);
+ }
+
+ @Override
+ public int lockSurface() throws NativeWindowException, RuntimeException {
+ surfaceLock.lock();
+ int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ?
+
+ if ( LOCK_SURFACE_NOT_READY == res ) {
+ try {
+ final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
+ adevice.lock();
+ try {
+ res = lockSurfaceImpl();
+ if(LOCK_SUCCESS == res && surfaceHandle_old != getSurfaceHandle()) {
+ res = LOCK_SURFACE_CHANGED;
+ if(DEBUG) {
+ System.err.println("ProxySurfaceImpl: surface change 0x"+Long.toHexString(surfaceHandle_old)+" -> 0x"+Long.toHexString(getSurfaceHandle()));
+ // Thread.dumpStack();
+ }
+ }
+ } finally {
+ if (LOCK_SURFACE_NOT_READY >= res) {
+ adevice.unlock();
+ }
+ }
+ } finally {
+ if (LOCK_SURFACE_NOT_READY >= res) {
+ surfaceLock.unlock();
+ }
+ }
+ }
+ return res;
+ }
+
+ @Override
+ public final void unlockSurface() {
+ surfaceLock.validateLocked();
+ surfaceHandle_old = getSurfaceHandle();
+
+ if (surfaceLock.getHoldCount() == 1) {
+ final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
+ try {
+ unlockSurfaceImpl();
+ } finally {
+ adevice.unlock();
+ }
+ }
+ surfaceLock.unlock();
+ }
+
+ protected abstract int lockSurfaceImpl();
+
+ protected abstract void unlockSurfaceImpl() ;
+
+ public final void validateSurfaceLocked() {
+ surfaceLock.validateLocked();
+ }
+
+ @Override
+ public final boolean isSurfaceLockedByOtherThread() {
+ return surfaceLock.isLockedByOtherThread();
+ }
+
+ @Override
+ public final Thread getSurfaceLockOwner() {
+ return surfaceLock.getOwner();
+ }
+
+ public final StringBuilder getUpstreamOptionBits(StringBuilder sink) {
+ if(null == sink) {
+ sink = new StringBuilder();
+ }
+ sink.append("UOB[ ");
+ if(0 == implBitfield) {
+ sink.append("]");
+ return sink;
+ }
+ boolean needsOr = false;
+ if( 0 != ( implBitfield & OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ sink.append("OWNS_SURFACE");
+ needsOr = true;
+ }
+ if( 0 != ( implBitfield & OPT_PROXY_OWNS_UPSTREAM_DEVICE ) ) {
+ if(needsOr) {
+ sink.append(" | ");
+ }
+ sink.append("OWNS_DEVICE");
+ needsOr = true;
+ }
+ if( 0 != ( implBitfield & OPT_UPSTREAM_WINDOW_INVISIBLE ) ) {
+ if(needsOr) {
+ sink.append(" | ");
+ }
+ sink.append("WINDOW_INVISIBLE");
+ needsOr = true;
+ }
+ sink.append(" ]");
+ return sink;
+ }
+
+ @Override
+ public final int getUpstreamOptionBits() { return implBitfield; }
+
+ @Override
+ public final boolean containsUpstreamOptionBits(int v) {
+ return v == ( implBitfield & v ) ;
+ }
+
+ @Override
+ public final void addUpstreamOptionBits(int v) { implBitfield |= v; }
+
+ @Override
+ public final void clearUpstreamOptionBits(int v) { implBitfield &= ~v; }
+
+ @Override
+ public StringBuilder toString(StringBuilder sink) {
+ if(null == sink) {
+ sink = new StringBuilder();
+ }
+ sink.append(getUpstreamSurfaceHook()).
+ append(", displayHandle 0x" + Long.toHexString(getDisplayHandle())).
+ append(", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle())).
+ append(", size " + getWidth() + "x" + getHeight()).append(", ");
+ getUpstreamOptionBits(sink);
+ sink.append(", surfaceLock "+surfaceLock);
+ return sink;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder msg = new StringBuilder();
+ msg.append(getClass().getSimpleName()).append("[ ");
+ toString(msg);
+ msg.append(" ]");
+ return msg.toString();
+ }
+
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java
new file mode 100644
index 000000000..e544bc61a
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package jogamp.nativewindow;
+
+import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
+
+public class WrappedSurface extends ProxySurfaceImpl {
+ protected long surfaceHandle;
+
+ /**
+ * Utilizes a {@link UpstreamSurfaceHook.MutableSize} to hold the size information,
+ * which is being passed to the {@link ProxySurface} instance.
+ *
+ * @param cfg the {@link AbstractGraphicsConfiguration} to be used
+ * @param handle the wrapped pre-existing native surface handle, maybe 0 if not yet determined
+ * @param initialWidth
+ * @param initialHeight
+ * @param ownsDevice true if this {@link ProxySurface} instance
+ * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice},
+ * otherwise false. Owning the device implies closing it at {@link #destroyNotify()}.
+ */
+ public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, int initialWidth, int initialHeight, boolean ownsDevice) {
+ super(cfg, new UpstreamSurfaceHookMutableSize(initialWidth, initialHeight), ownsDevice);
+ surfaceHandle=handle;
+ }
+
+ /**
+ * @param cfg the {@link AbstractGraphicsConfiguration} to be used
+ * @param handle the wrapped pre-existing native surface handle, maybe 0 if not yet determined
+ * @param upstream the {@link UpstreamSurfaceHook} to be used
+ * @param ownsDevice true if this {@link ProxySurface} instance
+ * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice},
+ * otherwise false.
+ */
+ public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, UpstreamSurfaceHook upstream, boolean ownsDevice) {
+ super(cfg, upstream, ownsDevice);
+ surfaceHandle=handle;
+ }
+
+ @Override
+ protected void invalidateImpl() {
+ surfaceHandle = 0;
+ }
+
+ @Override
+ public final long getSurfaceHandle() {
+ return surfaceHandle;
+ }
+
+ @Override
+ public final void setSurfaceHandle(long surfaceHandle) {
+ this.surfaceHandle=surfaceHandle;
+ }
+
+ @Override
+ protected final int lockSurfaceImpl() {
+ return LOCK_SUCCESS;
+ }
+
+ @Override
+ protected final void unlockSurfaceImpl() {
+ }
+
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java
index e81d61e0f..5fd242247 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java
@@ -51,7 +51,6 @@ import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.MutableSurface;
import javax.media.nativewindow.util.Point;
-import com.jogamp.nativewindow.MutableGraphicsConfiguration;
import com.jogamp.nativewindow.awt.JAWTWindow;
import jogamp.nativewindow.jawt.JAWT;
@@ -71,17 +70,18 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface {
}
protected void invalidateNative() {
- surfaceHandle=0;
+ offscreenSurfaceHandle=0;
+ offscreenSurfaceHandleSet=false;
if(isOffscreenLayerSurfaceEnabled()) {
if(0 != rootSurfaceLayerHandle) {
OSXUtil.DestroyCALayer(rootSurfaceLayerHandle);
rootSurfaceLayerHandle = 0;
}
- if(0 != drawable) {
- OSXUtil.DestroyNSWindow(drawable);
- drawable = 0;
+ if(0 != windowHandle) {
+ OSXUtil.DestroyNSWindow(windowHandle);
}
}
+ windowHandle=0;
}
protected void attachSurfaceLayerImpl(final long layerHandle) {
@@ -92,8 +92,14 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface {
OSXUtil.RemoveCASublayer(rootSurfaceLayerHandle, layerHandle);
}
- public long getSurfaceHandle() {
- return isOffscreenLayerSurfaceEnabled() ? surfaceHandle : super.getSurfaceHandle() ;
+ @Override
+ public final long getWindowHandle() {
+ return windowHandle;
+ }
+
+ @Override
+ public final long getSurfaceHandle() {
+ return offscreenSurfaceHandleSet ? offscreenSurfaceHandle : drawable /* super.getSurfaceHandle() */ ;
}
public void setSurfaceHandle(long surfaceHandle) {
@@ -103,7 +109,8 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface {
if(DEBUG) {
System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle));
}
- this.surfaceHandle = surfaceHandle;
+ this.offscreenSurfaceHandle = surfaceHandle;
+ this.offscreenSurfaceHandleSet = true;
}
protected JAWT fetchJAWTImpl() throws NativeWindowException {
@@ -167,6 +174,7 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface {
unlockSurfaceImpl();
return NativeWindow.LOCK_SURFACE_NOT_READY;
} else {
+ windowHandle = OSXUtil.GetNSWindow(drawable);
ret = NativeWindow.LOCK_SUCCESS;
}
} else {
@@ -177,36 +185,46 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface {
* The actual surface/ca-layer shall be created/attached
* by the upper framework (JOGL) since they require more information.
*/
+ String errMsg = null;
if(0 == drawable) {
- drawable = OSXUtil.CreateNSWindow(0, 0, getBounds().getWidth(), getBounds().getHeight());
- if(0 == drawable) {
- unlockSurfaceImpl();
- throw new NativeWindowException("Unable to created dummy NSWindow (layered case)");
+ windowHandle = OSXUtil.CreateNSWindow(0, 0, 64, 64);
+ if(0 == windowHandle) {
+ errMsg = "Unable to create dummy NSWindow (layered case)";
+ } else {
+ drawable = OSXUtil.GetNSView(windowHandle);
+ if(0 == drawable) {
+ errMsg = "Null NSView of NSWindow 0x"+Long.toHexString(windowHandle);
+ }
+ }
+ if(null == errMsg) {
+ // fix caps reflecting offscreen! (no GL available here ..)
+ Capabilities caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable();
+ caps.setOnscreen(false);
+ setChosenCapabilities(caps);
}
- // fix caps reflecting offscreen!
- Capabilities caps = (Capabilities) getPrivateGraphicsConfiguration().getChosenCapabilities().cloneMutable();
- caps.setOnscreen(false);
- getPrivateGraphicsConfiguration().setChosenCapabilities(caps);
- caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable();
- caps.setOnscreen(false);
- ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps);
}
- if(0 == rootSurfaceLayerHandle) {
- rootSurfaceLayerHandle = OSXUtil.CreateCALayer(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
- if(0 == rootSurfaceLayerHandle) {
- OSXUtil.DestroyNSWindow(drawable);
- drawable = 0;
- unlockSurfaceImpl();
- throw new NativeWindowException("Could not create root CALayer: "+this);
+ if(null == errMsg) {
+ if(0 == rootSurfaceLayerHandle) {
+ rootSurfaceLayerHandle = OSXUtil.CreateCALayer(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
+ if(0 == rootSurfaceLayerHandle) {
+ errMsg = "Could not create root CALayer";
+ } else if(!SetJAWTRootSurfaceLayer0(dsi.getBuffer(), rootSurfaceLayerHandle)) {
+ errMsg = "Could not set JAWT rootSurfaceLayerHandle 0x"+Long.toHexString(rootSurfaceLayerHandle);
+ }
}
- if(!SetJAWTRootSurfaceLayer0(dsi.getBuffer(), rootSurfaceLayerHandle)) {
+ }
+ if(null != errMsg) {
+ if(0 != rootSurfaceLayerHandle) {
OSXUtil.DestroyCALayer(rootSurfaceLayerHandle);
rootSurfaceLayerHandle = 0;
- OSXUtil.DestroyNSWindow(drawable);
- drawable = 0;
- unlockSurfaceImpl();
- throw new NativeWindowException("Could not set JAWT rootSurfaceLayerHandle: "+this);
}
+ if(0 != windowHandle) {
+ OSXUtil.DestroyNSWindow(windowHandle);
+ windowHandle = 0;
+ }
+ drawable = 0;
+ unlockSurfaceImpl();
+ throw new NativeWindowException(errMsg+": "+this);
}
ret = NativeWindow.LOCK_SUCCESS;
}
@@ -264,7 +282,9 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface {
private long rootSurfaceLayerHandle = 0; // attached to the JAWT_SurfaceLayer
- private long surfaceHandle = 0;
+ private long windowHandle = 0;
+ private long offscreenSurfaceHandle = 0;
+ private boolean offscreenSurfaceHandleSet = false;
// Workaround for instance of 4796548
private boolean firstLock = true;
diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java
new file mode 100644
index 000000000..de3206c0c
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java
@@ -0,0 +1,56 @@
+package jogamp.nativewindow.macosx;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
+
+public class OSXDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize {
+ long nsWindow;
+
+ /**
+ * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)},
+ * not the actual dummy surface width.
+ * The latter is platform specific and small
+ * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)},
+ * not the actual dummy surface height,
+ * The latter is platform specific and small
+ */
+ public OSXDummyUpstreamSurfaceHook(int width, int height) {
+ super(width, height);
+ nsWindow = 0;
+ }
+
+ @Override
+ public final void create(ProxySurface s) {
+ if(0 == nsWindow && 0 == s.getSurfaceHandle()) {
+ nsWindow = OSXUtil.CreateNSWindow(0, 0, 64, 64);
+ if(0 == nsWindow) {
+ throw new NativeWindowException("Error NS window 0");
+ }
+ long nsView = OSXUtil.GetNSView(nsWindow);
+ if(0 == nsView) {
+ throw new NativeWindowException("Error NS view 0");
+ }
+ s.setSurfaceHandle(nsView);
+ s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE);
+ }
+
+ @Override
+ public final void destroy(ProxySurface s) {
+ if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ if( 0 == nsWindow || 0 == s.getSurfaceHandle() ) {
+ throw new InternalError("Owns upstream surface, but no OSX view/window: "+s+", nsWindow 0x"+Long.toHexString(nsWindow));
+ }
+ OSXUtil.DestroyNSWindow(nsWindow);
+ nsWindow = 0;
+ s.setSurfaceHandle(0);
+ s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ }
+
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
index 149ebdf4a..b7a83e133 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
@@ -72,6 +72,10 @@ public class OSXUtil {
return isNSView0(object);
}
+ public static boolean isNSWindow(long object) {
+ return isNSWindow0(object);
+ }
+
/**
* In case the windowOrView is top-level,
* you shall set topLevel to true where
@@ -114,6 +118,9 @@ public class OSXUtil {
public static long GetNSView(long nsWindow) {
return GetNSView0(nsWindow);
}
+ public static long GetNSWindow(long nsView) {
+ return GetNSWindow0(nsView);
+ }
public static long CreateCALayer(int x, int y, int width, int height) {
return CreateCALayer0(x, y, width, height);
@@ -149,6 +156,11 @@ public class OSXUtil {
return IsMainThread0();
}
+ /** Returns the screen refresh rate in Hz. If unavailable, returns 60Hz. */
+ public static int GetScreenRefreshRate(int scrn_idx) {
+ return GetScreenRefreshRate0(scrn_idx);
+ }
+
/***
private static boolean isAWTEDTMainThreadInit = false;
private static boolean isAWTEDTMainThread;
@@ -172,15 +184,18 @@ public class OSXUtil {
private static native boolean initIDs0();
private static native boolean isNSView0(long object);
+ private static native boolean isNSWindow0(long object);
private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y);
private static native Object GetInsets0(long windowOrView);
private static native long CreateNSWindow0(int x, int y, int width, int height);
private static native void DestroyNSWindow0(long nsWindow);
private static native long GetNSView0(long nsWindow);
+ private static native long GetNSWindow0(long nsView);
private static native long CreateCALayer0(int x, int y, int width, int height);
private static native void AddCASublayer0(long rootCALayer, long subCALayer);
private static native void RemoveCASublayer0(long rootCALayer, long subCALayer);
private static native void DestroyCALayer0(long caLayer);
private static native void RunOnMainThread0(boolean waitUntilDone, Runnable runnable);
private static native boolean IsMainThread0();
+ private static native int GetScreenRefreshRate0(int scrn_idx);
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java
new file mode 100644
index 000000000..aa5f3dac5
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java
@@ -0,0 +1,50 @@
+package jogamp.nativewindow.windows;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
+
+public class GDIDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize {
+ /**
+ * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)},
+ * not the actual dummy surface width.
+ * The latter is platform specific and small
+ * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)},
+ * not the actual dummy surface height,
+ * The latter is platform specific and small
+ */
+ public GDIDummyUpstreamSurfaceHook(int width, int height) {
+ super(width, height);
+ }
+
+ @Override
+ public final void create(ProxySurface s) {
+ final GDISurface ms = (GDISurface)s;
+ if(0 == ms.getWindowHandle()) {
+ final long windowHandle = GDIUtil.CreateDummyWindow(0, 0, 64, 64);
+ if(0 == windowHandle) {
+ throw new NativeWindowException("Error windowHandle 0, werr: "+GDI.GetLastError());
+ }
+ ms.setWindowHandle(windowHandle);
+ ms.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE);
+ }
+
+ @Override
+ public final void destroy(ProxySurface s) {
+ final GDISurface ms = (GDISurface)s;
+ if( ms.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ if( 0 == ms.getWindowHandle() ) {
+ throw new InternalError("Owns upstream surface, but no GDI window: "+ms);
+ }
+ GDI.ShowWindow(ms.getWindowHandle(), GDI.SW_HIDE);
+ GDIUtil.DestroyDummyWindow(ms.getWindowHandle());
+ ms.setWindowHandle(0);
+ ms.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ }
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java
index e368aa6a1..3db2b5fc9 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java
@@ -29,9 +29,13 @@
package jogamp.nativewindow.windows;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.ProxySurface;
-import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+import jogamp.nativewindow.ProxySurfaceImpl;
+import jogamp.nativewindow.windows.GDI;
/**
@@ -40,12 +44,20 @@ import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook;
* The latter will get and release the HDC.
* The size via getWidth()/getHeight() is invalid.
*/
-public class GDISurface extends ProxySurface {
+public class GDISurface extends ProxySurfaceImpl {
protected long windowHandle;
protected long surfaceHandle;
- public GDISurface(AbstractGraphicsConfiguration cfg, long windowHandle, int initialWidth, int initialHeight, UpstreamSurfaceHook upstream) {
- super(cfg, initialWidth, initialHeight, upstream);
+ /**
+ * @param cfg the {@link AbstractGraphicsConfiguration} to be used
+ * @param windowHandle the wrapped pre-existing native window handle, maybe 0 if not yet determined
+ * @param upstream the {@link UpstreamSurfaceHook} to be used
+ * @param ownsDevice true if this {@link ProxySurface} instance
+ * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice},
+ * otherwise false. Owning the device implies closing it at {@link #destroyNotify()}.
+ */
+ public GDISurface(AbstractGraphicsConfiguration cfg, long windowHandle, UpstreamSurfaceHook upstream, boolean ownsDevice) {
+ super(cfg, upstream, ownsDevice);
this.windowHandle=windowHandle;
this.surfaceHandle=0;
}
@@ -114,18 +126,4 @@ public class GDISurface extends ProxySurface {
final public long getSurfaceHandle() {
return surfaceHandle;
}
-
- @Override
- final public String toString() {
- final UpstreamSurfaceHook ush = getUpstreamSurfaceHook();
- final String ush_s = null != ush ? ( ush.getClass().getName() + ": " + ush ) : "nil";
- return getClass().getSimpleName()+"[config "+getPrivateGraphicsConfiguration()+
- ", displayHandle 0x"+Long.toHexString(getDisplayHandle())+
- ", windowHandle 0x"+Long.toHexString(windowHandle)+
- ", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+
- ", size "+getWidth()+"x"+getHeight()+
- ", surfaceLock "+surfaceLock+
- ", upstreamSurfaceHook "+ush_s+"]";
- }
-
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java
new file mode 100644
index 000000000..55a29dd5e
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java
@@ -0,0 +1,60 @@
+package jogamp.nativewindow.x11;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+import jogamp.nativewindow.x11.X11Lib;
+
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
+import com.jogamp.nativewindow.x11.X11GraphicsConfiguration;
+import com.jogamp.nativewindow.x11.X11GraphicsDevice;
+import com.jogamp.nativewindow.x11.X11GraphicsScreen;
+
+public class X11DummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize {
+ /**
+ * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)},
+ * not the actual dummy surface width.
+ * The latter is platform specific and small
+ * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)},
+ * not the actual dummy surface height,
+ * The latter is platform specific and small
+ */
+ public X11DummyUpstreamSurfaceHook(int width, int height) {
+ super(width, height);
+ }
+
+ @Override
+ public final void create(ProxySurface s) {
+ final X11GraphicsConfiguration cfg = (X11GraphicsConfiguration) s.getGraphicsConfiguration();
+ final X11GraphicsScreen screen = (X11GraphicsScreen) cfg.getScreen();
+ final X11GraphicsDevice device = (X11GraphicsDevice) screen.getDevice();
+ if(0 == device.getHandle()) {
+ device.open();
+ s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
+ if( 0 == s.getSurfaceHandle() ) {
+ final long windowHandle = X11Lib.CreateDummyWindow(device.getHandle(), screen.getIndex(), cfg.getXVisualID(), 64, 64);
+ if(0 == windowHandle) {
+ throw new NativeWindowException("Creating dummy window failed w/ "+cfg);
+ }
+ s.setSurfaceHandle(windowHandle);
+ s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE);
+ }
+
+ @Override
+ public final void destroy(ProxySurface s) {
+ if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ final X11GraphicsDevice device = (X11GraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice();
+ if( 0 == s.getSurfaceHandle() ) {
+ throw new InternalError("Owns upstream surface, but no X11 window: "+s);
+ }
+ X11Lib.DestroyDummyWindow(device.getHandle(), s.getSurfaceHandle());
+ s.setSurfaceHandle(0);
+ s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ }
+}
diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m
index 2c853a43d..d6ae7ed31 100644
--- a/src/nativewindow/native/macosx/OSXmisc.m
+++ b/src/nativewindow/native/macosx/OSXmisc.m
@@ -119,6 +119,12 @@ Java_jogamp_nativewindow_macosx_OSXUtil_isNSView0(JNIEnv *env, jclass _unused, j
return [nsObj isMemberOfClass:[NSView class]];
}
+JNIEXPORT jboolean JNICALL
+Java_jogamp_nativewindow_macosx_OSXUtil_isNSWindow0(JNIEnv *env, jclass _unused, jlong object) {
+ NSObject *nsObj = (NSObject*) (intptr_t) object;
+ return [nsObj isMemberOfClass:[NSWindow class]];
+}
+
/*
* Class: Java_jogamp_nativewindow_macosx_OSXUtil
* Method: getLocationOnScreen0
@@ -238,8 +244,10 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateNSWindow0
[myWindow setPreservesContentDuringLiveResize: YES];
// Remove animations
NS_DURING
+ if ( [myWindow respondsToSelector:@selector(setAnimationBehavior:)] ) {
// Available >= 10.7 - Removes default animations
[myWindow setAnimationBehavior: NSWindowAnimationBehaviorNone];
+ }
NS_HANDLER
NS_ENDHANDLER
@@ -278,11 +286,28 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetNSView0
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSWindow* win = (NSWindow*) ((intptr_t) window);
- DBG_PRINT( "contentView0 - window: %p (START)\n", win);
-
jlong res = (jlong) ((intptr_t) [win contentView]);
- DBG_PRINT( "contentView0 - window: %p (END)\n", win);
+ DBG_PRINT( "GetNSView(window: %p): %p\n", win, (void*) (intptr_t) res);
+
+ [pool release];
+ return res;
+}
+
+/*
+ * Class: Java_jogamp_nativewindow_macosx_OSXUtil
+ * Method: GetNSWindow0
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetNSWindow0
+ (JNIEnv *env, jclass unused, jlong view)
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSView* v = (NSView*) ((intptr_t) view);
+
+ jlong res = (jlong) ((intptr_t) [v window]);
+
+ DBG_PRINT( "GetNSWindow(view: %p): %p\n", v, (void*) (intptr_t) res);
[pool release];
return res;
@@ -314,6 +339,8 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0
// no animations for add/remove/swap sublayers etc
// doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition]
[layer removeAllAnimations];
+ [layer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
+ [layer setNeedsDisplayOnBoundsChange: YES];
DBG_PRINT("CALayer::CreateCALayer.1: %p %lf/%lf %lfx%lf\n", layer, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height);
DBG_PRINT("CALayer::CreateCALayer.X: %p (refcnt %d)\n", layer, (int)[layer retainCount]);
@@ -357,7 +384,11 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0
// no animations for add/remove/swap sublayers etc
// doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition]
[rootLayer removeAllAnimations];
+ [rootLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
+ [rootLayer setNeedsDisplayOnBoundsChange: YES];
[subLayer removeAllAnimations];
+ [subLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
+ [subLayer setNeedsDisplayOnBoundsChange: YES];
}];
DBG_PRINT("CALayer::AddCASublayer0.X: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]);
JNF_COCOA_EXIT(env);
@@ -404,6 +435,63 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyCALayer0
JNF_COCOA_EXIT(env);
}
+/*
+ * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow
+ * Method: SetJAWTRootSurfaceLayer0
+ * Signature: (JJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_SetJAWTRootSurfaceLayer0
+ (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer)
+{
+ JNF_COCOA_ENTER(env);
+ JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer);
+ if (NULL == dsi) {
+ NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer");
+ return JNI_FALSE;
+ }
+ CALayer* layer = (CALayer*) (intptr_t) caLayer;
+ [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
+ id surfaceLayers = (id )dsi->platformInfo;
+ DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.0: %p -> %p (refcnt %d)\n", surfaceLayers.layer, layer, (int)[layer retainCount]);
+ surfaceLayers.layer = layer; // already incr. retain count
+ DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.X: %p (refcnt %d)\n", layer, (int)[layer retainCount]);
+ }];
+ JNF_COCOA_EXIT(env);
+ return JNI_TRUE;
+}
+
+/*
+ * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow
+ * Method: UnsetJAWTRootSurfaceLayer0
+ * Signature: (JJ)Z
+JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_UnsetJAWTRootSurfaceLayer0
+ (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer)
+{
+ JNF_COCOA_ENTER(env);
+ JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer);
+ if (NULL == dsi) {
+ NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer");
+ return JNI_FALSE;
+ }
+ CALayer* layer = (CALayer*) (intptr_t) caLayer;
+ {
+ id surfaceLayers = (id )dsi->platformInfo;
+ if(layer != surfaceLayers.layer) {
+ NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer);
+ return JNI_FALSE;
+ }
+ }
+ // [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
+ id surfaceLayers = (id )dsi->platformInfo;
+ DBG_PRINT("CALayer::detachJAWTSurfaceLayer: (%p) %p -> NULL\n", layer, surfaceLayers.layer);
+ surfaceLayers.layer = NULL;
+ [layer release];
+ // }];
+ JNF_COCOA_EXIT(env);
+ return JNI_TRUE;
+}
+ */
+
@interface MainRunnable : NSObject
{
@@ -489,60 +577,65 @@ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_IsMainThread0
return ( [NSThread isMainThread] == YES ) ? JNI_TRUE : JNI_FALSE ;
}
-/*
- * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow
- * Method: SetJAWTRootSurfaceLayer0
- * Signature: (JJ)Z
+/***
+ * The following static functions are copied out of NEWT's OSX impl.
+ * May need to push code to NativeWindow, to remove duplication.
*/
-JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_SetJAWTRootSurfaceLayer0
- (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer)
+static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx) {
+ NSArray *screens = [NSScreen screens];
+ if(screen_idx<0) screen_idx=0;
+ if(screen_idx>=[screens count]) screen_idx=0;
+ return (NSScreen *) [screens objectAtIndex: screen_idx];
+}
+static CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) {
+ // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?!
+ NSDictionary * dict = [screen deviceDescription];
+ NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"];
+ // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size
+ return (CGDirectDisplayID) [val integerValue];
+}
+static long GetDictionaryLong(CFDictionaryRef theDict, const void* key)
{
- JNF_COCOA_ENTER(env);
- JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer);
- if (NULL == dsi) {
- NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer");
- return JNI_FALSE;
- }
- CALayer* layer = (CALayer*) (intptr_t) caLayer;
- [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
- id surfaceLayers = (id )dsi->platformInfo;
- DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.0: %p -> %p (refcnt %d)\n", surfaceLayers.layer, layer, (int)[layer retainCount]);
- surfaceLayers.layer = layer; // already incr. retain count
- DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.X: %p (refcnt %d)\n", layer, (int)[layer retainCount]);
- }];
- JNF_COCOA_EXIT(env);
- return JNI_TRUE;
+ long value = 0;
+ CFNumberRef numRef;
+ numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
+ if (numRef != NULL)
+ CFNumberGetValue(numRef, kCFNumberLongType, &value);
+ return value;
}
+#define CGDDGetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate)
/*
- * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow
- * Method: UnsetJAWTRootSurfaceLayer0
- * Signature: (JJ)Z
-JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_UnsetJAWTRootSurfaceLayer0
- (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer)
+ * Class: Java_jogamp_nativewindow_macosx_OSXUtil
+ * Method: GetScreenRefreshRate
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetScreenRefreshRate0
+ (JNIEnv *env, jclass unused, jint scrn_idx)
{
+ int res = 0;
JNF_COCOA_ENTER(env);
- JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer);
- if (NULL == dsi) {
- NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer");
- return JNI_FALSE;
- }
- CALayer* layer = (CALayer*) (intptr_t) caLayer;
- {
- id surfaceLayers = (id )dsi->platformInfo;
- if(layer != surfaceLayers.layer) {
- NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer);
- return JNI_FALSE;
+ // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx);
+ DBG_PRINT("GetScreenRefreshRate.0: screen %p\n", (void *)screen);
+ if(NULL != screen) {
+ CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen);
+ DBG_PRINT("GetScreenRefreshRate.1: display %p\n", (void *)display);
+ if(0 != display) {
+ CFDictionaryRef mode = CGDisplayCurrentMode(display);
+ DBG_PRINT("GetScreenRefreshRate.2: mode %p\n", (void *)mode);
+ if(NULL != mode) {
+ res = CGDDGetModeRefreshRate(mode);
+ DBG_PRINT("GetScreenRefreshRate.3: res %d\n", res);
+ }
}
}
- // [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
- id surfaceLayers = (id )dsi->platformInfo;
- DBG_PRINT("CALayer::detachJAWTSurfaceLayer: (%p) %p -> NULL\n", layer, surfaceLayers.layer);
- surfaceLayers.layer = NULL;
- [layer release];
- // }];
+ if(0 == res) {
+ res = 60; // default .. (experienced on OSX 10.6.8)
+ }
+ fprintf(stderr, "GetScreenRefreshRate.X: %d\n", res);
+ // [pool release];
JNF_COCOA_EXIT(env);
- return JNI_TRUE;
+ return res;
}
- */
diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
index 6f0028a77..89a749c51 100644
--- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
+++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
@@ -68,6 +68,15 @@ import com.jogamp.newt.event.awt.AWTAdapter;
import com.jogamp.newt.event.awt.AWTKeyAdapter;
import com.jogamp.newt.event.awt.AWTMouseAdapter;
+/**
+ * AWT {@link java.awt.Canvas Canvas} containing a NEWT {@link Window} using native parenting.
+ *
+ *
+ *
+ * {@link OffscreenLayerOption#setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)}
+ * maybe called to use an offscreen drawable (FBO or PBuffer) allowing
+ * the underlying JAWT mechanism to composite the image, if supported.
+ */
@SuppressWarnings("serial")
public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProtocol, OffscreenLayerOption {
public static final boolean DEBUG = Debug.debug("Window");
diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
index 0fc1b4e89..a89ccaedb 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
@@ -51,6 +51,7 @@ import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLException;
@@ -97,7 +98,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
* Constructor. Do not call this directly -- use {@link #create()} instead.
*/
protected GLWindow(Window window) {
- super(null, null, false);
+ super(null, null, false /* always handle device lifecycle ourselves */);
this.window = (WindowImpl) window;
this.window.setHandleDestroyNotify(false);
window.addWindowListener(new WindowAdapter() {
@@ -107,8 +108,8 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
}
@Override
- public void windowResized(WindowEvent e) {
- defaultWindowResizedOp();
+ public void windowResized(WindowEvent e) {
+ defaultWindowResizedOp(getWidth(), getHeight());
}
@Override
@@ -201,11 +202,8 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
@Override
public final CapabilitiesImmutable getChosenCapabilities() {
- if (drawable == null) {
- return window.getChosenCapabilities();
- }
-
- return drawable.getChosenGLCapabilities();
+ final GLDrawable _drawable = drawable;
+ return null != _drawable ? _drawable.getChosenGLCapabilities() : window.getChosenCapabilities();
}
@Override
@@ -536,19 +534,24 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
return;
}
+ final boolean done;
final RecursiveLock lock = window.getLock();
lock.lock(); // sync: context/drawable could have been recreated/destroyed while animating
try {
if( null != context ) {
// surface is locked/unlocked implicit by context's makeCurrent/release
helper.invokeGL(drawable, context, defaultDisplayAction, defaultInitAction);
- } else if( 0 display
- setVisible(true);
+ done = true;
+ } else {
+ done = false;
}
} finally {
lock.unlock();
}
+ if( !done && 0 display
+ setVisible(true);
+ }
}
//----------------------------------------------------------------------
diff --git a/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java b/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java
index cada253bc..36bc3f28f 100644
--- a/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java
+++ b/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java
@@ -63,6 +63,9 @@ import com.jogamp.newt.Window;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.util.EDTUtil;
+/**
+ * SWT {@link Canvas} containing a NEWT {@link Window} using native parenting.
+ */
public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol {
private static final boolean DEBUG = Debug.debug("Window");
private static final boolean isOSX = NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(false);
diff --git a/src/newt/classes/jogamp/newt/OffscreenWindow.java b/src/newt/classes/jogamp/newt/OffscreenWindow.java
index ba98ca3af..c6c1814f6 100644
--- a/src/newt/classes/jogamp/newt/OffscreenWindow.java
+++ b/src/newt/classes/jogamp/newt/OffscreenWindow.java
@@ -39,20 +39,16 @@ import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.GraphicsConfigurationFactory;
import javax.media.nativewindow.MutableSurface;
import javax.media.nativewindow.NativeWindowException;
-import javax.media.nativewindow.ProxySurface;
import javax.media.nativewindow.VisualIDHolder;
import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.Point;
public class OffscreenWindow extends WindowImpl implements MutableSurface {
- long surfaceHandle = 0;
- ProxySurface.UpstreamSurfaceHook upstreamHook;
- ProxySurface dummySurface;
+ long surfaceHandle;
public OffscreenWindow() {
- upstreamHook = null;
- dummySurface = null;
+ surfaceHandle = 0;
}
static long nextWindowHandle = 0x100; // start here - a marker
@@ -62,17 +58,6 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface {
throw new NativeWindowException("Capabilities is onscreen");
}
final AbstractGraphicsScreen aScreen = getScreen().getGraphicsScreen();
- /** Cannot use OpenGL here ..
- if(capsRequested instanceof GLCapabilitiesImmutable) {
- final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) capsRequested;
- if(caps.isFBO() && GLContext.isFBOAvailable(aScreen.getDevice(), caps.getGLProfile()) ) {
- final GLDrawableFactoryImpl factory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactory(caps.getGLProfile());
- final GLCapabilitiesImmutable dummyCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(caps);
- final ProxySurface dummySurface = factory.createDummySurfaceImpl(aScreen.getDevice(), false, dummyCaps, null, 64, 64);
- upstreamHook = dummySurface.getUpstreamSurfaceHook();
- dummySurface.createNotify();
- }
- } */
final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(aScreen.getDevice(), capsRequested).chooseGraphicsConfiguration(
capsRequested, capsRequested, capabilitiesChooser, aScreen, VisualIDHolder.VID_UNDEFINED);
if (null == cfg) {
@@ -83,6 +68,7 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface {
synchronized(OffscreenWindow.class) {
setWindowHandle(nextWindowHandle++);
}
+ visibleChanged(false, true);
}
protected void closeNativeImpl() {
@@ -92,11 +78,6 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface {
@Override
public synchronized void destroy() {
super.destroy();
- if(null != dummySurface) {
- dummySurface.destroyNotify();
- dummySurface = null;
- upstreamHook = null;
- }
surfaceHandle = 0;
}
@@ -106,10 +87,6 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface {
@Override
public long getSurfaceHandle() {
- if(null != dummySurface) {
- return dummySurface.getSurfaceHandle();
- // return upstreamHook.getWidth();
- }
return surfaceHandle;
}
@@ -128,8 +105,8 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface {
}
protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
+ sizeChanged(false, width, height, false);
if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) {
- sizeChanged(false, width, height, false);
visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags));
} else {
/**
diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java
index ad7195944..c1ac87d38 100644
--- a/src/newt/classes/jogamp/newt/WindowImpl.java
+++ b/src/newt/classes/jogamp/newt/WindowImpl.java
@@ -767,11 +767,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
- public void setVisible(boolean visible) {
+ protected void setVisible(boolean wait, boolean visible) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window setVisible: START ("+getThreadName()+") "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+this.visible+" -> "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+(null!=parentWindow));
}
- runOnEDTIfAvail(true, new VisibleAction(visible));
+ runOnEDTIfAvail(wait, new VisibleAction(visible));
+ }
+
+ public void setVisible(boolean visible) {
+ setVisible(true, visible);
}
private class SetSizeAction implements Runnable {
@@ -783,21 +787,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
public final void run() {
- boolean recreate = false;
final RecursiveLock _lock = windowLock;
_lock.lock();
try {
if ( !isFullscreen() && ( getWidth() != width || getHeight() != height ) ) {
- recreate = isNativeValid() && !getGraphicsConfiguration().getChosenCapabilities().isOnscreen();
if(DEBUG_IMPLEMENTATION) {
- System.err.println("Window setSize: START "+getWidth()+"x"+getHeight()+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible+", recreate "+recreate);
- }
- if(recreate) {
- // will trigger visibleAction:=2 -> create if wasVisible
- final boolean wasVisible = WindowImpl.this.visible;
- screen.addReference(); // retain screen
- destroyAction.run();
- WindowImpl.this.visible = wasVisible;
+ System.err.println("Window setSize: START "+getWidth()+"x"+getHeight()+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible);
}
int visibleAction; // 0 nop, 1 invisible, 2 visible (create)
if ( isNativeValid() && 0>=width*height && visible ) {
@@ -823,9 +818,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
} finally {
- if(recreate) {
- screen.removeReference(); // bring back ref-count
- }
_lock.unlock();
}
}
@@ -940,11 +932,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
*/
protected static boolean isOffscreenInstance(NativeWindow cWin, NativeWindow pWin) {
boolean ofs = false;
- if( null != cWin.getGraphicsConfiguration() ) {
- ofs = !cWin.getGraphicsConfiguration().getChosenCapabilities().isOnscreen();
+ final AbstractGraphicsConfiguration cWinCfg = cWin.getGraphicsConfiguration();
+ if( null != cWinCfg ) {
+ ofs = !cWinCfg.getChosenCapabilities().isOnscreen();
}
- if( !ofs && null != pWin && null != pWin.getGraphicsConfiguration() ) {
- ofs |= !pWin.getGraphicsConfiguration().getChosenCapabilities().isOnscreen();
+ if( !ofs && null != pWin ) {
+ final AbstractGraphicsConfiguration pWinCfg = pWin.getGraphicsConfiguration();
+ if( null != pWinCfg ) {
+ ofs = !pWinCfg.getChosenCapabilities().isOnscreen();
+ }
}
return ofs;
}
diff --git a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java
index 276b0d070..f18520630 100644
--- a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java
@@ -428,7 +428,7 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 {
getX()+"/"+getY()+" "+nWidth+"x"+nHeight+", visible: "+isVisible());
if(isVisible()) {
- setVisible(true);
+ setVisible(false, true);
}
}
sizeChanged(false, aWidth, aHeight, false);
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
index ea48569bf..d0c0b8b20 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
@@ -117,6 +117,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
return 0 != sscSurfaceHandle ? sscSurfaceHandle : surfaceHandle;
}
+ @Override
public void setSurfaceHandle(long surfaceHandle) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("MacWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle));
@@ -170,13 +171,22 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) {
- final Point pS = getTopLevelLocationOnScreen(x, y);
- isOffscreenInstance = 0 != sscSurfaceHandle || isOffscreenInstance(this, this.getParent());
+ final boolean _isOffscreenInstance = isOffscreenInstance(this, this.getParent());
+ isOffscreenInstance = 0 != sscSurfaceHandle || _isOffscreenInstance;
+ final PointImmutable pS = isOffscreenInstance ? new Point(0, 0) : getTopLevelLocationOnScreen(x, y);
if(DEBUG_IMPLEMENTATION) {
+ final AbstractGraphicsConfiguration cWinCfg = this.getGraphicsConfiguration();
+ final NativeWindow pWin = getParent();
+ final AbstractGraphicsConfiguration pWinCfg = null != pWin ? pWin.getGraphicsConfiguration() : null;
System.err.println("MacWindow reconfig: "+x+"/"+y+" -> "+pS+" - "+width+"x"+height+
- ", offscreenInstance "+isOffscreenInstance+
- ", "+getReconfigureFlagsAsString(null, flags));
+ ",\n\t parent type "+(null != pWin ? pWin.getClass().getName() : null)+
+ ",\n\t this-chosenCaps "+(null != cWinCfg ? cWinCfg.getChosenCapabilities() : null)+
+ ",\n\t parent-chosenCaps "+(null != pWinCfg ? pWinCfg.getChosenCapabilities() : null)+
+ ", isOffscreenInstance(sscSurfaceHandle "+toHexString(sscSurfaceHandle)+
+ ", ioi: "+_isOffscreenInstance+
+ ") -> "+isOffscreenInstance+
+ "\n\t, "+getReconfigureFlagsAsString(null, flags));
}
if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && 0 == ( FLAG_IS_VISIBLE & flags) ) {
@@ -190,7 +200,11 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
0 != ( FLAG_CHANGE_DECORATION & flags) ||
0 != ( FLAG_CHANGE_PARENTING & flags) ||
0 != ( FLAG_CHANGE_FULLSCREEN & flags) ) {
- createWindow(isOffscreenInstance, 0 != getWindowHandle(), pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags));
+ if(isOffscreenInstance) {
+ createWindow(true, 0 != getWindowHandle(), pS, 64, 64, false);
+ } else {
+ createWindow(false, 0 != getWindowHandle(), pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags));
+ }
if(isVisible()) { flags |= FLAG_CHANGE_VISIBILITY; }
}
if(x>=0 && y>=0) {
diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m
index e0330a563..b9c339285 100644
--- a/src/newt/native/MacWindow.m
+++ b/src/newt/native/MacWindow.m
@@ -94,7 +94,13 @@ static void changeContentView(JNIEnv *env, jobject javaWindowObject, NSView *pvi
if(NULL!=oldNSView) {
NS_DURING
// Available >= 10.5 - Makes the menubar disapear
- if([oldNSView isInFullScreenMode]) {
+ BOOL iifs;
+ if ( [oldNSView respondsToSelector:@selector(isInFullScreenMode)] ) {
+ iifs = [oldNSView isInFullScreenMode];
+ } else {
+ iifs = NO;
+ }
+ if(iifs && [oldNSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)] ) {
[oldNSView exitFullScreenModeWithOptions: NULL];
}
NS_HANDLER
@@ -430,6 +436,8 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getScree
if( -1 < mode_idx ) {
prop[propIndex++] = mode_idx;
}
+ int refreshRate = CGDDGetModeRefreshRate(mode);
+ int fRefreshRate = ( 0 < refreshRate ) ? refreshRate : 60; // default .. (experienced on OSX 10.6.8)
prop[propIndex++] = 0; // set later for verification of iterator
propIndexRes = propIndex;
prop[propIndex++] = mWidth;
@@ -437,14 +445,14 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getScree
prop[propIndex++] = CGDDGetModeBitsPerPixel(mode);
prop[propIndex++] = widthMM;
prop[propIndex++] = heightMM;
- prop[propIndex++] = CGDDGetModeRefreshRate(mode);
+ prop[propIndex++] = fRefreshRate;
prop[propIndex++] = ccwRot;
prop[propIndex - NUM_SCREEN_MODE_PROPERTIES_ALL] = ( -1 < mode_idx ) ? propIndex-1 : propIndex ; // count == NUM_SCREEN_MODE_PROPERTIES_ALL
- DBG_PRINT( "getScreenMode0: Mode %d/%d (%d): %dx%d, %d bpp, %dx%d mm, %d Hz, rot %d ccw\n",
+ DBG_PRINT( "getScreenMode0: Mode %d/%d (%d): %dx%d, %d bpp, %dx%d mm, %d / %d Hz, rot %d ccw\n",
(int)mode_idx, (int)numberOfAvailableModesRots, (int)numberOfAvailableModes,
(int)prop[propIndexRes+0], (int)prop[propIndexRes+1], (int)prop[propIndexRes+2],
- (int)prop[propIndexRes+3], (int)prop[propIndexRes+4], (int)prop[propIndexRes+5], (int)prop[propIndexRes+6]);
+ (int)prop[propIndexRes+3], (int)prop[propIndexRes+4], (int)prop[propIndexRes+5], refreshRate, (int)prop[propIndexRes+6]);
jintArray properties = (*env)->NewIntArray(env, prop_num);
if (properties == NULL) {
@@ -516,6 +524,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initIDs0
if(initialized) return JNI_TRUE;
initialized = 1;
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
jclass c;
c = (*env)->FindClass(env, ClazzNamePoint);
if(NULL==c) {
@@ -537,7 +547,10 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initIDs0
// printf("Going to sleep for 10 seconds\n");
// sleep(10);
- return (jboolean) [NewtMacWindow initNatives: env forClass: clazz];
+ BOOL res = [NewtMacWindow initNatives: env forClass: clazz];
+ [pool release];
+
+ return (jboolean) res;
}
/*
@@ -602,8 +615,10 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createWindow
// Remove animations for child windows
if(NULL != parentWindow) {
NS_DURING
- // Available >= 10.7 - Removes default animations
- [myWindow setAnimationBehavior: NSWindowAnimationBehaviorNone];
+ if ( [myWindow respondsToSelector:@selector(setAnimationBehavior:)] ) {
+ // Available >= 10.7 - Removes default animations
+ [myWindow setAnimationBehavior: NSWindowAnimationBehaviorNone];
+ }
NS_HANDLER
NS_ENDHANDLER
}
@@ -658,8 +673,12 @@ NS_ENDHANDLER
NS_DURING
// concurrent view rendering
// Available >= 10.6 - Makes the menubar disapear
- [myWindow setAllowsConcurrentViewDrawing: YES];
- [myView setCanDrawConcurrently: YES];
+ if ( [myWindow respondsToSelector:@selector(setAllowsConcurrentViewDrawing:)] ) {
+ [myWindow setAllowsConcurrentViewDrawing: YES];
+ }
+ if ( [myView respondsToSelector:@selector(setCanDrawConcurrently:)] ) {
+ [myView setCanDrawConcurrently: YES];
+ }
NS_HANDLER
NS_ENDHANDLER
@@ -669,7 +688,9 @@ NS_ENDHANDLER
NS_DURING
// Available >= 10.5 - Makes the menubar disapear
if(fullscreen) {
- [myView enterFullScreenMode: myScreen withOptions:NULL];
+ if ( [myView respondsToSelector:@selector(enterFullScreenMode:withOptions:)] ) {
+ [myView enterFullScreenMode: myScreen withOptions:NULL];
+ }
}
NS_HANDLER
NS_ENDHANDLER
@@ -730,7 +751,13 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_close0
NS_DURING
if(NULL!=mView) {
// Available >= 10.5 - Makes the menubar disapear
- if([mView isInFullScreenMode]) {
+ BOOL iifs;
+ if ( [mView respondsToSelector:@selector(isInFullScreenMode)] ) {
+ iifs = [mView isInFullScreenMode];
+ } else {
+ iifs = NO;
+ }
+ if(iifs && [mView respondsToSelector:@selector(exitFullScreenModeWithOptions:)] ) {
[mView exitFullScreenModeWithOptions: NULL];
}
// Note: mWin's release will also release it's mView!
diff --git a/src/test/com/jogamp/opengl/test/android/MovieCubeActivityLauncher0.java b/src/test/com/jogamp/opengl/test/android/MovieCubeActivityLauncher0.java
index 4f24fc9b8..c4b74c56f 100644
--- a/src/test/com/jogamp/opengl/test/android/MovieCubeActivityLauncher0.java
+++ b/src/test/com/jogamp/opengl/test/android/MovieCubeActivityLauncher0.java
@@ -50,6 +50,8 @@ public class MovieCubeActivityLauncher0 extends LauncherUtil.BaseActivityLaunche
// props.setProperty("jogamp.debug.NativeLibrary", "true");
// props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true");
// props.setProperty("jogamp.debug.IOUtil", "true");
+ // props.setProperty("jogamp.debug.Lock", "true");
+ // props.setProperty("jogamp.debug.Lock.TraceLock", "true");
// props.setProperty("nativewindow.debug", "all");
props.setProperty("nativewindow.debug.GraphicsConfiguration", "true");
// props.setProperty("jogl.debug", "all");
diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivityLauncher.java b/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivityLauncher.java
index c75c229a8..576305835 100644
--- a/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivityLauncher.java
+++ b/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivityLauncher.java
@@ -14,23 +14,23 @@ public class NEWTGraphUI1pActivityLauncher extends LauncherUtil.BaseActivityLaun
final OrderedProperties props = getProperties();
// props.setProperty("jogamp.debug.JNILibLoader", "true");
// props.setProperty("jogamp.debug.NativeLibrary", "true");
- // properties.setProperty("jogamp.debug.NativeLibrary.Lookup", "true");
- // properties.setProperty("jogamp.debug.IOUtil", "true");
- // properties.setProperty("nativewindow.debug", "all");
+ // props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true");
+ // props.setProperty("jogamp.debug.IOUtil", "true");
+ // props.setProperty("nativewindow.debug", "all");
props.setProperty("nativewindow.debug.GraphicsConfiguration", "true");
- // properties.setProperty("jogl.debug", "all");
- // properties.setProperty("jogl.debug.GLProfile", "true");
+ // props.setProperty("jogl.debug", "all");
+ // props.setProperty("jogl.debug.GLProfile", "true");
props.setProperty("jogl.debug.GLDrawable", "true");
props.setProperty("jogl.debug.GLContext", "true");
props.setProperty("jogl.debug.GLSLCode", "true");
props.setProperty("jogl.debug.CapabilitiesChooser", "true");
- // properties.setProperty("jogl.debug.GLSLState", "true");
- // properties.setProperty("jogl.debug.DebugGL", "true");
- // properties.setProperty("jogl.debug.TraceGL", "true");
- // properties.setProperty("newt.debug", "all");
+ // props.setProperty("jogl.debug.GLSLState", "true");
+ // props.setProperty("jogl.debug.DebugGL", "true");
+ // props.setProperty("jogl.debug.TraceGL", "true");
+ // props.setProperty("newt.debug", "all");
props.setProperty("newt.debug.Window", "true");
- // properties.setProperty("newt.debug.Window.MouseEvent", "true");
- // properties.setProperty("newt.debug.Window.KeyEvent", "true");
+ // props.setProperty("newt.debug.Window.MouseEvent", "true");
+ // props.setProperty("newt.debug.Window.KeyEvent", "true");
}
@Override
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableDeadlockAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableDeadlockAWT.java
new file mode 100644
index 000000000..eab1a37e3
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableDeadlockAWT.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.test.junit.jogl.acore;
+
+import java.awt.EventQueue;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.media.opengl.DefaultGLCapabilitiesChooser;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLOffscreenAutoDrawable;
+import javax.media.opengl.GLProfile;
+
+import jogamp.nativewindow.jawt.JAWTUtil;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.jogamp.common.util.RunnableTask;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+public class TestFBOAutoDrawableDeadlockAWT extends UITestCase {
+ static GLProfile glp;
+ static int width, height;
+
+ @BeforeClass
+ public static void initClass() {
+ glp = GLProfile.getGL2ES2();
+ Assert.assertNotNull( glp );
+ width = 512;
+ height = 512;
+ }
+
+ protected void runTestGL( GLCapabilities caps ) throws InterruptedException, InvocationTargetException {
+ final GLOffscreenAutoDrawable fbod = GLDrawableFactory.getFactory(caps.getGLProfile()).createOffscreenAutoDrawable(
+ null,
+ caps, new DefaultGLCapabilitiesChooser(),
+ 512, 512,
+ null
+ );
+
+ final boolean[] done = {false};
+ final Runnable pbufferCreationAction = new Runnable() {
+ public void run() {
+ System.err.println("AA.1");
+ fbod.display();
+ done[ 0 ] = true;
+ System.err.println("AA.X");
+ }
+ };
+
+ EventQueue.invokeAndWait(new Runnable() {
+ public void run() {
+ Assert.assertTrue(EventQueue.isDispatchThread());
+ JAWTUtil.lockToolkit();
+ try {
+ final RunnableTask rTask = new RunnableTask(pbufferCreationAction, new Object(), false);
+ System.err.println("BB.0: "+rTask.getSyncObject());
+ synchronized (rTask.getSyncObject()) {
+ System.err.println("BB.1: "+rTask.getSyncObject());
+ new Thread(rTask, Thread.currentThread().getName()+"-Pbuffer_Creation").start();
+ try {
+ System.err.println("BB.2");
+ rTask.getSyncObject().wait();
+ System.err.println("BB.3");
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ System.err.println("BB.X");
+ }
+ } finally {
+ JAWTUtil.unlockToolkit();
+ }
+ }
+ });
+ Assert.assertTrue(done[0]);
+ fbod.destroy();
+ }
+
+ @Test(timeout = 2000) // 2s timeout
+ public void testDeadlock() throws InterruptedException, InvocationTargetException {
+ GLCapabilities caps = new GLCapabilities( glp );
+ runTestGL( caps );
+ }
+
+ static long duration = 500; // ms
+
+ public static void main( String args[] ) {
+ for ( int i = 0; i < args.length; i++ ) {
+ if ( args[ i ].equals( "-time" ) ) {
+ i++;
+ try {
+ duration = Integer.parseInt( args[ i ] );
+ }
+ catch ( Exception ex ) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ org.junit.runner.JUnitCore.main( TestFBOAutoDrawableDeadlockAWT.class.getName() );
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableFactoryNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableFactoryNEWT.java
new file mode 100644
index 000000000..2dc547f39
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableFactoryNEWT.java
@@ -0,0 +1,375 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.jogl.acore;
+
+import java.io.IOException;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLOffscreenAutoDrawable;
+import javax.media.opengl.GLProfile;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.jogamp.opengl.FBObject;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.FBOMix2DemosES2;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.MultisampleDemoES2;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+/**
+ * Toolkit agnostic {@link GLOffscreenAutoDrawable.FBO} tests using the
+ * {@link GLDrawableFactory#createOffscreenAutoDrawable(javax.media.nativewindow.AbstractGraphicsDevice, GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, int, int, GLContext) factory model}.
+ *
+ * The created {@link GLOffscreenAutoDrawable.FBO} is being used to run the {@link GLEventListener}.
+ *
+ *
+ * Extensive FBO reconfiguration (size and sample buffer count) and validation are performed.
+ *
+ */
+public class TestFBOAutoDrawableFactoryNEWT extends UITestCase {
+
+ static final int widthStep = 800/4;
+ static final int heightStep = 600/4;
+ volatile int szStep = 2;
+
+ interface MyGLEventListener extends GLEventListener {
+ void setMakeSnapshot();
+ }
+
+ @Test
+ public void testGL2ES2_Demo1_SingleBuffer_Normal() throws InterruptedException {
+ final GLProfile glp = GLProfile.getGL2ES2();
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setDoubleBuffered(false);
+ testGLFBODrawableImpl(caps, new GearsES2(0));
+ }
+
+ @Test
+ public void testGL2ES2_Demo1_DoubleBuffer_Normal() throws InterruptedException {
+ final GLProfile glp = GLProfile.getGL2ES2();
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setDoubleBuffered(true); // default
+ testGLFBODrawableImpl(caps, new GearsES2(0));
+ }
+
+ @Test
+ public void testGL2ES2_Demo2MSAA4() throws InterruptedException {
+ final GLProfile glp = GLProfile.getGL2ES2();
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4);
+ testGLFBODrawableImpl(caps, new MultisampleDemoES2(true));
+ }
+
+ @Test
+ public void testGL2ES2_FBODemoMSAA4() throws InterruptedException {
+ final GLProfile glp = GLProfile.getGL2ES2();
+ final FBOMix2DemosES2 demo = new FBOMix2DemosES2(0);
+ demo.setDoRotation(false);
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4);
+ testGLFBODrawableImpl(caps, demo);
+ }
+
+ @Test
+ public void testEGLES2_Demo0Normal() throws InterruptedException {
+ if( GLProfile.isAvailable(GLProfile.GLES2) ) {
+ final GLProfile glp = GLProfile.get(GLProfile.GLES2);
+ final GLCapabilities caps = new GLCapabilities(glp);
+ testGLFBODrawableImpl(caps, new GearsES2(0));
+ } else {
+ System.err.println("EGL ES2 n/a");
+ }
+ }
+
+ @Test
+ public void testEGLES2_Demo0MSAA4() throws InterruptedException {
+ if( GLProfile.isAvailable(GLProfile.GLES2) ) {
+ final GLProfile glp = GLProfile.get(GLProfile.GLES2);
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4);
+ testGLFBODrawableImpl(caps, new GearsES2(0));
+ } else {
+ System.err.println("EGL ES2 n/a");
+ }
+ }
+
+ void testGLFBODrawableImpl(GLCapabilities caps, GLEventListener demo) throws InterruptedException {
+ caps.setFBO(true);
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
+ final GLOffscreenAutoDrawable.FBO glad = (GLOffscreenAutoDrawable.FBO)
+ factory.createOffscreenAutoDrawable(null, caps, null, widthStep*szStep, heightStep*szStep, null);
+ Assert.assertNotNull(glad);
+
+ System.out.println("Realized GLAD: "+glad);
+ System.out.println("Realized GLAD: "+glad.getChosenGLCapabilities());
+ Assert.assertTrue("FBO drawable is initialized before ctx creation", !glad.isInitialized());
+
+ glad.display(); // initial display incl. init!
+ {
+ final GLContext context = glad.getContext();
+ Assert.assertNotNull(context);
+ Assert.assertTrue(context.isCreated());
+ }
+ Assert.assertTrue("FBO drawable is not initialized after ctx creation", glad.isInitialized());
+
+ //
+ // FBO incl. MSAA is fully initialized now
+ //
+
+ final GLCapabilitiesImmutable chosenCaps = glad.getChosenGLCapabilities();
+ System.out.println("Init GLAD: "+glad);
+ System.out.println("Init GLAD: "+chosenCaps);
+
+ final FBObject fboFront = glad.getFBObject(GL.GL_FRONT);
+ final FBObject fboBack = glad.getFBObject(GL.GL_BACK);
+
+ System.out.println("Init front FBO: "+fboFront);
+ System.out.println("Init back FBO: "+fboBack);
+
+ Assert.assertTrue("FBO drawable is not initialized before ctx creation", glad.isInitialized());
+ Assert.assertTrue("FBO Front is not initialized before ctx creation", fboFront.isInitialized());
+ Assert.assertTrue("FBO Back is not initialized before ctx creation", fboBack.isInitialized());
+
+ if( chosenCaps.getDoubleBuffered() ) {
+ Assert.assertTrue("FBO are equal: "+fboFront+" == "+fboBack, !fboFront.equals(fboBack));
+ Assert.assertNotSame(fboFront, fboBack);
+ } else {
+ Assert.assertTrue("FBO are not equal: "+fboFront+" != "+fboBack, fboFront.equals(fboBack));
+ Assert.assertSame(fboFront, fboBack);
+ }
+
+ final FBObject.TextureAttachment texAttachA, texAttachB;
+
+ texAttachA = glad.getTextureBuffer(GL.GL_FRONT);
+ if(0==glad.getNumSamples()) {
+ texAttachB = glad.getTextureBuffer(GL.GL_BACK);
+ } else {
+ texAttachB = null;
+ }
+
+ final FBObject.Colorbuffer colorA, colorB;
+ final FBObject.RenderAttachment depthA, depthB;
+
+ colorA = fboFront.getColorbuffer(0);
+ Assert.assertNotNull(colorA);
+ colorB = fboBack.getColorbuffer(0);
+ Assert.assertNotNull(colorB);
+
+ depthA = fboFront.getDepthAttachment();
+ Assert.assertNotNull(depthA);
+ depthB = fboBack.getDepthAttachment();
+ Assert.assertNotNull(depthB);
+
+ glad.display(); // SWAP_ODD
+
+ if( chosenCaps.getDoubleBuffered() ) {
+ // double buffer or MSAA
+ Assert.assertTrue("Color attachments are equal: "+colorB+" == "+colorA, !colorB.equals(colorA));
+ Assert.assertNotSame(colorB, colorA);
+ Assert.assertTrue("Depth attachments are equal: "+depthB+" == "+depthA, !depthB.equals(depthA));
+ Assert.assertNotSame(depthB, depthA);
+ } else {
+ // single buffer
+ Assert.assertEquals(colorA, colorB);
+ Assert.assertSame(colorA, colorB);
+ Assert.assertEquals(depthA, depthB);
+ Assert.assertSame(depthA, depthB);
+ }
+
+ Assert.assertEquals(texAttachA, colorA);
+ Assert.assertSame(texAttachA, colorA);
+ if(0==glad.getNumSamples()) {
+ Assert.assertEquals(texAttachB, colorB);
+ Assert.assertSame(texAttachB, colorB);
+ }
+
+ if( chosenCaps.getNumSamples() > 0 ) {
+ // MSAA
+ FBObject _fboFront = glad.getFBObject(GL.GL_FRONT);
+ FBObject _fboBack = glad.getFBObject(GL.GL_BACK);
+ Assert.assertTrue("FBO are not equal: "+fboFront+" != "+_fboFront, fboFront.equals(_fboFront));
+ Assert.assertSame(fboFront, _fboFront);
+ Assert.assertTrue("FBO are not equal: "+fboBack+" != "+_fboBack, fboBack.equals(_fboBack));
+ Assert.assertSame(fboBack, _fboBack);
+ } else if( chosenCaps.getDoubleBuffered() ) {
+ // real double buffer
+ FBObject _fboFront = glad.getFBObject(GL.GL_FRONT);
+ FBObject _fboBack = glad.getFBObject(GL.GL_BACK);
+ Assert.assertTrue("FBO are not equal: "+fboBack+" != "+_fboFront, fboBack.equals(_fboFront));
+ Assert.assertSame(fboBack, _fboFront);
+ Assert.assertTrue("FBO are not equal: "+fboFront+" != "+_fboBack, fboFront.equals(_fboBack));
+ Assert.assertSame(fboFront, _fboBack);
+ } else {
+ // single buffer
+ FBObject _fboFront = glad.getFBObject(GL.GL_FRONT);
+ FBObject _fboBack = glad.getFBObject(GL.GL_BACK);
+ Assert.assertTrue("FBO are not equal: "+fboFront+" != "+_fboFront, fboFront.equals(_fboFront));
+ Assert.assertSame(fboFront, _fboFront);
+ Assert.assertTrue("FBO are not equal: "+fboBack+" != "+_fboFront, fboBack.equals(_fboFront));
+ Assert.assertSame(fboBack, _fboFront);
+ Assert.assertTrue("FBO are not equal: "+fboBack+" != "+_fboBack, fboBack.equals(_fboBack));
+ Assert.assertSame(fboBack, _fboBack);
+ Assert.assertTrue("FBO are not equal: "+fboFront+" != "+_fboBack, fboFront.equals(_fboBack));
+ Assert.assertSame(fboFront, _fboBack);
+ }
+
+ glad.addGLEventListener(demo);
+
+ final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener();
+ glad.addGLEventListener(snapshotGLEventListener);
+
+ glad.display(); // - SWAP_EVEN
+
+ // 1 - szStep = 2
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display(); // - SWAP_ODD
+
+ // 2, 3 (resize + display)
+ szStep = 1;
+ glad.setSize(widthStep*szStep, heightStep*szStep); // SWAP_EVEN
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display(); // - SWAP_ODD
+ glad.display(); // - SWAP_EVEN
+ {
+ // Check whether the attachment reference are still valid!
+ final FBObject _fboFront = glad.getFBObject(GL.GL_FRONT);
+ final FBObject _fboBack = glad.getFBObject(GL.GL_BACK);
+ System.out.println("Resize1.oldFront: "+fboFront);
+ System.out.println("Resize1.nowFront: "+_fboFront);
+ System.out.println("Resize1.oldBack : "+fboBack);
+ System.out.println("Resize1.nowBack : "+_fboBack);
+ Assert.assertEquals(fboFront, _fboFront);
+ Assert.assertSame(fboFront, _fboFront);
+ Assert.assertEquals(fboBack, _fboBack);
+ Assert.assertSame(fboBack, _fboBack);
+
+ FBObject.Colorbuffer _color = _fboFront.getColorbuffer(0);
+ Assert.assertNotNull(_color);
+ Assert.assertEquals(colorA, _color);
+ Assert.assertSame(colorA, _color);
+
+ FBObject.RenderAttachment _depth = _fboFront.getDepthAttachment();
+ System.err.println("Resize1.oldDepth "+depthA);
+ System.err.println("Resize1.newDepth "+_depth);
+ Assert.assertNotNull(_depth);
+
+ Assert.assertEquals(depthA, _depth);
+ Assert.assertSame(depthA, _depth);
+ _depth = _fboBack.getDepthAttachment();
+ Assert.assertNotNull(_depth);
+ Assert.assertEquals(depthB, _depth);
+ Assert.assertSame(depthB, _depth);
+
+ _color = _fboFront.getColorbuffer(colorA);
+ Assert.assertNotNull(_color);
+ Assert.assertEquals(colorA, _color);
+ Assert.assertSame(colorA, _color);
+ }
+
+ // 4, 5 (resize + display)
+ szStep = 4;
+ glad.setSize(widthStep*szStep, heightStep*szStep); // SWAP_ODD
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display(); // - SWAP_EVEN
+ glad.display(); // - SWAP_ODD
+ {
+ // Check whether the attachment reference are still valid!
+ final FBObject _fboFront = glad.getFBObject(GL.GL_FRONT);
+ final FBObject _fboBack = glad.getFBObject(GL.GL_BACK);
+ System.out.println("Resize2.oldFront: "+fboFront);
+ System.out.println("Resize2.nowFront: "+_fboFront);
+ System.out.println("Resize2.oldBack : "+fboBack);
+ System.out.println("Resize2.nowBack : "+_fboBack);
+ if(chosenCaps.getDoubleBuffered() && 0==chosenCaps.getNumSamples()) {
+ // real double buffer
+ Assert.assertEquals(fboBack, _fboFront);
+ Assert.assertEquals(fboFront, _fboBack);
+ } else {
+ // single or MSAA
+ Assert.assertEquals(fboFront, _fboFront);
+ Assert.assertEquals(fboBack, _fboBack);
+ }
+
+ FBObject.Colorbuffer _color = fboBack.getColorbuffer(0);
+ Assert.assertNotNull(_color);
+ Assert.assertEquals(colorB, _color);
+ Assert.assertSame(colorB, _color);
+
+ FBObject.RenderAttachment _depth = fboBack.getDepthAttachment();
+ Assert.assertNotNull(_depth); // MSAA back w/ depth
+ Assert.assertEquals(depthB, _depth);
+ Assert.assertSame(depthB, _depth);
+
+ _depth = fboFront.getDepthAttachment();
+ Assert.assertNotNull(_depth);
+ Assert.assertEquals(depthA, _depth);
+ Assert.assertSame(depthA, _depth);
+
+ _color = fboBack.getColorbuffer(colorB);
+ Assert.assertNotNull(_color);
+ Assert.assertEquals(colorB, _color);
+ Assert.assertSame(colorB, _color);
+ }
+
+ // 6 + 7 (samples + display)
+ glad.setNumSamples(glad.getGL(), chosenCaps.getNumSamples() > 0 ? 0 : 4); // triggers repaint
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display(); // actual screenshot
+
+ // 8, 9 (resize + samples + display)
+ szStep = 3;
+ glad.setSize(widthStep*szStep, heightStep*szStep);
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ glad.destroy();
+ System.out.println("Fin: "+glad);
+ }
+
+ public static void main(String args[]) throws IOException {
+ org.junit.runner.JUnitCore.main(TestFBOAutoDrawableFactoryNEWT.class.getName());
+ }
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBODrawableNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBODrawableNEWT.java
deleted file mode 100644
index 7977347a7..000000000
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBODrawableNEWT.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/**
- * Copyright 2012 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
-
-package com.jogamp.opengl.test.junit.jogl.acore;
-
-import java.io.IOException;
-
-import javax.media.opengl.GL;
-import javax.media.opengl.GLAutoDrawable;
-import javax.media.opengl.GLCapabilities;
-import javax.media.opengl.GLContext;
-import javax.media.opengl.GLDrawable;
-import javax.media.opengl.GLDrawableFactory;
-import javax.media.opengl.GLEventListener;
-import javax.media.opengl.GLProfile;
-
-import jogamp.opengl.GLFBODrawableImpl;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import com.jogamp.opengl.FBObject;
-import com.jogamp.opengl.OffscreenAutoDrawable;
-import com.jogamp.opengl.test.junit.jogl.demos.es2.FBOMix2DemosES2;
-import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
-import com.jogamp.opengl.test.junit.jogl.demos.es2.MultisampleDemoES2;
-import com.jogamp.opengl.test.junit.util.UITestCase;
-import com.jogamp.opengl.util.GLReadBufferUtil;
-import com.jogamp.opengl.util.texture.TextureIO;
-
-public class TestFBODrawableNEWT extends UITestCase {
-
- static final int widthStep = 800/4;
- static final int heightStep = 600/4;
- volatile int szStep = 2;
-
- @Test
- public void testGL2ES2_Demo1Normal() throws InterruptedException {
- final GLProfile glp = GLProfile.getGL2ES2();
- final GLCapabilities caps = new GLCapabilities(glp);
- testGLFBODrawableImpl(caps, new GearsES2(0));
- }
-
- @Test
- public void testGL2ES2_Demo1MSAA4() throws InterruptedException {
- final GLProfile glp = GLProfile.getGL2ES2();
- final GLCapabilities caps = new GLCapabilities(glp);
- caps.setSampleBuffers(true);
- caps.setNumSamples(4);
- testGLFBODrawableImpl(caps, new GearsES2(0));
- }
-
- @Test
- public void testGL2ES2_Demo2Normal() throws InterruptedException {
- final GLProfile glp = GLProfile.getGL2ES2();
- final GLCapabilities caps = new GLCapabilities(glp);
- testGLFBODrawableImpl(caps, new MultisampleDemoES2(false));
- }
-
- @Test
- public void testGL2ES2_Demo2MSAA4() throws InterruptedException {
- final GLProfile glp = GLProfile.getGL2ES2();
- final GLCapabilities caps = new GLCapabilities(glp);
- caps.setSampleBuffers(true);
- caps.setNumSamples(4);
- testGLFBODrawableImpl(caps, new MultisampleDemoES2(true));
- }
-
- @Test
- public void testGL2ES2_FBODemoNormal() throws InterruptedException {
- final GLProfile glp = GLProfile.getGL2ES2();
- final FBOMix2DemosES2 demo = new FBOMix2DemosES2(0);
- demo.setDoRotation(false);
- final GLCapabilities caps = new GLCapabilities(glp);
- testGLFBODrawableImpl(caps, demo);
- }
-
- @Test
- public void testGL2ES2_FBODemoMSAA4() throws InterruptedException {
- final GLProfile glp = GLProfile.getGL2ES2();
- final FBOMix2DemosES2 demo = new FBOMix2DemosES2(0);
- demo.setDoRotation(false);
- final GLCapabilities caps = new GLCapabilities(glp);
- caps.setSampleBuffers(true);
- caps.setNumSamples(4);
- testGLFBODrawableImpl(caps, demo);
- }
-
- @Test
- public void testEGLES2_Demo0Normal() throws InterruptedException {
- if( GLProfile.isAvailable(GLProfile.GLES2) ) {
- final GLProfile glp = GLProfile.get(GLProfile.GLES2);
- final GLCapabilities caps = new GLCapabilities(glp);
- testGLFBODrawableImpl(caps, new GearsES2(0));
- } else {
- System.err.println("EGL ES2 n/a");
- }
- }
-
- @Test
- public void testEGLES2_Demo0MSAA4() throws InterruptedException {
- if( GLProfile.isAvailable(GLProfile.GLES2) ) {
- final GLProfile glp = GLProfile.get(GLProfile.GLES2);
- final GLCapabilities caps = new GLCapabilities(glp);
- caps.setSampleBuffers(true);
- caps.setNumSamples(4);
- testGLFBODrawableImpl(caps, new GearsES2(0));
- } else {
- System.err.println("EGL ES2 n/a");
- }
- }
-
- boolean skipShot = false;
-
- void testGLFBODrawableImpl(GLCapabilities caps, GLEventListener demo) throws InterruptedException {
- final GLReadBufferUtil screenshot = new GLReadBufferUtil(false, false);
- caps.setFBO(true);
- final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
- final GLDrawable fboDrawable = factory.createOffscreenDrawable(null, caps, null, widthStep*szStep, heightStep*szStep);
- Assert.assertNotNull(fboDrawable);
- Assert.assertTrue("Not an FBO Drawable", fboDrawable instanceof GLFBODrawableImpl);
-
- fboDrawable.setRealized(true);
- Assert.assertTrue(fboDrawable.isRealized());
-
- final FBObject fbo = ((GLFBODrawableImpl)fboDrawable).getFBObject();
-
- System.out.println("Realized: "+fboDrawable);
- System.out.println("Realized: "+fboDrawable.getChosenGLCapabilities());
- System.out.println("Realized: "+fbo);
-
- final GLContext context = fboDrawable.createContext(null);
- Assert.assertNotNull(context);
-
- int res = context.makeCurrent();
- Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res);
- context.release();
-
- System.out.println("Post Create-Ctx: "+fbo);
- final FBObject.Colorbuffer colorA = fbo.getColorbuffer(0);
- Assert.assertNotNull(colorA);
- final FBObject.RenderAttachment depthA = fbo.getDepthAttachment();
- Assert.assertNotNull(depthA);
-
- final OffscreenAutoDrawable glad = new OffscreenAutoDrawable(fboDrawable, context, true);
-
- glad.addGLEventListener(demo);
- glad.addGLEventListener(new GLEventListener() {
- volatile int displayCount=0;
- volatile int reshapeCount=0;
- public void init(GLAutoDrawable drawable) {}
- public void dispose(GLAutoDrawable drawable) {}
- public void display(GLAutoDrawable drawable) {
- final GL gl = drawable.getGL();
- // System.err.println(Thread.currentThread().getName()+": ** display: "+displayCount+": step "+szStep+" "+drawable.getWidth()+"x"+drawable.getHeight());
- // System.err.println(Thread.currentThread().getName()+": ** FBO-THIS: "+fbo);
- // System.err.println(Thread.currentThread().getName()+": ** FBO-SINK: "+fbo.getSamplingSinkFBO());
- // System.err.println(Thread.currentThread().getName()+": ** drawable-read: "+gl.getDefaultReadFramebuffer());
- if(skipShot) {
- skipShot=false;
- } else {
- snapshot(getSimpleTestName("."), displayCount, "msaa"+fbo.getNumSamples(), gl, screenshot, TextureIO.PNG, null);
- }
- Assert.assertEquals(drawable.getWidth(), widthStep*szStep);
- Assert.assertEquals(drawable.getHeight(), heightStep*szStep);
- displayCount++;
- }
- public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
- System.err.println(Thread.currentThread().getName()+": ** reshape: "+reshapeCount+": step "+szStep+" "+width+"x"+height+" - "+drawable.getWidth()+"x"+drawable.getHeight());
- Assert.assertEquals(drawable.getWidth(), widthStep*szStep);
- Assert.assertEquals(drawable.getHeight(), heightStep*szStep);
- reshapeCount++;
- }
- });
-
- // 0 - szStep = 2
- glad.display();
-
- // 1, 2 (resize + display)
- szStep = 1;
- skipShot=true;
- glad.setSize(widthStep*szStep, heightStep*szStep);
- glad.display();
- Assert.assertEquals(glad.getWidth(), widthStep*szStep);
- Assert.assertEquals(glad.getHeight(), heightStep*szStep);
- {
- // Check whether the attachment reference are still valid!
- FBObject.Colorbuffer _colorA = fbo.getColorbuffer(0);
- Assert.assertNotNull(_colorA);
- Assert.assertTrue(colorA == _colorA);
- Assert.assertTrue(colorA.equals(_colorA));
- FBObject.RenderAttachment _depthA = fbo.getDepthAttachment();
- Assert.assertNotNull(_depthA);
- Assert.assertTrue(depthA == _depthA);
- Assert.assertTrue(depthA.equals(_depthA));
-
- _colorA = fbo.getColorbuffer(colorA);
- Assert.assertNotNull(_colorA);
- Assert.assertTrue(colorA == _colorA);
- Assert.assertTrue(colorA.equals(_colorA));
- }
-
- // 3, 4 (resize + display)
- szStep = 4;
- skipShot=true;
- glad.setSize(widthStep*szStep, heightStep*szStep);
- glad.display();
- Assert.assertEquals(glad.getWidth(), widthStep*szStep);
- Assert.assertEquals(glad.getHeight(), heightStep*szStep);
- {
- // Check whether the attachment reference are still valid!
- FBObject.Colorbuffer _colorA = fbo.getColorbuffer(0);
- Assert.assertNotNull(_colorA);
- Assert.assertTrue(colorA == _colorA);
- final FBObject.RenderAttachment _depthA = fbo.getDepthAttachment();
- Assert.assertNotNull(_depthA);
- Assert.assertTrue(depthA == _depthA);
-
- _colorA = fbo.getColorbuffer(colorA);
- Assert.assertNotNull(_colorA);
- Assert.assertTrue(colorA == _colorA);
- }
-
- // 5
- glad.display();
- Assert.assertEquals(glad.getWidth(), widthStep*szStep);
- Assert.assertEquals(glad.getHeight(), heightStep*szStep);
-
- // 6, 7 (resize + display)
- szStep = 3;
- skipShot=true;
- glad.setSize(widthStep*szStep, heightStep*szStep);
- glad.display();
- Assert.assertEquals(glad.getWidth(), widthStep*szStep);
- Assert.assertEquals(glad.getHeight(), heightStep*szStep);
-
- glad.destroy();
- System.out.println("Fin: "+fboDrawable);
-
- // final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(fboDrawable, context);
- }
-
- public static void main(String args[]) throws IOException {
- org.junit.runner.JUnitCore.main(TestFBODrawableNEWT.class.getName());
- }
-
-}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMRTNEWT01.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMRTNEWT01.java
index f7c83a03b..077baad43 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMRTNEWT01.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMRTNEWT01.java
@@ -229,7 +229,7 @@ public class TestFBOMRTNEWT01 extends UITestCase {
final NativeSurface ns = gl.getContext().getGLReadDrawable().getNativeSurface();
if(last_snap_size[0] != ns.getWidth() && last_snap_size[1] != ns.getHeight()) {
gl.glFinish(); // sync .. no swap buffers yet!
- snapshot(getSimpleTestName("."), step_i, null, gl, screenshot, TextureIO.PNG, null); // overwrite ok
+ snapshot(step_i, null, gl, screenshot, TextureIO.PNG, null); // overwrite ok
last_snap_size[0] = ns.getWidth();
last_snap_size[1] = ns.getHeight();
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMix2DemosES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMix2DemosES2NEWT.java
index b384c9327..b3c542c63 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMix2DemosES2NEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMix2DemosES2NEWT.java
@@ -106,7 +106,7 @@ public class TestFBOMix2DemosES2NEWT extends UITestCase {
if(dw<800) {
System.err.println("XXX: "+dw+"x"+dh+", c "+c);
if(0 == c%3) {
- snapshot(getSimpleTestName("."), i++, "msaa"+demo.getMSAA(), drawable.getGL(), screenshot, TextureIO.PNG, null);
+ snapshot(i++, "msaa"+demo.getMSAA(), drawable.getGL(), screenshot, TextureIO.PNG, null);
}
if( 3 == c ) {
new Thread() {
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOffThreadSharedContextMix2DemosES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOffThreadSharedContextMix2DemosES2NEWT.java
new file mode 100644
index 000000000..3ecf89bfc
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOffThreadSharedContextMix2DemosES2NEWT.java
@@ -0,0 +1,298 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.jogl.acore;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
+import com.jogamp.opengl.test.junit.util.MiscUtils;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+import com.jogamp.opengl.test.junit.util.QuitAdapter;
+
+import com.jogamp.opengl.util.Animator;
+import com.jogamp.opengl.util.FPSAnimator;
+import com.jogamp.opengl.util.GLReadBufferUtil;
+import com.jogamp.opengl.util.texture.TextureIO;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.Mix2TexturesES2;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.SurfaceUpdatedListener;
+import javax.media.opengl.GL;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLOffscreenAutoDrawable;
+import javax.media.opengl.GLProfile;
+
+import org.junit.Assert;
+import org.junit.AfterClass;
+import org.junit.Test;
+
+/**
+ * Toolkit agnostic {@link GLOffscreenAutoDrawable.FBO} tests using the
+ * {@link GLDrawableFactory#createOffscreenAutoDrawable(javax.media.nativewindow.AbstractGraphicsDevice, GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, int, int, GLContext) factory model}.
+ *
+ * The created {@link GLOffscreenAutoDrawable.FBO} is being used to run the {@link GLEventListener}.
+ *
+ *
+ * This test simulates shared off-thread GL context / texture usage,
+ * where the producer use FBOs and delivers shared textures.
+ * The receiver blends the shared textures onscreen.
+ * In detail the test consist of:
+ *
each with their own {@link GLContext}, which is shares the {@link GLWindow} one (see below)
+ *
both run within one {@link FPSAnimator} @ 30fps
+ *
produce a texture
+ *
notify the onscreen renderer about new textureID (swapping double buffer)
+ *
+ *
1 onscreen {@link GLWindow}
+ *
+ *
shares it's {@link GLContext} w/ above FBOs
+ *
running within one {@link Animator} at v-sync
+ *
uses the shared FBO textures and blends them onscreen
+ *
+ *
+ *
+ */
+public class TestFBOOffThreadSharedContextMix2DemosES2NEWT extends UITestCase {
+ static long duration = 500; // ms
+ static int swapInterval = 1;
+ static boolean showFPS = false;
+ static boolean forceES2 = false;
+ static boolean mainRun = false;
+
+ @AfterClass
+ public static void releaseClass() {
+ }
+
+ protected void runTestGL(GLCapabilitiesImmutable caps) throws InterruptedException {
+ final GLReadBufferUtil screenshot = new GLReadBufferUtil(false, false);
+ System.err.println("requested: vsync "+swapInterval+", "+caps);
+
+ final GLWindow glWindow = GLWindow.create(caps);
+ Assert.assertNotNull(glWindow);
+ glWindow.setTitle("Gears NEWT Test (translucent "+!caps.isBackgroundOpaque()+"), swapInterval "+swapInterval);
+ if(mainRun) {
+ glWindow.setSize(512, 512);
+ } else {
+ glWindow.setSize(256, 256);
+ }
+ // eager initialization of context
+ glWindow.setVisible(true);
+ glWindow.display();
+
+ final int fbod1_texUnit = 0;
+ final int fbod2_texUnit = 1;
+
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
+ GLCapabilities fbodCaps = (GLCapabilities) caps.cloneMutable();
+ // fbodCaps.setDoubleBuffered(false);
+
+ final Mix2TexturesES2 mixerDemo = new Mix2TexturesES2(1, fbod1_texUnit, fbod2_texUnit);
+
+ // FBOD1
+ final GLOffscreenAutoDrawable.FBO fbod1 = (GLOffscreenAutoDrawable.FBO)
+ factory.createOffscreenAutoDrawable(null, fbodCaps, null, glWindow.getWidth(), glWindow.getHeight(), glWindow.getContext());
+ fbod1.setUpstreamWidget(glWindow); // connect the real GLWindow (mouse/key) to offscreen!
+ fbod1.setTextureUnit(fbod1_texUnit);
+ {
+ GearsES2 demo0 = new GearsES2(-1);
+ fbod1.addGLEventListener(demo0);
+ demo0.setIgnoreFocus(true);
+ }
+ fbod1.getNativeSurface().addSurfaceUpdatedListener(new SurfaceUpdatedListener() {
+ @Override
+ public void surfaceUpdated(Object updater, NativeSurface ns, long when) {
+ mixerDemo.setTexID0(fbod1.getTextureBuffer(GL.GL_FRONT).getName());
+ } });
+ fbod1.display(); // init
+ System.err.println("FBOD1 "+fbod1);
+ Assert.assertTrue(fbod1.isInitialized());
+
+ // FBOD2
+ final GLOffscreenAutoDrawable.FBO fbod2 = (GLOffscreenAutoDrawable.FBO)
+ factory.createOffscreenAutoDrawable(null, fbodCaps, null, glWindow.getWidth(), glWindow.getHeight(), glWindow.getContext());
+ fbod2.setTextureUnit(fbod2_texUnit);
+ fbod2.addGLEventListener(new RedSquareES2(-1));
+ fbod2.getNativeSurface().addSurfaceUpdatedListener(new SurfaceUpdatedListener() {
+ @Override
+ public void surfaceUpdated(Object updater, NativeSurface ns, long when) {
+ mixerDemo.setTexID1(fbod2.getTextureBuffer(GL.GL_FRONT).getName());
+ } });
+ fbod2.display(); // init
+ System.err.println("FBOD2 "+fbod2);
+ Assert.assertTrue(fbod2.isInitialized());
+
+ // preinit texIDs
+ mixerDemo.setTexID0(fbod1.getTextureBuffer(GL.GL_FRONT).getName());
+ mixerDemo.setTexID1(fbod2.getTextureBuffer(GL.GL_FRONT).getName());
+
+ glWindow.addGLEventListener(mixerDemo);
+ glWindow.addGLEventListener(new GLEventListener() {
+ int i=0, c=0;
+ public void init(GLAutoDrawable drawable) {}
+ public void dispose(GLAutoDrawable drawable) {}
+ public void display(GLAutoDrawable drawable) {
+ if(mainRun) return;
+
+ final int dw = drawable.getWidth();
+ final int dh = drawable.getHeight();
+ c++;
+
+ if(dw<800) {
+ System.err.println("XXX: "+dw+"x"+dh+", c "+c);
+ if(8 == c) {
+ snapshot(i++, "msaa"+fbod1.getNumSamples(), drawable.getGL(), screenshot, TextureIO.PNG, null);
+ }
+ if(9 == c) {
+ c=0;
+ new Thread() {
+ @Override
+ public void run() {
+ glWindow.setSize(dw+256, dh+256);
+ } }.start();
+ }
+ }
+ }
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+ fbod1.setSize(width, height);
+ fbod2.setSize(width, height);
+ }
+ });
+
+ final FPSAnimator animator0 = new FPSAnimator(30);
+ animator0.add(fbod1);
+ animator0.add(fbod2);
+
+ final Animator animator1 = new Animator();
+ animator1.add(glWindow);
+
+ QuitAdapter quitAdapter = new QuitAdapter();
+
+ //glWindow.addKeyListener(new TraceKeyAdapter(quitAdapter));
+ //glWindow.addWindowListener(new TraceWindowAdapter(quitAdapter));
+ glWindow.addKeyListener(quitAdapter);
+ glWindow.addWindowListener(quitAdapter);
+
+ glWindow.addWindowListener(new WindowAdapter() {
+ public void windowResized(WindowEvent e) {
+ System.err.println("window resized: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight());
+ }
+ public void windowMoved(WindowEvent e) {
+ System.err.println("window moved: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight());
+ }
+ });
+
+ animator0.start();
+ animator1.start();
+ // glWindow.setSkipContextReleaseThread(animator.getThread());
+
+ glWindow.setVisible(true);
+
+ System.err.println("NW chosen: "+glWindow.getDelegatedWindow().getChosenCapabilities());
+ System.err.println("GL chosen: "+glWindow.getChosenCapabilities());
+ System.err.println("window pos/siz: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight()+", "+glWindow.getInsets());
+
+ animator0.setUpdateFPSFrames(30, showFPS ? System.err : null);
+ animator1.setUpdateFPSFrames(60, showFPS ? System.err : null);
+
+ while(!quitAdapter.shouldQuit() && animator1.isAnimating() && animator1.getTotalFPSDuration()
+ * The created {@link GLOffscreenAutoDrawable.FBO} is being used to run the {@link GLEventListener}.
+ *
+ *
+ * This test simulates shared on-thread GL context / texture usage,
+ * where the producer uses an FBO and delivers a shared texture.
+ * The receiver draws the shared texture onscreen.
+ * In detail the test consist of:
+ *
notify the onscreen renderer about new textureID (swapping double buffer)
+ *
+ *
1 onscreen {@link GLWindow}
+ *
+ *
shares it's {@link GLContext} w/ above FBO
+ *
running within common {@link Animator} @ 60fps
+ *
uses the shared FBO texture and draws it onscreen
+ *
+ *
+ *
+ */
+public class TestFBOOnThreadSharedContext1DemoES2NEWT extends UITestCase {
+ static long duration = 500; // ms
+ static int swapInterval = 1;
+ static boolean showFPS = false;
+ static boolean forceES2 = false;
+ static boolean mainRun = false;
+
+ @AfterClass
+ public static void releaseClass() {
+ }
+
+ protected void runTestGL(GLCapabilitiesImmutable caps) throws InterruptedException {
+ final GLReadBufferUtil screenshot = new GLReadBufferUtil(false, false);
+ System.err.println("requested: vsync "+swapInterval+", "+caps);
+
+ final GLWindow glWindow = GLWindow.create(caps);
+ Assert.assertNotNull(glWindow);
+ glWindow.setTitle("Gears NEWT Test (translucent "+!caps.isBackgroundOpaque()+"), swapInterval "+swapInterval);
+ if(mainRun) {
+ glWindow.setSize(512, 512);
+ } else {
+ glWindow.setSize(256, 256);
+ }
+ // eager initialization of context
+ glWindow.setVisible(true);
+ glWindow.display();
+
+ final int fbod1_texUnit = 0;
+
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
+ GLCapabilities fbodCaps = (GLCapabilities) caps.cloneMutable();
+ // fbodCaps.setDoubleBuffered(false);
+
+ final Mix2TexturesES2 mixerDemo = new Mix2TexturesES2(1, fbod1_texUnit, 0);
+
+ // FBOD1
+ final GLOffscreenAutoDrawable.FBO fbod1 = (GLOffscreenAutoDrawable.FBO)
+ factory.createOffscreenAutoDrawable(null, fbodCaps, null, glWindow.getWidth(), glWindow.getHeight(), glWindow.getContext());
+ fbod1.setUpstreamWidget(glWindow); // connect the real GLWindow (mouse/key) to offscreen!
+ fbod1.setTextureUnit(fbod1_texUnit);
+ {
+ GearsES2 demo0 = new GearsES2(-1);
+ fbod1.addGLEventListener(demo0);
+ demo0.setIgnoreFocus(true);
+ }
+ fbod1.getNativeSurface().addSurfaceUpdatedListener(new SurfaceUpdatedListener() {
+ @Override
+ public void surfaceUpdated(Object updater, NativeSurface ns, long when) {
+ mixerDemo.setTexID0(fbod1.getTextureBuffer(GL.GL_FRONT).getName());
+ } });
+ fbod1.display(); // init
+ System.err.println("FBOD1 "+fbod1);
+ Assert.assertTrue(fbod1.isInitialized());
+
+ // preinit texIDs
+ mixerDemo.setTexID0(fbod1.getTextureBuffer(GL.GL_FRONT).getName());
+
+ glWindow.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowResized(WindowEvent e) {
+ fbod1.setSize(glWindow.getWidth(), glWindow.getHeight());
+ }
+ });
+ glWindow.addGLEventListener(mixerDemo);
+ glWindow.addGLEventListener(new GLEventListener() {
+ int i=0, c=0;
+ public void init(GLAutoDrawable drawable) {}
+ public void dispose(GLAutoDrawable drawable) {}
+ public void display(GLAutoDrawable drawable) {
+ if(mainRun) return;
+
+ final int dw = drawable.getWidth();
+ final int dh = drawable.getHeight();
+ c++;
+
+ if(dw<800) {
+ System.err.println("XXX: "+dw+"x"+dh+", c "+c);
+ if(8 == c) {
+ snapshot(i++, "msaa"+fbod1.getNumSamples(), drawable.getGL(), screenshot, TextureIO.PNG, null);
+ }
+ if(9 == c) {
+ c=0;
+ new Thread() {
+ @Override
+ public void run() {
+ glWindow.setSize(dw+256, dh+256);
+ } }.start();
+ }
+ }
+ }
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { }
+ });
+
+ final Animator animator1 = new Animator();
+ animator1.add(fbod1);
+ animator1.add(glWindow);
+
+ QuitAdapter quitAdapter = new QuitAdapter();
+
+ //glWindow.addKeyListener(new TraceKeyAdapter(quitAdapter));
+ //glWindow.addWindowListener(new TraceWindowAdapter(quitAdapter));
+ glWindow.addKeyListener(quitAdapter);
+ glWindow.addWindowListener(quitAdapter);
+
+ glWindow.addWindowListener(new WindowAdapter() {
+ public void windowResized(WindowEvent e) {
+ System.err.println("window resized: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight());
+ }
+ public void windowMoved(WindowEvent e) {
+ System.err.println("window moved: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight());
+ }
+ });
+
+ animator1.start();
+ // glWindow.setSkipContextReleaseThread(animator.getThread());
+
+ glWindow.setVisible(true);
+
+ System.err.println("NW chosen: "+glWindow.getDelegatedWindow().getChosenCapabilities());
+ System.err.println("GL chosen: "+glWindow.getChosenCapabilities());
+ System.err.println("window pos/siz: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight()+", "+glWindow.getInsets());
+
+ animator1.setUpdateFPSFrames(60, showFPS ? System.err : null);
+
+ while(!quitAdapter.shouldQuit() && animator1.isAnimating() && animator1.getTotalFPSDuration()
+ * Each test creates a {@link GLDrawable} using the
+ * {@link GLDrawableFactory#createGLDrawable(javax.media.nativewindow.NativeSurface) factory model}.
+ * The {@link GLContext} is derived {@link GLDrawable#createContext(GLContext) from the drawable}.
+ *
+ *
+ * Finally a {@link GLAutoDrawableDelegate} is created with the just created {@link GLDrawable} and {@link GLContext}.
+ * It is being used to run the {@link GLEventListener}.
+ *
+ */
+public class TestGLAutoDrawableDelegateOnOffscrnCapsNEWT extends UITestCase {
+ static final int widthStep = 800/4;
+ static final int heightStep = 600/4;
+ volatile int szStep = 2;
+
+ static GLCapabilities getCaps(String profile) {
+ if( !GLProfile.isAvailable(profile) ) {
+ System.err.println("Profile "+profile+" n/a");
+ return null;
+ }
+ return new GLCapabilities(GLProfile.get(profile));
+ }
+
+ void doTest(GLCapabilitiesImmutable reqGLCaps, GLEventListener demo) throws InterruptedException {
+ System.out.println("Requested GL Caps: "+reqGLCaps);
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(reqGLCaps.getGLProfile());
+
+ final boolean fboAvailable = factory.canCreateFBO(null, reqGLCaps.getGLProfile());
+ final boolean pbufferAvailable = factory.canCreateGLPbuffer(null);
+ final GLCapabilitiesImmutable expGLCaps = GLGraphicsConfigurationUtil.fixGLCapabilities(reqGLCaps, fboAvailable, pbufferAvailable);
+ System.out.println("Expected GL Caps: "+expGLCaps);
+ //
+ // Create native windowing resources .. X11/Win/OSX
+ //
+ final Window window = NewtFactory.createWindow(reqGLCaps);
+ Assert.assertNotNull(window);
+ window.setSize(widthStep*szStep, heightStep*szStep);
+ window.setVisible(true);
+ Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true));
+ Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true));
+ System.out.println("Window: "+window.getClass().getName());
+
+ // Check caps of NativeWindow config w/o GL
+ final CapabilitiesImmutable chosenCaps = window.getGraphicsConfiguration().getChosenCapabilities();
+ System.out.println("Window Caps Pre_GL: "+chosenCaps);
+ Assert.assertNotNull(chosenCaps);
+ Assert.assertTrue(chosenCaps.getGreenBits()>5);
+ Assert.assertTrue(chosenCaps.getBlueBits()>5);
+ Assert.assertTrue(chosenCaps.getRedBits()>5);
+
+ //
+ // Create native OpenGL resources .. XGL/WGL/CGL ..
+ // equivalent to GLAutoDrawable methods: setVisible(true)
+ //
+ final GLDrawable drawable = factory.createGLDrawable(window);
+ Assert.assertNotNull(drawable);
+ System.out.println("Drawable Pre-GL(0): "+drawable.getClass().getName()+", "+drawable.getNativeSurface().getClass().getName());
+
+ //
+ drawable.setRealized(true);
+ Assert.assertTrue(drawable.isRealized());
+
+ System.out.println("Window Caps PostGL : "+window.getGraphicsConfiguration().getChosenCapabilities());
+ System.out.println("Drawable Post-GL(1): "+drawable.getClass().getName()+", "+drawable.getNativeSurface().getClass().getName());
+
+ // Check caps of GLDrawable after realization
+ final GLCapabilitiesImmutable chosenGLCaps = drawable.getChosenGLCapabilities();
+ System.out.println("Chosen GL Caps(1): "+chosenGLCaps);
+ Assert.assertNotNull(chosenGLCaps);
+ Assert.assertTrue(chosenGLCaps.getGreenBits()>5);
+ Assert.assertTrue(chosenGLCaps.getBlueBits()>5);
+ Assert.assertTrue(chosenGLCaps.getRedBits()>5);
+ Assert.assertTrue(chosenGLCaps.getDepthBits()>4);
+ Assert.assertEquals(expGLCaps.isOnscreen(), chosenGLCaps.isOnscreen());
+ Assert.assertEquals(expGLCaps.isFBO(), chosenGLCaps.isFBO());
+ Assert.assertEquals(expGLCaps.isPBuffer(), chosenGLCaps.isPBuffer());
+ Assert.assertEquals(expGLCaps.isBitmap(), chosenGLCaps.isBitmap());
+ /** Single/Double buffer cannot be checked since result may vary ..
+ if(chosenGLCaps.isOnscreen() || chosenGLCaps.isFBO()) {
+ // dbl buffer may be disabled w/ offscreen pbuffer and bitmap
+ Assert.assertEquals(expGLCaps.getDoubleBuffered(), chosenGLCaps.getDoubleBuffered());
+ } */
+
+ GLContext context = drawable.createContext(null);
+ Assert.assertNotNull(context);
+ int res = context.makeCurrent();
+ Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res);
+ context.release();
+
+ System.out.println("Chosen GL Caps(2): "+drawable.getChosenGLCapabilities());
+ System.out.println("Chosen GL CTX (2): "+context.getGLVersion());
+ System.out.println("Drawable Post-GL(2): "+drawable.getClass().getName()+", "+drawable.getNativeSurface().getClass().getName());
+
+ final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context, window, false, null) {
+ @Override
+ protected void destroyImplInLock() {
+ super.destroyImplInLock(); // destroys drawable/context
+ window.destroy(); // destroys the actual window, incl. the device
+ }
+ };
+
+ window.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowRepaint(WindowUpdateEvent e) {
+ glad.windowRepaintOp();
+ }
+
+ @Override
+ public void windowResized(WindowEvent e) {
+ glad.windowResizedOp(window.getWidth(), window.getHeight());
+ }
+
+ @Override
+ public void windowDestroyNotify(WindowEvent e) {
+ glad.windowDestroyNotifyOp();
+ }
+ });
+
+ glad.addGLEventListener(demo);
+
+ final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener();
+ glad.addGLEventListener(snapshotGLEventListener);
+
+ glad.display(); // initial resize/display
+
+ // 1 - szStep = 2
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ // 2, 3 (resize + display)
+ szStep = 1;
+ window.setSize(widthStep*szStep, heightStep*szStep);
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ // 4, 5 (resize + display)
+ szStep = 4;
+ window.setSize(widthStep*szStep, heightStep*szStep);
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ Thread.sleep(50);
+
+ glad.destroy();
+ System.out.println("Fin Drawable: "+drawable);
+ System.out.println("Fin Window: "+window);
+ }
+
+ @Test
+ public void testAvailableInfo() {
+ GLDrawableFactory f = GLDrawableFactory.getDesktopFactory();
+ if(null != f) {
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
+ }
+ f = GLDrawableFactory.getEGLFactory();
+ if(null != f) {
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
+ }
+ }
+
+ @Test
+ public void testGL2OnScreenDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OnScreenSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenAutoDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenFBODblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenFBOSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenPbufferDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenPbufferSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenBitmapDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setBitmap(true);
+ doTest(reqGLCaps, new Gears(1));
+ }
+
+ @Test
+ public void testGL2OffScreenBitmapSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setBitmap(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new Gears(1));
+ }
+
+ @Test
+ public void testES2OnScreenDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OnScreenSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenAutoDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenFBODblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenFBOSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenPbufferDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenPbufferSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ /** Not implemented !
+ @Test
+ public void testES2OffScreenBitmapDblBuf() throws InterruptedException {
+ if(!checkProfile(GLProfile.GLES2)) {
+ return;
+ }
+ final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GLES2));
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setBitmap(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ } */
+
+ public static void main(String args[]) throws IOException {
+ org.junit.runner.JUnitCore.main(TestGLAutoDrawableDelegateOnOffscrnCapsNEWT.class.getName());
+ }
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryOffscrnCapsNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryOffscrnCapsNEWT.java
new file mode 100644
index 000000000..544d74aa5
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryOffscrnCapsNEWT.java
@@ -0,0 +1,317 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.jogl.acore;
+
+import java.io.IOException;
+
+import javax.media.nativewindow.CapabilitiesImmutable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLOffscreenAutoDrawable;
+import javax.media.opengl.GLProfile;
+
+import jogamp.opengl.GLGraphicsConfigurationUtil;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.jogamp.opengl.JoglVersion;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
+import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+/**
+ * Toolkit agnostic {@link GLOffscreenAutoDrawable} tests using the
+ * {@link GLDrawableFactory#createOffscreenAutoDrawable(javax.media.nativewindow.AbstractGraphicsDevice, GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, int, int, GLContext) factory model}.
+ *
+ * The created {@link GLOffscreenAutoDrawable} is being used to run the {@link GLEventListener}.
+ *
+ */
+public class TestGLAutoDrawableFactoryOffscrnCapsNEWT extends UITestCase {
+ static final int widthStep = 800/4;
+ static final int heightStep = 600/4;
+ volatile int szStep = 2;
+
+ static GLCapabilities getCaps(String profile) {
+ if( !GLProfile.isAvailable(profile) ) {
+ System.err.println("Profile "+profile+" n/a");
+ return null;
+ }
+ return new GLCapabilities(GLProfile.get(profile));
+ }
+
+ void doTest(GLCapabilitiesImmutable reqGLCaps, GLEventListener demo) throws InterruptedException {
+ System.out.println("Requested GL Caps: "+reqGLCaps);
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(reqGLCaps.getGLProfile());
+
+ final boolean fboAvailable = factory.canCreateFBO(null, reqGLCaps.getGLProfile());
+ final boolean pbufferAvailable = factory.canCreateGLPbuffer(null);
+ final GLCapabilitiesImmutable expGLCaps = GLGraphicsConfigurationUtil.fixGLCapabilities(reqGLCaps, fboAvailable, pbufferAvailable);
+ System.out.println("Expected GL Caps: "+expGLCaps);
+
+ //
+ // Create native OpenGL resources .. XGL/WGL/CGL ..
+ // equivalent to GLAutoDrawable methods: setVisible(true)
+ //
+ final GLOffscreenAutoDrawable glad = factory.createOffscreenAutoDrawable(null, reqGLCaps, null, widthStep*szStep, heightStep*szStep, null);
+
+ Assert.assertNotNull(glad);
+ System.out.println("Drawable Pre-GL(0): "+glad.getClass().getName()+", "+glad.getNativeSurface().getClass().getName());
+ Assert.assertTrue(glad.isRealized());
+
+ // Check caps of NativeWindow config w/o GL
+ final CapabilitiesImmutable chosenCaps = glad.getChosenGLCapabilities();
+ System.out.println("Drawable Caps Pre_GL : "+chosenCaps);
+ Assert.assertNotNull(chosenCaps);
+ Assert.assertTrue(chosenCaps.getGreenBits()>5);
+ Assert.assertTrue(chosenCaps.getBlueBits()>5);
+ Assert.assertTrue(chosenCaps.getRedBits()>5);
+
+ glad.display(); // force native context creation
+
+ // Check caps of GLDrawable after realization
+ final GLCapabilitiesImmutable chosenGLCaps = glad.getChosenGLCapabilities();
+ System.out.println("Chosen GL Caps(1): "+chosenGLCaps);
+ System.out.println("Chosen GL CTX (1): "+glad.getContext().getGLVersion());
+
+ Assert.assertNotNull(chosenGLCaps);
+ Assert.assertTrue(chosenGLCaps.getGreenBits()>5);
+ Assert.assertTrue(chosenGLCaps.getBlueBits()>5);
+ Assert.assertTrue(chosenGLCaps.getRedBits()>5);
+ Assert.assertTrue(chosenGLCaps.getDepthBits()>4);
+ Assert.assertEquals(expGLCaps.isOnscreen(), chosenGLCaps.isOnscreen());
+ Assert.assertEquals(expGLCaps.isFBO(), chosenGLCaps.isFBO());
+ Assert.assertEquals(expGLCaps.isPBuffer(), chosenGLCaps.isPBuffer());
+ Assert.assertEquals(expGLCaps.isBitmap(), chosenGLCaps.isBitmap());
+ /** Single/Double buffer cannot be checked since result may vary ..
+ if(chosenGLCaps.isOnscreen() || chosenGLCaps.isFBO()) {
+ // dbl buffer may be disabled w/ offscreen pbuffer and bitmap
+ Assert.assertEquals(expGLCaps.getDoubleBuffered(), chosenGLCaps.getDoubleBuffered());
+ } */
+
+ glad.addGLEventListener(demo);
+
+ final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener();
+ glad.addGLEventListener(snapshotGLEventListener);
+
+ glad.display(); // initial resize/display
+
+ // 1 - szStep = 2
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ // 2, 3 (resize + display)
+ szStep = 1;
+ glad.setSize(widthStep*szStep, heightStep*szStep);
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ // 4, 5 (resize + display)
+ szStep = 4;
+ glad.setSize(widthStep*szStep, heightStep*szStep);
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ Thread.sleep(50);
+
+ glad.destroy();
+ System.out.println("Fin Drawable: "+glad);
+ }
+
+ @Test
+ public void testAvailableInfo() {
+ GLDrawableFactory f = GLDrawableFactory.getDesktopFactory();
+ if(null != f) {
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
+ }
+ f = GLDrawableFactory.getEGLFactory();
+ if(null != f) {
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
+ }
+ }
+
+ @Test
+ public void testGL2OffScreenAutoDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenFBODblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenFBOSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenFBOStencil() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ reqGLCaps.setStencilBits(1);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenFBOStencilMSAA() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ reqGLCaps.setStencilBits(1);
+ reqGLCaps.setSampleBuffers(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenPbufferDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenPbufferSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenBitmapDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setBitmap(true);
+ doTest(reqGLCaps, new Gears(1));
+ }
+
+ @Test
+ public void testGL2OffScreenBitmapSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setBitmap(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new Gears(1));
+ }
+
+ @Test
+ public void testES2OffScreenAutoDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenFBODblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenFBOSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenPbufferDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenPbufferSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ /** Not implemented !
+ @Test
+ public void testES2OffScreenBitmapDblBuf() throws InterruptedException {
+ if(!checkProfile(GLProfile.GLES2)) {
+ return;
+ }
+ final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GLES2));
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setBitmap(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ } */
+
+ public static void main(String args[]) throws IOException {
+ org.junit.runner.JUnitCore.main(TestGLAutoDrawableFactoryOffscrnCapsNEWT.class.getName());
+ }
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java
new file mode 100644
index 000000000..64a75716b
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java
@@ -0,0 +1,328 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.jogl.acore;
+
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.io.IOException;
+
+import javax.media.nativewindow.CapabilitiesImmutable;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLProfile;
+import javax.media.opengl.awt.GLCanvas;
+
+import jogamp.nativewindow.jawt.JAWTUtil;
+import jogamp.opengl.GLGraphicsConfigurationUtil;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.JoglVersion;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+/**
+ * Tests using a NEWT {@link GLWindow} {@link GLAutoDrawable auto drawable} for on- and offscreen cases.
+ *
+ * The NEWT {@link GLAutoDrawable} is being used to run the {@link GLEventListener}.
+ *
+ */
+public class TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT extends UITestCase {
+ static final int widthStep = 800/4;
+ static final int heightStep = 600/4;
+ volatile int szStep = 2;
+
+ static GLCapabilities getCaps(String profile) {
+ if( !GLProfile.isAvailable(profile) ) {
+ System.err.println("Profile "+profile+" n/a");
+ return null;
+ }
+ return new GLCapabilities(GLProfile.get(profile));
+ }
+
+ static void setGLCanvasSize(final Frame frame, final GLCanvas glc, final int width, final int height) {
+ try {
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ final Dimension new_sz = new Dimension(width, height);
+ glc.setMinimumSize(new_sz);
+ glc.setPreferredSize(new_sz);
+ glc.setSize(new_sz);
+ frame.pack();
+ frame.validate();
+ } } );
+ } catch( Throwable throwable ) {
+ throwable.printStackTrace();
+ Assume.assumeNoException( throwable );
+ }
+ }
+
+ static interface MyGLEventListener extends GLEventListener {
+ void setMakeSnapshot();
+ }
+
+ void doTest(GLCapabilitiesImmutable reqGLCaps, GLEventListener demo) throws InterruptedException {
+ if(reqGLCaps.isOnscreen() && JAWTUtil.isOffscreenLayerRequired()) {
+ System.err.println("onscreen layer n/a");
+ return;
+ }
+ if(!reqGLCaps.isOnscreen() && !JAWTUtil.isOffscreenLayerSupported()) {
+ System.err.println("offscreen layer n/a");
+ return;
+ }
+ System.out.println("Requested GL Caps: "+reqGLCaps);
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(reqGLCaps.getGLProfile());
+
+ final boolean fboAvailable = factory.canCreateFBO(null, reqGLCaps.getGLProfile());
+ final boolean pbufferAvailable = factory.canCreateGLPbuffer(null);
+ final GLCapabilitiesImmutable expGLCaps = GLGraphicsConfigurationUtil.fixGLCapabilities(reqGLCaps, fboAvailable, pbufferAvailable);
+ System.out.println("Expected GL Caps: "+expGLCaps);
+ //
+ // Create native windowing resources .. X11/Win/OSX
+ //
+ final GLCanvas glad = new GLCanvas(reqGLCaps); // will implicit trigger offscreen layer - if !onscreen && supported
+ Assert.assertNotNull(glad);
+ Dimension glc_sz = new Dimension(widthStep*szStep, heightStep*szStep);
+ glad.setMinimumSize(glc_sz);
+ glad.setPreferredSize(glc_sz);
+ glad.setSize(glc_sz);
+ final Frame frame = new Frame(getSimpleTestName("."));
+ Assert.assertNotNull(frame);
+ frame.add(glad);
+
+ try {
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ frame.pack();
+ frame.setVisible(true);
+ }});
+ } catch( Throwable throwable ) {
+ throwable.printStackTrace();
+ Assume.assumeNoException( throwable );
+ }
+
+ Assert.assertTrue(AWTRobotUtil.waitForVisible(glad, true));
+ Assert.assertTrue(AWTRobotUtil.waitForRealized(glad, true));
+ System.out.println("Window: "+glad.getClass().getName());
+
+ // Check caps of NativeWindow config w/o GL
+ final CapabilitiesImmutable chosenCaps = glad.getChosenGLCapabilities();
+ System.out.println("Window Caps Pre_GL: "+chosenCaps);
+ Assert.assertNotNull(chosenCaps);
+ Assert.assertTrue(chosenCaps.getGreenBits()>5);
+ Assert.assertTrue(chosenCaps.getBlueBits()>5);
+ Assert.assertTrue(chosenCaps.getRedBits()>5);
+
+ glad.display(); // force native context creation
+
+ //
+ // Create native OpenGL resources .. XGL/WGL/CGL ..
+ // equivalent to GLAutoDrawable methods: setVisible(true)
+ //
+ {
+ final GLDrawable actualDrawable = glad.getDelegatedDrawable();
+ Assert.assertNotNull(actualDrawable);
+ System.out.println("Drawable Pre-GL(0): "+actualDrawable.getClass().getName()+", "+actualDrawable.getNativeSurface().getClass().getName());
+ }
+
+ System.out.println("Window Caps PostGL : "+glad.getChosenGLCapabilities());
+ System.out.println("Drawable Post-GL(1): "+glad.getClass().getName()+", "+glad.getNativeSurface().getClass().getName());
+
+ // Check caps of GLDrawable after realization
+ final GLCapabilitiesImmutable chosenGLCaps = glad.getChosenGLCapabilities();
+ System.out.println("Chosen GL Caps(1): "+chosenGLCaps);
+ Assert.assertNotNull(chosenGLCaps);
+ Assert.assertTrue(chosenGLCaps.getGreenBits()>5);
+ Assert.assertTrue(chosenGLCaps.getBlueBits()>5);
+ Assert.assertTrue(chosenGLCaps.getRedBits()>5);
+ Assert.assertTrue(chosenGLCaps.getDepthBits()>4);
+ Assert.assertEquals(expGLCaps.isOnscreen(), chosenGLCaps.isOnscreen());
+ Assert.assertEquals(expGLCaps.isFBO(), chosenGLCaps.isFBO());
+ Assert.assertEquals(expGLCaps.isPBuffer(), chosenGLCaps.isPBuffer());
+ Assert.assertEquals(expGLCaps.isBitmap(), chosenGLCaps.isBitmap());
+ /** Single/Double buffer cannot be checked since result may vary ..
+ if(chosenGLCaps.isOnscreen() || chosenGLCaps.isFBO()) {
+ // dbl buffer may be disabled w/ offscreen pbuffer and bitmap
+ Assert.assertEquals(expGLCaps.getDoubleBuffered(), chosenGLCaps.getDoubleBuffered());
+ } */
+
+ {
+ GLContext context = glad.getContext();
+ System.out.println("Chosen GL CTX (2): "+context.getGLVersion());
+ Assert.assertNotNull(context);
+ Assert.assertTrue(context.isCreated());
+ }
+
+ System.out.println("Chosen GL Caps(2): "+glad.getChosenGLCapabilities());
+ System.out.println("Drawable Post-GL(2): "+glad.getClass().getName()+", "+glad.getNativeSurface().getClass().getName());
+
+ glad.addGLEventListener(demo);
+
+ final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener();
+ glad.addGLEventListener(snapshotGLEventListener);
+
+ glad.display(); // initial resize/display
+
+ // 1 - szStep = 2
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ // 2, 3 (resize + display)
+ szStep = 1;
+ setGLCanvasSize(frame, glad, widthStep*szStep, heightStep*szStep);
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ glad.display();
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ // 4, 5 (resize + display)
+ szStep = 4;
+ setGLCanvasSize(frame, glad, widthStep*szStep, heightStep*szStep);
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ glad.display();
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ Thread.sleep(50);
+
+ try {
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ frame.setVisible(false);
+ frame.remove(glad);
+ frame.dispose();
+ }});
+ } catch( Throwable throwable ) {
+ throwable.printStackTrace();
+ Assume.assumeNoException( throwable );
+ }
+ System.out.println("Fin: "+glad);
+ }
+
+ @Test
+ public void testAvailableInfo() {
+ GLDrawableFactory f = GLDrawableFactory.getDesktopFactory();
+ if(null != f) {
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
+ }
+ f = GLDrawableFactory.getEGLFactory();
+ if(null != f) {
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
+ }
+ }
+
+ @Test
+ public void testGL2OnScreen() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenAuto() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenFBOMSAA() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ reqGLCaps.setSampleBuffers(true);
+ reqGLCaps.setNumSamples(4);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenPbuffer() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OnScreen() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenAuto() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenFBOMSAA() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ reqGLCaps.setSampleBuffers(true);
+ reqGLCaps.setNumSamples(4);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenPbuffer() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+
+ public static void main(String args[]) throws IOException {
+ org.junit.runner.JUnitCore.main(TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.class.getName());
+ }
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT.java
new file mode 100644
index 000000000..37ec44566
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT.java
@@ -0,0 +1,351 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.jogl.acore;
+
+import java.io.IOException;
+
+import javax.media.nativewindow.CapabilitiesImmutable;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLProfile;
+
+import jogamp.opengl.GLGraphicsConfigurationUtil;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.JoglVersion;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
+import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+/**
+ * Tests using a NEWT {@link GLWindow} {@link GLAutoDrawable auto drawable} for on- and offscreen cases.
+ *
+ * The NEWT {@link GLAutoDrawable} is being used to run the {@link GLEventListener}.
+ *
+ */
+public class TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT extends UITestCase {
+ static final int widthStep = 800/4;
+ static final int heightStep = 600/4;
+ volatile int szStep = 2;
+
+ static interface MyGLEventListener extends GLEventListener {
+ void setMakeSnapshot();
+ }
+
+ static GLCapabilities getCaps(String profile) {
+ if( !GLProfile.isAvailable(profile) ) {
+ System.err.println("Profile "+profile+" n/a");
+ return null;
+ }
+ return new GLCapabilities(GLProfile.get(profile));
+ }
+
+ void doTest(GLCapabilitiesImmutable reqGLCaps, GLEventListener demo) throws InterruptedException {
+ System.out.println("Requested GL Caps: "+reqGLCaps);
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(reqGLCaps.getGLProfile());
+
+ final boolean fboAvailable = factory.canCreateFBO(null, reqGLCaps.getGLProfile());
+ final boolean pbufferAvailable = factory.canCreateGLPbuffer(null);
+ final GLCapabilitiesImmutable expGLCaps = GLGraphicsConfigurationUtil.fixGLCapabilities(reqGLCaps, fboAvailable, pbufferAvailable);
+ System.out.println("Expected GL Caps: "+expGLCaps);
+ //
+ // Create native windowing resources .. X11/Win/OSX
+ //
+ final GLWindow glad = GLWindow.create(reqGLCaps);
+ Assert.assertNotNull(glad);
+ glad.setSize(widthStep*szStep, heightStep*szStep);
+ glad.setVisible(true);
+ Assert.assertTrue(AWTRobotUtil.waitForVisible(glad, true));
+ Assert.assertTrue(AWTRobotUtil.waitForRealized(glad, true));
+ System.out.println("Window: "+glad.getClass().getName());
+
+ // Check caps of NativeWindow config w/o GL
+ final CapabilitiesImmutable chosenCaps = glad.getGraphicsConfiguration().getChosenCapabilities();
+ System.out.println("Window Caps Pre_GL: "+chosenCaps);
+ Assert.assertNotNull(chosenCaps);
+ Assert.assertTrue(chosenCaps.getGreenBits()>5);
+ Assert.assertTrue(chosenCaps.getBlueBits()>5);
+ Assert.assertTrue(chosenCaps.getRedBits()>5);
+
+ //
+ // Create native OpenGL resources .. XGL/WGL/CGL ..
+ // equivalent to GLAutoDrawable methods: setVisible(true)
+ //
+ {
+ final GLDrawable actualDrawable = glad.getDelegatedDrawable();
+ Assert.assertNotNull(actualDrawable);
+ System.out.println("Drawable Pre-GL(0): "+actualDrawable.getClass().getName()+", "+actualDrawable.getNativeSurface().getClass().getName());
+ }
+
+ System.out.println("Window Caps PostGL : "+glad.getGraphicsConfiguration().getChosenCapabilities());
+ System.out.println("Drawable Post-GL(1): "+glad.getClass().getName()+", "+glad.getNativeSurface().getClass().getName());
+
+ // Check caps of GLDrawable after realization
+ final GLCapabilitiesImmutable chosenGLCaps = glad.getChosenGLCapabilities();
+ System.out.println("Chosen GL Caps(1): "+chosenGLCaps);
+ Assert.assertNotNull(chosenGLCaps);
+ Assert.assertTrue(chosenGLCaps.getGreenBits()>5);
+ Assert.assertTrue(chosenGLCaps.getBlueBits()>5);
+ Assert.assertTrue(chosenGLCaps.getRedBits()>5);
+ Assert.assertTrue(chosenGLCaps.getDepthBits()>4);
+ Assert.assertEquals(expGLCaps.isOnscreen(), chosenGLCaps.isOnscreen());
+ Assert.assertEquals(expGLCaps.isFBO(), chosenGLCaps.isFBO());
+ Assert.assertEquals(expGLCaps.isPBuffer(), chosenGLCaps.isPBuffer());
+ Assert.assertEquals(expGLCaps.isBitmap(), chosenGLCaps.isBitmap());
+ /** Single/Double buffer cannot be checked since result may vary ..
+ if(chosenGLCaps.isOnscreen() || chosenGLCaps.isFBO()) {
+ // dbl buffer may be disabled w/ offscreen pbuffer and bitmap
+ Assert.assertEquals(expGLCaps.getDoubleBuffered(), chosenGLCaps.getDoubleBuffered());
+ } */
+
+ glad.display();
+ {
+ GLContext context = glad.getContext();
+ System.out.println("Chosen GL CTX (2): "+context.getGLVersion());
+ Assert.assertNotNull(context);
+ Assert.assertTrue(context.isCreated());
+ }
+
+ System.out.println("Chosen GL Caps(2): "+glad.getChosenGLCapabilities());
+ System.out.println("Drawable Post-GL(2): "+glad.getClass().getName()+", "+glad.getNativeSurface().getClass().getName());
+
+ glad.addGLEventListener(demo);
+
+ final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener();
+ glad.addGLEventListener(snapshotGLEventListener);
+
+ glad.display(); // initial resize/display
+
+ // 1 - szStep = 2
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ // 2, 3 (resize + display)
+ szStep = 1;
+ glad.setSize(widthStep*szStep, heightStep*szStep);
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ // 4, 5 (resize + display)
+ szStep = 4;
+ glad.setSize(widthStep*szStep, heightStep*szStep);
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ Thread.sleep(50);
+
+ glad.destroy();
+ System.out.println("Fin: "+glad);
+ }
+
+ @Test
+ public void testAvailableInfo() {
+ GLDrawableFactory f = GLDrawableFactory.getDesktopFactory();
+ if(null != f) {
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
+ }
+ f = GLDrawableFactory.getEGLFactory();
+ if(null != f) {
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
+ }
+ }
+
+ @Test
+ public void testGL2OnScreenDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OnScreenSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenAutoDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenFBODblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenFBOSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenPbufferDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenPbufferSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenBitmapDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setBitmap(true);
+ doTest(reqGLCaps, new Gears(1));
+ }
+
+ @Test
+ public void testGL2OffScreenBitmapSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setBitmap(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new Gears(1));
+ }
+
+ @Test
+ public void testES2OnScreenDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OnScreenSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenAutoDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenFBODblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenFBOSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setFBO(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenPbufferDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testES2OffScreenPbufferSglBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setPBuffer(true);
+ reqGLCaps.setDoubleBuffered(false);
+ doTest(reqGLCaps, new GearsES2(1));
+ }
+
+ /** Not implemented !
+ @Test
+ public void testES2OffScreenBitmapDblBuf() throws InterruptedException {
+ if(!checkProfile(GLProfile.GLES2)) {
+ return;
+ }
+ final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GLES2));
+ reqGLCaps.setOnscreen(false);
+ reqGLCaps.setBitmap(true);
+ doTest(reqGLCaps, new GearsES2(1));
+ } */
+
+ public static void main(String args[]) throws IOException {
+ org.junit.runner.JUnitCore.main(TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT.class.getName());
+ }
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT.java
new file mode 100644
index 000000000..47fc99844
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT.java
@@ -0,0 +1,300 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.jogl.acore;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.io.IOException;
+
+import javax.media.nativewindow.CapabilitiesImmutable;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLProfile;
+
+import jogamp.nativewindow.jawt.JAWTUtil;
+import jogamp.opengl.GLGraphicsConfigurationUtil;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import com.jogamp.newt.awt.NewtCanvasAWT;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.JoglVersion;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+/**
+ * Tests using a NEWT {@link GLWindow} {@link GLAutoDrawable auto drawable} for on- and offscreen cases.
+ *
+ * The NEWT {@link GLAutoDrawable} is being used to run the {@link GLEventListener}.
+ *
+ */
+public class TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT extends UITestCase {
+ static final int widthStep = 800/4;
+ static final int heightStep = 600/4;
+ volatile int szStep = 2;
+
+ static GLCapabilities getCaps(String profile) {
+ if( !GLProfile.isAvailable(profile) ) {
+ System.err.println("Profile "+profile+" n/a");
+ return null;
+ }
+ return new GLCapabilities(GLProfile.get(profile));
+ }
+
+ static void setComponentSize(final Frame frame, final Component comp, final int width, final int height) {
+ try {
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ final Dimension new_sz = new Dimension(width, height);
+ comp.setMinimumSize(new_sz);
+ comp.setPreferredSize(new_sz);
+ comp.setSize(new_sz);
+ frame.pack();
+ frame.validate();
+ } } );
+ } catch( Throwable throwable ) {
+ throwable.printStackTrace();
+ Assume.assumeNoException( throwable );
+ }
+ }
+
+ static interface MyGLEventListener extends GLEventListener {
+ void setMakeSnapshot();
+ }
+
+ void doTest(boolean offscreenLayer, GLCapabilitiesImmutable reqGLCaps, GLEventListener demo) throws InterruptedException {
+ if(!offscreenLayer && JAWTUtil.isOffscreenLayerRequired()) {
+ System.err.println("onscreen layer n/a");
+ return;
+ }
+ if(offscreenLayer && !JAWTUtil.isOffscreenLayerSupported()) {
+ System.err.println("offscreen layer n/a");
+ return;
+ }
+ System.out.println("Requested GL Caps: "+reqGLCaps);
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(reqGLCaps.getGLProfile());
+
+ final boolean fboAvailable = factory.canCreateFBO(null, reqGLCaps.getGLProfile());
+ final boolean pbufferAvailable = factory.canCreateGLPbuffer(null);
+ final GLCapabilitiesImmutable expGLCaps = offscreenLayer ?
+ GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(reqGLCaps, fboAvailable, pbufferAvailable) :
+ GLGraphicsConfigurationUtil.fixGLCapabilities(reqGLCaps, fboAvailable, pbufferAvailable);
+ System.out.println("Expected GL Caps: "+expGLCaps);
+
+ final GLWindow glad = GLWindow.create(reqGLCaps);
+ Assert.assertNotNull(glad);
+
+
+ final NewtCanvasAWT nca = new NewtCanvasAWT(glad);
+ Assert.assertNotNull(nca);
+ Dimension size0 = new Dimension(widthStep*szStep, heightStep*szStep);
+ nca.setShallUseOffscreenLayer(offscreenLayer); // trigger offscreen layer - if supported
+ nca.setPreferredSize(size0);
+ nca.setMinimumSize(size0);
+ nca.setSize(size0);
+
+ final Frame frame = new Frame(getSimpleTestName("."));
+ Assert.assertNotNull(frame);
+ frame.add(nca);
+
+ try {
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ frame.pack();
+ frame.setVisible(true);
+ }});
+ } catch( Throwable throwable ) {
+ throwable.printStackTrace();
+ Assume.assumeNoException( throwable );
+ }
+
+ Assert.assertTrue(AWTRobotUtil.waitForVisible(glad, true));
+ Assert.assertTrue(AWTRobotUtil.waitForRealized(glad, true));
+ System.out.println("Window: "+glad.getClass().getName());
+
+ // Check caps of NativeWindow config w/o GL
+ final CapabilitiesImmutable chosenCaps = glad.getChosenGLCapabilities();
+ System.out.println("Window Caps Pre_GL: "+chosenCaps);
+ Assert.assertNotNull(chosenCaps);
+ Assert.assertTrue(chosenCaps.getGreenBits()>5);
+ Assert.assertTrue(chosenCaps.getBlueBits()>5);
+ Assert.assertTrue(chosenCaps.getRedBits()>5);
+
+ glad.display(); // force native context creation
+
+ //
+ // Create native OpenGL resources .. XGL/WGL/CGL ..
+ // equivalent to GLAutoDrawable methods: setVisible(true)
+ //
+ {
+ final GLDrawable actualDrawable = glad.getDelegatedDrawable();
+ Assert.assertNotNull(actualDrawable);
+ System.out.println("Drawable Pre-GL(0): "+actualDrawable.getClass().getName()+", "+actualDrawable.getNativeSurface().getClass().getName());
+ }
+
+ System.out.println("Window Caps PostGL : "+glad.getChosenGLCapabilities());
+ System.out.println("Drawable Post-GL(1): "+glad.getClass().getName()+", "+glad.getNativeSurface().getClass().getName());
+
+ // Check caps of GLDrawable after realization
+ final GLCapabilitiesImmutable chosenGLCaps = glad.getChosenGLCapabilities();
+ System.out.println("Chosen GL Caps(1): "+chosenGLCaps);
+ Assert.assertNotNull(chosenGLCaps);
+ Assert.assertTrue(chosenGLCaps.getGreenBits()>5);
+ Assert.assertTrue(chosenGLCaps.getBlueBits()>5);
+ Assert.assertTrue(chosenGLCaps.getRedBits()>5);
+ Assert.assertTrue(chosenGLCaps.getDepthBits()>4);
+ Assert.assertEquals(expGLCaps.isOnscreen(), chosenGLCaps.isOnscreen());
+ Assert.assertEquals(expGLCaps.isFBO(), chosenGLCaps.isFBO());
+ Assert.assertEquals(expGLCaps.isPBuffer(), chosenGLCaps.isPBuffer());
+ Assert.assertEquals(expGLCaps.isBitmap(), chosenGLCaps.isBitmap());
+ /** Single/Double buffer cannot be checked since result may vary ..
+ if(chosenGLCaps.isOnscreen() || chosenGLCaps.isFBO()) {
+ // dbl buffer may be disabled w/ offscreen pbuffer and bitmap
+ Assert.assertEquals(expGLCaps.getDoubleBuffered(), chosenGLCaps.getDoubleBuffered());
+ } */
+
+ {
+ GLContext context = glad.getContext();
+ System.out.println("Chosen GL CTX (2): "+context.getGLVersion());
+ Assert.assertNotNull(context);
+ Assert.assertTrue(context.isCreated());
+ }
+
+ System.out.println("Chosen GL Caps(2): "+glad.getChosenGLCapabilities());
+ System.out.println("Drawable Post-GL(2): "+glad.getClass().getName()+", "+glad.getNativeSurface().getClass().getName());
+
+ glad.addGLEventListener(demo);
+
+ final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener();
+ glad.addGLEventListener(snapshotGLEventListener);
+
+ glad.display(); // initial resize/display
+
+ // 1 - szStep = 2
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ // 2, 3 (resize + display)
+ szStep = 1;
+ setComponentSize(frame, nca, widthStep*szStep, heightStep*szStep);
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ glad.display();
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ // 4, 5 (resize + display)
+ szStep = 4;
+ setComponentSize(frame, nca, widthStep*szStep, heightStep*szStep);
+ Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getWidth()+"x"+glad.getHeight(),
+ AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep));
+ glad.display();
+ snapshotGLEventListener.setMakeSnapshot();
+ glad.display();
+
+ Thread.sleep(50);
+
+ try {
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ frame.setVisible(false);
+ frame.remove(nca);
+ frame.dispose();
+ }});
+ } catch( Throwable throwable ) {
+ throwable.printStackTrace();
+ Assume.assumeNoException( throwable );
+ }
+ glad.destroy();
+ System.out.println("Fin: "+nca);
+ System.out.println("Fin: "+glad);
+ }
+
+ @Test
+ public void testAvailableInfo() {
+ GLDrawableFactory f = GLDrawableFactory.getDesktopFactory();
+ if(null != f) {
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
+ }
+ f = GLDrawableFactory.getEGLFactory();
+ if(null != f) {
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
+ }
+ }
+
+ @Test
+ public void testGL2OnScreenDblBuf() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ doTest(false, reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenLayerAuto() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ doTest(true, reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenFBOMSAA() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setFBO(true);
+ reqGLCaps.setOnscreen(true); // get native NEWT Window, not OffscreenWindow
+ reqGLCaps.setSampleBuffers(true);
+ reqGLCaps.setNumSamples(4);
+ doTest(true, reqGLCaps, new GearsES2(1));
+ }
+
+ @Test
+ public void testGL2OffScreenPbuffer() throws InterruptedException {
+ final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2);
+ if(null == reqGLCaps) return;
+ reqGLCaps.setPBuffer(true);
+ reqGLCaps.setOnscreen(true); // get native NEWT Window, not OffscreenWindow
+ doTest(true, reqGLCaps, new GearsES2(1));
+ }
+
+ public static void main(String args[]) throws IOException {
+ org.junit.runner.JUnitCore.main(TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT.class.getName());
+ }
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLCapabilities01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLCapabilities01NEWT.java
deleted file mode 100644
index cd1107e25..000000000
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLCapabilities01NEWT.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/**
- * Copyright 2010 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
-
-package com.jogamp.opengl.test.junit.jogl.acore;
-
-import java.io.IOException;
-
-import javax.media.nativewindow.CapabilitiesImmutable;
-import javax.media.opengl.GLCapabilities;
-import javax.media.opengl.GLCapabilitiesImmutable;
-import javax.media.opengl.GLContext;
-import javax.media.opengl.GLDrawable;
-import javax.media.opengl.GLDrawableFactory;
-import javax.media.opengl.GLEventListener;
-import javax.media.opengl.GLProfile;
-
-import jogamp.opengl.GLGraphicsConfigurationUtil;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import com.jogamp.newt.NewtFactory;
-import com.jogamp.newt.Window;
-import com.jogamp.opengl.JoglVersion;
-import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
-import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
-import com.jogamp.opengl.test.junit.util.UITestCase;
-
-public class TestGLCapabilities01NEWT extends UITestCase {
- static final int width = 100;
- static final int height = 100;
-
- boolean checkProfile(String profile) {
- if( !GLProfile.isAvailable(profile) ) {
- System.err.println("Profile "+profile+" n/a");
- return false;
- }
- return true;
- }
-
- void doTest(GLCapabilitiesImmutable reqGLCaps, GLEventListener demo) throws InterruptedException {
- System.out.println("Requested GL Caps: "+reqGLCaps);
-
- final GLCapabilitiesImmutable expGLCaps;
- if( GLGraphicsConfigurationUtil.isGLCapabilitiesOffscreenAutoSelection(reqGLCaps) ) {
- final GLDrawableFactory f = GLDrawableFactory.getFactory(reqGLCaps.getGLProfile());
- final boolean fboAvailable = true ; // f.canCreateFBO(null, reqGLCaps.getGLProfile());
- final boolean pbufferAvailable = f.canCreateGLPbuffer(null);
- expGLCaps = GLGraphicsConfigurationUtil.fixGLCapabilities(reqGLCaps, fboAvailable, pbufferAvailable);
- } else {
- expGLCaps = reqGLCaps;
- }
- System.out.println("Expected GL Caps: "+expGLCaps);
- //
- // Create native windowing resources .. X11/Win/OSX
- //
- final Window window = NewtFactory.createWindow(reqGLCaps);
- Assert.assertNotNull(window);
- window.setSize(width, height);
- window.setVisible(true);
- Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true));
- Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true));
- System.out.println("Window: "+window.getClass().getName());
-
- // Check caps of NativeWindow config w/o GL
- final CapabilitiesImmutable chosenCaps = window.getGraphicsConfiguration().getChosenCapabilities();
- System.out.println("Window Caps Pre_GL: "+chosenCaps);
- Assert.assertNotNull(chosenCaps);
- Assert.assertTrue(chosenCaps.getGreenBits()>5);
- Assert.assertTrue(chosenCaps.getBlueBits()>5);
- Assert.assertTrue(chosenCaps.getRedBits()>5);
-
- //
- // Create native OpenGL resources .. XGL/WGL/CGL ..
- // equivalent to GLAutoDrawable methods: setVisible(true)
- //
- final GLDrawableFactory factory = GLDrawableFactory.getFactory(reqGLCaps.getGLProfile());
-
- final GLDrawable drawable = factory.createGLDrawable(window);
- Assert.assertNotNull(drawable);
- System.out.println("Drawable Pre-GL(0): "+drawable.getClass().getName()+", "+drawable.getNativeSurface().getClass().getName());
-
- //
- drawable.setRealized(true);
- Assert.assertTrue(drawable.isRealized());
-
- System.out.println("Window Caps PostGL : "+window.getGraphicsConfiguration().getChosenCapabilities());
- System.out.println("Drawable Post-GL(1): "+drawable.getClass().getName()+", "+drawable.getNativeSurface().getClass().getName());
-
- // Check caps of GLDrawable after realization
- final GLCapabilitiesImmutable chosenGLCaps = drawable.getChosenGLCapabilities();
- System.out.println("Chosen GL Caps(1): "+chosenGLCaps);
- Assert.assertNotNull(chosenGLCaps);
- Assert.assertTrue(chosenGLCaps.getGreenBits()>5);
- Assert.assertTrue(chosenGLCaps.getBlueBits()>5);
- Assert.assertTrue(chosenGLCaps.getRedBits()>5);
- Assert.assertTrue(chosenGLCaps.getDepthBits()>4);
- Assert.assertEquals(expGLCaps.isOnscreen(), chosenGLCaps.isOnscreen());
- Assert.assertEquals(expGLCaps.isFBO(), chosenGLCaps.isFBO());
- Assert.assertEquals(expGLCaps.isPBuffer(), chosenGLCaps.isPBuffer());
- Assert.assertEquals(expGLCaps.isBitmap(), chosenGLCaps.isBitmap());
- if(chosenGLCaps.isOnscreen() || chosenGLCaps.isFBO()) {
- // dbl buffer may be disabled w/ offscreen pbuffer and bitmap
- Assert.assertEquals(expGLCaps.getDoubleBuffered(), chosenGLCaps.getDoubleBuffered());
- }
-
- GLContext context = drawable.createContext(null);
- Assert.assertNotNull(context);
- int res = context.makeCurrent();
- Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res);
- context.release();
-
- System.out.println("Chosen GL Caps(2): "+drawable.getChosenGLCapabilities());
- System.out.println("Drawable Post-GL(2): "+drawable.getClass().getName()+", "+drawable.getNativeSurface().getClass().getName());
-
- drawable.setRealized(false);
- window.destroy();
- }
-
- @Test
- public void testAvailableInfo() {
- GLDrawableFactory f = GLDrawableFactory.getDesktopFactory();
- if(null != f) {
- System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
- }
- f = GLDrawableFactory.getEGLFactory();
- if(null != f) {
- System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString());
- }
- }
-
- @Test
- public void testGL2OnScreenDblBuf() throws InterruptedException {
- if(!checkProfile(GLProfile.GL2)) {
- return;
- }
- final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GL2));
- doTest(reqGLCaps, new GearsES2(1));
- }
-
- @Test
- public void testGL2OffScreenAutoDblBuf() throws InterruptedException {
- if(!checkProfile(GLProfile.GL2)) {
- return;
- }
- final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GL2));
- reqGLCaps.setOnscreen(false);
- doTest(reqGLCaps, new GearsES2(1));
- }
-
- @Test
- public void testGL2OffScreenFBODblBuf() throws InterruptedException {
- if(!checkProfile(GLProfile.GL2)) {
- return;
- }
- final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GL2));
- reqGLCaps.setOnscreen(false);
- reqGLCaps.setFBO(true);
- doTest(reqGLCaps, new GearsES2(1));
- }
-
- @Test
- public void testGL2OffScreenPbufferDblBuf() throws InterruptedException {
- if(!checkProfile(GLProfile.GL2)) {
- return;
- }
- final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GL2));
- reqGLCaps.setOnscreen(false);
- reqGLCaps.setPBuffer(true);
- doTest(reqGLCaps, new GearsES2(1));
- }
-
- @Test
- public void testGL2OffScreenBitmapDblBuf() throws InterruptedException {
- if(!checkProfile(GLProfile.GL2)) {
- return;
- }
- final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GL2));
- reqGLCaps.setOnscreen(false);
- reqGLCaps.setBitmap(true);
- doTest(reqGLCaps, new GearsES2(1));
- }
-
- @Test
- public void testES2OnScreenDblBuf() throws InterruptedException {
- if(!checkProfile(GLProfile.GLES2)) {
- return;
- }
- final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GLES2));
- doTest(reqGLCaps, new GearsES2(1));
- }
-
- @Test
- public void testES2OffScreenAutoDblBuf() throws InterruptedException {
- if(!checkProfile(GLProfile.GLES2)) {
- return;
- }
- final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GLES2));
- reqGLCaps.setOnscreen(false);
- doTest(reqGLCaps, new GearsES2(1));
- }
-
- @Test
- public void testES2OffScreenFBODblBuf() throws InterruptedException {
- if(!checkProfile(GLProfile.GLES2)) {
- return;
- }
- final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GLES2));
- reqGLCaps.setOnscreen(false);
- reqGLCaps.setFBO(true);
- doTest(reqGLCaps, new GearsES2(1));
- }
-
- @Test
- public void testES2OffScreenPbufferDblBuf() throws InterruptedException {
- if(!checkProfile(GLProfile.GLES2)) {
- return;
- }
- final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GLES2));
- reqGLCaps.setOnscreen(false);
- reqGLCaps.setPBuffer(true);
- doTest(reqGLCaps, new GearsES2(1));
- }
-
- /** Not implemented !
- @Test
- public void testES2OffScreenBitmapDblBuf() throws InterruptedException {
- if(!checkProfile(GLProfile.GLES2)) {
- return;
- }
- final GLCapabilities reqGLCaps = new GLCapabilities(GLProfile.get(GLProfile.GLES2));
- reqGLCaps.setOnscreen(false);
- reqGLCaps.setBitmap(true);
- doTest(reqGLCaps, new GearsES2(1));
- } */
-
- public static void main(String args[]) throws IOException {
- org.junit.runner.JUnitCore.main(TestGLCapabilities01NEWT.class.getName());
- }
-
-}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
index cece4c6d5..4c1130498 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
@@ -39,13 +39,14 @@ import com.jogamp.newt.event.WindowUpdateEvent;
import com.jogamp.newt.opengl.GLWindow;
import javax.media.opengl.GLAutoDrawable;
-import javax.media.opengl.GLAutoDrawableDelegate;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
+
+import com.jogamp.opengl.GLAutoDrawableDelegate;
import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
@@ -81,14 +82,17 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true));
Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true));
- GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
- GLDrawable drawable = factory.createGLDrawable(window);
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
+ final GLDrawable drawable = factory.createGLDrawable(window);
Assert.assertNotNull(drawable);
drawable.setRealized(true);
Assert.assertTrue(drawable.isRealized());
- final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, null, window, false) {
+ final GLContext context = drawable.createContext(null);
+ Assert.assertNotNull(context);
+
+ final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context, window, false, null) {
@Override
protected void destroyImplInLock() {
super.destroyImplInLock();
@@ -104,7 +108,7 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
}
@Override
public void windowResized(WindowEvent e) {
- glad.windowResizedOp();
+ glad.windowResizedOp(window.getWidth(), window.getHeight());
}
@Override
public void windowDestroyNotify(WindowEvent e) {
@@ -123,9 +127,13 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
GLAutoDrawable glad1 = createGLAutoDrawable(caps, 64, 64, width, height, quitAdapter); // no GLContext!
GLAutoDrawable glad2 = createGLAutoDrawable(caps, 2*64+width, 64, width+100, height+100, quitAdapter); // no GLContext!
- // create single context using glad1 and assign it to glad1
+ // create single context using glad1 and assign it to glad1,
+ // after destroying the prev. context!
{
- GLContext singleCtx = glad1.createContext(null);
+ final GLContext oldCtx = glad1.getContext();
+ Assert.assertNotNull(oldCtx);
+ oldCtx.destroy();
+ final GLContext singleCtx = glad1.createContext(null);
Assert.assertNotNull(singleCtx);
int res = singleCtx.makeCurrent();
Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res);
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDrawable01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDrawable01NEWT.java
deleted file mode 100644
index a6e9cfb07..000000000
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDrawable01NEWT.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- * Copyright 2010 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
-
-package com.jogamp.opengl.test.junit.jogl.acore;
-
-import java.io.IOException;
-
-import javax.media.nativewindow.CapabilitiesImmutable;
-import javax.media.opengl.GL;
-import javax.media.opengl.GLCapabilities;
-import javax.media.opengl.GLCapabilitiesImmutable;
-import javax.media.opengl.GLContext;
-import javax.media.opengl.GLDrawable;
-import javax.media.opengl.GLDrawableFactory;
-import javax.media.opengl.GLProfile;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import com.jogamp.newt.NewtFactory;
-import com.jogamp.newt.Window;
-import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
-import com.jogamp.opengl.test.junit.util.UITestCase;
-
-public class TestGLDrawable01NEWT extends UITestCase {
- static final int width = 200, height = 200;
-
- void doTest(String profile, boolean onscreen, boolean fbo, boolean pbuffer) throws InterruptedException {
- if( !GLProfile.isAvailable(profile) ) {
- System.err.println("Profile "+profile+" n/a");
- return;
- }
-
- final GLProfile glp = GLProfile.get(profile);
- final GLCapabilities reqGLCaps = new GLCapabilities(glp);
-
- reqGLCaps.setOnscreen(onscreen);
- reqGLCaps.setPBuffer(!onscreen && pbuffer);
- reqGLCaps.setFBO(!onscreen && fbo);
- reqGLCaps.setDoubleBuffered(onscreen);
- // System.out.println("Requested: "+caps);
-
- //
- // Create native windowing resources .. X11/Win/OSX
- //
- Window window = NewtFactory.createWindow(reqGLCaps);
- Assert.assertNotNull(window);
- window.setSize(width, height);
- window.setVisible(true);
- AWTRobotUtil.waitForVisible(window, true);
- AWTRobotUtil.waitForRealized(window, true);
- // System.out.println("Created: "+window);
-
- // Check caps of NativeWindow config w/o GL
- final CapabilitiesImmutable chosenCaps = window.getGraphicsConfiguration().getChosenCapabilities();
- Assert.assertNotNull(chosenCaps);
- Assert.assertTrue(chosenCaps.getGreenBits()>5);
- Assert.assertTrue(chosenCaps.getBlueBits()>5);
- Assert.assertTrue(chosenCaps.getRedBits()>5);
-
- //
- // Create native OpenGL resources .. XGL/WGL/CGL ..
- // equivalent to GLAutoDrawable methods: setVisible(true)
- //
- final GLDrawableFactory factory = GLDrawableFactory.getFactory(glp);
-
- final GLDrawable drawable = factory.createGLDrawable(window);
- Assert.assertNotNull(drawable);
- // System.out.println("Pre: "+drawable);
- //
- drawable.setRealized(true);
- Assert.assertTrue(drawable.isRealized());
-
- // Check caps of GLDrawable after realization
- final GLCapabilitiesImmutable chosenGLCaps = drawable.getChosenGLCapabilities();
- Assert.assertNotNull(chosenGLCaps);
- Assert.assertTrue(chosenGLCaps.getGreenBits()>5);
- Assert.assertTrue(chosenGLCaps.getBlueBits()>5);
- Assert.assertTrue(chosenGLCaps.getRedBits()>5);
- Assert.assertTrue(chosenGLCaps.getDepthBits()>4);
- Assert.assertEquals(reqGLCaps.isOnscreen(), chosenGLCaps.isOnscreen());
- Assert.assertEquals(reqGLCaps.isOnscreen(), chosenGLCaps.getDoubleBuffered()); // offscreen shall be !dbl-buffer
- // System.out.println("Post: "+drawable);
-
- GLContext context = drawable.createContext(null);
- Assert.assertNotNull(context);
- // System.out.println(context);
-
- int res = context.makeCurrent();
- Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res);
-
- // draw something ..
- final GL gl = context.getGL();
- gl.glClearColor(1, 1, 1, 1);
- gl.glEnable(GL.GL_DEPTH_TEST);
- Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
- gl.glViewport(0, 0, width, height);
- gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
- Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
-
- drawable.swapBuffers();
- context.release();
-
- Thread.sleep(50);
-
- context.destroy();
- drawable.setRealized(false);
- window.destroy();
- // System.out.println("Final: "+window);
- }
-
- @Test
- public void testGL2OnScreen() throws InterruptedException {
- doTest(GLProfile.GL2, true, false, false);
- }
-
- @Test
- public void testES2OnScreen() throws InterruptedException {
- doTest(GLProfile.GLES2, true, false, false);
- }
-
- @Test
- public void testGL2PBuffer() throws InterruptedException {
- doTest(GLProfile.GL2, false, false, true);
- }
-
- @Test
- public void testES2PBuffer() throws InterruptedException {
- doTest(GLProfile.GLES2, false, false, true);
- }
-
- // @Test // TODO: FBO-Drawable via createGLDrawable and pre-exisiting NativeSurface
- public void testGL2FBO() throws InterruptedException {
- doTest(GLProfile.GL2, false, true, false);
- }
-
- // @Test // TODO: FBO-Drawable via createGLDrawable and pre-exisiting NativeSurface
- public void testES2FBO() throws InterruptedException {
- doTest(GLProfile.GLES2, false, true, false);
- }
-
- public static void main(String args[]) throws IOException {
- org.junit.runner.JUnitCore.main(TestGLDrawable01NEWT.class.getName());
- }
-
-}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLExtensionQueryOffscreen.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLExtensionQueryOffscreen.java
index e4245ef11..d4f3fece5 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLExtensionQueryOffscreen.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLExtensionQueryOffscreen.java
@@ -32,14 +32,11 @@ import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
-import javax.media.nativewindow.AbstractGraphicsDevice;
-import javax.media.opengl.DefaultGLCapabilitiesChooser;
import javax.media.opengl.GL;
-import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
-import javax.media.opengl.GLCapabilitiesChooser;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLOffscreenAutoDrawable;
import javax.media.opengl.GLProfile;
import jogamp.opengl.GLDrawableFactoryImpl;
@@ -77,13 +74,11 @@ public class TestGLExtensionQueryOffscreen {
@Test
public void testJogl2ExtensionCheck2() {
- GLCapabilities caps = new GLCapabilities(GLProfile.getDefault());
- GLDrawableFactory factory = GLDrawableFactory.getDesktopFactory();
- GLCapabilitiesChooser glCapsChooser = new DefaultGLCapabilitiesChooser();
- AbstractGraphicsDevice agd = factory.getDefaultDevice();
+ final GLCapabilities caps = new GLCapabilities(GLProfile.getDefault());
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
+ final GLOffscreenAutoDrawable drawable = factory.createOffscreenAutoDrawable(null, caps, null, 256, 256, null);
- GLAutoDrawable drawable = factory.createGLPbuffer(agd, caps, glCapsChooser, 256, 256, null);
- GLContext context = drawable.getContext();
+ final GLContext context = drawable.getContext();
context.makeCurrent();
String extensions;
try {
@@ -94,8 +89,8 @@ public class TestGLExtensionQueryOffscreen {
String[] tabExtensions = extensions.split(" ");
SortedSet setExtensions = new TreeSet();
Collections.addAll(setExtensions, tabExtensions);
- System.out.println("DefaulContext: "+context);
- System.out.println("DefaulContext: "+setExtensions);
+ System.out.println("DefaultContext: "+context);
+ System.out.println("DefaultContext: "+setExtensions);
}
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNEWTCloseX11DisplayBug565.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNEWTCloseX11DisplayBug565.java
index 33a9b7799..c1b7464e7 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNEWTCloseX11DisplayBug565.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNEWTCloseX11DisplayBug565.java
@@ -11,12 +11,14 @@ import javax.media.opengl.DefaultGLCapabilitiesChooser;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLOffscreenAutoDrawable;
import javax.media.opengl.GLPbuffer;
import javax.media.opengl.GLProfile;
/**
* Tests the closing the device of GLWindow and GLPBuffer in JOGL
*/
+@SuppressWarnings("deprecation")
public class TestNEWTCloseX11DisplayBug565 {
@Test
@@ -59,7 +61,7 @@ public class TestNEWTCloseX11DisplayBug565 {
@Test
- public void testX11WindowMemoryLeakOffscreenWindow() throws Exception {
+ public void testX11WindowMemoryLeakGLPbuffer() throws Exception {
GLProfile.initSingleton(); // ensure shared resource runner is done
try {
for ( int j = 0; j < 10; j++ ) {
@@ -100,6 +102,48 @@ public class TestNEWTCloseX11DisplayBug565 {
}
}
+ @Test
+ public void testX11WindowMemoryLeakFBOAutoDrawable() throws Exception {
+ GLProfile.initSingleton(); // ensure shared resource runner is done
+ try {
+ for ( int j = 0; j < 10; j++ ) {
+ final int open0;
+ if(NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(false)) {
+ open0 = X11Util.getOpenDisplayConnectionNumber();
+ } else {
+ open0 = 0;
+ }
+ final GLProfile glp = GLProfile.getDefault( );
+ GLCapabilitiesImmutable caps = new GLCapabilities( glp );
+
+
+ GLOffscreenAutoDrawable buffer = GLDrawableFactory.getFactory( glp ).createOffscreenAutoDrawable(
+ null,
+ caps,
+ new DefaultGLCapabilitiesChooser(),
+ 256,
+ 256,
+ null
+ );
+ buffer.display();
+ buffer.destroy();
+
+ if(NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(false)) {
+ final int openD = X11Util.getOpenDisplayConnectionNumber() - open0;
+ if(openD > 0) {
+ X11Util.dumpOpenDisplayConnections();
+ X11Util.dumpPendingDisplayConnections();
+ Assert.assertEquals("New display connection didn't close", 0, openD);
+ }
+ }
+ }
+ }
+ catch ( Exception e ) {
+ e.printStackTrace();
+ Assert.fail(e.getMessage());
+ }
+ }
+
public static void main(String args[]) {
org.junit.runner.JUnitCore.main(TestNEWTCloseX11DisplayBug565.class.getName());
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer01GLCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer01GLCanvasAWT.java
new file mode 100644
index 000000000..d181800c5
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer01GLCanvasAWT.java
@@ -0,0 +1,236 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.jogl.acore;
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.awt.GLCanvas;
+
+import jogamp.nativewindow.jawt.JAWTUtil;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.jogamp.common.os.Platform;
+import com.jogamp.newt.Window;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
+import com.jogamp.opengl.test.junit.util.MiscUtils;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+import com.jogamp.opengl.util.Animator;
+
+public class TestOffscreenLayer01GLCanvasAWT extends UITestCase {
+ static boolean useMSAA = false;
+ static boolean addComp = true;
+ static int swapInterval = 1;
+ static boolean shallUseOffscreenPBufferLayer = false;
+ static boolean noAnimation = false;
+ static Dimension frameSize0;
+ static Dimension frameSize1;
+ static Dimension preferredGLSize;
+ static long durationPerTest = 1000;
+
+ @BeforeClass
+ public static void initClass() {
+ frameSize0 = new Dimension(500,300);
+ frameSize1 = new Dimension(800,600);
+ preferredGLSize = new Dimension(400,200);
+ }
+
+ private void setupFrameAndShow(final Frame f, java.awt.Component comp) throws InterruptedException, InvocationTargetException {
+
+ Container c = new Container();
+ c.setLayout(new BorderLayout());
+ c.add(new Button("north"), BorderLayout.NORTH);
+ c.add(new Button("south"), BorderLayout.SOUTH);
+ c.add(new Button("east"), BorderLayout.EAST);
+ c.add(new Button("west"), BorderLayout.WEST);
+ c.add(comp, BorderLayout.CENTER);
+
+ f.setLayout(new BorderLayout());
+ f.add(new Button("NORTH"), BorderLayout.NORTH);
+ f.add(new Button("SOUTH"), BorderLayout.SOUTH);
+ f.add(new Button("EAST"), BorderLayout.EAST);
+ f.add(new Button("WEST"), BorderLayout.WEST);
+ f.add(c, BorderLayout.CENTER);
+
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ f.pack();
+ f.validate();
+ f.setVisible(true);
+ }});
+ }
+
+ private void end(GLAnimatorControl actrl, final Frame f, Window w) throws InterruptedException, InvocationTargetException {
+ actrl.stop();
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ f.dispose();
+ } } );
+ if(null != w) {
+ w.destroy();
+ }
+ }
+
+ @Test
+ public void testInfo00() throws InterruptedException, InvocationTargetException {
+ System.err.println("Java Version: "+Platform.getJavaVersionNumber());
+ System.err.println("OS Version: "+Platform.getOSVersionNumber());
+ System.err.println("JAWTUtil.isOffscreenLayerRequired(): "+JAWTUtil.isOffscreenLayerRequired());
+ System.err.println("JAWTUtil.isOffscreenLayerSupported(): "+JAWTUtil.isOffscreenLayerSupported());
+ }
+
+ @Test
+ public void testOffscreenLayerGLCanvas_OffscreenLayerWithOnscreenClass() throws InterruptedException, InvocationTargetException {
+ testOffscreenLayerGLCanvas_Impl(true);
+ }
+
+ private void testOffscreenLayerGLCanvas_Impl(boolean offscreenLayer) throws InterruptedException, InvocationTargetException {
+ if(!offscreenLayer && JAWTUtil.isOffscreenLayerRequired()) {
+ System.err.println("onscreen layer n/a");
+ return;
+ }
+ if(offscreenLayer && !JAWTUtil.isOffscreenLayerSupported()) {
+ System.err.println("offscreen layer n/a");
+ return;
+ }
+ final Frame frame1 = new Frame("AWT Parent Frame");
+
+ GLCapabilities caps = new GLCapabilities(null);
+ if(useMSAA) {
+ caps.setNumSamples(4);
+ caps.setSampleBuffers(true);
+ }
+ if(shallUseOffscreenPBufferLayer) {
+ caps.setPBuffer(true);
+ caps.setOnscreen(true); // simulate normal behavior ..
+ }
+ final GLCanvas glc = new GLCanvas(caps);
+ glc.setShallUseOffscreenLayer(offscreenLayer); // trigger offscreen layer - if supported
+ glc.setPreferredSize(preferredGLSize);
+ glc.setMinimumSize(preferredGLSize);
+ glc.setSize(preferredGLSize);
+
+ GearsES2 demo1 = new GearsES2(swapInterval);
+ if(noAnimation) {
+ demo1.setDoRotation(false);
+ }
+ glc.addGLEventListener(demo1);
+
+ frame1.setSize(frameSize0);
+ setupFrameAndShow(frame1, glc);
+ Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glc, true));
+ Assert.assertEquals(true, AWTRobotUtil.waitForVisible(glc, true));
+ Assert.assertEquals(JAWTUtil.isOffscreenLayerSupported() && offscreenLayer,
+ glc.isOffscreenLayerSurfaceEnabled());
+
+ GLAnimatorControl animator1 = new Animator(glc);
+ if(!noAnimation) {
+ animator1.start();
+ }
+ animator1.setUpdateFPSFrames(60, System.err);
+
+ Thread.sleep(durationPerTest/2);
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ frame1.setSize(frameSize1);
+ frame1.pack();
+ frame1.validate();
+ }});
+
+ Thread.sleep(durationPerTest/2);
+
+ end(animator1, frame1, null);
+ }
+
+ public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) {
+ Assert.assertNotNull(demo);
+ Assert.assertNotNull(glWindow);
+ Window window = glWindow.getDelegatedWindow();
+ if(debug) {
+ MiscUtils.setFieldIfExists(demo, "glDebug", true);
+ MiscUtils.setFieldIfExists(demo, "glTrace", true);
+ }
+ if(!MiscUtils.setFieldIfExists(demo, "window", window)) {
+ MiscUtils.setFieldIfExists(demo, "glWindow", glWindow);
+ }
+ }
+
+ static int atoi(String a) {
+ int i=0;
+ try {
+ i = Integer.parseInt(a);
+ } catch (Exception ex) { ex.printStackTrace(); }
+ return i;
+ }
+
+ public static void main(String args[]) throws IOException {
+ for(int i=0; i
+ * {@link JFrame} . {@link Container}+ . {@link NewtCanvasAWT} . {@link GLWindow}
+ *
+ *
+ * + Container is the JFrame's implicit root content pane
+ *
+ */
public class TestFocus01SwingAWTRobot extends UITestCase {
static int width, height;
static long durationPerTest = 10;
@@ -125,6 +135,10 @@ public class TestFocus01SwingAWTRobot extends UITestCase {
AWTKeyAdapter buttonKA = new AWTKeyAdapter("Button");
button.addKeyListener(buttonKA);
eventCountAdapters.add(buttonKA);
+ AWTMouseAdapter buttonMA = new AWTMouseAdapter("Button");
+ button.addMouseListener(buttonMA);
+ eventCountAdapters.add(buttonMA);
+
frame1.getContentPane().add(button, BorderLayout.NORTH);
frame1.setSize(width, height);
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
@@ -158,13 +172,18 @@ public class TestFocus01SwingAWTRobot extends UITestCase {
Assert.assertEquals(false, newtCanvasAWTFA.focusGained());
System.err.println("FOCUS AWT Button sync");
AWTRobotUtil.assertKeyType(robot, java.awt.event.KeyEvent.VK_A, 2, button, buttonKA);
+ AWTRobotUtil.assertMouseClick(robot, java.awt.event.InputEvent.BUTTON1_MASK, 1,
+ button, buttonMA);
+ AWTRobotUtil.assertMouseClick(robot, java.awt.event.InputEvent.BUTTON1_MASK, 2,
+ button, buttonMA);
// Request the AWT focus, which should automatically provide the NEWT window with focus.
Thread.sleep(100); // allow event sync
System.err.println("FOCUS NEWT Canvas/GLWindow request");
EventCountAdapterUtil.reset(eventCountAdapters);
AWTRobotUtil.assertRequestFocusAndWait(robot, newtCanvasAWT, newtCanvasAWT.getNEWTChild(), glWindow1FA, buttonFA);
- Assert.assertEquals(false, newtCanvasAWTFA.focusGained());
+ Assert.assertTrue("Focus prev. gained, but NewtCanvasAWT didn't loose it. Gainer: "+glWindow1FA+"; Looser "+newtCanvasAWTFA,
+ AWTRobotUtil.waitForFocus(glWindow1FA, newtCanvasAWTFA));
System.err.println("FOCUS NEWT Canvas/GLWindow sync");
AWTRobotUtil.assertKeyType(robot, java.awt.event.KeyEvent.VK_A, 2, glWindow1, glWindow1KA);
Assert.assertEquals("AWT parent canvas received keyboard events", 0, newtCanvasAWTKA.getCount());
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java b/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java
index a0efa53ad..d8a9640c1 100644
--- a/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java
+++ b/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java
@@ -56,6 +56,15 @@ import java.io.IOException;
import com.jogamp.opengl.test.junit.util.*;
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
+/**
+ * Testing focus traversal of an AWT component tree with {@link NewtCanvasAWT} attached.
+ *
- *
- * @param simpleTestName will be used as the filename prefix
* @param sn sequential number
* @param postSNDetail optional detail to be added to the filename after sn
* @param gl the current GL context object. It's read drawable is being used as the pixel source and to gather some details which will end up in the filename.
@@ -137,30 +156,80 @@ public abstract class UITestCase {
* It shall not end with a directory separator, {@link File#separatorChar}.
* If null the current working directory is being used.
*/
- public static void snapshot(String simpleTestName, int sn, String postSNDetail, GL gl, GLReadBufferUtil readBufferUtil, String fileSuffix, String destPath) {
+ public void snapshot(int sn, String postSNDetail, GL gl, GLReadBufferUtil readBufferUtil, String fileSuffix, String destPath) {
if(null == fileSuffix) {
fileSuffix = TextureIO.PNG;
}
- final StringWriter filenameSW = new StringWriter();
- {
+ final int maxSimpleTestNameLen = getMaxTestNameLen()+getClass().getSimpleName().length()+1;
+ final String simpleTestName = this.getSimpleTestName(".");
+ final String filenameBaseName;
+ {
final GLDrawable drawable = gl.getContext().getGLReadDrawable();
final GLCapabilitiesImmutable caps = drawable.getChosenGLCapabilities();
+ final String accel = caps.getHardwareAccelerated() ? "hw" : "sw" ;
+ final String scrnm;
+ if(caps.isOnscreen()) {
+ scrnm = "onscreen";
+ } else if(caps.isFBO()) {
+ scrnm = "fbobject";
+ } else if(caps.isPBuffer()) {
+ scrnm = "pbuffer_";
+ } else if(caps.isBitmap()) {
+ scrnm = "bitmap__";
+ } else {
+ scrnm = "unknown_";
+ }
+ final String dblb = caps.getDoubleBuffered() ? "dbl" : "one";
final String F_pfmt = readBufferUtil.hasAlpha() ? "rgba" : "rgb_";
final String pfmt = caps.getAlphaBits() > 0 ? "rgba" : "rgb_";
- final String aaext = caps.getSampleExtension();
final int samples = caps.getNumSamples() ;
+ final String aaext = caps.getSampleExtension();
postSNDetail = null != postSNDetail ? "-"+postSNDetail : "";
- final PrintWriter pw = new PrintWriter(filenameSW);
- pw.printf("%s-n%04d%s-F_%s-I_%s-S%d_%s-%s-%04dx%04d.%s",
- simpleTestName, sn, postSNDetail, F_pfmt, pfmt, samples, aaext, drawable.getGLProfile().getName(),
- drawable.getWidth(), drawable.getHeight(), fileSuffix);
+
+ filenameBaseName = String.format("%-"+maxSimpleTestNameLen+"s-n%04d%s-%-6s-%s-%s-B%s-F%s_I%s-S%02d_%s-%04dx%04d.%s",
+ simpleTestName, sn, postSNDetail, drawable.getGLProfile().getName(), accel,
+ scrnm, dblb, F_pfmt, pfmt, samples, aaext,
+ drawable.getWidth(), drawable.getHeight(), fileSuffix).replace(' ', '_');
}
- final String filename = null != destPath ? destPath + File.separator + filenameSW.toString() : filenameSW.toString();
- System.err.println(Thread.currentThread().getName()+": ** screenshot: "+filename);
+ final String filename = null != destPath ? destPath + File.separator + filenameBaseName : filenameBaseName;
+ System.err.println(Thread.currentThread().getName()+": ** screenshot: "+filename+", maxTestNameLen "+maxSimpleTestNameLen+", <"+simpleTestName+">");
gl.glFinish(); // just make sure rendering finished ..
if(readBufferUtil.readPixels(gl, false)) {
readBufferUtil.write(new File(filename));
}
- }
+ }
+
+ public class SnapshotGLEventListener implements GLEventListener {
+ private final GLReadBufferUtil screenshot;
+ private volatile boolean makeShot = false;
+ private volatile int displayCount=0;
+ private volatile int reshapeCount=0;
+ public SnapshotGLEventListener(GLReadBufferUtil screenshot) {
+ this.screenshot = screenshot;
+ }
+ public SnapshotGLEventListener() {
+ this.screenshot = new GLReadBufferUtil(false, false);
+ }
+
+ public void init(GLAutoDrawable drawable) {}
+ public void dispose(GLAutoDrawable drawable) {}
+ public void display(GLAutoDrawable drawable) {
+ final GL gl = drawable.getGL();
+ System.err.println(Thread.currentThread().getName()+": ** display: "+displayCount+": "+drawable.getWidth()+"x"+drawable.getHeight()+", makeShot "+makeShot);
+ if(makeShot) {
+ makeShot=false;
+ snapshot(displayCount, null, gl, screenshot, TextureIO.PNG, null);
+ }
+ displayCount++;
+ }
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+ System.err.println(Thread.currentThread().getName()+": ** reshape: "+reshapeCount+": "+width+"x"+height+" - "+drawable.getWidth()+"x"+drawable.getHeight());
+ reshapeCount++;
+ }
+ public void setMakeSnapshot() {
+ makeShot=true;
+ }
+ };
+
}
--
cgit v1.2.3
From 4f8432b0a5ac2a030056884c8f6c877435aaf5c8 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Sat, 29 Sep 2012 03:02:09 +0200
Subject: GLDrawableHelper.init(..): Avoid double reshape if subsequent display
issues reshape
Adding boolean sendReshape argument to be set to false, if subsequent display won't reshape.
---
src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java | 2 +-
src/jogl/classes/javax/media/opengl/awt/GLCanvas.java | 2 +-
src/jogl/classes/javax/media/opengl/awt/GLJPanel.java | 2 +-
src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java | 2 +-
src/jogl/classes/jogamp/opengl/GLDrawableHelper.java | 9 ++++++---
5 files changed, 10 insertions(+), 7 deletions(-)
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
index 02f62daec..6fec18470 100644
--- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
+++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
@@ -118,7 +118,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
private final Runnable initAction = new Runnable() {
@Override
public void run() {
- helper.init(GLCanvas.this);
+ helper.init(GLCanvas.this, !sendReshape);
}
};
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
index 329cf9e3f..335322be9 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
@@ -947,7 +947,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private final Runnable initAction = new Runnable() {
@Override
public void run() {
- helper.init(GLCanvas.this);
+ helper.init(GLCanvas.this, !sendReshape);
}
};
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
index 6d4a5861f..d0b9fb913 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
@@ -679,7 +679,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
if (!backend.preGL(g)) {
return;
}
- helper.init(GLJPanel.this);
+ helper.init(GLJPanel.this, !sendReshape);
backend.postGL(g, false);
}
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index 07029f143..d49fc75d9 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -265,7 +265,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
@Override
public final void run() {
// Lock: Locked Surface/Window by MakeCurrent/Release
- helper.init(GLAutoDrawableBase.this);
+ helper.init(GLAutoDrawableBase.this, !sendReshape);
resetFPSCounter();
} };
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
index 83b16884e..13c387231 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
@@ -330,8 +330,11 @@ public class GLDrawableHelper {
}
}
- /** The default init action to be called once after ctx is being created @ 1st makeCurrent(). */
- public final void init(GLAutoDrawable drawable) {
+ /**
+ * The default init action to be called once after ctx is being created @ 1st makeCurrent().
+ * @param sendReshape set to true if the subsequent display call won't reshape, otherwise false to avoid double reshape.
+ **/
+ public final void init(GLAutoDrawable drawable, boolean sendReshape) {
synchronized(listenersLock) {
final ArrayList _listeners = listeners;
for (int i=0; i < _listeners.size(); i++) {
@@ -341,7 +344,7 @@ public class GLDrawableHelper {
// This may happen not just for initial setup, but for ctx recreation due to resource change (drawable/window),
// hence it must be called unconditional, always.
listenersToBeInit.remove(listener); // remove if exist, avoiding dbl init
- init( listener, drawable, true /* sendReshape */);
+ init( listener, drawable, sendReshape);
}
}
}
--
cgit v1.2.3
From 742282292bb115343287a626b35211e81d695bad Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Fri, 5 Oct 2012 06:32:50 +0200
Subject: Use helper.isExternalAnimatorAnimating() instead of
helper.isAnimatorAnimating() for decision whether to display() now; Minor API
comments.
---
src/jogl/classes/javax/media/opengl/GLDrawable.java | 2 +-
src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java | 4 ++--
src/newt/classes/jogamp/newt/DisplayImpl.java | 1 +
3 files changed, 4 insertions(+), 3 deletions(-)
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/src/jogl/classes/javax/media/opengl/GLDrawable.java b/src/jogl/classes/javax/media/opengl/GLDrawable.java
index 10eea2efc..c0910eb0f 100644
--- a/src/jogl/classes/javax/media/opengl/GLDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLDrawable.java
@@ -149,7 +149,7 @@ public interface GLDrawable {
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.
- @return A copy of the queried object.
+ @return The immutable queried instance.
*/
public GLCapabilitiesImmutable getChosenGLCapabilities();
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index d49fc75d9..d76272723 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -95,7 +95,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
protected final void defaultWindowRepaintOp() {
final GLDrawable _drawable = drawable;
if( null != _drawable && _drawable.isRealized() ) {
- if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimating() ) {
+ if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isExternalAnimatorAnimating() ) {
display();
}
}
@@ -124,7 +124,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock
if( _drawable.isRealized() ) {
- if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimating() ) {
+ if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isExternalAnimatorAnimating() ) {
display();
}
}
diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java
index daeb3e886..fbccc5767 100644
--- a/src/newt/classes/jogamp/newt/DisplayImpl.java
+++ b/src/newt/classes/jogamp/newt/DisplayImpl.java
@@ -359,6 +359,7 @@ public abstract class DisplayImpl extends Display {
return "NEWT-Display["+getFQName()+", excl "+exclusive+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", edtRunning "+isEDTRunning()+", "+aDevice+"]";
}
+ /** Dispatch native Toolkit messageges */
protected abstract void dispatchMessagesNative();
private Object eventsLock = new Object();
--
cgit v1.2.3
From 455fed40391afe10ce5ffb9146ca325af63b0a49 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Mon, 8 Oct 2012 01:55:22 +0200
Subject: Fix GLDrawable.swapBuffer() implementation in AWT/SWT GLCanvas and
GLAutoDrawableBase
Simply lock drawable and issue drawable.swapBuffers(), no need to make context current.
---
.../classes/com/jogamp/opengl/swt/GLCanvas.java | 26 ++++++++--------------
.../classes/javax/media/opengl/awt/GLCanvas.java | 11 ++-------
.../classes/jogamp/opengl/GLAutoDrawableBase.java | 12 ++--------
3 files changed, 13 insertions(+), 36 deletions(-)
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
index 24971ff97..73d3cd01e 100644
--- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
+++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
@@ -153,24 +153,16 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
};
/* Swaps buffers, assuming the GLContext is current */
- private final Runnable swapBuffersAction = new Runnable() {
+ private final Runnable swapBuffersOnEDTAction = new Runnable() {
@Override
public void run() {
- drawable.swapBuffers();
- }
- };
-
- /* Swaps buffers, making the GLContext current first */
- private final Runnable makeCurrentAndSwapBuffersOnEDTAction = new Runnable() {
- @Override
- public void run() {
- final RecursiveLock _lock = lock;
- _lock.lock();
- try {
- helper.invokeGL(drawable, context, swapBuffersAction, initAction);
- } finally {
- _lock.unlock();
- }
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ drawable.swapBuffers();
+ } finally {
+ _lock.unlock();
+ }
}
};
@@ -627,7 +619,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
@Override
public void swapBuffers() throws GLException {
- runInGLThread(makeCurrentAndSwapBuffersOnEDTAction);
+ runInGLThread(swapBuffersOnEDTAction);
}
@Override
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
index a5c15dbda..ed069bf22 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
@@ -982,13 +982,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
};
- private final Runnable swapBuffersAction = new Runnable() {
- @Override
- public void run() {
- drawable.swapBuffers();
- }
- };
-
// Workaround for ATI driver bugs related to multithreading issues
// like simultaneous rendering via Animators to canvases that are
// being resized on the AWT event dispatch thread
@@ -1010,8 +1003,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
public void run() {
final RecursiveLock _lock = lock;
_lock.lock();
- try {
- helper.invokeGL(drawable, context, swapBuffersAction, initAction);
+ try {
+ drawable.swapBuffers();
} finally {
_lock.unlock();
}
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index d76272723..42e14366c 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -248,10 +248,8 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
public final void defaultSwapBuffers() throws GLException {
final RecursiveLock _lock = getLock();
_lock.lock();
- try {
- if(drawable!=null && context != null) {
- helper.invokeGL(drawable, context, defaultSwapAction, defaultInitAction);
- }
+ try {
+ drawable.swapBuffers();
} finally {
_lock.unlock();
}
@@ -299,12 +297,6 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
}
- protected final Runnable defaultSwapAction = new Runnable() {
- @Override
- public final void run() {
- drawable.swapBuffers();
- } } ;
-
@Override
public final GLDrawable getDelegatedDrawable() {
return drawable;
--
cgit v1.2.3
From d4114a6142e8d71ccd342ca61b1b73a1ee48411b Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Mon, 8 Oct 2012 02:03:00 +0200
Subject: Refine GLDrawable.swapBuffer() fix (AWT/SWT GLCanvas and
GLAutoDrawableBase) of commit 455fed40391afe10ce5ffb9146ca325af63b0a49
Add drawable null check before using.
---
src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java | 4 +++-
src/jogl/classes/javax/media/opengl/awt/GLCanvas.java | 4 +++-
src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java | 4 +++-
3 files changed, 9 insertions(+), 3 deletions(-)
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
index 73d3cd01e..33322628d 100644
--- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
+++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
@@ -159,7 +159,9 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
final RecursiveLock _lock = lock;
_lock.lock();
try {
- drawable.swapBuffers();
+ if(null != drawable) {
+ drawable.swapBuffers();
+ }
} finally {
_lock.unlock();
}
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
index ed069bf22..31c91e046 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
@@ -1004,7 +1004,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
final RecursiveLock _lock = lock;
_lock.lock();
try {
- drawable.swapBuffers();
+ if(null != drawable) {
+ drawable.swapBuffers();
+ }
} finally {
_lock.unlock();
}
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index 42e14366c..057f28487 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -249,7 +249,9 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
final RecursiveLock _lock = getLock();
_lock.lock();
try {
- drawable.swapBuffers();
+ if(null != drawable) {
+ drawable.swapBuffers();
+ }
} finally {
_lock.unlock();
}
--
cgit v1.2.3
From 1b327874356130096546533a690deff3b7bc876c Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Wed, 17 Oct 2012 08:08:09 +0200
Subject: Minor NEWT Display/Screen API doc
---
src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java | 4 ++--
src/newt/classes/com/jogamp/newt/Display.java | 6 +++---
src/newt/classes/com/jogamp/newt/Screen.java | 8 +++++---
3 files changed, 10 insertions(+), 8 deletions(-)
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index 057f28487..85156e8a1 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -500,8 +500,8 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
/**
* @param t the thread for which context release shall be skipped, usually the animation thread,
* ie. {@link Animator#getThread()}.
- * @deprecated this is an experimental feature,
- * intended for measuring performance in regards to GL context switch
+ * @deprecated This is an experimental feature,
+ * intended for measuring performance in regards to GL context switch.
*/
@Deprecated
public void setSkipContextReleaseThread(Thread t) {
diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java
index de1d58068..e97dec88d 100644
--- a/src/newt/classes/com/jogamp/newt/Display.java
+++ b/src/newt/classes/com/jogamp/newt/Display.java
@@ -88,7 +88,7 @@ public abstract class Display {
public abstract boolean isNativeValid();
/**
- * @return number of references by Screen
+ * @return number of references
*/
public abstract int getReferenceCount();
@@ -96,7 +96,7 @@ public abstract class Display {
* The 1st call will initiate native creation,
* since we follow the lazy creation pattern.
*
- * @return number of references after adding one
+ * @return number of references post operation
* @throws NativeWindowException if the native creation failed.
* @see #removeReference()
*/
@@ -106,7 +106,7 @@ public abstract class Display {
* The last call may destroy this instance,
* if {@link #getDestroyWhenUnused()} returns true.
*
- * @return number of references after removing one
+ * @return number of references post operation
* @see #addReference()
* @see #getDestroyWhenUnused()
* @see #setDestroyWhenUnused(boolean)
diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java
index cfbcc988a..a09748d52 100644
--- a/src/newt/classes/com/jogamp/newt/Screen.java
+++ b/src/newt/classes/com/jogamp/newt/Screen.java
@@ -89,13 +89,14 @@ public abstract class Screen {
public abstract boolean isNativeValid();
/**
- * @return number of references by Window
+ * @return number of references
*/
public abstract int getReferenceCount();
/**
* See {@link Display#addReference()}
- *
+ *
+ * @return number of references post operation
* @throws NativeWindowException if the native creation failed.
* @see #removeReference()
* @see #setDestroyWhenUnused(boolean)
@@ -105,7 +106,8 @@ public abstract class Screen {
/**
* See {@link Display#removeReference()}
- *
+ *
+ * @return number of references post operation
* @see #addReference()
* @see #setDestroyWhenUnused(boolean)
* @see #getDestroyWhenUnused()
--
cgit v1.2.3
From c002e04f848116922a1ed7bd96ead54961649bbd Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Sun, 4 Nov 2012 07:09:39 +0100
Subject: GLAutoDrawable: Fix GLEventListener lifecycle and expose more user
control (API Change) ; Added GLDrawableUtil
A GLEventListener resides in two states, initialized and uninitialized.
When added to a GLAutoDrawable, it is uninitialized.
A first 'display()' will issue GLEventListener's 'init(..)' which renders it initialized.
This is usually accompanied by 'reshape(..)' propagating the drawable's dimension.
Destruction of the GLAutoDrawable will issue GLEventListener's 'dispose(..)' which renders it uninitialized.
It turns our these means of GLEventListener controls are not sufficient in case
the user requires to remove and add them during the lifecycle and rendering of their GLAutoDrawable host.
GLAutoDrawable 'removeGLEventListener(..)' merely removes the GLEventListener from the list,
but does not complete it's lifecycle, i.e. issues 'dispose(..)' if initialized to realease GL related resources.
Hence the following essential API changes are made to complete the lifecycle:
+ public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove);
disposing a single GLEventListener, allowing it's removal from the list being optional
This is demonstrated via GLDrawableUtil.swapGLContextAndAllGLEventListener(GLAutoDrawable a, GLAutoDrawable b), see below.
++++++++
Further more the following API changes were made to expose complete control of
GLEventListener to the user:
- public void removeGLEventListener(GLEventListener listener);
+ public GLEventListener removeGLEventListener(GLEventListener listener);
The return value allows simple pipelining, and also delivers information whether
the passed listener was actually removed.
- public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException;
+ public int getGLEventListenerCount();
+ public GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException;
Dropping the redundant removal by index, while adding count and get methods.
+ public boolean getGLEventListenerInitState(GLEventListener listener);
+ public void setGLEventListenerInitState(GLEventListener listener, boolean initialized);
Allows retrieving and setting of listener states.
All in all these API changes allows a user to experience all freedoms in dealing w/
GLEventListeners hosted by GLAutoDrawable impl. and shall be future proof.
Note that we have avoided the Iterator pattern due to it's overhead of temporal objects creation.
The simple indexed access allows us to implement each method as an atomic operation.
+++++++++++
Further more a simple enqueue(..) method has been added, allowing to just enqueue a GLRunnable
w/o provoking it's execution - as invoke(..) does.
This method pleases a use case where GLRunnables are batched and shall be executed later on..
public boolean invoke(boolean wait, GLRunnable glRunnable);
+ public void enqueue(GLRunnable glRunnable);
+++++++++++
Added GLDrawableUtil, exposes utility function to rearrange GLEventListener, modifiy GLAutoDrawable, etc.
GLDrawableUtil.swapGLContextAndAllGLEventListener(GLAutoDrawable a, GLAutoDrawable b)
is tested and demonstrated w/ TestGLContextDrawableSwitchNEWT.
Manually tested on X11, OSX and Windows.
---
make/scripts/tests-x64.bat | 5 +-
make/scripts/tests.sh | 7 +-
.../classes/com/jogamp/opengl/swt/GLCanvas.java | 73 ++++-
.../com/jogamp/opengl/util/GLDrawableUtil.java | 241 ++++++++++++++++
.../classes/javax/media/opengl/GLAutoDrawable.java | 183 ++++++++++--
.../classes/javax/media/opengl/awt/GLCanvas.java | 62 ++++-
.../classes/javax/media/opengl/awt/GLJPanel.java | 63 ++++-
.../classes/jogamp/opengl/GLAutoDrawableBase.java | 49 +++-
.../classes/jogamp/opengl/GLDrawableHelper.java | 306 ++++++++++++++++-----
.../acore/TestGLContextDrawableSwitchNEWT.java | 64 ++---
.../opengl/test/junit/jogl/demos/es2/GearsES2.java | 11 -
.../test/junit/jogl/demos/es2/RedSquareES2.java | 11 -
.../jogl/demos/es2/TextureSequenceCubeES2.java | 1 -
13 files changed, 876 insertions(+), 200 deletions(-)
create mode 100644 src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/make/scripts/tests-x64.bat b/make/scripts/tests-x64.bat
index c8bc03017..586b65175 100755
--- a/make/scripts/tests-x64.bat
+++ b/make/scripts/tests-x64.bat
@@ -14,12 +14,13 @@ REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedCon
REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT2 %*
REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT %*
-REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile02NEWT %*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile02NEWT %*
+scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNewtAWTWrapper %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNEWT -time 30000
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es1.newt.TestGearsES1NEWT %*
-scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT %*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT %*
REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT -vsync -time 4000 -x 10 -y 10 -width 100 -height 100 -screen 0
REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT -vsync -time 40000 -width 100 -height 100 -screen 0 %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.awt.TestAWTCardLayoutAnimatorStartStopBug532 %*
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index ef64aa7dd..1fa687a21 100755
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -146,6 +146,7 @@ function jrun() {
#D_ARGS="-Djogl.debug.Animator"
#D_ARGS="-Dnativewindow.debug=all"
#D_ARGS="-Djogl.debug.GLCanvas"
+ #D_ARGS="-Djogl.debug.GLCanvas -Djogl.debug.Animator"
#D_ARGS="-Djogl.debug.GLContext -Dnativewindow.debug.X11Util.XSync"
#D_ARGS="-Dnativewindow.debug.X11Util.XSync -Dnativewindow.debug.ToolkitLock.TraceLock"
#D_ARGS="-Dnativewindow.debug.NativeWindow"
@@ -246,7 +247,7 @@ function testawtswt() {
#testnoawt com.jogamp.newt.opengl.GLWindow $*
#testnoawt com.jogamp.opengl.test.junit.jogl.offscreen.TestOffscreen01GLPBufferNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.offscreen.TestOffscreen02BitmapNEWT $*
-testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestElektronenMultipliziererNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFloatUtil01MatrixMatrixMultNOUI $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestPMVMatrix01NEWT $*
@@ -266,7 +267,7 @@ testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES1NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOffscrnCapsNEWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $*
+testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestPointsNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT $*
@@ -349,6 +350,8 @@ testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
#testawt com.jogamp.opengl.test.junit.jogl.awt.TestBug461PBufferSupersamplingSwingAWT
#testawt com.jogamp.opengl.test.junit.jogl.glu.TestBug463ScaleImageMemoryAWT $*
#testawt com.jogamp.opengl.test.junit.jogl.awt.TestAWTCardLayoutAnimatorStartStopBug532 $*
+#testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAWTActionDeadlock00AWT $*
+#testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAWTActionDeadlock01AWT $*
#
# swt (testswt)
diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
index 33322628d..ea794cc78 100644
--- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
+++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
@@ -216,6 +216,26 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
}
};
+ private class DisposeGLEventListenerAction implements Runnable {
+ private GLEventListener listener;
+ private boolean remove;
+ private DisposeGLEventListenerAction(GLEventListener listener, boolean remove) {
+ this.listener = listener;
+ this.remove = remove;
+ }
+
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ listener = helper.disposeGLEventListener(GLCanvas.this, drawable, context, listener, remove);
+ } finally {
+ _lock.unlock();
+ }
+ }
+ };
+
/**
* Storage for the client area rectangle so that it may be accessed from outside of the SWT thread.
*/
@@ -302,7 +322,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
addPaintListener(new PaintListener() {
@Override
public void paintControl(final PaintEvent arg0) {
- if ( !helper.isExternalAnimatorAnimating() ) {
+ if ( !helper.isAnimatorAnimatingOnOtherThread() ) {
display(); // checks: null != drawable
}
}
@@ -439,13 +459,45 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
}
@Override
- public void addGLEventListener(final GLEventListener arg0) {
- helper.addGLEventListener(arg0);
+ public void addGLEventListener(final GLEventListener listener) {
+ helper.addGLEventListener(listener);
}
@Override
- public void addGLEventListener(final int arg0, final GLEventListener arg1) throws IndexOutOfBoundsException {
- helper.addGLEventListener(arg0, arg1);
+ public void addGLEventListener(final int idx, final GLEventListener listener) throws IndexOutOfBoundsException {
+ helper.addGLEventListener(idx, listener);
+ }
+
+ @Override
+ public int getGLEventListenerCount() {
+ return helper.getGLEventListenerCount();
+ }
+
+ @Override
+ public GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException {
+ return helper.getGLEventListener(index);
+ }
+
+ @Override
+ public boolean getGLEventListenerInitState(GLEventListener listener) {
+ return helper.getGLEventListenerInitState(listener);
+ }
+
+ @Override
+ public void setGLEventListenerInitState(GLEventListener listener, boolean initialized) {
+ helper.setGLEventListenerInitState(listener, initialized);
+ }
+
+ @Override
+ public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove) {
+ final DisposeGLEventListenerAction r = new DisposeGLEventListenerAction(listener, remove);
+ runInGLThread(r);
+ return r.listener;
+ }
+
+ @Override
+ public GLEventListener removeGLEventListener(final GLEventListener listener) {
+ return helper.removeGLEventListener(listener);
}
/**
@@ -496,17 +548,12 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
public boolean invoke(final boolean wait, final GLRunnable run) {
return helper.invoke(this, wait, run);
}
-
+
@Override
- public void removeGLEventListener(final GLEventListener arg0) {
- helper.removeGLEventListener(arg0);
+ public void enqueue(GLRunnable glRunnable) {
+ helper.enqueue(glRunnable);
}
- @Override
- public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException {
- return helper.removeGLEventListener(index);
- }
-
@Override
public void setAnimator(final GLAnimatorControl arg0) throws GLException {
helper.setAnimator(arg0);
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
new file mode 100644
index 000000000..8197be4f5
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
@@ -0,0 +1,241 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.util;
+
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLRunnable;
+
+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(GLAnimatorControl animatorCtrl) {
+ return ( null != animatorCtrl ) ? animatorCtrl.isStarted() && animatorCtrl.getThread() != Thread.currentThread() : false ;
+ }
+
+ public static final boolean isAnimatorStarted(GLAnimatorControl animatorCtrl) {
+ return ( null != animatorCtrl ) ? animatorCtrl.isStarted() : false ;
+ }
+
+ public static final boolean isAnimatorAnimatingOnOtherThread(GLAnimatorControl animatorCtrl) {
+ return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() && animatorCtrl.getThread() != Thread.currentThread() : false ;
+ }
+
+ public static final boolean isAnimatorAnimating(GLAnimatorControl animatorCtrl) {
+ return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() : false ;
+ }
+
+ /**
+ * Moves the designated {@link GLEventListener} from {@link GLAutoDrawable} src to dest.
+ * If preserveInitState is true, it's initialized state is preserved
+ * and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued w/ the next {@link GLAutoDrawable#display()} call.
+ *
+ * Note that it is only legal to pass preserveInitState := true,
+ * if the {@link GLContext} of both src and dest are shared, or has itself moved from src to dest.
+ *
+ *
+ * Also note that the caller is encouraged to pause an attached {@link GLAnimatorControl}.
+ *
+ * @param src
+ * @param dest
+ * @param listener
+ * @param preserveInitState
+ */
+ public static final void moveGLEventListener(GLAutoDrawable src, GLAutoDrawable dest, GLEventListener listener, boolean preserveInitState) {
+ final boolean initialized = src.getGLEventListenerInitState(listener);
+ src.removeGLEventListener(listener);
+ dest.addGLEventListener(listener);
+ if(preserveInitState && initialized) {
+ dest.setGLEventListenerInitState(listener, true);
+ dest.enqueue(new ReshapeGLEventListener(listener));
+ } // else .. !init state is default
+ }
+
+ /**
+ * Moves all {@link GLEventListener} from {@link GLAutoDrawable} src to dest.
+ * If preserveInitState is true, it's initialized state is preserved
+ * and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued w/ the next {@link GLAutoDrawable#display()} call.
+ *
+ * Note that it is only legal to pass preserveInitState := true,
+ * if the {@link GLContext} of both src and dest are shared, or has itself moved from src to dest.
+ *
+ *
+ * Also note that the caller is encouraged to pause an attached {@link GLAnimatorControl}.
+ *
+ * @param src
+ * @param dest
+ * @param listener
+ * @param preserveInitState
+ */
+ public static final void moveAllGLEventListener(GLAutoDrawable src, GLAutoDrawable dest, boolean preserveInitState) {
+ for(int count = src.getGLEventListenerCount(); 0a and b,
+ * while preserving it's initialized state, resets the GL-Viewport and issuing {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)}.
+ *
+ * If an {@link GLAnimatorControl} is being attached to {@link GLAutoDrawable} a or b
+ * and the current thread is different than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
+ *
+ * @param a
+ * @param b
+ */
+ public static final void swapGLContextAndAllGLEventListener(GLAutoDrawable a, 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();
+
+ // enqueue reset GL-Viewport
+ a.enqueue(setViewport);
+ b.enqueue(setViewport);
+
+ //
+ // cache all GLEventListener and their init-state
+ // enqueue reshape on their destination, if already initialized
+ //
+ final int aSz = a.getGLEventListenerCount();
+ final GLEventListener[] aGLE = new GLEventListener[aSz];
+ final boolean[] aInit = new boolean[aSz];
+ for(int i=0; i
+ * The GL-Viewport is reset and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued implicit.
+ *
+ *
+ * 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.
+ *
+ * @param src
+ * @param dest
+ */
+ public static final void swapGLContext(GLAutoDrawable src, 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);
+ }
+ for(int i = dest.getGLEventListenerCount() - 1; 0 <= i; i--) {
+ dest.disposeGLEventListener(dest.getGLEventListener(i), false);
+ }
+ dest.setContext( src.setContext( dest.getContext() ) );
+
+ src.enqueue(setViewport);
+ dest.enqueue(setViewport);
+ src.display();
+ dest.display();
+
+ if(aIsPaused) { aAnim.resume(); }
+ if(bIsPaused) { bAnim.resume(); }
+ }
+
+}
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
index 38f1746f9..fc569b13d 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
@@ -166,13 +166,26 @@ public interface GLAutoDrawable extends GLDrawable {
*/
public GLContext setContext(GLContext newCtx);
- /** Adds a {@link GLEventListener} to the end of this drawable queue.
- The listeners are notified of events in the order of the queue. */
+ /**
+ * Adds the given {@link GLEventListener listener} to the end of this drawable queue.
+ * The {@link GLEventListener listeners} are notified of events in the order of the queue.
+ *
+ * The newly added listener's {@link GLEventListener#init(GLAutoDrawable) init(..)}
+ * method will be called once before any other of it's callback methods.
+ * See {@link #getGLEventListenerInitState(GLEventListener)} for details.
+ *
+ * @param listener The GLEventListener object to be inserted
+ */
public void addGLEventListener(GLEventListener listener);
/**
- * Adds a {@link GLEventListener} at the given index of this drawable queue.
- * The listeners are notified of events in the order of the queue.
+ * Adds the given {@link GLEventListener listener} at the given index of this drawable queue.
+ * The {@link GLEventListener listeners} are notified of events in the order of the queue.
+ *
+ * The newly added listener's {@link GLEventListener#init(GLAutoDrawable) init(..)}
+ * method will be called once before any other of it's callback methods.
+ * See {@link #getGLEventListenerInitState(GLEventListener)} for details.
+ *
* @param index Position where the listener will be inserted.
* Should be within (0 <= index && index <= size()).
* An index value of -1 is interpreted as the end of the list, size().
@@ -181,30 +194,120 @@ public interface GLAutoDrawable extends GLDrawable {
*/
public void addGLEventListener(int index, GLEventListener listener) throws IndexOutOfBoundsException;
- /**
- * Removes a {@link GLEventListener} from this drawable.
- * Note that if this is done from within a particular drawable's
- * {@link GLEventListener} handler (reshape, display, etc.) that it is not
+ /**
+ * Returns the number of {@link GLEventListener} of this drawable queue.
+ * @return The number of GLEventListener objects of this drawable queue.
+ */
+ public int getGLEventListenerCount();
+
+ /**
+ * Returns the {@link GLEventListener} at the given index of this drawable queue.
+ * @param index Position of the listener to be returned.
+ * Should be within (0 <= index && index < size()).
+ * An index value of -1 is interpreted as last listener, size()-1.
+ * @return The GLEventListener object at the given index.
+ * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index < size()), or -1
+ */
+ public GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException;
+
+ /**
+ * Retrieves whether the given {@link GLEventListener listener} is initialized or not.
+ *
+ * After {@link #addGLEventListener(GLEventListener) adding} a {@link GLEventListener} it is
+ * marked uninitialized and added to a list of to be initialized {@link GLEventListener}.
+ * If such uninitialized {@link GLEventListener}'s handler methods (reshape, display)
+ * are about to be invoked, it's {@link GLEventListener#init(GLAutoDrawable) init(..)} method is invoked first.
+ * Afterwards the {@link GLEventListener} is marked initialized
+ * and removed from the list of to be initialized {@link GLEventListener}.
+ *
+ *
+ * This methods returns the {@link GLEventListener} initialized state,
+ * i.e. returns false if it is included in the list of to be initialized {@link GLEventListener},
+ * otherwise true.
+ *
+ * @param listener the GLEventListener object to query it's initialized state.
+ */
+ public boolean getGLEventListenerInitState(GLEventListener listener);
+
+ /**
+ * Sets the given {@link GLEventListener listener's} initialized state.
+ *
+ * This methods allows manually setting the {@link GLEventListener} initialized state,
+ * i.e. adding it to, or removing it from the list of to be initialized {@link GLEventListener}.
+ * See {@link #getGLEventListenerInitState(GLEventListener)} for details.
+ *
+ *
+ * Warning: This method does not validate whether the given {@link GLEventListener listener's}
+ * is member of this drawable queue, i.e. {@link #addGLEventListener(GLEventListener) added}.
+ *
+ *
+ * This method is only exposed to allow users full control over the {@link GLEventListener}'s state
+ * and is usually not recommended to change.
+ *
+ *
+ * One use case is moving a {@link GLContext} and their initialized {@link GLEventListener}
+ * from one {@link GLAutoDrawable} to another,
+ * where a subsequent {@link GLEventListener#init(GLAutoDrawable) init(..)} call after adding it
+ * to the new owner is neither required nor desired.
+ * See {@link com.jogamp.opengl.util.GLDrawableUtil#swapGLContextAndAllGLEventListener(GLAutoDrawable, GLAutoDrawable) swapGLContextAndAllGLEventListener(..)}.
+ *
+ * @param listener the GLEventListener object to perform a state change.
+ * @param initialized if true, mark the listener initialized, otherwise uninitialized.
+ */
+ public void setGLEventListenerInitState(GLEventListener listener, boolean initialized);
+
+ /**
+ * Disposes the given {@link GLEventListener listener} via {@link GLEventListener#dispose(GLAutoDrawable) dispose(..)}
+ * if it has been initialized and added to this queue.
+ *
+ * If remove is true, the {@link GLEventListener} is removed from this drawable queue before disposal,
+ * otherwise marked uninitialized.
+ *
+ *
+ * If an {@link GLAnimatorControl} is being attached and the current thread is different
+ * than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
+ *
+ *
+ * Note that this is an expensive operation, since {@link GLEventListener#dispose(GLAutoDrawable) dispose(..)}
+ * is decorated by {@link GLContext#makeCurrent()} and {@link GLContext#release()}.
+ *
+ *
+ * Use {@link #removeGLEventListener(GLEventListener) removeGLEventListener(listener)} instead
+ * if you just want to remove the {@link GLEventListener listener} and don't care about the disposal of the it's (OpenGL) resources.
+ *
+ *
+ * Also note that this is done from within a particular drawable's
+ * {@link GLEventListener} handler (reshape, display, etc.), that it is not
* guaranteed that all other listeners will be evaluated properly
* during this update cycle.
- * @param listener The GLEventListener object to be removed
+ *
+ * @param listener The GLEventListener object to be disposed and removed if remove is true
+ * @param remove pass true to have the listener removed from this drawable queue, otherwise pass false
+ * @return the disposed and/or removed GLEventListener, or null if no action was performed, i.e. listener was not added
*/
- public void removeGLEventListener(GLEventListener listener);
-
+ public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove);
+
/**
- * Removes a {@link GLEventListener} at the given index from this drawable.
+ * Removes the given {@link GLEventListener listener} from this drawable queue.
+ *
+ * This is an inexpensive operation, since the removed listener's
+ * {@link GLEventListener#dispose(GLAutoDrawable) dispose(..)} method will not be called.
+ *
+ *
+ * Use {@link #disposeGLEventListener(GLEventListener, boolean) disposeGLEventListener(listener, true)}
+ * instead to ensure disposal of the {@link GLEventListener listener}'s (OpenGL) resources.
+ *
+ *
* Note that if this is done from within a particular drawable's
- * {@link GLEventListener} handler (reshape, display, etc.) that it is not
+ * {@link GLEventListener} handler (reshape, display, etc.), that it is not
* guaranteed that all other listeners will be evaluated properly
* during this update cycle.
- * @param index Position of the listener to be removed.
- * Should be within (0 <= index && index < size()).
- * An index value of -1 is interpreted as last listener, size()-1.
- * @return The removed GLEventListener object
- * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index < size()), or -1
+ *
+ * @param listener The GLEventListener object to be removed
+ * @return the removed GLEventListener, or null if listener was not added
*/
- public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException;
-
+ public GLEventListener removeGLEventListener(GLEventListener listener);
+
/**
*
* Registers the usage of an animator, an {@link javax.media.opengl.GLAnimatorControl} implementation.
@@ -236,25 +339,25 @@ public interface GLAutoDrawable extends GLDrawable {
public GLAnimatorControl getAnimator();
/**
- *
* Enqueues a one-shot {@link GLRunnable},
* which will be executed within the next {@link #display()} call
* after all registered {@link GLEventListener}s
* {@link GLEventListener#display(GLAutoDrawable) display(GLAutoDrawable)}
* methods has been called.
- *
*
* If no {@link GLAnimatorControl} is animating (default),
* or if the current thread is the animator thread,
- * a {@link #display()} call is issued after enqueue the GLRunnable.
- * No extra synchronization is performed in case wait is true, since it is executed in the current thread.
+ * a {@link #display()} call is issued after enqueue the GLRunnable,
+ * hence the {@link GLRunnable} will be executed right away.
+ *
*
- * If an {@link GLAnimatorControl} is animating,
- * no {@link #display()} call is issued, since the animator thread performs it.
+ * If an {@link GLAnimatorControl animator} is running,
+ * no explicit {@link #display()} call is issued, allowing the {@link GLAnimatorControl animator} to perform it when it's due.
*
*
* If wait is true the call blocks until the glRunnable
- * has been executed.
+ * has been executed by the {@link GLAnimatorControl animator}, otherwise the method returns immediately.
+ *
*
* If wait is trueand
* {@link #isRealized()} returns falseor {@link #getContext()} returns null,
@@ -266,16 +369,40 @@ public interface GLAutoDrawable extends GLDrawable {
* where all blocked callers are being notified.
*
*
- * @param wait if true block until execution of glRunnable is finished, otherwise return immediatly w/o waiting
+ * @param wait if true block until execution of glRunnable is finished, otherwise return immediately w/o waiting
* @param glRunnable the {@link GLRunnable} to execute within {@link #display()}
* @return true if the {@link GLRunnable} has been processed or queued, otherwise false.
*
* @see #setAnimator(GLAnimatorControl)
* @see #display()
* @see GLRunnable
+ * @see #enqueue(GLRunnable)
*/
public boolean invoke(boolean wait, GLRunnable glRunnable);
+ /**
+ * Enqueues a one-shot {@link GLRunnable},
+ * which will be executed within the next {@link #display()} call
+ * after all registered {@link GLEventListener}s
+ * {@link GLEventListener#display(GLAutoDrawable) display(GLAutoDrawable)}
+ * methods has been called.
+ *
+ * Unlike the {@link #invoke(boolean, GLRunnable)}, this method only enqueues the {@link GLRunnable}
+ * w/o taking care of it's execution. Hence either a performing {@link GLAnimatorControl animator}
+ * or explicit user call shall trigger {@link #display()} to ensure it's execution.
+ *
+ *
+ * @param glRunnable the {@link GLRunnable} to execute within the next {@link #display()} call
+ *
+ * @see #invoke(boolean, GLRunnable)
+ * @see #display()
+ * @see GLRunnable
+ */
+ public void enqueue(GLRunnable glRunnable);
+
/** Destroys all resources associated with this GLAutoDrawable,
inclusive the GLContext.
If a window is attached to it's implementation, it shall be closed.
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
index 1e9fcc95e..5b5f800a4 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
@@ -495,7 +495,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
(int) ((getHeight() + bounds.getHeight()) / 2));
return;
}
- if( ! this.helper.isExternalAnimatorAnimating() ) {
+ if( ! this.helper.isAnimatorAnimatingOnOtherThread() ) {
display();
}
}
@@ -699,15 +699,37 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
@Override
- public void removeGLEventListener(GLEventListener listener) {
- helper.removeGLEventListener(listener);
+ public int getGLEventListenerCount() {
+ return helper.getGLEventListenerCount();
}
@Override
- public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException {
- return helper.removeGLEventListener(index);
+ public GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException {
+ return helper.getGLEventListener(index);
+ }
+
+ @Override
+ public boolean getGLEventListenerInitState(GLEventListener listener) {
+ return helper.getGLEventListenerInitState(listener);
+ }
+
+ @Override
+ public void setGLEventListenerInitState(GLEventListener listener, boolean initialized) {
+ helper.setGLEventListenerInitState(listener, initialized);
}
+ @Override
+ public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove) {
+ final DisposeGLEventListenerAction r = new DisposeGLEventListenerAction(listener, remove);
+ Threading.invoke(true, r, getTreeLock());
+ return r.listener;
+ }
+
+ @Override
+ public GLEventListener removeGLEventListener(GLEventListener listener) {
+ return helper.removeGLEventListener(listener);
+ }
+
@Override
public void setAnimator(GLAnimatorControl animatorControl) {
helper.setAnimator(animatorControl);
@@ -723,6 +745,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
return helper.invoke(this, wait, glRunnable);
}
+ @Override
+ public void enqueue(GLRunnable glRunnable) {
+ helper.enqueue(glRunnable);
+ }
+
@Override
public GLContext setContext(GLContext newCtx) {
final RecursiveLock _lock = lock;
@@ -984,15 +1011,12 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
};
- // Workaround for ATI driver bugs related to multithreading issues
- // like simultaneous rendering via Animators to canvases that are
- // being resized on the AWT event dispatch thread
private final Runnable displayOnEDTAction = new Runnable() {
@Override
public void run() {
final RecursiveLock _lock = lock;
_lock.lock();
- try {
+ try {
helper.invokeGL(drawable, context, displayAction, initAction);
} finally {
_lock.unlock();
@@ -1015,6 +1039,26 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
};
+ private class DisposeGLEventListenerAction implements Runnable {
+ GLEventListener listener;
+ private boolean remove;
+ private DisposeGLEventListenerAction(GLEventListener listener, boolean remove) {
+ this.listener = listener;
+ this.remove = remove;
+ }
+
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ listener = helper.disposeGLEventListener(GLCanvas.this, drawable, context, listener, remove);
+ } finally {
+ _lock.unlock();
+ }
+ }
+ };
+
// Disables the AWT's erasing of this Canvas's background on Windows
// in Java SE 6. This internal API is not available in previous
// releases, but the system property
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
index d0b9fb913..08d70211b 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
@@ -426,15 +426,47 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
@Override
- public void removeGLEventListener(GLEventListener listener) {
- helper.removeGLEventListener(listener);
+ public int getGLEventListenerCount() {
+ return helper.getGLEventListenerCount();
}
@Override
- public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException {
- return helper.removeGLEventListener(index);
- }
+ public GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException {
+ return helper.getGLEventListener(index);
+ }
+
+ @Override
+ public boolean getGLEventListenerInitState(GLEventListener listener) {
+ return helper.getGLEventListenerInitState(listener);
+ }
+
+ @Override
+ public void setGLEventListenerInitState(GLEventListener listener, boolean initialized) {
+ helper.setGLEventListenerInitState(listener, initialized);
+ }
+
+ @Override
+ public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove) {
+ final DisposeGLEventListenerAction r = new DisposeGLEventListenerAction(listener, remove);
+ if (EventQueue.isDispatchThread()) {
+ r.run();
+ } else {
+ // Multithreaded redrawing of Swing components is not allowed,
+ // so do everything on the event dispatch thread
+ try {
+ EventQueue.invokeAndWait(r);
+ } catch (Exception e) {
+ throw new GLException(e);
+ }
+ }
+ return r.listener;
+ }
+ @Override
+ public GLEventListener removeGLEventListener(GLEventListener listener) {
+ return helper.removeGLEventListener(listener);
+ }
+
@Override
public void setAnimator(GLAnimatorControl animatorControl) {
helper.setAnimator(animatorControl);
@@ -450,6 +482,11 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
return helper.invoke(this, wait, glRunnable);
}
+ @Override
+ public void enqueue(GLRunnable glRunnable) {
+ helper.enqueue(glRunnable);
+ }
+
@Override
public GLContext createContext(GLContext shareWith) {
return (null != backend) ? backend.createContext(shareWith) : null;
@@ -685,7 +722,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
@Override
public void dispose(GLAutoDrawable drawable) {
- helper.dispose(GLJPanel.this);
+ helper.disposeAllGLEventListener(GLJPanel.this, false);
}
@Override
@@ -758,6 +795,20 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
};
+ private class DisposeGLEventListenerAction implements Runnable {
+ GLEventListener listener;
+ private boolean remove;
+ private DisposeGLEventListenerAction(GLEventListener listener, boolean remove) {
+ this.listener = listener;
+ this.remove = remove;
+ }
+
+ @Override
+ public void run() {
+ listener = helper.disposeGLEventListener(GLJPanel.this, backend.getDrawable(), backend.getContext(), listener, remove);
+ }
+ };
+
private int getNextPowerOf2(int number) {
// Workaround for problems where 0 width or height are transiently
// seen during layout
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index 85156e8a1..09a754279 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -95,7 +95,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
protected final void defaultWindowRepaintOp() {
final GLDrawable _drawable = drawable;
if( null != _drawable && _drawable.isRealized() ) {
- if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isExternalAnimatorAnimating() ) {
+ if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimatingOnOtherThread() ) {
display();
}
}
@@ -124,7 +124,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock
if( _drawable.isRealized() ) {
- if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isExternalAnimatorAnimating() ) {
+ if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimatingOnOtherThread() ) {
display();
}
}
@@ -178,7 +178,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
final GLAnimatorControl ctrl = helper.getAnimator();
// Is an animator thread perform rendering?
- if ( helper.isAnimatorRunningOnOtherThread() ) {
+ if ( helper.isAnimatorStartedOnOtherThread() ) {
// Pause animations before initiating safe destroy.
final boolean isPaused = ctrl.pause();
destroy();
@@ -299,6 +299,16 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
}
+ protected final GLEventListener defaultDisposeGLEventListener(GLEventListener listener, boolean remove) {
+ final RecursiveLock _lock = getLock();
+ _lock.lock();
+ try {
+ return helper.disposeGLEventListener(GLAutoDrawableBase.this, drawable, context, listener, remove);
+ } finally {
+ _lock.unlock();
+ }
+ }
+
@Override
public final GLDrawable getDelegatedDrawable() {
return drawable;
@@ -356,13 +366,33 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
@Override
- public final void removeGLEventListener(GLEventListener listener) {
- helper.removeGLEventListener(listener);
+ public int getGLEventListenerCount() {
+ return helper.getGLEventListenerCount();
+ }
+
+ @Override
+ public GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException {
+ return helper.getGLEventListener(index);
+ }
+
+ @Override
+ public boolean getGLEventListenerInitState(GLEventListener listener) {
+ return helper.getGLEventListenerInitState(listener);
+ }
+
+ @Override
+ public void setGLEventListenerInitState(GLEventListener listener, boolean initialized) {
+ helper.setGLEventListenerInitState(listener, initialized);
+ }
+
+ @Override
+ public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove) {
+ return defaultDisposeGLEventListener(listener, remove);
}
@Override
- public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException {
- return helper.removeGLEventListener(index);
+ public final GLEventListener removeGLEventListener(GLEventListener listener) {
+ return helper.removeGLEventListener(listener);
}
@Override
@@ -381,6 +411,11 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
return helper.invoke(this, wait, glRunnable);
}
+ @Override
+ public final void enqueue(GLRunnable glRunnable) {
+ helper.enqueue(glRunnable);
+ }
+
@Override
public final void setAutoSwapBufferMode(boolean enable) {
helper.setAutoSwapBufferMode(enable);
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
index d4ff9702c..d891ae810 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
@@ -61,7 +61,6 @@ import com.jogamp.opengl.util.Animator;
/** Encapsulates the implementation of most of the GLAutoDrawable's
methods to be able to share it between GLCanvas and GLJPanel. */
-
public class GLDrawableHelper {
/** true if property jogl.debug.GLDrawable.PerfStats is defined. */
private static final boolean PERF_STATS = Debug.isPropertyDefined("jogl.debug.GLDrawable.PerfStats", true);
@@ -75,6 +74,7 @@ public class GLDrawableHelper {
private boolean autoSwapBufferMode;
private Thread skipContextReleaseThread;
private GLAnimatorControl animatorCtrl;
+ private static Runnable nop = new Runnable() { public void run() {} };
public GLDrawableHelper() {
reset();
@@ -289,45 +289,239 @@ public class GLDrawableHelper {
// GLEventListener may be added after context is created,
// hence we earmark initialization for the next display call.
listenersToBeInit.add(listener);
+
listeners.add(index, listener);
}
}
-
- public final void removeGLEventListener(GLEventListener listener) {
+
+ /**
+ * Note that no {@link GLEventListener#dispose(GLAutoDrawable)} call is being issued
+ * due to the lack of a current context.
+ * Consider calling {@link #disposeGLEventListener(GLAutoDrawable, GLDrawable, GLContext, GLEventListener)}.
+ * @return the removed listener, or null if listener was not added
+ */
+ public final GLEventListener removeGLEventListener(GLEventListener listener) {
synchronized(listenersLock) {
- listeners.remove(listener);
listenersToBeInit.remove(listener);
+ return listeners.remove(listener) ? listener : null;
}
}
- public final GLEventListener removeGLEventListener(int index)
- throws IndexOutOfBoundsException {
+ public final GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException {
synchronized(listenersLock) {
if(0>index) {
index = listeners.size()-1;
}
- return listeners.remove(index);
+ final GLEventListener listener = listeners.remove(index);
+ listenersToBeInit.remove(listener);
+ return listener;
+ }
+ }
+
+ public final int getGLEventListenerCount() {
+ synchronized(listenersLock) {
+ return listeners.size();
+ }
+ }
+
+ public final GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException {
+ synchronized(listenersLock) {
+ if(0>index) {
+ index = listeners.size()-1;
+ }
+ return listeners.get(index);
+ }
+ }
+
+ public final boolean getGLEventListenerInitState(GLEventListener listener) {
+ synchronized(listenersLock) {
+ return !listenersToBeInit.contains(listener);
+ }
+ }
+
+ public final void setGLEventListenerInitState(GLEventListener listener, boolean initialized) {
+ synchronized(listenersLock) {
+ if(initialized) {
+ listenersToBeInit.remove(listener);
+ } else {
+ listenersToBeInit.add(listener);
+ }
}
}
/**
- * Issues {@link javax.media.opengl.GLEventListener#dispose(javax.media.opengl.GLAutoDrawable)}
- * to all listeners.
+ * Disposes the given {@link GLEventListener} via {@link GLEventListener#dispose(GLAutoDrawable)}
+ * if it has been initialized and added to this queue.
*
- * Please consider using {@link #disposeGL(GLAutoDrawable, GLDrawable, GLContext, Runnable)}
- * for correctness!
+ * If remove is true, the {@link GLEventListener} is removed from this drawable queue before disposal,
+ * otherwise marked uninitialized.
*
- * @param drawable
+ *
+ * Please consider using {@link #disposeGLEventListener(GLAutoDrawable, GLDrawable, GLContext, GLEventListener)}
+ * for correctness, i.e. encapsulating all calls w/ makeCurrent etc.
+ *
+ * @param autoDrawable
+ * @param remove if true, the listener gets removed
+ * @return the disposed and/or removed listener, otherwise null if neither action is performed
*/
- public final void dispose(GLAutoDrawable drawable) {
+ public final GLEventListener disposeGLEventListener(GLAutoDrawable autoDrawable, GLEventListener listener, boolean remove) {
+ synchronized(listenersLock) {
+ if( remove ) {
+ if( listeners.remove(listener) ) {
+ if( !listenersToBeInit.remove(listener) ) {
+ listener.dispose(autoDrawable);
+ }
+ return listener;
+ }
+ } else {
+ if( listeners.contains(listener) && !listenersToBeInit.contains(listener) ) {
+ listener.dispose(autoDrawable);
+ listenersToBeInit.add(listener);
+ return listener;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Disposes all added initialized {@link GLEventListener}s via {@link GLEventListener#dispose(GLAutoDrawable)}.
+ *
+ * If remove is true, the {@link GLEventListener}s are removed from this drawable queue before disposal,
+ * otherwise maked uninitialized.
+ *
+ *
+ * Please consider using {@link #disposeAllGLEventListener(GLAutoDrawable, GLDrawable, GLContext)}
+ * or {@link #disposeGL(GLAutoDrawable, GLDrawable, GLContext, Runnable)}
+ * for correctness, i.e. encapsulating all calls w/ makeCurrent etc.
+ *
+ * @param autoDrawable
+ * @return the disposal count
+ */
+ public final int disposeAllGLEventListener(GLAutoDrawable autoDrawable, boolean remove) {
+ int disposeCount = 0;
synchronized(listenersLock) {
- final ArrayList _listeners = listeners;
- for (int i=0; i < _listeners.size(); i++) {
- _listeners.get(i).dispose(drawable);
+ if( remove ) {
+ for (int count = listeners.size(); 0 < count; count--) {
+ final GLEventListener listener = listeners.remove(0);
+ if( !listenersToBeInit.remove(listener) ) {
+ listener.dispose(autoDrawable);
+ disposeCount++;
+ }
+ }
+ } else {
+ final int count = listeners.size();
+ for (int i = 0; i < count; i++) {
+ final GLEventListener listener = listeners.get(i);
+ if( !listenersToBeInit.contains(listener) ) {
+ listener.dispose(autoDrawable);
+ listenersToBeInit.add(listener);
+ disposeCount++;
+ }
+ }
}
}
+ return disposeCount;
}
+ /**
+ * Principal helper method which runs {@link #disposeGLEventListener(GLAutoDrawable, GLEventListener, boolean)}
+ * with the context made current.
+ *
+ * If an {@link GLAnimatorControl} is being attached and the current thread is different
+ * than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
+ *
+ *
+ * @param autoDrawable
+ * @param context
+ * @param listener
+ * @param initAction
+ */
+ public final GLEventListener disposeGLEventListener(final GLAutoDrawable autoDrawable,
+ final GLDrawable drawable,
+ final GLContext context,
+ final GLEventListener listener,
+ final boolean remove) {
+ synchronized(listenersLock) {
+ // fast path for uninitialized listener
+ if( listenersToBeInit.contains(listener) ) {
+ if( remove ) {
+ listenersToBeInit.remove(listener);
+ return listeners.remove(listener) ? listener : null;
+ }
+ return null;
+ }
+ }
+ final boolean isPaused = isAnimatorAnimatingOnOtherThread() && animatorCtrl.pause();
+ final GLEventListener[] res = new GLEventListener[] { null };
+ final Runnable action = new Runnable() {
+ public void run() {
+ res[0] = disposeGLEventListener(autoDrawable, listener, remove);
+ }
+ };
+ invokeGL(drawable, context, action, nop);
+
+ if(isPaused) {
+ animatorCtrl.resume();
+ }
+ return res[0];
+ }
+
+ /**
+ * Principal helper method which runs {@link #disposeAllGLEventListener(GLAutoDrawable, boolean)}
+ * with the context made current.
+ *
+ * If an {@link GLAnimatorControl} is being attached and the current thread is different
+ * than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
+ *
+ *
+ * @param autoDrawable
+ * @param context
+ * @param listener
+ * @param initAction
+ */
+ public final void disposeAllGLEventListener(final GLAutoDrawable autoDrawable,
+ final GLDrawable drawable,
+ final GLContext context,
+ final boolean remove) {
+
+ final boolean isPaused = isAnimatorAnimatingOnOtherThread() && animatorCtrl.pause();
+
+ final Runnable action = new Runnable() {
+ public void run() {
+ disposeAllGLEventListener(autoDrawable, remove);
+ }
+ };
+ invokeGL(drawable, context, action, nop);
+
+ if(isPaused) {
+ animatorCtrl.resume();
+ }
+ }
+
+ /**
+ * Principal helper method which runs
+ * {@link #disposeAllGLEventListener(GLAutoDrawable, boolean) disposeAllGLEventListener(autoDrawable, false)}
+ * with the context made current and destroys the context afterwards while holding the lock.
+ * @param autoDrawable
+ * @param drawable
+ * @param context
+ * @param postAction
+ */
+ public final void disposeGL(final GLAutoDrawable autoDrawable,
+ final GLDrawable drawable,
+ final GLContext context,
+ final Runnable postAction) {
+ if(PERF_STATS) {
+ invokeGLImplStats(drawable, context, null, null, autoDrawable);
+ } else {
+ invokeGLImpl(drawable, context, null, null, autoDrawable);
+ }
+ if(null != postAction) {
+ postAction.run();
+ }
+ }
+
private final void init(GLEventListener l, GLAutoDrawable drawable, boolean sendReshape) {
l.init(drawable);
if(sendReshape) {
@@ -374,7 +568,7 @@ public class GLDrawableHelper {
}
}
}
-
+
private final void reshape(GLEventListener listener, GLAutoDrawable drawable,
int x, int y, int width, int height, boolean setViewport, boolean checkInit) {
if(checkInit) {
@@ -459,15 +653,15 @@ public class GLDrawableHelper {
}
}
- public final boolean isAnimatorRunningOnOtherThread() {
+ public final boolean isAnimatorStartedOnOtherThread() {
return ( null != animatorCtrl ) ? animatorCtrl.isStarted() && animatorCtrl.getThread() != Thread.currentThread() : false ;
}
- public final boolean isAnimatorRunning() {
+ public final boolean isAnimatorStarted() {
return ( null != animatorCtrl ) ? animatorCtrl.isStarted() : false ;
}
- public final boolean isExternalAnimatorAnimating() {
+ public final boolean isAnimatorAnimatingOnOtherThread() {
return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() && animatorCtrl.getThread() != Thread.currentThread() : false ;
}
@@ -501,9 +695,9 @@ public class GLDrawableHelper {
GLRunnableTask rTask = null;
Object rTaskLock = new Object();
synchronized(rTaskLock) {
- boolean deferred;
+ final boolean deferred;
synchronized(glRunnablesLock) {
- deferred = isExternalAnimatorAnimating();
+ deferred = isAnimatorAnimatingOnOtherThread();
if(!deferred) {
wait = false; // don't wait if exec immediatly
}
@@ -531,6 +725,15 @@ public class GLDrawableHelper {
return true;
}
+ public final void enqueue(GLRunnable glRunnable) {
+ if( null == glRunnable) {
+ return;
+ }
+ synchronized(glRunnablesLock) {
+ glRunnables.add( new GLRunnableTask(glRunnable, null, false) );
+ }
+ }
+
public final void setAutoSwapBufferMode(boolean enable) {
autoSwapBufferMode = enable;
}
@@ -576,10 +779,10 @@ public class GLDrawableHelper {
* @param runnable
* @param initAction
*/
- public final void invokeGL(GLDrawable drawable,
- GLContext context,
- Runnable runnable,
- Runnable initAction) {
+ public final void invokeGL(final GLDrawable drawable,
+ final GLContext context,
+ final Runnable runnable,
+ final Runnable initAction) {
if(null==context) {
if (DEBUG) {
Exception e = new GLException(Thread.currentThread().getName()+" Info: GLDrawableHelper " + this + ".invokeGL(): NULL GLContext");
@@ -595,34 +798,11 @@ public class GLDrawableHelper {
}
}
- /**
- * Principal helper method which runs {@link #dispose(GLAutoDrawable)} with the context
- * made current and destroys the context afterwards while holding the lock.
- *
- * @param autoDrawable
- * @param drawable
- * @param context
- * @param postAction
- */
- public final void disposeGL(GLAutoDrawable autoDrawable,
- GLDrawable drawable,
- GLContext context,
- Runnable postAction) {
- if(PERF_STATS) {
- invokeGLImplStats(drawable, context, null, null, autoDrawable);
- } else {
- invokeGLImpl(drawable, context, null, null, autoDrawable);
- }
- if(null != postAction) {
- postAction.run();
- }
- }
-
- private final void invokeGLImpl(GLDrawable drawable,
- GLContext context,
- Runnable runnable,
- Runnable initAction,
- GLAutoDrawable disposeAutoDrawable) {
+ private final void invokeGLImpl(final GLDrawable drawable,
+ final GLContext context,
+ final Runnable runnable,
+ final Runnable initAction,
+ final GLAutoDrawable disposeAutoDrawable) {
final Thread currentThread = Thread.currentThread();
final boolean isDisposeAction = null==initAction ;
@@ -660,8 +840,8 @@ public class GLDrawableHelper {
if(GLContext.CONTEXT_CURRENT_NEW == res) {
throw new GLException(currentThread.getName()+" GLDrawableHelper " + this + ".invokeGL(): Dispose case (no init action given): Native context was not created (new ctx): "+context);
}
- if(listeners.size()>0) {
- dispose(disposeAutoDrawable);
+ if( listeners.size() > 0 && null != disposeAutoDrawable ) {
+ disposeAllGLEventListener(disposeAutoDrawable, false);
}
}
}
@@ -686,11 +866,11 @@ public class GLDrawableHelper {
}
}
- private final void invokeGLImplStats(GLDrawable drawable,
- GLContext context,
- Runnable runnable,
- Runnable initAction,
- GLAutoDrawable disposeAutoDrawable) {
+ private final void invokeGLImplStats(final GLDrawable drawable,
+ final GLContext context,
+ final Runnable runnable,
+ final Runnable initAction,
+ final GLAutoDrawable disposeAutoDrawable) {
final Thread currentThread = Thread.currentThread();
final boolean isDisposeAction = null==initAction ;
@@ -748,8 +928,8 @@ public class GLDrawableHelper {
if(res == GLContext.CONTEXT_CURRENT_NEW) {
throw new GLException(currentThread.getName()+" GLDrawableHelper " + this + ".invokeGL(): Dispose case (no init action given): Native context was not created (new ctx): "+context);
}
- if(listeners.size()>0) {
- dispose(disposeAutoDrawable);
+ if( listeners.size() > 0 && null != disposeAutoDrawable ) {
+ disposeAllGLEventListener(disposeAutoDrawable, false);
}
}
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
index 496be3d93..8d4b8f700 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
@@ -43,11 +43,11 @@ import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLDrawableFactory;
-import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import com.jogamp.opengl.GLAutoDrawableDelegate;
import com.jogamp.opengl.util.Animator;
+import com.jogamp.opengl.util.GLDrawableUtil;
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2;
@@ -157,28 +157,11 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
if( ( t1 - t0 ) / period > s) {
s++;
System.err.println(s+" - switch - START "+ ( t1 - t0 ));
- animator.pause();
// switch context _and_ the demo synchronously
- if(0 == s%2) {
- final GLEventListener demo = glad2.removeGLEventListener(0);
- GLContext ctx1 = glad1.setContext(glad2.getContext());
- glad2.setContext(ctx1);
- glad1.addGLEventListener(0, demo);
- } else {
- final GLEventListener demo = glad1.removeGLEventListener(0);
- GLContext ctx2 = glad2.setContext(glad1.getContext());
- glad1.setContext(ctx2);
- glad2.addGLEventListener(0, demo);
- }
- System.err.println(s+" - switch - display-1");
- glad1.display();
- System.err.println(s+" - switch - display-2");
- glad2.display();
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(glad1, glad2);
- System.err.println(s+" - switch - END "+ ( t1 - t0 ));
-
- animator.resume();
+ System.err.println(s+" - switch - END "+ ( t1 - t0 ));
}
Thread.sleep(100);
t1 = System.currentTimeMillis();
@@ -223,24 +206,15 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
if( ( t1 - t0 ) / period > s) {
s++;
System.err.println(s+" - switch - START "+ ( t1 - t0 ));
- animator.pause();
+ System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle()));
+ System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle()));
// switch context _and_ the demo synchronously
- if(0 == s%2) {
- final GLEventListener demo = glWindow2.removeGLEventListener(0);
- GLContext ctx1 = glWindow1.setContext(glWindow2.getContext());
- glWindow1.addGLEventListener(0, demo);
- glWindow2.setContext(ctx1);
- } else {
- final GLEventListener demo = glWindow1.removeGLEventListener(0);
- GLContext ctx2 = glWindow2.setContext(glWindow1.getContext());
- glWindow2.addGLEventListener(0, demo);
- glWindow1.setContext(ctx2);
- }
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2);
+ System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle()));
+ System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle()));
System.err.println(s+" - switch - END "+ ( t1 - t0 ));
-
- animator.resume();
}
Thread.sleep(100);
t1 = System.currentTimeMillis();
@@ -288,27 +262,23 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
if( ( t1 - t0 ) / period > s) {
s++;
System.err.println(s+" - switch - START "+ ( t1 - t0 ));
- animator.pause();
-
- GLEventListener demo1 = glWindow1.removeGLEventListener(0);
- GLEventListener demo2 = glWindow2.removeGLEventListener(0);
-
- GLContext ctx1 = glWindow1.setContext(glWindow2.getContext());
- glWindow1.addGLEventListener(0, demo2);
-
- glWindow2.setContext(ctx1);
- glWindow2.addGLEventListener(0, demo1);
-
+ System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle()));
+ System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle()));
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2);
+ System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle()));
+ System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle()));
System.err.println(s+" - switch - END "+ ( t1 - t0 ));
-
- animator.resume();
}
Thread.sleep(100);
t1 = System.currentTimeMillis();
}
animator.stop();
+ System.err.println("pre -del-w1: w1: "+glWindow1);
+ System.err.println("pre -del-w1: w2: "+glWindow2);
glWindow1.destroy();
+ System.err.println("post-del-w1: w1: "+glWindow1);
+ System.err.println("post-del-w1: w2: "+glWindow2);
glWindow2.destroy();
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
index e703b6fd9..e9fe9b401 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
@@ -65,7 +65,6 @@ public class GearsES2 implements GLEventListener {
private int prevMouseX, prevMouseY;
private boolean doRotate = true;
- private boolean isInitialized = false;
boolean ignoreFocus = false;
public GearsES2(int swapInterval) {
@@ -106,11 +105,6 @@ public class GearsES2 implements GLEventListener {
public void init(GLAutoDrawable drawable) {
- if(isInitialized) {
- System.err.println(Thread.currentThread()+" GearsES2.init skipped!");
- return;
- }
- isInitialized = true;
System.err.println(Thread.currentThread()+" GearsES2.init ...");
GL2ES2 gl = drawable.getGL().getGL2ES2();
@@ -228,11 +222,6 @@ public class GearsES2 implements GLEventListener {
// private boolean useAndroidDebug = false;
public void dispose(GLAutoDrawable drawable) {
- if(!isInitialized) {
- System.err.println(Thread.currentThread()+" GearsES2.dispose skipped!");
- return;
- }
- isInitialized = false;
System.err.println(Thread.currentThread()+" GearsES2.dispose ... ");
final Object upstreamWidget = drawable.getUpstreamWidget();
if (upstreamWidget instanceof Window) {
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java
index bf1ca5c2d..e4a457954 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java
@@ -50,7 +50,6 @@ public class RedSquareES2 implements GLEventListener {
Window window = null;
float aspect = 1.0f;
boolean doRotate = true;
- boolean isInitialized = false;
public RedSquareES2(int swapInterval) {
this.swapInterval = swapInterval;
@@ -64,11 +63,6 @@ public class RedSquareES2 implements GLEventListener {
public void setDoRotation(boolean rotate) { this.doRotate = rotate; }
public void init(GLAutoDrawable glad) {
- if(isInitialized) {
- System.err.println(Thread.currentThread()+" RedSquareES2.init skipped!");
- return;
- }
- isInitialized = true;
System.err.println(Thread.currentThread()+" RedSquareES2.init ...");
GL2ES2 gl = glad.getGL().getGL2ES2();
@@ -184,11 +178,6 @@ public class RedSquareES2 implements GLEventListener {
}
public void dispose(GLAutoDrawable glad) {
- if(!isInitialized) {
- System.err.println(Thread.currentThread()+" RedSquareES2.dispose skipped!");
- return;
- }
- isInitialized = false;
System.err.println(Thread.currentThread()+" RedSquareES2.dispose ... ");
GL2ES2 gl = glad.getGL().getGL2ES2();
st.destroy(gl);
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TextureSequenceCubeES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TextureSequenceCubeES2.java
index 9217e2b53..25f8740d4 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TextureSequenceCubeES2.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TextureSequenceCubeES2.java
@@ -75,7 +75,6 @@ public class TextureSequenceCubeES2 implements GLEventListener {
private float view_rotx = 0.0f, view_roty = 0.0f, view_rotz = 0.0f;
int[] vboNames = new int[4];
boolean innerCube;
- boolean initialized = false;
private ByteBuffer cubeIndices;
private final MouseListener mouseAction = new MouseAdapter() {
--
cgit v1.2.3
From 8c78f80f205345fe43ec2639e648421ef0134e57 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Mon, 5 Nov 2012 05:02:38 +0100
Subject: GLAutoDrawable: Refine API change of commit
c002e04f848116922a1ed7bd96ead54961649bbd
As suggested by Julien Gouesse, align 'enqueue(..)' method w/ 'invoke(..)':
- public void enqueue(GLRunnable glRunnable);
+ public boolean invoke(boolean wait, List glRunnables);
---
make/scripts/tests.sh | 4 +-
.../classes/com/jogamp/opengl/swt/GLCanvas.java | 12 +++---
.../com/jogamp/opengl/util/GLDrawableUtil.java | 35 ++++++++--------
.../classes/javax/media/opengl/GLAutoDrawable.java | 32 +++++----------
.../classes/javax/media/opengl/awt/GLCanvas.java | 5 ++-
.../classes/javax/media/opengl/awt/GLJPanel.java | 5 ++-
.../classes/jogamp/opengl/GLAutoDrawableBase.java | 5 ++-
.../classes/jogamp/opengl/GLDrawableHelper.java | 47 +++++++++++++++++++++-
.../acore/TestGLContextDrawableSwitchNEWT.java | 8 ++--
9 files changed, 96 insertions(+), 57 deletions(-)
(limited to 'src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java')
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index cc9a330a5..3221deaab 100755
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -267,7 +267,7 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES1NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOffscrnCapsNEWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $*
+testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestPointsNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT $*
@@ -352,7 +352,7 @@ function testawtswt() {
#testawt com.jogamp.opengl.test.junit.jogl.awt.TestAWTCardLayoutAnimatorStartStopBug532 $*
#testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAWTActionDeadlock00AWT $*
#testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAWTActionDeadlock01AWT $*
-testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAWTActionDeadlock02AWT $*
+#testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAWTActionDeadlock02AWT $*
#
# swt (testswt)
diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
index ea794cc78..755a7c392 100644
--- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
+++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
@@ -27,6 +27,8 @@
*/
package com.jogamp.opengl.swt;
+import java.util.List;
+
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.ProxySurface;
@@ -545,15 +547,15 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
}
@Override
- public boolean invoke(final boolean wait, final GLRunnable run) {
- return helper.invoke(this, wait, run);
+ public boolean invoke(final boolean wait, final GLRunnable runnable) {
+ return helper.invoke(this, wait, runnable);
}
@Override
- public void enqueue(GLRunnable glRunnable) {
- helper.enqueue(glRunnable);
+ public boolean invoke(final boolean wait, final List runnables) {
+ return helper.invoke(this, wait, runnables);
}
-
+
@Override
public void setAnimator(final GLAnimatorControl arg0) throws GLException {
helper.setAnimator(arg0);
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
index 08eaf0494..cc81e4820 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
@@ -27,6 +27,9 @@
*/
package com.jogamp.opengl.util;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLContext;
@@ -80,7 +83,7 @@ public class GLDrawableUtil {
dest.addGLEventListener(listener);
if(preserveInitState && initialized) {
dest.setGLEventListenerInitState(listener, true);
- dest.enqueue(new ReshapeGLEventListener(listener));
+ dest.invoke(false, new ReshapeGLEventListener(listener));
} // else .. !init state is default
}
@@ -118,6 +121,8 @@ public class GLDrawableUtil {
* @param b
*/
public static final void swapGLContextAndAllGLEventListener(GLAutoDrawable a, GLAutoDrawable b) {
+ final List aGLCmds = new ArrayList();
+ final List bGLCmds = new ArrayList();
final GLAnimatorControl aAnim = a.getAnimator();
final GLAnimatorControl bAnim = b.getAnimator();
final boolean aIsPaused = isAnimatorAnimatingOnOtherThread(aAnim) && aAnim.pause();
@@ -146,32 +151,30 @@ public class GLDrawableUtil {
//
// trigger glFinish to sync GL ctx
//
- a.enqueue(glFinish);
- b.enqueue(glFinish);
- a.display();
- b.display();
+ a.invoke(true, glFinish);
+ b.invoke(true, glFinish);
//
// switch context and
// trigger GL-Viewport reset and reshape of all initialized GLEventListeners
//
b.setContext( a.setContext( b.getContext() ) );
- a.enqueue(setViewport);
- b.enqueue(setViewport);
+ aGLCmds.add(setViewport);
+ bGLCmds.add(setViewport);
for(int i=0; i
- * Unlike the {@link #invoke(boolean, GLRunnable)}, this method only enqueues the {@link GLRunnable}
- * w/o taking care of it's execution. Hence either a performing {@link GLAnimatorControl animator}
- * or explicit user call shall trigger {@link #display()} to ensure it's execution.
- *
- *