From 6fa7b4bb5ac8f5bbc7c6f55bfbbb8a293c1770d8 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 31 May 2020 23:57:03 +0900 Subject: [PATCH] shader: Analyze blocks and shadowings --- internal/shader/shader.go | 87 ++++++++++++++++++++-------------- internal/shader/shader_test.go | 49 +++++++++++++------ internal/shaderir/glsl.go | 33 ++++++++++++- internal/shaderir/ir_test.go | 30 ++++++------ 4 files changed, 133 insertions(+), 66 deletions(-) diff --git a/internal/shader/shader.go b/internal/shader/shader.go index 532765a42..fcd3ff4f7 100644 --- a/internal/shader/shader.go +++ b/internal/shader/shader.go @@ -28,7 +28,7 @@ import ( type variable struct { name string typ typ - init ast.Expr + init shaderir.Expr } type constant struct { @@ -68,6 +68,22 @@ type block struct { ir shaderir.Block } +func (b *block) findLocalVariable(name string) (int, bool) { + idx := 0 + for outer := b.outer; outer != nil; outer = outer.outer { + idx += len(outer.vars) + } + for i, v := range b.vars { + if v.name == name { + return idx + i, true + } + } + if b.outer != nil { + return b.outer.findLocalVariable(name) + } + return 0, false +} + type ParseError struct { errs []string } @@ -106,7 +122,7 @@ func (s *compileState) addError(pos token.Pos, str string) { func (cs *compileState) parse(f *ast.File) { for _, d := range f.Decls { - cs.parseDecl(&cs.global, d, true) + cs.parseDecl(&cs.global, d) } if len(cs.errs) > 0 { @@ -118,7 +134,7 @@ func (cs *compileState) parse(f *ast.File) { } } -func (cs *compileState) parseDecl(b *block, d ast.Decl, global bool) { +func (cs *compileState) parseDecl(b *block, d ast.Decl) { switch d := d.(type) { case *ast.GenDecl: switch d.Tok { @@ -140,17 +156,20 @@ func (cs *compileState) parseDecl(b *block, d ast.Decl, global bool) { for _, s := range d.Specs { s := s.(*ast.ValueSpec) vs := cs.parseVariable(b, s) - if !global { - b.vars = append(b.vars, vs...) + if b == &cs.global { + for i, v := range vs { + if v.name[0] < 'A' || 'Z' < v.name[0] { + cs.addError(s.Names[i].Pos(), fmt.Sprintf("global variables must be exposed: %s", v.name)) + } + // TODO: Check init + cs.uniforms = append(cs.uniforms, v.name) + cs.ir.Uniforms = append(cs.ir.Uniforms, v.typ.ir) + } continue } - for i, v := range vs { - if v.name[0] < 'A' || 'Z' < v.name[0] { - cs.addError(s.Names[i].Pos(), fmt.Sprintf("global variables must be exposed: %s", v.name)) - } - // TODO: Check RHS - cs.uniforms = append(cs.uniforms, v.name) - cs.ir.Uniforms = append(cs.ir.Uniforms, v.typ.ir) + for _, v := range vs { + b.vars = append(b.vars, v) + b.ir.LocalVars = append(b.ir.LocalVars, v.typ.ir) } } case token.IMPORT: @@ -181,10 +200,14 @@ func (s *compileState) parseVariable(block *block, vs *ast.ValueSpec) []variable } } name := n.Name + var e shaderir.Expr + if init != nil { + e = s.parseExpr(block, init) + } vars = append(vars, variable{ name: name, typ: t, - init: init, + init: e, }) } return vars @@ -298,20 +321,26 @@ func (cs *compileState) parseBlock(outer *block, b *ast.BlockStmt, inParams, out } case token.ASSIGN: // TODO: What about the statement `a,b = b,a?` - for range l.Rhs { - /*block.stmts = append(block.stmts, stmt{ - stmtType: stmtAssign, - exprs: []ast.Expr{l.Lhs[i], l.Rhs[i]}, - })*/ + for i := range l.Rhs { + block.ir.Stmts = append(block.ir.Stmts, shaderir.Stmt{ + Type: shaderir.Assign, + Exprs: []shaderir.Expr{ + cs.parseExpr(block, l.Lhs[i]), + cs.parseExpr(block, l.Rhs[i]), + }, + }) } } case *ast.BlockStmt: - /*block.stmts = append(block.stmts, stmt{ - stmtType: stmtBlock, - block: cs.parseBlock(block, l), - })*/ + b := cs.parseBlock(block, l, nil, nil) + block.ir.Stmts = append(block.ir.Stmts, shaderir.Stmt{ + Type: shaderir.BlockStmt, + Blocks: []shaderir.Block{ + b.ir, + }, + }) case *ast.DeclStmt: - cs.parseDecl(block, l.Decl, false) + cs.parseDecl(block, l.Decl) case *ast.ReturnStmt: for i, r := range l.Results { e := cs.parseExpr(block, r) @@ -379,18 +408,6 @@ func (s *compileState) detectType(b *block, expr ast.Expr) typ { } } -func (b *block) findLocalVariable(name string) (int, bool) { - for i, v := range b.vars { - if v.name == name { - return i, true - } - } - if b.outer != nil { - return b.outer.findLocalVariable(name) - } - return 0, false -} - func (cs *compileState) parseExpr(block *block, expr ast.Expr) shaderir.Expr { switch e := expr.(type) { case *ast.BasicLit: diff --git a/internal/shader/shader_test.go b/internal/shader/shader_test.go index b11da6860..3232c21e1 100644 --- a/internal/shader/shader_test.go +++ b/internal/shader/shader_test.go @@ -36,8 +36,6 @@ var ( Boo vec4 )`, VS: `uniform vec2 U0; -uniform vec4 U1;`, - FS: `uniform vec2 U0; uniform vec4 U1;`, }, { @@ -47,8 +45,6 @@ uniform vec4 U1;`, func Foo(foo vec2) vec4 { }`, VS: `void F0(in vec2 l0, out vec4 l1) { -}`, - FS: `void F0(in vec2 l0, out vec4 l1) { }`, }, { @@ -61,10 +57,6 @@ func Foo(foo vec2) vec4 { VS: `void F0(in vec2 l0, out vec4 l1) { l1 = vec4(l0, 0, 1); return; -}`, - FS: `void F0(in vec2 l0, out vec4 l1) { - l1 = vec4(l0, 0, 1); - return; }`, }, { @@ -81,11 +73,36 @@ func Foo(foo vec4) (float, float, float, float) { l4 = (l0).w; return; }`, - FS: `void F0(in vec4 l0, out float l1, out float l2, out float l3, out float l4) { - l1 = (l0).x; - l2 = (l0).y; - l3 = (l0).z; - l4 = (l0).w; + }, + { + Name: "blocks", + Src: `package main + +func Foo(foo vec2) vec4 { + var r vec4 + { + r.x = foo.x + var foo vec3 + { + r.y = foo.y + var foo vec4 + r.z = foo.z + } + } + return r +}`, + VS: `void F0(in vec2 l0, out vec4 l1) { + vec4 l2 = vec4(0.0); + { + vec3 l3 = vec3(0.0); + (l2).x = (l0).x; + { + vec4 l4 = vec4(0.0); + (l2).y = (l3).y; + (l2).z = (l4).z; + } + } + l1 = l2; return; }`, }, @@ -100,8 +117,10 @@ func Foo(foo vec4) (float, float, float, float) { if got, want := vs, tc.VS+"\n"; got != want { t.Errorf("%s: got: %v, want: %v", tc.Name, got, want) } - if got, want := fs, tc.FS+"\n"; got != want { - t.Errorf("%s: got: %v, want: %v", tc.Name, got, want) + if tc.FS != "" { + if got, want := fs, tc.FS+"\n"; got != want { + t.Errorf("%s: got: %v, want: %v", tc.Name, got, want) + } } } } diff --git a/internal/shaderir/glsl.go b/internal/shaderir/glsl.go index 2b2a16942..caa9a0d39 100644 --- a/internal/shaderir/glsl.go +++ b/internal/shaderir/glsl.go @@ -162,6 +162,37 @@ func (p *Program) glslVarDecl(t *Type, varname string) string { } } +func (p *Program) glslVarInit(t *Type) string { + switch t.Main { + case None: + return "?(none)" + case Array: + panic("not implemented") + case Struct: + panic("not implemented") + case Bool: + return "false" + case Int: + return "0" + case Float: + return "0.0" + case Vec2: + return "vec2(0.0)" + case Vec3: + return "vec3(0.0)" + case Vec4: + return "vec4(0.0)" + case Mat2: + return "mat2(0.0)" + case Mat3: + return "mat3(0.0)" + case Mat4: + return "mat4(0.0)" + default: + panic(fmt.Sprintf("?(unexpected type: %s)", p.glslType(t))) + } +} + func (p *Program) glslFunc(f *Func) []string { var args []string var idx int @@ -195,7 +226,7 @@ func (p *Program) glslBlock(b *Block, level int, localVarIndex int) []string { var lines []string for _, t := range b.LocalVars { - lines = append(lines, fmt.Sprintf("%s%s;", idt, p.glslVarDecl(&t, fmt.Sprintf("l%d", localVarIndex)))) + lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, p.glslVarDecl(&t, fmt.Sprintf("l%d", localVarIndex)), p.glslVarInit(&t))) localVarIndex++ } diff --git a/internal/shaderir/ir_test.go b/internal/shaderir/ir_test.go index f60b1d13e..fdaf983e5 100644 --- a/internal/shaderir/ir_test.go +++ b/internal/shaderir/ir_test.go @@ -296,12 +296,12 @@ varying vec3 V0;`, }, }, GlslVS: `void F0(in float l0, inout float l1, out float l2) { - mat4 l3; - mat4 l4; + mat4 l3 = mat4(0.0); + mat4 l4 = mat4(0.0); }`, GlslFS: `void F0(in float l0, inout float l1, out float l2) { - mat4 l3; - mat4 l4; + mat4 l3 = mat4(0.0); + mat4 l4 = mat4(0.0); }`, }, { @@ -337,19 +337,19 @@ varying vec3 V0;`, }, }, GlslVS: `void F0(in float l0, inout float l1, out float l2) { - mat4 l3; - mat4 l4; + mat4 l3 = mat4(0.0); + mat4 l4 = mat4(0.0); { - mat4 l5; - mat4 l6; + mat4 l5 = mat4(0.0); + mat4 l6 = mat4(0.0); } }`, GlslFS: `void F0(in float l0, inout float l1, out float l2) { - mat4 l3; - mat4 l4; + mat4 l3 = mat4(0.0); + mat4 l4 = mat4(0.0); { - mat4 l5; - mat4 l6; + mat4 l5 = mat4(0.0); + mat4 l6 = mat4(0.0); } }`, }, @@ -747,9 +747,9 @@ varying float V0; varying vec2 V1; void main(void) { - vec2 l0; - vec4 l1; - float l2; + vec2 l0 = vec2(0.0); + vec4 l1 = vec4(0.0); + float l2 = 0.0; l1 = V0; gl_FragColor = V1; l0 = gl_FragCoord;