driver: Let UI have Graphics

Now UIs own the implementation of Graphics.

Updates #1026
This commit is contained in:
Hajime Hoshi 2020-01-03 17:32:46 +09:00
parent e66f1fb71e
commit 982b7d6ddc
10 changed files with 75 additions and 47 deletions

View File

@ -31,8 +31,8 @@ type UIContext interface {
var RegularTermination = errors.New("regular termination")
type UI interface {
Run(context UIContext, graphics Graphics) error
RunWithoutMainLoop(width, height int, scale float64, title string, context UIContext, graphics Graphics) <-chan error
Run(context UIContext) error
RunWithoutMainLoop(width, height int, scale float64, title string, context UIContext) <-chan error
DeviceScaleFactor() float64
CursorMode() CursorMode
@ -51,6 +51,7 @@ type UI interface {
Input() Input
Window() Window
Graphics() Graphics
}
type Window interface {

View File

@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build darwin,!ios
// +build darwin
// +build !js
// +build !ebitengl
package ebiten
package glfw
// #cgo CFLAGS: -x objective-c
// #cgo LDFLAGS: -framework Foundation
@ -48,7 +48,7 @@ var (
isMetalSupportedOnce sync.Once
)
func graphicsDriver() driver.Graphics {
func (*UserInterface) Graphics() driver.Graphics {
isMetalSupportedOnce.Do(func() {
// On old mac devices like iMac 2011, Metal is not supported (#779).
if _, err := mtl.CreateSystemDefaultDevice(); err != nil {

View File

@ -12,15 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build android darwin,ios,386 darwin,ios,amd64 freebsd js linux windows ebitengl
// +build freebsd js linux windows ebitengl
package ebiten
package glfw
import (
"github.com/hajimehoshi/ebiten/internal/driver"
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
)
func graphicsDriver() driver.Graphics {
func (*UserInterface) Graphics() driver.Graphics {
return opengl.Get()
}

View File

@ -72,9 +72,8 @@ type UserInterface struct {
reqWidth int
reqHeight int
graphics driver.Graphics
input Input
iwindow window
input Input
iwindow window
t *thread.Thread
m sync.RWMutex
@ -509,11 +508,10 @@ func init() {
runtime.LockOSThread()
}
func (u *UserInterface) Run(uicontext driver.UIContext, graphics driver.Graphics) error {
func (u *UserInterface) Run(uicontext driver.UIContext) error {
// Initialize the main thread first so the thread is available at u.run (#809).
u.t = thread.New()
u.graphics = graphics
u.graphics.SetThread(u.t)
u.Graphics().SetThread(u.t)
ctx, cancel := context.WithCancel(context.Background())
@ -532,7 +530,7 @@ func (u *UserInterface) Run(uicontext driver.UIContext, graphics driver.Graphics
return <-ch
}
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics) <-chan error {
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext) <-chan error {
panic("glfw: RunWithoutMainLoop is not implemented")
}
@ -553,7 +551,7 @@ func (u *UserInterface) createWindow() error {
}
u.window = window
if u.graphics.IsGL() {
if u.Graphics().IsGL() {
u.window.MakeContextCurrent()
}
@ -591,7 +589,7 @@ func (u *UserInterface) run(context driver.UIContext) error {
u.window.Destroy()
u.window = nil
if u.graphics.IsGL() {
if u.Graphics().IsGL() {
glfw.WindowHint(glfw.ContextVersionMajor, 2)
glfw.WindowHint(glfw.ContextVersionMinor, 1)
} else {
@ -609,7 +607,7 @@ func (u *UserInterface) run(context driver.UIContext) error {
transparent = glfw.True
}
glfw.WindowHint(glfw.TransparentFramebuffer, transparent)
u.graphics.SetTransparent(u.isInitScreenTransparent())
u.Graphics().SetTransparent(u.isInitScreenTransparent())
resizable := glfw.False
if u.isInitWindowResizable() {
@ -652,7 +650,7 @@ func (u *UserInterface) run(context driver.UIContext) error {
w = u.nativeWindow()
return nil
})
u.graphics.SetWindow(w)
u.Graphics().SetWindow(w)
return u.loop(context)
}
@ -807,7 +805,7 @@ func (u *UserInterface) loop(context driver.UIContext) error {
// swapBuffers must be called from the main thread.
func (u *UserInterface) swapBuffers() {
if u.graphics.IsGL() {
if u.Graphics().IsGL() {
u.window.SwapBuffers()
}
}
@ -844,13 +842,13 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool, vsync
// Swapping buffer is necesary to prevent the image lag (#1004).
// TODO: This might not work when vsync is disabled.
if u.graphics.IsGL() {
if u.Graphics().IsGL() {
glfw.PollEvents()
u.swapBuffers()
}
} else {
if u.window.GetMonitor() != nil {
if u.graphics.IsGL() {
if u.Graphics().IsGL() {
// When OpenGL is used, swapping buffer is enough to solve the image-lag
// issue (#1004). Rather, recreating window destroys GPU resources.
// TODO: This might not work when vsync is disabled.
@ -929,7 +927,7 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool, vsync
u.windowWidth = width
u.windowHeight = height
if u.graphics.IsGL() {
if u.Graphics().IsGL() {
// SwapInterval is affected by the current monitor of the window.
// This needs to be called at least after SetMonitor.
// Without SwapInterval after SetMonitor, vsynch doesn't work (#375).
@ -943,14 +941,14 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool, vsync
glfw.SwapInterval(0)
}
}
u.graphics.SetVsyncEnabled(vsync)
u.Graphics().SetVsyncEnabled(vsync)
u.toChangeSize = true
return nil
})
if windowRecreated {
u.graphics.SetWindow(u.nativeWindow())
u.Graphics().SetWindow(u.nativeWindow())
}
}

View File

@ -24,6 +24,7 @@ import (
"github.com/hajimehoshi/ebiten/internal/devicescale"
"github.com/hajimehoshi/ebiten/internal/driver"
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
"github.com/hajimehoshi/ebiten/internal/hooks"
"github.com/hajimehoshi/ebiten/internal/jsutil"
)
@ -371,7 +372,7 @@ func init() {
}))
}
func (u *UserInterface) Run(context driver.UIContext, graphics driver.Graphics) error {
func (u *UserInterface) Run(context driver.UIContext) error {
canvas.Call("focus")
u.running = true
ch := u.loop(context)
@ -392,7 +393,7 @@ func (u *UserInterface) Run(context driver.UIContext, graphics driver.Graphics)
return nil
}
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics) <-chan error {
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext) <-chan error {
panic("js: RunWithoutMainLoop is not implemented")
}
@ -434,3 +435,7 @@ func (u *UserInterface) Input() driver.Input {
func (u *UserInterface) Window() driver.Window {
return nil
}
func (*UserInterface) Graphics() driver.Graphics {
return opengl.Get()
}

View File

@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build darwin,ios,arm darwin,ios,arm64
// +build ios,arm ios,arm64
// +build !ebitengl
package ebiten
package mobile
import (
"fmt"
@ -25,7 +25,7 @@ import (
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal/mtl"
)
func graphicsDriver() driver.Graphics {
func (*UserInterface) Graphics() driver.Graphics {
if _, err := mtl.CreateSystemDefaultDevice(); err != nil {
panic(fmt.Sprintf("ebiten: mtl.CreateSystemDefaultDevice failed on iOS: %v", err))
}

View File

@ -0,0 +1,26 @@
// Copyright 2018 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build android ios,386 ios,amd64 ebitengl
package mobile
import (
"github.com/hajimehoshi/ebiten/internal/driver"
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
)
func (*UserInterface) Graphics() driver.Graphics {
return opengl.Get()
}

View File

@ -72,7 +72,7 @@ func (u *UserInterface) Update() {
}
}()
if u.graphics.IsGL() {
if u.Graphics().IsGL() {
if u.glWorker == nil {
panic("mobile: glWorker must be initialized but not")
}
@ -105,8 +105,7 @@ type UserInterface struct {
gbuildHeightPx int
setGBuildSizeCh chan struct{}
context driver.UIContext
graphics driver.Graphics
context driver.UIContext
input Input
@ -182,12 +181,12 @@ func (u *UserInterface) appMain(a app.App) {
}
}
func (u *UserInterface) Run(context driver.UIContext, graphics driver.Graphics) error {
func (u *UserInterface) Run(context driver.UIContext) error {
// TODO: Remove width/height/scale arguments. They are not used from gomobile-build.
u.setGBuildSizeCh = make(chan struct{})
go func() {
if err := u.run(16, 16, 1, context, graphics, true); err != nil {
if err := u.run(16, 16, 1, context, true); err != nil {
// As mobile apps never ends, Loop can't return. Just panic here.
panic(err)
}
@ -196,12 +195,12 @@ func (u *UserInterface) Run(context driver.UIContext, graphics driver.Graphics)
return nil
}
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext, graphics driver.Graphics) <-chan error {
func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext) <-chan error {
ch := make(chan error)
go func() {
defer close(ch)
// title is ignored?
if err := u.run(width, height, scale, context, graphics, false); err != nil {
if err := u.run(width, height, scale, context, false); err != nil {
ch <- err
}
}()
@ -209,7 +208,7 @@ func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, tit
return ch
}
func (u *UserInterface) run(width, height int, scale float64, context driver.UIContext, graphics driver.Graphics, mainloop bool) (err error) {
func (u *UserInterface) run(width, height int, scale float64, context driver.UIContext, mainloop bool) (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.
@ -226,20 +225,19 @@ func (u *UserInterface) run(width, height int, scale float64, context driver.UIC
u.scale = scale
u.sizeChanged = true
u.context = context
u.graphics = graphics
u.m.Unlock()
if graphics.IsGL() {
if u.Graphics().IsGL() {
var ctx gl.Context
if mainloop {
ctx = <-glContextCh
} else {
ctx, u.glWorker = gl.NewContext()
}
graphics.(*opengl.Driver).SetMobileGLContext(ctx)
u.Graphics().(*opengl.Driver).SetMobileGLContext(ctx)
} else {
u.t = thread.New()
graphics.SetThread(u.t)
u.Graphics().SetThread(u.t)
}
// If gomobile-build is used, wait for the outside size fixed.

4
run.go
View File

@ -215,7 +215,7 @@ func RunGame(game Game) error {
func runGame(game Game, scale float64) error {
theUIContext.set(game, scale)
if err := uiDriver().Run(theUIContext, graphicsDriver()); err != nil {
if err := uiDriver().Run(theUIContext); err != nil {
if err == driver.RegularTermination {
return nil
}
@ -236,7 +236,7 @@ func RunWithoutMainLoop(f func(*Image) error, width, height int, scale float64,
height: height,
}
theUIContext.set(game, scale)
return uiDriver().RunWithoutMainLoop(width, height, scale, title, theUIContext, graphicsDriver())
return uiDriver().RunWithoutMainLoop(width, height, scale, title, theUIContext)
}
// ScreenSizeInFullscreen is deprecated as of 1.11.0-alpha.

View File

@ -28,8 +28,8 @@ import (
)
func init() {
shareable.SetGraphicsDriver(graphicsDriver())
graphicscommand.SetGraphicsDriver(graphicsDriver())
shareable.SetGraphicsDriver(uiDriver().Graphics())
graphicscommand.SetGraphicsDriver(uiDriver().Graphics())
}
type defaultGame struct {
@ -275,7 +275,7 @@ func (c *uiContext) update(afterFrameUpdate func()) error {
op := &DrawImageOptions{}
s := c.screenScale()
switch vd := graphicsDriver().VDirection(); vd {
switch vd := uiDriver().Graphics().VDirection(); vd {
case driver.VDownward:
// c.screen is special: its Y axis is down to up,
// and the origin point is lower left.