graphicsdriver/opengl: Ignore non-existent uniform locations

Shader users should not have to care about the existence of uniform
variables.

Updates #1168
This commit is contained in:
Hajime Hoshi 2020-05-27 11:07:21 +09:00
parent f80719ef9a
commit 1c980a16f5
5 changed files with 68 additions and 31 deletions

View File

@ -71,6 +71,7 @@ type programID uint32
const ( const (
invalidTexture = 0 invalidTexture = 0
invalidFramebuffer = (1 << 32) - 1 invalidFramebuffer = (1 << 32) - 1
invalidUniform = -1
) )
func getProgramID(p program) programID { func getProgramID(p program) programID {
@ -383,31 +384,45 @@ func (c *context) getUniformLocationImpl(p program, location string) uniformLoca
l, free := gl.Strs(location + "\x00") l, free := gl.Strs(location + "\x00")
uniform := uniformLocation(gl.GetUniformLocation(uint32(p), *l)) uniform := uniformLocation(gl.GetUniformLocation(uint32(p), *l))
free() free()
if uniform == -1 {
panic("opengl: invalid uniform location: " + location)
}
return uniform return uniform
} }
func (c *context) uniformInt(p program, location string, v int) { func (c *context) uniformInt(p program, location string, v int) bool {
var r bool
_ = c.t.Call(func() error { _ = c.t.Call(func() error {
l := int32(c.locationCache.GetUniformLocation(c, p, location)) l := int32(c.locationCache.GetUniformLocation(c, p, location))
if l == invalidUniform {
return nil
}
r = true
gl.Uniform1i(l, int32(v)) gl.Uniform1i(l, int32(v))
return nil return nil
}) })
return r
} }
func (c *context) uniformFloat(p program, location string, v float32) { func (c *context) uniformFloat(p program, location string, v float32) bool {
var r bool
_ = c.t.Call(func() error { _ = c.t.Call(func() error {
l := int32(c.locationCache.GetUniformLocation(c, p, location)) l := int32(c.locationCache.GetUniformLocation(c, p, location))
if l == invalidUniform {
return nil
}
r = true
gl.Uniform1f(l, v) gl.Uniform1f(l, v)
return nil return nil
}) })
return r
} }
func (c *context) uniformFloats(p program, location string, v []float32) { func (c *context) uniformFloats(p program, location string, v []float32) bool {
var r bool
_ = c.t.Call(func() error { _ = c.t.Call(func() error {
l := int32(c.locationCache.GetUniformLocation(c, p, location)) l := int32(c.locationCache.GetUniformLocation(c, p, location))
if l == invalidUniform {
return nil
}
r = true
switch len(v) { switch len(v) {
case 2: case 2:
gl.Uniform2fv(l, 1, (*float32)(gl.Ptr(v))) gl.Uniform2fv(l, 1, (*float32)(gl.Ptr(v)))
@ -420,6 +435,7 @@ func (c *context) uniformFloats(p program, location string, v []float32) {
} }
return nil return nil
}) })
return r
} }
func (c *context) vertexAttribPointer(p program, index int, size int, dataType dataType, stride int, offset int) { func (c *context) vertexAttribPointer(p program, index int, size int, dataType dataType, stride int, offset int) {

View File

@ -67,6 +67,8 @@ func (p program) equal(rhs program) bool {
var InvalidTexture = textureNative(js.Null()) var InvalidTexture = textureNative(js.Null())
var invalidUniform = uniformLocation(js.Null())
func getProgramID(p program) programID { func getProgramID(p program) programID {
return p.id return p.id
} }
@ -423,24 +425,35 @@ func (c *context) getUniformLocationImpl(p program, location string) uniformLoca
return uniformLocation(gl.Call("getUniformLocation", p.value, location)) return uniformLocation(gl.Call("getUniformLocation", p.value, location))
} }
func (c *context) uniformInt(p program, location string, v int) { func (c *context) uniformInt(p program, location string, v int) bool {
c.ensureGL() c.ensureGL()
gl := c.gl gl := c.gl
l := c.locationCache.GetUniformLocation(c, p, location) l := c.locationCache.GetUniformLocation(c, p, location)
if l.equal(invalidUniform) {
return false
}
gl.Call("uniform1i", js.Value(l), v) gl.Call("uniform1i", js.Value(l), v)
return true
} }
func (c *context) uniformFloat(p program, location string, v float32) { func (c *context) uniformFloat(p program, location string, v float32) bool {
c.ensureGL() c.ensureGL()
gl := c.gl gl := c.gl
l := c.locationCache.GetUniformLocation(c, p, location) l := c.locationCache.GetUniformLocation(c, p, location)
if l.equal(invalidUniform) {
return false
}
gl.Call("uniform1f", js.Value(l), v) gl.Call("uniform1f", js.Value(l), v)
return true
} }
func (c *context) uniformFloats(p program, location string, v []float32) { func (c *context) uniformFloats(p program, location string, v []float32) bool {
c.ensureGL() c.ensureGL()
gl := c.gl gl := c.gl
l := c.locationCache.GetUniformLocation(c, p, location) l := c.locationCache.GetUniformLocation(c, p, location)
if l.equal(invalidUniform) {
return false
}
switch len(v) { switch len(v) {
case 2: case 2:
gl.Call("uniform2f", js.Value(l), v[0], v[1]) gl.Call("uniform2f", js.Value(l), v[0], v[1])
@ -454,6 +467,7 @@ func (c *context) uniformFloats(p program, location string, v []float32) {
default: default:
panic(fmt.Sprintf("opengl: invalid uniform floats num: %d", len(v))) panic(fmt.Sprintf("opengl: invalid uniform floats num: %d", len(v)))
} }
return true
} }
func (c *context) vertexAttribPointer(p program, index int, size int, dataType dataType, stride int, offset int) { func (c *context) vertexAttribPointer(p program, index int, size int, dataType dataType, stride int, offset int) {

View File

@ -69,6 +69,7 @@ type programID uint32
var ( var (
invalidTexture = textureNative(mgl.Texture{}) invalidTexture = textureNative(mgl.Texture{})
invalidFramebuffer = framebufferNative(mgl.Framebuffer{(1 << 32) - 1}) invalidFramebuffer = framebufferNative(mgl.Framebuffer{(1 << 32) - 1})
invalidUniform = uniformLocation(mgl.Uniform{-1})
) )
func getProgramID(p program) programID { func getProgramID(p program) programID {
@ -286,35 +287,46 @@ func (c *context) deleteProgram(p program) {
func (c *context) getUniformLocationImpl(p program, location string) uniformLocation { func (c *context) getUniformLocationImpl(p program, location string) uniformLocation {
gl := c.gl gl := c.gl
u := uniformLocation(gl.GetUniformLocation(mgl.Program(p), location)) u := uniformLocation(gl.GetUniformLocation(mgl.Program(p), location))
if u.Value == -1 {
panic("invalid uniform location: " + location)
}
return u return u
} }
func (c *context) uniformInt(p program, location string, v int) { func (c *context) uniformInt(p program, location string, v int) bool {
gl := c.gl gl := c.gl
gl.Uniform1i(mgl.Uniform(c.locationCache.GetUniformLocation(c, p, location)), v) l := c.locationCache.GetUniformLocation(c, p, location)
if l == invalidUniform {
return false
}
gl.Uniform1i(mgl.Uniform(l), v)
return true
} }
func (c *context) uniformFloat(p program, location string, v float32) { func (c *context) uniformFloat(p program, location string, v float32) bool {
gl := c.gl gl := c.gl
gl.Uniform1f(mgl.Uniform(c.locationCache.GetUniformLocation(c, p, location)), v) l := c.locationCache.GetUniformLocation(c, p, location)
if l == invalidUniform {
return false
}
gl.Uniform1f(mgl.Uniform(l), v)
return true
} }
func (c *context) uniformFloats(p program, location string, v []float32) { func (c *context) uniformFloats(p program, location string, v []float32) bool {
gl := c.gl gl := c.gl
l := mgl.Uniform(c.locationCache.GetUniformLocation(c, p, location)) l := c.locationCache.GetUniformLocation(c, p, location)
if l == invalidUniform {
return false
}
switch len(v) { switch len(v) {
case 2: case 2:
gl.Uniform2fv(l, v) gl.Uniform2fv(mgl.Uniform(l), v)
case 4: case 4:
gl.Uniform4fv(l, v) gl.Uniform4fv(mgl.Uniform(l), v)
case 16: case 16:
gl.UniformMatrix4fv(l, v) gl.UniformMatrix4fv(mgl.Uniform(l), v)
default: default:
panic(fmt.Sprintf("opengl: invalid uniform floats num: %d", len(v))) panic(fmt.Sprintf("opengl: invalid uniform floats num: %d", len(v)))
} }
return true
} }
func (c *context) vertexAttribPointer(p program, index int, size int, dataType dataType, stride int, offset int) { func (c *context) vertexAttribPointer(p program, index int, size int, dataType dataType, stride int, offset int) {

View File

@ -266,6 +266,7 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable) error
if ok && cached == v { if ok && cached == v {
continue continue
} }
// TODO: Remember whether the location is available or not.
g.context.uniformFloat(program, u.name, v) g.context.uniformFloat(program, u.name, v)
g.state.lastUniforms[u.name] = v g.state.lastUniforms[u.name] = v
case []float32: case []float32:
@ -283,9 +284,6 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable) error
g.state.lastActiveTexture = u.textureIndex g.state.lastActiveTexture = u.textureIndex
} }
g.context.bindTexture(v) g.context.bindTexture(v)
case nil:
// TODO: Rather than using nil for skipping, check the availablity of locations at e.g.,
// uniformFloats and ignore the error for unavailability.
default: default:
return fmt.Errorf("opengl: unexpected uniform value: %v", u.value) return fmt.Errorf("opengl: unexpected uniform value: %v", u.value)
} }

View File

@ -112,18 +112,15 @@ func TestShaderMultipleSources(t *testing.T) {
ir := etesting.ShaderProgramImages(3) ir := etesting.ShaderProgramImages(3)
s := NewShader(&ir) s := NewShader(&ir)
// TODO: Now GLSL's optimization eliminates unused uniform variables by the program. Now nils are given,
// but it is strange to care about optimization from users. We should ignore the error when the location is
// not available.
us := []interface{}{ us := []interface{}{
[]float32{1, 1}, []float32{1, 1},
srcs[0], srcs[0],
srcs[1], srcs[1],
nil, // []float32{1, 1}, []float32{1, 1},
nil, // []float32{0, 0, 1, 1}, []float32{0, 0, 1, 1},
srcs[2], srcs[2],
nil, // []float32{1, 1}, []float32{1, 1},
nil, // []float32{0, 0, 1, 1}, []float32{0, 0, 1, 1},
} }
dst.DrawTriangles(nil, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, s, us) dst.DrawTriangles(nil, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, s, us)