opengl: Remove Init (except for mobile)

This commit is contained in:
Hajime Hoshi 2018-11-04 23:32:18 +09:00
parent 16ada03928
commit 4090258904
7 changed files with 167 additions and 123 deletions

View File

@ -0,0 +1,44 @@
// 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.
package mainthread
var funcs = make(chan func())
// Loop starts the main-thread loop.
//
// Loop must be called on the main thread.
func Loop(ch <-chan error) error {
for {
select {
case f := <-funcs:
f()
case err := <-ch:
// ch returns a value not only when an error occur but also it is closed.
return err
}
}
}
// Run calls f on the main thread.
func Run(f func() error) error {
ch := make(chan struct{})
var err error
funcs <- func() {
err = f()
close(ch)
}
<-ch
return err
}

View File

@ -26,6 +26,7 @@ import (
"github.com/go-gl/gl/v2.1/gl"
"github.com/hajimehoshi/ebiten/internal/graphics"
"github.com/hajimehoshi/ebiten/internal/mainthread"
)
type (
@ -74,22 +75,15 @@ func init() {
}
type context struct {
init bool
runOnMainThread func(func() error) error
init bool
}
func Init(runOnMainThread func(func() error) error) {
c := &Context{}
c.runOnMainThread = runOnMainThread
theContext = c
}
func (c *Context) runOnContextThread(f func() error) error {
return c.runOnMainThread(f)
func init() {
theContext = &Context{}
}
func (c *Context) reset() error {
if err := c.runOnContextThread(func() error {
if err := mainthread.Run(func() error {
if c.init {
return nil
}
@ -108,12 +102,12 @@ func (c *Context) reset() error {
c.lastViewportWidth = 0
c.lastViewportHeight = 0
c.lastCompositeMode = graphics.CompositeModeUnknown
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.Enable(gl.BLEND)
return nil
})
c.BlendFunc(graphics.CompositeModeSourceOver)
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
f := int32(0)
gl.GetIntegerv(gl.FRAMEBUFFER_BINDING, &f)
c.screenFramebuffer = framebufferNative(f)
@ -123,7 +117,7 @@ func (c *Context) reset() error {
}
func (c *Context) BlendFunc(mode graphics.CompositeMode) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
if c.lastCompositeMode == mode {
return nil
}
@ -137,7 +131,7 @@ func (c *Context) BlendFunc(mode graphics.CompositeMode) {
func (c *Context) newTexture(width, height int) (textureNative, error) {
var texture textureNative
if err := c.runOnContextThread(func() error {
if err := mainthread.Run(func() error {
var t uint32
gl.GenTextures(1, &t)
// TODO: Use gl.IsTexture
@ -151,7 +145,7 @@ func (c *Context) newTexture(width, height int) (textureNative, error) {
return 0, err
}
c.bindTexture(texture)
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
@ -163,7 +157,7 @@ func (c *Context) newTexture(width, height int) (textureNative, error) {
}
func (c *Context) bindFramebufferImpl(f framebufferNative) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.BindFramebufferEXT(gl.FRAMEBUFFER, uint32(f))
return nil
})
@ -171,12 +165,12 @@ func (c *Context) bindFramebufferImpl(f framebufferNative) {
func (c *Context) framebufferPixels(f *framebuffer, width, height int) ([]byte, error) {
var pixels []byte
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.Flush()
return nil
})
c.bindFramebuffer(f.native)
if err := c.runOnContextThread(func() error {
if err := mainthread.Run(func() error {
pixels = make([]byte, 4*width*height)
gl.ReadPixels(0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(pixels))
if e := gl.GetError(); e != gl.NO_ERROR {
@ -191,14 +185,14 @@ func (c *Context) framebufferPixels(f *framebuffer, width, height int) ([]byte,
}
func (c *Context) bindTextureImpl(t textureNative) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.BindTexture(gl.TEXTURE_2D, uint32(t))
return nil
})
}
func (c *Context) deleteTexture(t textureNative) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
tt := uint32(t)
if !gl.IsTexture(tt) {
return nil
@ -213,7 +207,7 @@ func (c *Context) deleteTexture(t textureNative) {
func (c *Context) isTexture(t textureNative) bool {
r := false
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
r = gl.IsTexture(uint32(t))
return nil
})
@ -222,7 +216,7 @@ func (c *Context) isTexture(t textureNative) bool {
func (c *Context) texSubImage2D(t textureNative, p []byte, x, y, width, height int) {
c.bindTexture(t)
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.TexSubImage2D(gl.TEXTURE_2D, 0, int32(x), int32(y), int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(p))
return nil
})
@ -235,7 +229,7 @@ func (c *Context) BeforeSwapping() {
func (c *Context) newFramebuffer(texture textureNative) (framebufferNative, error) {
var framebuffer framebufferNative
var f uint32
if err := c.runOnContextThread(func() error {
if err := mainthread.Run(func() error {
gl.GenFramebuffersEXT(1, &f)
// TODO: Use gl.IsFramebuffer
if f <= 0 {
@ -246,7 +240,7 @@ func (c *Context) newFramebuffer(texture textureNative) (framebufferNative, erro
return 0, err
}
c.bindFramebuffer(framebufferNative(f))
if err := c.runOnContextThread(func() error {
if err := mainthread.Run(func() error {
gl.FramebufferTexture2DEXT(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, uint32(texture), 0)
s := gl.CheckFramebufferStatusEXT(gl.FRAMEBUFFER)
if s != gl.FRAMEBUFFER_COMPLETE {
@ -267,14 +261,14 @@ func (c *Context) newFramebuffer(texture textureNative) (framebufferNative, erro
}
func (c *Context) setViewportImpl(width, height int) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.Viewport(0, 0, int32(width), int32(height))
return nil
})
}
func (c *Context) deleteFramebuffer(f framebufferNative) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
ff := uint32(f)
if !gl.IsFramebufferEXT(ff) {
return nil
@ -291,7 +285,7 @@ func (c *Context) deleteFramebuffer(f framebufferNative) {
func (c *Context) newShader(shaderType shaderType, source string) (shader, error) {
var sh shader
if err := c.runOnContextThread(func() error {
if err := mainthread.Run(func() error {
s := gl.CreateShader(uint32(shaderType))
if s == 0 {
return fmt.Errorf("opengl: glCreateShader failed: shader type: %d", shaderType)
@ -321,7 +315,7 @@ func (c *Context) newShader(shaderType shaderType, source string) (shader, error
}
func (c *Context) deleteShader(s shader) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.DeleteShader(uint32(s))
return nil
})
@ -329,7 +323,7 @@ func (c *Context) deleteShader(s shader) {
func (c *Context) newProgram(shaders []shader) (program, error) {
var pr program
if err := c.runOnContextThread(func() error {
if err := mainthread.Run(func() error {
p := gl.CreateProgram()
if p == 0 {
return errors.New("opengl: glCreateProgram failed")
@ -353,14 +347,14 @@ func (c *Context) newProgram(shaders []shader) (program, error) {
}
func (c *Context) useProgram(p program) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.UseProgram(uint32(p))
return nil
})
}
func (c *Context) deleteProgram(p program) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
if !gl.IsProgram(uint32(p)) {
return nil
}
@ -380,7 +374,7 @@ func (c *Context) getUniformLocationImpl(p program, location string) uniformLoca
}
func (c *Context) uniformInt(p program, location string, v int) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
l := int32(c.locationCache.GetUniformLocation(c, p, location))
gl.Uniform1i(l, int32(v))
return nil
@ -388,7 +382,7 @@ func (c *Context) uniformInt(p program, location string, v int) {
}
func (c *Context) uniformFloat(p program, location string, v float32) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
l := int32(c.locationCache.GetUniformLocation(c, p, location))
gl.Uniform1f(l, v)
return nil
@ -396,7 +390,7 @@ func (c *Context) uniformFloat(p program, location string, v float32) {
}
func (c *Context) uniformFloats(p program, location string, v []float32) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
l := int32(c.locationCache.GetUniformLocation(c, p, location))
switch len(v) {
case 2:
@ -423,7 +417,7 @@ func (c *Context) getAttribLocationImpl(p program, location string) attribLocati
}
func (c *Context) vertexAttribPointer(p program, location string, size int, dataType DataType, stride int, offset int) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
l := c.locationCache.GetAttribLocation(c, p, location)
gl.VertexAttribPointer(uint32(l), int32(size), uint32(dataType), false, int32(stride), gl.PtrOffset(offset))
return nil
@ -431,7 +425,7 @@ func (c *Context) vertexAttribPointer(p program, location string, size int, data
}
func (c *Context) enableVertexAttribArray(p program, location string) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
l := c.locationCache.GetAttribLocation(c, p, location)
gl.EnableVertexAttribArray(uint32(l))
return nil
@ -439,7 +433,7 @@ func (c *Context) enableVertexAttribArray(p program, location string) {
}
func (c *Context) disableVertexAttribArray(p program, location string) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
l := c.locationCache.GetAttribLocation(c, p, location)
gl.DisableVertexAttribArray(uint32(l))
return nil
@ -448,7 +442,7 @@ func (c *Context) disableVertexAttribArray(p program, location string) {
func (c *Context) newArrayBuffer(size int) buffer {
var bf buffer
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
var b uint32
gl.GenBuffers(1, &b)
gl.BindBuffer(uint32(arrayBuffer), b)
@ -461,7 +455,7 @@ func (c *Context) newArrayBuffer(size int) buffer {
func (c *Context) newElementArrayBuffer(size int) buffer {
var bf buffer
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
var b uint32
gl.GenBuffers(1, &b)
gl.BindBuffer(uint32(elementArrayBuffer), b)
@ -473,28 +467,28 @@ func (c *Context) newElementArrayBuffer(size int) buffer {
}
func (c *Context) bindBuffer(bufferType bufferType, b buffer) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.BindBuffer(uint32(bufferType), uint32(b))
return nil
})
}
func (c *Context) arrayBufferSubData(data []float32) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.BufferSubData(uint32(arrayBuffer), 0, len(data)*4, gl.Ptr(data))
return nil
})
}
func (c *Context) elementArrayBufferSubData(data []uint16) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.BufferSubData(uint32(elementArrayBuffer), 0, len(data)*2, gl.Ptr(data))
return nil
})
}
func (c *Context) deleteBuffer(b buffer) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
bb := uint32(b)
gl.DeleteBuffers(1, &bb)
return nil
@ -502,7 +496,7 @@ func (c *Context) deleteBuffer(b buffer) {
}
func (c *Context) DrawElements(len int, offsetInBytes int) {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.DrawElements(gl.TRIANGLES, int32(len), gl.UNSIGNED_SHORT, gl.PtrOffset(offsetInBytes))
return nil
})
@ -510,7 +504,7 @@ func (c *Context) DrawElements(len int, offsetInBytes int) {
func (c *Context) maxTextureSizeImpl() int {
size := 0
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
s := int32(0)
gl.GetIntegerv(gl.MAX_TEXTURE_SIZE, &s)
size = int(s)
@ -520,7 +514,7 @@ func (c *Context) maxTextureSizeImpl() int {
}
func (c *Context) Flush() {
_ = c.runOnContextThread(func() error {
_ = mainthread.Run(func() error {
gl.Flush()
return nil
})

View File

@ -119,11 +119,18 @@ type context struct {
lastProgramID programID
}
func Init() error {
if js.Global().Get("WebGLRenderingContext") == js.Undefined() {
return fmt.Errorf("opengl: WebGL is not supported")
func init() {
theContext = &Context{}
}
func (c *Context) ensureGL() {
if c.gl != (js.Value{}) {
return
}
if js.Global().Get("WebGLRenderingContext") == js.Undefined() {
panic("opengl: WebGL is not supported")
}
// TODO: Define id?
canvas := js.Global().Get("document").Call("querySelector", "canvas")
attr := js.Global().Get("Object").New()
@ -133,18 +140,15 @@ func Init() error {
if gl == js.Null() {
gl = canvas.Call("getContext", "experimental-webgl", attr)
if gl == js.Null() {
return fmt.Errorf("opengl: getContext failed")
panic("opengl: getContext failed")
}
}
c := &Context{}
c.gl = gl
// Getting an extension might fail after the context is lost, so
// it is required to get the extension here.
c.loseContext = gl.Call("getExtension", "WEBGL_lose_context")
theContext = c
return nil
}
func (c *Context) reset() error {
@ -154,6 +158,8 @@ func (c *Context) reset() error {
c.lastViewportWidth = 0
c.lastViewportHeight = 0
c.lastCompositeMode = graphics.CompositeModeUnknown
c.ensureGL()
gl := c.gl
gl.Call("enable", blend)
c.BlendFunc(graphics.CompositeModeSourceOver)
@ -169,11 +175,13 @@ func (c *Context) BlendFunc(mode graphics.CompositeMode) {
c.lastCompositeMode = mode
s, d := mode.Operations()
s2, d2 := convertOperation(s), convertOperation(d)
c.ensureGL()
gl := c.gl
gl.Call("blendFunc", int(s2), int(d2))
}
func (c *Context) newTexture(width, height int) (textureNative, error) {
c.ensureGL()
gl := c.gl
t := gl.Call("createTexture")
if t == js.Null() {
@ -200,11 +208,13 @@ func (c *Context) newTexture(width, height int) (textureNative, error) {
}
func (c *Context) bindFramebufferImpl(f framebufferNative) {
c.ensureGL()
gl := c.gl
gl.Call("bindFramebuffer", framebuffer_, js.Value(f))
}
func (c *Context) framebufferPixels(f *framebuffer, width, height int) ([]byte, error) {
c.ensureGL()
gl := c.gl
c.bindFramebuffer(f.native)
@ -221,11 +231,13 @@ func (c *Context) framebufferPixels(f *framebuffer, width, height int) ([]byte,
}
func (c *Context) bindTextureImpl(t textureNative) {
c.ensureGL()
gl := c.gl
gl.Call("bindTexture", texture2d, js.Value(t))
}
func (c *Context) deleteTexture(t textureNative) {
c.ensureGL()
gl := c.gl
if !gl.Call("isTexture", js.Value(t)).Bool() {
return
@ -237,12 +249,14 @@ func (c *Context) deleteTexture(t textureNative) {
}
func (c *Context) isTexture(t textureNative) bool {
c.ensureGL()
gl := c.gl
return gl.Call("isTexture", js.Value(t)).Bool()
}
func (c *Context) texSubImage2D(t textureNative, pixels []byte, x, y, width, height int) {
c.bindTexture(t)
c.ensureGL()
gl := c.gl
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
// GLsizei width, GLsizei height,
@ -253,6 +267,7 @@ func (c *Context) texSubImage2D(t textureNative, pixels []byte, x, y, width, hei
}
func (c *Context) newFramebuffer(t textureNative) (framebufferNative, error) {
c.ensureGL()
gl := c.gl
f := gl.Call("createFramebuffer")
c.bindFramebuffer(framebufferNative(f))
@ -266,11 +281,13 @@ func (c *Context) newFramebuffer(t textureNative) (framebufferNative, error) {
}
func (c *Context) setViewportImpl(width, height int) {
c.ensureGL()
gl := c.gl
gl.Call("viewport", 0, 0, width, height)
}
func (c *Context) deleteFramebuffer(f framebufferNative) {
c.ensureGL()
gl := c.gl
if !gl.Call("isFramebuffer", js.Value(f)).Bool() {
return
@ -287,6 +304,7 @@ func (c *Context) deleteFramebuffer(f framebufferNative) {
}
func (c *Context) newShader(shaderType shaderType, source string) (shader, error) {
c.ensureGL()
gl := c.gl
s := gl.Call("createShader", int(shaderType))
if s == js.Null() {
@ -304,11 +322,13 @@ func (c *Context) newShader(shaderType shaderType, source string) (shader, error
}
func (c *Context) deleteShader(s shader) {
c.ensureGL()
gl := c.gl
gl.Call("deleteShader", js.Value(s))
}
func (c *Context) newProgram(shaders []shader) (program, error) {
c.ensureGL()
gl := c.gl
v := gl.Call("createProgram")
if v == js.Null() {
@ -332,11 +352,13 @@ func (c *Context) newProgram(shaders []shader) (program, error) {
}
func (c *Context) useProgram(p program) {
c.ensureGL()
gl := c.gl
gl.Call("useProgram", p.value)
}
func (c *Context) deleteProgram(p program) {
c.ensureGL()
gl := c.gl
if !gl.Call("isProgram", p.value).Bool() {
return
@ -345,17 +367,20 @@ func (c *Context) deleteProgram(p program) {
}
func (c *Context) getUniformLocationImpl(p program, location string) uniformLocation {
c.ensureGL()
gl := c.gl
return uniformLocation(gl.Call("getUniformLocation", p.value, location))
}
func (c *Context) uniformInt(p program, location string, v int) {
c.ensureGL()
gl := c.gl
l := c.locationCache.GetUniformLocation(c, p, location)
gl.Call("uniform1i", js.Value(l), v)
}
func (c *Context) uniformFloat(p program, location string, v float32) {
c.ensureGL()
gl := c.gl
l := c.locationCache.GetUniformLocation(c, p, location)
gl.Call("uniform1f", js.Value(l), v)
@ -366,6 +391,7 @@ var (
)
func (c *Context) uniformFloats(p program, location string, v []float32) {
c.ensureGL()
gl := c.gl
l := c.locationCache.GetUniformLocation(c, p, location)
switch len(v) {
@ -383,29 +409,34 @@ func (c *Context) uniformFloats(p program, location string, v []float32) {
}
func (c *Context) getAttribLocationImpl(p program, location string) attribLocation {
c.ensureGL()
gl := c.gl
return attribLocation(gl.Call("getAttribLocation", p.value, location).Int())
}
func (c *Context) vertexAttribPointer(p program, location string, size int, dataType DataType, stride int, offset int) {
c.ensureGL()
gl := c.gl
l := c.locationCache.GetAttribLocation(c, p, location)
gl.Call("vertexAttribPointer", int(l), size, int(dataType), false, stride, offset)
}
func (c *Context) enableVertexAttribArray(p program, location string) {
c.ensureGL()
gl := c.gl
l := c.locationCache.GetAttribLocation(c, p, location)
gl.Call("enableVertexAttribArray", int(l))
}
func (c *Context) disableVertexAttribArray(p program, location string) {
c.ensureGL()
gl := c.gl
l := c.locationCache.GetAttribLocation(c, p, location)
gl.Call("disableVertexAttribArray", int(l))
}
func (c *Context) newArrayBuffer(size int) buffer {
c.ensureGL()
gl := c.gl
b := gl.Call("createBuffer")
gl.Call("bindBuffer", int(arrayBuffer), js.Value(b))
@ -414,6 +445,7 @@ func (c *Context) newArrayBuffer(size int) buffer {
}
func (c *Context) newElementArrayBuffer(size int) buffer {
c.ensureGL()
gl := c.gl
b := gl.Call("createBuffer")
gl.Call("bindBuffer", int(elementArrayBuffer), js.Value(b))
@ -422,11 +454,13 @@ func (c *Context) newElementArrayBuffer(size int) buffer {
}
func (c *Context) bindBuffer(bufferType bufferType, b buffer) {
c.ensureGL()
gl := c.gl
gl.Call("bindBuffer", int(bufferType), js.Value(b))
}
func (c *Context) arrayBufferSubData(data []float32) {
c.ensureGL()
gl := c.gl
arr := js.TypedArrayOf(data)
gl.Call("bufferSubData", int(arrayBuffer), 0, arr)
@ -434,6 +468,7 @@ func (c *Context) arrayBufferSubData(data []float32) {
}
func (c *Context) elementArrayBufferSubData(data []uint16) {
c.ensureGL()
gl := c.gl
arr := js.TypedArrayOf(data)
gl.Call("bufferSubData", int(elementArrayBuffer), 0, arr)
@ -441,26 +476,31 @@ func (c *Context) elementArrayBufferSubData(data []uint16) {
}
func (c *Context) deleteBuffer(b buffer) {
c.ensureGL()
gl := c.gl
gl.Call("deleteBuffer", js.Value(b))
}
func (c *Context) DrawElements(len int, offsetInBytes int) {
c.ensureGL()
gl := c.gl
gl.Call("drawElements", triangles, len, unsignedShort, offsetInBytes)
}
func (c *Context) maxTextureSizeImpl() int {
c.ensureGL()
gl := c.gl
return gl.Call("getParameter", maxTextureSize).Int()
}
func (c *Context) Flush() {
c.ensureGL()
gl := c.gl
gl.Call("flush")
}
func (c *Context) IsContextLost() bool {
c.ensureGL()
gl := c.gl
return gl.Call("isContextLost").Bool()
}

View File

@ -31,6 +31,7 @@ import (
"github.com/hajimehoshi/ebiten/internal/devicescale"
"github.com/hajimehoshi/ebiten/internal/hooks"
"github.com/hajimehoshi/ebiten/internal/input"
"github.com/hajimehoshi/ebiten/internal/mainthread"
"github.com/hajimehoshi/ebiten/internal/opengl"
)
@ -58,8 +59,6 @@ type userInterface struct {
initWindowDecorated bool
initIconImages []image.Image
funcs chan func()
m sync.Mutex
}
@ -102,7 +101,6 @@ func initialize() error {
}
hideConsoleWindowOnWindows()
currentUI.window = window
currentUI.funcs = make(chan func())
currentUI.window.MakeContextCurrent()
@ -120,23 +118,13 @@ func initialize() error {
return nil
}
func RunMainThreadLoop(ch <-chan error) error {
// This must be called on the main thread.
// TODO: Check this is done on the main thread.
func Loop(ch <-chan error) error {
currentUI.setRunning(true)
defer func() {
currentUI.setRunning(false)
}()
for {
select {
case f := <-currentUI.funcs:
f()
case err := <-ch:
// ch returns a value not only when an error occur but also it is closed.
return err
}
if err := mainthread.Loop(ch); err != nil {
return err
}
currentUI.setRunning(false)
return nil
}
func (u *userInterface) isRunning() bool {
@ -217,27 +205,12 @@ func (u *userInterface) setInitIconImages(iconImages []image.Image) {
u.m.Unlock()
}
func (u *userInterface) runOnMainThread(f func() error) error {
if u.funcs == nil {
// already closed
return nil
}
ch := make(chan struct{})
var err error
u.funcs <- func() {
err = f()
close(ch)
}
<-ch
return err
}
func ScreenSizeInFullscreen() (int, int) {
u := currentUI
var v *glfw.VidMode
s := 0.0
if u.isRunning() {
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
v = u.currentMonitor().GetVideoMode()
s = glfwScale()
return nil
@ -255,7 +228,7 @@ func SetScreenSize(width, height int) bool {
panic("ui: Run is not called yet")
}
r := false
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
r = u.setScreenSize(width, height, u.scale, u.fullscreen(), u.vsync)
return nil
})
@ -268,7 +241,7 @@ func SetScreenScale(scale float64) bool {
panic("ui: Run is not called yet")
}
r := false
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
r = u.setScreenSize(u.width, u.height, scale, u.fullscreen(), u.vsync)
return nil
})
@ -281,7 +254,7 @@ func ScreenScale() float64 {
return 0
}
s := 0.0
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
s = u.scale
return nil
})
@ -302,7 +275,7 @@ func IsFullscreen() bool {
return u.isInitFullscreen()
}
b := false
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
b = u.fullscreen()
return nil
})
@ -315,7 +288,7 @@ func SetFullscreen(fullscreen bool) {
u.setInitFullscreen(fullscreen)
return
}
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
u := currentUI
u.setScreenSize(u.width, u.height, u.scale, fullscreen, u.vsync)
return nil
@ -342,7 +315,7 @@ func SetVsyncEnabled(enabled bool) {
u.m.Unlock()
return
}
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
u := currentUI
u.setScreenSize(u.width, u.height, u.scale, u.fullscreen(), enabled)
return nil
@ -361,7 +334,7 @@ func SetWindowTitle(title string) {
if !currentUI.isRunning() {
return
}
_ = currentUI.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
currentUI.window.SetTitle(title)
return nil
})
@ -372,7 +345,7 @@ func SetWindowIcon(iconImages []image.Image) {
currentUI.setInitIconImages(iconImages)
return
}
_ = currentUI.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
currentUI.window.SetIcon(iconImages)
return nil
})
@ -399,7 +372,7 @@ func ScreenPadding() (x0, y0, x1, y1 float64) {
sx := 0.0
sy := 0.0
gs := 0.0
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
sx = float64(u.width) * u.actualScreenScale()
sy = float64(u.height) * u.actualScreenScale()
gs = glfwScale()
@ -424,7 +397,7 @@ func adjustCursorPosition(x, y int) (int, int) {
}
ox, oy, _, _ := ScreenPadding()
s := 0.0
_ = currentUI.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
s = currentUI.actualScreenScale()
return nil
})
@ -442,7 +415,7 @@ func IsCursorVisible() bool {
return u.isInitCursorVisible()
}
v := false
_ = currentUI.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
v = currentUI.window.GetInputMode(glfw.CursorMode) == glfw.CursorNormal
return nil
})
@ -455,7 +428,7 @@ func SetCursorVisible(visible bool) {
u.setInitCursorVisible(visible)
return
}
_ = currentUI.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
c := glfw.CursorNormal
if !visible {
c = glfw.CursorHidden
@ -471,7 +444,7 @@ func IsWindowDecorated() bool {
return u.isInitWindowDecorated()
}
v := false
_ = currentUI.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
v = currentUI.window.GetAttrib(glfw.Decorated) == glfw.True
return nil
})
@ -490,7 +463,7 @@ func SetWindowDecorated(decorated bool) {
// TODO: Now SetAttrib doesn't exist on GLFW 3.2. Revisit later (#556).
// If SetAttrib exists, the implementation would be:
//
// _ = currentUI.runOnMainThread(func() error {
// _ = mainthread.Run(func() error {
// v := glfw.False
// if decorated {
// v = glfw.True
@ -506,7 +479,7 @@ func DeviceScaleFactor() float64 {
return devicescale.GetAt(u.currentMonitor().GetPos())
}
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
m := u.currentMonitor()
f = devicescale.GetAt(m.GetPos())
return nil
@ -516,10 +489,7 @@ func DeviceScaleFactor() float64 {
func Run(width, height int, scale float64, title string, g GraphicsContext, mainloop bool) error {
u := currentUI
// GLContext must be created before setting the screen size, which requires
// swapping buffers.
opengl.Init(currentUI.runOnMainThread)
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
// Get the monitor before showing the window.
//
// On Windows, there are two types of windows:
@ -596,7 +566,7 @@ func (u *userInterface) updateGraphicsContext(g GraphicsContext) {
actualScale := 0.0
sizeChanged := false
// TODO: Is it possible to reduce 'runOnMainThread' calls?
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
actualScale = u.actualScreenScale()
if u.lastActualScale != actualScale {
u.forceSetScreenSize(u.width, u.height, u.scale, u.fullscreen(), u.vsync)
@ -618,7 +588,7 @@ func (u *userInterface) updateGraphicsContext(g GraphicsContext) {
func (u *userInterface) update(g GraphicsContext) error {
shouldClose := false
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
shouldClose = u.window.ShouldClose()
return nil
})
@ -626,7 +596,7 @@ func (u *userInterface) update(g GraphicsContext) error {
return RegularTermination
}
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
if u.isInitFullscreen() {
u := currentUI
u.setScreenSize(u.width, u.height, u.scale, true, u.vsync)
@ -638,7 +608,7 @@ func (u *userInterface) update(g GraphicsContext) error {
// This call is needed for initialization.
u.updateGraphicsContext(g)
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
u.pollEvents()
defer hooks.ResumeAudio()
for !u.isRunnableInBackground() && u.window.GetAttrib(glfw.Focused) == 0 {
@ -665,7 +635,7 @@ func (u *userInterface) update(g GraphicsContext) error {
func (u *userInterface) loop(g GraphicsContext) error {
defer func() {
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
glfw.Terminate()
return nil
})
@ -683,7 +653,7 @@ func (u *userInterface) loop(g GraphicsContext) error {
// before swapping buffers.
opengl.GetContext().BeforeSwapping()
_ = u.runOnMainThread(func() error {
_ = mainthread.Run(func() error {
if !vsync {
u.swapBuffers()
return nil

View File

@ -357,7 +357,7 @@ func init() {
}))
}
func RunMainThreadLoop(ch <-chan error) error {
func Loop(ch <-chan error) error {
return <-ch
}
@ -366,9 +366,6 @@ func Run(width, height int, scale float64, title string, g GraphicsContext, main
document.Set("title", title)
u.setScreenSize(width, height, scale, u.fullscreen)
canvas.Call("focus")
if err := opengl.Init(); err != nil {
return err
}
return u.loop(g)
}

View File

@ -166,11 +166,10 @@ func Run(width, height int, scale float64, title string, g GraphicsContext, main
}
}
// RunMainThreadLoop runs the main routine for gomobile-build.
func RunMainThreadLoop(ch <-chan error) error {
// Loop runs the main routine for gomobile-build.
func Loop(ch <-chan error) error {
go func() {
// As mobile apps never ends, RunMainThreadLoop can't return.
// Just panic here.
// As mobile apps never ends, Loop can't return. Just panic here.
err := <-ch
panic(err)
}()

2
run.go
View File

@ -318,7 +318,7 @@ func Run(f func(*Image) error, width, height int, scale float64, title string) e
}
}()
// TODO: Use context in Go 1.7?
if err := ui.RunMainThreadLoop(ch); err != nil {
if err := ui.Loop(ch); err != nil {
return err
}
return nil