From dee869050240633c4cd67624dc96403e5dc371b5 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 9 Aug 2020 18:55:39 +0900 Subject: [PATCH] shaderir/glsl: Bug fix: Copying an array did not work on GLSL Fixes #1286 --- internal/shader/testdata/array.expected.vs | 9 ++- internal/shaderir/glsl/glsl.go | 71 +++++++++++++++++----- internal/shaderir/metal/metal.go | 2 - 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/internal/shader/testdata/array.expected.vs b/internal/shader/testdata/array.expected.vs index 38939a2db..85dfa7f02 100644 --- a/internal/shader/testdata/array.expected.vs +++ b/internal/shader/testdata/array.expected.vs @@ -7,7 +7,8 @@ void F0(out vec2 l0[2]) { vec2 l1[2]; l1[0] = vec2(0); l1[1] = vec2(0); - l0 = l1; + l0[0] = l1[0]; + l0[1] = l1[1]; return; } @@ -19,8 +20,10 @@ void F1(out vec2 l0[2]) { l2[0] = vec2(0); l2[1] = vec2(0); (l1)[0] = vec2(1.0); - l2 = l1; + l2[0] = l1[0]; + l2[1] = l1[1]; ((l2)[1]).y = vec2(2.0); - l0 = l2; + l0[0] = l2[0]; + l0[1] = l2[1]; return; } diff --git a/internal/shaderir/glsl/glsl.go b/internal/shaderir/glsl/glsl.go index b9c672c50..7d6abaaf5 100644 --- a/internal/shaderir/glsl/glsl.go +++ b/internal/shaderir/glsl/glsl.go @@ -273,35 +273,67 @@ func constantToNumberLiteral(t shaderir.ConstType, v constant.Value) string { return fmt.Sprintf("?(unexpected literal: %s)", v) } -func localVariableName(p *shaderir.Program, topBlock *shaderir.Block, idx int) string { +func descendantLocalVars(block, target *shaderir.Block) ([]shaderir.Type, bool) { + if block == target { + return block.LocalVars, true + } + + var ts []shaderir.Type + for _, s := range block.Stmts { + for _, b := range s.Blocks { + if ts2, found := descendantLocalVars(b, target); found { + ts = append(ts, block.LocalVars...) + ts = append(ts, ts2...) + return ts, true + } + } + } + return nil, false +} + +func localVariableType(p *shaderir.Program, topBlock, block *shaderir.Block, absidx int) shaderir.Type { + var ts []shaderir.Type + for _, f := range p.Funcs { + if f.Block == topBlock { + ts = append(f.InParams, f.OutParams...) + break + } + } + + ts2, _ := descendantLocalVars(topBlock, block) + ts = append(ts, ts2...) + return ts[absidx] +} + +func localVariable(p *shaderir.Program, topBlock, block *shaderir.Block, idx int) (string, shaderir.Type) { switch topBlock { case p.VertexFunc.Block: na := len(p.Attributes) nv := len(p.Varyings) switch { case idx < na: - return fmt.Sprintf("A%d", idx) + return fmt.Sprintf("A%d", idx), p.Attributes[idx] case idx == na: - return "gl_Position" + return "gl_Position", shaderir.Type{Main: shaderir.Vec4} case idx < na+nv+1: - return fmt.Sprintf("V%d", idx-na-1) + return fmt.Sprintf("V%d", idx-na-1), p.Varyings[idx-na-1] default: - return fmt.Sprintf("l%d", idx-(na+nv+1)) + return fmt.Sprintf("l%d", idx-(na+nv+1)), localVariableType(p, topBlock, block, idx-(na+nv+1)) } case p.FragmentFunc.Block: nv := len(p.Varyings) switch { case idx == 0: - return "gl_FragCoord" + return "gl_FragCoord", shaderir.Type{Main: shaderir.Vec4} case idx < nv+1: - return fmt.Sprintf("V%d", idx-1) + return fmt.Sprintf("V%d", idx-1), p.Varyings[idx-1] case idx == nv+1: - return "gl_FragColor" + return "gl_FragColor", shaderir.Type{Main: shaderir.Vec4} default: - return fmt.Sprintf("l%d", idx-(nv+2)) + return fmt.Sprintf("l%d", idx-(nv+2)), localVariableType(p, topBlock, block, idx-(nv+2)) } default: - return fmt.Sprintf("l%d", idx) + return fmt.Sprintf("l%d", idx), localVariableType(p, topBlock, block, idx) } } @@ -340,7 +372,8 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi case shaderir.TextureVariable: return fmt.Sprintf("T%d", e.Index) case shaderir.LocalVariable: - return localVariableName(p, topBlock, e.Index) + n, _ := localVariable(p, topBlock, block, e.Index) + return n case shaderir.StructMember: return fmt.Sprintf("M%d", e.Index) case shaderir.BuiltinFuncExpr: @@ -390,8 +423,17 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi lines = append(lines, c.glslBlock(p, topBlock, s.Blocks[0], level+1, localVarIndex)...) lines = append(lines, idt+"}") case shaderir.Assign: - // TODO: Give an appropriate context - lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, glslExpr(&s.Exprs[0]), glslExpr(&s.Exprs[1]))) + lhs := s.Exprs[0] + rhs := s.Exprs[1] + if lhs.Type == shaderir.LocalVariable { + if _, t := localVariable(p, topBlock, block, lhs.Index); t.Main == shaderir.Array { + for i := 0; i < t.Length; i++ { + lines = append(lines, fmt.Sprintf("%[1]s%[2]s[%[3]d] = %[4]s[%[3]d];", idt, glslExpr(&lhs), i, glslExpr(&rhs))) + } + continue + } + } + lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, glslExpr(&lhs), glslExpr(&rhs))) case shaderir.If: lines = append(lines, fmt.Sprintf("%sif (%s) {", idt, glslExpr(&s.Exprs[0]))) lines = append(lines, c.glslBlock(p, topBlock, s.Blocks[0], level+1, localVarIndex)...) @@ -409,7 +451,7 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi ct = shaderir.ConstTypeFloat } - v := localVariableName(p, topBlock, s.ForVarIndex) + v, _ := localVariable(p, topBlock, block, s.ForVarIndex) var delta string switch val, _ := constant.Float64Val(s.ForDelta); val { case 0: @@ -450,7 +492,6 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi if len(s.Exprs) == 0 { lines = append(lines, idt+"return;") } else { - // TODO: Give an appropriate context. lines = append(lines, fmt.Sprintf("%sreturn %s;", idt, glslExpr(&s.Exprs[0]))) } case shaderir.Discard: diff --git a/internal/shaderir/metal/metal.go b/internal/shaderir/metal/metal.go index 58677787d..8f74ead6c 100644 --- a/internal/shaderir/metal/metal.go +++ b/internal/shaderir/metal/metal.go @@ -398,7 +398,6 @@ func (c *compileContext) metalBlock(p *shaderir.Program, topBlock, block *shader lines = append(lines, c.metalBlock(p, topBlock, s.Blocks[0], level+1, localVarIndex)...) lines = append(lines, idt+"}") case shaderir.Assign: - // TODO: Give an appropriate context lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, metalExpr(&s.Exprs[0]), metalExpr(&s.Exprs[1]))) case shaderir.If: lines = append(lines, fmt.Sprintf("%sif (%s) {", idt, metalExpr(&s.Exprs[0]))) @@ -463,7 +462,6 @@ func (c *compileContext) metalBlock(p *shaderir.Program, topBlock, block *shader case len(s.Exprs) == 0: lines = append(lines, idt+"return;") default: - // TODO: Give an appropriate context. lines = append(lines, fmt.Sprintf("%sreturn %s;", idt, metalExpr(&s.Exprs[0]))) } case shaderir.Discard: