aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2015-08-27 13:15:44 +0200
committerSven Gothel <[email protected]>2015-08-27 13:15:44 +0200
commitdeff49c901915e007f43a1df1a0d217a786e9f06 (patch)
tree46b5c4ed38772c1f5d32498904da9318b3ecab83 /src/jogl/classes/jogamp
parent8b4f68a3a014c3ae62a64def3011ccc43e8c41c9 (diff)
Bug 1202 - Add support of Adaptive Vsync via [GLX|WGL]_EXT_swap_control_tear
[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 +++
Diffstat (limited to 'src/jogl/classes/jogamp')
-rw-r--r--src/jogl/classes/jogamp/opengl/GLContextImpl.java31
-rw-r--r--src/jogl/classes/jogamp/opengl/GLXExtensions.java6
-rw-r--r--src/jogl/classes/jogamp/opengl/egl/EGLContext.java16
-rw-r--r--src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java13
-rw-r--r--src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java45
-rw-r--r--src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java77
6 files changed, 145 insertions, 43 deletions
diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java
index fa7aeaff8..39c5796f3 100644
--- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java
@@ -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.
diff --git a/src/jogl/classes/jogamp/opengl/GLXExtensions.java b/src/jogl/classes/jogamp/opengl/GLXExtensions.java
index 9325c6f68..db4757e4d 100644
--- a/src/jogl/classes/jogamp/opengl/GLXExtensions.java
+++ b/src/jogl/classes/jogamp/opengl/GLXExtensions.java
@@ -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";
}
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java
index b6a05aeeb..b64bb375a 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java
@@ -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)
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
index d4fc0b005..2f88e7619 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
@@ -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
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java
index a8269ad5c..6ff8c57c8 100644
--- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java
+++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java
@@ -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) {
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java
index 63b0b35c0..3f856e4f8 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java
@@ -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) {