Add shaderir

This commit is contained in:
Hajime Hoshi 2020-05-12 00:19:42 +09:00
parent 6d182c4b55
commit a5d570a7a8
4 changed files with 369 additions and 0 deletions

71
internal/shaderir/glsl.go Normal file
View File

@ -0,0 +1,71 @@
// Copyright 2020 The Ebiten 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 shaderir
import (
"fmt"
"strings"
)
func (p *Program) structName(t *Type) string {
if t.MainType != Struct {
panic("shaderir: the given type at structName must be a struct")
}
s := t.serialize()
if n, ok := p.structNames[s]; ok {
return n
}
n := fmt.Sprintf("S%d", len(p.structNames))
p.structNames[s] = n
p.structTypes = append(p.structTypes, *t)
return n
}
func (p *Program) Glsl() string {
p.structNames = map[string]string{}
p.structTypes = nil
var lines []string
for _, u := range p.Uniforms {
lines = append(lines, fmt.Sprintf("uniform %s;", p.glslVarDecl(&u.Type, u.Name)))
}
var stLines []string
for i, t := range p.structTypes {
stLines = append(stLines, fmt.Sprintf("struct S%d {", i))
for j, st := range t.SubTypes {
stLines = append(stLines, fmt.Sprintf("\t%s;", p.glslVarDecl(&st, fmt.Sprintf("M%d", j))))
}
stLines = append(stLines, "};")
}
lines = append(stLines, lines...)
return strings.Join(lines, "\n") + "\n"
}
func (p *Program) glslVarDecl(t *Type, varname string) string {
switch t.MainType {
case None:
return "?(none)"
case Image2D:
panic("not implemented")
case Array:
return fmt.Sprintf("")
case Struct:
return fmt.Sprintf("%s %s", p.structName(t), varname)
default:
return fmt.Sprintf("%s %s", t.MainType.Glsl(), varname)
}
}

View File

@ -0,0 +1,74 @@
// Copyright 2020 The Ebiten 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 shaderir_test
import (
"testing"
. "github.com/hajimehoshi/ebiten/internal/shaderir"
)
func TestOutput(t *testing.T) {
tests := []struct {
Name string
Program Program
Glsl string
}{
{
Name: "Empty",
Program: Program{},
Glsl: ``,
},
{
Name: "Uniform",
Program: Program{
Uniforms: []Variable{
{
Name: "U1",
Type: Type{MainType: Float},
},
},
},
Glsl: `uniform float U1;`,
},
{
Name: "UniformStruct",
Program: Program{
Uniforms: []Variable{
{
Name: "U1",
Type: Type{
MainType: Struct,
SubTypes: []Type{
{MainType: Float},
},
},
},
},
},
Glsl: `struct S0 {
float M0;
};
uniform S0 U1;`,
},
}
for _, tc := range tests {
got := tc.Program.Glsl()
want := tc.Glsl + "\n"
if got != want {
t.Errorf("%s: got: %s, want: %s", tc.Name, got, want)
}
}
}

View File

@ -0,0 +1,111 @@
// Copyright 2020 The Ebiten 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 shaderir
type Program struct {
Uniforms []Variable
Attributes []Variable
Varyings []Variable
Funcs []Func
VertexEntry string
FragmentEntry string
structNames map[string]string
structTypes []Type
}
type Variable struct {
Name string
Type Type
}
type Func struct {
Name string
InParams []Type
OutParams []Type
Block Block
}
type Block struct {
LocalVars []Type
Stmts []Stmt
}
type Stmt struct {
Type StmtType
Exprs []Expr
Condition Expr
ElseStmts []Expr
ForInit Expr
ForRest Expr
}
type StmtType int
const (
ExprStmt StmtType = iota
Assign
If
For
Continue
Break
Return
Discard
)
type Expr struct {
Type ExprType
Exprs []Expr
Value string
Op Op
}
type ExprType int
const (
Literal ExprType = iota
Ident
LocalVarID
Unary
Binary
Call
Selector
Index
)
type Op string
const (
Add Op = "+"
Sub Op = "-"
Neg Op = "!"
Mul Op = "*"
Div Op = "/"
Mod Op = "%"
LShift Op = "<<"
RShift Op = ">>"
LT Op = "<"
LE Op = "<="
GT Op = ">"
GE Op = ">="
Eq Op = "=="
NE Op = "!="
And Op = "&"
Xor Op = "^"
Or Op = "|"
AndAnd Op = "&&"
OrOr Op = "||"
Cond Op = "?:"
)

113
internal/shaderir/type.go Normal file
View File

@ -0,0 +1,113 @@
// Copyright 2020 The Ebiten 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 shaderir
import (
"fmt"
"strings"
)
type Type struct {
MainType BasicType
SubTypes []Type
Length int
}
func (t *Type) serialize() string {
switch t.MainType {
case None:
return "none"
case Bool:
return "bool"
case Float:
return "float"
case Vec2:
return "vec2"
case Vec3:
return "vec3"
case Vec4:
return "vec4"
case Mat2:
return "mat2"
case Mat3:
return "mat3"
case Mat4:
return "mat4"
case Image2D:
return "image2d"
case Array:
return fmt.Sprintf("%s[%d]", t.SubTypes[0].serialize(), t.Length)
case Struct:
str := "struct{"
sub := make([]string, 0, len(t.SubTypes))
for _, st := range t.SubTypes {
sub = append(sub, st.serialize())
}
str += strings.Join(sub, ",")
str += "}"
return str
default:
return fmt.Sprintf("?(unknown type: %d)", t)
}
}
type BasicType int
const (
None BasicType = iota
Bool
Float
Vec2
Vec3
Vec4
Mat2
Mat3
Mat4
Image2D
Array
Struct
)
func (t BasicType) Glsl() string {
switch t {
case None:
return "?(none)"
case Bool:
return "bool"
case Float:
return "float"
case Vec2:
return "vec2"
case Vec3:
return "vec3"
case Vec4:
return "vec4"
case Mat2:
return "mat2"
case Mat3:
return "mat3"
case Mat4:
return "mat4"
case Image2D:
return "?(image2d)"
case Array:
// First-class array is not available on GLSL ES 2.
return "?(array)"
case Struct:
return "?(struct)"
default:
return fmt.Sprintf("?(unknown type: %d)", t)
}
}