Jogamp
Bug 1202 - Add support of Adaptive Vsync via [GLX|WGL]_EXT_swap_control_tear
authorSven Gothel <sgothel@jausoft.com>
Thu, 27 Aug 2015 11:15:44 +0000 (13:15 +0200)
committerSven Gothel <sgothel@jausoft.com>
Thu, 27 Aug 2015 11:15:44 +0000 (13:15 +0200)
[GLX|WGL]_EXT_swap_control_tear extensions support
asynchronous buffer swaps, i.e. adaptive Vsync.

<https://www.opengl.org/wiki/SwapInterval_aka_vsync#Adaptive_Vsync>
<https://www.opengl.org/registry/specs/EXT/wgl_swap_control_tear.txt>
<https://www.opengl.org/registry/specs/EXT/glx_swap_control_tear.txt>

<http://keithp.com/blogs/async_flip/>

The extensions utilizes a negative interval value,
enabling late swaps to occur without synchronization to the video frame.

Hence '-1' has new semantics, previously it was the 'default value'
of 'untouched vsync interval'.

New default is:
  - 0 for unrealized context
  - 1 for realized context

+++

It requires [GLX|WGL]_EXT_swap_control,
hence we shall ensure to use use this extension
in the implementation of GLContext.setSwapInterval(..).

+++

Mesa3D seems to support GLX_SGI_swap_control only.

+++

Implemented on Windows and X11.

+++

On GNU/Linux using NVidia driver w/ my setup(*), sadly the query
  GLX.glXQueryDrawable(displayHandle, drawable.getHandle(), GLX.GLX_LATE_SWAPS_TEAR_EXT, val);
always returns zero here, indicating async vsync is not supported.

(Queried the attribute for every frame in windowed or fullscreen mode)

Fullscreen
(*)
  - Debian 8
  - Kernel 3.16
  - KDE/Kwin
  - GL Version     4.5 (Core profile, arb, compat[ES2, ES3, ES31], FBO, hardware) - 4.5.0 NVIDIA 355.06 [GL 4.5.0, vendor 355.6.0 (NVIDIA 355.06)]
  - GL_RENDERER    GeForce GTX 660/PCIe/SSE2
  - Samsung U28D590 (DFP-4): Internal DisplayPort

+++

28 files changed:
src/jogl/classes/com/jogamp/opengl/GLBase.java
src/jogl/classes/com/jogamp/opengl/GLContext.java
src/jogl/classes/jogamp/opengl/GLContextImpl.java
src/jogl/classes/jogamp/opengl/GLXExtensions.java
src/jogl/classes/jogamp/opengl/egl/EGLContext.java
src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java
src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java
src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java
src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
src/newt/classes/com/jogamp/newt/util/applet3/JOGLNewtApplet3Run.java
src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT00.java
src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java
src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIListenerBase01.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/PointsDemoES1.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/RedSquareES1.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/FBOMix2DemosES2.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/LandscapeES2.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/Mix2TexturesES2.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/PointsDemoES2.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareMappedES2.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TextureDraw02ES2ListenerFBO.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSimple.java
src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java
src/test/com/jogamp/opengl/test/junit/util/NEWTDemoListener.java

