internal/graphicsdriver/opengl: Optimization: Avoid the empty interface

This commit is contained in:
Hajime Hoshi 2021-10-30 02:25:37 +09:00
parent 60f2c7ace6
commit 1f82bb297c
2 changed files with 73 additions and 45 deletions

View File

@ -196,16 +196,20 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
dw, dh := destination.framebufferSize() dw, dh := destination.framebufferSize()
g.uniformVars = append(g.uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "viewport_size", name: "viewport_size",
valueSlice: []float32{float32(dw), float32(dh)}, value: uniformVariableValue{
typ: shaderir.Type{Main: shaderir.Vec2}, f32s: []float32{float32(dw), float32(dh)},
},
typ: shaderir.Type{Main: shaderir.Vec2},
}, uniformVariable{ }, uniformVariable{
name: "source_region", name: "source_region",
valueSlice: []float32{ value: uniformVariableValue{
srcRegion.X, f32s: []float32{
srcRegion.Y, srcRegion.X,
srcRegion.X + srcRegion.Width, srcRegion.Y,
srcRegion.Y + srcRegion.Height, srcRegion.X + srcRegion.Width,
srcRegion.Y + srcRegion.Height,
},
}, },
typ: shaderir.Type{Main: shaderir.Vec4}, typ: shaderir.Type{Main: shaderir.Vec4},
}) })
@ -216,31 +220,39 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
var esTranslate [4]float32 var esTranslate [4]float32
colorM.Elements(&esBody, &esTranslate) colorM.Elements(&esBody, &esTranslate)
g.uniformVars = append(g.uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "color_matrix_body", name: "color_matrix_body",
valueSlice: esBody[:], value: uniformVariableValue{
typ: shaderir.Type{Main: shaderir.Mat4}, f32s: esBody[:],
},
typ: shaderir.Type{Main: shaderir.Mat4},
}, uniformVariable{ }, uniformVariable{
name: "color_matrix_translation", name: "color_matrix_translation",
valueSlice: esTranslate[:], value: uniformVariableValue{
typ: shaderir.Type{Main: shaderir.Vec4}, f32s: esTranslate[:],
},
typ: shaderir.Type{Main: shaderir.Vec4},
}) })
} }
if filter != driver.FilterNearest { if filter != driver.FilterNearest {
sw, sh := g.images[srcIDs[0]].framebufferSize() sw, sh := g.images[srcIDs[0]].framebufferSize()
g.uniformVars = append(g.uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "source_size", name: "source_size",
valueSlice: []float32{float32(sw), float32(sh)}, value: uniformVariableValue{
typ: shaderir.Type{Main: shaderir.Vec2}, f32s: []float32{float32(sw), float32(sh)},
},
typ: shaderir.Type{Main: shaderir.Vec2},
}) })
} }
if filter == driver.FilterScreen { if filter == driver.FilterScreen {
scale := float32(destination.width) / float32(g.images[srcIDs[0]].width) scale := float32(destination.width) / float32(g.images[srcIDs[0]].width)
g.uniformVars = append(g.uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "scale", name: "scale",
value: scale, value: uniformVariableValue{
typ: shaderir.Type{Main: shaderir.Float}, f32: scale,
},
typ: shaderir.Type{Main: shaderir.Float},
}) })
} }
} else { } else {
@ -258,7 +270,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
const idx = graphics.DestinationTextureSizeUniformVariableIndex const idx = graphics.DestinationTextureSizeUniformVariableIndex
w, h := destination.framebufferSize() w, h := destination.framebufferSize()
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].valueSlice = []float32{float32(w), float32(h)} g.uniformVars[idx].value.f32s = []float32{float32(w), float32(h)}
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
@ -273,7 +285,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
} }
const idx = graphics.TextureSizesUniformVariableIndex const idx = graphics.TextureSizesUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].valueSlice = sizes g.uniformVars[idx].value.f32s = sizes
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
dw, dh := destination.framebufferSize() dw, dh := destination.framebufferSize()
@ -281,14 +293,14 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
origin := []float32{float32(dstRegion.X) / float32(dw), float32(dstRegion.Y) / float32(dh)} origin := []float32{float32(dstRegion.X) / float32(dw), float32(dstRegion.Y) / float32(dh)}
const idx = graphics.TextureDestinationRegionOriginUniformVariableIndex const idx = graphics.TextureDestinationRegionOriginUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].valueSlice = origin g.uniformVars[idx].value.f32s = origin
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
size := []float32{float32(dstRegion.Width) / float32(dw), float32(dstRegion.Height) / float32(dh)} size := []float32{float32(dstRegion.Width) / float32(dw), float32(dstRegion.Height) / float32(dh)}
const idx = graphics.TextureDestinationRegionSizeUniformVariableIndex const idx = graphics.TextureDestinationRegionSizeUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].valueSlice = size g.uniformVars[idx].value.f32s = size
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
@ -299,21 +311,21 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
} }
const idx = graphics.TextureSourceOffsetsUniformVariableIndex const idx = graphics.TextureSourceOffsetsUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].valueSlice = voffsets g.uniformVars[idx].value.f32s = voffsets
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
origin := []float32{float32(srcRegion.X), float32(srcRegion.Y)} origin := []float32{float32(srcRegion.X), float32(srcRegion.Y)}
const idx = graphics.TextureSourceRegionOriginUniformVariableIndex const idx = graphics.TextureSourceRegionOriginUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].valueSlice = origin g.uniformVars[idx].value.f32s = origin
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
size := []float32{float32(srcRegion.Width), float32(srcRegion.Height)} size := []float32{float32(srcRegion.Width), float32(srcRegion.Height)}
const idx = graphics.TextureSourceRegionSizeUniformVariableIndex const idx = graphics.TextureSourceRegionSizeUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].valueSlice = size g.uniformVars[idx].value.f32s = size
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
@ -322,9 +334,9 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
g.uniformVars[i+offset].name = fmt.Sprintf("U%d", i+offset) g.uniformVars[i+offset].name = fmt.Sprintf("U%d", i+offset)
switch v := v.(type) { switch v := v.(type) {
case float32: case float32:
g.uniformVars[i+offset].value = v g.uniformVars[i+offset].value.f32 = v
case []float32: case []float32:
g.uniformVars[i+offset].valueSlice = v g.uniformVars[i+offset].value.f32s = v
default: default:
return fmt.Errorf("opengl: unexpected uniform value: %v (type: %T)", v, v) return fmt.Errorf("opengl: unexpected uniform value: %v (type: %T)", v, v)
} }

