ebiten/internal/shaderir/program.go

415 lines
8.5 KiB
Go
Raw Normal View History

2020-05-11 17:19:42 +02:00
// 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.
2020-05-16 16:42:32 +02:00
// Package shaderir offers intermediate representation for shader programs.
2020-05-11 17:19:42 +02:00
package shaderir
2020-06-20 16:26:29 +02:00
import (
"go/constant"
2020-06-20 16:26:29 +02:00
"go/token"
"strings"
2020-06-20 16:26:29 +02:00
)
2020-05-11 17:19:42 +02:00
type Program struct {
UniformNames []string
2020-05-16 15:18:58 +02:00
Uniforms []Type
TextureNum int
2020-05-16 15:18:58 +02:00
Attributes []Type
Varyings []Type
Funcs []Func
VertexFunc VertexFunc
FragmentFunc FragmentFunc
2020-05-11 17:19:42 +02:00
}
type Func struct {
2020-06-07 11:57:46 +02:00
Index int
InParams []Type
OutParams []Type
Return Type
2020-08-09 08:55:59 +02:00
Block *Block
2020-05-11 17:19:42 +02:00
}
2020-05-16 15:18:58 +02:00
// VertexFunc takes pseudo params, and the number if len(attributes) + len(varyings) + 1.
2020-06-02 17:46:52 +02:00
// If 0 <= index < len(attributes), the params are in-params and represent attribute variables.
// If index == len(attributes), the param is an out-param and repesents the position in vec4 (gl_Position in GLSL)
// If len(attributes) + 1 <= index < len(attributes) + len(varyings) + 1, the params are out-params and represent
// varying variables.
2020-05-16 15:18:58 +02:00
type VertexFunc struct {
2020-08-09 08:55:59 +02:00
Block *Block
2020-05-16 15:18:58 +02:00
}
// FragmentFunc takes pseudo params, and the number is len(varyings) + 2.
// If index == 0, the param represents the coordinate of the fragment (gl_FragCoord in GLSL).
2022-08-17 10:43:59 +02:00
// If 0 < index <= len(varyings), the param represents (index-1)th verying variable.
2020-05-16 15:18:58 +02:00
type FragmentFunc struct {
2020-08-09 08:55:59 +02:00
Block *Block
2020-05-16 15:18:58 +02:00
}
2020-05-11 17:19:42 +02:00
type Block struct {
LocalVars []Type
LocalVarIndexOffset int
Stmts []Stmt
2020-05-11 17:19:42 +02:00
}
type Stmt struct {
Type StmtType
Exprs []Expr
2020-08-09 08:55:59 +02:00
Blocks []*Block
ForVarType Type
ForVarIndex int
ForInit constant.Value
ForEnd constant.Value
ForOp Op
ForDelta constant.Value
InitIndex int
2020-05-11 17:19:42 +02:00
}
type StmtType int
const (
ExprStmt StmtType = iota
2020-05-13 18:45:33 +02:00
BlockStmt
2020-05-11 17:19:42 +02:00
Assign
Init
2020-05-11 17:19:42 +02:00
If
For
Continue
Break
2020-05-13 20:14:39 +02:00
Return
2020-05-11 17:19:42 +02:00
Discard
)
type ConstType int
const (
ConstTypeNone ConstType = iota
ConstTypeBool
ConstTypeInt
ConstTypeFloat
)
2020-05-11 17:19:42 +02:00
type Expr struct {
2020-05-16 17:25:31 +02:00
Type ExprType
Exprs []Expr
Const constant.Value
ConstType ConstType
2020-05-16 17:25:31 +02:00
BuiltinFunc BuiltinFunc
2020-05-16 20:00:57 +02:00
Swizzling string
Index int
2020-05-16 17:25:31 +02:00
Op Op
2020-05-11 17:19:42 +02:00
}
type ExprType int
const (
Blank ExprType = iota
NumberExpr
UniformVariable
TextureVariable
LocalVariable
StructMember
2020-05-16 17:25:31 +02:00
BuiltinFuncExpr
2020-05-16 19:24:35 +02:00
SwizzlingExpr
2020-05-16 20:00:57 +02:00
FunctionExpr
2020-05-11 17:19:42 +02:00
Unary
Binary
2020-05-16 10:22:17 +02:00
Selection
2020-05-11 17:19:42 +02:00
Call
2020-05-16 10:22:17 +02:00
FieldSelector
2020-05-11 17:19:42 +02:00
Index
)
type Op int
2020-05-11 17:19:42 +02:00
const (
Add Op = iota
Sub
NotOp
ComponentWiseMul
MatrixMul
Div
ModOp
LeftShift
RightShift
LessThanOp
LessThanEqualOp
GreaterThanOp
GreaterThanEqualOp
EqualOp
NotEqualOp
VectorEqualOp
VectorNotEqualOp
And
Xor
Or
AndAnd
OrOr
2020-05-16 17:25:31 +02:00
)
func OpFromToken(t token.Token, lhs, rhs Type) (Op, bool) {
2020-06-20 16:26:29 +02:00
switch t {
case token.ADD:
return Add, true
case token.SUB:
return Sub, true
case token.NOT:
return NotOp, true
case token.MUL:
if lhs.IsMatrix() || rhs.IsMatrix() {
return MatrixMul, true
}
return ComponentWiseMul, true
2020-06-20 16:26:29 +02:00
case token.QUO:
return Div, true
case token.REM:
return ModOp, true
case token.SHL:
return LeftShift, true
case token.SHR:
return RightShift, true
case token.LSS:
return LessThanOp, true
case token.LEQ:
return LessThanEqualOp, true
case token.GTR:
return GreaterThanOp, true
case token.GEQ:
return GreaterThanEqualOp, true
case token.EQL:
if lhs.IsVector() || rhs.IsVector() {
return VectorEqualOp, true
}
2020-06-20 16:26:29 +02:00
return EqualOp, true
case token.NEQ:
if lhs.IsVector() || rhs.IsVector() {
return VectorNotEqualOp, true
}
2020-06-20 16:26:29 +02:00
return NotEqualOp, true
case token.AND:
return And, true
case token.XOR:
return Xor, true
case token.OR:
return Or, true
case token.LAND:
return AndAnd, true
case token.LOR:
return OrOr, true
}
return 0, false
2020-06-20 16:26:29 +02:00
}
2020-05-16 17:25:31 +02:00
type BuiltinFunc string
const (
Len BuiltinFunc = "len"
Cap BuiltinFunc = "cap"
BoolF BuiltinFunc = "bool"
IntF BuiltinFunc = "int"
FloatF BuiltinFunc = "float"
Vec2F BuiltinFunc = "vec2"
Vec3F BuiltinFunc = "vec3"
Vec4F BuiltinFunc = "vec4"
Mat2F BuiltinFunc = "mat2"
Mat3F BuiltinFunc = "mat3"
Mat4F BuiltinFunc = "mat4"
Radians BuiltinFunc = "radians"
Degrees BuiltinFunc = "degrees"
Sin BuiltinFunc = "sin"
Cos BuiltinFunc = "cos"
Tan BuiltinFunc = "tan"
Asin BuiltinFunc = "asin"
Acos BuiltinFunc = "acos"
Atan BuiltinFunc = "atan"
Atan2 BuiltinFunc = "atan2"
Pow BuiltinFunc = "pow"
Exp BuiltinFunc = "exp"
Log BuiltinFunc = "log"
Exp2 BuiltinFunc = "exp2"
Log2 BuiltinFunc = "log2"
Sqrt BuiltinFunc = "sqrt"
Inversesqrt BuiltinFunc = "inversesqrt"
Abs BuiltinFunc = "abs"
Sign BuiltinFunc = "sign"
Floor BuiltinFunc = "floor"
Ceil BuiltinFunc = "ceil"
Fract BuiltinFunc = "fract"
Mod BuiltinFunc = "mod"
Min BuiltinFunc = "min"
Max BuiltinFunc = "max"
Clamp BuiltinFunc = "clamp"
Mix BuiltinFunc = "mix"
Step BuiltinFunc = "step"
Smoothstep BuiltinFunc = "smoothstep"
Length BuiltinFunc = "length"
Distance BuiltinFunc = "distance"
Dot BuiltinFunc = "dot"
Cross BuiltinFunc = "cross"
Normalize BuiltinFunc = "normalize"
Faceforward BuiltinFunc = "faceforward"
Reflect BuiltinFunc = "reflect"
Transpose BuiltinFunc = "transpose"
Texture2DF BuiltinFunc = "texture2D"
Dfdx BuiltinFunc = "dfdx"
Dfdy BuiltinFunc = "dfdy"
Fwidth BuiltinFunc = "fwidth"
DiscardF BuiltinFunc = "discard"
2020-05-11 17:19:42 +02:00
)
2020-05-31 11:11:55 +02:00
func ParseBuiltinFunc(str string) (BuiltinFunc, bool) {
switch BuiltinFunc(str) {
case Len,
Cap,
BoolF,
IntF,
FloatF,
Vec2F,
2020-05-31 11:11:55 +02:00
Vec3F,
Vec4F,
Mat2F,
Mat3F,
Mat4F,
Sin,
Cos,
Tan,
Asin,
Acos,
Atan,
Atan2,
2020-05-31 11:11:55 +02:00
Pow,
Exp,
Log,
Exp2,
Log2,
Sqrt,
Inversesqrt,
Abs,
Sign,
Floor,
Ceil,
Fract,
Mod,
Min,
Max,
Clamp,
Mix,
Step,
Smoothstep,
Length,
Distance,
Dot,
Cross,
Normalize,
Faceforward,
Reflect,
Transpose,
Texture2DF,
Dfdx,
Dfdy,
Fwidth,
DiscardF:
2020-05-31 11:11:55 +02:00
return BuiltinFunc(str), true
}
return "", false
}
func IsValidSwizzling(s string) bool {
if len(s) < 1 || 4 < len(s) {
return false
}
const (
xyzw = "xyzw"
rgba = "rgba"
strq = "strq"
)
switch {
case strings.IndexByte(xyzw, s[0]) >= 0:
for _, c := range s {
if strings.IndexRune(xyzw, c) == -1 {
return false
}
}
return true
case strings.IndexByte(rgba, s[0]) >= 0:
for _, c := range s {
if strings.IndexRune(rgba, c) == -1 {
return false
}
}
return true
case strings.IndexByte(strq, s[0]) >= 0:
for _, c := range s {
if strings.IndexRune(strq, c) == -1 {
return false
}
}
return true
}
return false
}
func (p *Program) ReferredFuncIndicesInVertexShader() []int {
return p.referredFuncIndicesInBlockEntryPoint(p.VertexFunc.Block)
}
func (p *Program) ReferredFuncIndicesInFragmentShader() []int {
return p.referredFuncIndicesInBlockEntryPoint(p.FragmentFunc.Block)
}
func (p *Program) referredFuncIndicesInBlockEntryPoint(b *Block) []int {
indexToFunc := map[int]*Func{}
for _, f := range p.Funcs {
f := f
indexToFunc[f.Index] = &f
}
visited := map[int]struct{}{}
return referredFuncIndicesInBlock(b, indexToFunc, visited)
}
func referredFuncIndicesInBlock(b *Block, indexToFunc map[int]*Func, visited map[int]struct{}) []int {
if b == nil {
return nil
}
var fs []int
for _, s := range b.Stmts {
for _, e := range s.Exprs {
fs = append(fs, referredFuncIndicesInExpr(&e, indexToFunc, visited)...)
}
for _, bb := range s.Blocks {
fs = append(fs, referredFuncIndicesInBlock(bb, indexToFunc, visited)...)
}
}
return fs
}
func referredFuncIndicesInExpr(e *Expr, indexToFunc map[int]*Func, visited map[int]struct{}) []int {
var fs []int
if e.Type == FunctionExpr {
if _, ok := visited[e.Index]; !ok {
fs = append(fs, e.Index)
visited[e.Index] = struct{}{}
fs = append(fs, referredFuncIndicesInBlock(indexToFunc[e.Index].Block, indexToFunc, visited)...)
}
}
for _, ee := range e.Exprs {
fs = append(fs, referredFuncIndicesInExpr(&ee, indexToFunc, visited)...)
}
return fs
}