diff options
38 files changed, 1087 insertions, 336 deletions
diff --git a/doc/Implementation/MultiThreading.txt b/doc/Implementation/MultiThreading.txt index fb586e1ec..272204d94 100644 --- a/doc/Implementation/MultiThreading.txt +++ b/doc/Implementation/MultiThreading.txt @@ -1,4 +1,9 @@ +Don't miss + Current 'violations' of synchronization/memory-barriers + using explicit locking: +below .. + Locking ========= @@ -92,3 +97,29 @@ Summary: - swapBuffersImpl - [Surface i/o] - if not locked already ++++ + +Complying with synchronization/memory-barriers +using explicit locking: + +- NativeSurface's handle access + +Current 'violations' of synchronization/memory-barriers +using explicit locking: + +- Using 'volatile' to avoid locking for read-only access + with rare write access + + - GLAutoDrawable's drawable reference + + - GLAutoDrawable's context reference + Since 7f7a23dd0ddf106e6f0c69fc2a05ff92ac56200e + + - GLContext's contextHandle + Since 7f7a23dd0ddf106e6f0c69fc2a05ff92ac56200e + + - GLDrawableImpl's realized + Used for Pre-locking queries, whether drawable is realized + +- Misc 'volatile' usage: + diff --git a/make/build-test.xml b/make/build-test.xml index b7220aed6..d4274cd76 100644 --- a/make/build-test.xml +++ b/make/build-test.xml @@ -478,7 +478,7 @@ <batchtest todir="${results.test}"> <fileset dir="${classes}"> - <include name="${java.dir.junit}/**/acore/TestSharedContextVBO**"/> + <include name="${java.dir.junit}/**/acore/TestSharedContext**"/> <exclude name="**/*$$*"/> </fileset> <formatter usefile="false" type="brief"/> diff --git a/make/scripts/tests-win.bat b/make/scripts/tests-win.bat index 71ac8c43d..0632c24b0 100755 --- a/make/scripts/tests-win.bat +++ b/make/scripts/tests-win.bat @@ -14,10 +14,10 @@ REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedConte REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT1 %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT2 %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT3 %* -scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3 %* +REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3 %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3b %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextWithJTabbedPaneAWT %* -REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2SWT3 %* +scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2SWT3 %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextNewtAWTBug523 %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListAWT %* diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 0f3388fb3..ee93334d4 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -84,8 +84,10 @@ function jrun() { #D_ARGS="-Dnativewindow.debug.X11Util.ATI_HAS_NO_XCLOSEDISPLAY_BUG" #D_ARGS="-Dnativewindow.debug.X11Util.ATI_HAS_NO_MULTITHREADING_BUG" #D_ARGS="-Djogl.disable.opengles" - #D_ARGS="-Djogl.debug.DebugGL" + #D_ARGS="-Djogl.debug.DebugGL -Dnewt.debug.Window" #D_ARGS="-Djogl.debug.DebugGL -Djogl.debug.FBObject" + #D_ARGS="-Djogl.debug.TraceGL" + #D_ARGS="-Djogl.debug.DebugGL" #D_ARGS="-Djogl.debug.FBObject -Djogl.debug.TraceGL -Djogl.debug.GLBufferStateTracker" #D_ARGS="-Djogl.debug.FBObject" #D_ARGS="-Djogl.debug.GLSLCode" @@ -375,12 +377,12 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES1NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT0 $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT1 $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT2 $* +testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT2 $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT3 $* -testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3 $* +#testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3 $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2AWT3b $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2SWT3 $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextWithJTabbedPaneAWT $* -#testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2SWT3 $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextNewtAWTBug523 $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListAWT $* diff --git a/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java b/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java index 703f832c3..b7a9c270e 100644 --- a/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java +++ b/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java @@ -83,12 +83,12 @@ public class BuildComposablePipeline { public static final int GEN_GL_IDENTITY_BY_ASSIGNABLE_CLASS = 1 << 4; int mode; - private String outputDir; - private String outputPackage; - private String outputName; - private Class<?> classToComposeAround; - private Class<?> classPrologOpt; - private Class<?> classDownstream; + private final String outputDir; + private final String outputPackage; + private final String outputName; + private final Class<?> classToComposeAround; + private final Class<?> classPrologOpt; + private final Class<?> classDownstream; // Only desktop OpenGL has immediate mode glBegin / glEnd private boolean hasImmediateMode; // Desktop OpenGL and GLES1 have GL_STACK_OVERFLOW and GL_STACK_UNDERFLOW errors @@ -590,7 +590,7 @@ public class BuildComposablePipeline { output.println(" @Override"); output.println(" public String toString() {"); output.println(" StringBuilder sb = new StringBuilder();"); - output.println(" sb.append(\"" + getOutputName() + " [ implementing " + baseInterfaceClass.getName() + ",\\n\\t\");"); + output.println(" sb.append(\"" + getOutputName() + " [this 0x\"+Integer.toHexString(hashCode())+\" implementing " + baseInterfaceClass.getName() + ",\\n\\t\");"); if (null != prologClassOpt) { output.println(" sb.append(\" prolog: \"+" + getPrologObjectNameOpt() + ".toString()+\",\\n\\t\");"); } @@ -646,7 +646,10 @@ public class BuildComposablePipeline { * Emits all of the isGL* methods. */ protected void emitGLIsMethods(PrintWriter output) { - emitGLIsMethod(output, "GL"); + output.println(" @Override"); + output.println(" public final boolean isGL() {"); + output.println(" return true;"); + output.println(" }"); emitGLIsMethod(output, "GL4bc"); emitGLIsMethod(output, "GL4"); emitGLIsMethod(output, "GL3bc"); @@ -697,15 +700,16 @@ public class BuildComposablePipeline { protected void emitGLGetMethod(PrintWriter output, String type) { output.println(" @Override"); output.println(" public final javax.media.opengl." + type + " get" + type + "() {"); - if( 0 != (GEN_GL_IDENTITY_BY_ASSIGNABLE_CLASS & getMode() ) ) { - final Class<?> clazz = BuildComposablePipeline.getClass("javax.media.opengl." + type); - if (clazz.isAssignableFrom(baseInterfaceClass)) { + final Class<?> clazz = BuildComposablePipeline.getClass("javax.media.opengl." + type); + if (clazz.isAssignableFrom(baseInterfaceClass)) { + if( 0 != (GEN_GL_IDENTITY_BY_ASSIGNABLE_CLASS & getMode() ) ) { output.println(" return this;"); } else { + output.println(" if( is" + type + "() ) { return this; }"); output.println(" throw new GLException(\"Not a " + type + " implementation\");"); } } else { - output.println(" return " + getDownstreamObjectName() + ".get" + type + "();"); + output.println(" throw new GLException(\"Not a " + type + " implementation\");"); } output.println(" }"); } @@ -714,7 +718,10 @@ public class BuildComposablePipeline { * Emits all of the getGL* methods. */ protected void emitGLGetMethods(PrintWriter output) { - emitGLGetMethod(output, "GL"); + output.println(" @Override"); + output.println(" public final javax.media.opengl.GL getGL() {"); + output.println(" return this;"); + output.println(" }"); emitGLGetMethod(output, "GL4bc"); emitGLGetMethod(output, "GL4"); emitGLGetMethod(output, "GL3bc"); diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java index 5e3731984..cad780a89 100644 --- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java +++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java @@ -52,6 +52,7 @@ import javax.media.opengl.GLEventListener; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; import javax.media.opengl.GLRunnable; +import javax.media.opengl.GLSharedContextSetter; import javax.media.opengl.Threading; import jogamp.nativewindow.x11.X11Util; @@ -85,7 +86,7 @@ import com.jogamp.opengl.JoglVersion; * Implementation allows use of custom {@link GLCapabilities}. * </p> */ -public class GLCanvas extends Canvas implements GLAutoDrawable { +public class GLCanvas extends Canvas implements GLAutoDrawable, GLSharedContextSetter { private static final boolean DEBUG = Debug.debug("GLCanvas"); /* @@ -103,13 +104,12 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { private final RecursiveLock lock = LockFactory.createRecursiveLock(); private final GLDrawableHelper helper = new GLDrawableHelper(); - private final GLContext shareWith; private final GLCapabilitiesImmutable capsRequested; private final GLCapabilitiesChooser capsChooser; private volatile Rectangle clientArea; private volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access - private volatile GLContextImpl context; + private volatile GLContextImpl context; // volatile: avoid locking for read-only access /* Native window surface */ private final boolean useX11GTK; @@ -124,6 +124,10 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { /* Flag indicating whether an unprocessed reshape is pending. */ private volatile boolean sendReshape; // volatile: maybe written by WindowManager thread w/o locking + private static String getThreadName() { return Thread.currentThread().getName(); } + private static String toHexString(int v) { return "0x"+Integer.toHexString(v); } + private static String toHexString(long v) { return "0x"+Long.toHexString(v); } + /* * Invokes init(...) on all GLEventListeners. Assumes context is current when run. */ @@ -263,6 +267,36 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { }; /** + * Creates an instance using {@link #GLCanvas(Composite, int, GLCapabilitiesImmutable, GLCapabilitiesChooser)} + * on the SWT thread. + * + * @param parent + * Required (non-null) parent Composite. + * @param style + * Optional SWT style bit-field. The {@link SWT#NO_BACKGROUND} bit is set before passing this up to the + * Canvas constructor, so OpenGL handles the background. + * @param caps + * Optional GLCapabilities. If not provided, the default capabilities for the default GLProfile for the + * graphics device determined by the parent Composite are used. Note that the GLCapabilities that are + * actually used may differ based on the capabilities of the graphics device. + * @param chooser + * Optional GLCapabilitiesChooser to customize the selection of the used GLCapabilities based on the + * requested GLCapabilities, and the available capabilities of the graphics device. + * @return a new instance + */ + public static GLCanvas create(final Composite parent, final int style, final GLCapabilitiesImmutable caps, + final GLCapabilitiesChooser chooser) { + final GLCanvas[] res = new GLCanvas[] { null }; + parent.getDisplay().syncExec(new Runnable() { + @Override + public void run() { + res[0] = new GLCanvas( parent, style, caps, chooser ); + } + }); + return res[0]; + } + + /** * Creates an instance using {@link #GLCanvas(Composite, int, GLCapabilitiesImmutable, GLCapabilitiesChooser, GLContext)} * on the SWT thread. * @@ -281,6 +315,8 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { * @param shareWith * Optional GLContext to share state (textures, vbos, shaders, etc.) with. * @return a new instance + * @deprecated Use {@link #create(Composite, int, GLCapabilitiesImmutable, GLCapabilitiesChooser)} + * and set shared GLContext via {@link #setSharedContext(GLContext)} or {@link #setSharedAutoDrawable(GLAutoDrawable)}. */ public static GLCanvas create(final Composite parent, final int style, final GLCapabilitiesImmutable caps, final GLCapabilitiesChooser chooser, final GLContext shareWith) { @@ -309,8 +345,31 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { * @param capsChooser * Optional GLCapabilitiesChooser to customize the selection of the used GLCapabilities based on the * requested GLCapabilities, and the available capabilities of the graphics device. + */ + public GLCanvas(final Composite parent, final int style, GLCapabilitiesImmutable capsReqUser, + final GLCapabilitiesChooser capsChooser) { + this(parent, style, capsReqUser, capsChooser, null); + } + + /** + * Creates a new SWT GLCanvas. + * + * @param parent + * Required (non-null) parent Composite. + * @param style + * Optional SWT style bit-field. The {@link SWT#NO_BACKGROUND} bit is set before passing this up to the + * Canvas constructor, so OpenGL handles the background. + * @param capsReqUser + * Optional GLCapabilities. If not provided, the default capabilities for the default GLProfile for the + * graphics device determined by the parent Composite are used. Note that the GLCapabilities that are + * actually used may differ based on the capabilities of the graphics device. + * @param capsChooser + * Optional GLCapabilitiesChooser to customize the selection of the used GLCapabilities based on the + * requested GLCapabilities, and the available capabilities of the graphics device. * @param shareWith * Optional GLContext to share state (textures, vbos, shaders, etc.) with. + * @deprecated Use {@link #GLCanvas(Composite, int, GLCapabilitiesImmutable, GLCapabilitiesChooser)} + * and set shared GLContext via {@link #setSharedContext(GLContext)} or {@link #setSharedAutoDrawable(GLAutoDrawable)}. */ public GLCanvas(final Composite parent, final int style, GLCapabilitiesImmutable capsReqUser, final GLCapabilitiesChooser capsChooser, final GLContext shareWith) { @@ -347,7 +406,9 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { this.capsRequested = capsReqUser; this.capsChooser = capsChooser; - this.shareWith = shareWith; + if( null != shareWith ) { + helper.setSharedContext(null, shareWith); + } // post create .. when ready gdkWindow = 0; @@ -376,6 +437,16 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { addListener (SWT.Dispose, listener); } + @Override + public final void setSharedContext(GLContext sharedContext) throws IllegalStateException { + helper.setSharedContext(this.context, sharedContext); + } + + @Override + public final void setSharedAutoDrawable(GLAutoDrawable sharedAutoDrawable) throws IllegalStateException { + helper.setSharedAutoDrawable(this, sharedAutoDrawable); + } + private final UpstreamSurfaceHook swtCanvasUpStreamHook = new UpstreamSurfaceHook() { @Override public final void create(ProxySurface s) { /* nop */ } @@ -411,7 +482,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { final boolean drawableOK = null != _drawable && _drawable.isRealized(); if(DEBUG) { final long dh = drawableOK ? _drawable.getHandle() : 0; - System.err.println("GLCanvas.sizeChanged: ("+Thread.currentThread().getName()+"): "+nClientArea.x+"/"+nClientArea.y+" "+nClientArea.width+"x"+nClientArea.height+" - drawableHandle 0x"+Long.toHexString(dh)); + System.err.println(getThreadName()+": GLCanvas.sizeChanged: ("+Thread.currentThread().getName()+"): "+nClientArea.x+"/"+nClientArea.y+" "+nClientArea.width+"x"+nClientArea.height+" - drawableHandle "+toHexString(dh)); } if( drawableOK ) { if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) { @@ -451,7 +522,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } } - /** assumes drawable == null || !drawable.isRealized() ! Checks of !isDispose() and isVisible() */ + /** assumes drawable == null (implying !drawable.isRealized()) ! Checks of !isDispose() and isVisible() */ protected final boolean validateDrawableAndContextWithCheck() { if( !isValidAndVisibleOnEDT() ) { return false; @@ -459,41 +530,55 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { return validateDrawableAndContextPostCheck(); } - /** assumes drawable == null || !drawable.isRealized() ! No check of !isDispose() and isVisible() */ - protected final boolean validateDrawableAndContextPostCheck() { - final Rectangle nClientArea = clientArea; - if(0 >= nClientArea.width || 0 >= nClientArea.height) { - return false; - } + private final boolean isDrawableAndContextValid() { + // drawable != null implies drawable.isRealized()==true + return null != drawable && null != context; + } - final boolean res; + /** assumes drawable == null (implying !drawable.isRealized()) || context == null ! No check of !isDispose() and isVisible() */ + private final boolean validateDrawableAndContextPostCheck() { + boolean res; final RecursiveLock _lock = lock; _lock.lock(); try { if(null == drawable) { - createDrawableAndContext(); + // 'displayable' (isValidAndVisibleOnEDT()) must have been checked upfront if appropriate! + createDrawableImpl(); // checks clientArea size (i.e. drawable size) and perf. realization } - if(null != drawable) { - drawable.setRealized(true); - res = drawable.isRealized(); + final GLDrawable _drawable = drawable; + if ( null != _drawable ) { + // drawable realization goes in-hand w/ it's construction + if( null == context ) { + // re-try context creation + res = createContextImpl(_drawable); // pending creation. + } else { + res = true; + } + if(res) { + sendReshape = true; + } } else { + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate "+toHexString(hashCode())+": null drawable"); + } res = false; } - } finally { - _lock.unlock(); - } - - if(res) { - sendReshape = true; if(DEBUG) { - System.err.println("SWT GLCanvas realized! "+this+", "+drawable); - // Thread.dumpStack(); + System.err.println(getThreadName()+": SWT.GLCanvas.validate.X "+toHexString(hashCode())+": "+res+", drawable-realized "+drawable.isRealized()+", has context "+(null!=context)); } + } finally { + _lock.unlock(); } return res; } - - private final void createDrawableAndContext() { + private final void createDrawableImpl() { + final Rectangle nClientArea = clientArea; + if(0 >= nClientArea.width || 0 >= nClientArea.height) { + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate.X "+toHexString(hashCode())+": drawable could not be created: size < 0x0"); + } + return; // early out + } final AbstractGraphicsDevice device = screen.getDevice(); device.open(); @@ -503,7 +588,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { final AbstractGraphicsConfiguration cfg = factory.chooseGraphicsConfiguration( capsRequested, capsRequested, capsChooser, screen, VisualIDHolder.VID_UNDEFINED); if(DEBUG) { - System.err.println("SWT.GLCanvas.X11 factory: "+factory+", chosen config: "+cfg); + System.err.println(getThreadName()+": SWT.GLCanvas.X11 "+toHexString(hashCode())+": factory: "+factory+", chosen config: "+cfg); } if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); @@ -515,7 +600,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { x11Window = SWTAccessor.createCompatibleX11ChildWindow(screen, this, visualID, clientArea.width, clientArea.height); nativeWindowHandle = x11Window; } else { - throw new GLException("Could not choose valid visualID: 0x"+Integer.toHexString(visualID)+", "+this); + throw new GLException("Could not choose valid visualID: "+toHexString(visualID)+", "+this); } } else { nativeWindowHandle = SWTAccessor.getWindowHandle(this); @@ -526,9 +611,35 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { ProxySurface proxySurface = glFactory.createProxySurface(device, screen.getIndex(), nativeWindowHandle, capsRequested, capsChooser, swtCanvasUpStreamHook); // Associate a GL surface with the proxy - drawable = (GLDrawableImpl) glFactory.createGLDrawable(proxySurface); - context = (GLContextImpl) drawable.createContext(shareWith); - context.setContextCreationFlags(additionalCtxCreationFlags); + final GLDrawableImpl _drawable = (GLDrawableImpl) glFactory.createGLDrawable(proxySurface); + _drawable.setRealized(true); + if(!_drawable.isRealized()) { + // oops + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate.X "+toHexString(hashCode())+": Drawable could not be realized: "+_drawable); + } + } else { + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate "+toHexString(hashCode())+": Drawable created and realized"); + } + drawable = _drawable; + } + } + private boolean createContextImpl(final GLDrawable drawable) { + final GLContext[] shareWith = { null }; + if( !helper.isSharedGLContextPending(shareWith) ) { + context = (GLContextImpl) drawable.createContext(shareWith[0]); + context.setContextCreationFlags(additionalCtxCreationFlags); + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate "+toHexString(hashCode())+": Context created: has shared "+(null != shareWith[0])); + } + return true; + } else { + if(DEBUG) { + System.err.println(getThreadName()+": SWT.GLCanvas.validate "+toHexString(hashCode())+": Context !created: pending share"); + } + return false; + } } @Override @@ -555,8 +666,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { private final void displayIfNoAnimatorNoCheck() { if ( !helper.isAnimatorAnimatingOnOtherThread() ) { - final boolean drawableOK = null != drawable && drawable.isRealized(); - if( drawableOK || validateDrawableAndContextPostCheck() ) { + if( isDrawableAndContextValid() || validateDrawableAndContextPostCheck() ) { runInGLThread(makeCurrentAndDisplayOnGLAction); } } @@ -568,8 +678,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { @Override public void display() { - final boolean drawableOK = null != drawable && drawable.isRealized(); - if( drawableOK || validateDrawableAndContextWithCheck() ) { + if( isDrawableAndContextValid() || validateDrawableAndContextWithCheck() ) { runInGLThread(makeCurrentAndDisplayOnGLAction); } } @@ -876,7 +985,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { return "SWT-GLCanvas[Realized "+isRealized()+ ",\n\t"+((null!=_drawable)?_drawable.getClass().getName():"null-drawable")+ ",\n\tFactory "+getFactory()+ - ",\n\thandle 0x"+Long.toHexString(getHandle())+ + ",\n\thandle "+toHexString(getHandle())+ ",\n\tDrawable size "+dw+"x"+dh+ ",\n\tSWT size "+getWidth()+"x"+getHeight()+"]"; } @@ -895,7 +1004,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { shell.setSize(128,128); shell.setLayout(new FillLayout()); - final GLCanvas canvas = new GLCanvas(shell, 0, caps, null, null); + final GLCanvas canvas = new GLCanvas(shell, 0, caps, null); canvas.addGLEventListener(new GLEventListener() { @Override diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java index f480c4bde..f84342e88 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java @@ -28,6 +28,7 @@ package com.jogamp.opengl.util; +import java.lang.reflect.Constructor; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.FloatBuffer; @@ -444,6 +445,38 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData protected GLArrayDataClient() { } + /** + * Copy Constructor + * <p> + * Buffer is {@link Buffers#slice(Buffer) sliced}, i.e. sharing content but using own state. + * </p> + * <p> + * All other values are simply copied. + * </p> + */ + public GLArrayDataClient(GLArrayDataClient src) { + super(src); + this.isValidated = src.isValidated; + this.sealed = src.sealed; + this.bufferEnabled = src.bufferEnabled; + this.bufferWritten = src.bufferWritten; + this.enableBufferAlways = src.enableBufferAlways; + this.initialElementCount = src.initialElementCount; + if( null != src.glArrayHandler ) { + final Class<? extends GLArrayHandler> clazz = src.glArrayHandler.getClass(); + try { + final Constructor<? extends GLArrayHandler> ctor = clazz.getConstructor(GLArrayDataEditable.class); + this.glArrayHandler = ctor.newInstance(this); + } catch (Exception e) { + throw new RuntimeException("Could not ctor "+clazz.getName()+"("+this.getClass().getName()+")", e); + } + } else { + this.glArrayHandler = null; + } + this.usesGLSL = src.usesGLSL; + this.shaderState = src.shaderState; + } + protected boolean sealed; protected boolean bufferEnabled; protected boolean bufferWritten; diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java index 96643ae72..4a12ff1ae 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java @@ -29,6 +29,7 @@ package com.jogamp.opengl.util; import java.nio.Buffer; +import java.nio.FloatBuffer; import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; @@ -36,6 +37,8 @@ import javax.media.opengl.GLArrayData; import javax.media.opengl.GLException; import javax.media.opengl.fixedfunc.GLPointerFuncUtil; +import com.jogamp.common.nio.Buffers; + import jogamp.opengl.util.GLArrayHandler; import jogamp.opengl.util.GLArrayHandlerInterleaved; import jogamp.opengl.util.GLDataArrayHandler; @@ -364,6 +367,14 @@ public class GLArrayDataServer extends GLArrayDataClient implements GLArrayDataE return ad; } + public final void setInterleavedOffset(int interleavedOffset) { + this.interleavedOffset = interleavedOffset; + } + + public final int getInterleavedOffset() { + return interleavedOffset; + } + // // Data matters GLArrayData // @@ -458,6 +469,22 @@ public class GLArrayDataServer extends GLArrayDataClient implements GLArrayDataE } } + protected GLArrayDataServer() { } + + /** + * Copy Constructor + * <p> + * Buffer is {@link Buffers#slice(Buffer) sliced}, i.e. sharing content but using own state. + * </p> + * <p> + * All other values are simply copied. + * </p> + */ + public GLArrayDataServer(GLArrayDataServer src) { + super(src); + this.interleavedOffset = src.interleavedOffset; + } + private int interleavedOffset = 0; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataWrapper.java b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataWrapper.java index 290f47a6d..068ab5203 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataWrapper.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataWrapper.java @@ -42,6 +42,8 @@ import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; import javax.media.opengl.fixedfunc.GLPointerFuncUtil; +import com.jogamp.common.nio.Buffers; + import jogamp.opengl.Debug; public class GLArrayDataWrapper implements GLArrayData { @@ -373,6 +375,44 @@ public class GLArrayDataWrapper implements GLArrayData { protected GLArrayDataWrapper() { } + /** + * Copy Constructor + * <p> + * Buffer is {@link Buffers#slice(Buffer) sliced}, i.e. sharing content but using own state. + * </p> + * <p> + * All other values are simply copied. + * </p> + */ + public GLArrayDataWrapper(GLArrayDataWrapper src) { + this.alive = src.alive; + this.index = src.index; + this.location = src.location; + this.name = src.name; + this.components = src.components; + this.componentType = src.componentType; + this.componentClazz = src.componentClazz; + this.componentByteSize = src.componentByteSize; + this.normalized = src.normalized; + this.strideB = src.strideB; + this.strideL = src.strideL; + if( null != src.buffer ) { + if( src.buffer.position() == 0 ) { + this.buffer = Buffers.slice(src.buffer); + } else { + this.buffer = Buffers.slice(src.buffer, 0, src.buffer.limit()); + } + } else { + this.buffer = null; + } + this.isVertexAttribute = src.isVertexAttribute; + this.vboOffset = src.vboOffset; + this.vboName = src.vboName; + this.vboEnabled = src.vboEnabled; + this.vboUsage = src.vboUsage; + this.vboTarget = src.vboTarget; + } + protected boolean alive; protected int index; protected int location; diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index 5c6c7073a..deb1d7587 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -207,7 +207,7 @@ public abstract class GLContext { protected final RecursiveLock lock = LockFactory.createRecursiveLock(); /** The underlying native OpenGL context */ - protected volatile long contextHandle; + protected volatile long contextHandle; // volatile: avoid locking for read-only access protected GLContext() { resetStates(true); diff --git a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java index 98eb9bdde..3e53a1819 100644 --- a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java +++ b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java @@ -270,7 +270,7 @@ public abstract class GLDrawableFactory { public abstract AbstractGraphicsDevice getDefaultDevice(); /** - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. * @return true if the device is compatible with this factory, ie. if it can be used for GLDrawable creation. Otherwise false. * This implies validation whether the implementation is functional. * @@ -316,7 +316,7 @@ public abstract class GLDrawableFactory { * This does not imply a shared resource is mapped (ie. made persistent), but is available in general<br>. * </p> * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. * @return true if a shared resource could been created, otherwise false. */ protected final boolean createSharedResource(AbstractGraphicsDevice device) { @@ -334,7 +334,7 @@ public abstract class GLDrawableFactory { * </pre> * </p> * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. * @param quirk the quirk to be tested, e.g. {@link GLRendererQuirks#NoDoubleBufferedPBuffer}. * @throws IllegalArgumentException if the quirk is out of range * @see #getRendererQuirks(AbstractGraphicsDevice) @@ -354,7 +354,7 @@ public abstract class GLDrawableFactory { * In case no shared device exist yet or the implementation doesn't support tracking quirks, * the result is always <code>null</code>. * </p> - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. * @see GLContext#getRendererQuirks() * @see GLRendererQuirks */ @@ -413,7 +413,7 @@ public abstract class GLDrawableFactory { * The chosen GLProfile statement in the result may not refer to the maximum available profile * due to implementation constraints, ie using the shared resource. * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. * @return A list of {@link javax.media.opengl.GLCapabilitiesImmutable}'s, maybe empty if none is available. */ public final List<GLCapabilitiesImmutable> getAvailableCapabilities(AbstractGraphicsDevice device) { @@ -460,14 +460,14 @@ public abstract class GLDrawableFactory { * @see javax.media.opengl.GLCapabilities#isOnscreen() * @see javax.media.opengl.GLCapabilities#isFBO() * @see javax.media.opengl.GLCapabilities#isPBuffer() - * @see javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(CapabilitiesImmutable, CapabilitiesImmutable, javax.media.nativewindow.CapabilitiesChooser, AbstractGraphicsScreen, int) + * @see GraphicsConfigurationFactory#chooseGraphicsConfiguration(CapabilitiesImmutable, CapabilitiesImmutable, CapabilitiesChooser, AbstractGraphicsScreen, int) */ public abstract GLDrawable createGLDrawable(NativeSurface target) throws IllegalArgumentException, GLException; /** * Creates a {@link GLDrawable#isRealized() realized} {@link GLOffscreenAutoDrawable} - * incl it's offscreen {@link javax.media.nativewindow.NativeSurface} with the given capabilites and dimensions. + * incl it's offscreen {@link NativeSurface} with the given capabilites and dimensions. * <p> * The {@link GLOffscreenAutoDrawable}'s {@link GLDrawable} is {@link GLDrawable#isRealized() realized} * and it's {@link GLContext} assigned but not yet made current. @@ -491,7 +491,7 @@ public abstract class GLDrawableFactory { * a simple pixmap/bitmap auto drawable is created, which is unlikely to be hardware accelerated. * </p> * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> 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 @@ -512,10 +512,10 @@ public abstract class GLDrawableFactory { /** * Creates a {@link GLDrawable#isRealized() realized} {@link GLOffscreenAutoDrawable} - * incl it's offscreen {@link javax.media.nativewindow.NativeSurface} with the given capabilites and dimensions. + * incl it's offscreen {@link NativeSurface} with the given capabilites and dimensions. * <p> * The {@link GLOffscreenAutoDrawable}'s {@link GLDrawable} is {@link GLDrawable#isRealized() realized} - * <i>without</i> an assigned {@link GLContext}.<br> + * <i>without</i> an assigned {@link GLContext}, hence not initialized completely.<br> * The {@link GLContext} can be assigned later manually via {@link GLAutoDrawable#setContext(GLContext, boolean) setContext(ctx)} * <i>or</i> it will be created <i>lazily</i> at the 1st {@link GLAutoDrawable#display() display()} method call.<br> * <i>Lazy</i> {@link GLContext} creation will take a shared {@link GLContext} into account @@ -541,12 +541,12 @@ public abstract class GLDrawableFactory { * a simple pixmap/bitmap auto drawable is created, which is unlikely to be hardware accelerated. * </p> * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> 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 and initialized offscreen {@link GLOffscreenAutoDrawable} instance + * @return the created and realized offscreen {@link GLOffscreenAutoDrawable} instance * * @throws GLException if any window system-specific errors caused * the creation of the Offscreen to fail. @@ -559,8 +559,31 @@ public abstract class GLDrawableFactory { int width, int height) throws GLException; /** + * Creates a {@link GLDrawable#isRealized() realized} <i>dummy</i> {@link GLAutoDrawable} + * incl it's <i>dummy, invisible</i> {@link NativeSurface} + * as created with {@link #createDummyDrawable(AbstractGraphicsDevice, boolean, GLProfile)}. + * <p> + * The <i>dummy</i> {@link GLAutoDrawable}'s {@link GLDrawable} is {@link GLDrawable#isRealized() realized} + * <i>without</i> an assigned {@link GLContext}, hence not initialized completely.<br> + * The {@link GLContext} can be assigned later manually via {@link GLAutoDrawable#setContext(GLContext, boolean) setContext(ctx)} + * <i>or</i> it will be created <i>lazily</i> at the 1st {@link GLAutoDrawable#display() display()} method call.<br> + * <i>Lazy</i> {@link GLContext} creation will take a shared {@link GLContext} into account + * which has been set {@link GLOffscreenAutoDrawable#setSharedContext(GLContext) directly} + * or {@link GLOffscreenAutoDrawable#setSharedAutoDrawable(GLAutoDrawable) via another GLAutoDrawable}. + * </p> + * + * @param deviceReq which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device. + * @param createNewDevice if <code>true</code> a new independent device instance is created from the <code>deviceReq</code>, otherwise <code>deviceReq</code> is used as-is and must be valid! + * @param glp the desired {@link GLProfile} + * @return the created and realized <i>dummy</i> {@link GLAutoDrawable} instance + * + * @see #createDummyDrawable(AbstractGraphicsDevice, boolean, GLProfile) + */ + public abstract GLAutoDrawable createDummyAutoDrawable(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLProfile glp); + + /** * Creates an {@link GLDrawable#isRealized() unrealized} offscreen {@link GLDrawable} - * incl it's offscreen {@link javax.media.nativewindow.NativeSurface} with the given capabilites and dimensions. + * incl it's offscreen {@link NativeSurface} with the given capabilites and dimensions. * <p> * In case the passed {@link GLCapabilitiesImmutable} contains default values, i.e. * {@link GLCapabilitiesImmutable#isOnscreen() caps.isOnscreen()} <code> == true</code>, @@ -579,13 +602,13 @@ public abstract class GLDrawableFactory { * a simple pixmap/bitmap drawable is created, which is unlikely to be hardware accelerated. * </p> * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> 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} + * @return the created unrealized offscreen {@link GLDrawable} * * @throws GLException if any window system-specific errors caused * the creation of the Offscreen to fail. @@ -604,10 +627,10 @@ public abstract class GLDrawableFactory { * It is used to allow the creation of a {@link GLContext} to query information. * It also allows creation of framebuffer objects which are used for rendering or creating a shared GLContext w/o actually rendering to this dummy drawable's framebuffer. * </p> - * @param deviceReq which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device. + * @param deviceReq which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device. * @param createNewDevice if <code>true</code> a new independent device instance is created from the <code>deviceReq</code>, otherwise <code>deviceReq</code> is used as-is and must be valid! * @param glp the desired {@link GLProfile} - * @return the created dummy {@link GLDrawable} + * @return the created unrealized dummy {@link GLDrawable} */ public abstract GLDrawable createDummyDrawable(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLProfile glp); @@ -628,7 +651,7 @@ public abstract class GLDrawableFactory { * see {@link com.jogamp.opengl.swt.GLCanvas}. * </p> * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. * Caller has to ensure it is compatible w/ the given <code>windowHandle</code> * @param screenIdx matching screen index of given <code>windowHandle</code> * @param windowHandle the native window handle @@ -651,7 +674,7 @@ public abstract class GLDrawableFactory { * FBO support is queried as described in {@link GLContext#hasBasicFBOSupport()}. * </p> * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. * @param glp {@link GLProfile} to check for FBO capabilities * @see GLContext#hasBasicFBOSupport() */ @@ -664,7 +687,7 @@ public abstract class GLDrawableFactory { * as well as some new GL implementation, i.e. OpenGL 3 core on OSX. * </p> * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. * @param glp {@link GLProfile} to check for FBO capabilities */ public abstract boolean canCreateGLPbuffer(AbstractGraphicsDevice device, GLProfile glp); @@ -678,7 +701,7 @@ public abstract class GLDrawableFactory { * See the note in the overview documentation in {@link GLSharedContextSetter} and on * <a href="../../../spec-overview.html#SHARING">context sharing</a>. * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. * @param capabilities the requested capabilities * @param chooser the custom chooser, may be null for default * @param initialWidth initial width of pbuffer @@ -733,7 +756,7 @@ public abstract class GLDrawableFactory { * Returns true if it is possible to create an external GLDrawable * object via {@link #createExternalGLDrawable}. * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. */ public abstract boolean canCreateExternalGLDrawable(AbstractGraphicsDevice device); diff --git a/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java b/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java index 8c2311329..873e4cd9f 100644 --- a/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java +++ b/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java @@ -36,24 +36,45 @@ package javax.media.opengl; * </p> * <p> * A <i>master</i> {@link GLContext} is the {@link GLContext} which is created first, - * shared {@link GLContext} w/ this master are referred as slave {@link GLContext}. + * shared {@link GLContext} w/ this master are referred as slave {@link GLContext} + * and controls the shared object's lifecycle, i.e. their construction and destruction. * </p> - * <h5><a name="driverstabilityconstraints">Driver stability constraints</a></h5> + * <h5><a name="lifecycle">Lifecycle Considerations</a></h5> * <p> - * Be aware that the <i>master</i> {@link GLContext} and related resources, i.e. the {@link GLAutoDrawable}, - * <i>shall not</i> be destroyed before it's <i>slave</i> {@link GLContext} instances.<br> - * Otherwise the OpenGL driver implementation may crash w/ SIGSEGV if shared resources are still used!<br> - * Note that this is not specified within OpenGL and <i>should work</i>, however, some drivers - * do not seem to handle this situation well, i.e. they do not postpone resource destruction - * until the last reference is removed.<br> - * Since pending destruction of {@link GLContext} and it's {@link GLDrawable} is complex and nearly impossible - * for us at the top level, considering the different windowing systems and {@link GLAutoDrawable} types, - * the user shall take care of proper destruction order. + * After shared objects are created on the <i>master</i>, the OpenGL pipeline + * might need to be synchronized w/ the <i>slaves</i>, e.g. via {@link GL#glFinish()}. + * At least this has been experienced w/ OSX 10.9. * </p> * <p> - * Users may use a {@link GLDrawableFactory#createDummyDrawable(javax.media.nativewindow.AbstractGraphicsDevice, boolean, GLProfile) dummy} + * Be aware that the <i>master</i> {@link GLContext} and related resources + * <i>shall not</i> be destroyed before it's <i>slave</i> {@link GLContext} instances <i>while they are using them</i>.<br> + * Otherwise the OpenGL driver implementation may crash w/ SIGSEGV, since using already destroyed resources, + * e.g. OpenGL buffer objects, may not be validated by the driver!<br> + * </p> + * <p> + * Either proper lifecycle synchronization is implemented, e.g. by notifying the <i>slaves</i> about the loss of the shared resources, + * <i>or</i> the <i>slaves</i> validate whether the resources are still valid. + * </p> + * <p> + * To simplify above lifecycle issues, one may use a {@link GLDrawableFactory#createDummyDrawable(javax.media.nativewindow.AbstractGraphicsDevice, boolean, GLProfile) dummy} * {@link GLDrawable} and it's {@link GLContext} as the <i>master</i> of all shared <i>slave</i> {@link GLContext}. - * Same constraints as above apply, i.e. it shall be destroyed <i>after</i> all shared slaves. + * Since this <i>dummy instance</i> does not depend on any native windowing system, it can be controlled easily w/o being <i>in sight</i>.<br> + * Below code creates a {@link GLAutoDrawable} based on a <i>dummy GLDrawable</i>: + * <pre> + // GLProfile and GLCapabilities should be equal across all shared GL drawable/context. + final GLCapabilitiesImmutable caps = ... ; + final GLProfile glp = caps.getGLProfile(); + .. + final boolean createNewDevice = true; // use 'own' display device! + final GLAutoDrawable sharedDrawable = GLDrawableFactory.getFactory(glp).createDummyAutoDrawable(null, createNewDevice, glp); + sharedDrawable.display(); // triggers GLContext object creation and native realization. + ... + // Later a shared 'slave' can be created e.g.: + GLWindow glad = GLWindow.create(caps); // or any other GLAutoDrawable supporting GLSharedContextSetter + glad.setSharedAutoDrawable(sharedDrawable); + glad.addGLEventListener(..); + glad.setVisible(true); // GLWindow creation .. + * </pre> * </p> */ public interface GLSharedContextSetter extends GLAutoDrawable { @@ -69,7 +90,7 @@ public interface GLSharedContextSetter extends GLAutoDrawable { * as long it is not {@link GLContext#isCreated() created natively}. * </p> * <p> - * See <a href="#driverstabilityconstraints">driver stability constraints</a>. + * See <a href="#lifecycle">Lifecycle Considerations</a>. * </p> * * @param sharedContext The OpenGL context to be shared by this {@link GLAutoDrawable}'s {@link GLContext}. @@ -93,7 +114,7 @@ public interface GLSharedContextSetter extends GLAutoDrawable { * or has not been {@link GLContext#isCreated() created natively}. * </p> * <p> - * See <a href="#driverstabilityconstraints">driver stability constraints</a>. + * See <a href="#lifecycle">Lifecycle Considerations</a>. * </p> * * @param sharedContext The GLAutoDrawable, which OpenGL context shall be shared by this {@link GLAutoDrawable}'s {@link GLContext}. diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index 439a5bd30..01d6a6738 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -163,7 +163,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private AWTGraphicsConfiguration awtConfig; 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 volatile GLContextImpl context; + private volatile GLContextImpl context; // volatile: avoid locking for read-only access private volatile boolean sendReshape = false; // volatile: maybe written by EDT w/o locking // copy of the cstr args, mainly for recreation diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index 8b1467268..fdacc5bc4 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -1295,12 +1295,12 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing protected IntBuffer readBackIntsForCPUVFlip; // Implementation using software rendering - private volatile GLDrawableImpl offscreenDrawable; + private volatile GLDrawableImpl offscreenDrawable; // volatile: avoid locking for read-only access private boolean offscreenIsFBO; private FBObject fboFlipped; private GLSLTextureRaster glslTextureRaster; - private volatile GLContextImpl offscreenContext; + private volatile GLContextImpl offscreenContext; // volatile: avoid locking for read-only access private boolean flipVertical; // For saving/restoring of OpenGL state during ReadPixels diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 77e493b25..eae40631d 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -280,11 +280,11 @@ public abstract class GLContextImpl extends GLContext { @Override public GL setGL(GL gl) { - if(DEBUG) { - String sgl1 = (null!=this.gl)?this.gl.getClass().getSimpleName()+", "+this.gl.toString():"<null>"; - String sgl2 = (null!=gl)?gl.getClass().getSimpleName()+", "+gl.toString():"<null>"; - Exception e = new Exception("Info: setGL (OpenGL "+getGLVersion()+"): "+getThreadName()+", "+sgl1+" -> "+sgl2); - e.printStackTrace(); + if( DEBUG ) { + final String sgl1 = (null!=this.gl)?this.gl.getClass().getSimpleName()+", "+this.gl.toString():"<null>"; + final String sgl2 = (null!=gl)?gl.getClass().getSimpleName()+", "+gl.toString():"<null>"; + System.err.println("Info: setGL (OpenGL "+getGLVersion()+"): "+getThreadName()+", "+sgl1+" -> "+sgl2); + Thread.dumpStack(); } this.gl = gl; return gl; @@ -600,13 +600,13 @@ public abstract class GLContextImpl extends GLContext { glDebugHandler.init( isGL2GL3() && isGLDebugEnabled() ); if(DEBUG_GL) { - gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Debug", null, gl, null) ); + setGL( GLPipelineFactory.create("javax.media.opengl.Debug", null, gl, null) ); if(glDebugHandler.isEnabled()) { glDebugHandler.addListener(new GLDebugMessageHandler.StdErrGLDebugListener(true)); } } if(TRACE_GL) { - gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) ); + setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) ); } forceDrawableAssociation = true; @@ -650,6 +650,10 @@ public abstract class GLContextImpl extends GLContext { final GLContextImpl shareWith = (GLContextImpl) GLContextShareSet.getCreatedShare(this); if (null != shareWith) { shareWith.getDrawableImpl().lockSurface(); + // FIXME: + // Contemplate whether we shall 'fail' creating this context + // if 0==shareWith.getHandle(), since at this point + // both context are locked and current values are available. } final boolean created; try { diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index ecb9f7dd1..a9f12b17e 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -49,6 +49,7 @@ import javax.media.nativewindow.OffscreenLayerSurface; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.MutableSurface; import javax.media.nativewindow.UpstreamSurfaceHook; +import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; @@ -64,6 +65,7 @@ import javax.media.opengl.GLProfile; import com.jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.nativewindow.DelegatedUpstreamSurfaceHookWithSurfaceSize; import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; +import com.jogamp.opengl.GLAutoDrawableDelegate; import com.jogamp.opengl.GLRendererQuirks; @@ -326,6 +328,14 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { } @Override + public final GLAutoDrawable createDummyAutoDrawable(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLProfile glp) { + final GLDrawable drawable = createDummyDrawable(deviceReq, createNewDevice, glp); + drawable.setRealized(true); + final GLAutoDrawable sharedDrawable = new GLAutoDrawableDelegate(drawable, null, null, true /*ownDevice*/, null) { }; + return sharedDrawable; + } + + @Override public final GLDrawable createOffscreenDrawable(AbstractGraphicsDevice deviceReq, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index cf5d7a206..61735c487 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -48,6 +48,7 @@ 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.GLAnimatorControl; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLContext; @@ -662,6 +663,14 @@ public class GLDrawableHelper { } } if(setViewport) { + final GL gl = drawable.getGL(); + final int glerr0 = gl.glGetError(); + if( GL.GL_NO_ERROR != glerr0 ) { + System.err.println("Info: GLDrawableHelper.reshape: pre-exisiting GL error 0x"+Integer.toHexString(glerr0)); + if(DEBUG) { + Thread.dumpStack(); + } + } drawable.getGL().glViewport(x, y, width, height); } listener.reshape(drawable, x, y, width, height); diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java index a79a3cf25..94d39a4ab 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java @@ -344,9 +344,9 @@ public abstract class GLDrawableImpl implements GLDrawable { protected static String getThreadName() { return Thread.currentThread().getName(); } - protected GLDrawableFactory factory; - protected NativeSurface surface; - protected GLCapabilitiesImmutable requestedCapabilities; + protected final GLDrawableFactory factory; + protected final NativeSurface surface; + protected final GLCapabilitiesImmutable requestedCapabilities; // Indicates whether the surface (if an onscreen context) has been // realized. Plausibly, before the surface is realized the JAWT diff --git a/src/jogl/classes/jogamp/opengl/util/GLArrayHandlerInterleaved.java b/src/jogl/classes/jogamp/opengl/util/GLArrayHandlerInterleaved.java index 0d4452864..89e01edd8 100644 --- a/src/jogl/classes/jogamp/opengl/util/GLArrayHandlerInterleaved.java +++ b/src/jogl/classes/jogamp/opengl/util/GLArrayHandlerInterleaved.java @@ -39,8 +39,8 @@ import com.jogamp.opengl.util.GLArrayDataEditable; * Interleaved fixed function arrays, i.e. where this buffer data * represents many arrays. */ -public class GLArrayHandlerInterleaved extends GLVBOArrayHandler implements GLArrayHandler { - private List<GLArrayHandlerFlat> subArrays = new ArrayList<GLArrayHandlerFlat>(); +public class GLArrayHandlerInterleaved extends GLVBOArrayHandler { + private final List<GLArrayHandlerFlat> subArrays = new ArrayList<GLArrayHandlerFlat>(); public GLArrayHandlerInterleaved(GLArrayDataEditable ad) { super(ad); diff --git a/src/jogl/classes/jogamp/opengl/util/GLDataArrayHandler.java b/src/jogl/classes/jogamp/opengl/util/GLDataArrayHandler.java index c1f6b954a..8a587980d 100644 --- a/src/jogl/classes/jogamp/opengl/util/GLDataArrayHandler.java +++ b/src/jogl/classes/jogamp/opengl/util/GLDataArrayHandler.java @@ -38,7 +38,7 @@ import com.jogamp.opengl.util.GLArrayDataEditable; * Used for pure VBO data arrays, i.e. where the buffer data * does not represents a specific array name. */ -public class GLDataArrayHandler extends GLVBOArrayHandler implements GLArrayHandler { +public class GLDataArrayHandler extends GLVBOArrayHandler { public GLDataArrayHandler(GLArrayDataEditable ad) { super(ad); diff --git a/src/jogl/classes/jogamp/opengl/util/GLFixedArrayHandler.java b/src/jogl/classes/jogamp/opengl/util/GLFixedArrayHandler.java index 3aac9612a..7f7a99a2d 100644 --- a/src/jogl/classes/jogamp/opengl/util/GLFixedArrayHandler.java +++ b/src/jogl/classes/jogamp/opengl/util/GLFixedArrayHandler.java @@ -38,7 +38,7 @@ import com.jogamp.opengl.util.GLArrayDataEditable; * Used for 1:1 fixed function arrays, i.e. where the buffer data * represents this array only. */ -public class GLFixedArrayHandler extends GLVBOArrayHandler implements GLArrayHandler { +public class GLFixedArrayHandler extends GLVBOArrayHandler { public GLFixedArrayHandler(GLArrayDataEditable ad) { super(ad); } diff --git a/src/jogl/classes/jogamp/opengl/util/glsl/GLSLArrayHandler.java b/src/jogl/classes/jogamp/opengl/util/glsl/GLSLArrayHandler.java index 3b443fdd0..1f402f48b 100644 --- a/src/jogl/classes/jogamp/opengl/util/glsl/GLSLArrayHandler.java +++ b/src/jogl/classes/jogamp/opengl/util/glsl/GLSLArrayHandler.java @@ -33,7 +33,6 @@ import java.nio.Buffer; import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; -import jogamp.opengl.util.GLArrayHandler; import jogamp.opengl.util.GLArrayHandlerFlat; import jogamp.opengl.util.GLVBOArrayHandler; @@ -44,7 +43,7 @@ import com.jogamp.opengl.util.glsl.ShaderState; * Used for 1:1 GLSL arrays, i.e. where the buffer data * represents this array only. */ -public class GLSLArrayHandler extends GLVBOArrayHandler implements GLArrayHandler { +public class GLSLArrayHandler extends GLVBOArrayHandler { public GLSLArrayHandler(GLArrayDataEditable ad) { super(ad); diff --git a/src/jogl/classes/jogamp/opengl/util/glsl/GLSLArrayHandlerInterleaved.java b/src/jogl/classes/jogamp/opengl/util/glsl/GLSLArrayHandlerInterleaved.java index b175bb5dc..e153082e0 100644 --- a/src/jogl/classes/jogamp/opengl/util/glsl/GLSLArrayHandlerInterleaved.java +++ b/src/jogl/classes/jogamp/opengl/util/glsl/GLSLArrayHandlerInterleaved.java @@ -33,7 +33,6 @@ import java.util.List; import javax.media.opengl.GL; -import jogamp.opengl.util.GLArrayHandler; import jogamp.opengl.util.GLArrayHandlerFlat; import jogamp.opengl.util.GLVBOArrayHandler; @@ -43,8 +42,8 @@ import com.jogamp.opengl.util.GLArrayDataEditable; * Interleaved fixed function arrays, i.e. where this buffer data * represents many arrays. */ -public class GLSLArrayHandlerInterleaved extends GLVBOArrayHandler implements GLArrayHandler { - private List<GLArrayHandlerFlat> subArrays = new ArrayList<GLArrayHandlerFlat>(); +public class GLSLArrayHandlerInterleaved extends GLVBOArrayHandler { + private final List<GLArrayHandlerFlat> subArrays = new ArrayList<GLArrayHandlerFlat>(); public GLSLArrayHandlerInterleaved(GLArrayDataEditable ad) { super(ad); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextNewtAWTBug523.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextNewtAWTBug523.java index 90344fb0b..ff98d6f57 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextNewtAWTBug523.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextNewtAWTBug523.java @@ -36,9 +36,12 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.nio.FloatBuffer; import java.nio.IntBuffer; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import javax.media.opengl.GL; import javax.media.opengl.GL2; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; @@ -82,7 +85,9 @@ import com.jogamp.opengl.util.GLBuffers; * * Each window renders a red triangle and a blue triangle. * The red triangle is rendered using glBegin / glVertex / glEnd. - * The blue triangle is rendered using vertex buffer objects bound to a vertex array object. + * The blue triangle is rendered using vertex buffer objects. + * + * VAO's are not used to allow testing on OSX GL2 context! * * If static useNewt is true, then those windows are GLWindow objects in a NewtCanvasAWT. * If static useNewt is false, then those windows are GLCanvas objects. @@ -114,10 +119,8 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { // Buffer objects can be shared across shared OpenGL context. // If we run with sharedContext, then the tests will use these shared buffer objects, // otherwise each event listener allocates its own buffer objects. - private static int [] sharedVertexBufferObjects = {0}; - private static int [] sharedIndexBufferObjects = {0}; - private static FloatBuffer sharedVertexBuffer; - private static IntBuffer sharedIndexBuffer; + private static volatile int[] sharedVertexBufferObjects = {0}; + private static volatile int[] sharedIndexBufferObjects = {0}; @BeforeClass public static void initClass() { @@ -131,6 +134,9 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { Assert.assertNotNull(sharedDrawable); // init and render one frame, which will setup the Gears display lists sharedDrawable.display(); + final GLContext ctx = sharedDrawable.getContext(); + Assert.assertNotNull("Shared drawable's ctx is null", ctx); + Assert.assertTrue("Shared drawable's ctx is not created", ctx.isCreated()); return sharedDrawable; } @@ -153,19 +159,43 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { private float yAxisRotation; private final float viewFovDegrees = 15f; - // vertex array objects cannot be shared across open gl canvases; - // - // However, display lists can be shared across GLCanvas instances (if those canvases are initialized with the same GLContext), - // including a display list created in one context that uses a VAO. - private final int [] vertexArrayObjects = {0}; - // Buffer objects can be shared across canvas instances, if those canvases are initialized with the same GLContext. // If we run with sharedBufferObjects true, then the tests will use these shared buffer objects. // If we run with sharedBufferObjects false, then each event listener allocates its own buffer objects. private final int [] privateVertexBufferObjects = {0}; private final int [] privateIndexBufferObjects = {0}; - private FloatBuffer privateVertexBuffer; - private IntBuffer privateIndexBuffer; + + public static int createVertexBuffer(GL2 gl2) { + final FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(18); + vertexBuffer.put(new float[]{ + 1.0f, -0.5f, 0f, // vertex 1 + 0f, 0f, 1f, // normal 1 + 1.5f, -0.5f, 0f, // vertex 2 + 0f, 0f, 1f, // normal 2 + 1.0f, 0.5f, 0f, // vertex 3 + 0f, 0f, 1f // normal 3 + }); + vertexBuffer.position(0); + + final int[] vbo = { 0 }; + gl2.glGenBuffers(1, vbo, 0); + gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, vbo[0]); + gl2.glBufferData(GL2.GL_ARRAY_BUFFER, vertexBuffer.capacity() * Buffers.SIZEOF_FLOAT, vertexBuffer, GL2.GL_STATIC_DRAW); + gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0); + return vbo[0]; + } + public static int createVertexIndexBuffer(GL2 gl2) { + final IntBuffer indexBuffer = GLBuffers.newDirectIntBuffer(3); + indexBuffer.put(new int[]{0, 1, 2}); + indexBuffer.position(0); + + final int[] vbo = { 0 }; + gl2.glGenBuffers(1, vbo, 0); + gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, vbo[0]); + gl2.glBufferData(GL2.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity() * Buffers.SIZEOF_INT, indexBuffer, GL2.GL_STATIC_DRAW); + gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0); + return vbo[0]; + } TwoTriangles (int canvasWidth, int canvasHeight, boolean useShared) { // instanceNum = instanceCounter++; @@ -199,47 +229,27 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { gl2.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // the first instance of TwoTriangles initializes the shared buffer objects; - // synchronizing to deal with potential liveness issues if the data is intialized from one thread and used on another + // synchronizing to deal with potential liveness issues if the data is initialized from one thread and used on another synchronized (this) { - gl2.glGenVertexArrays(1, vertexArrayObjects, 0); - - gl2.glBindVertexArray(vertexArrayObjects[0]); - // use either the shared or private vertex buffers, as int [] vertexBufferObjects; int [] indexBufferObjects; - FloatBuffer vertexBuffer; - IntBuffer indexBuffer; // if (useShared) { + System.err.println("Using shared VBOs on slave 0x"+Integer.toHexString(hashCode())); vertexBufferObjects = sharedVertexBufferObjects; indexBufferObjects = sharedIndexBufferObjects; - vertexBuffer = sharedVertexBuffer; - indexBuffer = sharedIndexBuffer; } else { + System.err.println("Using local VBOs on slave 0x"+Integer.toHexString(hashCode())); vertexBufferObjects = privateVertexBufferObjects; indexBufferObjects = privateIndexBufferObjects; - vertexBuffer = privateVertexBuffer; - indexBuffer = privateIndexBuffer; } // if buffer sharing is enabled, then the first of the two event listeners to be // initialized will allocate the buffers, and the other will re-use the allocated one if (vertexBufferObjects[0] == 0) { - vertexBuffer = GLBuffers.newDirectFloatBuffer(18); - vertexBuffer.put(new float[]{ - 1.0f, -0.5f, 0f, // vertex 1 - 0f, 0f, 1f, // normal 1 - 1.5f, -0.5f, 0f, // vertex 2 - 0f, 0f, 1f, // normal 2 - 1.0f, 0.5f, 0f, // vertex 3 - 0f, 0f, 1f // normal 3 - }); - vertexBuffer.position(0); - - gl2.glGenBuffers(1, vertexBufferObjects, 0); - gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, vertexBufferObjects[0]); - gl2.glBufferData(GL2.GL_ARRAY_BUFFER, vertexBuffer.capacity() * Buffers.SIZEOF_FLOAT, vertexBuffer, GL2.GL_STATIC_DRAW); + System.err.println("Creating vertex VBO on slave 0x"+Integer.toHexString(hashCode())); + vertexBufferObjects[0] = createVertexBuffer(gl2); } // A check in the case that buffer sharing is enabled but context sharing is not enabled -- in that @@ -256,24 +266,22 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { // gl2.glEnableClientState(GL2.GL_NORMAL_ARRAY); gl2.glNormalPointer(GL2.GL_FLOAT, 6 * GLBuffers.SIZEOF_FLOAT, 3 * GLBuffers.SIZEOF_FLOAT); + } else { + System.err.println("Vertex VBO is not a buffer on slave 0x"+Integer.toHexString(hashCode())); } if (indexBufferObjects[0] == 0) { - indexBuffer = GLBuffers.newDirectIntBuffer(3); - indexBuffer.put(new int[]{0, 1, 2}); - indexBuffer.position(0); - - gl2.glGenBuffers(1, indexBufferObjects, 0); - gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, indexBufferObjects[0]); - gl2.glBufferData(GL2.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity() * Buffers.SIZEOF_INT, indexBuffer, GL2.GL_STATIC_DRAW); + System.err.println("Creating index VBO on slave 0x"+Integer.toHexString(hashCode())); + indexBufferObjects[0] = createVertexIndexBuffer(gl2); } // again, a check in the case that buffer sharing is enabled but context sharing is not enabled if (gl2.glIsBuffer(indexBufferObjects[0])) { gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, indexBufferObjects[0]); + } else { + System.err.println("Index VBO is not a buffer on slave 0x"+Integer.toHexString(hashCode())); } - gl2.glBindVertexArray(0); gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0); gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0); gl2.glDisableClientState(GL2.GL_VERTEX_ARRAY); @@ -294,10 +302,6 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { GL2 gl2 = drawable.getGL().getGL2(); - gl2.glDeleteVertexArrays(1, vertexArrayObjects, 0); - vertexArrayObjects[0] = 0; - logAnyErrorCodes(gl2, "display"); - // release shared resources if (initializationCounter == 0 || !useShared) { // use either the shared or private vertex buffers, as @@ -312,10 +316,11 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { } gl2.glDeleteBuffers(1, vertexBufferObjects, 0); + logAnyErrorCodes(this, gl2, "dispose.2"); gl2.glDeleteBuffers(1, indexBufferObjects, 0); + logAnyErrorCodes(this, gl2, "dispose.3"); vertexBufferObjects[0] = 0; indexBufferObjects[0] = 0; - logAnyErrorCodes(gl2, "display"); } // release the main thread once for each disposal @@ -330,7 +335,7 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { // wait until all instances are initialized before attempting to draw using the // vertex array object, because the buffers are allocated in init and when the - // buffers are shared, we need to ensure that they are allocated before trying to use thems + // buffers are shared, we need to ensure that they are allocated before trying to use them synchronized (this) { if (initializationCounter != 2) { return; @@ -340,6 +345,8 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { GL2 gl2 = drawable.getGL().getGL2(); GLU glu = new GLU(); + logAnyErrorCodes(this, gl2, "display.0"); + // Clear the drawing area gl2.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); @@ -364,6 +371,8 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { gl2.glDisable(GL2.GL_CULL_FACE); gl2.glEnable(GL2.GL_DEPTH_TEST); + logAnyErrorCodes(this, gl2, "display.1"); + // draw the triangles drawTwoTriangles(gl2); @@ -373,7 +382,7 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { // Flush all drawing operations to the graphics card gl2.glFlush(); - logAnyErrorCodes(gl2, "display"); + logAnyErrorCodes(this, gl2, "display.X"); } public void drawTwoTriangles(GL2 gl2) { @@ -389,12 +398,14 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { gl2.glNormal3d(0, 0, 1); gl2.glEnd(); + logAnyErrorCodes(this, gl2, "drawTwoTriangles.1"); + // draw the blue triangle using a vertex array object, sharing the vertex and index buffer objects across // contexts; if context sharing is not initialized, then one window will simply have to live without a blue triangle // - // synchronizing to deal with potential liveness issues if the data is intialized from one + // synchronizing to deal with potential liveness issues if the data is initialized from one // thread and used on another - boolean vaoBound = false; + boolean vboBound = false; // use either the shared or private vertex buffers, as int [] vertexBufferObjects; int [] indexBufferObjects; @@ -414,21 +425,33 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { // when this check is removed, true blue triangle is not rendered anyways, and more importantly, // I found that with my system glDrawElements causes a runtime exception 50% of the time. Executing the binds // to unshareable buffers sets up glDrawElements for unpredictable crashes -- sometimes it does, sometimes not. - if (gl2.glIsVertexArray(vertexArrayObjects[0]) && - gl2.glIsBuffer(indexBufferObjects[0]) && gl2.glIsBuffer(vertexBufferObjects[0])) { - gl2.glBindVertexArray(vertexArrayObjects[0]); + final boolean isVBO1 = gl2.glIsBuffer(indexBufferObjects[0]); + final boolean isVBO2 = gl2.glIsBuffer(vertexBufferObjects[0]); + final boolean useVBO = isVBO1 && isVBO2; + if ( useVBO ) { + gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, vertexBufferObjects[0]); gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, indexBufferObjects[0]); - vaoBound = true; + + gl2.glEnableClientState(GL2.GL_VERTEX_ARRAY); + // gl2.glVertexPointer(3, GL2.GL_FLOAT, 6 * GLBuffers.SIZEOF_FLOAT, 0); + gl2.glEnableClientState(GL2.GL_NORMAL_ARRAY); + // gl2.glNormalPointer(GL2.GL_FLOAT, 6 * GLBuffers.SIZEOF_FLOAT, 3 * GLBuffers.SIZEOF_FLOAT); + vboBound = true; } + // System.err.println("XXX VBO bound "+vboBound+"[ vbo1 "+isVBO1+", vbo2 "+isVBO2+"]"); - logAnyErrorCodes(gl2, "drawTwoTriangles"); + logAnyErrorCodes(this, gl2, "drawTwoTriangles.2"); - if (vaoBound) { + if (vboBound) { gl2.glColor3f(0f, 0f, 1f); gl2.glDrawElements(GL2.GL_TRIANGLES, 3, GL2.GL_UNSIGNED_INT, 0); - gl2.glBindVertexArray(0); + gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0); gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0); + gl2.glDisableClientState(GL2.GL_VERTEX_ARRAY); + gl2.glDisableClientState(GL2.GL_NORMAL_ARRAY); } + + logAnyErrorCodes(this, gl2, "drawTwoTriangles.3"); } public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { @@ -436,15 +459,24 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { } // inner class TwoTriangles - public static void logAnyErrorCodes(GL2 gl2, String prefix) { - int glError = gl2.glGetError(); - while (glError != GL2.GL_NO_ERROR) { - System.err.println(prefix + ", OpenGL error: 0x" + Integer.toHexString(glError)); - glError = gl2.glGetError(); + private static final Set<String> errorSet = new HashSet<String>(); + + public static void logAnyErrorCodes(Object obj, GL gl, String prefix) { + final int glError = gl.glGetError(); + if(glError != GL.GL_NO_ERROR) { + final String errStr = "GL-Error: "+prefix + " on obj 0x"+Integer.toHexString(obj.hashCode())+", OpenGL error: 0x" + Integer.toHexString(glError); + if( errorSet.add(errStr) ) { + System.err.println(errStr); + Thread.dumpStack(); + } } - int status = gl2.glCheckFramebufferStatus(GL2.GL_FRAMEBUFFER); - if (status != GL2.GL_FRAMEBUFFER_COMPLETE) { - System.err.println(prefix + ", glCheckFramebufferStatus: 0x" + Integer.toHexString(status)); + final int status = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); + if (status != GL.GL_FRAMEBUFFER_COMPLETE) { + final String errStr = "GL-Error: "+prefix + " on obj 0x"+Integer.toHexString(obj.hashCode())+", glCheckFramebufferStatus: 0x" + Integer.toHexString(status); + if( errorSet.add(errStr) ) { + System.err.println(errStr); + Thread.dumpStack(); + } } } @@ -486,22 +518,22 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { } @Test - public void testContextSharingCreateVisibleDestroy1() throws InterruptedException, InvocationTargetException { + public void test01UseAWTNotShared() throws InterruptedException, InvocationTargetException { testContextSharingCreateVisibleDestroy(false, false); } @Test - public void testContextSharingCreateVisibleDestroy2() throws InterruptedException, InvocationTargetException { + public void test02UseAWTSharedContext() throws InterruptedException, InvocationTargetException { testContextSharingCreateVisibleDestroy(false, true); } @Test - public void testContextSharingCreateVisibleDestroy3() throws InterruptedException, InvocationTargetException { + public void test10UseNEWTNotShared() throws InterruptedException, InvocationTargetException { testContextSharingCreateVisibleDestroy(true, false); } @Test - public void testContextSharingCreateVisibleDestroy4() throws InterruptedException, InvocationTargetException { + public void test11UseNEWTSharedContext() throws InterruptedException, InvocationTargetException { testContextSharingCreateVisibleDestroy(true, true); } @@ -522,13 +554,10 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { glCapabilities.setNumSamples(4); final GLOffscreenAutoDrawable sharedDrawable; - final GLContext sharedContext; if(shareContext) { sharedDrawable = initShared(glCapabilities); - sharedContext = sharedDrawable.getContext(); } else { sharedDrawable = null; - sharedContext = null; } final TwoTriangles eventListener1 = new TwoTriangles(640, 480, shareContext); @@ -542,13 +571,16 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { if (useNewt) { GLWindow glWindow1 = GLWindow.create(glCapabilities); if(shareContext) { - glWindow1.setSharedContext(sharedContext); + glWindow1.setSharedAutoDrawable(sharedDrawable); } NewtCanvasAWT newtCanvasAWT1 = new NewtCanvasAWT(glWindow1); newtCanvasAWT1.setPreferredSize(new Dimension(eventListener1.canvasWidth, eventListener1.canvasHeight)); glWindow1.addGLEventListener(eventListener1); // GLWindow glWindow2 = GLWindow.create(glCapabilities); + if(shareContext) { + glWindow2.setSharedAutoDrawable(sharedDrawable); + } NewtCanvasAWT newtCanvasAWT2 = new NewtCanvasAWT(glWindow2); newtCanvasAWT2.setPreferredSize(new Dimension(eventListener2.canvasWidth, eventListener2.canvasHeight)); glWindow2.addGLEventListener(eventListener2); @@ -566,9 +598,9 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { if (shareContext) { canvas1 = new GLCanvas(glCapabilities); - canvas1.setSharedContext(sharedContext); + canvas1.setSharedAutoDrawable(sharedDrawable); canvas2 = new GLCanvas(glCapabilities); - canvas2.setSharedContext(sharedContext); + canvas2.setSharedAutoDrawable(sharedDrawable); } else { canvas1 = new GLCanvas(glCapabilities); canvas2 = new GLCanvas(glCapabilities); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3.java index 5cf2e4b24..3b576fabd 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3.java @@ -50,7 +50,7 @@ import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; /** - * Sharing the VBO of 3 GearsES2 instances, each in their own GLCanvas. + * Sharing the VBO of 3 GearsES2 instances, each in their own AWT GLCanvas. * <p> * This is achieved by using the 1st GLCanvas as the <i>master</i> * and using the build-in blocking mechanism to postpone creation @@ -97,8 +97,7 @@ public class TestSharedContextVBOES2AWT3 extends UITestCase { syncedOneAnimator(true); } - // Don't test erroneous test case ! - // @Test + @Test public void test02SyncedOneAnimatorDirtyDtorOrder() throws InterruptedException, InvocationTargetException { syncedOneAnimator(false); } @@ -182,7 +181,10 @@ public class TestSharedContextVBOES2AWT3 extends UITestCase { } catch(Exception e) { e.printStackTrace(); } + // Stopped animator allows native windowing system 'repaint' event + // to trigger GLAD 'display' animator.stop(); + Assert.assertEquals(false, animator.isAnimating()); if( destroyCleanOrder ) { System.err.println("XXX Destroy in clean order NOW"); @@ -234,13 +236,12 @@ public class TestSharedContextVBOES2AWT3 extends UITestCase { } @Test - public void test11SyncEachAnimatorCleanDtorOrder() throws InterruptedException, InvocationTargetException { + public void test11AsyncEachAnimatorCleanDtorOrder() throws InterruptedException, InvocationTargetException { syncedOneAnimator(true); } - // Don't test erroneous test case ! - // @Test - public void test12SyncEachAnimatorDirtyDtorOrder() throws InterruptedException, InvocationTargetException { + @Test + public void test12AsyncEachAnimatorDirtyDtorOrder() throws InterruptedException, InvocationTargetException { asyncEachOneAnimator(false); } @@ -334,9 +335,14 @@ public class TestSharedContextVBOES2AWT3 extends UITestCase { } catch(Exception e) { e.printStackTrace(); } + // Stopped animator allows native windowing system 'repaint' event + // to trigger GLAD 'display' a1.stop(); + Assert.assertEquals(false, a1.isAnimating()); a2.stop(); + Assert.assertEquals(false, a2.isAnimating()); a3.stop(); + Assert.assertEquals(false, a3.isAnimating()); if( destroyCleanOrder ) { System.err.println("XXX Destroy in clean order NOW"); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3b.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3b.java index 07b9fd4eb..d4079e30c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3b.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2AWT3b.java @@ -50,7 +50,7 @@ import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; /** - * Sharing the VBO of 3 GearsES2 instances, each in their own GLJPanel. + * Sharing the VBO of 3 GearsES2 instances, each in their own AWT GLJPanel. * <p> * This is achieved by using the 1st GLJPanel as the <i>master</i> * and using the build-in blocking mechanism to postpone creation @@ -172,7 +172,10 @@ public class TestSharedContextVBOES2AWT3b extends UITestCase { } catch(Exception e) { e.printStackTrace(); } + // Stopped animator allows native windowing system 'repaint' event + // to trigger GLAD 'display' animator.stop(); + Assert.assertEquals(false, animator.isAnimating()); javax.swing.SwingUtilities.invokeAndWait(new Runnable() { public void run() { @@ -281,9 +284,14 @@ public class TestSharedContextVBOES2AWT3b extends UITestCase { } catch(Exception e) { e.printStackTrace(); } + // Stopped animator allows native windowing system 'repaint' event + // to trigger GLAD 'display' a1.stop(); + Assert.assertEquals(false, a1.isAnimating()); a2.stop(); + Assert.assertEquals(false, a2.isAnimating()); a3.stop(); + Assert.assertEquals(false, a3.isAnimating()); javax.swing.SwingUtilities.invokeAndWait(new Runnable() { public void run() { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT1.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT1.java index 827601869..3cd26028b 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT1.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT1.java @@ -34,11 +34,9 @@ import javax.media.nativewindow.util.InsetsImmutable; 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.GLProfile; -import com.jogamp.opengl.GLAutoDrawableDelegate; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; import com.jogamp.opengl.test.junit.util.MiscUtils; @@ -107,9 +105,7 @@ public class TestSharedContextVBOES2NEWT1 extends UITestCase { glWindow.setVisible(true); sharedDrawable = glWindow; } else { - GLDrawable dummyDrawable = GLDrawableFactory.getFactory(glp).createDummyDrawable(null, true /* createNewDevice */, caps.getGLProfile()); - dummyDrawable.setRealized(true); - sharedDrawable = new GLAutoDrawableDelegate(dummyDrawable, null, null, true /*ownDevice*/, null) { }; + sharedDrawable = GLDrawableFactory.getFactory(glp).createDummyAutoDrawable(null, true /* createNewDevice */, caps.getGLProfile()); } Assert.assertNotNull(sharedDrawable); Assert.assertTrue(AWTRobotUtil.waitForRealized(sharedDrawable, true)); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java index d9fe2a949..e8e4cc739 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java @@ -100,8 +100,7 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase { syncedOneAnimator(true); } - // Don't test erroneous test case ! - // @Test + @Test public void test02SyncedOneAnimatorDirtyDtorOrder() throws InterruptedException { syncedOneAnimator(false); } @@ -215,12 +214,11 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase { } @Test - public void test11ASyncEachAnimatorCleanDtorOrder() throws InterruptedException { + public void test11AsyncEachAnimatorCleanDtorOrder() throws InterruptedException { asyncEachAnimator(true); } - // Don't test erroneous test case ! - // @Test + @Test public void test12AsyncEachAnimatorDirtyDtorOrder() throws InterruptedException { asyncEachAnimator(false); } @@ -310,6 +308,8 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase { } catch(Exception e) { e.printStackTrace(); } + // Stopped animator allows native windowing system 'repaint' event + // to trigger GLAD 'display' a1.stop(); Assert.assertEquals(false, a1.isAnimating()); a2.stop(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT3.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT3.java index adadf85e3..c94ae1140 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT3.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT3.java @@ -97,8 +97,7 @@ public class TestSharedContextVBOES2NEWT3 extends UITestCase { syncedOneAnimator(true); } - // Don't test erroneous test case ! - // @Test + @Test public void test02SyncedOneAnimatorDirtyDtorOrder() throws InterruptedException { syncedOneAnimator(false); } @@ -177,7 +176,10 @@ public class TestSharedContextVBOES2NEWT3 extends UITestCase { } catch(Exception e) { e.printStackTrace(); } + // Stopped animator allows native windowing system 'repaint' event + // to trigger GLAD 'display' animator.stop(); + Assert.assertEquals(false, animator.isAnimating()); if( destroyCleanOrder ) { System.err.println("XXX Destroy in clean order NOW"); @@ -203,8 +205,7 @@ public class TestSharedContextVBOES2NEWT3 extends UITestCase { asyncEachAnimator(true); } - // Don't test erroneous test case ! - // @Test + @Test public void test12AsyncEachAnimatorDirtyDtorOrder() throws InterruptedException { asyncEachAnimator(false); } @@ -289,9 +290,14 @@ public class TestSharedContextVBOES2NEWT3 extends UITestCase { } catch(Exception e) { e.printStackTrace(); } + // Stopped animator allows native windowing system 'repaint' event + // to trigger GLAD 'display' a1.stop(); + Assert.assertEquals(false, a1.isAnimating()); a2.stop(); + Assert.assertEquals(false, a2.isAnimating()); a3.stop(); + Assert.assertEquals(false, a3.isAnimating()); if( destroyCleanOrder ) { System.err.println("XXX Destroy in clean order NOW"); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2SWT3.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2SWT3.java new file mode 100644 index 000000000..9ccfd394f --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2SWT3.java @@ -0,0 +1,375 @@ +/** + * 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.util.List; + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLProfile; + +import com.jogamp.nativewindow.swt.SWTAccessor; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.swt.GLCanvas; +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.jogl.demos.es2.GearsES2; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.junit.After; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +/** + * Sharing the VBO of 3 GearsES2 instances, each in their own SWT GLCanvas. + * <p> + * This is achieved by using the 1st GLCanvas as the <i>master</i> + * and using the build-in blocking mechanism to postpone creation + * of the 2nd and 3rd GLCanvas until the 1st GLCanvas's GLContext becomes created. + * </p> + * <p> + * Above method allows random creation of the 1st GLCanvas <b>in theory</b>, which triggers + * creation of the <i>dependent</i> other GLCanvas sharing it's GLContext.<br> + * However, since this test may perform on the <i>main thread</i> we have + * to initialize all in order, since otherwise the <i>test main thread</i> + * itself blocks SWT GLCanvas creation .. + * </p> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestSharedContextVBOES2SWT3 extends UITestCase { + static GLProfile glp; + static GLCapabilities caps; + static int width, height; + + @BeforeClass + public static void initClass() { + if(GLProfile.isAvailable(GLProfile.GL2ES2)) { + glp = GLProfile.get(GLProfile.GL2ES2); + Assert.assertNotNull(glp); + caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + width = 256; + height = 256; + } else { + setTestSupported(false); + } + } + + Display display = null; + Shell shell1 = null; + Composite composite1 = null; + Shell shell2 = null; + Composite composite2 = null; + Shell shell3 = null; + Composite composite3 = null; + + @Before + public void init() { + SWTAccessor.invoke(true, new Runnable() { + public void run() { + display = new Display(); + Assert.assertNotNull( display ); + }}); + display.syncExec(new Runnable() { + public void run() { + shell1 = new Shell( display ); + shell1.setLayout( new FillLayout() ); + composite1 = new Composite( shell1, SWT.NO_BACKGROUND ); + composite1.setLayout( new FillLayout() ); + + shell2 = new Shell( display ); + shell2.setLayout( new FillLayout() ); + composite2 = new Composite( shell2, SWT.NO_BACKGROUND ); + composite2.setLayout( new FillLayout() ); + + shell3 = new Shell( display ); + shell3.setLayout( new FillLayout() ); + composite3 = new Composite( shell3, SWT.NO_BACKGROUND ); + composite3.setLayout( new FillLayout() ); + }}); + } + + @After + public void release() { + Assert.assertNotNull( display ); + Assert.assertNotNull( shell1 ); + Assert.assertNotNull( composite1 ); + Assert.assertNotNull( shell2 ); + Assert.assertNotNull( composite2 ); + Assert.assertNotNull( shell3 ); + Assert.assertNotNull( composite3 ); + try { + display.syncExec(new Runnable() { + public void run() { + composite3.dispose(); + shell3.dispose(); + composite2.dispose(); + shell2.dispose(); + composite1.dispose(); + shell1.dispose(); + }}); + SWTAccessor.invoke(true, new Runnable() { + public void run() { + display.dispose(); + }}); + } + catch( Throwable throwable ) { + throwable.printStackTrace(); + Assume.assumeNoException( throwable ); + } + display = null; + shell1 = null; + composite1 = null; + shell2 = null; + composite2 = null; + shell3 = null; + composite3 = null; + } + + protected GLCanvas createGLCanvas(final Shell shell, final Composite composite, final int x, final int y, GearsES2 gears) throws InterruptedException { + final GLCanvas glCanvas = GLCanvas.create( composite, 0, caps, null); + Assert.assertNotNull( glCanvas ); + glCanvas.addGLEventListener(gears); + display.syncExec(new Runnable() { + public void run() { + shell.setText("SWT GLCanvas Shared Gears Test"); + shell.setSize( width, height); + shell.setLocation(x, y); + } } ); + return glCanvas; + } + + @Test + public void test01SyncedOneAnimator() throws InterruptedException { + final Animator animator = new Animator(); + final GearsES2 g1 = new GearsES2(0); + final GLCanvas c1 = createGLCanvas(shell1, composite1, 0, 0, g1); + animator.add(c1); + + final GearsES2 g2 = new GearsES2(0); + g2.setSharedGears(g1); + final GLCanvas c2 = createGLCanvas(shell2, composite2, 0+width, 0+0, g2); + c2.setSharedAutoDrawable(c1); + animator.add(c2); + + final GearsES2 g3 = new GearsES2(0); + g3.setSharedGears(g1); + final GLCanvas c3 = createGLCanvas(shell3, composite3, 0, height, g3); + c3.setSharedAutoDrawable(c1); + animator.add(c3); + + display.syncExec(new Runnable() { + public void run() { + shell1.open(); // master .. + shell2.open(); // shall wait until f1 is ready + shell3.open(); // shall wait until f1 is ready + } } ); + animator.start(); // kicks off GLContext .. and hence gears of f2 + f3 completion + + Thread.sleep(1000/60*10); // wait ~10 frames giving a chance to create (blocking until master share is valid) + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c1, true)); + Assert.assertTrue("Gears1 not initialized", g1.waitForInit(true)); + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c2, true)); + Assert.assertTrue("Gears2 not initialized", g2.waitForInit(true)); + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c3, true)); + Assert.assertTrue("Gears3 not initialized", g3.waitForInit(true)); + + final GLContext ctx1 = c1.getContext(); + final GLContext ctx2 = c2.getContext(); + final GLContext ctx3 = c3.getContext(); + { + final List<GLContext> ctx1Shares = ctx1.getCreatedShares(); + final List<GLContext> ctx2Shares = ctx2.getCreatedShares(); + final List<GLContext> ctx3Shares = ctx3.getCreatedShares(); + System.err.println("XXX-C-3.1:"); + MiscUtils.dumpSharedGLContext(ctx1); + System.err.println("XXX-C-3.2:"); + MiscUtils.dumpSharedGLContext(ctx2); + System.err.println("XXX-C-3.3:"); + MiscUtils.dumpSharedGLContext(ctx3); + + Assert.assertTrue("Ctx1 is not shared", ctx1.isShared()); + Assert.assertTrue("Ctx2 is not shared", ctx2.isShared()); + Assert.assertTrue("Ctx3 is not shared", ctx3.isShared()); + Assert.assertEquals("Ctx1 has unexpected number of created shares", 2, ctx1Shares.size()); + Assert.assertEquals("Ctx2 has unexpected number of created shares", 2, ctx2Shares.size()); + Assert.assertEquals("Ctx3 has unexpected number of created shares", 2, ctx3Shares.size()); + } + + Assert.assertTrue("Gears1 is shared", !g1.usesSharedGears()); + Assert.assertTrue("Gears2 is not shared", g2.usesSharedGears()); + Assert.assertTrue("Gears3 is not shared", g3.usesSharedGears()); + + try { + Thread.sleep(duration); + } catch(Exception e) { + e.printStackTrace(); + } + // Stopped animator allows native windowing system 'repaint' event + // to trigger GLAD 'display' + animator.stop(); + Assert.assertEquals(false, animator.isAnimating()); + + display.syncExec(new Runnable() { + public void run() { + c3.dispose(); + c2.dispose(); + c1.dispose(); + } } ); + } + + @Test + public void test02AsyncEachAnimator() throws InterruptedException { + final Animator a1 = new Animator(); + final GearsES2 g1 = new GearsES2(0); + final GLCanvas c1 = createGLCanvas(shell1, composite1, 0, 0, g1); + a1.add(c1); + display.syncExec(new Runnable() { + public void run() { + shell1.open(); + } } ); + a1.start(); + + + Thread.sleep(1000/60*10); // wait ~10 frames giving a chance to create (blocking until master share is valid) + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c1, true)); + Assert.assertTrue("Gears1 not initialized", g1.waitForInit(true)); + + final Animator a2 = new Animator(); + final GearsES2 g2 = new GearsES2(0); + g2.setSharedGears(g1); + final GLCanvas c2 = createGLCanvas(shell2, composite2, width, 0, g2); + c2.setSharedAutoDrawable(c1); + a2.add(c2); + display.syncExec(new Runnable() { + public void run() { + shell2.open(); + } } ); + a2.start(); + + Thread.sleep(200); // wait a while .. + + final Animator a3 = new Animator(); + final GearsES2 g3 = new GearsES2(0); + g3.setSharedGears(g1); + final GLCanvas c3 = createGLCanvas(shell3, composite3, 0, height, g3); + c3.setSharedAutoDrawable(c1); + a3.add(c3); + display.syncExec(new Runnable() { + public void run() { + shell3.open(); + } } ); + a3.start(); + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c2, true)); + Assert.assertTrue("Gears2 not initialized", g2.waitForInit(true)); + + Assert.assertTrue(AWTRobotUtil.waitForContextCreated(c3, true)); + Assert.assertTrue("Gears3 not initialized", g3.waitForInit(true)); + + final GLContext ctx1 = c1.getContext(); + final GLContext ctx2 = c2.getContext(); + final GLContext ctx3 = c3.getContext(); + { + final List<GLContext> ctx1Shares = ctx1.getCreatedShares(); + final List<GLContext> ctx2Shares = ctx2.getCreatedShares(); + final List<GLContext> ctx3Shares = ctx3.getCreatedShares(); + System.err.println("XXX-C-3.1:"); + MiscUtils.dumpSharedGLContext(ctx1); + System.err.println("XXX-C-3.2:"); + MiscUtils.dumpSharedGLContext(ctx2); + System.err.println("XXX-C-3.3:"); + MiscUtils.dumpSharedGLContext(ctx3); + + Assert.assertTrue("Ctx1 is not shared", ctx1.isShared()); + Assert.assertTrue("Ctx2 is not shared", ctx2.isShared()); + Assert.assertTrue("Ctx3 is not shared", ctx3.isShared()); + Assert.assertEquals("Ctx1 has unexpected number of created shares", 2, ctx1Shares.size()); + Assert.assertEquals("Ctx2 has unexpected number of created shares", 2, ctx2Shares.size()); + Assert.assertEquals("Ctx3 has unexpected number of created shares", 2, ctx3Shares.size()); + } + + Assert.assertTrue("Gears1 is shared", !g1.usesSharedGears()); + Assert.assertTrue("Gears2 is not shared", g2.usesSharedGears()); + Assert.assertTrue("Gears3 is not shared", g3.usesSharedGears()); + + try { + Thread.sleep(duration); + } catch(Exception e) { + e.printStackTrace(); + } + // Stopped animator allows native windowing system 'repaint' event + // to trigger GLAD 'display' + a1.stop(); + Assert.assertEquals(false, a1.isAnimating()); + a2.stop(); + Assert.assertEquals(false, a2.isAnimating()); + a3.stop(); + Assert.assertEquals(false, a3.isAnimating()); + + display.syncExec(new Runnable() { + public void run() { + c3.dispose(); + c2.dispose(); + c1.dispose(); + } } ); + } + + static long duration = 1000; // 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(); } + } + } + /** + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + System.err.println("Press enter to continue"); + System.err.println(stdin.readLine()); */ + org.junit.runner.JUnitCore.main(TestSharedContextVBOES2SWT3.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/GearsObject.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/GearsObject.java index 7adcce2ae..4d5d69539 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/GearsObject.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/GearsObject.java @@ -23,6 +23,7 @@ package com.jogamp.opengl.test.junit.jogl.demos; import java.nio.FloatBuffer; import javax.media.opengl.GL; +import javax.media.opengl.GL2ES2; import com.jogamp.common.nio.Buffers; import com.jogamp.opengl.util.GLArrayDataServer; @@ -46,11 +47,32 @@ public abstract class GearsObject { public GLArrayDataServer insideRadiusCyl; public boolean isShared; - public abstract GLArrayDataServer createInterleaveClone(GLArrayDataServer ads); public abstract GLArrayDataServer createInterleaved(int comps, int dataType, boolean normalized, int initialSize, int vboUsage); public abstract void addInterleavedVertexAndNormalArrays(GLArrayDataServer array, int components); public abstract void draw(GL gl, float x, float y, float angle); + private GLArrayDataServer createInterleavedClone(GLArrayDataServer ads) { + final GLArrayDataServer n = new GLArrayDataServer(ads); + n.setInterleavedOffset(0); + return n; + } + + private void init(GL2ES2 gl, GLArrayDataServer array) { + array.enableBuffer(gl, true); + array.enableBuffer(gl, false); + } + + /** Init VBO and data .. */ + public final void init(GL _gl) { + final GL2ES2 gl = _gl.getGL2ES2(); + init(gl, frontFace); + init(gl, frontSide); + init(gl, backFace); + init(gl, backSide); + init(gl, outwardFace); + init(gl, insideRadiusCyl); + } + public void destroy(GL gl) { if(!isShared) { // could be already destroyed by shared configuration @@ -84,17 +106,17 @@ public abstract class GearsObject { public GearsObject ( GearsObject shared ) { isShared = true; - frontFace = createInterleaveClone(shared.frontFace); + frontFace = createInterleavedClone(shared.frontFace); addInterleavedVertexAndNormalArrays(frontFace, 3); - backFace = createInterleaveClone(shared.backFace); + backFace = createInterleavedClone(shared.backFace); addInterleavedVertexAndNormalArrays(backFace, 3); - frontSide = createInterleaveClone(shared.frontSide); + frontSide = createInterleavedClone(shared.frontSide); addInterleavedVertexAndNormalArrays(frontSide, 3); - backSide= createInterleaveClone(shared.backSide); + backSide= createInterleavedClone(shared.backSide); addInterleavedVertexAndNormalArrays(backSide, 3); - outwardFace = createInterleaveClone(shared.outwardFace); + outwardFace = createInterleavedClone(shared.outwardFace); addInterleavedVertexAndNormalArrays(outwardFace, 3); - insideRadiusCyl = createInterleaveClone(shared.insideRadiusCyl); + insideRadiusCyl = createInterleavedClone(shared.insideRadiusCyl); addInterleavedVertexAndNormalArrays(insideRadiusCyl, 3); gearColor = shared.gearColor; } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java index db1f217ba..9f191d3b6 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java @@ -162,6 +162,7 @@ public class GearsES1 implements GLEventListener { /* make the gears */ if(null == gear1) { gear1 = new GearsObjectES1(gear1Color, 1.0f, 4.0f, 1.0f, 20, 0.7f); + gear1.init(gl); System.err.println("gear1 created: "+gear1); } else { usesSharedGears = true; @@ -170,6 +171,7 @@ public class GearsES1 implements GLEventListener { if(null == gear2) { gear2 = new GearsObjectES1(gear2Color, 0.5f, 2.0f, 2.0f, 10, 0.7f); + gear2.init(gl); System.err.println("gear2 created: "+gear2); } else { usesSharedGears = true; @@ -178,6 +180,7 @@ public class GearsES1 implements GLEventListener { if(null == gear3) { gear3 = new GearsObjectES1(gear3Color, 1.3f, 2.0f, 0.5f, 10, 0.7f); + gear3.init(gl); System.err.println("gear3 created: "+gear3); } else { usesSharedGears = true; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsObjectES1.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsObjectES1.java index 6c9587931..fb9251e75 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsObjectES1.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsObjectES1.java @@ -41,21 +41,6 @@ public class GearsObjectES1 extends GearsObject { } @Override - public GLArrayDataServer createInterleaveClone(GLArrayDataServer ads) { - final FloatBuffer fb0 = (FloatBuffer) ads.getBuffer(); - final FloatBuffer fb1 = fb0.slice(); - // manual 'unseal' - fb1.position(fb1.limit()); - fb1.limit(fb1.capacity()); - - final GLArrayDataServer adsClone = GLArrayDataServer.createFixedInterleaved(ads.getComponentCount(), ads.getComponentType(), ads.getNormalized(), - ads.getStride(), fb1, ads.getVBOUsage()); - adsClone.setVBOName(ads.getVBOName()); - adsClone.seal(true); - return adsClone; - } - - @Override public GLArrayDataServer createInterleaved(int comps, int dataType, boolean normalized, int initialSize, int vboUsage) { return GLArrayDataServer.createFixedInterleaved(comps, dataType, normalized, initialSize, vboUsage); } @@ -67,9 +52,11 @@ public class GearsObjectES1 extends GearsObject { } private void draw(GL2ES1 gl, GLArrayDataServer array, int mode) { - array.enableBuffer(gl, true); - gl.glDrawArrays(mode, 0, array.getElementCount()); - array.enableBuffer(gl, false); + if( !isShared || gl.glIsBuffer(array.getVBOName()) ) { + array.enableBuffer(gl, true); + gl.glDrawArrays(mode, 0, array.getElementCount()); + array.enableBuffer(gl, false); + } } @Override 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 60242d604..be7fcee07 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 @@ -45,7 +45,6 @@ import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; import javax.media.opengl.GLAnimatorControl; import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLContext; import javax.media.opengl.GLEventListener; import javax.media.opengl.GLProfile; import javax.media.opengl.GLUniformData; @@ -109,11 +108,11 @@ public class GearsES2 implements GLEventListener, TileRendererBase.TileRendererL } @Override public void startTileRendering(TileRendererBase tr) { - System.err.println("GearsES2.startTileRendering: "+tr); + System.err.println("GearsES2.startTileRendering: "+sid()+""+tr); } @Override public void endTileRendering(TileRendererBase tr) { - System.err.println("GearsES2.endTileRendering: "+tr); + System.err.println("GearsES2.endTileRendering: "+sid()+""+tr); } public void setIgnoreFocus(boolean v) { ignoreFocus = v; } @@ -178,18 +177,20 @@ public class GearsES2 implements GLEventListener, TileRendererBase.TileRendererL return wait<POLL_DIVIDER; } + private final String sid() { return "0x"+Integer.toHexString(hashCode()); } + @Override public void init(GLAutoDrawable drawable) { - if(null != sharedGears && sharedGears.getGear1() == null ) { - System.err.println(Thread.currentThread()+" GearsES2.init: pending shared Gears .. re-init later XXXXX"); + if(null != sharedGears && !sharedGears.isInit() ) { + System.err.println(Thread.currentThread()+" GearsES2.init "+sid()+": pending shared Gears .. re-init later XXXXX"); drawable.setGLEventListenerInitState(this, false); return; } - System.err.println(Thread.currentThread()+" GearsES2.init: tileRendererInUse "+tileRendererInUse); + System.err.println(Thread.currentThread()+" GearsES2.init "+sid()+": tileRendererInUse "+tileRendererInUse); final GL2ES2 gl = drawable.getGL().getGL2ES2(); if(verbose) { - System.err.println("GearsES2 init on "+Thread.currentThread()); + System.err.println("GearsES2 init "+sid()+" on "+Thread.currentThread()); System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities()); System.err.println("INIT GL IS: " + gl.getClass().getName()); System.err.println(JoglVersion.getGLStrings(gl, null, false).toString()); @@ -236,49 +237,53 @@ public class GearsES2 implements GLEventListener, TileRendererBase.TileRendererL gear3 = new GearsObjectES2(sharedGears.getGear3(), st, pmvMatrix, pmvMatrixUniform, colorU); usesSharedGears = true; if(verbose) { - System.err.println("gear1 created w/ share: "+sharedGears.getGear1()+" -> "+gear1); - System.err.println("gear2 created w/ share: "+sharedGears.getGear2()+" -> "+gear2); - System.err.println("gear3 created w/ share: "+sharedGears.getGear3()+" -> "+gear3); + System.err.println("gear1 "+sid()+" created w/ share: "+sharedGears.getGear1()+" -> "+gear1); + System.err.println("gear2 "+sid()+" created w/ share: "+sharedGears.getGear2()+" -> "+gear2); + System.err.println("gear3 "+sid()+" created w/ share: "+sharedGears.getGear3()+" -> "+gear3); } } else { if(null == gear1) { gear1 = new GearsObjectES2(st, gear1Color, 1.0f, 4.0f, 1.0f, 20, 0.7f, pmvMatrix, pmvMatrixUniform, colorU); + gear1.init(gl); if(verbose) { - System.err.println("gear1 created: "+gear1); + System.err.println("gear1 "+sid()+" created: "+gear1); } } else { final GearsObjectES2 _gear1 = gear1; gear1 = new GearsObjectES2(_gear1, st, pmvMatrix, pmvMatrixUniform, colorU); usesSharedGears = true; if(verbose) { - System.err.println("gear1 created w/ share: "+_gear1+" -> "+gear1); + System.err.println("gear1 "+sid()+" created w/ share: "+_gear1+" -> "+gear1); } } if(null == gear2) { gear2 = new GearsObjectES2(st, gear2Color, 0.5f, 2.0f, 2.0f, 10, 0.7f, pmvMatrix, pmvMatrixUniform, colorU); + gear2.init(gl); if(verbose) { - System.err.println("gear2 created: "+gear2); + System.err.println("gear2 "+sid()+" created: "+gear2); } } else { final GearsObjectES2 _gear2 = gear2; gear2 = new GearsObjectES2(_gear2, st, pmvMatrix, pmvMatrixUniform, colorU); usesSharedGears = true; if(verbose) { - System.err.println("gear2 created w/ share: "+_gear2+" -> "+gear2); + System.err.println("gear2 "+sid()+" created w/ share: "+_gear2+" -> "+gear2); } } if(null == gear3) { gear3 = new GearsObjectES2(st, gear3Color, 1.3f, 2.0f, 0.5f, 10, 0.7f, pmvMatrix, pmvMatrixUniform, colorU); + gear3.init(gl); if(verbose) { + System.err.println("gear3 "+sid()+" created: "+gear2); } } else { final GearsObjectES2 _gear3 = gear3; gear3 = new GearsObjectES2(_gear3, st, pmvMatrix, pmvMatrixUniform, colorU); usesSharedGears = true; if(verbose) { - System.err.println("gear3 created w/ share: "+_gear3+" -> "+gear3); + System.err.println("gear3 "+sid()+" created w/ share: "+_gear3+" -> "+gear3); } } } @@ -299,10 +304,14 @@ public class GearsES2 implements GLEventListener, TileRendererBase.TileRendererL st.useProgram(gl, false); - System.err.println(Thread.currentThread()+" GearsES2.init FIN"); + gl.glFinish(); // make sure .. for shared context (impacts OSX 10.9) + + System.err.println(Thread.currentThread()+" GearsES2.init "+sid()+" FIN "+this); isInit = true; } + public final boolean isInit() { return isInit; } + private final GestureHandler.GestureListener pinchToZoomListener = new GestureHandler.GestureListener() { @Override public void gestureDetected(GestureEvent gh) { @@ -334,7 +343,7 @@ public class GearsES2 implements GLEventListener, TileRendererBase.TileRendererL void reshapeImpl(GL2ES2 gl, int tileX, int tileY, int tileWidth, int tileHeight, int imageWidth, int imageHeight) { final boolean msaa = gl.getContext().getGLDrawable().getChosenGLCapabilities().getSampleBuffers(); - System.err.println(Thread.currentThread()+" GearsES2.reshape "+tileX+"/"+tileY+" "+tileWidth+"x"+tileHeight+" of "+imageWidth+"x"+imageHeight+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(gl.getContext().getGLDrawable().getHandle())+", msaa "+msaa+", tileRendererInUse "+tileRendererInUse); + System.err.println(Thread.currentThread()+" GearsES2.reshape "+sid()+" "+tileX+"/"+tileY+" "+tileWidth+"x"+tileHeight+" of "+imageWidth+"x"+imageHeight+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(gl.getContext().getGLDrawable().getHandle())+", msaa "+msaa+", tileRendererInUse "+tileRendererInUse); if( !gl.hasGLSL() ) { return; @@ -371,7 +380,7 @@ public class GearsES2 implements GLEventListener, TileRendererBase.TileRendererL final float _w = r - l; final float _h = t - b; if(verbose) { - System.err.println(">> angle "+angle+", [l "+left+", r "+right+", b "+bottom+", t "+top+"] "+w+"x"+h+" -> [l "+l+", r "+r+", b "+b+", t "+t+"] "+_w+"x"+_h); + System.err.println(">> angle "+sid()+" "+angle+", [l "+left+", r "+right+", b "+bottom+", t "+top+"] "+w+"x"+h+" -> [l "+l+", r "+r+", b "+b+", t "+t+"] "+_w+"x"+_h); } pmvMatrix.glFrustumf(l, r, b, t, 5.0f, 200.0f); @@ -390,7 +399,7 @@ public class GearsES2 implements GLEventListener, TileRendererBase.TileRendererL public void dispose(GLAutoDrawable drawable) { if( !isInit ) { return; } isInit = false; - System.err.println(Thread.currentThread()+" GearsES2.dispose: tileRendererInUse "+tileRendererInUse); + System.err.println(Thread.currentThread()+" GearsES2.dispose "+sid()+": tileRendererInUse "+tileRendererInUse); final Object upstreamWidget = drawable.getUpstreamWidget(); if (upstreamWidget instanceof Window) { final Window window = (Window) upstreamWidget; @@ -416,15 +425,16 @@ public class GearsES2 implements GLEventListener, TileRendererBase.TileRendererL st.destroy(gl); st = null; - System.err.println(Thread.currentThread()+" GearsES2.dispose FIN"); + System.err.println(Thread.currentThread()+" GearsES2.dispose "+sid()+" FIN"); } @Override public void display(GLAutoDrawable drawable) { if( !isInit ) { return; } + if(null != sharedGears && !sharedGears.isInit() ) { return; } GLAnimatorControl anim = drawable.getAnimator(); if( verbose && ( null == anim || !anim.isAnimating() ) ) { - System.err.println(Thread.currentThread()+" GearsES2.display "+drawable.getWidth()+"x"+drawable.getHeight()+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(drawable.getHandle())); + System.err.println(Thread.currentThread()+" GearsES2.display "+sid()+" "+drawable.getWidth()+"x"+drawable.getHeight()+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(drawable.getHandle())); } // Turn the gears' teeth if(doRotate) { @@ -485,6 +495,11 @@ public class GearsES2 implements GLEventListener, TileRendererBase.TileRendererL gl.glDisable(GL.GL_CULL_FACE); } + @Override + public String toString() { + return "GearsES2[obj "+sid()+" 1 "+gear1+", 2 "+gear2+", 3 "+gear3+"]"; + } + boolean confinedFixedCenter = false; public void setConfinedFixedCenter(boolean v) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsObjectES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsObjectES2.java index 89006d28c..f3367ad1c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsObjectES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsObjectES2.java @@ -78,21 +78,6 @@ public class GearsObjectES2 extends GearsObject { } @Override - public GLArrayDataServer createInterleaveClone(GLArrayDataServer ads) { - final FloatBuffer fb0 = (FloatBuffer) ads.getBuffer(); - final FloatBuffer fb1 = fb0.slice(); - // manual 'unseal' - fb1.position(fb1.limit()); - fb1.limit(fb1.capacity()); - - final GLArrayDataServer adsClone = GLArrayDataServer.createGLSLInterleaved(ads.getComponentCount(), ads.getComponentType(), ads.getNormalized(), - ads.getStride(), fb1, ads.getVBOUsage()); - adsClone.setVBOName(ads.getVBOName()); - adsClone.seal(true); - return adsClone; - } - - @Override public GLArrayDataServer createInterleaved(int comps, int dataType, boolean normalized, int initialSize, int vboUsage) { return GLArrayDataServer.createGLSLInterleaved(comps, dataType, normalized, initialSize, vboUsage); } @@ -104,10 +89,12 @@ public class GearsObjectES2 extends GearsObject { } private void draw(GL2ES2 gl, GLArrayDataServer array, int mode, int face) { - array.enableBuffer(gl, true); - // System.err.println("XXX Draw face "+face+" of "+this); - gl.glDrawArrays(mode, 0, array.getElementCount()); - array.enableBuffer(gl, false); + if( !isShared || gl.glIsBuffer(array.getVBOName()) ) { + array.enableBuffer(gl, true); + // System.err.println("XXX Draw face "+face+" of "+this); + gl.glDrawArrays(mode, 0, array.getElementCount()); + array.enableBuffer(gl, false); + } } @Override diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/swt/TestGearsES2SWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/swt/TestGearsES2SWT.java index df7a25448..b6463ac0f 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/swt/TestGearsES2SWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/swt/TestGearsES2SWT.java @@ -3,14 +3,14 @@ * * 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 @@ -20,12 +20,12 @@ * 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.demos.es2.swt; import java.io.IOException; @@ -65,7 +65,7 @@ import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class TestGearsES2SWT extends UITestCase { +public class TestGearsES2SWT extends UITestCase { static int screenIdx = 0; static PointImmutable wpos; static DimensionImmutable wsize, rwsize=null; @@ -83,7 +83,7 @@ public class TestGearsES2SWT extends UITestCase { static boolean forceGL3 = false; static boolean mainRun = false; static boolean exclusiveContext = false; - + @BeforeClass public static void initClass() { if(null == wsize) { @@ -98,16 +98,16 @@ public class TestGearsES2SWT extends UITestCase { Display display = null; Shell shell = null; Composite composite = null; - + @Before public void init() { SWTAccessor.invoke(true, new Runnable() { - public void run() { + public void run() { display = new Display(); Assert.assertNotNull( display ); }}); display.syncExec(new Runnable() { - public void run() { + public void run() { shell = new Shell( display ); Assert.assertNotNull( shell ); shell.setLayout( new FillLayout() ); @@ -141,21 +141,21 @@ public class TestGearsES2SWT extends UITestCase { shell = null; composite = null; } - + protected void runTestGL(GLCapabilitiesImmutable caps) throws InterruptedException, InvocationTargetException { System.err.println("requested: vsync "+swapInterval+", "+caps); - - final GLCanvas canvas = GLCanvas.create( composite, 0, caps, null, null); + + final GLCanvas canvas = GLCanvas.create( composite, 0, caps, null); Assert.assertNotNull( canvas ); - + final GearsES2 demo = new GearsES2(swapInterval); demo.setPMVUseBackingArray(pmvUseBackingArray); canvas.addGLEventListener(demo); - + Animator animator = new Animator(); animator.setModeBits(false, Animator.MODE_EXPECT_AWT_RENDERING_THREAD); animator.setExclusiveContext(exclusiveContext); - + animator.add(canvas); animator.start(); Assert.assertTrue(animator.isStarted()); @@ -172,9 +172,9 @@ public class TestGearsES2SWT extends UITestCase { shell.open(); } }); - + animator.setUpdateFPSFrames(60, showFPS ? System.err : null); - + while(animator.isAnimating() && !canvas.isRealized() && animator.getTotalFPSDuration()<duration) { if( !display.readAndDispatch() ) { // blocks on linux .. display.sleep(); @@ -184,7 +184,7 @@ public class TestGearsES2SWT extends UITestCase { System.err.println("NW chosen: "+canvas.getDelegatedDrawable().getChosenGLCapabilities()); System.err.println("GL chosen: "+canvas.getChosenGLCapabilities()); System.err.println("window pos/siz: "+canvas.getLocation()+" "+canvas.getWidth()+"x"+canvas.getHeight()); - + if( null != rwsize ) { for(int i=0; i<50; i++) { // 500 ms dispatched delay if( !display.readAndDispatch() ) { @@ -199,7 +199,7 @@ public class TestGearsES2SWT extends UITestCase { }); System.err.println("window resize pos/siz: "+canvas.getLocation()+" "+canvas.getWidth()+"x"+canvas.getHeight()); } - + while(animator.isAnimating() && animator.getTotalFPSDuration()<duration) { if( !display.readAndDispatch() ) { // blocks on linux .. display.sleep(); @@ -212,7 +212,7 @@ public class TestGearsES2SWT extends UITestCase { Assert.assertFalse(animator.isAnimating()); Assert.assertFalse(animator.isStarted()); Assert.assertEquals(null, canvas.getExclusiveContextThread()); - + display.syncExec(new Runnable() { public void run() { canvas.dispose(); @@ -234,7 +234,7 @@ public class TestGearsES2SWT extends UITestCase { final GLCapabilities caps = new GLCapabilities( glp ); caps.setBackgroundOpaque(opaque); if(-1 < forceAlpha) { - caps.setAlphaBits(forceAlpha); + caps.setAlphaBits(forceAlpha); } runTestGL(caps); if(loop_shutdown) { @@ -246,7 +246,7 @@ public class TestGearsES2SWT extends UITestCase { @Test public void test02GL3() throws InterruptedException, InvocationTargetException { if(mainRun) return; - + if( !GLProfile.isAvailable(GLProfile.GL3) ) { System.err.println("GL3 n/a"); return; @@ -255,13 +255,13 @@ public class TestGearsES2SWT extends UITestCase { final GLCapabilities caps = new GLCapabilities( glp ); runTestGL(caps); } - + public static void main(String args[]) throws IOException { mainRun = true; - + int x=0, y=0, w=640, h=480, rw=-1, rh=-1; boolean usePos = false; - + for(int i=0; i<args.length; i++) { if(args[i].equals("-time")) { i++; @@ -320,7 +320,7 @@ public class TestGearsES2SWT extends UITestCase { if( 0 < rw && 0 < rh ) { rwsize = new Dimension(rw, rh); } - + if(usePos) { wpos = new Point(x, y); } @@ -329,9 +329,9 @@ public class TestGearsES2SWT extends UITestCase { System.err.println("resize "+rwsize); System.err.println("screen "+screenIdx); System.err.println("translucent "+(!opaque)); - System.err.println("forceAlpha "+forceAlpha); + System.err.println("forceAlpha "+forceAlpha); System.err.println("fullscreen "+fullscreen); - System.err.println("pmvDirect "+(!pmvUseBackingArray)); + System.err.println("pmvDirect "+(!pmvUseBackingArray)); System.err.println("loops "+loops); System.err.println("loop shutdown "+loop_shutdown); System.err.println("forceES2 "+forceES2); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java index 8b4e095f3..fd6d370ac 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java @@ -227,7 +227,7 @@ public class TestSWTBug643AsyncExec extends UITestCase { final GLAutoDrawable glad; if( useJOGLGLCanvas ) { final GearsES2 demo = new GearsES2(); - final GLCanvas glc = GLCanvas.create(dsc.composite, 0, caps, null, null); + final GLCanvas glc = GLCanvas.create(dsc.composite, 0, caps, null); final SWTNewtEventFactory swtNewtEventFactory = new SWTNewtEventFactory(); swtNewtEventFactory.attachDispatchListener(glc, glc, demo.gearsMouse, demo.gearsKeys); glc.addGLEventListener( demo ) ; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java index a1d8d40c2..b38bf0c2c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java @@ -3,14 +3,14 @@ * * 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 @@ -20,12 +20,12 @@ * 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.swt; import javax.media.opengl.GLAutoDrawable; @@ -60,13 +60,13 @@ import com.jogamp.opengl.util.texture.TextureIO; /** * Tests that a basic SWT app can open without crashing under different GL profiles. - * <p> + * <p> * Uses JOGL's new SWT GLCanvas, * which allows utilizing custom GLCapability settings, * independent from the already instantiated SWT visual. * </p> * <p> - * Note that {@link SWTAccessor#invoke(boolean, Runnable)} is still used to comply w/ + * Note that {@link SWTAccessor#invoke(boolean, Runnable)} is still used to comply w/ * SWT running on Mac OSX, i.e. to enforce UI action on the main thread. * </p> * @author Wade Walker, et al. @@ -76,7 +76,7 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { static int duration = 250; static boolean doAnimation = true; - + static final int iwidth = 640; static final int iheight = 480; @@ -92,12 +92,12 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { @Before public void init() { SWTAccessor.invoke(true, new Runnable() { - public void run() { + public void run() { display = new Display(); Assert.assertNotNull( display ); }}); display.syncExec(new Runnable() { - public void run() { + public void run() { shell = new Shell( display ); Assert.assertNotNull( shell ); shell.setLayout( new FillLayout() ); @@ -134,14 +134,14 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { protected void runTestAGL( GLCapabilitiesImmutable caps, GLEventListener demo ) throws InterruptedException { final GLReadBufferUtil screenshot = new GLReadBufferUtil(false, false); - - final GLCanvas canvas = GLCanvas.create( composite, 0, caps, null, null); + + final GLCanvas canvas = GLCanvas.create( composite, 0, caps, null); Assert.assertNotNull( canvas ); canvas.addGLEventListener( demo ); canvas.addGLEventListener(new GLEventListener() { int displayCount = 0; - public void init(final GLAutoDrawable drawable) { } + public void init(final GLAutoDrawable drawable) { } public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { } public void display(final GLAutoDrawable drawable) { if(displayCount < 3) { @@ -149,21 +149,21 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { } } public void dispose(final GLAutoDrawable drawable) { } - }); - + }); + display.syncExec(new Runnable() { public void run() { shell.setText( getSimpleTestName(".") ); shell.setSize( 640, 480 ); shell.open(); } } ); - + Animator anim = new Animator(); if(doAnimation) { anim.add(canvas); anim.start(); - } - + } + long lStartTime = System.currentTimeMillis(); long lEndTime = lStartTime + duration; try { @@ -177,9 +177,9 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { throwable.printStackTrace(); Assume.assumeNoException( throwable ); } - + anim.stop(); - + display.syncExec(new Runnable() { public void run() { canvas.dispose(); @@ -198,7 +198,7 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { caps.setNumSamples(2); runTestAGL( caps, new MultisampleDemoES2(true) ); } - + static int atoi(String a) { int i=0; try { |