internal/graphicsdriver/opengl: Optimization: Avoid creating slices for every frame (uniform variables)

This commit is contained in:
Hajime Hoshi 2021-10-30 00:22:28 +09:00
parent b4f45edff8
commit 60f2c7ace6

View File

@ -48,6 +48,8 @@ type Graphics struct {
uniformVariableNameCache map[int]string uniformVariableNameCache map[int]string
uniformVars []uniformVariable
// activatedTextures is a set of activated textures. // activatedTextures is a set of activated textures.
// textureNative cannot be a map key unfortunately. // textureNative cannot be a map key unfortunately.
activatedTextures []activatedTexture activatedTextures []activatedTexture
@ -185,7 +187,6 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
g.context.blendFunc(mode) g.context.blendFunc(mode)
var program program var program program
var uniformVars []uniformVariable
if shaderID == driver.InvalidShaderID { if shaderID == driver.InvalidShaderID {
program = g.state.programs[programKey{ program = g.state.programs[programKey{
useColorM: !colorM.IsIdentity(), useColorM: !colorM.IsIdentity(),
@ -194,7 +195,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
}] }]
dw, dh := destination.framebufferSize() dw, dh := destination.framebufferSize()
uniformVars = append(uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "viewport_size", name: "viewport_size",
valueSlice: []float32{float32(dw), float32(dh)}, valueSlice: []float32{float32(dw), float32(dh)},
typ: shaderir.Type{Main: shaderir.Vec2}, typ: shaderir.Type{Main: shaderir.Vec2},
@ -214,7 +215,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
var esBody [16]float32 var esBody [16]float32
var esTranslate [4]float32 var esTranslate [4]float32
colorM.Elements(&esBody, &esTranslate) colorM.Elements(&esBody, &esTranslate)
uniformVars = append(uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "color_matrix_body", name: "color_matrix_body",
valueSlice: esBody[:], valueSlice: esBody[:],
typ: shaderir.Type{Main: shaderir.Mat4}, typ: shaderir.Type{Main: shaderir.Mat4},
@ -227,7 +228,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
if filter != driver.FilterNearest { if filter != driver.FilterNearest {
sw, sh := g.images[srcIDs[0]].framebufferSize() sw, sh := g.images[srcIDs[0]].framebufferSize()
uniformVars = append(uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "source_size", name: "source_size",
valueSlice: []float32{float32(sw), float32(sh)}, valueSlice: []float32{float32(sw), float32(sh)},
typ: shaderir.Type{Main: shaderir.Vec2}, typ: shaderir.Type{Main: shaderir.Vec2},
@ -236,7 +237,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
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)
uniformVars = append(uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "scale", name: "scale",
value: scale, value: scale,
typ: shaderir.Type{Main: shaderir.Float}, typ: shaderir.Type{Main: shaderir.Float},
@ -245,14 +246,20 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
} else { } else {
shader := g.shaders[shaderID] shader := g.shaders[shaderID]
program = shader.p program = shader.p
uniformVars = make([]uniformVariable, graphics.PreservedUniformVariablesNum+len(uniforms))
ulen := graphics.PreservedUniformVariablesNum + len(uniforms)
if cap(g.uniformVars) < ulen {
g.uniformVars = make([]uniformVariable, ulen)
} else {
g.uniformVars = g.uniformVars[:ulen]
}
{ {
const idx = graphics.DestinationTextureSizeUniformVariableIndex const idx = graphics.DestinationTextureSizeUniformVariableIndex
w, h := destination.framebufferSize() w, h := destination.framebufferSize()
uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
uniformVars[idx].valueSlice = []float32{float32(w), float32(h)} g.uniformVars[idx].valueSlice = []float32{float32(w), float32(h)}
uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
sizes := make([]float32, 2*len(srcIDs)) sizes := make([]float32, 2*len(srcIDs))
@ -265,24 +272,24 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
} }
const idx = graphics.TextureSizesUniformVariableIndex const idx = graphics.TextureSizesUniformVariableIndex
uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
uniformVars[idx].valueSlice = sizes g.uniformVars[idx].valueSlice = sizes
uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
dw, dh := destination.framebufferSize() dw, dh := destination.framebufferSize()
{ {
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
uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
uniformVars[idx].valueSlice = origin g.uniformVars[idx].valueSlice = origin
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
uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
uniformVars[idx].valueSlice = size g.uniformVars[idx].valueSlice = size
uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
voffsets := make([]float32, 2*len(offsets)) voffsets := make([]float32, 2*len(offsets))
@ -291,37 +298,37 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
voffsets[2*i+1] = o[1] voffsets[2*i+1] = o[1]
} }
const idx = graphics.TextureSourceOffsetsUniformVariableIndex const idx = graphics.TextureSourceOffsetsUniformVariableIndex
uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
uniformVars[idx].valueSlice = voffsets g.uniformVars[idx].valueSlice = voffsets
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
uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
uniformVars[idx].valueSlice = origin g.uniformVars[idx].valueSlice = origin
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
uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
uniformVars[idx].valueSlice = size g.uniformVars[idx].valueSlice = size
uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
for i, v := range uniforms { for i, v := range uniforms {
const offset = graphics.PreservedUniformVariablesNum const offset = graphics.PreservedUniformVariablesNum
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:
uniformVars[i+offset].value = v g.uniformVars[i+offset].value = v
case []float32: case []float32:
uniformVars[i+offset].valueSlice = v g.uniformVars[i+offset].valueSlice = 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)
} }
uniformVars[i+offset].typ = shader.ir.Uniforms[i+offset] g.uniformVars[i+offset].typ = shader.ir.Uniforms[i+offset]
} }
} }
@ -334,10 +341,15 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
imgs[i].native = g.images[srcID].texture imgs[i].native = g.images[srcID].texture
} }
if err := g.useProgram(program, uniformVars, imgs); err != nil { if err := g.useProgram(program, g.uniformVars, imgs); err != nil {
return err return err
} }
for i := range g.uniformVars {
g.uniformVars[i] = uniformVariable{}
}
g.uniformVars = g.uniformVars[:0]
if evenOdd { if evenOdd {
if err := destination.ensureStencilBuffer(); err != nil { if err := destination.ensureStencilBuffer(); err != nil {
return err return err