index dee5f14..e0c7843 100644 (file)
@@ -446,29 +446,43 @@ public interface GLBase {
 
    public boolean isTextureFormatBGRA8888Available();
 
-   /** Provides a platform-independent way to specify the minimum swap
-       interval for buffer swaps. An argument of 0 disables
-       sync-to-vertical-refresh completely, while an argument of 1
-       causes the application to wait until the next vertical refresh
-       until swapping buffers. The default, which is platform-specific,
-       is usually either 0 or 1. This function is not guaranteed to
-       have an effect, and in particular only affects heavyweight
-       onscreen components.
-
-       @see #getSwapInterval
-       @throws GLException if this context is not the current
+   /**
+    * Set the swap interval of the current context and attached <i>onscreen {@link GLDrawable}</i>.
+    * <p>
+    * <i>offscreen {@link GLDrawable}</i> are ignored and {@code false} is returned.
+    * </p>
+    * <p>
+    * The {@code interval} semantics:
+    * <ul>
+    *   <li><i>0</i> disables the vertical synchronization</li>
+    *   <li><i>&ge;1</i> is the number of vertical refreshes before a swap buffer occurs</li>
+    *   <li><i>&lt;0</i> enables <i>late swaps to occur without synchronization to the video frame</i>, a.k.a <i>EXT_swap_control_tear</i>.
+    *              If supported, the absolute value is the minimum number of
+    *              video frames between buffer swaps. If not supported, the absolute value is being used, see above.
+    *   </li>
+    * </ul>
+    * </p>
+    * @param interval see above
+    * @return true if the operation was successful, otherwise false
+    * @throws GLException if the context is not current.
+    * @see GLContext#setSwapInterval(int)
+    * @see #getSwapInterval()
     */
-   public void setSwapInterval(int interval);
-
-   /** Provides a platform-independent way to get the swap
-       interval set by {@link #setSwapInterval}. <br>
+   public void setSwapInterval(int interval) throws GLException;
 
-       If the interval is not set by {@link #setSwapInterval} yet,
-       -1 is returned, indicating that the platforms default
-       is being used.
-
-       @see #setSwapInterval
-     */
+   /**
+    * Return the current swap interval.
+    * <p>
+    * If the context has not been made current at all,
+    * the default value {@code 0} is returned.
+    * </p>
+    * <p>
+    * For a valid context w/ an <o>onscreen {@link GLDrawable}</i> the default value is {@code 1},
+    * otherwise the default value is {@code 0}.
+    * </p>
+    * @see GLContext#getSwapInterval()
+    * @see #setSwapInterval(int)
+    */
    public int getSwapInterval();
 
    /**
@@ -494,12 +508,12 @@ public interface GLBase {
     * for accessing it, including which class or interface contains the
     * functions.
     *
-    * <P>
-    *
+    * <p>
     * Note: it is the intent to add new extensions as quickly as possible
     * to the core GL API. Therefore it is unlikely that most vendors will
     * use this extension mechanism, but it is being provided for
     * completeness.
+    * </p>
     */
    public Object getExtension(String extensionName);
 
index f68c029..3ac5df7 100644 (file)
@@ -237,7 +237,6 @@ public abstract class GLContext {
   protected String ctxVersionString;
   protected VersionNumberString ctxVendorVersion;
   protected VersionNumber ctxGLSLVersion;
-  private int currentSwapInterval;
   protected GLRendererQuirks glRendererQuirks;
 
   /** Did the drawable association changed ? see {@link GLRendererQuirks#NoSetSwapIntervalPostRetarget} */
@@ -258,7 +257,6 @@ public abstract class GLContext {
       ctxGLSLVersion = VersionNumber.zeroVersion;
       attachedObjects.clear();
       contextHandle=0;
-      currentSwapInterval = -1;
       glRendererQuirks = null;
       drawableRetargeted = false;
   }
@@ -1246,50 +1244,41 @@ public abstract class GLContext {
   }
 
   /**
-   * Set the swap interval of the current context and attached drawable.
-   * @param interval Should be &ge; 0. 0 disables the vertical synchronization,
-   *                 where &ge; 1 is the number of vertical refreshes before a swap buffer occurs.
-   *                 A value &lt; 0 is ignored.
+   * Set the swap interval of the current context and attached <i>onscreen {@link GLDrawable}</i>.
+   * <p>
+   * <i>offscreen {@link GLDrawable}</i> are ignored and {@code false} is returned.
+   * </p>
+   * <p>
+   * The {@code interval} semantics:
+   * <ul>
+   *   <li><i>0</i> disables the vertical synchronization</li>
+   *   <li><i>&ge;1</i> is the number of vertical refreshes before a swap buffer occurs</li>
+   *   <li><i>&lt;0</i> enables <i>late swaps to occur without synchronization to the video frame</i>, a.k.a <i>EXT_swap_control_tear</i>.
+   *              If supported, the absolute value is the minimum number of
+   *              video frames between buffer swaps. If not supported, the absolute value is being used, see above.
+   *   </li>
+   * </ul>
+   * </p>
+   * @param interval see above
    * @return true if the operation was successful, otherwise false
-   *
    * @throws GLException if the context is not current.
+   * @see #getSwapInterval()
    */
-  public final boolean setSwapInterval(final int interval) throws GLException {
-    validateCurrent();
-    if(0<=interval) {
-        if( !drawableRetargeted || !hasRendererQuirk(GLRendererQuirks.NoSetSwapIntervalPostRetarget) ) {
-            if( setSwapIntervalImpl(interval) ) {
-                currentSwapInterval = interval;
-                return true;
-            }
-        }
-    }
-    return false;
-  }
-  protected boolean setSwapIntervalImpl(final int interval) {
-      return false;
-  }
-  /** Return the current swap interval.
+  public abstract boolean setSwapInterval(final int interval) throws GLException;
+
+  /**
+   * Return the current swap interval.
    * <p>
    * If the context has not been made current at all,
-   * the default value <code>-1</code> is returned.
+   * the default value {@code 0} is returned.
    * </p>
    * <p>
-   * For a valid context the default value is <code>1</code>
-   * in case of an EGL based profile (ES1 or ES2) and <code>-1</code>
-   * (undefined) for desktop.
+   * For a valid context w/ an <o>onscreen {@link GLDrawable}</i> the default value is {@code 1},
+   * otherwise the default value is {@code 0}.
    * </p>
+   * @see #setSwapInterval(int)
    */
-  public final int getSwapInterval() {
-    return currentSwapInterval;
-  }
-  protected final void setDefaultSwapInterval() {
-    if(this.isGLES()) {
-        currentSwapInterval = 1;
-    } else {
-        currentSwapInterval = -1;
-    }
-  }
+  public abstract int getSwapInterval();
 
   public final boolean queryMaxSwapGroups(final int[] maxGroups, final int maxGroups_offset,
                                           final int[] maxBarriers, final int maxBarriers_offset) {
index fa7aeaf..39c5796 100644 (file)
@@ -131,6 +131,8 @@ public abstract class GLContextImpl extends GLContext {
   private boolean pixelDataEvaluated;
   private int /* pixelDataInternalFormat, */ pixelDataFormat, pixelDataType;
 
+  private int currentSwapInterval;
+
   protected GL gl;
 
   protected static final Object mappedContextTypeObjectLock;
@@ -209,6 +211,7 @@ public abstract class GLContextImpl extends GLContext {
 
       surfacelessOK = false;
       pixelDataEvaluated = false;
+      currentSwapInterval = 0;
 
       super.resetStates(isInit);
   }
@@ -1110,6 +1113,34 @@ public abstract class GLContextImpl extends GLContext {
     }
   }
 
+  @Override
+  public final boolean setSwapInterval(final int interval) throws GLException {
+    validateCurrent();
+    return setSwapIntervalNC(interval);
+  }
+  protected final boolean setSwapIntervalNC(final int interval) throws GLException {
+    if( drawable.getChosenGLCapabilities().isOnscreen() &&
+        ( !drawableRetargeted || !hasRendererQuirk(GLRendererQuirks.NoSetSwapIntervalPostRetarget) )
+      )
+    {
+        final Integer usedInterval = setSwapIntervalImpl(interval);
+        if( null != usedInterval ) {
+            currentSwapInterval = usedInterval.intValue();
+            return true;
+        }
+    }
+    return false;
+  }
+  protected abstract Integer setSwapIntervalImpl(final int interval);
+
+  public final int getSwapInterval() {
+    return currentSwapInterval;
+  }
+  protected final void setDefaultSwapInterval() {
+    currentSwapInterval = 0;
+    setSwapIntervalNC(1);
+  }
+
   /**
    * Note: Since context creation is temporary, caller need to issue {@link #resetStates(boolean)}, if creation was successful, i.e. returns true.
    * This method does not reset the states, allowing the caller to utilize the state variables.
index 9325c6f..db4757e 100644 (file)
@@ -34,4 +34,10 @@ public class GLXExtensions {
   public static final String GLX_MESA_swap_control           = "GLX_MESA_swap_control";
   public static final String GLX_SGI_swap_control            = "GLX_SGI_swap_control";
   public static final String GLX_NV_swap_group               = "GLX_NV_swap_group";
+
+  public static final String GLX_EXT_swap_control            = "GLX_EXT_swap_control";
+  public static final String GLX_EXT_swap_control_tear       = "GLX_EXT_swap_control_tear";
+
+  public static final String WGL_EXT_swap_control            = "WGL_EXT_swap_control";
+  public static final String WGL_EXT_swap_control_tear       = "WGL_EXT_swap_control_tear";
 }
index b6a05ae..b64bb37 100644 (file)
@@ -51,7 +51,6 @@ import jogamp.opengl.GLContextImpl;
 import jogamp.opengl.GLDrawableImpl;
 import jogamp.opengl.egl.EGLExtImpl;
 import jogamp.opengl.egl.EGLExtProcAddressTable;
-import jogamp.opengl.windows.wgl.WindowsWGLContext;
 
 import com.jogamp.common.ExceptionUtils;
 import com.jogamp.common.nio.Buffers;
@@ -432,11 +431,20 @@ public class EGLContext extends GLContextImpl {
     }
 
     @Override
-    protected boolean setSwapIntervalImpl(final int interval) {
+    protected final Integer setSwapIntervalImpl(final int interval) {
         if( hasRendererQuirk(GLRendererQuirks.NoSetSwapInterval) ) {
-            return false;
+            return null;
         }
-        return EGL.eglSwapInterval(drawable.getNativeSurface().getDisplayHandle(), interval);
+        final int useInterval;
+        if( 0 > interval ) {
+            useInterval = Math.abs(interval);
+        } else {
+            useInterval = interval;
+        }
+        if( EGL.eglSwapInterval(drawable.getNativeSurface().getDisplayHandle(), useInterval) ) {
+            return Integer.valueOf(useInterval);
+        }
+        return null;
     }
 
     static long eglGetProcAddress(final long eglGetProcAddressHandle, final String procname)
index d4fc0b0..2f88e76 100644 (file)
@@ -423,8 +423,17 @@ public class MacOSXCGLContext extends GLContextImpl
   }
 
   @Override
-  protected boolean setSwapIntervalImpl(final int interval) {
-    return impl.setSwapInterval(interval);
+  protected final Integer setSwapIntervalImpl(final int interval) {
+      final int useInterval;
+      if( 0 > interval ) {
+          useInterval = Math.abs(interval);
+      } else {
+          useInterval = interval;
+      }
+      if( impl.setSwapInterval(useInterval) ) {
+          return Integer.valueOf(useInterval);
+      }
+      return null;
   }
 
   @Override
index a8269ad..6ff8c57 100644 (file)
@@ -50,6 +50,7 @@ import com.jogamp.nativewindow.NativeSurface;
 import com.jogamp.opengl.GLContext;
 import com.jogamp.opengl.GLException;
 import com.jogamp.opengl.GLCapabilitiesImmutable;
+import com.jogamp.common.ExceptionUtils;
 import com.jogamp.common.nio.Buffers;
 import com.jogamp.gluegen.runtime.ProcAddressTable;
 import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver;
@@ -59,6 +60,7 @@ import com.jogamp.opengl.GLRendererQuirks;
 import jogamp.nativewindow.windows.GDI;
 import jogamp.opengl.GLContextImpl;
 import jogamp.opengl.GLDrawableImpl;
+import jogamp.opengl.GLXExtensions;
 
 public class WindowsWGLContext extends GLContextImpl {
   static final Map<String, String> extensionNameMap;
@@ -70,7 +72,8 @@ public class WindowsWGLContext extends GLContextImpl {
   // Table that holds the addresses of the native C-language entry points for
   // WGL extension functions.
   private WGLExtProcAddressTable wglExtProcAddressTable;
-  private int hasSwapIntervalSGI = 0;
+  /** 2 WGL_EXT_swap_control_tear, 1 WGL_EXT_swap_control, 0 undefined, -1 none */
+  private int hasSwapInterval = 0;
   private int hasSwapGroupNV = 0;
 
   static {
@@ -93,7 +96,7 @@ public class WindowsWGLContext extends GLContextImpl {
     wglGLReadDrawableAvailable=false;
     // no inner state _wglExt=null;
     wglExtProcAddressTable=null;
-    hasSwapIntervalSGI = 0;
+    hasSwapInterval = 0;
     hasSwapGroupNV = 0;
     super.resetStates(isInit);
   }
@@ -487,19 +490,39 @@ public class WindowsWGLContext extends GLContextImpl {
   }
 
   @Override
-  protected boolean setSwapIntervalImpl(final int interval) {
-    final WGLExt wglExt = getWGLExt();
-    if(0==hasSwapIntervalSGI) {
+  protected final Integer setSwapIntervalImpl(final int interval) {
+    if( 0 == hasSwapInterval ) {
         try {
-            hasSwapIntervalSGI = wglExt.isExtensionAvailable("WGL_EXT_swap_control")?1:-1;
-        } catch (final Throwable t) { hasSwapIntervalSGI=1; }
+            if ( isExtensionAvailable(GLXExtensions.WGL_EXT_swap_control) ) {
+                hasSwapInterval = 1;
+                if ( isExtensionAvailable(GLXExtensions.WGL_EXT_swap_control_tear) ) {
+                    hasSwapInterval =  2;
+                    if(DEBUG) { System.err.println("WGLContext.setSwapInterval.2 using: "+GLXExtensions.WGL_EXT_swap_control_tear + ", " + GLXExtensions.WGL_EXT_swap_control_tear); }
+                } else {
+                    hasSwapInterval =  1;
+                    if(DEBUG) { System.err.println("WGLContext.setSwapInterval.1 using: "+GLXExtensions.WGL_EXT_swap_control); }
+                }
+            } else {
+                hasSwapInterval = -1;
+                if(DEBUG) { System.err.println("WGLContext.setSwapInterval.0 N/A"); }
+            }
+        } catch (final Throwable t) { hasSwapInterval=-1; if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } }
     }
-    if (hasSwapIntervalSGI>0) {
+    if ( 0 < hasSwapInterval ) { // 2 || 1
+        final int useInterval;
+        if( 1 == hasSwapInterval && 0 > interval ) {
+            useInterval = Math.abs(interval);
+        } else {
+            useInterval = interval;
+        }
         try {
-            return wglExt.wglSwapIntervalEXT(interval);
-        } catch (final Throwable t) { hasSwapIntervalSGI=-1; }
+            final WGLExt wglExt = getWGLExt();
+            if( wglExt.wglSwapIntervalEXT(useInterval) ) {
+                return Integer.valueOf(useInterval);
+            }
+        } catch (final Throwable t) { hasSwapInterval=-1; if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } }
     }
-    return false;
+    return null;
   }
 
   private final int initSwapGroupImpl(final WGLExt wglExt) {
index 63b0b35..3f856e4 100644 (file)
@@ -72,7 +72,7 @@ public class X11GLXContext extends GLContextImpl {
   // Table that holds the addresses of the native C-language entry points for
   // GLX extension functions.
   private GLXExtProcAddressTable glXExtProcAddressTable;
-  /** 1 MESA, 2 SGI, 0 undefined, -1 none */
+  /** 3 SGI, 2 GLX_EXT_swap_control_tear, 1 GLX_EXT_swap_control, 0 undefined, -1 none */
   private int hasSwapInterval = 0;
   private int hasSwapGroupNV = 0;
 
@@ -549,39 +549,64 @@ public class X11GLXContext extends GLContextImpl {
   }
 
   @Override
-  protected boolean setSwapIntervalImpl(final int interval) {
-    if( !drawable.getChosenGLCapabilities().isOnscreen() ) { return false; }
-
-    final GLXExt glXExt = getGLXExt();
-    if(0==hasSwapInterval) {
+  protected final Integer setSwapIntervalImpl(final int interval) {
+    final long displayHandle = drawable.getNativeSurface().getDisplayHandle();
+    if( 0 == hasSwapInterval ) {
         try {
-            /** Same impl. ..
-            if( glXExt.isExtensionAvailable(GLXExtensions.GLX_MESA_swap_control) ) {
-                if(DEBUG) { System.err.println("X11GLXContext.setSwapInterval using: "+GLXExtensions.GLX_MESA_swap_control); }
-                hasSwapInterval =  1;
-            } else */
-            if ( glXExt.isExtensionAvailable(GLXExtensions.GLX_SGI_swap_control) ) {
-                if(DEBUG) { System.err.println("X11GLXContext.setSwapInterval using: "+GLXExtensions.GLX_SGI_swap_control); }
-                hasSwapInterval =  2;
+            if ( isExtensionAvailable(GLXExtensions.GLX_EXT_swap_control) ) {
+                hasSwapInterval = 1;
+                if ( isExtensionAvailable(GLXExtensions.GLX_EXT_swap_control_tear) ) {
+                    try {
+                        final IntBuffer val = Buffers.newDirectIntBuffer(1);
+                        GLX.glXQueryDrawable(displayHandle, drawable.getHandle(), GLX.GLX_LATE_SWAPS_TEAR_EXT, val);
+                        if( 1 == val.get(0) ) {
+                            hasSwapInterval =  2;
+                            if(DEBUG) { System.err.println("X11GLXContext.setSwapInterval.2 using: "+GLXExtensions.GLX_EXT_swap_control_tear + ", " + GLXExtensions.GLX_EXT_swap_control_tear); }
+                        } else if(DEBUG) {
+                            System.err.println("X11GLXContext.setSwapInterval.2 n/a: "+GLXExtensions.GLX_EXT_swap_control_tear+", query: "+val.get(0));
+                        }
+                    } catch (final Throwable t) { if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } }
+                }
+                if(DEBUG) {
+                    if( 1 == hasSwapInterval ) {
+                        System.err.println("X11GLXContext.setSwapInterval.1 using: "+GLXExtensions.GLX_EXT_swap_control);
+                    }
+                }
+            } else if ( isExtensionAvailable(GLXExtensions.GLX_SGI_swap_control) ) {
+                hasSwapInterval =  3;
+                if(DEBUG) { System.err.println("X11GLXContext.setSwapInterval.3 using: "+GLXExtensions.GLX_SGI_swap_control); }
             } else {
                 hasSwapInterval = -1;
+                if(DEBUG) { System.err.println("X11GLXContext.setSwapInterval.0 N/A"); }
             }
-        } catch (final Throwable t) { hasSwapInterval=-1; }
+        } catch (final Throwable t) { hasSwapInterval=-1; if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } }
     }
-    /* try {
-        switch( hasSwapInterval ) {
-            case 1:
-                return 0 == glXExt.glXSwapIntervalMESA(interval);
-            case 2:
-                return 0 == glXExt.glXSwapIntervalSGI(interval);
+    if (3 == hasSwapInterval) {
+        final int useInterval;
+        if( 0 > interval ) {
+            useInterval = Math.abs(interval);
+        } else {
+            useInterval = interval;
+        }
+        try {
+            final GLXExt glXExt = getGLXExt();
+            if( 0 == glXExt.glXSwapIntervalSGI(useInterval) ) {
+                return Integer.valueOf(useInterval);
+            }
+        } catch (final Throwable t) { hasSwapInterval=-1; if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } }
+    } else if ( 0 < hasSwapInterval ) { // 2 || 1
+        final int useInterval;
+        if( 1 == hasSwapInterval && 0 > interval ) {
+            useInterval = Math.abs(interval);
+        } else {
+            useInterval = interval;
         }
-    } catch (Throwable t) { hasSwapInterval = -1; } */
-    if (2 == hasSwapInterval) {
         try {
-            return 0 == glXExt.glXSwapIntervalSGI(interval);
-        } catch (final Throwable t) { hasSwapInterval=-1; }
+            GLX.glXSwapIntervalEXT(displayHandle, drawable.getHandle(), useInterval);
+            return Integer.valueOf(useInterval);
+        } catch (final Throwable t) { hasSwapInterval=-1; if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } }
     }
-    return false;
+    return null;
   }
 
   private final int initSwapGroupImpl(final GLXExt glXExt) {
index cd53294..6bf9f41 100644 (file)
@@ -115,7 +115,7 @@ public class JOGLNewtApplet1Run extends Applet {
 
         String glEventListenerClazzName=null;
         String glProfileName=null;
-        int glSwapInterval=0;
+        int glSwapInterval=1;
         boolean glDebug=false;
         boolean glTrace=false;
         boolean glUndecorated=false;
index cc159e6..c2cf64d 100644 (file)
@@ -291,10 +291,7 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
                 _gl = _gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, _gl, new Object[] { System.err } ) );
             } catch (final Exception e) {e.printStackTrace();}
         }
-
-        if(glSwapInterval>=0) {
-            _gl.setSwapInterval(glSwapInterval);
-        }
+        _gl.setSwapInterval(glSwapInterval);
     }
     @Override
     public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