View File

@ -120,6 +120,11 @@ type programKey struct {
address driver.Address address driver.Address
} }
type uniformVariableValue struct {
f32 float32
f32s []float32
}
// openGLState is a state for // openGLState is a state for
type openGLState struct { type openGLState struct {
// arrayBuffer is OpenGL's array buffer (vertices data). // arrayBuffer is OpenGL's array buffer (vertices data).
@ -132,7 +137,7 @@ type openGLState struct {
programs map[programKey]program programs map[programKey]program
lastProgram program lastProgram program
lastUniforms map[string]interface{} lastUniforms map[string]uniformVariableValue
lastActiveTexture int lastActiveTexture int
} }
@ -149,7 +154,9 @@ func (s *openGLState) reset(context *context) error {
s.lastProgram = zeroProgram s.lastProgram = zeroProgram
context.useProgram(zeroProgram) context.useProgram(zeroProgram)
s.lastUniforms = map[string]interface{}{} for key := range s.lastUniforms {
delete(s.lastUniforms, key)
}
// When context lost happens, deleting programs or buffers is not necessary. // When context lost happens, deleting programs or buffers is not necessary.
// However, it is not assumed that reset is called only when context lost happens. // However, it is not assumed that reset is called only when context lost happens.
@ -239,10 +246,9 @@ func areSameFloat32Array(a, b []float32) bool {
} }
type uniformVariable struct { type uniformVariable struct {
name string name string
value float32 value uniformVariableValue
valueSlice []float32 typ shaderir.Type
typ shaderir.Type
} }
type textureVariable struct { type textureVariable struct {
@ -269,31 +275,41 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textu
} }
for _, u := range uniforms { for _, u := range uniforms {
if len(u.valueSlice) == 0 { if len(u.value.f32s) == 0 {
if u.typ.Main != shaderir.Float { if u.typ.Main != shaderir.Float {
expected := &shaderir.Type{Main: shaderir.Float} expected := &shaderir.Type{Main: shaderir.Float}
got := &u.typ got := &u.typ
return fmt.Errorf("opengl: uniform variable %s type doesn't match: expected %s but %s", u.name, expected.String(), got.String()) return fmt.Errorf("opengl: uniform variable %s type doesn't match: expected %s but %s", u.name, expected.String(), got.String())
} }
cached, ok := g.state.lastUniforms[u.name].(float32) cached, ok := g.state.lastUniforms[u.name]
if ok && cached == u.value { if ok && cached.f32 == u.value.f32 {
continue continue
} }
// TODO: Remember whether the location is available or not. // TODO: Remember whether the location is available or not.
g.context.uniformFloat(program, u.name, u.value) g.context.uniformFloat(program, u.name, u.value.f32)
g.state.lastUniforms[u.name] = u.value if g.state.lastUniforms == nil {
g.state.lastUniforms = map[string]uniformVariableValue{}
}
g.state.lastUniforms[u.name] = uniformVariableValue{
f32: u.value.f32,
}
} else { } else {
if got, expected := len(u.valueSlice), u.typ.FloatNum(); got != expected { if got, expected := len(u.value.f32s), u.typ.FloatNum(); got != expected {
return fmt.Errorf("opengl: length of a uniform variables %s (%s) doesn't match: expected %d but %d", u.name, u.typ.String(), expected, got) return fmt.Errorf("opengl: length of a uniform variables %s (%s) doesn't match: expected %d but %d", u.name, u.typ.String(), expected, got)
} }
cached, ok := g.state.lastUniforms[u.name].([]float32) cached, ok := g.state.lastUniforms[u.name]
if ok && areSameFloat32Array(cached, u.valueSlice) { if ok && areSameFloat32Array(cached.f32s, u.value.f32s) {
continue continue
} }
g.context.uniformFloats(program, u.name, u.valueSlice, u.typ) g.context.uniformFloats(program, u.name, u.value.f32s, u.typ)
g.state.lastUniforms[u.name] = u.valueSlice if g.state.lastUniforms == nil {
g.state.lastUniforms = map[string]uniformVariableValue{}
}
g.state.lastUniforms[u.name] = uniformVariableValue{
f32s: u.value.f32s,
}
} }
} }