internal/graphicsdriver/metal: replace Get with NewGraphics

This is a prepartion to return an error when a graphics driver, especially
DirectX, fails to initialize.

Updates #2142
This commit is contained in:
Hajime Hoshi 2022-06-17 02:10:29 +09:00
parent a6d415ebf2
commit 7484df0c5e
11 changed files with 97 additions and 97 deletions

View File

@ -19,7 +19,6 @@ import (
"math"
"sort"
"strings"
"sync"
"unsafe"
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
@ -347,18 +346,11 @@ const (
noStencil
)
var (
// isMetalAvailable reports whether Metal is available or not.
isMetalAvailable bool
isMetalAvailableOnce sync.Once
)
var theGraphics Graphics
func Get() *Graphics {
isMetalAvailableOnce.Do(func() {
// NewGraphics creates an implementation of graphicsdriver.Graphcis for Metal.
// The returned graphics value is nil iff the error is not nil.
func NewGraphics() (graphicsdriver.Graphics, error) {
if !supportsMetal() {
return
return nil, fmt.Errorf("metal: Metal is not supported in this environment")
}
// Initialize isMetalAvailable on the main thread.
@ -368,14 +360,10 @@ func Get() *Graphics {
// 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.
if _, ok := mtl.CreateSystemDefaultDevice(); !ok {
return
return nil, fmt.Errorf("metal: mtl.CreateSystemDefaultDevice failed")
}
isMetalAvailable = true
})
if !isMetalAvailable {
return nil
}
return &theGraphics
return &Graphics{}, nil
}
func (g *Graphics) Begin() error {

View File

@ -21,19 +21,19 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
)
type graphicsDriverGetter interface {
type graphicsDriverCreator interface {
newAuto() (graphicsdriver.Graphics, error)
newOpenGL() (graphicsdriver.Graphics, error)
getDirectX() graphicsdriver.Graphics
getMetal() graphicsdriver.Graphics
newMetal() (graphicsdriver.Graphics, error)
}
func chooseGraphicsDriver(getter graphicsDriverGetter) (graphicsdriver.Graphics, error) {
func chooseGraphicsDriver(creator graphicsDriverCreator) (graphicsdriver.Graphics, error) {
const envName = "EBITEN_GRAPHICS_LIBRARY"
switch env := os.Getenv(envName); env {
case "", "auto":
g, err := getter.newAuto()
g, err := creator.newAuto()
if err != nil {
return nil, err
}
@ -42,7 +42,7 @@ func chooseGraphicsDriver(getter graphicsDriverGetter) (graphicsdriver.Graphics,
}
return g, nil
case "opengl":
g, err := getter.newOpenGL()
g, err := creator.newOpenGL()
if err != nil {
return nil, err
}
@ -51,15 +51,19 @@ func chooseGraphicsDriver(getter graphicsDriverGetter) (graphicsdriver.Graphics,
}
return g, nil
case "directx":
if g := getter.getDirectX(); g != nil {
if g := creator.getDirectX(); g != nil {
return g, nil
}
return nil, fmt.Errorf("ui: %s=%s is specified but DirectX is not available.", envName, env)
case "metal":
if g := getter.getMetal(); g != nil {
return g, nil
g, err := creator.newMetal()
if err != nil {
return nil, err
}
if g == nil {
return nil, fmt.Errorf("ui: %s=%s is specified but Metal is not available", envName, env)
}
return g, nil
default:
return nil, fmt.Errorf("ui: an unsupported graphics library is specified: %s", env)
}

View File

@ -19,22 +19,22 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl"
)
type graphicsDriverGetterImpl struct {
type graphicsDriverCreatorImpl struct {
gomobileBuild bool
}
func (g *graphicsDriverGetterImpl) newAuto() (graphicsdriver.Graphics, error) {
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, error) {
return g.newOpenGL()
}
func (*graphicsDriverGetterImpl) newOpenGL() (graphicsdriver.Graphics, error) {
func (*graphicsDriverCreatorImpl) newOpenGL() (graphicsdriver.Graphics, error) {
return opengl.NewGraphics()
}
func (*graphicsDriverGetterImpl) getDirectX() graphicsdriver.Graphics {
func (*graphicsDriverCreatorImpl) getDirectX() graphicsdriver.Graphics {
return nil
}
func (*graphicsDriverGetterImpl) getMetal() graphicsdriver.Graphics {
return nil
func (*graphicsDriverCreatorImpl) newMetal() (graphicsdriver.Graphics, error) {
return nil, nil
}

View File

@ -25,22 +25,22 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl"
)
type graphicsDriverGetterImpl struct{}
type graphicsDriverCreatorImpl struct{}
func (g *graphicsDriverGetterImpl) newAuto() (graphicsdriver.Graphics, error) {
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, error) {
return g.newOpenGL()
}
func (*graphicsDriverGetterImpl) newOpenGL() (graphicsdriver.Graphics, error) {
func (*graphicsDriverCreatorImpl) newOpenGL() (graphicsdriver.Graphics, error) {
return opengl.NewGraphics()
}
func (*graphicsDriverGetterImpl) getDirectX() graphicsdriver.Graphics {
func (*graphicsDriverCreatorImpl) getDirectX() graphicsdriver.Graphics {
return nil
}
func (*graphicsDriverGetterImpl) getMetal() graphicsdriver.Graphics {
return nil
func (*graphicsDriverCreatorImpl) newMetal() (graphicsdriver.Graphics, error) {
return nil, nil
}
const deviceScaleFactor = 1
@ -58,7 +58,7 @@ type userInterfaceImpl struct {
func (u *userInterfaceImpl) Run(game Game) error {
u.context = newContext(game)
g, err := chooseGraphicsDriver(&graphicsDriverGetterImpl{})
g, err := chooseGraphicsDriver(&graphicsDriverCreatorImpl{})
if err != nil {
return err
}

View File

@ -834,7 +834,7 @@ func (u *userInterfaceImpl) init() error {
}
glfw.WindowHint(glfw.TransparentFramebuffer, glfwTransparent)
g, err := chooseGraphicsDriver(&graphicsDriverGetterImpl{
g, err := chooseGraphicsDriver(&graphicsDriverCreatorImpl{
transparent: transparent,
})
if err != nil {

View File

@ -248,36 +248,40 @@ package ui
import "C"
import (
"fmt"
"github.com/hajimehoshi/ebiten/v2/internal/glfw"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl"
)
type graphicsDriverGetterImpl struct {
type graphicsDriverCreatorImpl struct {
transparent bool
}
func (g *graphicsDriverGetterImpl) newAuto() (graphicsdriver.Graphics, error) {
if m := g.getMetal(); m != nil {
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, error) {
m, err1 := g.newMetal()
if err1 == nil {
return m, nil
}
return g.newOpenGL()
o, err2 := g.newOpenGL()
if err2 == nil {
return o, nil
}
return nil, fmt.Errorf("ui: failed to choose graphics drivers: Metal: %v, OpenGL: %v", err1, err2)
}
func (*graphicsDriverGetterImpl) newOpenGL() (graphicsdriver.Graphics, error) {
func (*graphicsDriverCreatorImpl) newOpenGL() (graphicsdriver.Graphics, error) {
return opengl.NewGraphics()
}
func (*graphicsDriverGetterImpl) getDirectX() graphicsdriver.Graphics {
func (*graphicsDriverCreatorImpl) getDirectX() graphicsdriver.Graphics {
return nil
}
func (*graphicsDriverGetterImpl) getMetal() graphicsdriver.Graphics {
if m := metal.Get(); m != nil {
return m
}
return nil
func (*graphicsDriverCreatorImpl) newMetal() (graphicsdriver.Graphics, error) {
return metal.NewGraphics()
}
// clearVideoModeScaleCache must be called from the main thread.

View File

@ -31,24 +31,24 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl"
)
type graphicsDriverGetterImpl struct {
type graphicsDriverCreatorImpl struct {
transparent bool
}
func (g *graphicsDriverGetterImpl) newAuto() (graphicsdriver.Graphics, error) {
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, error) {
return g.newOpenGL()
}
func (*graphicsDriverGetterImpl) newOpenGL() (graphicsdriver.Graphics, error) {
func (*graphicsDriverCreatorImpl) newOpenGL() (graphicsdriver.Graphics, error) {
return opengl.NewGraphics()
}
func (*graphicsDriverGetterImpl) getDirectX() graphicsdriver.Graphics {
func (*graphicsDriverCreatorImpl) getDirectX() graphicsdriver.Graphics {
return nil
}
func (*graphicsDriverGetterImpl) getMetal() graphicsdriver.Graphics {
return nil
func (*graphicsDriverCreatorImpl) newMetal() (graphicsdriver.Graphics, error) {
return nil, nil
}
type videoModeScaleCacheKey struct{ X, Y int }

View File

@ -31,22 +31,22 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
)
type graphicsDriverGetterImpl struct {
type graphicsDriverCreatorImpl struct {
transparent bool
}
func (g *graphicsDriverGetterImpl) newAuto() (graphicsdriver.Graphics, error) {
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, error) {
if d := g.getDirectX(); d != nil {
return d, nil
}
return g.newOpenGL()
}
func (*graphicsDriverGetterImpl) newOpenGL() (graphicsdriver.Graphics, error) {
func (*graphicsDriverCreatorImpl) newOpenGL() (graphicsdriver.Graphics, error) {
return opengl.NewGraphics()
}
func (g *graphicsDriverGetterImpl) getDirectX() graphicsdriver.Graphics {
func (g *graphicsDriverCreatorImpl) getDirectX() graphicsdriver.Graphics {
if g.transparent {
return nil
}
@ -56,8 +56,8 @@ func (g *graphicsDriverGetterImpl) getDirectX() graphicsdriver.Graphics {
return nil
}
func (*graphicsDriverGetterImpl) getMetal() graphicsdriver.Graphics {
return nil
func (*graphicsDriverCreatorImpl) newMetal() (graphicsdriver.Graphics, error) {
return nil, nil
}
const (

View File

@ -18,40 +18,42 @@
package ui
import (
"fmt"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl"
)
type graphicsDriverGetterImpl struct {
type graphicsDriverCreatorImpl struct {
gomobileBuild bool
}
func (g *graphicsDriverGetterImpl) newAuto() (graphicsdriver.Graphics, error) {
if m := g.getMetal(); m != nil {
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, error) {
m, err1 := g.newMetal()
if err1 == nil {
return m, nil
}
return g.newOpenGL()
o, err2 := g.newOpenGL()
if err2 == nil {
return o, nil
}
return nil, fmt.Errorf("ui: failed to choose graphics drivers: Metal: %v, OpenGL: %v", err1, err2)
}
func (*graphicsDriverGetterImpl) newOpenGL() (graphicsdriver.Graphics, error) {
func (*graphicsDriverCreatorImpl) newOpenGL() (graphicsdriver.Graphics, error) {
return opengl.NewGraphics()
}
func (*graphicsDriverGetterImpl) getDirectX() graphicsdriver.Graphics {
func (*graphicsDriverCreatorImpl) getDirectX() graphicsdriver.Graphics {
return nil
}
func (g *graphicsDriverGetterImpl) getMetal() graphicsdriver.Graphics {
// When gomobile-build is used, GL functions must be called via
// gl.Context so that they are called on the appropriate thread.
func (g *graphicsDriverCreatorImpl) newMetal() (graphicsdriver.Graphics, error) {
if g.gomobileBuild {
return nil
return nil, fmt.Errorf("ui: Metal is not available with gomobile-build")
}
if m := metal.Get(); m != nil {
return m
}
return nil
return metal.NewGraphics()
}
func SetUIView(uiview uintptr) {

View File

@ -25,22 +25,22 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/hooks"
)
type graphicsDriverGetterImpl struct{}
type graphicsDriverCreatorImpl struct{}
func (g *graphicsDriverGetterImpl) newAuto() (graphicsdriver.Graphics, error) {
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, error) {
return g.newOpenGL()
}
func (*graphicsDriverGetterImpl) newOpenGL() (graphicsdriver.Graphics, error) {
func (*graphicsDriverCreatorImpl) newOpenGL() (graphicsdriver.Graphics, error) {
return opengl.NewGraphics()
}
func (*graphicsDriverGetterImpl) getDirectX() graphicsdriver.Graphics {
func (*graphicsDriverCreatorImpl) getDirectX() graphicsdriver.Graphics {
return nil
}
func (*graphicsDriverGetterImpl) getMetal() graphicsdriver.Graphics {
return nil
func (*graphicsDriverCreatorImpl) newMetal() (graphicsdriver.Graphics, error) {
return nil, nil
}
var (
@ -609,7 +609,7 @@ func (u *userInterfaceImpl) Run(game Game) error {
}
}
u.running = true
g, err := chooseGraphicsDriver(&graphicsDriverGetterImpl{})
g, err := chooseGraphicsDriver(&graphicsDriverCreatorImpl{})
if err != nil {
return err
}

View File

@ -270,7 +270,7 @@ func (u *userInterfaceImpl) run(game Game, mainloop bool) (err error) {
}()
u.context = newContext(game)
g, err := chooseGraphicsDriver(&graphicsDriverGetterImpl{
g, err := chooseGraphicsDriver(&graphicsDriverCreatorImpl{
gomobileBuild: mainloop,
})
if err != nil {
@ -279,6 +279,8 @@ func (u *userInterfaceImpl) run(game Game, mainloop bool) (err error) {
u.graphicsDriver = g
if mainloop {
// When gomobile-build is used, GL functions must be called via
// gl.Context so that they are called on the appropriate thread.
ctx := <-glContextCh
g.(*opengl.Graphics).SetGomobileGLContext(ctx)
} else {