diff --git a/internal/driver/graphics.go b/internal/driver/graphics.go index 7c96b4851..40fd4931e 100644 --- a/internal/driver/graphics.go +++ b/internal/driver/graphics.go @@ -47,6 +47,7 @@ type Graphics interface { NewScreenFramebufferImage(width, height int) (Image, error) Initialize() error SetVsyncEnabled(enabled bool) + SetFullscreen(fullscreen bool) FramebufferYDirection() YDirection NeedsRestoring() bool NeedsClearingScreen() bool diff --git a/internal/graphicsdriver/metal/graphics.go b/internal/graphicsdriver/metal/graphics.go index 30071b666..5f4fed29c 100644 --- a/internal/graphicsdriver/metal/graphics.go +++ b/internal/graphicsdriver/metal/graphics.go @@ -1007,6 +1007,10 @@ func (g *Graphics) SetVsyncEnabled(enabled bool) { g.view.setDisplaySyncEnabled(enabled) } +func (g *Graphics) SetFullscreen(fullscreen bool) { + g.view.setFullscreen(fullscreen) +} + func (g *Graphics) FramebufferYDirection() driver.YDirection { return driver.Downward } diff --git a/internal/graphicsdriver/metal/ns/ns.go b/internal/graphicsdriver/metal/ns/ns.go index 4e917d9bf..9f1838cb4 100644 --- a/internal/graphicsdriver/metal/ns/ns.go +++ b/internal/graphicsdriver/metal/ns/ns.go @@ -77,3 +77,10 @@ func (v View) SetWantsLayer(wantsLayer bool) { C.View_SetWantsLayer(v.view, 0) } } + +// IsInFullScreenMode returns a boolean value indicating whether the view is in full screen mode. +// +// Reference: https://developer.apple.com/documentation/appkit/nsview/1483337-infullscreenmode. +func (v View) IsInFullScreenMode() bool { + return C.View_IsInFullScreenMode(v.view) != 0 +} diff --git a/internal/graphicsdriver/metal/ns/ns.h b/internal/graphicsdriver/metal/ns/ns.h index 4858c2e99..e6b2e6d14 100644 --- a/internal/graphicsdriver/metal/ns/ns.h +++ b/internal/graphicsdriver/metal/ns/ns.h @@ -20,3 +20,4 @@ void *Window_ContentView(uintptr_t window); void View_SetLayer(void *view, void *layer); void View_SetWantsLayer(void *view, unsigned char wantsLayer); +uint8_t View_IsInFullScreenMode(void *view); diff --git a/internal/graphicsdriver/metal/ns/ns.m b/internal/graphicsdriver/metal/ns/ns.m index da1173378..481cb2299 100644 --- a/internal/graphicsdriver/metal/ns/ns.m +++ b/internal/graphicsdriver/metal/ns/ns.m @@ -28,3 +28,7 @@ void View_SetLayer(void *view, void *layer) { void View_SetWantsLayer(void *view, unsigned char wantsLayer) { ((NSView *)view).wantsLayer = (BOOL)wantsLayer; } + +uint8_t View_IsInFullScreenMode(void *view) { + return ((NSView *)view).isInFullScreenMode; +} diff --git a/internal/graphicsdriver/metal/view.go b/internal/graphicsdriver/metal/view.go index 51df46dc0..999ade8d2 100644 --- a/internal/graphicsdriver/metal/view.go +++ b/internal/graphicsdriver/metal/view.go @@ -30,6 +30,7 @@ type view struct { windowChanged bool vsyncDisabled bool + fullscreen bool device mtl.Device ml ca.MetalLayer @@ -54,11 +55,33 @@ func (v *view) setDisplaySyncEnabled(enabled bool) { func (v *view) forceSetDisplaySyncEnabled(enabled bool) { v.ml.SetDisplaySyncEnabled(enabled) + v.vsyncDisabled = !enabled // setting presentsWithTransaction true makes the FPS stable (#1196). We're not sure why... - v.ml.SetPresentsWithTransaction(enabled) + v.updatePresentsWithTransaction() +} - v.vsyncDisabled = !enabled +func (v *view) setFullscreen(fullscreen bool) { + if v.fullscreen == fullscreen { + return + } + v.fullscreen = fullscreen + v.updatePresentsWithTransaction() +} + +func (v *view) updatePresentsWithTransaction() { + // Disable presentsWithTransaction on the fullscreen mode (#1745). + + pwt := !v.vsyncDisabled && !v.fullscreen + v.ml.SetPresentsWithTransaction(pwt) + + // When presentsWithTransaction is YES and triple buffering is enabled, nextDrawing returns immediately once every two times. + // This makes FPS doubled. To avoid this, disable the triple buffering. + if pwt { + v.ml.SetMaximumDrawableCount(2) + } else { + v.ml.SetMaximumDrawableCount(3) + } } func (v *view) colorPixelFormat() mtl.PixelFormat { @@ -81,10 +104,6 @@ func (v *view) reset() error { // MTLPixelFormatBGRA10_XR_sRGB. v.ml.SetPixelFormat(mtl.PixelFormatBGRA8UNorm) - // When presentsWithTransaction is YES and triple buffering is enabled, nextDrawing returns immediately once every two times. - // This makes FPS doubled. To avoid this, disable the triple buffering. - v.ml.SetMaximumDrawableCount(2) - // The vsync state might be reset. Set the state again (#1364). v.forceSetDisplaySyncEnabled(!v.vsyncDisabled) v.ml.SetFramebufferOnly(true) diff --git a/internal/graphicsdriver/opengl/graphics.go b/internal/graphicsdriver/opengl/graphics.go index 88ea8ed53..49af2a267 100644 --- a/internal/graphicsdriver/opengl/graphics.go +++ b/internal/graphicsdriver/opengl/graphics.go @@ -327,6 +327,10 @@ func (g *Graphics) SetVsyncEnabled(enabled bool) { // Do nothing } +func (g *Graphics) SetFullscreen(fullscreen bool) { + // Do nothing +} + func (g *Graphics) FramebufferYDirection() driver.YDirection { return driver.Upward } diff --git a/internal/uidriver/glfw/ui.go b/internal/uidriver/glfw/ui.go index edfef9cc2..6c18f6a41 100644 --- a/internal/uidriver/glfw/ui.go +++ b/internal/uidriver/glfw/ui.go @@ -1180,6 +1180,8 @@ func (u *UserInterface) adjustWindowSizeBasedOnSizeLimitsInDP(width, height int) func (u *UserInterface) setWindowSize(width, height int, fullscreen bool) { width, height = u.adjustWindowSizeBasedOnSizeLimits(width, height) + u.Graphics().SetFullscreen(fullscreen || u.isNativeFullscreen()) + if u.windowWidth == width && u.windowHeight == height && u.isFullscreen() == fullscreen && u.lastDeviceScaleFactor == u.deviceScaleFactor() { return }