diff --git a/src/org/lwjgl/opengl/awt/AWTGLCanvas.java b/src/org/lwjgl/opengl/awt/AWTGLCanvas.java index bbad65a..c80bd07 100644 --- a/src/org/lwjgl/opengl/awt/AWTGLCanvas.java +++ b/src/org/lwjgl/opengl/awt/AWTGLCanvas.java @@ -151,6 +151,10 @@ public final void swapBuffers() { platformCanvas.swapBuffers(); } + public final void setSwapInterval(int interval) { + platformCanvas.setSwapInterval(interval); + } + /** * Returns Graphics object that ignores {@link Graphics#clearRect(int, int, int, int)} * calls. diff --git a/src/org/lwjgl/opengl/awt/PlatformGLCanvas.java b/src/org/lwjgl/opengl/awt/PlatformGLCanvas.java index 9410d29..0da4235 100644 --- a/src/org/lwjgl/opengl/awt/PlatformGLCanvas.java +++ b/src/org/lwjgl/opengl/awt/PlatformGLCanvas.java @@ -14,6 +14,7 @@ public interface PlatformGLCanvas { boolean makeCurrent(long context); boolean isCurrent(long context); boolean swapBuffers(); + void setSwapInterval(int interval); boolean delayBeforeSwapNV(float seconds); void lock() throws AWTException; void unlock() throws AWTException; diff --git a/src/org/lwjgl/opengl/awt/PlatformLinuxGLCanvas.java b/src/org/lwjgl/opengl/awt/PlatformLinuxGLCanvas.java index 27e388a..2944725 100644 --- a/src/org/lwjgl/opengl/awt/PlatformLinuxGLCanvas.java +++ b/src/org/lwjgl/opengl/awt/PlatformLinuxGLCanvas.java @@ -4,6 +4,7 @@ import static org.lwjgl.system.MemoryUtil.*; import static org.lwjgl.opengl.GLX.*; import static org.lwjgl.opengl.GLX13.*; +import static org.lwjgl.opengl.GLXEXTSwapControl.*; import static org.lwjgl.opengl.GLXARBCreateContext.*; import static org.lwjgl.opengl.GLXARBCreateContextProfile.*; import static org.lwjgl.opengl.GLXARBCreateContextRobustness.*; @@ -14,7 +15,8 @@ import java.awt.Canvas; import java.nio.IntBuffer; import java.util.Arrays; -import java.util.List; +import java.util.Collection; +import java.util.HashSet; import java.util.Objects; import org.lwjgl.BufferUtils; @@ -49,9 +51,14 @@ public class PlatformLinuxGLCanvas implements PlatformGLCanvas { public long display; public long drawable; public JAWTDrawingSurface ds; + public Collection extensions; + public boolean has_GLX_EXT_swap_control, has_GLX_EXT_swap_control_tear; private long create(int depth, GLData attribs, GLData effective) throws AWTException { int screen = X11.XDefaultScreen(display); + extensions = new HashSet(Arrays.asList(glXQueryExtensionsString(display, screen).split(" "))); + has_GLX_EXT_swap_control = extensions.contains("GLX_EXT_swap_control"); + has_GLX_EXT_swap_control_tear = extensions.contains("GLX_EXT_swap_control_tear"); IntBuffer attrib_list = BufferUtils.createIntBuffer(16 * 2); attrib_list.put(GLX_DRAWABLE_TYPE).put(GLX_WINDOW_BIT); attrib_list.put(GLX_RENDER_TYPE).put(GLX_RGBA_BIT); @@ -149,6 +156,14 @@ public boolean swapBuffers() { return true; } + public void setSwapInterval(int interval) { + if(has_GLX_EXT_swap_control) { + if(interval < 0 && !has_GLX_EXT_swap_control_tear) + interval = -interval; + glXSwapIntervalEXT(display, drawable, interval); + } + } + public boolean delayBeforeSwapNV(float seconds) { throw new UnsupportedOperationException("NYI"); } @@ -160,8 +175,7 @@ public void dispose() { } } - private static void verifyGLXCapabilities(long display, int screen, GLData data) throws AWTException { - List extensions = Arrays.asList(glXQueryExtensionsString(display, screen).split(" ")); + private void verifyGLXCapabilities(long display, int screen, GLData data) throws AWTException { if (!extensions.contains("GLX_ARB_create_context")) { throw new AWTException("GLX_ARB_create_context is unavailable"); } diff --git a/src/org/lwjgl/opengl/awt/PlatformMacOSXGLCanvas.java b/src/org/lwjgl/opengl/awt/PlatformMacOSXGLCanvas.java index cf866c5..561c4ec 100644 --- a/src/org/lwjgl/opengl/awt/PlatformMacOSXGLCanvas.java +++ b/src/org/lwjgl/opengl/awt/PlatformMacOSXGLCanvas.java @@ -335,6 +335,11 @@ public boolean swapBuffers() { return true; } + @Override + public void setSwapInterval(int interval) { + /* XXX: How does this work on MacOS? */ + } + @Override public boolean deleteContext(long context) { // frees created NSOpenGLView diff --git a/src/org/lwjgl/opengl/awt/PlatformWin32GLCanvas.java b/src/org/lwjgl/opengl/awt/PlatformWin32GLCanvas.java index 35f8838..ec2ce23 100644 --- a/src/org/lwjgl/opengl/awt/PlatformWin32GLCanvas.java +++ b/src/org/lwjgl/opengl/awt/PlatformWin32GLCanvas.java @@ -56,6 +56,8 @@ public class PlatformWin32GLCanvas implements PlatformGLCanvas { } public long hwnd; + public long wglSwapIntervalEXTAddr = 0L; + public boolean has_WGL_EXT_swap_control_tear = false; public long wglDelayBeforeSwapNVAddr = 0L; public boolean wglDelayBeforeSwapNVAddr_set = false; public JAWTDrawingSurface ds; @@ -158,7 +160,7 @@ public long create(Canvas canvas, GLData attribs, GLData effective) throws AWTEx } } - private static long create(MemoryStack stack, long windowHandle, long dummyWindowHandle, GLData attribs, GLData effective) throws AWTException { + private long create(MemoryStack stack, long windowHandle, long dummyWindowHandle, GLData attribs, GLData effective) throws AWTException { long bufferAddr = stack.nmalloc(4, (4*2) << 2); // Validate context attributes @@ -252,6 +254,11 @@ private static long create(MemoryStack stack, long windowHandle, long dummyWindo throw new AWTException("Could not release dummy DC"); } + if (wglExtensionsList.contains("WGL_EXT_swap_control")) { + this.wglSwapIntervalEXTAddr = wglGetProcAddress("wglSwapIntervalEXT"); + this.has_WGL_EXT_swap_control_tear = wglExtensionsList.contains("WGL_EXT_swap_control_tear"); + } + // For some constellations of context attributes, we can stop right here. if (!atLeast30(attribs.majorVersion, attribs.minorVersion) && attribs.samples == 0 && !attribs.sRGB && !attribs.pixelFormatFloat && attribs.contextReleaseBehavior == null && !attribs.robustness && attribs.api != API.GLES) { @@ -267,8 +274,7 @@ private static long create(MemoryStack stack, long windowHandle, long dummyWindo long context = wglCreateContext(hDC); if (attribs.swapInterval != null) { - boolean has_WGL_EXT_swap_control = wglExtensionsList.contains("WGL_EXT_swap_control"); - if (!has_WGL_EXT_swap_control) { + if (wglSwapIntervalEXTAddr == 0) { ReleaseDC(windowHandle, hDC); wglMakeCurrent(currentDc, currentContext); wglDeleteContext(context); @@ -276,7 +282,6 @@ private static long create(MemoryStack stack, long windowHandle, long dummyWindo } if (attribs.swapInterval < 0) { // Only allowed if WGL_EXT_swap_control_tear is available - boolean has_WGL_EXT_swap_control_tear = wglExtensionsList.contains("WGL_EXT_swap_control_tear"); if (!has_WGL_EXT_swap_control_tear) { ReleaseDC(windowHandle, hDC); wglMakeCurrent(currentDc, currentContext); @@ -292,10 +297,7 @@ private static long create(MemoryStack stack, long windowHandle, long dummyWindo wglDeleteContext(context); throw new AWTException("Could not make GL context current"); } - long wglSwapIntervalEXTAddr = wglGetProcAddress("wglSwapIntervalEXT"); - if (wglSwapIntervalEXTAddr != 0L) { - callI(attribs.swapInterval, wglSwapIntervalEXTAddr); - } + callI(attribs.swapInterval, wglSwapIntervalEXTAddr); } if (attribs.swapGroupNV > 0 || attribs.swapBarrierNV > 0) { @@ -611,8 +613,7 @@ else if (attribs.contextReleaseBehavior == ReleaseBehavior.FLUSH) // Make context current for next operations wglMakeCurrent(hDC, newCtx); if (attribs.swapInterval != null) { - boolean has_WGL_EXT_swap_control = wglExtensionsList.contains("WGL_EXT_swap_control"); - if (!has_WGL_EXT_swap_control) { + if (wglSwapIntervalEXTAddr == 0) { ReleaseDC(windowHandle, hDC); wglMakeCurrent(currentDc, currentContext); wglDeleteContext(newCtx); @@ -620,7 +621,6 @@ else if (attribs.contextReleaseBehavior == ReleaseBehavior.FLUSH) } if (attribs.swapInterval < 0) { // Only allowed if WGL_EXT_swap_control_tear is available - boolean has_WGL_EXT_swap_control_tear = wglExtensionsList.contains("WGL_EXT_swap_control_tear"); if (!has_WGL_EXT_swap_control_tear) { ReleaseDC(windowHandle, hDC); wglMakeCurrent(currentDc, currentContext); @@ -628,10 +628,7 @@ else if (attribs.contextReleaseBehavior == ReleaseBehavior.FLUSH) throw new AWTException("Negative swap interval requested but WGL_EXT_swap_control_tear is unavailable"); } } - long wglSwapIntervalEXTAddr = wglGetProcAddress("wglSwapIntervalEXT"); - if (wglSwapIntervalEXTAddr != 0L) { - callI(attribs.swapInterval, wglSwapIntervalEXTAddr); - } + callI(attribs.swapInterval, wglSwapIntervalEXTAddr); } if (attribs.swapGroupNV > 0 || attribs.swapBarrierNV > 0) { // Only allowed if WGL_NV_swap_group is available @@ -770,6 +767,15 @@ public boolean swapBuffers() { return ret; } + @Override + public void setSwapInterval(int interval) { + if (wglSwapIntervalEXTAddr != 0) { + if (interval < 0 && !has_WGL_EXT_swap_control_tear) + interval = -interval; + callI(interval, wglSwapIntervalEXTAddr); + } + } + @Override public boolean delayBeforeSwapNV(float seconds) { if (!wglDelayBeforeSwapNVAddr_set) {