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 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) { func (c *context) bindTextureImpl(t textureNative) {
_ = c.t.Call(func() error { _ = c.t.Call(func() error {
gl.BindTexture(gl.TEXTURE_2D, uint32(t)) gl.BindTexture(gl.TEXTURE_2D, uint32(t))

View File

@ -112,6 +112,8 @@ var (
unsignedByte js.Value unsignedByte js.Value
unsignedShort js.Value unsignedShort js.Value
texture0 int
isWebGL2Available bool isWebGL2Available bool
) )
@ -154,6 +156,7 @@ func init() {
nearest = contextPrototype.Get("NEAREST") nearest = contextPrototype.Get("NEAREST")
noError = contextPrototype.Get("NO_ERROR") noError = contextPrototype.Get("NO_ERROR")
rgba = contextPrototype.Get("RGBA") rgba = contextPrototype.Get("RGBA")
texture0 = contextPrototype.Get("TEXTURE0").Int()
texture2d = contextPrototype.Get("TEXTURE_2D") texture2d = contextPrototype.Get("TEXTURE_2D")
textureMagFilter = contextPrototype.Get("TEXTURE_MAG_FILTER") textureMagFilter = contextPrototype.Get("TEXTURE_MAG_FILTER")
textureMinFilter = contextPrototype.Get("TEXTURE_MIN_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 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) { func (c *context) bindTextureImpl(t textureNative) {
c.ensureGL() c.ensureGL()
gl := c.gl gl := c.gl

View File

@ -156,6 +156,11 @@ func (c *context) framebufferPixels(f *framebuffer, width, height int) ([]byte,
return pixels, nil 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) { func (c *context) bindTextureImpl(t textureNative) {
gl := c.gl gl := c.gl
gl.BindTexture(mgl.TEXTURE_2D, mgl.Texture(t)) gl.BindTexture(mgl.TEXTURE_2D, mgl.Texture(t))

View File

@ -49,6 +49,7 @@ const (
NO_ERROR = 0 NO_ERROR = 0
READ_WRITE = 0x88BA READ_WRITE = 0x88BA
RGBA = 0x1908 RGBA = 0x1908
TEXTURE0 = 0x84C0
TEXTURE_2D = 0x0DE1 TEXTURE_2D = 0x0DE1
TEXTURE_MAG_FILTER = 0x2800 TEXTURE_MAG_FILTER = 0x2800
TEXTURE_MIN_FILTER = 0x2801 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 void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
// typedef unsigned short GLhalfNV; // typedef unsigned short GLhalfNV;
// typedef GLintptr GLvdpauSurfaceNV; // 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 GPATTACHSHADER)(GLuint program, GLuint shader);
// typedef void (APIENTRYP GPBINDATTRIBLOCATION)(GLuint program, GLuint index, const GLchar * name); // typedef void (APIENTRYP GPBINDATTRIBLOCATION)(GLuint program, GLuint index, const GLchar * name);
// typedef void (APIENTRYP GPBINDBUFFER)(GLenum target, GLuint buffer); // 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 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); // 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) { // static void glowAttachShader(GPATTACHSHADER fnptr, GLuint program, GLuint shader) {
// (*fnptr)(program, shader); // (*fnptr)(program, shader);
// } // }
@ -353,6 +357,7 @@ import (
) )
var ( var (
gpActiveTexture C.GPACTIVETEXTURE
gpAttachShader C.GPATTACHSHADER gpAttachShader C.GPATTACHSHADER
gpBindAttribLocation C.GPBINDATTRIBLOCATION gpBindAttribLocation C.GPBINDATTRIBLOCATION
gpBindBuffer C.GPBINDBUFFER gpBindBuffer C.GPBINDBUFFER
@ -424,6 +429,10 @@ func boolToInt(b bool) int {
return 0 return 0
} }
func ActiveTexture(texture uint32) {
C.glowActiveTexture(gpActiveTexture, (C.GLenum)(texture))
}
func AttachShader(program uint32, shader uint32) { func AttachShader(program uint32, shader uint32) {
C.glowAttachShader(gpAttachShader, (C.GLuint)(program), (C.GLuint)(shader)) 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 // InitWithProcAddrFunc intializes the package using the specified OpenGL
// function pointer loading function. For more cases Init should be used // function pointer loading function. For more cases Init should be used
func InitWithProcAddrFunc(getProcAddr func(name string) unsafe.Pointer) error { 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")) gpAttachShader = (C.GPATTACHSHADER)(getProcAddr("glAttachShader"))
if gpAttachShader == nil { if gpAttachShader == nil {
return errors.New("glAttachShader") return errors.New("glAttachShader")

View File

@ -10,6 +10,7 @@ import (
) )
var ( var (
gpActiveTexture uintptr
gpAttachShader uintptr gpAttachShader uintptr
gpBindAttribLocation uintptr gpBindAttribLocation uintptr
gpBindBuffer uintptr gpBindBuffer uintptr
@ -81,6 +82,10 @@ func boolToUintptr(b bool) uintptr {
return 0 return 0
} }
func ActiveTexture(texture uint32) {
syscall.Syscall(gpActiveTexture, 1, uintptr(texture), 0, 0)
}
func AttachShader(program uint32, shader uint32) { func AttachShader(program uint32, shader uint32) {
syscall.Syscall(gpAttachShader, 2, uintptr(program), uintptr(shader), 0) 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 // InitWithProcAddrFunc intializes the package using the specified OpenGL
// function pointer loading function. For more cases Init should be used // function pointer loading function. For more cases Init should be used
func InitWithProcAddrFunc(getProcAddr func(name string) uintptr) error { func InitWithProcAddrFunc(getProcAddr func(name string) uintptr) error {
gpActiveTexture = getProcAddr("glActiveTexture")
if gpActiveTexture == 0 {
return errors.New("glActiveTexture")
}
gpAttachShader = getProcAddr("glAttachShader") gpAttachShader = getProcAddr("glAttachShader")
if gpAttachShader == 0 { if gpAttachShader == 0 {
return errors.New("glAttachShader") 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["scale"] = scale
} }
uniforms["texture"] = source.textureNative uniforms["texture/0"] = source.textureNative
if err := g.useProgram(program, uniforms); err != nil { if err := g.useProgram(program, uniforms); err != nil {
return err return err

View File

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