graphicsdriver/opengl: Use glBindAttribLocation instead of glGetAttribLocation

Attribute variables are often optimized out and it is really hard
to prevent this.

Instead of implicit indices of attribute variables, use explicit
indices by glBindAttribLocation.

Bug: #816
This commit is contained in:
Hajime Hoshi 2019-02-16 14:03:21 +09:00
parent 7ff99d3965
commit 09ca873c41
6 changed files with 55 additions and 80 deletions

View File

@ -311,7 +311,7 @@ func (c *context) deleteShader(s shader) {
}) })
} }
func (c *context) newProgram(shaders []shader) (program, error) { func (c *context) newProgram(shaders []shader, attributes []string) (program, error) {
var pr program var pr program
if err := mainthread.Run(func() error { if err := mainthread.Run(func() error {
p := gl.CreateProgram() p := gl.CreateProgram()
@ -322,6 +322,13 @@ func (c *context) newProgram(shaders []shader) (program, error) {
for _, shader := range shaders { for _, shader := range shaders {
gl.AttachShader(p, uint32(shader)) gl.AttachShader(p, uint32(shader))
} }
for i, name := range attributes {
l, free := gl.Strs(name + "\x00")
gl.BindAttribLocation(p, uint32(i), *l)
free()
}
gl.LinkProgram(p) gl.LinkProgram(p)
var v int32 var v int32
gl.GetProgramiv(p, gl.LINK_STATUS, &v) gl.GetProgramiv(p, gl.LINK_STATUS, &v)
@ -396,36 +403,23 @@ func (c *context) uniformFloats(p program, location string, v []float32) {
}) })
} }
func (c *context) getAttribLocationImpl(p program, location string) attribLocation { func (c *context) vertexAttribPointer(p program, index int, size int, dataType dataType, stride int, offset int) {
l, free := gl.Strs(location + "\x00")
attrib := attribLocation(gl.GetAttribLocation(uint32(p), *l))
free()
if attrib == -1 {
panic("opengl: invalid attrib location: " + location)
}
return attrib
}
func (c *context) vertexAttribPointer(p program, location string, size int, dataType dataType, stride int, offset int) {
_ = mainthread.Run(func() error { _ = mainthread.Run(func() error {
l := c.locationCache.GetAttribLocation(c, p, location) gl.VertexAttribPointer(uint32(index), int32(size), uint32(dataType), false, int32(stride), gl.PtrOffset(offset))
gl.VertexAttribPointer(uint32(l), int32(size), uint32(dataType), false, int32(stride), gl.PtrOffset(offset))
return nil return nil
}) })
} }
func (c *context) enableVertexAttribArray(p program, location string) { func (c *context) enableVertexAttribArray(p program, index int) {
_ = mainthread.Run(func() error { _ = mainthread.Run(func() error {
l := c.locationCache.GetAttribLocation(c, p, location) gl.EnableVertexAttribArray(uint32(index))
gl.EnableVertexAttribArray(uint32(l))
return nil return nil
}) })
} }
func (c *context) disableVertexAttribArray(p program, location string) { func (c *context) disableVertexAttribArray(p program, index int) {
_ = mainthread.Run(func() error { _ = mainthread.Run(func() error {
l := c.locationCache.GetAttribLocation(c, p, location) gl.DisableVertexAttribArray(uint32(index))
gl.DisableVertexAttribArray(uint32(l))
return nil return nil
}) })
} }

View File

@ -293,7 +293,7 @@ func (c *context) deleteShader(s shader) {
gl.Call("deleteShader", js.Value(s)) gl.Call("deleteShader", js.Value(s))
} }
func (c *context) newProgram(shaders []shader) (program, error) { func (c *context) newProgram(shaders []shader, attributes []string) (program, error) {
c.ensureGL() c.ensureGL()
gl := c.gl gl := c.gl
v := gl.Call("createProgram") v := gl.Call("createProgram")
@ -304,6 +304,11 @@ func (c *context) newProgram(shaders []shader) (program, error) {
for _, shader := range shaders { for _, shader := range shaders {
gl.Call("attachShader", v, js.Value(shader)) gl.Call("attachShader", v, js.Value(shader))
} }
for i, name := range attributes {
gl.Call("bindAttribLocation", v, i, name)
}
gl.Call("linkProgram", v) gl.Call("linkProgram", v)
if !gl.Call("getProgramParameter", v, linkStatus).Bool() { if !gl.Call("getProgramParameter", v, linkStatus).Bool() {
return program{}, errors.New("opengl: program error") return program{}, errors.New("opengl: program error")
@ -374,31 +379,22 @@ func (c *context) uniformFloats(p program, location string, v []float32) {
} }
} }
func (c *context) getAttribLocationImpl(p program, location string) attribLocation { func (c *context) vertexAttribPointer(p program, index int, size int, dataType dataType, stride int, offset int) {
c.ensureGL() c.ensureGL()
gl := c.gl gl := c.gl
return attribLocation(gl.Call("getAttribLocation", p.value, location).Int()) gl.Call("vertexAttribPointer", index, size, int(dataType), false, stride, offset)
} }
func (c *context) vertexAttribPointer(p program, location string, size int, dataType dataType, stride int, offset int) { func (c *context) enableVertexAttribArray(p program, index int) {
c.ensureGL() c.ensureGL()
gl := c.gl gl := c.gl
l := c.locationCache.GetAttribLocation(c, p, location) gl.Call("enableVertexAttribArray", index)
gl.Call("vertexAttribPointer", int(l), size, int(dataType), false, stride, offset)
} }
func (c *context) enableVertexAttribArray(p program, location string) { func (c *context) disableVertexAttribArray(p program, index int) {
c.ensureGL() c.ensureGL()
gl := c.gl gl := c.gl
l := c.locationCache.GetAttribLocation(c, p, location) gl.Call("disableVertexAttribArray", index)
gl.Call("enableVertexAttribArray", int(l))
}
func (c *context) disableVertexAttribArray(p program, location string) {
c.ensureGL()
gl := c.gl
l := c.locationCache.GetAttribLocation(c, p, location)
gl.Call("disableVertexAttribArray", int(l))
} }
func (c *context) newArrayBuffer(size int) buffer { func (c *context) newArrayBuffer(size int) buffer {

View File

@ -243,7 +243,7 @@ func (c *context) deleteShader(s shader) {
gl.DeleteShader(mgl.Shader(s)) gl.DeleteShader(mgl.Shader(s))
} }
func (c *context) newProgram(shaders []shader) (program, error) { func (c *context) newProgram(shaders []shader, attributes []string) (program, error) {
gl := c.gl gl := c.gl
p := gl.CreateProgram() p := gl.CreateProgram()
if p.Value == 0 { if p.Value == 0 {
@ -253,6 +253,11 @@ func (c *context) newProgram(shaders []shader) (program, error) {
for _, shader := range shaders { for _, shader := range shaders {
gl.AttachShader(p, mgl.Shader(shader)) gl.AttachShader(p, mgl.Shader(shader))
} }
for i, name := range attributes {
gl.BindAttribLocation(p, mgl.Attrib{uint(i)}, name)
}
gl.LinkProgram(p) gl.LinkProgram(p)
v := gl.GetProgrami(p, mgl.LINK_STATUS) v := gl.GetProgrami(p, mgl.LINK_STATUS)
if v == mgl.FALSE { if v == mgl.FALSE {
@ -308,31 +313,19 @@ func (c *context) uniformFloats(p program, location string, v []float32) {
} }
} }
func (c *context) getAttribLocationImpl(p program, location string) attribLocation { func (c *context) vertexAttribPointer(p program, index int, size int, dataType dataType, stride int, offset int) {
gl := c.gl gl := c.gl
a := attribLocation(gl.GetAttribLocation(mgl.Program(p), location)) gl.VertexAttribPointer(mgl.Attrib{uint(index)}, size, mgl.Enum(dataType), false, stride, offset)
if a.Value == ^uint(0) {
panic("invalid attrib location: " + location)
}
return a
} }
func (c *context) vertexAttribPointer(p program, location string, size int, dataType dataType, stride int, offset int) { func (c *context) enableVertexAttribArray(p program, index int) {
gl := c.gl gl := c.gl
l := c.locationCache.GetAttribLocation(c, p, location) gl.EnableVertexAttribArray(mgl.Attrib{uint(index)})
gl.VertexAttribPointer(mgl.Attrib(l), size, mgl.Enum(dataType), false, stride, offset)
} }
func (c *context) enableVertexAttribArray(p program, location string) { func (c *context) disableVertexAttribArray(p program, index int) {
gl := c.gl gl := c.gl
l := c.locationCache.GetAttribLocation(c, p, location) gl.DisableVertexAttribArray(mgl.Attrib{uint(index)})
gl.EnableVertexAttribArray(mgl.Attrib(l))
}
func (c *context) disableVertexAttribArray(p program, location string) {
gl := c.gl
l := c.locationCache.GetAttribLocation(c, p, location)
gl.DisableVertexAttribArray(mgl.Attrib(l))
} }
func (c *context) newArrayBuffer(size int) buffer { func (c *context) newArrayBuffer(size int) buffer {

View File

@ -18,13 +18,11 @@ package opengl
type locationCache struct { type locationCache struct {
uniformLocationCache map[programID]map[string]uniformLocation uniformLocationCache map[programID]map[string]uniformLocation
attribLocationCache map[programID]map[string]attribLocation
} }
func newLocationCache() *locationCache { func newLocationCache() *locationCache {
return &locationCache{ return &locationCache{
uniformLocationCache: map[programID]map[string]uniformLocation{}, uniformLocationCache: map[programID]map[string]uniformLocation{},
attribLocationCache: map[programID]map[string]attribLocation{},
} }
} }
@ -40,16 +38,3 @@ func (c *locationCache) GetUniformLocation(context *context, p program, location
} }
return l return l
} }
func (c *locationCache) GetAttribLocation(context *context, p program, location string) attribLocation {
id := getProgramID(p)
if _, ok := c.attribLocationCache[id]; !ok {
c.attribLocationCache[id] = map[string]attribLocation{}
}
l, ok := c.attribLocationCache[id][location]
if !ok {
l = context.getAttribLocationImpl(p, location)
c.attribLocationCache[id][location] = l
}
return l
}

View File

@ -38,6 +38,14 @@ type arrayBufferLayout struct {
total int total int
} }
func (a *arrayBufferLayout) names() []string {
ns := make([]string, len(a.parts))
for i, p := range a.parts {
ns[i] = p.name
}
return ns
}
// totalBytes returns the size in bytes for one element of the array buffer. // totalBytes returns the size in bytes for one element of the array buffer.
func (a *arrayBufferLayout) totalBytes() int { func (a *arrayBufferLayout) totalBytes() int {
if a.total != 0 { if a.total != 0 {
@ -58,13 +66,13 @@ func (a *arrayBufferLayout) newArrayBuffer(context *context) buffer {
// enable binds the array buffer the given program to use the array buffer. // enable binds the array buffer the given program to use the array buffer.
func (a *arrayBufferLayout) enable(context *context, program program) { func (a *arrayBufferLayout) enable(context *context, program program) {
for _, p := range a.parts { for i := range a.parts {
context.enableVertexAttribArray(program, p.name) context.enableVertexAttribArray(program, i)
} }
total := a.totalBytes() total := a.totalBytes()
offset := 0 offset := 0
for _, p := range a.parts { for i, p := range a.parts {
context.vertexAttribPointer(program, p.name, p.num, float, total, offset) context.vertexAttribPointer(program, i, p.num, float, total, offset)
offset += float.SizeInBytes() * p.num offset += float.SizeInBytes() * p.num
} }
} }
@ -72,8 +80,8 @@ func (a *arrayBufferLayout) enable(context *context, program program) {
// disable stops using the array buffer. // disable stops using the array buffer.
func (a *arrayBufferLayout) disable(context *context, program program) { func (a *arrayBufferLayout) disable(context *context, program program) {
// TODO: Disabling should be done in reversed order? // TODO: Disabling should be done in reversed order?
for _, p := range a.parts { for i := range a.parts {
context.disableVertexAttribArray(program, p.name) context.disableVertexAttribArray(program, i)
} }
} }
@ -210,10 +218,12 @@ func (s *openGLState) reset(context *context) error {
program, err := context.newProgram([]shader{ program, err := context.newProgram([]shader{
shaderVertexModelviewNative, shaderVertexModelviewNative,
shaderFragmentColorMatrixNative, shaderFragmentColorMatrixNative,
}) }, theArrayBufferLayout.names())
if err != nil { if err != nil {
return err return err
} }
s.programs[programKey{ s.programs[programKey{
filter: f, filter: f,
address: a, address: a,

View File

@ -234,9 +234,6 @@ void main(void) {
highp vec2 p0 = pos - texel_size / 2.0 / scale; highp vec2 p0 = pos - texel_size / 2.0 / scale;
highp vec2 p1 = pos + texel_size / 2.0 / scale; highp vec2 p1 = pos + texel_size / 2.0 / scale;
// Prevent this variable from being optimized out.
p0 += varying_tex_region.xy - varying_tex_region.xy;
p1 = adjustTexel(p0, p1); p1 = adjustTexel(p0, p1);
vec4 c0 = texture2D(texture, p0); vec4 c0 = texture2D(texture, p0);