From 1f82bb297c538a7e5a3eaf750958ba1023cb46b6 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 30 Oct 2021 02:25:37 +0900 Subject: [PATCH] internal/graphicsdriver/opengl: Optimization: Avoid the empty interface --- internal/graphicsdriver/opengl/graphics.go | 70 +++++++++++++--------- internal/graphicsdriver/opengl/program.go | 48 ++++++++++----- 2 files changed, 73 insertions(+), 45 deletions(-) diff --git a/internal/graphicsdriver/opengl/graphics.go b/internal/graphicsdriver/opengl/graphics.go index 1012a0a32..e5105f874 100644 --- a/internal/graphicsdriver/opengl/graphics.go +++ b/internal/graphicsdriver/opengl/graphics.go @@ -196,16 +196,20 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm dw, dh := destination.framebufferSize() g.uniformVars = append(g.uniformVars, uniformVariable{ - name: "viewport_size", - valueSlice: []float32{float32(dw), float32(dh)}, - typ: shaderir.Type{Main: shaderir.Vec2}, + name: "viewport_size", + value: uniformVariableValue{ + f32s: []float32{float32(dw), float32(dh)}, + }, + typ: shaderir.Type{Main: shaderir.Vec2}, }, uniformVariable{ name: "source_region", - valueSlice: []float32{ - srcRegion.X, - srcRegion.Y, - srcRegion.X + srcRegion.Width, - srcRegion.Y + srcRegion.Height, + value: uniformVariableValue{ + f32s: []float32{ + srcRegion.X, + srcRegion.Y, + srcRegion.X + srcRegion.Width, + srcRegion.Y + srcRegion.Height, + }, }, typ: shaderir.Type{Main: shaderir.Vec4}, }) @@ -216,31 +220,39 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm var esTranslate [4]float32 colorM.Elements(&esBody, &esTranslate) g.uniformVars = append(g.uniformVars, uniformVariable{ - name: "color_matrix_body", - valueSlice: esBody[:], - typ: shaderir.Type{Main: shaderir.Mat4}, + name: "color_matrix_body", + value: uniformVariableValue{ + f32s: esBody[:], + }, + typ: shaderir.Type{Main: shaderir.Mat4}, }, uniformVariable{ - name: "color_matrix_translation", - valueSlice: esTranslate[:], - typ: shaderir.Type{Main: shaderir.Vec4}, + name: "color_matrix_translation", + value: uniformVariableValue{ + f32s: esTranslate[:], + }, + typ: shaderir.Type{Main: shaderir.Vec4}, }) } if filter != driver.FilterNearest { sw, sh := g.images[srcIDs[0]].framebufferSize() g.uniformVars = append(g.uniformVars, uniformVariable{ - name: "source_size", - valueSlice: []float32{float32(sw), float32(sh)}, - typ: shaderir.Type{Main: shaderir.Vec2}, + name: "source_size", + value: uniformVariableValue{ + f32s: []float32{float32(sw), float32(sh)}, + }, + typ: shaderir.Type{Main: shaderir.Vec2}, }) } if filter == driver.FilterScreen { scale := float32(destination.width) / float32(g.images[srcIDs[0]].width) g.uniformVars = append(g.uniformVars, uniformVariable{ - name: "scale", - value: scale, - typ: shaderir.Type{Main: shaderir.Float}, + name: "scale", + value: uniformVariableValue{ + f32: scale, + }, + typ: shaderir.Type{Main: shaderir.Float}, }) } } else { @@ -258,7 +270,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm const idx = graphics.DestinationTextureSizeUniformVariableIndex w, h := destination.framebufferSize() 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] } { @@ -273,7 +285,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm } const idx = graphics.TextureSizesUniformVariableIndex 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] } 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)} const idx = graphics.TextureDestinationRegionOriginUniformVariableIndex 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] } { size := []float32{float32(dstRegion.Width) / float32(dw), float32(dstRegion.Height) / float32(dh)} const idx = graphics.TextureDestinationRegionSizeUniformVariableIndex 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] } { @@ -299,21 +311,21 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm } const idx = graphics.TextureSourceOffsetsUniformVariableIndex 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] } { origin := []float32{float32(srcRegion.X), float32(srcRegion.Y)} const idx = graphics.TextureSourceRegionOriginUniformVariableIndex 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] } { size := []float32{float32(srcRegion.Width), float32(srcRegion.Height)} const idx = graphics.TextureSourceRegionSizeUniformVariableIndex 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] } @@ -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) switch v := v.(type) { case float32: - g.uniformVars[i+offset].value = v + g.uniformVars[i+offset].value.f32 = v case []float32: - g.uniformVars[i+offset].valueSlice = v + g.uniformVars[i+offset].value.f32s = v default: return fmt.Errorf("opengl: unexpected uniform value: %v (type: %T)", v, v) } diff --git a/internal/graphicsdriver/opengl/program.go b/internal/graphicsdriver/opengl/program.go index 05b452055..d213d3f7f 100644 --- a/internal/graphicsdriver/opengl/program.go +++ b/internal/graphicsdriver/opengl/program.go @@ -120,6 +120,11 @@ type programKey struct { address driver.Address } +type uniformVariableValue struct { + f32 float32 + f32s []float32 +} + // openGLState is a state for type openGLState struct { // arrayBuffer is OpenGL's array buffer (vertices data). @@ -132,7 +137,7 @@ type openGLState struct { programs map[programKey]program lastProgram program - lastUniforms map[string]interface{} + lastUniforms map[string]uniformVariableValue lastActiveTexture int } @@ -149,7 +154,9 @@ func (s *openGLState) reset(context *context) error { s.lastProgram = 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. // 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 { - name string - value float32 - valueSlice []float32 - typ shaderir.Type + name string + value uniformVariableValue + typ shaderir.Type } type textureVariable struct { @@ -269,31 +275,41 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textu } for _, u := range uniforms { - if len(u.valueSlice) == 0 { + if len(u.value.f32s) == 0 { if u.typ.Main != shaderir.Float { expected := &shaderir.Type{Main: shaderir.Float} got := &u.typ 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) - if ok && cached == u.value { + cached, ok := g.state.lastUniforms[u.name] + if ok && cached.f32 == u.value.f32 { continue } // TODO: Remember whether the location is available or not. - g.context.uniformFloat(program, u.name, u.value) - g.state.lastUniforms[u.name] = u.value + g.context.uniformFloat(program, u.name, u.value.f32) + if g.state.lastUniforms == nil { + g.state.lastUniforms = map[string]uniformVariableValue{} + } + g.state.lastUniforms[u.name] = uniformVariableValue{ + f32: u.value.f32, + } } 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) } - cached, ok := g.state.lastUniforms[u.name].([]float32) - if ok && areSameFloat32Array(cached, u.valueSlice) { + cached, ok := g.state.lastUniforms[u.name] + if ok && areSameFloat32Array(cached.f32s, u.value.f32s) { continue } - g.context.uniformFloats(program, u.name, u.valueSlice, u.typ) - g.state.lastUniforms[u.name] = u.valueSlice + g.context.uniformFloats(program, u.name, u.value.f32s, u.typ) + if g.state.lastUniforms == nil { + g.state.lastUniforms = map[string]uniformVariableValue{} + } + g.state.lastUniforms[u.name] = uniformVariableValue{ + f32s: u.value.f32s, + } } }