diff --git a/internal/graphicsdriver/metal/graphics_darwin.go b/internal/graphicsdriver/metal/graphics_darwin.go index 31da63021..79e92cf23 100644 --- a/internal/graphicsdriver/metal/graphics_darwin.go +++ b/internal/graphicsdriver/metal/graphics_darwin.go @@ -346,9 +346,24 @@ const ( noStencil ) +// isMetalAvailable reports whether Metal is available or not. +// +// On old mac devices like iMac 2011, Metal is not supported (#779). +var isMetalAvailable bool + +func init() { + // Initialize isMetalAvailable on the main thread. + // TODO: Is there a better way to check whether Metal is available or not? + // It seems OK to call MTLCreateSystemDefaultDevice multiple times, so this should be fine. + _, isMetalAvailable = mtl.CreateSystemDefaultDevice() +} + var theGraphics Graphics func Get() *Graphics { + if !isMetalAvailable { + return nil + } return &theGraphics } diff --git a/internal/graphicsdriver/metal/mtl/mtl_darwin.go b/internal/graphicsdriver/metal/mtl/mtl_darwin.go index 6c28deec2..4a62a622e 100644 --- a/internal/graphicsdriver/metal/mtl/mtl_darwin.go +++ b/internal/graphicsdriver/metal/mtl/mtl_darwin.go @@ -460,10 +460,10 @@ type Device struct { // CreateSystemDefaultDevice returns the preferred system default Metal device. // // Reference: https://developer.apple.com/documentation/metal/1433401-mtlcreatesystemdefaultdevice. -func CreateSystemDefaultDevice() (Device, error) { +func CreateSystemDefaultDevice() (Device, bool) { d := C.CreateSystemDefaultDevice() if d.Device == nil { - return Device{}, errors.New("Metal is not supported on this system") + return Device{}, false } return Device{ @@ -471,7 +471,7 @@ func CreateSystemDefaultDevice() (Device, error) { Headless: d.Headless != 0, LowPower: d.LowPower != 0, Name: C.GoString(d.Name), - }, nil + }, true } // Device returns the underlying id pointer. diff --git a/internal/graphicsdriver/metal/view_darwin.go b/internal/graphicsdriver/metal/view_darwin.go index daf212793..9a703a890 100644 --- a/internal/graphicsdriver/metal/view_darwin.go +++ b/internal/graphicsdriver/metal/view_darwin.go @@ -15,6 +15,7 @@ package metal import ( + "errors" "sync" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ca" @@ -76,10 +77,10 @@ func (v *view) colorPixelFormat() mtl.PixelFormat { } func (v *view) initialize() error { - var err error - v.device, err = mtl.CreateSystemDefaultDevice() - if err != nil { - return err + var ok bool + v.device, ok = mtl.CreateSystemDefaultDevice() + if !ok { + return errors.New("metal: Metal is not supported") } v.ml = ca.MakeMetalLayer() diff --git a/internal/ui/graphics_darwin.go b/internal/ui/graphics_darwin.go index 19cc4b81a..a9469178a 100644 --- a/internal/ui/graphics_darwin.go +++ b/internal/ui/graphics_darwin.go @@ -38,24 +38,19 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal" - "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl" ) var graphics graphicsdriver.Graphics func supportsMetal() bool { - // On old mac devices like iMac 2011, Metal is not supported (#779). - if _, err := mtl.CreateSystemDefaultDevice(); err != nil { - return false - } - // On macOS 10.11 El Capitan, there is a rendering issue on Metal (#781). // Use the OpenGL in macOS 10.11 or older. if C.getMacOSMajorVersion() <= 10 && C.getMacOSMinorVersion() <= 11 { return false } - return true + + return metal.Get() != nil } var graphicsOnce sync.Once diff --git a/internal/ui/graphics_ios.go b/internal/ui/graphics_ios.go index 0790de038..14f6be198 100644 --- a/internal/ui/graphics_ios.go +++ b/internal/ui/graphics_ios.go @@ -23,7 +23,6 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal" - "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl" ) @@ -32,8 +31,8 @@ func Graphics() graphicsdriver.Graphics { return opengl.Get() } - if _, err := mtl.CreateSystemDefaultDevice(); err != nil { - panic(fmt.Sprintf("mobile: mtl.CreateSystemDefaultDevice failed on iOS: %v", err)) + if metal.Get() == nil { + panic(fmt.Sprintf("ui: Metal is not available on this iOS device")) } return metal.Get() }