graphicsdriver/opengl: Enable to bind multiple textures (in theory)

This commit is contained in:
Hajime Hoshi 2020-05-17 23:04:13 +09:00
parent 733c463e26
commit 7f2092f964
8 changed files with 66 additions and 8 deletions

View File

@ -198,6 +198,13 @@ func (c *context) framebufferPixels(f *framebuffer, width, height int) ([]byte,
return pixels, nil
}
func (c *context) activeTexture(idx int) {
_ = c.t.Call(func() error {
gl.ActiveTexture(gl.TEXTURE0 + uint32(idx))
return nil
})
}
func (c *context) bindTextureImpl(t textureNative) {
_ = c.t.Call(func() error {
gl.BindTexture(gl.TEXTURE_2D, uint32(t))

View File

@ -112,6 +112,8 @@ var (
unsignedByte js.Value
unsignedShort js.Value
texture0 int
isWebGL2Available bool
)
@ -154,6 +156,7 @@ func init() {
nearest = contextPrototype.Get("NEAREST")
noError = contextPrototype.Get("NO_ERROR")
rgba = contextPrototype.Get("RGBA")
texture0 = contextPrototype.Get("TEXTURE0").Int()
texture2d = contextPrototype.Get("TEXTURE_2D")
textureMagFilter = contextPrototype.Get("TEXTURE_MAG_FILTER")
textureMinFilter = contextPrototype.Get("TEXTURE_MIN_FILTER")
@ -279,6 +282,12 @@ func (c *context) framebufferPixels(f *framebuffer, width, height int) ([]byte,
return jsutil.Uint8ArrayToSlice(p), nil
}
func (c *context) activeTexture(idx int) {
c.ensureGL()
gl := c.gl
gl.Call("activeTexture", texture0+idx)
}
func (c *context) bindTextureImpl(t textureNative) {
c.ensureGL()
gl := c.gl

View File

@ -156,6 +156,11 @@ func (c *context) framebufferPixels(f *framebuffer, width, height int) ([]byte,
return pixels, nil
}
func (c *context) activeTexture(idx int) {
gl := c.gl
gl.ActiveTexture(mgl.Enum(mgl.TEXTURE0 + idx))
}
func (c *context) bindTextureImpl(t textureNative) {
gl := c.gl
gl.BindTexture(mgl.TEXTURE_2D, mgl.Texture(t))

View File

@ -49,6 +49,7 @@ const (
NO_ERROR = 0
READ_WRITE = 0x88BA
RGBA = 0x1908
TEXTURE0 = 0x84C0
TEXTURE_2D = 0x0DE1
TEXTURE_MAG_FILTER = 0x2800
TEXTURE_MIN_FILTER = 0x2801

View File

@ -95,7 +95,8 @@ package gl
// typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
// typedef unsigned short GLhalfNV;
// typedef GLintptr GLvdpauSurfaceNV;
// typedef void (APIENTRY *GLVULKANPROCNV)(void);
//
// typedef void (APIENTRYP GPACTIVETEXTURE)(GLenum texture);
// typedef void (APIENTRYP GPATTACHSHADER)(GLuint program, GLuint shader);
// typedef void (APIENTRYP GPBINDATTRIBLOCATION)(GLuint program, GLuint index, const GLchar * name);
// typedef void (APIENTRYP GPBINDBUFFER)(GLenum target, GLuint buffer);
@ -159,6 +160,9 @@ package gl
// typedef void (APIENTRYP GPVERTEXATTRIBPOINTER)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const uintptr_t pointer);
// typedef void (APIENTRYP GPVIEWPORT)(GLint x, GLint y, GLsizei width, GLsizei height);
//
// static void glowActiveTexture(GPACTIVETEXTURE fnptr, GLenum texture) {
// (*fnptr)(texture);
// }
// static void glowAttachShader(GPATTACHSHADER fnptr, GLuint program, GLuint shader) {
// (*fnptr)(program, shader);
// }
@ -353,6 +357,7 @@ import (
)
var (
gpActiveTexture C.GPACTIVETEXTURE
gpAttachShader C.GPATTACHSHADER
gpBindAttribLocation C.GPBINDATTRIBLOCATION
gpBindBuffer C.GPBINDBUFFER
@ -424,6 +429,10 @@ func boolToInt(b bool) int {
return 0
}
func ActiveTexture(texture uint32) {
C.glowActiveTexture(gpActiveTexture, (C.GLenum)(texture))
}
func AttachShader(program uint32, shader uint32) {
C.glowAttachShader(gpAttachShader, (C.GLuint)(program), (C.GLuint)(shader))
}
@ -675,6 +684,10 @@ func Viewport(x int32, y int32, width int32, height int32) {
// InitWithProcAddrFunc intializes the package using the specified OpenGL
// function pointer loading function. For more cases Init should be used
func InitWithProcAddrFunc(getProcAddr func(name string) unsafe.Pointer) error {
gpActiveTexture = (C.GPACTIVETEXTURE)(getProcAddr("glActiveTexture"))
if gpActiveTexture == nil {
return errors.New("glActiveTexture")
}
gpAttachShader = (C.GPATTACHSHADER)(getProcAddr("glAttachShader"))
if gpAttachShader == nil {
return errors.New("glAttachShader")

View File

@ -10,6 +10,7 @@ import (
)
var (
gpActiveTexture uintptr
gpAttachShader uintptr
gpBindAttribLocation uintptr
gpBindBuffer uintptr
@ -81,6 +82,10 @@ func boolToUintptr(b bool) uintptr {
return 0
}
func ActiveTexture(texture uint32) {
syscall.Syscall(gpActiveTexture, 1, uintptr(texture), 0, 0)
}
func AttachShader(program uint32, shader uint32) {
syscall.Syscall(gpAttachShader, 2, uintptr(program), uintptr(shader), 0)
}
@ -332,6 +337,10 @@ func Viewport(x int32, y int32, width int32, height int32) {
// InitWithProcAddrFunc intializes the package using the specified OpenGL
// function pointer loading function. For more cases Init should be used
func InitWithProcAddrFunc(getProcAddr func(name string) uintptr) error {
gpActiveTexture = getProcAddr("glActiveTexture")
if gpActiveTexture == 0 {
return errors.New("glActiveTexture")
}
gpAttachShader = getProcAddr("glAttachShader")
if gpAttachShader == 0 {
return errors.New("glAttachShader")

View File

@ -160,7 +160,7 @@ func (g *Graphics) Draw(indexLen int, indexOffset int, mode driver.CompositeMode
uniforms["scale"] = scale
}
uniforms["texture"] = source.textureNative
uniforms["texture/0"] = source.textureNative
if err := g.useProgram(program, uniforms); err != nil {
return err

View File

@ -16,6 +16,8 @@ package opengl
import (
"fmt"
"strconv"
"strings"
"github.com/hajimehoshi/ebiten/internal/driver"
"github.com/hajimehoshi/ebiten/internal/graphics"
@ -132,8 +134,9 @@ type openGLState struct {
// programs is OpenGL's program for rendering a texture.
programs map[programKey]program
lastProgram program
lastUniforms map[string]interface{}
lastProgram program
lastUniforms map[string]interface{}
lastActiveTexture int
source *Image
destination *Image
@ -251,6 +254,8 @@ func (g *Graphics) useProgram(program program, uniforms map[string]interface{})
g.state.lastProgram = program
g.state.lastUniforms = map[string]interface{}{}
g.state.lastActiveTexture = 0
g.context.activeTexture(0)
}
for key, u := range uniforms {
@ -271,10 +276,19 @@ func (g *Graphics) useProgram(program program, uniforms map[string]interface{})
g.state.lastUniforms[key] = u
case textureNative:
// Apparently, a texture must be bound every time. The cache is not used here.
// TODO: Use another value than 0 when binding multiple textures.
g.context.uniformInt(program, key, 0)
// We don't have to call gl.ActiveTexture here: GL_TEXTURE0 is the default active texture
// See also: https://www.opengl.org/sdk/docs/man2/xhtml/glActiveTexture.xml
tokens := strings.SplitN(key, "/", 2)
if len(tokens) != 2 {
return fmt.Errorf("opengl: a uniform variable name for textures must be '[name]/[index]' but %s", key)
}
idx, err := strconv.Atoi(tokens[1])
if err != nil {
return fmt.Errorf("opengl: a uniform variable name for textures must be '[name]/[index]' but %s", key)
}
g.context.uniformInt(program, tokens[0], idx)
if g.state.lastActiveTexture != idx {
g.context.activeTexture(idx)
g.state.lastActiveTexture = idx
}
g.context.bindTexture(u)
}
}