diff options
author | Sven Gothel <[email protected]> | 2015-08-27 13:15:44 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-08-27 13:15:44 +0200 |
commit | deff49c901915e007f43a1df1a0d217a786e9f06 (patch) | |
tree | 46b5c4ed38772c1f5d32498904da9318b3ecab83 /src/jogl/classes/jogamp | |
parent | 8b4f68a3a014c3ae62a64def3011ccc43e8c41c9 (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')
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) { |