diff --git a/src/windy/platforms/linux/x11.nim b/src/windy/platforms/linux/x11.nim index 5f84b366..d87d678c 100644 --- a/src/windy/platforms/linux/x11.nim +++ b/src/windy/platforms/linux/x11.nim @@ -47,6 +47,7 @@ type innerDecorated: bool innerFocused: bool mouseCaptured: bool + vsyncEnabled: bool # XDnD state xdndSource: XWindow @@ -406,6 +407,34 @@ proc makeContextCurrent*(window: Window) = proc swapBuffers*(window: Window) = display.glXSwapBuffers(window.handle) +proc applyVsync(window: Window, enabled: bool) = + window.makeContextCurrent() + let interval = if enabled: 1.cint else: 0.cint + if glXSwapIntervalEXT != nil: + display.glXSwapIntervalEXT(window.handle, interval) + elif glXSwapIntervalMESA != nil: + if glXSwapIntervalMESA(interval) != 0: + raise WindyError.newException("Error setting the GLX swap interval") + elif glXSwapIntervalSGI != nil: + if not enabled: + raise WindyError.newException( + "Disabling VSync is not supported by GLX_SGI_swap_control" + ) + if glXSwapIntervalSGI(interval) != 0: + raise WindyError.newException("Error setting the GLX swap interval") + else: + raise WindyError.newException("VSync control is not supported") + window.vsyncEnabled = enabled + +proc vsync*(window: Window): bool = + ## Returns true when vertical sync is enabled for this window. + window.vsyncEnabled + +proc `vsync=`*(window: Window, enabled: bool) = + ## Changes the GLX swap interval without recreating the window. + if window.vsyncEnabled != enabled: + window.applyVsync(enabled) + template blockUntil(expression: untyped) {.dirty.} = ## In X11 many properties are async, you change them and then it takes ## time for them to take effect. This is different from Win/Mac. This @@ -819,15 +848,7 @@ proc newWindow*( makeContextCurrent result - if vsync: - if glXSwapIntervalEXT != nil: - display.glXSwapIntervalEXT(result.handle, 1) - elif glXSwapIntervalMESA != nil: - glXSwapIntervalMESA(1) - elif glXSwapIntervalSGI != nil: - glXSwapIntervalSGI(1) - else: - raise WindyError.newException("VSync is not supported") + result.applyVsync(vsync) if visible: result.visible = true diff --git a/src/windy/platforms/linux/x11/glx.nim b/src/windy/platforms/linux/x11/glx.nim index b626244f..39b7719d 100644 --- a/src/windy/platforms/linux/x11/glx.nim +++ b/src/windy/platforms/linux/x11/glx.nim @@ -30,5 +30,5 @@ proc glXSwapBuffers*(d: Display, drawable: Drawable) {.libglx.} proc glXSwapIntervalEXT*(d: Display, drawable: Drawable, interval: cint) {.libglx.} -proc glXSwapIntervalMESA*(interval: cint) {.libglx.} -proc glXSwapIntervalSGI*(interval: cint) {.libglx.} +proc glXSwapIntervalMESA*(interval: cint): cint {.libglx.} +proc glXSwapIntervalSGI*(interval: cint): cint {.libglx.} diff --git a/src/windy/platforms/macos/platform.nim b/src/windy/platforms/macos/platform.nim index 8741e70a..6dafa492 100644 --- a/src/windy/platforms/macos/platform.nim +++ b/src/windy/platforms/macos/platform.nim @@ -41,6 +41,7 @@ type minimizedState: bool cpuImage: NSImage activationSettlePolls: int + vsyncEnabled: bool const ActivationSettlePolls = 60 @@ -1090,6 +1091,23 @@ proc swapBuffers*(window: Window) = else: window.inner.contentView.NSOpenGLView.openGLContext.flushBuffer() +proc vsync*(window: Window): bool = + ## Returns true when vertical sync is enabled for this window. + window.vsyncEnabled + +proc `vsync=`*(window: Window, enabled: bool) = + ## Changes the OpenGL swap interval without recreating the window. + if window.vsyncEnabled == enabled: + return + when not defined(useMetal4) and not defined(useCpu): + window.makeContextCurrent() + var swapInterval: GLint = if enabled: 1 else: 0 + window.inner.contentView.NSOpenGLView.openGLContext.setValues( + swapInterval.addr, + NSOpenGLContextParameterSwapInterval + ) + window.vsyncEnabled = enabled + proc presentPixels*(window: Window, image: Image) = ## Presents a CPU-rendered Pixie image into the macOS window content view. when defined(useCpu): @@ -1142,6 +1160,7 @@ proc newWindow*( stencilBits = 8 ): Window = result = Window() + result.vsyncEnabled = vsync init() diff --git a/src/windy/platforms/win32/platform.nim b/src/windy/platforms/win32/platform.nim index e8486f8b..ecece3f6 100644 --- a/src/windy/platforms/win32/platform.nim +++ b/src/windy/platforms/win32/platform.nim @@ -84,7 +84,7 @@ type hdc: HDC hglrc: HGLRC cpuPresentBuffer: seq[uint8] - vsync*: bool + vsyncEnabled: bool iconHandle: HICON customCursor: HCURSOR @@ -1339,7 +1339,7 @@ proc newWindow*( result.title = title result.hWnd = createWindow(windowClassName, title) result.size = size - result.vsync = vsync + result.vsyncEnabled = vsync discard SetPropW(result.hWnd, cast[ptr WCHAR](windowPropKey[0].addr), 1) @@ -1366,7 +1366,17 @@ proc title*(window: Window): string = proc vsync*(window: Window): bool = ## Returns true when vertical sync is enabled for this window. - window.vsync + window.vsyncEnabled + +proc `vsync=`*(window: Window, enabled: bool) = + ## Changes the OpenGL swap interval without recreating the window. + if window.vsyncEnabled == enabled: + return + when not defined(useDirectX) and not defined(useVulkan) and not defined(useCpu): + window.makeContextCurrent() + if wglSwapIntervalEXT(if enabled: 1 else: 0) == 0: + raise newException(WindyError, "Error setting swap interval") + window.vsyncEnabled = enabled proc icon*(window: Window): Image = window.state.icon diff --git a/tests/test.nim b/tests/test.nim index 7a5fffe1..e547f330 100644 --- a/tests/test.nim +++ b/tests/test.nim @@ -1 +1,5 @@ import windy + +proc checkVsyncApi(window: Window) {.used.} = + window.vsync = false + discard window.vsync