diff --git a/cmd/ebitenmobile/_files/EbitenViewController.m b/cmd/ebitenmobile/_files/EbitenViewController.m index 8ca0b77f7..69cdfc4eb 100644 --- a/cmd/ebitenmobile/_files/EbitenViewController.m +++ b/cmd/ebitenmobile/_files/EbitenViewController.m @@ -59,7 +59,18 @@ started_ = true; } - if (EbitenmobileviewIsGL()) { + NSError* err = nil; + BOOL isGL = NO; + EbitenmobileviewIsGL(&isGL, &err); + if (err != nil) { + [self onErrorOnGameUpdate:err]; + @synchronized(self) { + error_ = true; + } + return; + } + + if (isGL) { self.glkView.delegate = (id)(self); [self.view addSubview: self.glkView]; @@ -69,7 +80,14 @@ [EAGLContext setCurrentContext:context]; } else { [self.view addSubview: self.metalView]; - EbitenmobileviewSetUIView((uintptr_t)(self.metalView)); + EbitenmobileviewSetUIView((uintptr_t)(self.metalView), &err); + if (err != nil) { + [self onErrorOnGameUpdate:err]; + @synchronized(self) { + error_ = true; + } + return; + } } displayLink_ = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawFrame)]; @@ -78,8 +96,19 @@ } - (void)viewWillLayoutSubviews { + NSError* err = nil; + BOOL isGL = NO; + EbitenmobileviewIsGL(&isGL, &err); + if (err != nil) { + [self onErrorOnGameUpdate:err]; + @synchronized(self) { + error_ = true; + } + return; + } + CGRect viewRect = [[self view] frame]; - if (EbitenmobileviewIsGL()) { + if (isGL) { [[self glkView] setFrame:viewRect]; } else { [[self metalView] setFrame:viewRect]; @@ -106,7 +135,18 @@ } } - if (EbitenmobileviewIsGL()) { + NSError* err = nil; + BOOL isGL = NO; + EbitenmobileviewIsGL(&isGL, &err); + if (err != nil) { + [self onErrorOnGameUpdate:err]; + @synchronized(self) { + error_ = true; + } + return; + } + + if (isGL) { [[self glkView] setNeedsDisplay]; } else { [self updateEbiten]; @@ -124,8 +164,10 @@ } - (void)updateEbiten { - if (error_) { - return; + @synchronized(self) { + if (error_) { + return; + } } NSError* err = nil; @@ -134,7 +176,9 @@ [self performSelectorOnMainThread:@selector(onErrorOnGameUpdate:) withObject:err waitUntilDone:NO]; - error_ = true; + @synchronized(self) { + error_ = true; + } } } @@ -143,8 +187,19 @@ } - (void)updateTouches:(NSSet*)touches { + NSError* err = nil; + BOOL isGL = NO; + EbitenmobileviewIsGL(&isGL, &err); + if (err != nil) { + [self onErrorOnGameUpdate:err]; + @synchronized(self) { + error_ = true; + } + return; + } + for (UITouch* touch in touches) { - if (EbitenmobileviewIsGL()) { + if (isGL) { if (touch.view != [self glkView]) { continue; } diff --git a/internal/ui/ui_ios.go b/internal/ui/ui_ios.go index 32ec17b5e..497a5d25b 100644 --- a/internal/ui/ui_ios.go +++ b/internal/ui/ui_ios.go @@ -55,13 +55,34 @@ func (g *graphicsDriverCreatorImpl) newMetal() (graphicsdriver.Graphics, error) return metal.NewGraphics() } -func SetUIView(uiview uintptr) { - // This function should be called only when the graphics library is Metal. - if g, ok := theUI.graphicsDriver.(interface{ SetUIView(uintptr) }); ok { - g.SetUIView(uiview) - } +func SetUIView(uiview uintptr) error { + return theUI.setUIView(uiview) } -func IsGL() bool { - return theUI.graphicsDriver.IsGL() +func IsGL() (bool, error) { + return theUI.isGL() +} + +func (u *userInterfaceImpl) setUIView(uiview uintptr) error { + select { + case err := <-u.errCh: + return err + case <-u.graphicsDriverInitCh: + } + + // This function should be called only when the graphics library is Metal. + if g, ok := u.graphicsDriver.(interface{ SetUIView(uintptr) }); ok { + g.SetUIView(uiview) + } + return nil +} + +func (u *userInterfaceImpl) isGL() (bool, error) { + select { + case err := <-u.errCh: + return false, err + case <-u.graphicsDriverInitCh: + } + + return u.graphicsDriver.IsGL(), nil } diff --git a/internal/ui/ui_mobile.go b/internal/ui/ui_mobile.go index 71aab8043..a5fb6cf27 100644 --- a/internal/ui/ui_mobile.go +++ b/internal/ui/ui_mobile.go @@ -52,8 +52,9 @@ var ( func init() { theUI.userInterfaceImpl = userInterfaceImpl{ - foreground: 1, - errCh: make(chan error), + foreground: 1, + graphicsDriverInitCh: make(chan struct{}), + errCh: make(chan error), // Give a default outside size so that the game can start without initializing them. outsideWidth: 640, @@ -90,7 +91,8 @@ func (u *userInterfaceImpl) Update() error { } type userInterfaceImpl struct { - graphicsDriver graphicsdriver.Graphics + graphicsDriver graphicsdriver.Graphics + graphicsDriverInitCh chan struct{} outsideWidth float64 outsideHeight float64 @@ -287,6 +289,7 @@ func (u *userInterfaceImpl) run(game Game, mainloop bool) (err error) { return err } u.graphicsDriver = g + close(u.graphicsDriverInitCh) // If gomobile-build is used, wait for the outside size fixed. if u.setGBuildSizeCh != nil { diff --git a/mobile/ebitenmobileview/view_ios.go b/mobile/ebitenmobileview/view_ios.go index 3e6f1d9af..835f7ada3 100644 --- a/mobile/ebitenmobileview/view_ios.go +++ b/mobile/ebitenmobileview/view_ios.go @@ -18,10 +18,10 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/ui" ) -func SetUIView(uiview int64) { - ui.SetUIView(uintptr(uiview)) +func SetUIView(uiview int64) error { + return ui.SetUIView(uintptr(uiview)) } -func IsGL() bool { +func IsGL() (bool, error) { return ui.IsGL() }