From c7ac21e7d25e5271f600806c93e3bd870d45bce3 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 8 Oct 2014 08:16:10 +0200 Subject: Bug 1088: Add GLRendererQuirks.NeedSharedObjectSync; Tests: Synchronize GL objects if GLRendererQuirks.NeedSharedObjectSync is set. GLSharedContextSetter#synchronization GL Object Synchronization Usually synchronization of shared GL objects should not be required, if the shared GL objects are created and immutable before concurrent usage. However, using drivers exposing GLRendererQuirks.NeedSharedObjectSync always require the user to synchronize access of shared GL objects. Synchronization can be avoided if accessing the shared GL objects exclusively via a queue or com.jogamp.common.util.Ringbuffer, see GLMediaPlayerImpl as an example. +++ GLRendererQuirks.NeedSharedObjectSync is set for all OSX versions +++ Handle GLRendererQuirks.NeedSharedObjectSync in user code! +++ All shared context tests passed on OSX 10.9.5, and GNU/Linux w/ Nvidia + Mesa/AMD driver. Conflicts: src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java --- make/scripts/tests.sh | 10 ++-- .../com/jogamp/opengl/GLRendererQuirks.java | 37 ++++++++++++++- .../javax/media/opengl/GLSharedContextSetter.java | 16 +++++++ src/jogl/classes/jogamp/opengl/GLContextImpl.java | 7 +++ .../jogl/acore/TestSharedContextVBOES2NEWT2.java | 12 +++-- .../jogl/acore/TestSharedContextVBOES2NEWT3.java | 7 ++- .../opengl/test/junit/jogl/demos/es1/GearsES1.java | 21 +++++++-- .../opengl/test/junit/jogl/demos/es2/GearsES2.java | 25 ++++++++-- .../opengl/test/junit/jogl/demos/gl2/Gears.java | 55 ++++++++++++++-------- 9 files changed, 154 insertions(+), 36 deletions(-) diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 2d05c2110..0d8fe8d4f 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -88,7 +88,7 @@ function jrun() { swton=$1 shift - #D_ARGS="-Djogl.debug.DebugGL" + D_ARGS="-Djogl.debug.DebugGL" #D_ARGS="-Djogl.debug.TraceGL" #D_ARGS="-Djogl.debug.DebugGL -Djogl.debug.TraceGL" #D_ARGS="-Djogl.debug.DebugGL -Djogl.debug.TraceGL -Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all" @@ -96,6 +96,7 @@ function jrun() { #D_ARGS="-Djogamp.debug=all" #D_ARGS="-Dnativewindow.debug=all" #D_ARGS="-Djogl.debug=all" + #D_ARGS="-Djogl.debug=all -Dnewt.debug=all -Djogl.debug.DebugGL" #D_ARGS="-Dnewt.debug=all" #D_ARGS="-Djogl.debug=all -Dnewt.debug=all" #D_ARGS="-Djogl.debug=all -Dnativewindow.debug=all" @@ -381,7 +382,7 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestMainVersionGLWindowNEWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestMainVersionGLCanvasAWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile00NEWT $* -testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestVersionSemanticsNOUI $* # @@ -502,8 +503,11 @@ testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $* #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.TestSharedContextVBOES2NEWT0 $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT1 $* +testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT1 $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT2 $* + +#testnoawt com.jogamp.opengl.test.junit.graph.demos.GPUUISceneNewtDemo $* + #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT3 $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT4 $* #testswt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2SWT3 $* diff --git a/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java b/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java index 828aca78c..a7749e100 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java +++ b/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java @@ -363,11 +363,43 @@ public class GLRendererQuirks { */ public static final int NoPBufferWithAccum = 19; + /** + * Need GL objects (VBO, ..) to be synchronized when utilized + * concurrently from multiple threads via a shared GL context, + * otherwise driver crashes the VM. + *

+ * Usually synchronization should not be required, if the shared GL objects + * are created and immutable before concurrent usage.
+ * However, using drivers exposing this issue always require the user to + * synchronize access of shared GL objects. + *

