uidriver/glfw: Reduce (*thread).Call at (*Input).update

This commit is contained in:
Hajime Hoshi 2020-10-17 05:16:02 +09:00
parent 495b2b722a
commit 1864c22ad6
6 changed files with 80 additions and 89 deletions

View File

@ -22,7 +22,9 @@ import (
type UIContext interface {
Update() error
Layout(outsideWidth, outsideHeight float64)
AdjustPosition(x, y float64) (float64, float64)
// AdjustPosition can be called from a different goroutine from Update's or Layout's.
AdjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64)
}
// RegularTermination represents a regular termination.

View File

@ -308,81 +308,73 @@ func (i *Input) setWheel(xoff, yoff float64) {
i.scrollY = yoff
}
// update must be called from the main thread.
func (i *Input) update(window *glfw.Window, context driver.UIContext) {
var cx, cy float64
_ = i.ui.t.Call(func() error {
i.onceCallback.Do(func() {
window.SetCharModsCallback(func(w *glfw.Window, char rune, mods glfw.ModifierKey) {
i.appendRuneBuffer(char)
})
window.SetScrollCallback(func(w *glfw.Window, xoff float64, yoff float64) {
i.setWheel(xoff, yoff)
})
i.onceCallback.Do(func() {
window.SetCharModsCallback(func(w *glfw.Window, char rune, mods glfw.ModifierKey) {
i.appendRuneBuffer(char)
})
window.SetScrollCallback(func(w *glfw.Window, xoff float64, yoff float64) {
i.setWheel(xoff, yoff)
})
if i.keyPressed == nil {
i.keyPressed = map[glfw.Key]bool{}
}
for gk := range glfwKeyToDriverKey {
i.keyPressed[gk] = window.GetKey(gk) == glfw.Press
}
if i.mouseButtonPressed == nil {
i.mouseButtonPressed = map[glfw.MouseButton]bool{}
}
for gb := range glfwMouseButtonToMouseButton {
i.mouseButtonPressed[gb] = window.GetMouseButton(gb) == glfw.Press
}
cx, cy = window.GetCursorPos()
// TODO: This is tricky. Rename the function?
cx = i.ui.fromGLFWMonitorPixel(cx)
cy = i.ui.fromGLFWMonitorPixel(cy)
return nil
})
if i.keyPressed == nil {
i.keyPressed = map[glfw.Key]bool{}
}
for gk := range glfwKeyToDriverKey {
i.keyPressed[gk] = window.GetKey(gk) == glfw.Press
}
if i.mouseButtonPressed == nil {
i.mouseButtonPressed = map[glfw.MouseButton]bool{}
}
for gb := range glfwMouseButtonToMouseButton {
i.mouseButtonPressed[gb] = window.GetMouseButton(gb) == glfw.Press
}
cx, cy := window.GetCursorPos()
// TODO: This is tricky. Rename the function?
cx = i.ui.fromGLFWMonitorPixel(cx)
cy = i.ui.fromGLFWMonitorPixel(cy)
cx, cy = context.AdjustPosition(cx, cy, i.ui.deviceScaleFactor())
i.cursorX, i.cursorY = int(cx), int(cy)
cx, cy = context.AdjustPosition(cx, cy)
for id := glfw.Joystick(0); id < glfw.Joystick(len(i.gamepads)); id++ {
i.gamepads[id].valid = false
if !id.Present() {
continue
}
_ = i.ui.t.Call(func() error {
i.cursorX, i.cursorY = int(cx), int(cy)
buttons := id.GetButtons()
for id := glfw.Joystick(0); id < glfw.Joystick(len(i.gamepads)); id++ {
i.gamepads[id].valid = false
if !id.Present() {
// A gamepad can be detected even though there are not. Apparently, some special devices are
// recognized as gamepads by GLFW. In this case, the number of the 'buttons' can exceeds the
// maximum. Skip such devices as a tentative solution (#1173).
if len(buttons) > driver.GamepadButtonNum {
continue
}
i.gamepads[id].valid = true
i.gamepads[id].buttonNum = len(buttons)
for b := 0; b < len(i.gamepads[id].buttonPressed); b++ {
if len(buttons) <= b {
i.gamepads[id].buttonPressed[b] = false
continue
}
i.gamepads[id].buttonPressed[b] = glfw.Action(buttons[b]) == glfw.Press
}
buttons := id.GetButtons()
// A gamepad can be detected even though there are not. Apparently, some special devices are
// recognized as gamepads by GLFW. In this case, the number of the 'buttons' can exceeds the
// maximum. Skip such devices as a tentative solution (#1173).
if len(buttons) > driver.GamepadButtonNum {
axes32 := id.GetAxes()
i.gamepads[id].axisNum = len(axes32)
for a := 0; a < len(i.gamepads[id].axes); a++ {
if len(axes32) <= a {
i.gamepads[id].axes[a] = 0
continue
}
i.gamepads[id].valid = true
i.gamepads[id].buttonNum = len(buttons)
for b := 0; b < len(i.gamepads[id].buttonPressed); b++ {
if len(buttons) <= b {
i.gamepads[id].buttonPressed[b] = false
continue
}
i.gamepads[id].buttonPressed[b] = glfw.Action(buttons[b]) == glfw.Press
}
axes32 := id.GetAxes()
i.gamepads[id].axisNum = len(axes32)
for a := 0; a < len(i.gamepads[id].axes); a++ {
if len(axes32) <= a {
i.gamepads[id].axes[a] = 0
continue
}
i.gamepads[id].axes[a] = float64(axes32[a])
}
// Note that GLFW's gamepad GUID follows SDL's GUID.
i.gamepads[id].guid = id.GetGUID()
i.gamepads[id].name = id.GetName()
i.gamepads[id].axes[a] = float64(axes32[a])
}
return nil
})
// Note that GLFW's gamepad GUID follows SDL's GUID.
i.gamepads[id].guid = id.GetGUID()
i.gamepads[id].name = id.GetName()
}
}

View File

@ -834,12 +834,9 @@ func (u *UserInterface) update() error {
_ = u.t.Call(func() error {
glfw.PollEvents()
return nil
})
u.input.update(u.window, u.context)
_ = u.t.Call(func() error {
defer hooks.ResumeAudio()
u.input.update(u.window, u.context)
defer hooks.ResumeAudio()
for !u.isRunnableOnUnfocused() && u.window.GetAttrib(glfw.Focused) == 0 && !u.window.ShouldClose() {
hooks.SuspendAudio()
// Wait for an arbitrary period to avoid busy loop.

View File

@ -52,7 +52,7 @@ type Input struct {
}
func (i *Input) CursorPosition() (x, y int) {
xf, yf := i.ui.context.AdjustPosition(float64(i.cursorX), float64(i.cursorY))
xf, yf := i.ui.context.AdjustPosition(float64(i.cursorX), float64(i.cursorY), i.ui.DeviceScaleFactor())
return int(xf), int(yf)
}
@ -131,9 +131,10 @@ func (i *Input) TouchIDs() []driver.TouchID {
}
func (i *Input) TouchPosition(id driver.TouchID) (x, y int) {
d := i.ui.DeviceScaleFactor()
for tid, pos := range i.touches {
if id == tid {
x, y := i.ui.context.AdjustPosition(float64(pos.X), float64(pos.Y))
x, y := i.ui.context.AdjustPosition(float64(pos.X), float64(pos.Y), d)
return int(x), int(y)
}
}

View File

@ -402,7 +402,7 @@ func (u *UserInterface) setGBuildSize(widthPx, heightPx int) {
}
func (u *UserInterface) adjustPosition(x, y int) (int, int) {
xf, yf := u.context.AdjustPosition(float64(x), float64(y))
xf, yf := u.context.AdjustPosition(float64(x), float64(y), deviceScale())
return int(xf), int(yf)
}

View File

@ -112,27 +112,27 @@ func (c *uiContext) setWindowResizable(resizable bool) {
}
}
func (c *uiContext) screenScale() float64 {
func (c *uiContext) screenScale(deviceScaleFactor float64) float64 {
if c.offscreen == nil {
return 0
}
sw, sh := c.offscreen.Size()
d := uiDriver().DeviceScaleFactor()
scaleX := c.outsideWidth / float64(sw) * d
scaleY := c.outsideHeight / float64(sh) * d
scaleX := c.outsideWidth / float64(sw) * deviceScaleFactor
scaleY := c.outsideHeight / float64(sh) * deviceScaleFactor
return math.Min(scaleX, scaleY)
}
func (c *uiContext) offsets() (float64, float64) {
func (c *uiContext) offsets(deviceScaleFactor float64) (float64, float64) {
if c.offscreen == nil {
return 0, 0
}
sw, sh := c.offscreen.Size()
d := uiDriver().DeviceScaleFactor()
s := c.screenScale()
s := c.screenScale(deviceScaleFactor)
width := float64(sw) * s
height := float64(sh) * s
return (c.outsideWidth*d - width) / 2, (c.outsideHeight*d - height) / 2
x := (c.outsideWidth*deviceScaleFactor - width) / 2
y := (c.outsideHeight*deviceScaleFactor - height) / 2
return x, y
}
func (c *uiContext) Update() error {
@ -185,7 +185,7 @@ func (c *uiContext) update() error {
op := &DrawImageOptions{}
s := c.screenScale()
s := c.screenScale(uiDriver().DeviceScaleFactor())
switch vd := uiDriver().Graphics().FramebufferYDirection(); vd {
case driver.Upward:
op.GeoM.Scale(s, -s)
@ -197,7 +197,7 @@ func (c *uiContext) update() error {
panic(fmt.Sprintf("ebiten: invalid v-direction: %d", vd))
}
op.GeoM.Translate(c.offsets())
op.GeoM.Translate(c.offsets(uiDriver().DeviceScaleFactor()))
op.CompositeMode = CompositeModeCopy
// filterScreen works with >=1 scale, but does not well with <1 scale.
@ -211,9 +211,8 @@ func (c *uiContext) update() error {
return nil
}
func (c *uiContext) AdjustPosition(x, y float64) (float64, float64) {
d := uiDriver().DeviceScaleFactor()
ox, oy := c.offsets()
s := c.screenScale()
return (x*d - ox) / s, (y*d - oy) / s
func (c *uiContext) AdjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64) {
ox, oy := c.offsets(deviceScaleFactor)
s := c.screenScale(deviceScaleFactor)
return (x*deviceScaleFactor - ox) / s, (y*deviceScaleFactor - oy) / s
}