shader: Bug fix: Wrong local variable indices in blocks

This commit is contained in:
Hajime Hoshi 2020-08-09 23:40:41 +09:00
parent 240e20ad87
commit 5d2606b6a5
10 changed files with 137 additions and 52 deletions

View File

@ -633,7 +633,7 @@ func (cs *compileState) parseFunc(block *block, d *ast.FuncDecl) (function, bool
} }
} }
b, ok := cs.parseBlock(block, d.Body.List, inParams, outParams) b, ok := cs.parseBlock(block, d.Name.Name, d.Body.List, inParams, outParams)
if !ok { if !ok {
return function{}, false return function{}, false
} }
@ -657,17 +657,34 @@ func (cs *compileState) parseFunc(block *block, d *ast.FuncDecl) (function, bool
}, true }, true
} }
func (cs *compileState) parseBlock(outer *block, stmts []ast.Stmt, inParams, outParams []variable) (*block, bool) { func (cs *compileState) parseBlock(outer *block, fname string, stmts []ast.Stmt, inParams, outParams []variable) (*block, bool) {
var vars []variable var vars []variable
if outer == &cs.global { if outer == &cs.global {
vars = make([]variable, 0, len(inParams)+len(outParams)) vars = make([]variable, 0, len(inParams)+len(outParams))
vars = append(vars, inParams...) vars = append(vars, inParams...)
vars = append(vars, outParams...) vars = append(vars, outParams...)
} }
var offset int
switch {
case outer.outer == nil && fname == cs.vertexEntry:
offset = 0
case outer.outer == nil && fname == cs.fragmentEntry:
offset = 0
case outer.outer == nil:
offset = len(inParams) + len(outParams)
case outer.outer.outer == nil:
offset = len(outer.outer.vars) + len(outer.vars)
default:
offset = outer.ir.LocalVarIndexOffset + len(outer.vars)
}
block := &block{ block := &block{
vars: vars, vars: vars,
outer: outer, outer: outer,
ir: &shaderir.Block{}, ir: &shaderir.Block{
LocalVarIndexOffset: offset,
},
} }
defer func() { defer func() {
@ -685,7 +702,7 @@ func (cs *compileState) parseBlock(outer *block, stmts []ast.Stmt, inParams, out
}() }()
for _, stmt := range stmts { for _, stmt := range stmts {
ss, ok := cs.parseStmt(block, stmt, inParams) ss, ok := cs.parseStmt(block, fname, stmt, inParams)
if !ok { if !ok {
return nil, false return nil, false
} }

View File

@ -24,7 +24,7 @@ import (
"github.com/hajimehoshi/ebiten/internal/shaderir" "github.com/hajimehoshi/ebiten/internal/shaderir"
) )
func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variable) ([]shaderir.Stmt, bool) { func (cs *compileState) parseStmt(block *block, fname string, stmt ast.Stmt, inParams []variable) ([]shaderir.Stmt, bool) {
var stmts []shaderir.Stmt var stmts []shaderir.Stmt
switch stmt := stmt.(type) { switch stmt := stmt.(type) {
@ -97,7 +97,7 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab
cs.addError(stmt.Pos(), fmt.Sprintf("unexpected token: %s", stmt.Tok)) cs.addError(stmt.Pos(), fmt.Sprintf("unexpected token: %s", stmt.Tok))
} }
case *ast.BlockStmt: case *ast.BlockStmt:
b, ok := cs.parseBlock(block, stmt.List, inParams, nil) b, ok := cs.parseBlock(block, fname, stmt.List, inParams, nil)
if !ok { if !ok {
return nil, false return nil, false
} }
@ -132,7 +132,7 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab
// Create a new pseudo block for the initial statement, so that the counter variable belongs to the // Create a new pseudo block for the initial statement, so that the counter variable belongs to the
// new pseudo block for each for-loop. Without this, the samely named counter variables in different // new pseudo block for each for-loop. Without this, the samely named counter variables in different
// for-loops confuses the parser. // for-loops confuses the parser.
pseudoBlock, ok := cs.parseBlock(block, []ast.Stmt{stmt.Init}, inParams, nil) pseudoBlock, ok := cs.parseBlock(block, fname, []ast.Stmt{stmt.Init}, inParams, nil)
if !ok { if !ok {
return nil, false return nil, false
} }
@ -198,7 +198,7 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab
} }
end := exprs[0].Exprs[1].Const end := exprs[0].Exprs[1].Const
postSs, ok := cs.parseStmt(pseudoBlock, stmt.Post, inParams) postSs, ok := cs.parseStmt(pseudoBlock, fname, stmt.Post, inParams)
if !ok { if !ok {
return nil, false return nil, false
} }
@ -244,7 +244,7 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab
return nil, false return nil, false
} }
b, ok := cs.parseBlock(pseudoBlock, []ast.Stmt{stmt.Body}, inParams, nil) b, ok := cs.parseBlock(pseudoBlock, fname, []ast.Stmt{stmt.Body}, inParams, nil)
if !ok { if !ok {
return nil, false return nil, false
} }
@ -256,8 +256,9 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab
// As the pseudo block is not actually used, copy the variable part to the actual block. // As the pseudo block is not actually used, copy the variable part to the actual block.
// This must be done after parsing the for-loop is done, or the duplicated variables confuses the // This must be done after parsing the for-loop is done, or the duplicated variables confuses the
// parsing. // parsing.
block.vars = append(block.vars, pseudoBlock.vars[0]) v := pseudoBlock.vars[0]
block.vars[len(block.vars)-1].forLoopCounter = true v.forLoopCounter = true
block.vars = append(block.vars, v)
stmts = append(stmts, shaderir.Stmt{ stmts = append(stmts, shaderir.Stmt{
Type: shaderir.For, Type: shaderir.For,
@ -274,7 +275,7 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab
if stmt.Init != nil { if stmt.Init != nil {
init := stmt.Init init := stmt.Init
stmt.Init = nil stmt.Init = nil
b, ok := cs.parseBlock(block, []ast.Stmt{init, stmt}, inParams, nil) b, ok := cs.parseBlock(block, fname, []ast.Stmt{init, stmt}, inParams, nil)
if !ok { if !ok {
return nil, false return nil, false
} }
@ -301,7 +302,7 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab
stmts = append(stmts, ss...) stmts = append(stmts, ss...)
var bs []*shaderir.Block var bs []*shaderir.Block
b, ok := cs.parseBlock(block, stmt.Body.List, inParams, nil) b, ok := cs.parseBlock(block, fname, stmt.Body.List, inParams, nil)
if !ok { if !ok {
return nil, false return nil, false
} }
@ -310,13 +311,13 @@ func (cs *compileState) parseStmt(block *block, stmt ast.Stmt, inParams []variab
if stmt.Else != nil { if stmt.Else != nil {
switch s := stmt.Else.(type) { switch s := stmt.Else.(type) {
case *ast.BlockStmt: case *ast.BlockStmt:
b, ok := cs.parseBlock(block, s.List, inParams, nil) b, ok := cs.parseBlock(block, fname, s.List, inParams, nil)
if !ok { if !ok {
return nil, false return nil, false
} }
bs = append(bs, b.ir) bs = append(bs, b.ir)
default: default:
b, ok := cs.parseBlock(block, []ast.Stmt{s}, inParams, nil) b, ok := cs.parseBlock(block, fname, []ast.Stmt{s}, inParams, nil)
if !ok { if !ok {
return nil, false return nil, false
} }

View File

@ -0,0 +1,22 @@
void F0(in vec2 l0, out vec4 l1);
void F0(in vec2 l0, out vec4 l1) {
vec4 l2 = vec4(0);
{
vec3 l3 = vec3(0);
vec3 l4 = vec3(0);
(l2).x = (l0).x;
{
vec4 l4 = vec4(0);
(l2).y = (l3).y;
(l2).z = (l4).z;
}
{
vec4 l5 = vec4(0);
(l2).y = (l3).y;
(l2).z = (l4).z;
}
}
l1 = l2;
return;
}

21
internal/shader/testdata/blocks3.go vendored Normal file
View File

@ -0,0 +1,21 @@
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
}
var bar vec3
{
r.y = foo.y
var foo vec4
r.z = bar.z
}
}
return r
}

View File

@ -5,7 +5,7 @@ void F0(out vec2 l0) {
vec2 l3 = vec2(0); vec2 l3 = vec2(0);
l1 = vec2(0.0); l1 = vec2(0.0);
for (int l2 = 0; l2 < 100; l2++) { for (int l2 = 0; l2 < 100; l2++) {
vec2 l5 = vec2(0); vec2 l3 = vec2(0);
l3 = vec2(0.0); l3 = vec2(0.0);
l1 = l3; l1 = l3;
} }

View File

@ -91,7 +91,7 @@ func Compile(p *shaderir.Program) (vertexShader, fragmentShader string) {
if p.VertexFunc.Block != nil && len(p.VertexFunc.Block.Stmts) > 0 { if p.VertexFunc.Block != nil && len(p.VertexFunc.Block.Stmts) > 0 {
vslines = append(vslines, "") vslines = append(vslines, "")
vslines = append(vslines, "void main(void) {") 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)...)
vslines = append(vslines, "}") vslines = append(vslines, "}")
} }
} }
@ -129,7 +129,7 @@ func Compile(p *shaderir.Program) (vertexShader, fragmentShader string) {
if p.FragmentFunc.Block != nil && len(p.FragmentFunc.Block.Stmts) > 0 { if p.FragmentFunc.Block != nil && len(p.FragmentFunc.Block.Stmts) > 0 {
fslines = append(fslines, "") fslines = append(fslines, "")
fslines = append(fslines, "void main(void) {") 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)...)
fslines = append(fslines, "}") fslines = append(fslines, "}")
} }
} }
@ -239,7 +239,7 @@ func (c *compileContext) glslFunc(p *shaderir.Program, f *shaderir.Func, prototy
return lines return lines
} }
lines = append(lines, fmt.Sprintf("%s {", sig)) 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)...)
lines = append(lines, "}") lines = append(lines, "}")
return lines return lines
@ -337,7 +337,7 @@ func localVariable(p *shaderir.Program, topBlock, block *shaderir.Block, idx int
} }
} }
func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderir.Block, level int, localVarIndex int) []string { func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderir.Block, level int) []string {
if block == nil { if block == nil {
return nil return nil
} }
@ -345,8 +345,8 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi
idt := strings.Repeat("\t", level+1) idt := strings.Repeat("\t", level+1)
var lines []string var lines []string
for _, t := range block.LocalVars { for i, t := range block.LocalVars {
name := fmt.Sprintf("l%d", localVarIndex) name := fmt.Sprintf("l%d", block.LocalVarIndexOffset+i)
switch t.Main { switch t.Main {
case shaderir.Array: case shaderir.Array:
lines = append(lines, fmt.Sprintf("%s%s;", idt, c.glslVarDecl(p, &t, name))) lines = append(lines, fmt.Sprintf("%s%s;", idt, c.glslVarDecl(p, &t, name)))
@ -359,7 +359,6 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi
default: default:
lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, c.glslVarDecl(p, &t, name), c.glslVarInit(p, &t))) lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, c.glslVarDecl(p, &t, name), c.glslVarInit(p, &t)))
} }
localVarIndex++
} }
var glslExpr func(e *shaderir.Expr) string var glslExpr func(e *shaderir.Expr) string
@ -420,7 +419,7 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi
lines = append(lines, fmt.Sprintf("%s%s;", idt, glslExpr(&s.Exprs[0]))) lines = append(lines, fmt.Sprintf("%s%s;", idt, glslExpr(&s.Exprs[0])))
case shaderir.BlockStmt: case shaderir.BlockStmt:
lines = append(lines, idt+"{") 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)...)
lines = append(lines, idt+"}") lines = append(lines, idt+"}")
case shaderir.Assign: case shaderir.Assign:
lhs := s.Exprs[0] lhs := s.Exprs[0]
@ -436,10 +435,10 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi
lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, glslExpr(&lhs), glslExpr(&rhs))) lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, glslExpr(&lhs), glslExpr(&rhs)))
case shaderir.If: case shaderir.If:
lines = append(lines, fmt.Sprintf("%sif (%s) {", idt, glslExpr(&s.Exprs[0]))) 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)...)
if len(s.Blocks) > 1 { if len(s.Blocks) > 1 {
lines = append(lines, fmt.Sprintf("%s} else {", idt)) 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)...)
} }
lines = append(lines, fmt.Sprintf("%s}", idt)) lines = append(lines, fmt.Sprintf("%s}", idt))
case shaderir.For: case shaderir.For:
@ -482,7 +481,7 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi
end := constantToNumberLiteral(ct, s.ForEnd) end := constantToNumberLiteral(ct, s.ForEnd)
t0, t1 := typeString(&t) 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, 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)...)
lines = append(lines, fmt.Sprintf("%s}", idt)) lines = append(lines, fmt.Sprintf("%s}", idt))
case shaderir.Continue: case shaderir.Continue:
lines = append(lines, idt+"continue;") lines = append(lines, idt+"continue;")

