mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
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:
parent
2740938460
commit
f611b48c71
@ -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)
|
||||
}
|
||||
|
313
internal/graphicsdriver/opengl/gles/default.go
Normal file
313
internal/graphicsdriver/opengl/gles/default.go
Normal 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))
|
||||
}
|
298
internal/graphicsdriver/opengl/gles/gomobile.go
Normal file
298
internal/graphicsdriver/opengl/gles/gomobile.go
Normal 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))
|
||||
}
|
77
internal/graphicsdriver/opengl/gles/interface.go
Normal file
77
internal/graphicsdriver/opengl/gles/interface.go
Normal 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)
|
||||
}
|
39
internal/graphicsdriver/opengl/gles/str.go
Normal file
39
internal/graphicsdriver/opengl/gles/str.go
Normal 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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user