mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
internal/graphicscommand: remove unused uniform variables
This improves possibility of merging graphics commands by reducing uniform variables. Updates #2232
This commit is contained in:
parent
86e694941f
commit
384dee7160
9
image.go
9
image.go
@ -249,7 +249,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, false, canSkipMipmap(options.GeoM, filter), false)
|
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), img.adjustedRegion(), [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, false, canSkipMipmap(options.GeoM, filter), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertex represents a vertex passed to DrawTriangles.
|
// Vertex represents a vertex passed to DrawTriangles.
|
||||||
@ -424,11 +424,6 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
|||||||
}
|
}
|
||||||
|
|
||||||
address := builtinshader.Address(options.Address)
|
address := builtinshader.Address(options.Address)
|
||||||
var sr graphicsdriver.Region
|
|
||||||
if address != builtinshader.AddressUnsafe {
|
|
||||||
sr = img.adjustedRegion()
|
|
||||||
}
|
|
||||||
|
|
||||||
filter := builtinshader.Filter(options.Filter)
|
filter := builtinshader.Filter(options.Filter)
|
||||||
|
|
||||||
colorm, cr, cg, cb, ca := colorMToScale(options.ColorM.affineColorM())
|
colorm, cr, cg, cb, ca := colorMToScale(options.ColorM.affineColorM())
|
||||||
@ -480,7 +475,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), sr, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, options.FillRule == EvenOdd, filter != builtinshader.FilterLinear, options.AntiAlias)
|
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), img.adjustedRegion(), [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, options.FillRule == EvenOdd, filter != builtinshader.FilterLinear, options.AntiAlias)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DrawTrianglesShaderOptions represents options for DrawTrianglesShader.
|
// DrawTrianglesShaderOptions represents options for DrawTrianglesShader.
|
||||||
|
@ -110,6 +110,20 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh
|
|||||||
|
|
||||||
uniforms = prependPreservedUniforms(uniforms, dst, srcs, offsets, dstRegion, srcRegion)
|
uniforms = prependPreservedUniforms(uniforms, dst, srcs, offsets, dstRegion, srcRegion)
|
||||||
|
|
||||||
|
// Remove unused uniform variables so that more commands can be merged.
|
||||||
|
uvs := map[int]struct{}{}
|
||||||
|
for _, i := range shader.ir.ReachableUniformVariablesFromBlock(shader.ir.VertexFunc.Block) {
|
||||||
|
uvs[i] = struct{}{}
|
||||||
|
}
|
||||||
|
for _, i := range shader.ir.ReachableUniformVariablesFromBlock(shader.ir.FragmentFunc.Block) {
|
||||||
|
uvs[i] = struct{}{}
|
||||||
|
}
|
||||||
|
for i := range uniforms {
|
||||||
|
if _, ok := uvs[i]; !ok {
|
||||||
|
uniforms[i] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: If dst is the screen, reorder the command to be the last.
|
// TODO: If dst is the screen, reorder the command to be the last.
|
||||||
if !split && 0 < len(q.commands) {
|
if !split && 0 < len(q.commands) {
|
||||||
if last, ok := q.commands[len(q.commands)-1].(*drawTrianglesCommand); ok {
|
if last, ok := q.commands[len(q.commands)-1].(*drawTrianglesCommand); ok {
|
||||||
@ -575,7 +589,6 @@ func prependPreservedUniforms(uniforms [][]float32, dst *Image, srcs [graphics.S
|
|||||||
uniforms[graphics.TextureSourceSizesUniformVariableIndex] = usizes
|
uniforms[graphics.TextureSourceSizesUniformVariableIndex] = usizes
|
||||||
|
|
||||||
// Set the destination region.
|
// Set the destination region.
|
||||||
// TODO: Set them only when the shader refers this (#2232).
|
|
||||||
uniforms[graphics.TextureDestinationRegionOriginUniformVariableIndex] = []float32{float32(dstRegion.X) / float32(dw), float32(dstRegion.Y) / float32(dh)}
|
uniforms[graphics.TextureDestinationRegionOriginUniformVariableIndex] = []float32{float32(dstRegion.X) / float32(dw), float32(dstRegion.Y) / float32(dh)}
|
||||||
uniforms[graphics.TextureDestinationRegionSizeUniformVariableIndex] = []float32{float32(dstRegion.Width) / float32(dw), float32(dstRegion.Height) / float32(dh)}
|
uniforms[graphics.TextureDestinationRegionSizeUniformVariableIndex] = []float32{float32(dstRegion.Width) / float32(dw), float32(dstRegion.Height) / float32(dh)}
|
||||||
|
|
||||||
@ -600,7 +613,6 @@ func prependPreservedUniforms(uniforms [][]float32, dst *Image, srcs [graphics.S
|
|||||||
uniforms[graphics.TextureSourceOffsetsUniformVariableIndex] = uoffsets
|
uniforms[graphics.TextureSourceOffsetsUniformVariableIndex] = uoffsets
|
||||||
|
|
||||||
// Set the source region of texture0.
|
// Set the source region of texture0.
|
||||||
// TODO: Set them only when the shader refers this (#2232).
|
|
||||||
uniforms[graphics.TextureSourceRegionOriginUniformVariableIndex] = []float32{float32(srcRegion.X), float32(srcRegion.Y)}
|
uniforms[graphics.TextureSourceRegionOriginUniformVariableIndex] = []float32{float32(srcRegion.X), float32(srcRegion.Y)}
|
||||||
uniforms[graphics.TextureSourceRegionSizeUniformVariableIndex] = []float32{float32(srcRegion.Width), float32(srcRegion.Height)}
|
uniforms[graphics.TextureSourceRegionSizeUniformVariableIndex] = []float32{float32(srcRegion.Width), float32(srcRegion.Height)}
|
||||||
|
|
||||||
|
@ -21,10 +21,13 @@ import (
|
|||||||
|
|
||||||
type Shader struct {
|
type Shader struct {
|
||||||
shader graphicsdriver.Shader
|
shader graphicsdriver.Shader
|
||||||
|
ir *shaderir.Program
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewShader(ir *shaderir.Program) *Shader {
|
func NewShader(ir *shaderir.Program) *Shader {
|
||||||
s := &Shader{}
|
s := &Shader{
|
||||||
|
ir: ir,
|
||||||
|
}
|
||||||
c := &newShaderCommand{
|
c := &newShaderCommand{
|
||||||
result: s,
|
result: s,
|
||||||
ir: ir,
|
ir: ir,
|
||||||
|
@ -1763,53 +1763,116 @@ func (s *Shader) uniformsToFloat32s(uniforms [][]float32) []float32 {
|
|||||||
|
|
||||||
t := s.uniformTypes[i]
|
t := s.uniformTypes[i]
|
||||||
switch t.Main {
|
switch t.Main {
|
||||||
case shaderir.Float, shaderir.Vec2, shaderir.Vec3, shaderir.Vec4:
|
case shaderir.Float:
|
||||||
|
if u != nil {
|
||||||
fs = append(fs, u...)
|
fs = append(fs, u...)
|
||||||
|
} else {
|
||||||
|
fs = append(fs, 0)
|
||||||
|
}
|
||||||
|
case shaderir.Vec2:
|
||||||
|
if u != nil {
|
||||||
|
fs = append(fs, u...)
|
||||||
|
} else {
|
||||||
|
fs = append(fs, 0, 0)
|
||||||
|
}
|
||||||
|
case shaderir.Vec3:
|
||||||
|
if u != nil {
|
||||||
|
fs = append(fs, u...)
|
||||||
|
} else {
|
||||||
|
fs = append(fs, 0, 0, 0)
|
||||||
|
}
|
||||||
|
case shaderir.Vec4:
|
||||||
|
if u != nil {
|
||||||
|
fs = append(fs, u...)
|
||||||
|
} else {
|
||||||
|
fs = append(fs, 0, 0, 0, 0)
|
||||||
|
}
|
||||||
case shaderir.Mat2:
|
case shaderir.Mat2:
|
||||||
|
if u != nil {
|
||||||
fs = append(fs,
|
fs = append(fs,
|
||||||
u[0], u[2], 0, 0,
|
u[0], u[2], 0, 0,
|
||||||
u[1], u[3],
|
u[1], u[3],
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
fs = append(fs,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0,
|
||||||
|
)
|
||||||
|
}
|
||||||
case shaderir.Mat3:
|
case shaderir.Mat3:
|
||||||
|
if u != nil {
|
||||||
fs = append(fs,
|
fs = append(fs,
|
||||||
u[0], u[3], u[6], 0,
|
u[0], u[3], u[6], 0,
|
||||||
u[1], u[4], u[7], 0,
|
u[1], u[4], u[7], 0,
|
||||||
u[2], u[5], u[8],
|
u[2], u[5], u[8],
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
fs = append(fs,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0,
|
||||||
|
)
|
||||||
|
}
|
||||||
case shaderir.Mat4:
|
case shaderir.Mat4:
|
||||||
|
if u != nil {
|
||||||
fs = append(fs,
|
fs = append(fs,
|
||||||
u[0], u[4], u[8], u[12],
|
u[0], u[4], u[8], u[12],
|
||||||
u[1], u[5], u[9], u[13],
|
u[1], u[5], u[9], u[13],
|
||||||
u[2], u[6], u[10], u[14],
|
u[2], u[6], u[10], u[14],
|
||||||
u[3], u[7], u[11], u[15],
|
u[3], u[7], u[11], u[15],
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
fs = append(fs,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
)
|
||||||
|
}
|
||||||
case shaderir.Array:
|
case shaderir.Array:
|
||||||
// Each element is aligned to the boundary.
|
// Each element is aligned to the boundary.
|
||||||
switch t.Sub[0].Main {
|
switch t.Sub[0].Main {
|
||||||
case shaderir.Float:
|
case shaderir.Float:
|
||||||
|
if u != nil {
|
||||||
for j := 0; j < t.Length; j++ {
|
for j := 0; j < t.Length; j++ {
|
||||||
fs = append(fs, u[j])
|
fs = append(fs, u[j])
|
||||||
if j < t.Length-1 {
|
if j < t.Length-1 {
|
||||||
fs = append(fs, 0, 0, 0)
|
fs = append(fs, 0, 0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fs = append(fs, make([]float32, (t.Length-1)*4+1)...)
|
||||||
|
}
|
||||||
case shaderir.Vec2:
|
case shaderir.Vec2:
|
||||||
|
if u != nil {
|
||||||
for j := 0; j < t.Length; j++ {
|
for j := 0; j < t.Length; j++ {
|
||||||
fs = append(fs, u[2*j:2*(j+1)]...)
|
fs = append(fs, u[2*j:2*(j+1)]...)
|
||||||
if j < t.Length-1 {
|
if j < t.Length-1 {
|
||||||
fs = append(fs, 0, 0)
|
fs = append(fs, 0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fs = append(fs, make([]float32, (t.Length-1)*4+2)...)
|
||||||
|
}
|
||||||
case shaderir.Vec3:
|
case shaderir.Vec3:
|
||||||
|
if u != nil {
|
||||||
for j := 0; j < t.Length; j++ {
|
for j := 0; j < t.Length; j++ {
|
||||||
fs = append(fs, u[3*j:3*(j+1)]...)
|
fs = append(fs, u[3*j:3*(j+1)]...)
|
||||||
if j < t.Length-1 {
|
if j < t.Length-1 {
|
||||||
fs = append(fs, 0)
|
fs = append(fs, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fs = append(fs, make([]float32, (t.Length-1)*4+3)...)
|
||||||
|
}
|
||||||
case shaderir.Vec4:
|
case shaderir.Vec4:
|
||||||
|
if u != nil {
|
||||||
fs = append(fs, u...)
|
fs = append(fs, u...)
|
||||||
|
} else {
|
||||||
|
fs = append(fs, make([]float32, t.Length*4)...)
|
||||||
|
}
|
||||||
case shaderir.Mat2:
|
case shaderir.Mat2:
|
||||||
|
if u != nil {
|
||||||
for j := 0; j < t.Length; j++ {
|
for j := 0; j < t.Length; j++ {
|
||||||
u1 := u[4*j : 4*(j+1)]
|
u1 := u[4*j : 4*(j+1)]
|
||||||
fs = append(fs,
|
fs = append(fs,
|
||||||
@ -1820,7 +1883,11 @@ func (s *Shader) uniformsToFloat32s(uniforms [][]float32) []float32 {
|
|||||||
if t.Length > 0 {
|
if t.Length > 0 {
|
||||||
fs = fs[:len(fs)-2]
|
fs = fs[:len(fs)-2]
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fs = append(fs, make([]float32, (t.Length-1)*8+6)...)
|
||||||
|
}
|
||||||
case shaderir.Mat3:
|
case shaderir.Mat3:
|
||||||
|
if u != nil {
|
||||||
for j := 0; j < t.Length; j++ {
|
for j := 0; j < t.Length; j++ {
|
||||||
u1 := u[9*j : 9*(j+1)]
|
u1 := u[9*j : 9*(j+1)]
|
||||||
fs = append(fs,
|
fs = append(fs,
|
||||||
@ -1832,7 +1899,11 @@ func (s *Shader) uniformsToFloat32s(uniforms [][]float32) []float32 {
|
|||||||
if t.Length > 0 {
|
if t.Length > 0 {
|
||||||
fs = fs[:len(fs)-1]
|
fs = fs[:len(fs)-1]
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fs = append(fs, make([]float32, (t.Length-1)*12+11)...)
|
||||||
|
}
|
||||||
case shaderir.Mat4:
|
case shaderir.Mat4:
|
||||||
|
if u != nil {
|
||||||
for j := 0; j < t.Length; j++ {
|
for j := 0; j < t.Length; j++ {
|
||||||
u1 := u[16*j : 16*(j+1)]
|
u1 := u[16*j : 16*(j+1)]
|
||||||
fs = append(fs,
|
fs = append(fs,
|
||||||
@ -1842,6 +1913,9 @@ func (s *Shader) uniformsToFloat32s(uniforms [][]float32) []float32 {
|
|||||||
u1[3], u1[7], u1[11], u1[15],
|
u1[3], u1[7], u1[11], u1[15],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fs = append(fs, make([]float32, t.Length*16)...)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("directx: not implemented type for uniform variables: %s", t.String()))
|
panic(fmt.Sprintf("directx: not implemented type for uniform variables: %s", t.String()))
|
||||||
}
|
}
|
||||||
|
@ -484,6 +484,9 @@ func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion graph
|
|||||||
g.rce.SetVertexBuffer(g.vb, 0, 0)
|
g.rce.SetVertexBuffer(g.vb, 0, 0)
|
||||||
|
|
||||||
for i, u := range uniforms {
|
for i, u := range uniforms {
|
||||||
|
if u == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
g.rce.SetVertexBytes(unsafe.Pointer(&u[0]), unsafe.Sizeof(u[0])*uintptr(len(u)), i+1)
|
g.rce.SetVertexBytes(unsafe.Pointer(&u[0]), unsafe.Sizeof(u[0])*uintptr(len(u)), i+1)
|
||||||
g.rce.SetFragmentBytes(unsafe.Pointer(&u[0]), unsafe.Sizeof(u[0])*uintptr(len(u)), i+1)
|
g.rce.SetFragmentBytes(unsafe.Pointer(&u[0]), unsafe.Sizeof(u[0])*uintptr(len(u)), i+1)
|
||||||
}
|
}
|
||||||
|
@ -219,6 +219,9 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textu
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range uniforms {
|
for _, u := range uniforms {
|
||||||
|
if u.value == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if got, expected := len(u.value), u.typ.FloatCount(); got != expected {
|
if got, expected := len(u.value), u.typ.FloatCount(); got != expected {
|
||||||
// Copy a shaderir.Type value once. Do not pass u.typ directly to fmt.Errorf arguments, or
|
// Copy a shaderir.Type value once. Do not pass u.typ directly to fmt.Errorf arguments, or
|
||||||
// the value u would be allocated on heap.
|
// the value u would be allocated on heap.
|
||||||
|
107
internal/shader/reachable_test.go
Normal file
107
internal/shader/reachable_test.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// Copyright 2022 The Ebitengine Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package shader_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func areIntSlicesEqual(a, b []int) bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range a {
|
||||||
|
if a[i] != b[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReachableUniformVariablesFromBlock(t *testing.T) {
|
||||||
|
src0 := `package main
|
||||||
|
|
||||||
|
var U0 float
|
||||||
|
var U1 float
|
||||||
|
|
||||||
|
func F0() float {
|
||||||
|
return U0
|
||||||
|
}
|
||||||
|
|
||||||
|
func F1() {
|
||||||
|
a := U0
|
||||||
|
_ = a
|
||||||
|
}
|
||||||
|
|
||||||
|
func F2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func F3() float {
|
||||||
|
return F0()
|
||||||
|
}
|
||||||
|
|
||||||
|
func F4() float {
|
||||||
|
return F0() + U1
|
||||||
|
}
|
||||||
|
|
||||||
|
func neverCalled() float {
|
||||||
|
return U0 + U1
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
source string
|
||||||
|
index int
|
||||||
|
expected []int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
source: src0,
|
||||||
|
index: 0,
|
||||||
|
expected: []int{0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: src0,
|
||||||
|
index: 1,
|
||||||
|
expected: []int{0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: src0,
|
||||||
|
index: 2,
|
||||||
|
expected: []int{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: src0,
|
||||||
|
index: 3,
|
||||||
|
expected: []int{0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: src0,
|
||||||
|
index: 4,
|
||||||
|
expected: []int{0, 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
ir, err := compileToIR([]byte(c.source))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
got := ir.ReachableUniformVariablesFromBlock(ir.Funcs[c.index].Block)
|
||||||
|
want := c.expected
|
||||||
|
if !areIntSlicesEqual(got, want) {
|
||||||
|
t.Errorf("test: %v, got: %v, want: %v", c, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -129,7 +129,7 @@ func Compile(p *shaderir.Program, version GLSLVersion) (vertexShader, fragmentSh
|
|||||||
|
|
||||||
var funcs []*shaderir.Func
|
var funcs []*shaderir.Func
|
||||||
if p.VertexFunc.Block != nil {
|
if p.VertexFunc.Block != nil {
|
||||||
funcs = p.ReachableFuncsFromVertexShader()
|
funcs = p.ReachableFuncsFromBlock(p.VertexFunc.Block)
|
||||||
} else {
|
} else {
|
||||||
// When a vertex entry point is not defined, allow to put all the functions. This is useful for testing.
|
// When a vertex entry point is not defined, allow to put all the functions. This is useful for testing.
|
||||||
funcs = make([]*shaderir.Func, 0, len(p.Funcs))
|
funcs = make([]*shaderir.Func, 0, len(p.Funcs))
|
||||||
@ -222,7 +222,7 @@ func Compile(p *shaderir.Program, version GLSLVersion) (vertexShader, fragmentSh
|
|||||||
|
|
||||||
var funcs []*shaderir.Func
|
var funcs []*shaderir.Func
|
||||||
if p.VertexFunc.Block != nil {
|
if p.VertexFunc.Block != nil {
|
||||||
funcs = p.ReachableFuncsFromFragmentShader()
|
funcs = p.ReachableFuncsFromBlock(p.FragmentFunc.Block)
|
||||||
} else {
|
} else {
|
||||||
// When a fragment entry point is not defined, allow to put all the functions. This is useful for testing.
|
// When a fragment entry point is not defined, allow to put all the functions. This is useful for testing.
|
||||||
funcs = make([]*shaderir.Func, 0, len(p.Funcs))
|
funcs = make([]*shaderir.Func, 0, len(p.Funcs))
|
||||||
|
@ -364,15 +364,7 @@ func IsValidSwizzling(s string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) ReachableFuncsFromVertexShader() []*Func {
|
func (p *Program) ReachableFuncsFromBlock(block *Block) []*Func {
|
||||||
return p.reachableFuncsFromBlockEntryPoint(p.VertexFunc.Block)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Program) ReachableFuncsFromFragmentShader() []*Func {
|
|
||||||
return p.reachableFuncsFromBlockEntryPoint(p.FragmentFunc.Block)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Program) reachableFuncsFromBlockEntryPoint(block *Block) []*Func {
|
|
||||||
indexToFunc := map[int]*Func{}
|
indexToFunc := map[int]*Func{}
|
||||||
for _, f := range p.Funcs {
|
for _, f := range p.Funcs {
|
||||||
f := f
|
f := f
|
||||||
@ -427,3 +419,35 @@ func walkExprsInExpr(f func(expr *Expr), expr *Expr) {
|
|||||||
walkExprsInExpr(f, &e)
|
walkExprsInExpr(f, &e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Program) ReachableUniformVariablesFromBlock(block *Block) []int {
|
||||||
|
indexToFunc := map[int]*Func{}
|
||||||
|
for _, f := range p.Funcs {
|
||||||
|
f := f
|
||||||
|
indexToFunc[f.Index] = &f
|
||||||
|
}
|
||||||
|
|
||||||
|
visitedFuncs := map[int]struct{}{}
|
||||||
|
indices := map[int]struct{}{}
|
||||||
|
var f func(expr *Expr)
|
||||||
|
f = func(expr *Expr) {
|
||||||
|
switch expr.Type {
|
||||||
|
case UniformVariable:
|
||||||
|
indices[expr.Index] = struct{}{}
|
||||||
|
case FunctionExpr:
|
||||||
|
if _, ok := visitedFuncs[expr.Index]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
visitedFuncs[expr.Index] = struct{}{}
|
||||||
|
walkExprs(f, indexToFunc[expr.Index].Block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
walkExprs(f, block)
|
||||||
|
|
||||||
|
is := make([]int, 0, len(indices))
|
||||||
|
for i := range indices {
|
||||||
|
is = append(is, i)
|
||||||
|
}
|
||||||
|
sort.Ints(is)
|
||||||
|
return is
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user