diff --git a/internal/ui/run_glfw_notsinglethread.go b/internal/ui/run_notsinglethread.go similarity index 90% rename from internal/ui/run_glfw_notsinglethread.go rename to internal/ui/run_notsinglethread.go index 7718e6ce5..8e8bbbe8e 100644 --- a/internal/ui/run_glfw_notsinglethread.go +++ b/internal/ui/run_notsinglethread.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build !android && !ios && !js && !nintendosdk && !playstation5 && !ebitenginesinglethread && !ebitensinglethread +//go:build !android && !ios && !js && !ebitenginesinglethread && !ebitensinglethread package ui @@ -25,7 +25,7 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/thread" ) -func (u *UserInterface) Run(game Game, options *RunOptions) error { +func (u *UserInterface) run(game Game, options *RunOptions) error { u.mainThread = thread.NewOSThread() u.renderThread = thread.NewOSThread() graphicscommand.SetRenderThread(u.renderThread) diff --git a/internal/ui/run_glfw_singlethread.go b/internal/ui/run_singlethread.go similarity index 86% rename from internal/ui/run_glfw_singlethread.go rename to internal/ui/run_singlethread.go index 2c3860307..0fc6cb29f 100644 --- a/internal/ui/run_glfw_singlethread.go +++ b/internal/ui/run_singlethread.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build !android && !ios && !js && !nintendosdk && !playstation5 && (ebitenginesinglethread || ebitensinglethread) +//go:build js || (!android && !ios && (ebitenginesinglethread || ebitensinglethread)) package ui @@ -21,7 +21,7 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/thread" ) -func (u *UserInterface) Run(game Game, options *RunOptions) error { +func (u *UserInterface) run(game Game, options *RunOptions) error { // Initialize the main thread first so the thread is available at u.run (#809). u.mainThread = thread.NewNoopThread() u.renderThread = thread.NewNoopThread() diff --git a/internal/ui/ui.go b/internal/ui/ui.go index e39f0d6c5..b7fa0dd0f 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -22,6 +22,7 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/atlas" "github.com/hajimehoshi/ebiten/v2/internal/mipmap" + "github.com/hajimehoshi/ebiten/v2/internal/thread" ) // RegularTermination represents a regular termination. @@ -79,6 +80,9 @@ type UserInterface struct { whiteImage *Image + mainThread thread.Thread + renderThread thread.Thread + userInterfaceImpl } diff --git a/internal/ui/ui_glfw.go b/internal/ui/ui_glfw.go index d255e11f7..61e6e3ba8 100644 --- a/internal/ui/ui_glfw.go +++ b/internal/ui/ui_glfw.go @@ -107,9 +107,7 @@ type userInterfaceImpl struct { darwinInitOnce sync.Once bufferOnceSwappedOnce sync.Once - mainThread thread.Thread - renderThread thread.Thread - m sync.RWMutex + m sync.RWMutex } const ( @@ -123,6 +121,10 @@ func init() { runtime.LockOSThread() } +func (u *UserInterface) Run(game Game, options *RunOptions) error { + return u.run(game, options) +} + func (u *UserInterface) init() error { u.userInterfaceImpl = userInterfaceImpl{ runnableOnUnfocused: true, diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index 383534eb3..b9dd6a710 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -390,9 +390,7 @@ func (u *UserInterface) needsUpdate() bool { return false } -func (u *UserInterface) loop(game Game) <-chan error { - u.context = newContext(game) - +func (u *UserInterface) loopGame() error { errCh := make(chan error, 1) reqStopAudioCh := make(chan struct{}) resStopAudioCh := make(chan struct{}) @@ -476,7 +474,7 @@ func (u *UserInterface) loop(game Game) <-chan error { } }() - return errCh + return <-errCh } func (u *UserInterface) init() error { @@ -743,9 +741,10 @@ func (u *UserInterface) forceUpdateOnMinimumFPSMode() { } func (u *UserInterface) Run(game Game, options *RunOptions) error { - u.setRunning(true) - defer u.setRunning(false) + return u.run(game, options) +} +func (u *UserInterface) initOnMainThread(options *RunOptions) error { if !options.InitUnfocused && window.Truthy() { // Do not focus the canvas when the current document is in an iframe. // Otherwise, the parent page tries to focus the iframe on every loading, which is annoying (#1373). @@ -770,7 +769,7 @@ func (u *UserInterface) Run(game Game, options *RunOptions) error { bodyStyle.Set("backgroundColor", "#000") } - return <-u.loop(game) + return nil } func (u *UserInterface) updateScreenSize() { diff --git a/internal/ui/ui_mobile.go b/internal/ui/ui_mobile.go index c25d8f45f..46f4088bd 100644 --- a/internal/ui/ui_mobile.go +++ b/internal/ui/ui_mobile.go @@ -241,7 +241,7 @@ func (u *UserInterface) SetForeground(foreground bool) error { func (u *UserInterface) Run(game Game, options *RunOptions) error { u.setGBuildSizeCh = make(chan struct{}) go func() { - if err := u.run(game, true, options); err != nil { + if err := u.runMobile(game, true, options); err != nil { // As mobile apps never ends, Loop can't return. Just panic here. panic(err) } @@ -252,13 +252,13 @@ func (u *UserInterface) Run(game Game, options *RunOptions) error { func (u *UserInterface) RunWithoutMainLoop(game Game, options *RunOptions) { go func() { - if err := u.run(game, false, options); err != nil { + if err := u.runMobile(game, false, options); err != nil { u.errCh <- err } }() } -func (u *UserInterface) run(game Game, mainloop bool, options *RunOptions) (err error) { +func (u *UserInterface) runMobile(game Game, mainloop bool, options *RunOptions) (err error) { // Convert the panic to a regular error so that Java/Objective-C layer can treat this easily e.g., for // Crashlytics. A panic is treated as SIGABRT, and there is no way to handle this on Java/Objective-C layer // unfortunately. diff --git a/internal/ui/ui_nintendosdk.go b/internal/ui/ui_nintendosdk.go index 008f5c706..6d19d1692 100644 --- a/internal/ui/ui_nintendosdk.go +++ b/internal/ui/ui_nintendosdk.go @@ -21,15 +21,11 @@ package ui import "C" import ( - stdcontext "context" "errors" "image" "runtime" "sync" - "golang.org/x/sync/errgroup" - - "github.com/hajimehoshi/ebiten/v2/internal/graphicscommand" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl" "github.com/hajimehoshi/ebiten/v2/internal/thread" @@ -84,15 +80,10 @@ func (u *UserInterface) init() error { } func (u *UserInterface) Run(game Game, options *RunOptions) error { - u.mainThread = thread.NewOSThread() - u.renderThread = thread.NewOSThread() - graphicscommand.SetRenderThread(u.renderThread) - - u.setRunning(true) - defer u.setRunning(false) - - u.context = newContext(game) + return u.run(game, options) +} +func (u *UserInterface) initOnMainThread(options *RunOptions) error { g, lib, err := newGraphicsDriver(&graphicsDriverCreatorImpl{}, options.GraphicsLibrary) if err != nil { return err @@ -107,45 +98,25 @@ func (u *UserInterface) Run(game Game, options *RunOptions) error { initializeProfiler() - ctx, cancel := stdcontext.WithCancel(stdcontext.Background()) - defer cancel() - - var wg errgroup.Group - - // Run the render thread. - wg.Go(func() error { - defer cancel() - _ = u.renderThread.Loop(ctx) - return nil - }) - - // Run the game thread. - wg.Go(func() error { - defer cancel() - - u.renderThread.Call(func() { - u.egl.makeContextCurrent() - }) - - for { - recordProfilerHeartbeat() - - if err := u.context.updateFrame(u.graphicsDriver, float64(C.kScreenWidth), float64(C.kScreenHeight), deviceScaleFactor, u, func() { - u.egl.swapBuffers() - }); err != nil { - return err - } - } - }) - - // Run the main thread. - _ = u.mainThread.Loop(ctx) - if err := wg.Wait(); err != nil { - return err - } return nil } +func (u *UserInterface) loopGame() error { + u.renderThread.Call(func() { + u.egl.makeContextCurrent() + }) + + for { + recordProfilerHeartbeat() + + if err := u.context.updateFrame(u.graphicsDriver, float64(C.kScreenWidth), float64(C.kScreenHeight), deviceScaleFactor, u, func() { + u.egl.swapBuffers() + }); err != nil { + return err + } + } +} + func (*UserInterface) DeviceScaleFactor() float64 { return deviceScaleFactor } diff --git a/internal/ui/ui_playstation5.go b/internal/ui/ui_playstation5.go index e8dd04e76..4a2a6d802 100644 --- a/internal/ui/ui_playstation5.go +++ b/internal/ui/ui_playstation5.go @@ -64,10 +64,15 @@ func (u *UserInterface) init() error { } func (u *UserInterface) Run(game Game, options *RunOptions) error { - u.setRunning(true) - defer u.setRunning(false) + return u.run(game, options) +} - // TODO: Implement this. +func (u *UserInterface) initOnMainThread(options *RunOptions) error { + return nil +} + +func (u *UserInterface) loopGame() error { + // TODO: Implement this return nil }