From 9400efa9a5ca92b3059682b9826b801507bd709b Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Wed, 20 Jan 2021 02:21:51 +0900 Subject: [PATCH] internal/uidriver/glfw: Update the screen on resizing Closes #1204 --- internal/graphicscommand/thread.go | 1 + internal/uidriver/glfw/run_notsinglethread.go | 29 +++++++++++ internal/uidriver/glfw/run_singlethread.go | 4 ++ internal/uidriver/glfw/ui.go | 48 ++++++++++++++----- 4 files changed, 70 insertions(+), 12 deletions(-) diff --git a/internal/graphicscommand/thread.go b/internal/graphicscommand/thread.go index 7c9ed7d2a..a3a604161 100644 --- a/internal/graphicscommand/thread.go +++ b/internal/graphicscommand/thread.go @@ -20,6 +20,7 @@ type Thread interface { Call(f func() error) error } +// SetMainThread must be called from the main thread (i.e, the goroutine where the thread is created). func SetMainThread(thread Thread) { theThread = thread } diff --git a/internal/uidriver/glfw/run_notsinglethread.go b/internal/uidriver/glfw/run_notsinglethread.go index b7905122a..3af865ddd 100644 --- a/internal/uidriver/glfw/run_notsinglethread.go +++ b/internal/uidriver/glfw/run_notsinglethread.go @@ -59,3 +59,32 @@ func (u *UserInterface) Run(uicontext driver.UIContext) error { u.setRunning(false) return <-ch } + +// runOnAnotherThreadFromMainThread is called from the main thread, and calls f on a new goroutine (thread). +// runOnAnotherThreadFromMainThread creates a new nested main thread and runs the run loop. +// u.t is updated to the new thread until runOnAnotherThreadFromMainThread is called. +// +// Inside f, another functions that must be called from the main thread can be called safely. +func (u *UserInterface) runOnAnotherThreadFromMainThread(f func() error) error { + // As this function is called from the main thread, u.t should never be accessed and can be updated here. + t := u.t + defer func() { + u.t = t + graphicscommand.SetMainThread(t) + }() + + u.t = thread.NewOSThread() + graphicscommand.SetMainThread(u.t) + + var err error + go func() { + defer func() { + _ = u.t.Call(func() error { + return thread.BreakLoop + }) + }() + err = f() + }() + u.t.Loop() + return err +} diff --git a/internal/uidriver/glfw/run_singlethread.go b/internal/uidriver/glfw/run_singlethread.go index 42b0c48f0..c54b58540 100644 --- a/internal/uidriver/glfw/run_singlethread.go +++ b/internal/uidriver/glfw/run_singlethread.go @@ -45,3 +45,7 @@ func (u *UserInterface) Run(uicontext driver.UIContext) error { u.setRunning(false) return nil } + +func (u *UserInterface) runOnAnotherThreadFromMainThread(f func() error) error { + return f() +} diff --git a/internal/uidriver/glfw/ui.go b/internal/uidriver/glfw/ui.go index d5e7cea2c..d0c013ed5 100644 --- a/internal/uidriver/glfw/ui.go +++ b/internal/uidriver/glfw/ui.go @@ -50,6 +50,9 @@ type UserInterface struct { runnableOnUnfocused bool vsync bool + // err must be accessed from the main thread. + err error + lastDeviceScaleFactor float64 initMonitor *glfw.Monitor @@ -73,9 +76,6 @@ type UserInterface struct { vsyncInited bool - reqWidth int - reqHeight int - input Input iwindow window @@ -628,8 +628,35 @@ func (u *UserInterface) createWindow() error { if u.isFullscreen() { return } - u.reqWidth = width - u.reqHeight = height + + if err := u.runOnAnotherThreadFromMainThread(func() error { + var outsideWidth, outsideHeight float64 + var outsideSizeChanged bool + + _ = u.t.Call(func() error { + if width != 0 || height != 0 { + u.setWindowSize(width, height, u.isFullscreen()) + } + + outsideWidth, outsideHeight, outsideSizeChanged = u.updateSize() + return nil + }) + if outsideSizeChanged { + u.context.Layout(outsideWidth, outsideHeight) + } + if err := u.context.ForceUpdate(); err != nil { + return err + } + if u.Graphics().IsGL() { + _ = u.t.Call(func() error { + u.swapBuffers() + return nil + }) + } + return nil + }); err != nil { + u.err = err + } }) return nil @@ -754,6 +781,10 @@ func (u *UserInterface) updateSize() (float64, float64, bool) { // update must be called from the main thread. func (u *UserInterface) update() (float64, float64, bool, error) { + if u.err != nil { + return 0, 0, false, u.err + } + if u.window.ShouldClose() { return 0, 0, false, driver.RegularTermination } @@ -772,13 +803,6 @@ func (u *UserInterface) update() (float64, float64, bool, error) { u.vsyncInited = true } - // Update the screen size when the window is resizable. - if w, h := u.reqWidth, u.reqHeight; w != 0 || h != 0 { - u.setWindowSize(w, h, u.isFullscreen()) - } - u.reqWidth = 0 - u.reqHeight = 0 - outsideWidth, outsideHeight, outsideSizeChanged := u.updateSize() // TODO: Updating the input can be skipped when clock.Update returns 0 (#1367).