internal/graphicsdriver/opengl: reduce context functions

This commit is contained in:
Hajime Hoshi 2022-11-17 13:33:32 +09:00
parent 4de6da0a50
commit 95b4e67c77
8 changed files with 55 additions and 155 deletions

View File

@ -134,7 +134,7 @@ func (c *context) bindTexture(t textureNative) {
if c.lastTexture == t {
return
}
c.bindTextureImpl(t)
c.ctx.BindTexture(gl.TEXTURE_2D, uint32(t))
c.lastTexture = t
}
@ -142,7 +142,7 @@ func (c *context) bindRenderbuffer(r renderbufferNative) {
if c.lastRenderbuffer == r {
return
}
c.bindRenderbufferImpl(r)
c.ctx.BindRenderbuffer(gl.RENDERBUFFER, uint32(r))
c.lastRenderbuffer = r
}
@ -150,7 +150,7 @@ func (c *context) bindFramebuffer(f framebufferNative) {
if c.lastFramebuffer == f {
return
}
c.bindFramebufferImpl(f)
c.ctx.BindFramebuffer(gl.FRAMEBUFFER, uint32(f))
c.lastFramebuffer = f
}
@ -160,7 +160,7 @@ func (c *context) setViewport(f *framebuffer) {
// On some environments, viewport size must be within the framebuffer size.
// e.g. Edge (#71), Chrome on GPD Pocket (#420), macOS Mojave (#691).
// Use the same size of the framebuffer here.
c.setViewportImpl(f.width, f.height)
c.ctx.Viewport(0, 0, int32(f.width), int32(f.height))
// glViewport must be called at least at every frame on iOS.
// As the screen framebuffer is the last render target, next SetViewport should be
@ -181,7 +181,7 @@ func (c *context) getScreenFramebuffer() framebufferNative {
func (c *context) getMaxTextureSize() int {
c.maxTextureSizeOnce.Do(func() {
c.maxTextureSize = c.maxTextureSizeImpl()
c.maxTextureSize = c.ctx.GetInteger(gl.MAX_TEXTURE_SIZE)
})
return c.maxTextureSize
}
@ -231,10 +231,6 @@ func (c *context) blend(blend graphicsdriver.Blend) {
)
}
func (c *context) scissor(x, y, width, height int) {
c.ctx.Scissor(int32(x), int32(y), int32(width), int32(height))
}
func (c *context) newTexture(width, height int) (textureNative, error) {
t := c.ctx.CreateTexture()
if t <= 0 {
@ -260,10 +256,6 @@ func (c *context) newTexture(width, height int) (textureNative, error) {
return textureNative(t), nil
}
func (c *context) bindFramebufferImpl(f framebufferNative) {
c.ctx.BindFramebuffer(gl.FRAMEBUFFER, uint32(f))
}
func (c *context) framebufferPixels(buf []byte, f *framebuffer, x, y, width, height int) error {
if got, want := len(buf), 4*width*height; got != want {
return fmt.Errorf("opengl: len(buf) must be %d but was %d at framebufferPixels", got, want)
@ -285,14 +277,6 @@ func (c *context) framebufferPixelsToBuffer(f *framebuffer, buffer buffer, width
c.ctx.BindBuffer(gl.PIXEL_PACK_BUFFER, 0)
}
func (c *context) activeTexture(idx int) {
c.ctx.ActiveTexture(uint32(gl.TEXTURE0 + idx))
}
func (c *context) bindTextureImpl(t textureNative) {
c.ctx.BindTexture(gl.TEXTURE_2D, uint32(t))
}
func (c *context) deleteTexture(t textureNative) {
if !c.ctx.IsTexture(uint32(t)) {
return
@ -303,10 +287,6 @@ func (c *context) deleteTexture(t textureNative) {
c.ctx.DeleteTexture(uint32(t))
}
func (c *context) isTexture(t textureNative) bool {
return c.ctx.IsTexture(uint32(t))
}
func (c *context) newRenderbuffer(width, height int) (renderbufferNative, error) {
r := c.ctx.CreateRenderbuffer()
if r <= 0 {
@ -344,10 +324,6 @@ func (c *context) newRenderbuffer(width, height int) (renderbufferNative, error)
return renderbuffer, nil
}
func (c *context) bindRenderbufferImpl(r renderbufferNative) {
c.ctx.BindRenderbuffer(gl.RENDERBUFFER, uint32(r))
}
func (c *context) deleteRenderbuffer(r renderbufferNative) {
if !c.ctx.IsRenderbuffer(uint32(r)) {
return
@ -388,10 +364,6 @@ func (c *context) bindStencilBuffer(f framebufferNative, r renderbufferNative) e
return nil
}
func (c *context) setViewportImpl(width, height int) {
c.ctx.Viewport(0, 0, int32(width), int32(height))
}
func (c *context) deleteFramebuffer(f framebufferNative) {
if !c.ctx.IsFramebuffer(uint32(f)) {
return
@ -407,14 +379,6 @@ func (c *context) deleteFramebuffer(f framebufferNative) {
c.ctx.DeleteFramebuffer(uint32(f))
}
func (c *context) newVertexShader(source string) (shader, error) {
return c.newShader(gl.VERTEX_SHADER, source)
}
func (c *context) newFragmentShader(source string) (shader, error) {
return c.newShader(gl.FRAGMENT_SHADER, source)
}
func (c *context) newShader(shaderType uint32, source string) (shader, error) {
s := c.ctx.CreateShader(shaderType)
if s == 0 {
@ -431,10 +395,6 @@ func (c *context) newShader(shaderType uint32, source string) (shader, error) {
return shader(s), nil
}
func (c *context) deleteShader(s shader) {
c.ctx.DeleteShader(uint32(s))
}
func (c *context) newProgram(shaders []shader, attributes []string) (program, error) {
p := c.ctx.CreateProgram()
if p == 0 {
@ -457,10 +417,6 @@ func (c *context) newProgram(shaders []shader, attributes []string) (program, er
return program(p), nil
}
func (c *context) useProgram(p program) {
c.ctx.UseProgram(uint32(p))
}
func (c *context) deleteProgram(p program) {
c.locationCache.deleteProgram(p)
@ -470,10 +426,6 @@ func (c *context) deleteProgram(p program) {
c.ctx.DeleteProgram(uint32(p))
}
func (c *context) getUniformLocationImpl(p program, location string) uniformLocation {
return uniformLocation(c.ctx.GetUniformLocation(uint32(p), location))
}
func (c *context) uniformInt(p program, location string, v int) bool {
l := c.locationCache.GetUniformLocation(c, p, location)
if l == invalidUniform {
@ -517,18 +469,6 @@ func (c *context) uniforms(p program, location string, v []uint32, typ shaderir.
return true
}
func (c *context) vertexAttribPointer(index int, size int, stride int, offset int) {
c.ctx.VertexAttribPointer(uint32(index), int32(size), gl.FLOAT, false, int32(stride), offset)
}
func (c *context) enableVertexAttribArray(index int) {
c.ctx.EnableVertexAttribArray(uint32(index))
}
func (c *context) disableVertexAttribArray(index int) {
c.ctx.DisableVertexAttribArray(uint32(index))
}
func (c *context) newArrayBuffer(size int) buffer {
b := c.ctx.CreateBuffer()
c.ctx.BindBuffer(gl.ARRAY_BUFFER, b)
@ -543,14 +483,6 @@ func (c *context) newElementArrayBuffer(size int) buffer {
return buffer(b)
}
func (c *context) bindArrayBuffer(b buffer) {
c.ctx.BindBuffer(gl.ARRAY_BUFFER, uint32(b))
}
func (c *context) bindElementArrayBuffer(b buffer) {
c.ctx.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, uint32(b))
}
func (c *context) arrayBufferSubData(data []float32) {
s := unsafe.Slice((*byte)(unsafe.Pointer(&data[0])), len(data)*4)
c.ctx.BufferSubData(gl.ARRAY_BUFFER, 0, s)
@ -560,51 +492,3 @@ func (c *context) elementArrayBufferSubData(data []uint16) {
s := unsafe.Slice((*byte)(unsafe.Pointer(&data[0])), len(data)*2)
c.ctx.BufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, s)
}
func (c *context) deleteBuffer(b buffer) {
c.ctx.DeleteBuffer(uint32(b))
}
func (c *context) drawElements(len int, offsetInBytes int) {
c.ctx.DrawElements(gl.TRIANGLES, int32(len), gl.UNSIGNED_SHORT, offsetInBytes)
}
func (c *context) maxTextureSizeImpl() int {
return c.ctx.GetInteger(gl.MAX_TEXTURE_SIZE)
}
func (c *context) flush() {
c.ctx.Flush()
}
func (c *context) texSubImage2D(t textureNative, args []*graphicsdriver.WritePixelsArgs) {
c.bindTexture(t)
for _, a := range args {
c.ctx.TexSubImage2D(gl.TEXTURE_2D, 0, int32(a.X), int32(a.Y), int32(a.Width), int32(a.Height), gl.RGBA, gl.UNSIGNED_BYTE, a.Pixels)
}
}
func (c *context) enableStencilTest() {
c.ctx.Enable(gl.STENCIL_TEST)
}
func (c *context) disableStencilTest() {
c.ctx.Disable(gl.STENCIL_TEST)
}
func (c *context) beginStencilWithEvenOddRule() {
c.ctx.Clear(gl.STENCIL_BUFFER_BIT)
c.ctx.StencilFunc(gl.ALWAYS, 0x00, 0xff)
c.ctx.StencilOp(gl.KEEP, gl.KEEP, gl.INVERT)
c.ctx.ColorMask(false, false, false, false)
}
func (c *context) endStencilWithEvenOddRule() {
c.ctx.StencilFunc(gl.NOTEQUAL, 0x00, 0xff)
c.ctx.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
c.ctx.ColorMask(true, true, true, true)
}
func (c *context) isES() bool {
return c.ctx.IsES()
}

View File

@ -20,6 +20,7 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
)
@ -59,7 +60,7 @@ func (g *Graphics) Begin() error {
func (g *Graphics) End(present bool) error {
// Call glFlush to prevent black flicking (especially on Android (#226) and iOS).
// TODO: examples/sprites worked without this. Is this really needed?
g.context.flush()
g.context.ctx.Flush()
return nil
}
@ -231,27 +232,34 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
if err := destination.ensureStencilBuffer(); err != nil {
return err
}
g.context.enableStencilTest()
g.context.ctx.Enable(gl.STENCIL_TEST)
}
for _, dstRegion := range dstRegions {
g.context.scissor(
int(dstRegion.Region.X),
int(dstRegion.Region.Y),
int(dstRegion.Region.Width),
int(dstRegion.Region.Height),
g.context.ctx.Scissor(
int32(dstRegion.Region.X),
int32(dstRegion.Region.Y),
int32(dstRegion.Region.Width),
int32(dstRegion.Region.Height),
)
if evenOdd {
g.context.beginStencilWithEvenOddRule()
g.context.drawElements(dstRegion.IndexCount, indexOffset*2)
g.context.endStencilWithEvenOddRule()
g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT)
g.context.ctx.StencilFunc(gl.ALWAYS, 0x00, 0xff)
g.context.ctx.StencilOp(gl.KEEP, gl.KEEP, gl.INVERT)
g.context.ctx.ColorMask(false, false, false, false)
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_SHORT, indexOffset*2)
g.context.ctx.StencilFunc(gl.NOTEQUAL, 0x00, 0xff)
g.context.ctx.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
g.context.ctx.ColorMask(true, true, true, true)
}
g.context.drawElements(dstRegion.IndexCount, indexOffset*2) // 2 is uint16 size in bytes
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_SHORT, indexOffset*2) // 2 is uint16 size in bytes
indexOffset += dstRegion.IndexCount
}
if evenOdd {
g.context.disableStencilTest()
g.context.ctx.Disable(gl.STENCIL_TEST)
}
return nil
@ -270,7 +278,7 @@ func (g *Graphics) NeedsRestoring() bool {
if runtime.GOOS == "js" {
return false
}
return g.context.isES()
return g.context.ctx.IsES()
}
func (g *Graphics) NeedsClearingScreen() bool {

View File

@ -21,7 +21,7 @@ import (
)
func (g *Graphics) SetGLFWClientAPI() {
if g.context.isES() {
if g.context.ctx.IsES() {
glfw.WindowHint(glfw.ClientAPI, glfw.OpenGLESAPI)
glfw.WindowHint(glfw.ContextVersionMajor, 2)
glfw.WindowHint(glfw.ContextVersionMinor, 0)

View File

@ -19,6 +19,7 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
)
type Image struct {
@ -37,7 +38,7 @@ func (i *Image) ID() graphicsdriver.ImageID {
}
func (i *Image) IsInvalidated() bool {
return !i.graphics.context.isTexture(i.texture)
return !i.graphics.context.ctx.IsTexture(uint32(i.texture))
}
func (i *Image) Dispose() {
@ -132,9 +133,14 @@ func (i *Image) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
// glFlush is necessary on Android.
// glTexSubImage2D didn't work without this hack at least on Nexus 5x and NuAns NEO [Reloaded] (#211).
if i.graphics.drawCalled {
i.graphics.context.flush()
i.graphics.context.ctx.Flush()
}
i.graphics.drawCalled = false
i.graphics.context.texSubImage2D(i.texture, args)
i.graphics.context.bindTexture(i.texture)
for _, a := range args {
i.graphics.context.ctx.TexSubImage2D(gl.TEXTURE_2D, 0, int32(a.X), int32(a.Y), int32(a.Width), int32(a.Height), gl.RGBA, gl.UNSIGNED_BYTE, a.Pixels)
}
return nil
}

View File

@ -30,7 +30,7 @@ func (c *locationCache) GetUniformLocation(context *context, p program, location
}
l, ok := c.uniformLocationCache[p][location]
if !ok {
l = context.getUniformLocationImpl(p, location)
l = uniformLocation(context.ctx.GetUniformLocation(uint32(p), location))
c.uniformLocationCache[p][location] = l
}
return l

View File

@ -20,6 +20,7 @@ import (
"unsafe"
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
)
@ -70,12 +71,12 @@ func (a *arrayBufferLayout) newArrayBuffer(context *context) buffer {
// enable starts using the array buffer.
func (a *arrayBufferLayout) enable(context *context) {
for i := range a.parts {
context.enableVertexAttribArray(i)
context.ctx.EnableVertexAttribArray(uint32(i))
}
total := a.totalBytes()
offset := 0
for i, p := range a.parts {
context.vertexAttribPointer(i, p.num, total, offset)
context.ctx.VertexAttribPointer(uint32(i), int32(p.num), gl.FLOAT, false, int32(total), offset)
offset += floatSizeInBytes * p.num
}
}
@ -84,7 +85,7 @@ func (a *arrayBufferLayout) enable(context *context) {
func (a *arrayBufferLayout) disable(context *context) {
// TODO: Disabling should be done in reversed order?
for i := range a.parts {
context.disableVertexAttribArray(i)
context.ctx.DisableVertexAttribArray(uint32(i))
}
}
@ -134,7 +135,7 @@ func (s *openGLState) reset(context *context) error {
}
s.lastProgram = 0
context.useProgram(0)
context.ctx.UseProgram(0)
for key := range s.lastUniforms {
delete(s.lastUniforms, key)
}
@ -143,10 +144,10 @@ func (s *openGLState) reset(context *context) error {
// and must not be deleted by DeleteBuffer.
if runtime.GOOS != "js" {
if s.arrayBuffer != 0 {
context.deleteBuffer(s.arrayBuffer)
context.ctx.DeleteBuffer(uint32(s.arrayBuffer))
}
if s.elementArrayBuffer != 0 {
context.deleteBuffer(s.elementArrayBuffer)
context.ctx.DeleteBuffer(uint32(s.elementArrayBuffer))
}
}
@ -199,11 +200,11 @@ func (g *Graphics) textureVariableName(idx int) string {
// useProgram uses the program (programTexture).
func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textures [graphics.ShaderImageCount]textureVariable) error {
if g.state.lastProgram != program {
g.context.useProgram(program)
g.context.ctx.UseProgram(uint32(program))
if g.state.lastProgram == 0 {
theArrayBufferLayout.enable(&g.context)
g.context.bindArrayBuffer(g.state.arrayBuffer)
g.context.bindElementArrayBuffer(g.state.elementArrayBuffer)
g.context.ctx.BindBuffer(gl.ARRAY_BUFFER, uint32(g.state.arrayBuffer))
g.context.ctx.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, uint32(g.state.elementArrayBuffer))
}
g.state.lastProgram = program
@ -211,7 +212,7 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textu
delete(g.state.lastUniforms, k)
}
g.state.lastActiveTexture = 0
g.context.activeTexture(0)
g.context.ctx.ActiveTexture(gl.TEXTURE0)
}
for _, u := range uniforms {
@ -258,7 +259,7 @@ loop:
})
g.context.uniformInt(program, g.textureVariableName(i), idx)
if g.state.lastActiveTexture != idx {
g.context.activeTexture(idx)
g.context.ctx.ActiveTexture(uint32(gl.TEXTURE0 + idx))
g.state.lastActiveTexture = idx
}

View File

@ -18,6 +18,7 @@ import (
"fmt"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/glsl"
)
@ -54,17 +55,17 @@ func (s *Shader) Dispose() {
func (s *Shader) compile() error {
vssrc, fssrc := glsl.Compile(s.ir, s.graphics.context.glslVersion())
vs, err := s.graphics.context.newVertexShader(vssrc)
vs, err := s.graphics.context.newShader(gl.VERTEX_SHADER, vssrc)
if err != nil {
return fmt.Errorf("opengl: vertex shader compile error: %v, source:\n%s", err, vssrc)
}
defer s.graphics.context.deleteShader(vs)
defer s.graphics.context.ctx.DeleteShader(uint32(vs))
fs, err := s.graphics.context.newFragmentShader(fssrc)
fs, err := s.graphics.context.newShader(gl.FRAGMENT_SHADER, fssrc)
if err != nil {
return fmt.Errorf("opengl: fragment shader compile error: %v, source:\n%s", err, fssrc)
}
defer s.graphics.context.deleteShader(fs)
defer s.graphics.context.ctx.DeleteShader(uint32(fs))
p, err := s.graphics.context.newProgram([]shader{vs, fs}, theArrayBufferLayout.names())
if err != nil {

View File

@ -21,7 +21,7 @@ import (
)
func (c *context) glslVersion() glsl.GLSLVersion {
if c.isES() {
if c.ctx.IsES() {
return glsl.GLSLVersionES100
}
return glsl.GLSLVersionDefault