index 9b9b7d5..fce43d7 100644 (file)
@@ -243,7 +243,7 @@ public class JOGLNewtApplet3Run implements Applet3 {
         }
         this.ctx = ctx;
         String glEventListenerClazzName=null;
-        int glSwapInterval=0;
+        int glSwapInterval=1;
         boolean glDebug=false;
         boolean glTrace=false;
         boolean glNoDefaultKeyListener = false;
index 86b129f..36e263f 100644 (file)
@@ -54,6 +54,7 @@ import com.jogamp.graph.curve.opengl.RenderState;
 import com.jogamp.graph.font.Font;
 import com.jogamp.graph.font.FontFactory;
 import com.jogamp.graph.geom.SVertex;
+import com.jogamp.junit.util.JunitTracer;
 import com.jogamp.newt.Window;
 import com.jogamp.newt.opengl.GLWindow;
 import com.jogamp.opengl.test.junit.util.MiscUtils;
@@ -73,7 +74,7 @@ public class TestTextRendererNEWT00 extends UITestCase {
     static int GraphVBAASamples = 0;
     static int GraphMSAASamples = 0;
     static boolean ManualTest = false;
-    static int SwapInterval = 0;
+    static int SwapInterval = 1;
 
     static String fontFileName = null;
     static URL fontURL = null;
@@ -213,7 +214,7 @@ public class TestTextRendererNEWT00 extends UITestCase {
         window.display();
         System.err.println("Chosen: "+window.getChosenGLCapabilities());
         if( WaitStartEnd ) {
-            UITestCase.waitForKey("Start");
+            JunitTracer.waitForKey("Start");
         }
 
         final RenderState rs = RenderState.createRenderState(SVertex.factory());
@@ -252,7 +253,7 @@ public class TestTextRendererNEWT00 extends UITestCase {
         });
         anim.stop();
         if( WaitStartEnd ) {
-            UITestCase.waitForKey("Stop");
+            JunitTracer.waitForKey("Stop");
         }
         destroyWindow(window);
     }
