diff --git a/internal/shader/shader.go b/internal/shader/shader.go index 3f80cd9eb..0f513dfb7 100644 --- a/internal/shader/shader.go +++ b/internal/shader/shader.go @@ -92,7 +92,7 @@ type block struct { pos token.Pos outer *block - ir shaderir.Block + ir *shaderir.Block } func (b *block) findLocalVariable(name string) (int, shaderir.Type, bool) { @@ -140,6 +140,7 @@ func Compile(fs *token.FileSet, f *ast.File, vertexEntry, fragmentEntry string, vertexEntry: vertexEntry, fragmentEntry: fragmentEntry, } + s.global.ir = &shaderir.Block{} s.parse(f) if len(s.errs) > 0 { @@ -221,6 +222,7 @@ func (cs *compileState) parse(f *ast.File) { Index: len(cs.funcs), InParams: inT, OutParams: outT, + Block: &shaderir.Block{}, }, }) } @@ -657,7 +659,9 @@ func (cs *compileState) parseBlock(outer *block, stmts []ast.Stmt, inParams, out block := &block{ vars: vars, outer: outer, + ir: &shaderir.Block{}, } + defer func() { var offset int if outer == &cs.global { diff --git a/internal/shader/stmt.go b/internal/shader/stmt.go index c9f113c60..04248c55b 100644 --- a/internal/shader/stmt.go +++ b/internal/shader/stmt.go @@ -103,7 +103,7 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab } stmts = append(stmts, shaderir.Stmt{ Type: shaderir.BlockStmt, - Blocks: []shaderir.Block{ + Blocks: []*shaderir.Block{ b.ir, }, }) @@ -261,7 +261,7 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab stmts = append(stmts, shaderir.Stmt{ Type: shaderir.For, - Blocks: []shaderir.Block{bodyir}, + Blocks: []*shaderir.Block{bodyir}, ForVarType: vartype, ForVarIndex: varidx, ForInit: init, @@ -281,7 +281,7 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab stmts = append(stmts, shaderir.Stmt{ Type: shaderir.BlockStmt, - Blocks: []shaderir.Block{b.ir}, + Blocks: []*shaderir.Block{b.ir}, }) return stmts, true } @@ -300,7 +300,7 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab } stmts = append(stmts, ss...) - var bs []shaderir.Block + var bs []*shaderir.Block b, ok := cs.parseBlock(block, stmt.Body.List, inParams, nil) if !ok { return nil, false diff --git a/internal/shaderir/glsl/glsl.go b/internal/shaderir/glsl/glsl.go index 58805ff26..b9c672c50 100644 --- a/internal/shaderir/glsl/glsl.go +++ b/internal/shaderir/glsl/glsl.go @@ -88,10 +88,10 @@ func Compile(p *shaderir.Program) (vertexShader, fragmentShader string) { } } - if len(p.VertexFunc.Block.Stmts) > 0 { + if p.VertexFunc.Block != nil && len(p.VertexFunc.Block.Stmts) > 0 { vslines = append(vslines, "") vslines = append(vslines, "void main(void) {") - vslines = append(vslines, c.glslBlock(p, &p.VertexFunc.Block, &p.VertexFunc.Block, 0, 0)...) + vslines = append(vslines, c.glslBlock(p, p.VertexFunc.Block, p.VertexFunc.Block, 0, 0)...) vslines = append(vslines, "}") } } @@ -126,10 +126,10 @@ func Compile(p *shaderir.Program) (vertexShader, fragmentShader string) { } } - if len(p.FragmentFunc.Block.Stmts) > 0 { + if p.FragmentFunc.Block != nil && len(p.FragmentFunc.Block.Stmts) > 0 { fslines = append(fslines, "") fslines = append(fslines, "void main(void) {") - fslines = append(fslines, c.glslBlock(p, &p.FragmentFunc.Block, &p.FragmentFunc.Block, 0, 0)...) + fslines = append(fslines, c.glslBlock(p, p.FragmentFunc.Block, p.FragmentFunc.Block, 0, 0)...) fslines = append(fslines, "}") } } @@ -239,7 +239,7 @@ func (c *compileContext) glslFunc(p *shaderir.Program, f *shaderir.Func, prototy return lines } lines = append(lines, fmt.Sprintf("%s {", sig)) - lines = append(lines, c.glslBlock(p, &f.Block, &f.Block, 0, idx)...) + lines = append(lines, c.glslBlock(p, f.Block, f.Block, 0, idx)...) lines = append(lines, "}") return lines @@ -275,7 +275,7 @@ func constantToNumberLiteral(t shaderir.ConstType, v constant.Value) string { func localVariableName(p *shaderir.Program, topBlock *shaderir.Block, idx int) string { switch topBlock { - case &p.VertexFunc.Block: + case p.VertexFunc.Block: na := len(p.Attributes) nv := len(p.Varyings) switch { @@ -288,7 +288,7 @@ func localVariableName(p *shaderir.Program, topBlock *shaderir.Block, idx int) s default: return fmt.Sprintf("l%d", idx-(na+nv+1)) } - case &p.FragmentFunc.Block: + case p.FragmentFunc.Block: nv := len(p.Varyings) switch { case idx == 0: @@ -306,6 +306,10 @@ func localVariableName(p *shaderir.Program, topBlock *shaderir.Block, idx int) s } func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderir.Block, level int, localVarIndex int) []string { + if block == nil { + return nil + } + idt := strings.Repeat("\t", level+1) var lines []string @@ -383,17 +387,17 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi lines = append(lines, fmt.Sprintf("%s%s;", idt, glslExpr(&s.Exprs[0]))) case shaderir.BlockStmt: lines = append(lines, idt+"{") - lines = append(lines, c.glslBlock(p, topBlock, &s.Blocks[0], level+1, localVarIndex)...) + 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]))) 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)...) + lines = append(lines, c.glslBlock(p, topBlock, s.Blocks[0], level+1, localVarIndex)...) if len(s.Blocks) > 1 { lines = append(lines, fmt.Sprintf("%s} else {", idt)) - lines = append(lines, c.glslBlock(p, topBlock, &s.Blocks[1], level+1, localVarIndex)...) + lines = append(lines, c.glslBlock(p, topBlock, s.Blocks[1], level+1, localVarIndex)...) } lines = append(lines, fmt.Sprintf("%s}", idt)) case shaderir.For: @@ -436,7 +440,7 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi end := constantToNumberLiteral(ct, s.ForEnd) t0, t1 := typeString(&t) lines = append(lines, fmt.Sprintf("%sfor (%s %s%s = %s; %s %s %s; %s) {", idt, t0, v, t1, init, v, op, end, delta)) - lines = append(lines, c.glslBlock(p, topBlock, &s.Blocks[0], level+1, localVarIndex)...) + lines = append(lines, c.glslBlock(p, topBlock, s.Blocks[0], level+1, localVarIndex)...) lines = append(lines, fmt.Sprintf("%s}", idt)) case shaderir.Continue: lines = append(lines, idt+"continue;") diff --git a/internal/shaderir/ir_test.go b/internal/shaderir/ir_test.go index 896a583ec..765c7b313 100644 --- a/internal/shaderir/ir_test.go +++ b/internal/shaderir/ir_test.go @@ -20,10 +20,11 @@ import ( . "github.com/hajimehoshi/ebiten/internal/shaderir" "github.com/hajimehoshi/ebiten/internal/shaderir/glsl" + "github.com/hajimehoshi/ebiten/internal/shaderir/metal" ) -func block(localVars []Type, stmts ...Stmt) Block { - return Block{ +func block(localVars []Type, stmts ...Stmt) *Block { + return &Block{ LocalVars: localVars, Stmts: stmts, } @@ -36,10 +37,10 @@ func exprStmt(expr Expr) Stmt { } } -func blockStmt(block Block) Stmt { +func blockStmt(block *Block) Stmt { return Stmt{ Type: BlockStmt, - Blocks: []Block{block}, + Blocks: []*Block{block}, } } @@ -57,18 +58,18 @@ func assignStmt(lhs Expr, rhs Expr) Stmt { } } -func ifStmt(cond Expr, block Block, elseBlock Block) Stmt { +func ifStmt(cond Expr, block *Block, elseBlock *Block) Stmt { return Stmt{ Type: If, Exprs: []Expr{cond}, - Blocks: []Block{block, elseBlock}, + Blocks: []*Block{block, elseBlock}, } } -func forStmt(index, init, end int, op Op, delta int, block Block) Stmt { +func forStmt(index, init, end int, op Op, delta int, block *Block) Stmt { return Stmt{ Type: For, - Blocks: []Block{block}, + Blocks: []*Block{block}, ForVarType: Type{Main: Int}, ForVarIndex: index, ForInit: constant.MakeInt64(int64(init)), @@ -837,6 +838,7 @@ void main(void) { t.Errorf("%s fragment: got: %s, want: %s", tc.Name, got, want) } } + metal.Compile(&tc.Program, "Vertex", "Fragment") }) } } diff --git a/internal/shaderir/metal/metal.go b/internal/shaderir/metal/metal.go index 53e765dba..58677787d 100644 --- a/internal/shaderir/metal/metal.go +++ b/internal/shaderir/metal/metal.go @@ -95,7 +95,7 @@ func Compile(p *shaderir.Program, vertex, fragment string) (shader string) { } } - if len(p.VertexFunc.Block.Stmts) > 0 { + if p.VertexFunc.Block != nil && len(p.VertexFunc.Block.Stmts) > 0 { lines = append(lines, "") lines = append(lines, fmt.Sprintf("vertex Varyings %s(", vertex), @@ -111,14 +111,14 @@ func Compile(p *shaderir.Program, vertex, fragment string) (shader string) { } lines[len(lines)-1] += ") {" lines = append(lines, fmt.Sprintf("\tVaryings %s = {};", vertexOut)) - lines = append(lines, c.metalBlock(p, &p.VertexFunc.Block, &p.VertexFunc.Block, 0, 0)...) + lines = append(lines, c.metalBlock(p, p.VertexFunc.Block, p.VertexFunc.Block, 0, 0)...) if last := fmt.Sprintf("\treturn %s;", vertexOut); lines[len(lines)-1] != last { lines = append(lines, last) } lines = append(lines, "}") } - if len(p.FragmentFunc.Block.Stmts) > 0 { + if p.FragmentFunc.Block != nil && len(p.FragmentFunc.Block.Stmts) > 0 { lines = append(lines, "") lines = append(lines, fmt.Sprintf("fragment float4 %s(", fragment), @@ -133,7 +133,7 @@ func Compile(p *shaderir.Program, vertex, fragment string) (shader string) { } lines[len(lines)-1] += ") {" lines = append(lines, fmt.Sprintf("\tfloat4 %s = float4(0);", fragmentOut)) - lines = append(lines, c.metalBlock(p, &p.FragmentFunc.Block, &p.FragmentFunc.Block, 0, 0)...) + lines = append(lines, c.metalBlock(p, p.FragmentFunc.Block, p.FragmentFunc.Block, 0, 0)...) if last := fmt.Sprintf("\treturn %s;", fragmentOut); lines[len(lines)-1] != last { lines = append(lines, last) } @@ -245,7 +245,7 @@ func (c *compileContext) metalFunc(p *shaderir.Program, f *shaderir.Func, protot return lines } lines = append(lines, fmt.Sprintf("%s {", sig)) - lines = append(lines, c.metalBlock(p, &f.Block, &f.Block, 0, idx)...) + lines = append(lines, c.metalBlock(p, f.Block, f.Block, 0, idx)...) lines = append(lines, "}") return lines @@ -281,7 +281,7 @@ func constantToNumberLiteral(t shaderir.ConstType, v constant.Value) string { func localVariableName(p *shaderir.Program, topBlock *shaderir.Block, idx int) string { switch topBlock { - case &p.VertexFunc.Block: + case p.VertexFunc.Block: na := len(p.Attributes) nv := len(p.Varyings) switch { @@ -294,7 +294,7 @@ func localVariableName(p *shaderir.Program, topBlock *shaderir.Block, idx int) s default: return fmt.Sprintf("l%d", idx-(na+nv+1)) } - case &p.FragmentFunc.Block: + case p.FragmentFunc.Block: nv := len(p.Varyings) switch { case idx == 0: @@ -312,6 +312,10 @@ func localVariableName(p *shaderir.Program, topBlock *shaderir.Block, idx int) s } func (c *compileContext) metalBlock(p *shaderir.Program, topBlock, block *shaderir.Block, level int, localVarIndex int) []string { + if block == nil { + return nil + } + idt := strings.Repeat("\t", level+1) var lines []string @@ -391,17 +395,17 @@ func (c *compileContext) metalBlock(p *shaderir.Program, topBlock, block *shader lines = append(lines, fmt.Sprintf("%s%s;", idt, metalExpr(&s.Exprs[0]))) case shaderir.BlockStmt: lines = append(lines, idt+"{") - lines = append(lines, c.metalBlock(p, topBlock, &s.Blocks[0], level+1, localVarIndex)...) + 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]))) - lines = append(lines, c.metalBlock(p, topBlock, &s.Blocks[0], level+1, localVarIndex)...) + lines = append(lines, c.metalBlock(p, topBlock, s.Blocks[0], level+1, localVarIndex)...) if len(s.Blocks) > 1 { lines = append(lines, fmt.Sprintf("%s} else {", idt)) - lines = append(lines, c.metalBlock(p, topBlock, &s.Blocks[1], level+1, localVarIndex)...) + lines = append(lines, c.metalBlock(p, topBlock, s.Blocks[1], level+1, localVarIndex)...) } lines = append(lines, fmt.Sprintf("%s}", idt)) case shaderir.For: @@ -444,7 +448,7 @@ func (c *compileContext) metalBlock(p *shaderir.Program, topBlock, block *shader end := constantToNumberLiteral(ct, s.ForEnd) ts := typeString(&t, false, false) lines = append(lines, fmt.Sprintf("%sfor (%s %s = %s; %s %s %s; %s) {", idt, ts, v, init, v, op, end, delta)) - lines = append(lines, c.metalBlock(p, topBlock, &s.Blocks[0], level+1, localVarIndex)...) + lines = append(lines, c.metalBlock(p, topBlock, s.Blocks[0], level+1, localVarIndex)...) lines = append(lines, fmt.Sprintf("%s}", idt)) case shaderir.Continue: lines = append(lines, idt+"continue;") @@ -452,9 +456,9 @@ func (c *compileContext) metalBlock(p *shaderir.Program, topBlock, block *shader lines = append(lines, idt+"break;") case shaderir.Return: switch { - case topBlock == &p.VertexFunc.Block: + case topBlock == p.VertexFunc.Block: lines = append(lines, fmt.Sprintf("%sreturn %s;", idt, vertexOut)) - case topBlock == &p.FragmentFunc.Block: + case topBlock == p.FragmentFunc.Block: lines = append(lines, fmt.Sprintf("%sreturn %s;", idt, fragmentOut)) case len(s.Exprs) == 0: lines = append(lines, idt+"return;") diff --git a/internal/shaderir/program.go b/internal/shaderir/program.go index fe1566cfa..b5b2d0c28 100644 --- a/internal/shaderir/program.go +++ b/internal/shaderir/program.go @@ -36,7 +36,7 @@ type Func struct { InParams []Type OutParams []Type Return Type - Block Block + Block *Block } // VertexFunc takes pseudo params, and the number if len(attributes) + len(varyings) + 1. @@ -45,7 +45,7 @@ type Func struct { // If len(attributes) + 1 <= index < len(attributes) + len(varyings) + 1, the params are out-params and represent // varying variables. type VertexFunc struct { - Block Block + Block *Block } // FragmentFunc takes pseudo params, and the number is len(varyings) + 2. @@ -53,7 +53,7 @@ type VertexFunc struct { // If index == len(varyings), the param represents (index-1)th verying variable. // If index == len(varyings)+1, the param is an out-param representing the color of the pixel (gl_FragColor in GLSL). type FragmentFunc struct { - Block Block + Block *Block } type Block struct { @@ -64,7 +64,7 @@ type Block struct { type Stmt struct { Type StmtType Exprs []Expr - Blocks []Block + Blocks []*Block ForVarType Type ForVarIndex int ForInit constant.Value diff --git a/internal/testing/shader.go b/internal/testing/shader.go index 5272283d5..8eea05663 100644 --- a/internal/testing/shader.go +++ b/internal/testing/shader.go @@ -173,7 +173,7 @@ var ( }, } defaultVertexFunc = shaderir.VertexFunc{ - Block: shaderir.Block{ + Block: &shaderir.Block{ Stmts: []shaderir.Stmt{ { Type: shaderir.Assign, @@ -279,7 +279,7 @@ func ShaderProgramFill(r, g, b, a byte) shaderir.Program { p := defaultProgram() p.FragmentFunc = shaderir.FragmentFunc{ - Block: shaderir.Block{ + Block: &shaderir.Block{ Stmts: []shaderir.Stmt{ { Type: shaderir.Assign, @@ -413,7 +413,7 @@ func ShaderProgramImages(imageNum int) shaderir.Program { }) p.FragmentFunc = shaderir.FragmentFunc{ - Block: shaderir.Block{ + Block: &shaderir.Block{ LocalVars: []shaderir.Type{ {Main: shaderir.Vec4}, },