+ *

+ * Synchronization can be avoided if accessing the shared GL objects + * exclusively via a queue or {@link com.jogamp.common.util.Ringbuffer Ringbuffer}, see GLMediaPlayerImpl as an example. + *

+ *

+ * Appears on: + *

+ *

+ *

+ * See Bug 1088 - https://jogamp.org/bugzilla/show_bug.cgi?id=1088 + *

+ */ + public static final int NeedSharedObjectSync = 20; + /** @deprecated Use {@link #getCount()}, this value is no more valid! */ public static final int COUNT = 18; /** Return the number of known quirks. */ - public static final int getCount() { return 20; } + public static final int getCount() { return 21; } private static final String[] _names = new String[] { "NoDoubleBufferedPBuffer", "NoDoubleBufferedBitmap", "NoSetSwapInterval", "NoOffscreenBitmap", "NoSetSwapIntervalPostRetarget", "GLSLBuggyDiscard", @@ -375,7 +407,8 @@ public class GLRendererQuirks { "NeedCurrCtx4ARBPixFmtQueries", "NeedCurrCtx4ARBCreateContext", "NoFullFBOSupport", "GLSLNonCompliant", "GL4NeedsGL3Request", "GLSharedContextBuggy", "GLES3ViaEGLES2Config", "SingletonEGLDisplayOnly", - "NoMultiSamplingBuffers", "BuggyColorRenderbuffer", "NoPBufferWithAccum" + "NoMultiSamplingBuffers", "BuggyColorRenderbuffer", "NoPBufferWithAccum", + "NeedSharedObjectSync" }; private static final IdentityHashMap stickyDeviceQuirks = new IdentityHashMap(); diff --git a/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java b/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java index 526967d69..b8aef126b 100644 --- a/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java +++ b/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java @@ -28,6 +28,8 @@ package javax.media.opengl; +import com.jogamp.opengl.GLRendererQuirks; + /** * Adds capabilities to set a shared {@link GLContext} directly or via an {@link GLAutoDrawable}. *

@@ -88,6 +90,20 @@ package javax.media.opengl; glad.setVisible(true); // GLWindow creation .. * *

+ *
GL Object Synchronization
+ *

+ * Usually synchronization of shared GL objects should not be required, if the shared GL objects + * are created and immutable before concurrent usage. + *

+ *

+ * However, using drivers exposing {@link GLRendererQuirks#NeedSharedObjectSync} always + * require the user to synchronize access of shared GL objects. + *

+ *

+ * Synchronization can be avoided if accessing the shared GL objects + * exclusively via a queue or {@link com.jogamp.common.util.Ringbuffer Ringbuffer}, see GLMediaPlayerImpl as an example. + *

+ *

*
Known Driver Issues
* Intel's Mesa >= 9.1.2 Backend for [Sandybridge/Ivybridge] on GNU/Linux *

diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index bc8d3b7e4..45a4f2426 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -1785,6 +1785,13 @@ public abstract class GLContextImpl extends GLContext { } quirks.addQuirk( quirk ); } + { + final int quirk = GLRendererQuirks.NeedSharedObjectSync; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()); + } + quirks.addQuirk( quirk ); + } if( Platform.getOSVersionNumber().compareTo(Platform.OSXVersion.Mavericks) >= 0 && 3==reqMajor && 4==major ) { final int quirk = GLRendererQuirks.GL4NeedsGL3Request; if(DEBUG) { 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 a66aaf9d8..8d040222a 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 @@ -107,12 +107,13 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase { animator.start(); final GearsES2 g1 = new GearsES2(0); + g1.setSyncObjects(g1); // this is master, since rendered we must use it as sync final GLWindow f1 = createGLWindow(0, 0, g1); animator.add(f1); final InsetsImmutable insets = f1.getInsets(); final GearsES2 g2 = new GearsES2(0); - g2.setSharedGears(g1); + g2.setSharedGears(g1); // also uses master g1 as sync, if required final GLWindow f2 = createGLWindow(f1.getX()+width+insets.getTotalWidth(), f1.getY()+0, g2); f2.setSharedAutoDrawable(f1); @@ -120,7 +121,7 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase { f2.setVisible(true); final GearsES2 g3 = new GearsES2(0); - g3.setSharedGears(g1); + g3.setSharedGears(g1); // also uses master g1 as sync, if required final GLWindow f3 = createGLWindow(f1.getX()+0, f1.getY()+height+insets.getTotalHeight(), g3); f3.setSharedAutoDrawable(f1); @@ -222,6 +223,7 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase { public void asyncEachAnimator(final boolean destroyCleanOrder) throws InterruptedException { final Animator a1 = new Animator(); final GearsES2 g1 = new GearsES2(0); + g1.setSyncObjects(g1); // this is master, since rendered we must use it as sync final GLWindow f1 = createGLWindow(0, 0, g1); a1.add(f1); a1.start(); @@ -230,7 +232,7 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase { final Animator a2 = new Animator(); final GearsES2 g2 = new GearsES2(0); - g2.setSharedGears(g1); + g2.setSharedGears(g1); // also uses master g1 as sync, if required final GLWindow f2 = createGLWindow(f1.getX()+width+insets.getTotalWidth(), f1.getY()+0, g2); f2.setSharedAutoDrawable(f1); @@ -240,7 +242,7 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase { final Animator a3 = new Animator(); final GearsES2 g3 = new GearsES2(0); - g3.setSharedGears(g1); + g3.setSharedGears(g1); // also uses master g1 as sync, if required final GLWindow f3 = createGLWindow(f1.getX()+0, f1.getY()+height+insets.getTotalHeight(), g3); f3.setSharedAutoDrawable(f1); @@ -336,8 +338,10 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase { } static long duration = 1000; // ms + static boolean mainRun = false; public static void main(final String args[]) { + mainRun = true; for(int i=0; i "+gear2); System.err.println("gear3 "+sid()+" created w/ share: "+sharedGears.getGear3()+" -> "+gear3); } + if( gl.getContext().hasRendererQuirk(GLRendererQuirks.NeedSharedObjectSync) ) { + syncObjects = sharedGears; + System.err.println("Shared GearsES2: Synchronized Objects due to quirk "+GLRendererQuirks.toString(GLRendererQuirks.NeedSharedObjectSync)); + } else if( null == syncObjects ) { + syncObjects = new Object(); + System.err.println("Shared GearsES2: Unsynchronized Objects"); + } } else { gear1 = new GearsObjectES2(gl, useMappedBuffers, st, gear1Color, 1.0f, 4.0f, 1.0f, 20, 0.7f, pmvMatrix, pmvMatrixUniform, colorU, validateBuffers); if(verbose) { @@ -262,6 +275,8 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen if(verbose) { System.err.println("gear3 "+sid()+" created: "+gear2); } + if( null == syncObjects ) { + syncObjects = new Object(); } } @@ -461,6 +476,8 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen colorU = null; st.destroy(gl); st = null; + sharedGears = null; + syncObjects = null; if(verbose) { System.err.println(Thread.currentThread()+" GearsES2.dispose "+sid()+" FIN"); @@ -534,9 +551,11 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen pmvMatrix.glRotatef(view_roty, 0.0f, 1.0f, 0.0f); pmvMatrix.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f); - gear1.draw(gl, -3.0f, -2.0f, 1f * angle - 0f); - gear2.draw(gl, 3.1f, -2.0f, -2f * angle - 9.0f); - gear3.draw(gl, -3.1f, 4.2f, -2f * angle - 25.0f); + synchronized ( syncObjects ) { + gear1.draw(gl, -3.0f, -2.0f, 1f * angle - 0f); + gear2.draw(gl, 3.1f, -2.0f, -2f * angle - 9.0f); + gear3.draw(gl, -3.1f, 4.2f, -2f * angle - 25.0f); + } pmvMatrix.glPopMatrix(); st.useProgram(gl, false); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java index 6683f0fbf..28328fcd2 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java @@ -20,6 +20,7 @@ import com.jogamp.newt.event.MouseEvent; import com.jogamp.newt.event.MouseListener; import com.jogamp.newt.event.awt.AWTKeyAdapter; import com.jogamp.newt.event.awt.AWTMouseAdapter; +import com.jogamp.opengl.GLRendererQuirks; import com.jogamp.opengl.JoglVersion; import com.jogamp.opengl.util.TileRendererBase; @@ -33,6 +34,8 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList private float view_rotx = 20.0f, view_roty = 30.0f; private final float view_rotz = 0.0f; private int gear1=0, gear2=0, gear3=0; + private Gears sharedGears = null; + private Object syncObjects = null; private float angle = 0.0f; private boolean doRotate = true; private final int swapInterval; @@ -42,6 +45,7 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList private boolean doRotateBeforePrinting; private boolean verbose = true; private boolean flipVerticalInGLOrientation = false; + private volatile boolean isInit = false; // private boolean mouseRButtonDown = false; private int prevMouseX, prevMouseY; @@ -182,6 +186,13 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList System.err.println("gear1 list reused: "+gear1); System.err.println("gear2 list reused: "+gear2); System.err.println("gear3 list reused: "+gear3); + if( gl.getContext().hasRendererQuirk(GLRendererQuirks.NeedSharedObjectSync) ) { + syncObjects = sharedGears; + System.err.println("Shared Gears: Synchronized Objects due to quirk "+GLRendererQuirks.toString(GLRendererQuirks.NeedSharedObjectSync)); + } else { + syncObjects = new Object(); + System.err.println("Shared Gears: Unsynchronized Objects"); + } } else { gear1 = gl.glGenLists(1); gl.glNewList(gear1, GL2.GL_COMPILE); @@ -203,6 +214,8 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList gear(gl, 1.3f, 2.0f, 0.5f, 10, 0.7f); gl.glEndList(); System.err.println("gear3 list created: "+gear3); + + syncObjects = new Object(); } enableStates(gl, false); @@ -295,6 +308,8 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList gear1 = 0; gear2 = 0; gear3 = 0; + sharedGears = null; + syncObjects = null; } @Override @@ -355,25 +370,27 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f); // Place the first gear and call its display list - gl.glPushMatrix(); - gl.glTranslatef(-3.0f, -2.0f, 0.0f); - gl.glRotatef(angle, 0.0f, 0.0f, 1.0f); - gl.glCallList(gear1); - gl.glPopMatrix(); - - // Place the second gear and call its display list - gl.glPushMatrix(); - gl.glTranslatef(3.1f, -2.0f, 0.0f); - gl.glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f); - gl.glCallList(gear2); - gl.glPopMatrix(); - - // Place the third gear and call its display list - gl.glPushMatrix(); - gl.glTranslatef(-3.1f, 4.2f, 0.0f); - gl.glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f); - gl.glCallList(gear3); - gl.glPopMatrix(); + synchronized ( syncObjects ) { + gl.glPushMatrix(); + gl.glTranslatef(-3.0f, -2.0f, 0.0f); + gl.glRotatef(angle, 0.0f, 0.0f, 1.0f); + gl.glCallList(gear1); + gl.glPopMatrix(); + + // Place the second gear and call its display list + gl.glPushMatrix(); + gl.glTranslatef(3.1f, -2.0f, 0.0f); + gl.glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f); + gl.glCallList(gear2); + gl.glPopMatrix(); + + // Place the third gear and call its display list + gl.glPushMatrix(); + gl.glTranslatef(-3.1f, 4.2f, 0.0f); + gl.glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f); + gl.glCallList(gear3); + gl.glPopMatrix(); + } // Remember that every push needs a pop; this one is paired with // rotating the entire gear assembly -- cgit v1.2.3