index 73b76de..b26ed88 100644 (file)
@@ -302,9 +302,16 @@ public abstract class GPURendererListenerBase01 implements GLEventListener {
                         @Override
                         public boolean run(final GLAutoDrawable drawable) {
                             final GL gl = drawable.getGL();
-                            int i = gl.getSwapInterval();
-                            i = i==0 ? 1 : 0;
+                            final int _i = gl.getSwapInterval();
+                            final int i;
+                            switch(_i) {
+                                case  0: i = -1; break;
+                                case -1: i =  1; break;
+                                case  1: i =  0; break;
+                                default: i =  1; break;
+                            }
                             gl.setSwapInterval(i);
+
                             final GLAnimatorControl a = drawable.getAnimator();
                             if( null != a ) {
                                 a.resetFPSCounter();
@@ -312,7 +319,7 @@ public abstract class GPURendererListenerBase01 implements GLEventListener {
                             if(drawable instanceof FPSCounter) {
                                 ((FPSCounter)drawable).resetFPSCounter();
                             }
-                            System.err.println("Swap Interval: "+i);
+                            System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval());
                             return true;
                         }
                     });
index 2e3d2fa..ab5bfb9 100644 (file)
@@ -32,6 +32,7 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
+import com.jogamp.opengl.FPSCounter;
 import com.jogamp.opengl.GL;
 import com.jogamp.opengl.GL2ES2;
 import com.jogamp.opengl.GLAnimatorControl;