View File

@ -23,10 +23,11 @@ import (
"github.com/hajimehoshi/ebiten/internal/shaderir/metal" "github.com/hajimehoshi/ebiten/internal/shaderir/metal"
) )
func block(localVars []Type, stmts ...Stmt) *Block { func block(localVars []Type, offset int, stmts ...Stmt) *Block {
return &Block{ return &Block{
LocalVars: localVars, LocalVars: localVars,
Stmts: stmts, LocalVarIndexOffset: offset,
Stmts: stmts,
} }
} }
@ -279,6 +280,7 @@ void F0(in float l0, in vec2 l1, in vec4 l2, out mat4 l3) {
Return: Type{Main: Float}, Return: Type{Main: Float},
Block: block( Block: block(
nil, nil,
0,
returnStmt( returnStmt(
localVariableExpr(0), localVariableExpr(0),
), ),
@ -313,7 +315,7 @@ float F0(in float l0) {
Block: block([]Type{ Block: block([]Type{
{Main: Mat4}, {Main: Mat4},
{Main: Mat4}, {Main: Mat4},
}), }, 2),
}, },
}, },
}, },
@ -348,12 +350,14 @@ void F0(in float l0, out float l1) {
{Main: Mat4}, {Main: Mat4},
{Main: Mat4}, {Main: Mat4},
}, },
2,
blockStmt( blockStmt(
block( block(
[]Type{ []Type{
{Main: Mat4}, {Main: Mat4},
{Main: Mat4}, {Main: Mat4},
}, },
4,
), ),
), ),
), ),
@ -397,6 +401,7 @@ void F0(in float l0, out float l1) {
}, },
Block: block( Block: block(
nil, nil,
0,
assignStmt( assignStmt(
localVariableExpr(2), localVariableExpr(2),
binaryExpr( binaryExpr(
@ -437,6 +442,7 @@ void F0(in float l0, in float l1, out float l2) {
}, },
Block: block( Block: block(
nil, nil,
0,
assignStmt( assignStmt(
localVariableExpr(3), localVariableExpr(3),
selectionExpr( selectionExpr(
@ -476,6 +482,7 @@ void F0(in bool l0, in float l1, in float l2, out float l3) {
}, },
Block: block( Block: block(
nil, nil,
0,
exprStmt( exprStmt(
callExpr( callExpr(
functionExpr(1), functionExpr(1),
@ -522,6 +529,7 @@ void F0(in float l0, in float l1, out vec2 l2) {
}, },
Block: block( Block: block(
nil, nil,
0,
assignStmt( assignStmt(
localVariableExpr(2), localVariableExpr(2),
callExpr( callExpr(
@ -560,6 +568,7 @@ void F0(in float l0, in float l1, out float l2) {
}, },
Block: block( Block: block(
nil, nil,
0,
assignStmt( assignStmt(
localVariableExpr(1), localVariableExpr(1),
fieldSelectorExpr( fieldSelectorExpr(
@ -598,6 +607,7 @@ void F0(in vec4 l0, out vec2 l1) {
}, },
Block: block( Block: block(
nil, nil,
0,
ifStmt( ifStmt(
binaryExpr( binaryExpr(
EqualOp, EqualOp,
@ -606,6 +616,7 @@ void F0(in vec4 l0, out vec2 l1) {
), ),
block( block(
nil, nil,
0,
assignStmt( assignStmt(
localVariableExpr(2), localVariableExpr(2),
localVariableExpr(0), localVariableExpr(0),
@ -613,6 +624,7 @@ void F0(in vec4 l0, out vec2 l1) {
), ),
block( block(
nil, nil,
0,
assignStmt( assignStmt(
localVariableExpr(2), localVariableExpr(2),
localVariableExpr(1), localVariableExpr(1),
@ -660,6 +672,7 @@ void F0(in float l0, in float l1, out float l2) {
[]Type{ []Type{
{}, {},
}, },
0,
forStmt( forStmt(
Type{Main: Int}, Type{Main: Int},
3, 3,
@ -669,6 +682,7 @@ void F0(in float l0, in float l1, out float l2) {
1, 1,
block( block(
nil, nil,
4,
assignStmt( assignStmt(
localVariableExpr(2), localVariableExpr(2),
localVariableExpr(0), localVariableExpr(0),
@ -712,6 +726,7 @@ void F0(in float l0, in float l1, out float l2) {
[]Type{ []Type{
{}, {},
}, },
0,
forStmt( forStmt(
Type{Main: Int}, Type{Main: Int},
3, 3,
@ -723,6 +738,7 @@ void F0(in float l0, in float l1, out float l2) {
[]Type{ []Type{
{Main: Int}, {Main: Int},
}, },
4,
assignStmt( assignStmt(
localVariableExpr(2), localVariableExpr(2),
localVariableExpr(4), localVariableExpr(4),
@ -783,6 +799,7 @@ void F0(float l0, float l1, thread float& l2) {
{}, {},
{}, {},
}, },
0,
forStmt( forStmt(
Type{Main: Int}, Type{Main: Int},
3, 3,
@ -794,9 +811,10 @@ void F0(float l0, float l1, thread float& l2) {
[]Type{ []Type{
{Main: Int}, {Main: Int},
}, },
4,
assignStmt( assignStmt(
localVariableExpr(2), localVariableExpr(2),
localVariableExpr(5), localVariableExpr(4),
), ),
), ),
), ),
@ -811,6 +829,7 @@ void F0(float l0, float l1, thread float& l2) {
[]Type{ []Type{
{Main: Int}, {Main: Int},
}, },
5,
assignStmt( assignStmt(
localVariableExpr(2), localVariableExpr(2),
localVariableExpr(5), localVariableExpr(5),
@ -825,8 +844,8 @@ void F0(float l0, float l1, thread float& l2) {
void F0(in float l0, in float l1, out float l2) { void F0(in float l0, in float l1, out float l2) {
for (int l3 = 0; l3 < 100; l3++) { for (int l3 = 0; l3 < 100; l3++) {
int l5 = 0; int l4 = 0;
l2 = l5; l2 = l4;
} }
for (float l4 = 0.0; l4 < 100.0; l4++) { for (float l4 = 0.0; l4 < 100.0; l4++) {
int l5 = 0; int l5 = 0;
@ -838,8 +857,8 @@ void F0(in float l0, in float l1, out float l2);
void F0(in float l0, in float l1, out float l2) { void F0(in float l0, in float l1, out float l2) {
for (int l3 = 0; l3 < 100; l3++) { for (int l3 = 0; l3 < 100; l3++) {
int l5 = 0; int l4 = 0;
l2 = l5; l2 = l4;
} }
for (float l4 = 0.0; l4 < 100.0; l4++) { for (float l4 = 0.0; l4 < 100.0; l4++) {
int l5 = 0; int l5 = 0;
@ -856,8 +875,8 @@ void F0(float l0, float l1, thread float& l2);
void F0(float l0, float l1, thread float& l2) { void F0(float l0, float l1, thread float& l2) {
for (int l3 = 0; l3 < 100; l3++) { for (int l3 = 0; l3 < 100; l3++) {
int l5 = 0; int l4 = 0;
l2 = l5; l2 = l4;
} }
for (float l4 = 0.0; l4 < 100.0; l4++) { for (float l4 = 0.0; l4 < 100.0; l4++) {
int l5 = 0; int l5 = 0;
@ -883,6 +902,7 @@ void F0(float l0, float l1, thread float& l2) {
VertexFunc: VertexFunc{ VertexFunc: VertexFunc{
Block: block( Block: block(
nil, nil,
0,
assignStmt( assignStmt(
localVariableExpr(3), localVariableExpr(3),
localVariableExpr(0), localVariableExpr(0),
@ -933,6 +953,7 @@ varying vec2 V1;`,
VertexFunc: VertexFunc{ VertexFunc: VertexFunc{
Block: block( Block: block(
nil, nil,
0,
assignStmt( assignStmt(
localVariableExpr(3), localVariableExpr(3),
localVariableExpr(0), localVariableExpr(0),
@ -953,6 +974,7 @@ varying vec2 V1;`,
{Main: Float}, {Main: Float},
{Main: Vec2}, {Main: Vec2},
}, },
0,
assignStmt( assignStmt(
localVariableExpr(3), localVariableExpr(3),
localVariableExpr(0), localVariableExpr(0),

View File

@ -111,7 +111,7 @@ func Compile(p *shaderir.Program, vertex, fragment string) (shader string) {
} }
lines[len(lines)-1] += ") {" lines[len(lines)-1] += ") {"
lines = append(lines, fmt.Sprintf("\tVaryings %s = {};", vertexOut)) 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)...)
if last := fmt.Sprintf("\treturn %s;", vertexOut); lines[len(lines)-1] != last { if last := fmt.Sprintf("\treturn %s;", vertexOut); lines[len(lines)-1] != last {
lines = append(lines, last) lines = append(lines, last)
} }
@ -133,7 +133,7 @@ func Compile(p *shaderir.Program, vertex, fragment string) (shader string) {
} }
lines[len(lines)-1] += ") {" lines[len(lines)-1] += ") {"
lines = append(lines, fmt.Sprintf("\tfloat4 %s = float4(0);", fragmentOut)) 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)...)
if last := fmt.Sprintf("\treturn %s;", fragmentOut); lines[len(lines)-1] != last { if last := fmt.Sprintf("\treturn %s;", fragmentOut); lines[len(lines)-1] != last {
lines = append(lines, last) lines = append(lines, last)
} }
@ -245,7 +245,7 @@ func (c *compileContext) metalFunc(p *shaderir.Program, f *shaderir.Func, protot
return lines return lines
} }
lines = append(lines, fmt.Sprintf("%s {", sig)) 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)...)
lines = append(lines, "}") lines = append(lines, "}")
return lines return lines
@ -311,7 +311,7 @@ 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 { func (c *compileContext) metalBlock(p *shaderir.Program, topBlock, block *shaderir.Block, level int) []string {
if block == nil { if block == nil {
return nil return nil
} }
@ -319,12 +319,11 @@ func (c *compileContext) metalBlock(p *shaderir.Program, topBlock, block *shader
idt := strings.Repeat("\t", level+1) idt := strings.Repeat("\t", level+1)
var lines []string var lines []string
for _, t := range block.LocalVars { for i, t := range block.LocalVars {
// The type is None e.g., when the variable is a for-loop counter. // The type is None e.g., when the variable is a for-loop counter.
if t.Main != shaderir.None { if t.Main != shaderir.None {
lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, c.metalVarDecl(p, &t, fmt.Sprintf("l%d", localVarIndex), false, false), c.metalVarInit(p, &t))) lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, c.metalVarDecl(p, &t, fmt.Sprintf("l%d", block.LocalVarIndexOffset+i), false, false), c.metalVarInit(p, &t)))
} }
localVarIndex++
} }
var metalExpr func(e *shaderir.Expr) string var metalExpr func(e *shaderir.Expr) string
@ -395,16 +394,16 @@ func (c *compileContext) metalBlock(p *shaderir.Program, topBlock, block *shader
lines = append(lines, fmt.Sprintf("%s%s;", idt, metalExpr(&s.Exprs[0]))) lines = append(lines, fmt.Sprintf("%s%s;", idt, metalExpr(&s.Exprs[0])))
case shaderir.BlockStmt: case shaderir.BlockStmt:
lines = append(lines, idt+"{") 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)...)
lines = append(lines, idt+"}") lines = append(lines, idt+"}")
case shaderir.Assign: case shaderir.Assign:
lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, metalExpr(&s.Exprs[0]), metalExpr(&s.Exprs[1]))) lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, metalExpr(&s.Exprs[0]), metalExpr(&s.Exprs[1])))
case shaderir.If: case shaderir.If:
lines = append(lines, fmt.Sprintf("%sif (%s) {", idt, metalExpr(&s.Exprs[0]))) 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)...)
if len(s.Blocks) > 1 { if len(s.Blocks) > 1 {
lines = append(lines, fmt.Sprintf("%s} else {", idt)) 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)...)
} }
lines = append(lines, fmt.Sprintf("%s}", idt)) lines = append(lines, fmt.Sprintf("%s}", idt))
case shaderir.For: case shaderir.For:
@ -447,7 +446,7 @@ func (c *compileContext) metalBlock(p *shaderir.Program, topBlock, block *shader
end := constantToNumberLiteral(ct, s.ForEnd) end := constantToNumberLiteral(ct, s.ForEnd)
ts := typeString(&t, false, false) 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, 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)...)
lines = append(lines, fmt.Sprintf("%s}", idt)) lines = append(lines, fmt.Sprintf("%s}", idt))
case shaderir.Continue: case shaderir.Continue:
lines = append(lines, idt+"continue;") lines = append(lines, idt+"continue;")

View File

@ -57,8 +57,9 @@ type FragmentFunc struct {
} }
type Block struct { type Block struct {
LocalVars []Type LocalVars []Type
Stmts []Stmt LocalVarIndexOffset int
Stmts []Stmt
} }
type Stmt struct { type Stmt struct {

View File

@ -174,6 +174,7 @@ var (
} }
defaultVertexFunc = shaderir.VertexFunc{ defaultVertexFunc = shaderir.VertexFunc{
Block: &shaderir.Block{ Block: &shaderir.Block{
LocalVarIndexOffset: 0,
Stmts: []shaderir.Stmt{ Stmts: []shaderir.Stmt{
{ {
Type: shaderir.Assign, Type: shaderir.Assign,
@ -280,6 +281,7 @@ func ShaderProgramFill(r, g, b, a byte) shaderir.Program {
p := defaultProgram() p := defaultProgram()
p.FragmentFunc = shaderir.FragmentFunc{ p.FragmentFunc = shaderir.FragmentFunc{
Block: &shaderir.Block{ Block: &shaderir.Block{
LocalVarIndexOffset: 0,
Stmts: []shaderir.Stmt{ Stmts: []shaderir.Stmt{
{ {
Type: shaderir.Assign, Type: shaderir.Assign,
@ -417,7 +419,8 @@ func ShaderProgramImages(imageNum int) shaderir.Program {
LocalVars: []shaderir.Type{ LocalVars: []shaderir.Type{
{Main: shaderir.Vec4}, {Main: shaderir.Vec4},
}, },
Stmts: stmts, LocalVarIndexOffset: 0,
Stmts: stmts,
}, },
} }