graphicsdriver/opengl: Use native GLES functions for mobiles

After this change, GL functions for mobiles, especially Android, are
native ones instead of golang.org/x/mobile/gl functions in order to
reduce goroutine context switches.

On gomobile-build, golang.org/x/mobile/gl functions are still used.

Fixes #1387
This commit is contained in:
Hajime Hoshi 2020-10-18 18:28:23 +09:00
parent 2740938460
commit f611b48c71
7 changed files with 851 additions and 196 deletions

View File

@ -20,20 +20,17 @@ import (
"errors"
"fmt"
// TODO: Remove this dependency (#1387)
mgl "golang.org/x/mobile/gl"
"github.com/hajimehoshi/ebiten/v2/internal/driver"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gles"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
)
type (
textureNative mgl.Texture
framebufferNative mgl.Framebuffer
shader mgl.Shader
program mgl.Program
buffer mgl.Buffer
textureNative uint32
framebufferNative uint32
shader uint32
program uint32
buffer uint32
)
func (t textureNative) equal(rhs textureNative) bool {
@ -59,8 +56,8 @@ func (p program) equal(rhs program) bool {
var InvalidTexture textureNative
type (
uniformLocation mgl.Uniform
attribLocation mgl.Attrib
uniformLocation int32
attribLocation int32
)
func (u uniformLocation) equal(rhs uniformLocation) bool {
@ -69,14 +66,14 @@ func (u uniformLocation) equal(rhs uniformLocation) bool {
type programID uint32
var (
invalidTexture = textureNative(mgl.Texture{})
invalidFramebuffer = framebufferNative(mgl.Framebuffer{Value: (1 << 32) - 1})
invalidUniform = uniformLocation(mgl.Uniform{Value: -1})
const (
invalidTexture = 0
invalidFramebuffer = (1 << 32) - 1
invalidUniform = -1
)
func getProgramID(p program) programID {
return programID(p.Value)
return programID(p)
}
const (
@ -98,7 +95,7 @@ const (
)
type contextImpl struct {
gl mgl.Context
ctx gles.Context
}
func (c *context) reset() error {
@ -108,115 +105,105 @@ func (c *context) reset() error {
c.lastViewportWidth = 0
c.lastViewportHeight = 0
c.lastCompositeMode = driver.CompositeModeUnknown
c.gl.Enable(gles.BLEND)
c.ctx.Enable(gles.BLEND)
c.blendFunc(driver.CompositeModeSourceOver)
f := c.gl.GetInteger(gles.FRAMEBUFFER_BINDING)
c.screenFramebuffer = framebufferNative(mgl.Framebuffer{uint32(f)})
f := make([]int32, 1)
c.ctx.GetIntegerv(f, gles.FRAMEBUFFER_BINDING)
c.screenFramebuffer = framebufferNative(f[0])
// TODO: Need to update screenFramebufferWidth/Height?
return nil
}
func (c *context) blendFunc(mode driver.CompositeMode) {
gl := c.gl
if c.lastCompositeMode == mode {
return
}
c.lastCompositeMode = mode
s, d := mode.Operations()
s2, d2 := convertOperation(s), convertOperation(d)
gl.BlendFunc(mgl.Enum(s2), mgl.Enum(d2))
c.ctx.BlendFunc(uint32(s2), uint32(d2))
}
func (c *context) newTexture(width, height int) (textureNative, error) {
gl := c.gl
t := gl.CreateTexture()
if t.Value <= 0 {
return textureNative{}, errors.New("opengl: creating texture failed")
t := c.ctx.GenTextures(1)[0]
if t <= 0 {
return 0, errors.New("opengl: creating texture failed")
}
gl.PixelStorei(gles.UNPACK_ALIGNMENT, 4)
c.ctx.PixelStorei(gles.UNPACK_ALIGNMENT, 4)
c.bindTexture(textureNative(t))
gl.TexParameteri(gles.TEXTURE_2D, gles.TEXTURE_MAG_FILTER, gles.NEAREST)
gl.TexParameteri(gles.TEXTURE_2D, gles.TEXTURE_MIN_FILTER, gles.NEAREST)
gl.TexParameteri(gles.TEXTURE_2D, gles.TEXTURE_WRAP_S, gles.CLAMP_TO_EDGE)
gl.TexParameteri(gles.TEXTURE_2D, gles.TEXTURE_WRAP_T, gles.CLAMP_TO_EDGE)
gl.TexImage2D(gles.TEXTURE_2D, 0, gles.RGBA, width, height, gles.RGBA, gles.UNSIGNED_BYTE, nil)
c.ctx.TexParameteri(gles.TEXTURE_2D, gles.TEXTURE_MAG_FILTER, gles.NEAREST)
c.ctx.TexParameteri(gles.TEXTURE_2D, gles.TEXTURE_MIN_FILTER, gles.NEAREST)
c.ctx.TexParameteri(gles.TEXTURE_2D, gles.TEXTURE_WRAP_S, gles.CLAMP_TO_EDGE)
c.ctx.TexParameteri(gles.TEXTURE_2D, gles.TEXTURE_WRAP_T, gles.CLAMP_TO_EDGE)
c.ctx.TexImage2D(gles.TEXTURE_2D, 0, gles.RGBA, int32(width), int32(height), gles.RGBA, gles.UNSIGNED_BYTE, nil)
return textureNative(t), nil
}
func (c *context) bindFramebufferImpl(f framebufferNative) {
gl := c.gl
gl.BindFramebuffer(gles.FRAMEBUFFER, mgl.Framebuffer(f))
c.ctx.BindFramebuffer(gles.FRAMEBUFFER, uint32(f))
}
func (c *context) framebufferPixels(f *framebuffer, width, height int) []byte {
gl := c.gl
gl.Flush()
c.ctx.Flush()
c.bindFramebuffer(f.native)
pixels := make([]byte, 4*width*height)
gl.ReadPixels(pixels, 0, 0, width, height, gles.RGBA, gles.UNSIGNED_BYTE)
c.ctx.ReadPixels(pixels, 0, 0, int32(width), int32(height), gles.RGBA, gles.UNSIGNED_BYTE)
return pixels
}
func (c *context) activeTexture(idx int) {
gl := c.gl
gl.ActiveTexture(mgl.Enum(gles.TEXTURE0 + idx))
c.ctx.ActiveTexture(uint32(gles.TEXTURE0 + idx))
}
func (c *context) bindTextureImpl(t textureNative) {
gl := c.gl
gl.BindTexture(gles.TEXTURE_2D, mgl.Texture(t))
c.ctx.BindTexture(gles.TEXTURE_2D, uint32(t))
}
func (c *context) deleteTexture(t textureNative) {
gl := c.gl
if !gl.IsTexture(mgl.Texture(t)) {
if !c.ctx.IsTexture(uint32(t)) {
return
}
if c.lastTexture == t {
c.lastTexture = invalidTexture
}
gl.DeleteTexture(mgl.Texture(t))
c.ctx.DeleteTextures([]uint32{uint32(t)})
}
func (c *context) isTexture(t textureNative) bool {
gl := c.gl
return gl.IsTexture(mgl.Texture(t))
return c.ctx.IsTexture(uint32(t))
}
func (c *context) newFramebuffer(texture textureNative) (framebufferNative, error) {
gl := c.gl
f := gl.CreateFramebuffer()
if f.Value <= 0 {
return framebufferNative{}, fmt.Errorf("opengl: creating framebuffer failed: the returned value is not positive but %d", f.Value)
f := c.ctx.GenFramebuffers(1)[0]
if f <= 0 {
return 0, fmt.Errorf("opengl: creating framebuffer failed: the returned value is not positive but %d", f)
}
c.bindFramebuffer(framebufferNative(f))
gl.FramebufferTexture2D(gles.FRAMEBUFFER, gles.COLOR_ATTACHMENT0, gles.TEXTURE_2D, mgl.Texture(texture), 0)
s := gl.CheckFramebufferStatus(gles.FRAMEBUFFER)
c.ctx.FramebufferTexture2D(gles.FRAMEBUFFER, gles.COLOR_ATTACHMENT0, gles.TEXTURE_2D, uint32(texture), 0)
s := c.ctx.CheckFramebufferStatus(gles.FRAMEBUFFER)
if s != gles.FRAMEBUFFER_COMPLETE {
if s != 0 {
return framebufferNative{}, fmt.Errorf("opengl: creating framebuffer failed: %v", s)
return 0, fmt.Errorf("opengl: creating framebuffer failed: %v", s)
}
if e := gl.GetError(); e != gles.NO_ERROR {
return framebufferNative{}, fmt.Errorf("opengl: creating framebuffer failed: (glGetError) %d", e)
if e := c.ctx.GetError(); e != gles.NO_ERROR {
return 0, fmt.Errorf("opengl: creating framebuffer failed: (glGetError) %d", e)
}
return framebufferNative{}, fmt.Errorf("opengl: creating framebuffer failed: unknown error")
return 0, fmt.Errorf("opengl: creating framebuffer failed: unknown error")
}
return framebufferNative(f), nil
}
func (c *context) setViewportImpl(width, height int) {
gl := c.gl
gl.Viewport(0, 0, width, height)
c.ctx.Viewport(0, 0, int32(width), int32(height))
}
func (c *context) deleteFramebuffer(f framebufferNative) {
gl := c.gl
if !gl.IsFramebuffer(mgl.Framebuffer(f)) {
if !c.ctx.IsFramebuffer(uint32(f)) {
return
}
// If a framebuffer to be deleted is bound, a newly bound framebuffer
@ -227,96 +214,89 @@ func (c *context) deleteFramebuffer(f framebufferNative) {
c.lastViewportWidth = 0
c.lastViewportHeight = 0
}
gl.DeleteFramebuffer(mgl.Framebuffer(f))
c.ctx.DeleteFramebuffers([]uint32{uint32(f)})
}
func (c *context) newShader(shaderType shaderType, source string) (shader, error) {
gl := c.gl
s := gl.CreateShader(mgl.Enum(shaderType))
if s.Value == 0 {
return shader{}, fmt.Errorf("opengl: glCreateShader failed: shader type: %d", shaderType)
s := c.ctx.CreateShader(uint32(shaderType))
if s == 0 {
return 0, fmt.Errorf("opengl: glCreateShader failed: shader type: %d", shaderType)
}
gl.ShaderSource(s, source)
gl.CompileShader(s)
c.ctx.ShaderSource(s, source)
c.ctx.CompileShader(s)
v := gl.GetShaderi(s, gles.COMPILE_STATUS)
if v == gles.FALSE {
log := gl.GetShaderInfoLog(s)
return shader{}, fmt.Errorf("opengl: shader compile failed: %s", log)
v := make([]int32, 1)
c.ctx.GetShaderiv(v, s, gles.COMPILE_STATUS)
if v[0] == gles.FALSE {
log := c.ctx.GetShaderInfoLog(s)
return 0, fmt.Errorf("opengl: shader compile failed: %s", log)
}
return shader(s), nil
}
func (c *context) deleteShader(s shader) {
gl := c.gl
gl.DeleteShader(mgl.Shader(s))
c.ctx.DeleteShader(uint32(s))
}
func (c *context) newProgram(shaders []shader, attributes []string) (program, error) {
gl := c.gl
p := gl.CreateProgram()
if p.Value == 0 {
return program{}, errors.New("opengl: glCreateProgram failed")
p := c.ctx.CreateProgram()
if p == 0 {
return 0, errors.New("opengl: glCreateProgram failed")
}
for _, shader := range shaders {
gl.AttachShader(p, mgl.Shader(shader))
c.ctx.AttachShader(p, uint32(shader))
}
for i, name := range attributes {
gl.BindAttribLocation(p, mgl.Attrib{Value: uint(i)}, name)
c.ctx.BindAttribLocation(p, uint32(i), name)
}
gl.LinkProgram(p)
v := gl.GetProgrami(p, gles.LINK_STATUS)
if v == gles.FALSE {
info := gl.GetProgramInfoLog(p)
return program{}, fmt.Errorf("opengl: program error: %s", info)
c.ctx.LinkProgram(p)
v := make([]int32, 1)
c.ctx.GetProgramiv(v, p, gles.LINK_STATUS)
if v[0] == gles.FALSE {
info := c.ctx.GetProgramInfoLog(p)
return 0, fmt.Errorf("opengl: program error: %s", info)
}
return program(p), nil
}
func (c *context) useProgram(p program) {
gl := c.gl
gl.UseProgram(mgl.Program(p))
c.ctx.UseProgram(uint32(p))
}
func (c *context) deleteProgram(p program) {
gl := c.gl
if !gl.IsProgram(mgl.Program(p)) {
if !c.ctx.IsProgram(uint32(p)) {
return
}
gl.DeleteProgram(mgl.Program(p))
c.ctx.DeleteProgram(uint32(p))
}
func (c *context) getUniformLocationImpl(p program, location string) uniformLocation {
gl := c.gl
u := uniformLocation(gl.GetUniformLocation(mgl.Program(p), location))
u := uniformLocation(c.ctx.GetUniformLocation(uint32(p), location))
return u
}
func (c *context) uniformInt(p program, location string, v int) bool {
gl := c.gl
l := c.locationCache.GetUniformLocation(c, p, location)
if l == invalidUniform {
return false
}
gl.Uniform1i(mgl.Uniform(l), v)
c.ctx.Uniform1i(int32(l), int32(v))
return true
}
func (c *context) uniformFloat(p program, location string, v float32) bool {
gl := c.gl
l := c.locationCache.GetUniformLocation(c, p, location)
if l == invalidUniform {
return false
}
gl.Uniform1f(mgl.Uniform(l), v)
c.ctx.Uniform1f(int32(l), v)
return true
}
func (c *context) uniformFloats(p program, location string, v []float32, typ shaderir.Type) bool {
gl := c.gl
l := c.locationCache.GetUniformLocation(c, p, location)
if l == invalidUniform {
return false
@ -329,19 +309,19 @@ func (c *context) uniformFloats(p program, location string, v []float32, typ sha
switch base {
case shaderir.Float:
gl.Uniform1fv(mgl.Uniform(l), v)
c.ctx.Uniform1fv(int32(l), v)
case shaderir.Vec2:
gl.Uniform2fv(mgl.Uniform(l), v)
c.ctx.Uniform2fv(int32(l), v)
case shaderir.Vec3:
gl.Uniform3fv(mgl.Uniform(l), v)
c.ctx.Uniform3fv(int32(l), v)
case shaderir.Vec4:
gl.Uniform4fv(mgl.Uniform(l), v)
c.ctx.Uniform4fv(int32(l), v)
case shaderir.Mat2:
gl.UniformMatrix2fv(mgl.Uniform(l), v)
c.ctx.UniformMatrix2fv(int32(l), false, v)
case shaderir.Mat3:
gl.UniformMatrix3fv(mgl.Uniform(l), v)
c.ctx.UniformMatrix3fv(int32(l), false, v)
case shaderir.Mat4:
gl.UniformMatrix4fv(mgl.Uniform(l), v)
c.ctx.UniformMatrix4fv(int32(l), false, v)
default:
panic(fmt.Sprintf("opengl: unexpected type: %s", typ.String()))
}
@ -349,75 +329,64 @@ func (c *context) uniformFloats(p program, location string, v []float32, typ sha
}
func (c *context) vertexAttribPointer(p program, index int, size int, dataType dataType, stride int, offset int) {
gl := c.gl
gl.VertexAttribPointer(mgl.Attrib{Value: uint(index)}, size, mgl.Enum(dataType), false, stride, offset)
c.ctx.VertexAttribPointer(uint32(index), int32(size), uint32(dataType), false, int32(stride), offset)
}
func (c *context) enableVertexAttribArray(p program, index int) {
gl := c.gl
gl.EnableVertexAttribArray(mgl.Attrib{Value: uint(index)})
c.ctx.EnableVertexAttribArray(uint32(index))
}
func (c *context) disableVertexAttribArray(p program, index int) {
gl := c.gl
gl.DisableVertexAttribArray(mgl.Attrib{Value: uint(index)})
c.ctx.DisableVertexAttribArray(uint32(index))
}
func (c *context) newArrayBuffer(size int) buffer {
gl := c.gl
b := gl.CreateBuffer()
gl.BindBuffer(mgl.Enum(arrayBuffer), b)
gl.BufferInit(mgl.Enum(arrayBuffer), size, mgl.Enum(dynamicDraw))
b := c.ctx.GenBuffers(1)[0]
c.ctx.BindBuffer(uint32(arrayBuffer), b)
c.ctx.BufferData(uint32(arrayBuffer), size, nil, uint32(dynamicDraw))
return buffer(b)
}
func (c *context) newElementArrayBuffer(size int) buffer {
gl := c.gl
b := gl.CreateBuffer()
gl.BindBuffer(mgl.Enum(elementArrayBuffer), b)
gl.BufferInit(mgl.Enum(elementArrayBuffer), size, mgl.Enum(dynamicDraw))
b := c.ctx.GenBuffers(1)[0]
c.ctx.BindBuffer(uint32(elementArrayBuffer), b)
c.ctx.BufferData(uint32(elementArrayBuffer), size, nil, uint32(dynamicDraw))
return buffer(b)
}
func (c *context) bindBuffer(bufferType bufferType, b buffer) {
gl := c.gl
gl.BindBuffer(mgl.Enum(bufferType), mgl.Buffer(b))
c.ctx.BindBuffer(uint32(bufferType), uint32(b))
}
func (c *context) arrayBufferSubData(data []float32) {
gl := c.gl
gl.BufferSubData(mgl.Enum(arrayBuffer), 0, float32sToBytes(data))
c.ctx.BufferSubData(uint32(arrayBuffer), 0, float32sToBytes(data))
}
func (c *context) elementArrayBufferSubData(data []uint16) {
gl := c.gl
gl.BufferSubData(mgl.Enum(elementArrayBuffer), 0, uint16sToBytes(data))
c.ctx.BufferSubData(uint32(elementArrayBuffer), 0, uint16sToBytes(data))
}
func (c *context) deleteBuffer(b buffer) {
gl := c.gl
gl.DeleteBuffer(mgl.Buffer(b))
c.ctx.DeleteBuffers([]uint32{uint32(b)})
}
func (c *context) drawElements(len int, offsetInBytes int) {
gl := c.gl
gl.DrawElements(gles.TRIANGLES, len, gles.UNSIGNED_SHORT, offsetInBytes)
c.ctx.DrawElements(gles.TRIANGLES, int32(len), gles.UNSIGNED_SHORT, offsetInBytes)
}
func (c *context) maxTextureSizeImpl() int {
gl := c.gl
return gl.GetInteger(gles.MAX_TEXTURE_SIZE)
v := make([]int32, 1)
c.ctx.GetIntegerv(v, gles.MAX_TEXTURE_SIZE)
return int(v[0])
}
func (c *context) getShaderPrecisionFormatPrecision() int {
gl := c.gl
_, _, p := gl.GetShaderPrecisionFormat(gles.FRAGMENT_SHADER, gles.HIGH_FLOAT)
_, _, p := c.ctx.GetShaderPrecisionFormat(gles.FRAGMENT_SHADER, gles.HIGH_FLOAT)
return p
}
func (c *context) flush() {
gl := c.gl
gl.Flush()
c.ctx.Flush()
}
func (c *context) needsRestoring() bool {
@ -432,18 +401,16 @@ func (c *context) canUsePBO() bool {
func (c *context) texSubImage2D(t textureNative, width, height int, args []*driver.ReplacePixelsArgs) {
c.bindTexture(t)
gl := c.gl
for _, a := range args {
gl.TexSubImage2D(gles.TEXTURE_2D, 0, a.X, a.Y, a.Width, a.Height, gles.RGBA, gles.UNSIGNED_BYTE, a.Pixels)
c.ctx.TexSubImage2D(gles.TEXTURE_2D, 0, int32(a.X), int32(a.Y), int32(a.Width), int32(a.Height), gles.RGBA, gles.UNSIGNED_BYTE, a.Pixels)
}
}
func (c *context) newPixelBufferObject(width, height int) buffer {
gl := c.gl
b := gl.CreateBuffer()
gl.BindBuffer(gles.PIXEL_UNPACK_BUFFER, b)
gl.BufferInit(gles.PIXEL_UNPACK_BUFFER, 4*width*height, gles.STREAM_DRAW)
gl.BindBuffer(gles.PIXEL_UNPACK_BUFFER, mgl.Buffer{0})
b := c.ctx.GenBuffers(1)[0]
c.ctx.BindBuffer(gles.PIXEL_UNPACK_BUFFER, b)
c.ctx.BufferData(gles.PIXEL_UNPACK_BUFFER, 4*width*height, nil, gles.STREAM_DRAW)
c.ctx.BindBuffer(gles.PIXEL_UNPACK_BUFFER, 0)
return buffer(b)
}
@ -451,17 +418,16 @@ func (c *context) replacePixelsWithPBO(buffer buffer, t textureNative, width, he
// This implementation is not used yet so far. See the comment at canUsePBO.
c.bindTexture(t)
gl := c.gl
gl.BindBuffer(gles.PIXEL_UNPACK_BUFFER, mgl.Buffer(buffer))
c.ctx.BindBuffer(gles.PIXEL_UNPACK_BUFFER, uint32(buffer))
stride := 4 * width
for _, a := range args {
offset := 4 * (a.Y*width + a.X)
for j := 0; j < a.Height; j++ {
gl.BufferSubData(gles.PIXEL_UNPACK_BUFFER, offset+stride*j, a.Pixels[4*a.Width*j:4*a.Width*(j+1)])
c.ctx.BufferSubData(gles.PIXEL_UNPACK_BUFFER, offset+stride*j, a.Pixels[4*a.Width*j:4*a.Width*(j+1)])
}
}
gl.TexSubImage2D(gles.TEXTURE_2D, 0, 0, 0, width, height, gles.RGBA, gles.UNSIGNED_BYTE, nil)
gl.BindBuffer(gles.PIXEL_UNPACK_BUFFER, mgl.Buffer{0})
c.ctx.TexSubImage2D(gles.TEXTURE_2D, 0, 0, 0, int32(width), int32(height), gles.RGBA, gles.UNSIGNED_BYTE, nil)
c.ctx.BindBuffer(gles.PIXEL_UNPACK_BUFFER, 0)
}

View File

@ -0,0 +1,313 @@
// Copyright 2020 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
package gles
// #cgo android CFLAGS: -Dos_android
// #cgo android LDFLAGS: -lGLESv2
// #cgo ios CFLAGS: -Dos_ios
// #cgo ios LDFLAGS: -framework OpenGLES
//
// #if defined(os_android)
// #include <GLES2/gl2.h>
// #endif
//
// #if defined(os_ios)
// #include <OpenGLES/ES2/glext.h>
// #endif
import "C"
import (
"unsafe"
)
func glBool(x bool) C.GLboolean {
if x {
return TRUE
}
return FALSE
}
type DefaultContext struct{}
func (DefaultContext) ActiveTexture(texture uint32) {
C.glActiveTexture(C.GLenum(texture))
}
func (DefaultContext) AttachShader(program uint32, shader uint32) {
C.glAttachShader(C.GLuint(program), C.GLuint(shader))
}
func (DefaultContext) BindAttribLocation(program uint32, index uint32, name string) {
s, free := cString(name)
defer free()
C.glBindAttribLocation(C.GLuint(program), C.GLuint(index), (*C.GLchar)(unsafe.Pointer(s)))
}
func (DefaultContext) BindBuffer(target uint32, buffer uint32) {
C.glBindBuffer(C.GLenum(target), C.GLuint(buffer))
}
func (DefaultContext) BindFramebuffer(target uint32, framebuffer uint32) {
C.glBindFramebuffer(C.GLenum(target), C.GLuint(framebuffer))
}
func (DefaultContext) BindTexture(target uint32, texture uint32) {
C.glBindTexture(C.GLenum(target), C.GLuint(texture))
}
func (DefaultContext) BlendFunc(sfactor uint32, dfactor uint32) {
C.glBlendFunc(C.GLenum(sfactor), C.GLenum(dfactor))
}
func (DefaultContext) BufferData(target uint32, size int, data []byte, usage uint32) {
var p *byte
if data != nil {
p = &data[0]
}
C.glBufferData(C.GLenum(target), C.GLsizeiptr(size), unsafe.Pointer(p), C.GLenum(usage))
}
func (DefaultContext) BufferSubData(target uint32, offset int, data []byte) {
C.glBufferSubData(C.GLenum(target), C.GLintptr(offset), C.GLsizeiptr(len(data)), unsafe.Pointer(&data[0]))
}
func (DefaultContext) CheckFramebufferStatus(target uint32) uint32 {
return uint32(C.glCheckFramebufferStatus(C.GLenum(target)))
}
func (DefaultContext) CompileShader(shader uint32) {
C.glCompileShader(C.GLuint(shader))
}
func (DefaultContext) CreateProgram() uint32 {
return uint32(C.glCreateProgram())
}
func (DefaultContext) CreateShader(xtype uint32) uint32 {
return uint32(C.glCreateShader(C.GLenum(xtype)))
}
func (DefaultContext) DeleteBuffers(buffers []uint32) {
C.glDeleteBuffers(C.GLsizei(len(buffers)), (*C.GLuint)(unsafe.Pointer(&buffers[0])))
}
func (DefaultContext) DeleteFramebuffers(framebuffers []uint32) {
C.glDeleteFramebuffers(C.GLsizei(len(framebuffers)), (*C.GLuint)(unsafe.Pointer(&framebuffers[0])))
}
func (DefaultContext) DeleteProgram(program uint32) {
C.glDeleteProgram(C.GLuint(program))
}
func (DefaultContext) DeleteShader(shader uint32) {
C.glDeleteShader(C.GLuint(shader))
}
func (DefaultContext) DeleteTextures(textures []uint32) {
C.glDeleteTextures(C.GLsizei(len(textures)), (*C.GLuint)(unsafe.Pointer(&textures[0])))
}
func (DefaultContext) DisableVertexAttribArray(index uint32) {
C.glDisableVertexAttribArray(C.GLuint(index))
}
func (DefaultContext) DrawElements(mode uint32, count int32, xtype uint32, offset int) {
C.glDrawElements(C.GLenum(mode), C.GLsizei(count), C.GLenum(xtype), unsafe.Pointer(uintptr(offset)))
}
func (DefaultContext) Enable(cap uint32) {
C.glEnable(C.GLenum(cap))
}
func (DefaultContext) EnableVertexAttribArray(index uint32) {
C.glEnableVertexAttribArray(C.GLuint(index))
}
func (DefaultContext) Flush() {
C.glFlush()
}
func (DefaultContext) FramebufferTexture2D(target uint32, attachment uint32, textarget uint32, texture uint32, level int32) {
C.glFramebufferTexture2D(C.GLenum(target), C.GLenum(attachment), C.GLenum(textarget), C.GLuint(texture), C.GLint(level))
}
func (DefaultContext) GenBuffers(n int32) []uint32 {
buffers := make([]uint32, n)
C.glGenBuffers(C.GLsizei(n), (*C.GLuint)(unsafe.Pointer(&buffers[0])))
return buffers
}
func (DefaultContext) GenFramebuffers(n int32) []uint32 {
framebuffers := make([]uint32, n)
C.glGenFramebuffers(C.GLsizei(n), (*C.GLuint)(unsafe.Pointer(&framebuffers[0])))
return framebuffers
}
func (DefaultContext) GenTextures(n int32) []uint32 {
textures := make([]uint32, n)
C.glGenTextures(C.GLsizei(n), (*C.GLuint)(unsafe.Pointer(&textures[0])))
return textures
}
func (DefaultContext) GetError() uint32 {
return uint32(C.glGetError())
}
func (DefaultContext) GetIntegerv(dst []int32, pname uint32) {
C.glGetIntegerv(C.GLenum(pname), (*C.GLint)(unsafe.Pointer(&dst[0])))
}
func (DefaultContext) GetProgramiv(dst []int32, program uint32, pname uint32) {
C.glGetProgramiv(C.GLuint(program), C.GLenum(pname), (*C.GLint)(unsafe.Pointer(&dst[0])))
}
func (d DefaultContext) GetProgramInfoLog(program uint32) string {
buflens := make([]int32, 1)
d.GetProgramiv(buflens, program, INFO_LOG_LENGTH)
buflen := buflens[0]
if buflen == 0 {
return ""
}
buf := make([]byte, buflen)
var length int32
C.glGetProgramInfoLog(C.GLuint(program), C.GLsizei(buflen), (*C.GLsizei)(unsafe.Pointer(&length)), (*C.GLchar)(unsafe.Pointer(&buf[0])))
return string(buf[:length])
}
func (DefaultContext) GetShaderiv(dst []int32, shader uint32, pname uint32) {
C.glGetShaderiv(C.GLuint(shader), C.GLenum(pname), (*C.GLint)(unsafe.Pointer(&dst[0])))
}
func (d DefaultContext) GetShaderInfoLog(shader uint32) string {
buflens := make([]int32, 1)
d.GetShaderiv(buflens, shader, INFO_LOG_LENGTH)
buflen := buflens[0]
if buflen == 0 {
return ""
}
buf := make([]byte, buflen)
var length int32
C.glGetShaderInfoLog(C.GLuint(shader), C.GLsizei(buflen), (*C.GLsizei)(unsafe.Pointer(&length)), (*C.GLchar)(unsafe.Pointer(&buf[0])))
return string(buf[:length])
}
func (DefaultContext) GetShaderPrecisionFormat(shadertype uint32, precisiontype uint32) (rangeLow, rangeHigh, precision int) {
var r [2]int32
var p int32
C.glGetShaderPrecisionFormat(C.GLenum(shadertype), C.GLenum(precisiontype), (*C.GLint)(unsafe.Pointer(&r[0])), (*C.GLint)(unsafe.Pointer(&p)))
return int(r[0]), int(r[1]), int(p)
}
func (DefaultContext) GetUniformLocation(program uint32, name string) int32 {
s, free := cString(name)
defer free()
return int32(C.glGetUniformLocation(C.GLuint(program), (*C.GLchar)(unsafe.Pointer(s))))
}
func (DefaultContext) IsFramebuffer(framebuffer uint32) bool {
return C.glIsFramebuffer(C.GLuint(framebuffer)) != FALSE
}
func (DefaultContext) IsProgram(program uint32) bool {
return C.glIsProgram(C.GLuint(program)) != FALSE
}
func (DefaultContext) IsTexture(texture uint32) bool {
return C.glIsTexture(C.GLuint(texture)) != FALSE
}
func (DefaultContext) LinkProgram(program uint32) {
C.glLinkProgram(C.GLuint(program))
}
func (DefaultContext) PixelStorei(pname uint32, param int32) {
C.glPixelStorei(C.GLenum(pname), C.GLint(param))
}
func (DefaultContext) ReadPixels(dst []byte, x int32, y int32, width int32, height int32, format uint32, xtype uint32) {
C.glReadPixels(C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), C.GLenum(xtype), unsafe.Pointer(&dst[0]))
}
func (DefaultContext) ShaderSource(shader uint32, xstring string) {
s, free := cStringPtr(xstring)
defer free()
C.glShaderSource(C.GLuint(shader), 1, (**C.GLchar)(unsafe.Pointer(s)), nil)
}
func (DefaultContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
var p *byte
if pixels != nil {
p = &pixels[0]
}
C.glTexImage2D(C.GLenum(target), C.GLint(level), C.GLint(internalformat), C.GLsizei(width), C.GLsizei(height), 0 /* border */, C.GLenum(format), C.GLenum(xtype), unsafe.Pointer(p))
}
func (DefaultContext) TexParameteri(target uint32, pname uint32, param int32) {
C.glTexParameteri(C.GLenum(target), C.GLenum(pname), C.GLint(param))
}
func (DefaultContext) TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
C.glTexSubImage2D(C.GLenum(target), C.GLint(level), C.GLint(xoffset), C.GLint(yoffset), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), C.GLenum(xtype), unsafe.Pointer(&pixels[0]))
}
func (DefaultContext) Uniform1f(location int32, v0 float32) {
C.glUniform1f(C.GLint(location), C.GLfloat(v0))
}
func (DefaultContext) Uniform1fv(location int32, value []float32) {
C.glUniform1fv(C.GLint(location), C.GLsizei(len(value)), (*C.GLfloat)(unsafe.Pointer(&value[0])))
}
func (DefaultContext) Uniform1i(location int32, v0 int32) {
C.glUniform1i(C.GLint(location), C.GLint(v0))
}
func (DefaultContext) Uniform2fv(location int32, value []float32) {
C.glUniform2fv(C.GLint(location), C.GLsizei(len(value)/2), (*C.GLfloat)(unsafe.Pointer(&value[0])))
}
func (DefaultContext) Uniform3fv(location int32, value []float32) {
C.glUniform3fv(C.GLint(location), C.GLsizei(len(value)/3), (*C.GLfloat)(unsafe.Pointer(&value[0])))
}
func (DefaultContext) Uniform4fv(location int32, value []float32) {
C.glUniform4fv(C.GLint(location), C.GLsizei(len(value)/4), (*C.GLfloat)(unsafe.Pointer(&value[0])))
}
func (DefaultContext) UniformMatrix2fv(location int32, transpose bool, value []float32) {
C.glUniformMatrix2fv(C.GLint(location), C.GLsizei(len(value)/4), glBool(transpose), (*C.GLfloat)(unsafe.Pointer(&value[0])))
}
func (DefaultContext) UniformMatrix3fv(location int32, transpose bool, value []float32) {
C.glUniformMatrix3fv(C.GLint(location), C.GLsizei(len(value)/9), glBool(transpose), (*C.GLfloat)(unsafe.Pointer(&value[0])))
}
func (DefaultContext) UniformMatrix4fv(location int32, transpose bool, value []float32) {
C.glUniformMatrix4fv(C.GLint(location), C.GLsizei(len(value)/16), glBool(transpose), (*C.GLfloat)(unsafe.Pointer(&value[0])))
}
func (DefaultContext) UseProgram(program uint32) {
C.glUseProgram(C.GLuint(program))
}
func (DefaultContext) VertexAttribPointer(index uint32, size int32, xtype uint32, normalized bool, stride int32, offset int) {
C.glVertexAttribPointer(C.GLuint(index), C.GLint(size), C.GLenum(xtype), glBool(normalized), C.GLsizei(stride), unsafe.Pointer(uintptr(offset)))
}
func (DefaultContext) Viewport(x int32, y int32, width int32, height int32) {
C.glViewport(C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height))
}

View File

@ -0,0 +1,298 @@
// Copyright 2020 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
package gles
import (
"golang.org/x/mobile/gl"
)
type GomobileContext struct {
ctx gl.Context
}
func gmProgram(program uint32) gl.Program {
return gl.Program{
Init: true,
Value: program,
}
}
func NewGomobileContext(ctx gl.Context) *GomobileContext {
return &GomobileContext{ctx}
}
func (g *GomobileContext) ActiveTexture(texture uint32) {
g.ctx.ActiveTexture(gl.Enum(texture))
}
func (g *GomobileContext) AttachShader(program uint32, shader uint32) {
g.ctx.AttachShader(gmProgram(program), gl.Shader{Value: shader})
}
func (g *GomobileContext) BindAttribLocation(program uint32, index uint32, name string) {
g.ctx.BindAttribLocation(gmProgram(program), gl.Attrib{Value: uint(index)}, name)
}
func (g *GomobileContext) BindBuffer(target uint32, buffer uint32) {
g.ctx.BindBuffer(gl.Enum(target), gl.Buffer{Value: buffer})
}
func (g *GomobileContext) BindFramebuffer(target uint32, framebuffer uint32) {
g.ctx.BindFramebuffer(gl.Enum(target), gl.Framebuffer{Value: framebuffer})
}
func (g *GomobileContext) BindTexture(target uint32, texture uint32) {
g.ctx.BindTexture(gl.Enum(target), gl.Texture{Value: texture})
}
func (g *GomobileContext) BlendFunc(sfactor uint32, dfactor uint32) {
g.ctx.BlendFunc(gl.Enum(sfactor), gl.Enum(dfactor))
}
func (g *GomobileContext) BufferData(target uint32, size int, data []byte, usage uint32) {
if data == nil {
g.ctx.BufferInit(gl.Enum(target), size, gl.Enum(usage))
} else {
if size != len(data) {
panic("gles: size and len(data) must be same at BufferData")
}
g.ctx.BufferData(gl.Enum(target), data, gl.Enum(usage))
}
}
func (g *GomobileContext) BufferSubData(target uint32, offset int, data []byte) {
g.ctx.BufferSubData(gl.Enum(target), offset, data)
}
func (g *GomobileContext) CheckFramebufferStatus(target uint32) uint32 {
return uint32(g.ctx.CheckFramebufferStatus(gl.Enum(target)))
}
func (g *GomobileContext) CompileShader(shader uint32) {
g.ctx.CompileShader(gl.Shader{Value: shader})
}
func (g *GomobileContext) CreateProgram() uint32 {
return g.ctx.CreateProgram().Value
}
func (g *GomobileContext) CreateShader(xtype uint32) uint32 {
return g.ctx.CreateShader(gl.Enum(xtype)).Value
}
func (g *GomobileContext) DeleteBuffers(buffers []uint32) {
for _, b := range buffers {
g.ctx.DeleteBuffer(gl.Buffer{Value: b})
}
}
func (g *GomobileContext) DeleteFramebuffers(framebuffers []uint32) {
for _, b := range framebuffers {
g.ctx.DeleteFramebuffer(gl.Framebuffer{Value: b})
}
}
func (g *GomobileContext) DeleteProgram(program uint32) {
g.ctx.DeleteProgram(gmProgram(program))
}
func (g *GomobileContext) DeleteShader(shader uint32) {
g.ctx.DeleteShader(gl.Shader{Value: shader})
}
func (g *GomobileContext) DeleteTextures(textures []uint32) {
for _, t := range textures {
g.ctx.DeleteTexture(gl.Texture{Value: t})
}
}
func (g *GomobileContext) DisableVertexAttribArray(index uint32) {
g.ctx.DisableVertexAttribArray(gl.Attrib{Value: uint(index)})
}
func (g *GomobileContext) DrawElements(mode uint32, count int32, xtype uint32, offset int) {
g.ctx.DrawElements(gl.Enum(mode), int(count), gl.Enum(xtype), offset)
}
func (g *GomobileContext) Enable(cap uint32) {
g.ctx.Enable(gl.Enum(gl.Enum(cap)))
}
func (g *GomobileContext) EnableVertexAttribArray(index uint32) {
g.ctx.EnableVertexAttribArray(gl.Attrib{Value: uint(index)})
}
func (g *GomobileContext) Flush() {
g.ctx.Flush()
}
func (g *GomobileContext) FramebufferTexture2D(target uint32, attachment uint32, textarget uint32, texture uint32, level int32) {
g.ctx.FramebufferTexture2D(gl.Enum(target), gl.Enum(attachment), gl.Enum(textarget), gl.Texture{Value: texture}, int(level))
}
func (g *GomobileContext) GenBuffers(n int32) []uint32 {
buffers := make([]uint32, n)
for i := range buffers {
buffers[i] = g.ctx.CreateBuffer().Value
}
return buffers
}
func (g *GomobileContext) GenFramebuffers(n int32) []uint32 {
framebuffers := make([]uint32, n)
for i := range framebuffers {
framebuffers[i] = g.ctx.CreateFramebuffer().Value
}
return framebuffers
}
func (g *GomobileContext) GenTextures(n int32) []uint32 {
textures := make([]uint32, n)
for i := range textures {
textures[i] = g.ctx.CreateTexture().Value
}
return textures
}
func (g *GomobileContext) GetError() uint32 {
return uint32(g.ctx.GetError())
}
func (g *GomobileContext) GetIntegerv(dst []int32, pname uint32) {
g.ctx.GetIntegerv(dst, gl.Enum(pname))
}
func (g *GomobileContext) GetProgramiv(dst []int32, program uint32, pname uint32) {
dst[0] = int32(g.ctx.GetProgrami(gmProgram(program), gl.Enum(pname)))
}
func (g *GomobileContext) GetProgramInfoLog(program uint32) string {
return g.ctx.GetProgramInfoLog(gmProgram(program))
}
func (g *GomobileContext) GetShaderiv(dst []int32, shader uint32, pname uint32) {
dst[0] = int32(g.ctx.GetShaderi(gl.Shader{Value: shader}, gl.Enum(pname)))
}
func (g *GomobileContext) GetShaderInfoLog(shader uint32) string {
return g.ctx.GetShaderInfoLog(gl.Shader{Value: shader})
}
func (g *GomobileContext) GetShaderPrecisionFormat(shadertype uint32, precisiontype uint32) (rangeLow, rangeHigh, precision int) {
return g.ctx.GetShaderPrecisionFormat(gl.Enum(shadertype), gl.Enum(precisiontype))
}
func (g *GomobileContext) GetUniformLocation(program uint32, name string) int32 {
return g.ctx.GetUniformLocation(gmProgram(program), name).Value
}
func (g *GomobileContext) IsFramebuffer(framebuffer uint32) bool {
return g.ctx.IsFramebuffer(gl.Framebuffer{Value: framebuffer})
}
func (g *GomobileContext) IsProgram(program uint32) bool {
return g.ctx.IsProgram(gmProgram(program))
}
func (g *GomobileContext) IsTexture(texture uint32) bool {
return g.ctx.IsTexture(gl.Texture{Value: texture})
}
func (g *GomobileContext) LinkProgram(program uint32) {
g.ctx.LinkProgram(gmProgram(program))
}
func (g *GomobileContext) PixelStorei(pname uint32, param int32) {
g.ctx.PixelStorei(gl.Enum(pname), param)
}
func (g *GomobileContext) ReadPixels(dst []byte, x int32, y int32, width int32, height int32, format uint32, xtype uint32) {
g.ctx.ReadPixels(dst, int(x), int(y), int(width), int(height), gl.Enum(format), gl.Enum(xtype))
}
func (g *GomobileContext) ShaderSource(shader uint32, xstring string) {
g.ctx.ShaderSource(gl.Shader{Value: shader}, xstring)
}
func (g *GomobileContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
g.ctx.TexImage2D(gl.Enum(target), int(level), int(internalformat), int(width), int(height), gl.Enum(format), gl.Enum(xtype), pixels)
}
func (g *GomobileContext) TexParameteri(target uint32, pname uint32, param int32) {
g.ctx.TexParameteri(gl.Enum(target), gl.Enum(pname), int(param))
}
func (g *GomobileContext) TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
g.ctx.TexSubImage2D(gl.Enum(target), int(level), int(xoffset), int(yoffset), int(width), int(height), gl.Enum(format), gl.Enum(xtype), pixels)
}
func (g *GomobileContext) Uniform1f(location int32, v0 float32) {
g.ctx.Uniform1f(gl.Uniform{Value: location}, v0)
}
func (g *GomobileContext) Uniform1fv(location int32, value []float32) {
g.ctx.Uniform1fv(gl.Uniform{Value: location}, value)
}
func (g *GomobileContext) Uniform1i(location int32, v0 int32) {
g.ctx.Uniform1i(gl.Uniform{Value: location}, int(v0))
}
func (g *GomobileContext) Uniform2fv(location int32, value []float32) {
g.ctx.Uniform2fv(gl.Uniform{Value: location}, value)
}
func (g *GomobileContext) Uniform3fv(location int32, value []float32) {
g.ctx.Uniform3fv(gl.Uniform{Value: location}, value)
}
func (g *GomobileContext) Uniform4fv(location int32, value []float32) {
g.ctx.Uniform4fv(gl.Uniform{Value: location}, value)
}
func (g *GomobileContext) UniformMatrix2fv(location int32, transpose bool, value []float32) {
if transpose {
panic("gles: UniformMatrix2fv with transpose is not implemented")
}
g.ctx.UniformMatrix2fv(gl.Uniform{Value: location}, value)
}
func (g *GomobileContext) UniformMatrix3fv(location int32, transpose bool, value []float32) {
if transpose {
panic("gles: UniformMatrix3fv with transpose is not implemented")
}
g.ctx.UniformMatrix3fv(gl.Uniform{Value: location}, value)
}
func (g *GomobileContext) UniformMatrix4fv(location int32, transpose bool, value []float32) {
if transpose {
panic("gles: UniformMatrix4fv with transpose is not implemented")
}
g.ctx.UniformMatrix4fv(gl.Uniform{Value: location}, value)
}
func (g *GomobileContext) UseProgram(program uint32) {
g.ctx.UseProgram(gmProgram(program))
}
func (g *GomobileContext) VertexAttribPointer(index uint32, size int32, xtype uint32, normalized bool, stride int32, offset int) {
g.ctx.VertexAttribPointer(gl.Attrib{Value: uint(index)}, int(size), gl.Enum(xtype), normalized, int(stride), int(offset))
}
func (g *GomobileContext) Viewport(x int32, y int32, width int32, height int32) {
g.ctx.Viewport(int(x), int(y), int(width), int(height))
}

View File

@ -0,0 +1,77 @@
// Copyright 2020 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
package gles
type Context interface {
ActiveTexture(texture uint32)
AttachShader(program uint32, shader uint32)
BindAttribLocation(program uint32, index uint32, name string)
BindBuffer(target uint32, buffer uint32)
BindFramebuffer(target uint32, framebuffer uint32)
BindTexture(target uint32, texture uint32)
BlendFunc(sfactor uint32, dfactor uint32)
BufferData(target uint32, size int, data []byte, usage uint32)
BufferSubData(target uint32, offset int, data []byte)
CheckFramebufferStatus(target uint32) uint32
CompileShader(shader uint32)
CreateProgram() uint32
CreateShader(xtype uint32) uint32
DeleteBuffers(buffers []uint32)
DeleteFramebuffers(framebuffers []uint32)
DeleteProgram(program uint32)
DeleteShader(shader uint32)
DeleteTextures(textures []uint32)
DisableVertexAttribArray(index uint32)
DrawElements(mode uint32, count int32, xtype uint32, offset int)
Enable(cap uint32)
EnableVertexAttribArray(index uint32)
Flush()
FramebufferTexture2D(target uint32, attachment uint32, textarget uint32, texture uint32, level int32)
GenBuffers(n int32) []uint32
GenFramebuffers(n int32) []uint32
GenTextures(n int32) []uint32
GetError() uint32
GetIntegerv(dst []int32, pname uint32)
GetProgramiv(dst []int32, program uint32, pname uint32)
GetProgramInfoLog(program uint32) string
GetShaderiv(dst []int32, shader uint32, pname uint32)
GetShaderInfoLog(shader uint32) string
GetShaderPrecisionFormat(shadertype uint32, precisiontype uint32) (rangeLow, rangeHigh, precision int)
GetUniformLocation(program uint32, name string) int32
IsFramebuffer(framebuffer uint32) bool
IsProgram(program uint32) bool
IsTexture(texture uint32) bool
LinkProgram(program uint32)
PixelStorei(pname uint32, param int32)
ReadPixels(dst []byte, x int32, y int32, width int32, height int32, format uint32, xtype uint32)
ShaderSource(shader uint32, xstring string)
TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte)
TexParameteri(target uint32, pname uint32, param int32)
TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels []byte)
Uniform1f(location int32, v0 float32)
Uniform1fv(location int32, value []float32)
Uniform1i(location int32, v0 int32)
Uniform2fv(location int32, value []float32)
Uniform3fv(location int32, value []float32)
Uniform4fv(location int32, value []float32)
UniformMatrix2fv(location int32, transpose bool, value []float32)
UniformMatrix3fv(location int32, transpose bool, value []float32)
UniformMatrix4fv(location int32, transpose bool, value []float32)
UseProgram(program uint32)
VertexAttribPointer(index uint32, size int32, xtype uint32, normalized bool, stride int32, offset int)
Viewport(x int32, y int32, width int32, height int32)
}

View File

@ -0,0 +1,39 @@
// Copyright 2020 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
package gles
// #include <stdlib.h>
import "C"
import (
"unsafe"
)
func cString(str string) (uintptr, func()) {
ptr := C.CString(str)
return uintptr(unsafe.Pointer(ptr)), func() { C.free(unsafe.Pointer(ptr)) }
}
func cStringPtr(str string) (uintptr, func()) {
s, free := cString(str)
ptr := C.malloc(C.size_t(unsafe.Sizeof((*int)(nil))))
*(*uintptr)(ptr) = s
return uintptr(ptr), func() {
free()
C.free(ptr)
}
}

View File

@ -18,8 +18,14 @@ package opengl
import (
"golang.org/x/mobile/gl"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gles"
)
func (g *Graphics) SetMobileGLContext(context gl.Context) {
g.context.gl = context
func init() {
theGraphics.context.ctx = gles.DefaultContext{}
}
func (g *Graphics) SetGomobileGLContext(context gl.Context) {
g.context.ctx = gles.NewGomobileContext(context)
}

View File

@ -21,7 +21,6 @@ import (
"runtime/debug"
"sync"
"sync/atomic"
"time"
"unicode"
"golang.org/x/mobile/app"
@ -84,45 +83,6 @@ func (u *UserInterface) Update() error {
}
renderCh <- struct{}{}
if u.Graphics().IsGL() {
if u.glWorker == nil {
panic("mobile: glWorker must be initialized but not")
}
workAvailable := u.glWorker.WorkAvailable()
for {
// When the two channels don't receive for a while, call DoWork forcibly to avoid freeze
// (#1322, #1332).
//
// In theory, this timeout should not be necessary. However, it looks like this 'select'
// statement sometimes blocks forever on some Android devices like Pixel 4(a). Apparently
// workAvailable sometimes not receives even though there are queued OpenGL functions.
// Call DoWork for such case as a symptomatic treatment.
//
// Calling DoWork without waiting for workAvailable is safe. If there are no tasks, DoWork
// should return immediately.
//
// TODO: Fix the root cause. Note that this is pretty hard since e.g., logging affects the
// scheduling and freezing might not happen with logging.
t := time.NewTimer(100 * time.Millisecond)
select {
case <-workAvailable:
if !t.Stop() {
<-t.C
}
u.glWorker.DoWork()
case <-renderEndCh:
if !t.Stop() {
<-t.C
}
return nil
case <-t.C:
u.glWorker.DoWork()
}
}
}
go func() {
<-renderEndCh
u.t.Call(func() error {
@ -151,8 +111,7 @@ type UserInterface struct {
input Input
t *thread.Thread
glWorker gl.Worker
t *thread.Thread
m sync.RWMutex
}
@ -306,14 +265,11 @@ func (u *UserInterface) run(context driver.UIContext, mainloop bool) (err error)
u.context = context
if u.Graphics().IsGL() {
var ctx gl.Context
if mainloop {
ctx = <-glContextCh
} else {
ctx, u.glWorker = gl.NewContext()
}
u.Graphics().(*opengl.Graphics).SetMobileGLContext(ctx)
if mainloop {
// When mainloop is true, gomobile-build is used. In this case, GL functions must be called via
// gl.Context so that they are called on the appropriate thread.
ctx := <-glContextCh
u.Graphics().(*opengl.Graphics).SetGomobileGLContext(ctx)
} else {
u.t = thread.New()
graphicscommand.SetMainThread(u.t)