@@ -285,16 +286,27 @@ public abstract class UIListenerBase01 implements GLEventListener {
             else if(arg0.getKeyCode() == KeyEvent.VK_V) {
                 if(null != autoDrawable) {
                     autoDrawable.invoke(false, new GLRunnable() {
+                        @Override
                         public boolean run(final GLAutoDrawable drawable) {
                             final GL gl = drawable.getGL();
-                            int i = gl.getSwapInterval();
-                            i = i==0 ? 1 : 0;
+                            final int _i = gl.getSwapInterval();
+                            final int i;
+                            switch(_i) {
+                                case  0: i =  1; break;
+                                case  1: i = -1; break;
+                                case -1: i =  0; break;
+                                default: i =  1; break;
+                            }
                             gl.setSwapInterval(i);
+
                             final GLAnimatorControl a = drawable.getAnimator();
                             if( null != a ) {
                                 a.resetFPSCounter();
                             }
-                            System.err.println("Swap Interval: "+i);
+                            if(drawable instanceof FPSCounter) {
+                                ((FPSCounter)drawable).resetFPSCounter();
+                            }
+                            System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval());
                             return true;
                         }
                     });
index 7189db1..e8acb0b 100644 (file)
@@ -181,9 +181,7 @@ public class PointsDemoES1 extends PointsDemo {
         // Thread.dumpStack();
         final GL2ES1 gl = glad.getGL().getGL2ES1();
 
-        if(-1 != swapInterval) {
-            gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
-        }
+        gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
 
         // Set location in front of camera
         gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
index 60ac6b2..7eebf44 100644 (file)
@@ -141,9 +141,7 @@ public class RedSquareES1 implements GLEventListener, TileRendererBase.TileRende
     @Override
     public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) {
         final GL2ES1 gl = glad.getGL().getGL2ES1();
-        if(-1 != swapInterval) {
-            gl.setSwapInterval(swapInterval);
-        }
+        gl.setSwapInterval(swapInterval);
         reshapeImpl(gl, x, y, width, height, width, height);
     }
 
index ff88af5..de2d345 100644 (file)
@@ -267,9 +267,7 @@ public class FBOMix2DemosES2 implements GLEventListener {
     public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
         final GL2ES2 gl = drawable.getGL().getGL2ES2();
 
-        if(-1 != swapInterval) {
-            gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
-        }
+        gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
 
         System.err.println("**** Reshape: "+width+"x"+height);
         resetFBOs(gl, drawable);
index e1abcc7..c0a4756 100644 (file)
@@ -319,9 +319,7 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
     public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) {
         if( !isInit ) { return; }
         final GL2ES2 gl = glad.getGL().getGL2ES2();
-        if(-1 != swapInterval) {
-            gl.setSwapInterval(swapInterval);
-        }
+        gl.setSwapInterval(swapInterval);
         reshapeImpl(gl, x, y, width, height, width, height);
     }
 
index a504ec1..18c0ffd 100644 (file)
@@ -128,9 +128,7 @@ public class LandscapeES2 implements GLEventListener {
 
         final GL2ES2 gl = drawable.getGL().getGL2ES2();
 
-        if(-1 != swapInterval) {
-            gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
-        }
+        gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
 
         shaderState.useProgram(gl, true);
 
index 6d20270..3ec383a 100644 (file)
@@ -181,9 +181,7 @@ public class Mix2TexturesES2 implements GLEventListener {
     public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
         final GL2ES2 gl = drawable.getGL().getGL2ES2();
 
-        if(-1 != swapInterval) {
-            gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
-        }
+        gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
 
         pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
         pmvMatrix.glLoadIdentity();
index 673552c..d59c1bb 100644 (file)
@@ -186,9 +186,7 @@ public class PointsDemoES2 extends PointsDemo {
         // Thread.dumpStack();
         final GL2ES2 gl = glad.getGL().getGL2ES2();
 
-        if(-1 != swapInterval) {
-            gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
-        }
+        gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
 
         st.useProgram(gl, true);
         // Set location in front of camera
index a0afef8..4da4b7c 100644 (file)
@@ -192,9 +192,7 @@ public class RedSquareES2 implements GLEventListener, TileRendererBase.TileRende
     @Override
     public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) {
         final GL2ES2 gl = glad.getGL().getGL2ES2();
-        if(-1 != swapInterval) {
-            gl.setSwapInterval(swapInterval);
-        }
+        gl.setSwapInterval(swapInterval);
         reshapeImpl(gl, x, y, width, height, width, height);
     }
 
index 9dab97d..3b52640 100644 (file)
@@ -211,9 +211,7 @@ public class RedSquareMappedES2 implements GLEventListener, TileRendererBase.Til
     @Override
     public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) {
         final GL2ES2 gl = glad.getGL().getGL2ES2();
-        if(-1 != swapInterval) {
-            gl.setSwapInterval(swapInterval);
-        }
+        gl.setSwapInterval(swapInterval);
         reshapeImpl(gl, x, y, width, height, width, height);
     }
 
index 2d67455..e360b59 100644 (file)
@@ -230,9 +230,7 @@ public class TextureDraw02ES2ListenerFBO implements GLEventListener {
     public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
         final GL2ES2 gl = drawable.getGL().getGL2ES2();
 
-        if(-1 != swapInterval) {
-            gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
-        }
+        gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
 
         System.err.println("**** Reshape.Reset: "+width+"x"+height);
         if( keepTextureBound ) {
index b938adb..5259951 100644 (file)
@@ -46,6 +46,7 @@ import com.jogamp.graph.curve.Region;
 import com.jogamp.graph.curve.opengl.GLRegion;
 import com.jogamp.graph.curve.opengl.RegionRenderer;
 import com.jogamp.graph.font.Font;
+import com.jogamp.junit.util.JunitTracer;
 import com.jogamp.newt.Window;
 import com.jogamp.newt.event.KeyAdapter;
 import com.jogamp.newt.event.KeyEvent;
@@ -57,7 +58,6 @@ import com.jogamp.opengl.JoglVersion;
 import com.jogamp.opengl.test.junit.graph.TextRendererGLELBase;
 import com.jogamp.opengl.test.junit.jogl.demos.es2.TextureSequenceCubeES2;
 import com.jogamp.opengl.test.junit.util.MiscUtils;
-import com.jogamp.opengl.test.junit.util.UITestCase;
 import com.jogamp.opengl.util.Animator;
 import com.jogamp.opengl.util.av.GLMediaPlayer;
 import com.jogamp.opengl.util.av.GLMediaPlayer.GLMediaEventListener;
@@ -75,7 +75,7 @@ public class MovieCube implements GLEventListener {
     private TextureSequenceCubeES2 cube=null;
     private GLMediaPlayer mPlayer=null;
     private int swapInterval = 1;
-    private int swapIntervalSet = -1;
+    private boolean swapIntervalSet = true;
     private long lastPerfPos = 0;
     private volatile boolean resetGLState = false;
 
@@ -246,7 +246,7 @@ public class MovieCube implements GLEventListener {
             final String text1 = String.format("%0"+ptsPrec+"f/%0"+ptsPrec+"f s, %s (%01.2fx, vol %01.2f), a %01.2f, fps %02.1f -> %02.1f / %02.1f, v-sync %d",
                     pts, mPlayer.getDuration() / 1000f,
                     mPlayer.getState().toString().toLowerCase(), mPlayer.getPlaySpeed(), mPlayer.getAudioVolume(),
-                    aspect, mPlayer.getFramerate(), lfps, tfps, swapIntervalSet);
+                    aspect, mPlayer.getFramerate(), lfps, tfps, swapInterval);
             final String text2 = String.format("audio: id %d, kbps %d, codec %s",
                     mPlayer.getAID(), mPlayer.getAudioBitrate()/1000, mPlayer.getAudioCodec());
             final String text3 = String.format("video: id %d, kbps %d, codec %s",
@@ -278,10 +278,13 @@ public class MovieCube implements GLEventListener {
             int pts1 = 0;
             switch(e.getKeySymbol()) {
                 case KeyEvent.VK_V: {
-                    switch(swapIntervalSet) {
-                        case 0: swapInterval = 1; break;
-                        default: swapInterval = 0; break;
+                    switch(swapInterval) {
+                        case  0: swapInterval = -1; break;
+                        case -1: swapInterval =  1; break;
+                        case  1: swapInterval =  0; break;
+                        default: swapInterval =  1; break;
                     }
+                    swapIntervalSet = true;
                     break;
                 }
                 case KeyEvent.VK_O:          displayOSD = !displayOSD; break;
@@ -362,7 +365,7 @@ public class MovieCube implements GLEventListener {
         cube = new TextureSequenceCubeES2(mPlayer, false, zoom0, rotx, roty);
 
         if(waitForKey) {
-            UITestCase.waitForKey("Init>");
+            JunitTracer.waitForKey("Init>");
         }
 
         if( GLMediaPlayer.State.Initialized == mPlayer.getState() ) {
@@ -433,12 +436,14 @@ public class MovieCube implements GLEventListener {
 
     @Override
     public void display(final GLAutoDrawable drawable) {
-        if(-1 != swapInterval) {
+        if( swapIntervalSet ) {
             final GL2ES2 gl = drawable.getGL().getGL2ES2();
-            gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
+            final int _swapInterval = swapInterval;
+            gl.setSwapInterval(_swapInterval); // in case switching the drawable (impl. may bound attribute there)
             drawable.getAnimator().resetFPSCounter();
-            swapIntervalSet = swapInterval;
-            swapInterval = -1;
+            swapInterval = gl.getSwapInterval();
+            System.err.println("Swap Interval: "+_swapInterval+" -> "+swapInterval);
+            swapIntervalSet = false;
         }
         if(null == mPlayer) { return; }
 
index 22dfa92..ac5d298 100644 (file)
@@ -51,6 +51,7 @@ import com.jogamp.graph.curve.Region;
 import com.jogamp.graph.curve.opengl.GLRegion;
 import com.jogamp.graph.curve.opengl.RegionRenderer;
 import com.jogamp.graph.font.Font;
+import com.jogamp.junit.util.JunitTracer;
 import com.jogamp.newt.Window;
 import com.jogamp.newt.event.KeyAdapter;
 import com.jogamp.newt.event.KeyEvent;
@@ -65,7 +66,6 @@ import com.jogamp.opengl.GLExtensions;
 import com.jogamp.opengl.JoglVersion;
 import com.jogamp.opengl.test.junit.graph.TextRendererGLELBase;
 import com.jogamp.opengl.test.junit.util.MiscUtils;
-import com.jogamp.opengl.test.junit.util.UITestCase;
 import com.jogamp.opengl.util.Animator;
 import com.jogamp.opengl.util.GLArrayDataServer;
 import com.jogamp.opengl.util.PMVMatrix;
@@ -105,7 +105,7 @@ public class MovieSimple implements GLEventListener {
     private int effects = EFFECT_NORMAL;
     private float alpha = 1.0f;
     private int swapInterval = 1;
-    private int swapIntervalSet = -1;
+    private boolean swapIntervalSet = true;
 
     private GLMediaPlayer mPlayer;
     private final boolean mPlayerShared;
@@ -265,10 +265,13 @@ public class MovieSimple implements GLEventListener {
             int pts1 = 0;
             switch(e.getKeySymbol()) {
                 case KeyEvent.VK_V: {
-                    switch(swapIntervalSet) {
-                        case 0: swapInterval = 1; break;
-                        default: swapInterval = 0; break;
+                    switch(swapInterval) {
+                        case  0: swapInterval = -1; break;
+                        case -1: swapInterval =  1; break;
+                        case  1: swapInterval =  0; break;
+                        default: swapInterval =  1; break;
                     }
+                    swapIntervalSet = true;
                     break;
                 }
                 case KeyEvent.VK_O:          displayOSD = !displayOSD; break;
@@ -483,7 +486,7 @@ public class MovieSimple implements GLEventListener {
                            ", "+drawable.getClass().getName()+", "+drawable);
 
         if(waitForKey) {
-            UITestCase.waitForKey("Init>");
+            JunitTracer.waitForKey("Init>");
         }
         final Texture tex;
         try {
@@ -736,11 +739,13 @@ public class MovieSimple implements GLEventListener {
     @Override
     public void display(final GLAutoDrawable drawable) {
         final GL2ES2 gl = drawable.getGL().getGL2ES2();
-        if(-1 != swapInterval) {
-            gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there)
+        if( swapIntervalSet ) {
+            final int _swapInterval = swapInterval;
+            gl.setSwapInterval(_swapInterval); // in case switching the drawable (impl. may bound attribute there)
             drawable.getAnimator().resetFPSCounter();
-            swapIntervalSet = swapInterval;
-            swapInterval = -1;
+            swapInterval = gl.getSwapInterval();
+            System.err.println("Swap Interval: "+_swapInterval+" -> "+swapInterval);
+            swapIntervalSet = false;
         }
         if(null == mPlayer) { return; }
 
index c2761f6..a144ff1 100644 (file)
@@ -230,9 +230,7 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList
   public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) {
       if( !isInit ) { return; }
       final GL2 gl = glad.getGL().getGL2();
-      if(-1 != swapInterval) {
-          gl.setSwapInterval(swapInterval);
-      }
+      gl.setSwapInterval(swapInterval);
       reshape(gl, x, y, width, height, width, height);
   }
 
index 68a983a..3e0b7c7 100644 (file)
@@ -39,6 +39,11 @@ import com.jogamp.newt.event.KeyListener;
 import com.jogamp.newt.event.MouseAdapter;
 import com.jogamp.newt.event.MouseEvent;
 import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.FPSCounter;
+import com.jogamp.opengl.GL;
+import com.jogamp.opengl.GLAnimatorControl;
+import com.jogamp.opengl.GLAutoDrawable;
+import com.jogamp.opengl.GLRunnable;
 import com.jogamp.opengl.util.Gamma;
 import com.jogamp.opengl.util.PNGPixelRect;
 
@@ -290,29 +295,57 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener {
                 break;
             case KeyEvent.VK_V:
                 e.setConsumed(true);
-                new Thread() {
-                    public void run() {
-                        final boolean wasVisible = glWindow.isVisible();
-                        {
-                            final Thread t = glWindow.setExclusiveContextThread(null);
-                            printlnState("[set visible pre]");
-                            glWindow.setVisible(!wasVisible);
-                            printlnState("[set visible post]");
-                            glWindow.setExclusiveContextThread(t);
-                        }
-                        if( wasVisible && !e.isControlDown() ) {
-                            try {
-                                Thread.sleep(5000);
-                            } catch (final InterruptedException e) {
-                                e.printStackTrace();
+                if( e.isControlDown() ) {
+                    glWindow.invoke(false, new GLRunnable() {
+                        @Override
+                        public boolean run(final GLAutoDrawable drawable) {
+                            final GL gl = drawable.getGL();
+                            final int _i = gl.getSwapInterval();
+                            final int i;
+                            switch(_i) {
+                                case  0: i = -1; break;
+                                case -1: i =  1; break;
+                                case  1: i =  0; break;
+                                default: i =  1; break;
                             }
-                            final Thread t = glWindow.setExclusiveContextThread(null);
-                            printlnState("[reset visible pre]");
-                            glWindow.setVisible(true);
-                            printlnState("[reset visible post]");
-                            glWindow.setExclusiveContextThread(t);
+                            gl.setSwapInterval(i);
+
+                            final GLAnimatorControl a = drawable.getAnimator();
+                            if( null != a ) {
+                                a.resetFPSCounter();
+                            }
+                            if(drawable instanceof FPSCounter) {
+                                ((FPSCounter)drawable).resetFPSCounter();
+                            }
+                            System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval());
+                            return true;
                         }
-                } }.start();
+                    });
+                } else {
+                    new Thread() {
+                        public void run() {
+                            final boolean wasVisible = glWindow.isVisible();
+                            {
+                                final Thread t = glWindow.setExclusiveContextThread(null);
+                                printlnState("[set visible pre]");
+                                glWindow.setVisible(!wasVisible);
+                                printlnState("[set visible post]");
+                                glWindow.setExclusiveContextThread(t);
+                            }
+                            if( wasVisible && !e.isControlDown() ) {
+                                try {
+                                    Thread.sleep(5000);
+                                } catch (final InterruptedException e) {
+                                    e.printStackTrace();
+                                }
+                                final Thread t = glWindow.setExclusiveContextThread(null);
+                                printlnState("[reset visible pre]");
+                                glWindow.setVisible(true);
+                                printlnState("[reset visible post]");
+                                glWindow.setExclusiveContextThread(t);
+                            }
+                    } }.start();
+                }
                 break;
             case KeyEvent.VK_W:
                 e.setConsumed(true);
http://JogAmp.org git info: FAQ, tutorial and man pages.