diff --git a/examples/windowsize/main.go b/examples/windowsize/main.go index addf12e72..7039c247b 100644 --- a/examples/windowsize/main.go +++ b/examples/windowsize/main.go @@ -61,6 +61,7 @@ var ( flagAutoAdjusting = flag.Bool("autoadjusting", false, "make the game screen auto-adjusting") flagFloating = flag.Bool("floating", false, "make the window floating") flagMaximize = flag.Bool("maximize", false, "maximize the window") + flagVsync = flag.Bool("vsync", true, "enable vsync") ) func init() { @@ -409,6 +410,7 @@ func main() { ebiten.SetWindowResizable(true) ebiten.MaximizeWindow() } + ebiten.SetVsyncEnabled(*flagVsync) if *flagAutoAdjusting { if *flagLegacy { log.Println("-autoadjusting flag cannot work with -legacy flag") diff --git a/internal/uidriver/glfw/ui.go b/internal/uidriver/glfw/ui.go index c991c43e5..b84983841 100644 --- a/internal/uidriver/glfw/ui.go +++ b/internal/uidriver/glfw/ui.go @@ -57,6 +57,7 @@ type UserInterface struct { initMonitor *glfw.Monitor initTitle string + initVsync bool initFullscreenWidthInDP int initFullscreenHeightInDP int initFullscreen bool @@ -72,6 +73,8 @@ type UserInterface struct { initScreenTransparent bool initIconImages []image.Image + vsyncInited bool + reqWidth int reqHeight int @@ -92,13 +95,13 @@ var ( theUI = &UserInterface{ origPosX: invalidPos, origPosY: invalidPos, + initVsync: true, initCursorMode: driver.CursorModeVisible, initWindowDecorated: true, initWindowPositionXInDP: invalidPos, initWindowPositionYInDP: invalidPos, initWindowWidthInDP: 640, initWindowHeightInDP: 480, - vsync: true, } ) @@ -216,6 +219,13 @@ func (u *UserInterface) setInitTitle(title string) { u.m.RUnlock() } +func (u *UserInterface) isInitVsyncEnabled() bool { + u.m.RLock() + v := u.initVsync + u.m.RUnlock() + return v +} + func (u *UserInterface) isInitFullscreen() bool { u.m.RLock() v := u.initFullscreen @@ -428,7 +438,7 @@ func (u *UserInterface) SetFullscreen(fullscreen bool) { w, h = u.windowWidth, u.windowHeight return nil }) - u.setWindowSize(w, h, fullscreen, u.vsync) + u.setWindowSize(w, h, fullscreen) } func (u *UserInterface) IsFocused() bool { @@ -459,23 +469,37 @@ func (u *UserInterface) SetVsyncEnabled(enabled bool) { // it should be OK since any goroutines can't reach here when // the game already starts and setWindowSize can be called. u.m.Lock() - u.vsync = enabled + u.initVsync = enabled u.m.Unlock() return } - var w, h int _ = u.t.Call(func() error { - w, h = u.windowWidth, u.windowHeight + if !u.vsyncInited { + u.m.Lock() + u.initVsync = enabled + u.m.Unlock() + return nil + } + u.vsync = enabled + u.updateVsync() return nil }) - u.setWindowSize(w, h, u.isFullscreen(), enabled) } func (u *UserInterface) IsVsyncEnabled() bool { - u.m.RLock() - r := u.vsync - u.m.RUnlock() - return r + if !u.isRunning() { + return u.isInitVsyncEnabled() + } + var v bool + _ = u.t.Call(func() error { + if !u.vsyncInited { + v = u.isInitVsyncEnabled() + return nil + } + v = u.vsync + return nil + }) + return v } func (u *UserInterface) CursorMode() driver.CursorMode { @@ -691,7 +715,7 @@ func (u *UserInterface) run() error { ww, wh := u.getInitWindowSize() ww = int(u.toDeviceDependentPixel(float64(ww))) wh = int(u.toDeviceDependentPixel(float64(wh))) - u.setWindowSize(ww, wh, u.isFullscreen(), u.vsync) + u.setWindowSize(ww, wh, u.isFullscreen()) } // Set the window size and the window position in this order on Linux or other UNIX using X (#1118), @@ -737,7 +761,7 @@ func (u *UserInterface) updateSize() { w, h = u.windowWidth, u.windowHeight return nil }) - u.setWindowSize(w, h, u.isFullscreen(), u.vsync) + u.setWindowSize(w, h, u.isFullscreen()) sizeChanged := false _ = u.t.Call(func() error { @@ -787,7 +811,7 @@ func (u *UserInterface) update() error { w, h = u.window.GetSize() return nil }) - u.setWindowSize(w, h, true, u.vsync) + u.setWindowSize(w, h, true) u.setInitFullscreen(false) } @@ -827,7 +851,7 @@ func (u *UserInterface) update() error { return nil }) if w != 0 || h != 0 { - u.setWindowSize(w, h, u.isFullscreen(), u.vsync) + u.setWindowSize(w, h, u.isFullscreen()) } _ = u.t.Call(func() error { u.reqWidth = 0 @@ -890,11 +914,11 @@ func (u *UserInterface) swapBuffers() { } } -func (u *UserInterface) setWindowSize(width, height int, fullscreen bool, vsync bool) { +func (u *UserInterface) setWindowSize(width, height int, fullscreen bool) { windowRecreated := false _ = u.t.Call(func() error { - if u.windowWidth == width && u.windowHeight == height && u.isFullscreen() == fullscreen && u.vsync == vsync && u.lastDeviceScaleFactor == u.deviceScaleFactor() { + if u.windowWidth == width && u.windowHeight == height && u.isFullscreen() == fullscreen && u.lastDeviceScaleFactor == u.deviceScaleFactor() { return nil } @@ -905,7 +929,6 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool, vsync height = 1 } - u.vsync = vsync u.lastDeviceScaleFactor = u.deviceScaleFactor() // To make sure the current existing framebuffers are rendered, @@ -1007,21 +1030,12 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool, vsync u.windowWidth = width u.windowHeight = height - if u.Graphics().IsGL() { - // SwapInterval is affected by the current monitor of the window. - // This needs to be called at least after SetMonitor. - // Without SwapInterval after SetMonitor, vsynch doesn't work (#375). - // - // TODO: (#405) If triple buffering is needed, SwapInterval(0) should be called, - // but is this correct? If glfw.SwapInterval(0) and the driver doesn't support triple - // buffering, what will happen? - if u.vsync { - glfw.SwapInterval(1) - } else { - glfw.SwapInterval(0) - } + if !u.vsyncInited { + // Initialize vsync after SetMonitor is called. See the comment in updateVsync. + u.vsync = u.isInitVsyncEnabled() + u.updateVsync() + u.vsyncInited = true } - u.Graphics().SetVsyncEnabled(vsync) u.toChangeSize = true return nil @@ -1034,6 +1048,25 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool, vsync } } +// updateVsync must be called on the main thread. +func (u *UserInterface) updateVsync() { + if u.Graphics().IsGL() { + // SwapInterval is affected by the current monitor of the window. + // This needs to be called at least after SetMonitor. + // Without SwapInterval after SetMonitor, vsynch doesn't work (#375). + // + // TODO: (#405) If triple buffering is needed, SwapInterval(0) should be called, + // but is this correct? If glfw.SwapInterval(0) and the driver doesn't support triple + // buffering, what will happen? + if u.vsync { + glfw.SwapInterval(1) + } else { + glfw.SwapInterval(0) + } + } + u.Graphics().SetVsyncEnabled(u.vsync) +} + // currentMonitor returns the monitor most suitable with the current window. // // currentMonitor must be called on the main thread. diff --git a/internal/uidriver/glfw/window.go b/internal/uidriver/glfw/window.go index 8f410739c..8f0b95349 100644 --- a/internal/uidriver/glfw/window.go +++ b/internal/uidriver/glfw/window.go @@ -238,7 +238,7 @@ func (w *window) SetSize(width, height int) { } ww := int(w.ui.toDeviceDependentPixel(float64(width))) wh := int(w.ui.toDeviceDependentPixel(float64(height))) - w.ui.setWindowSize(ww, wh, w.ui.isFullscreen(), w.ui.vsync) + w.ui.setWindowSize(ww, wh, w.ui.isFullscreen()) } func (w *window) SetIcon(iconImages []image.Image) {