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 (
|
2020-06-20 18:22:30 +02:00
|
|
|
"go/constant"
|
2020-06-20 16:26:29 +02:00
|
|
|
"go/token"
|
2020-08-08 12:08:07 +02:00
|
|
|
"strings"
|
2020-06-20 16:26:29 +02:00
|
|
|
)
|
|
|
|
|
2020-05-11 17:19:42 +02:00
|
|
|
type Program struct {
|
2020-09-05 20:41:13 +02:00
|
|
|
UniformNames []string
|
2020-05-16 15:18:58 +02:00
|
|
|
Uniforms []Type
|
2020-07-05 20:36:15 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-05-24 10:14:37 +02:00
|
|
|
// FragmentFunc takes pseudo params, and the number is len(varyings) + 2.
|
2020-06-02 19:01:50 +02:00
|
|
|
// If index == 0, the param represents the coordinate of the fragment (gl_FragCoord in GLSL).
|
|
|
|
// If index == len(varyings), the param represents (index-1)th verying variable.
|
2020-05-23 19:07:57 +02:00
|
|
|
// If index == len(varyings)+1, the param is an out-param representing the color of the pixel (gl_FragColor in GLSL).
|
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 {
|
2020-08-09 16:40:41 +02:00
|
|
|
LocalVars []Type
|
|
|
|
LocalVarIndexOffset int
|
|
|
|
Stmts []Stmt
|
2020-05-11 17:19:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type Stmt struct {
|
2020-07-12 14:53:18 +02:00
|
|
|
Type StmtType
|
|
|
|
Exprs []Expr
|
2020-08-09 08:55:59 +02:00
|
|
|
Blocks []*Block
|
2020-07-12 15:22:22 +02:00
|
|
|
ForVarType Type
|
2020-07-12 14:53:18 +02:00
|
|
|
ForVarIndex int
|
2020-07-12 15:22:22 +02:00
|
|
|
ForInit constant.Value
|
|
|
|
ForEnd constant.Value
|
2020-07-12 14:53:18 +02:00
|
|
|
ForOp Op
|
2020-07-12 15:22:22 +02:00
|
|
|
ForDelta constant.Value
|
2020-09-06 17:13:46 +02:00
|
|
|
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
|
2020-09-06 17:13:46 +02:00
|
|
|
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
|
|
|
|
)
|
|
|
|
|
2020-06-20 18:22:30 +02:00
|
|
|
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
|
2020-06-20 18:22:30 +02:00
|
|
|
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 (
|
2020-09-02 18:15:37 +02:00
|
|
|
Blank ExprType = iota
|
|
|
|
NumberExpr
|
2020-05-16 21:28:03 +02:00
|
|
|
UniformVariable
|
2020-07-05 20:36:15 +02:00
|
|
|
TextureVariable
|
2020-05-16 21:28:03 +02:00
|
|
|
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
|
|
|
|
)
|
|
|
|
|
2022-03-13 08:20:01 +01:00
|
|
|
type Op int
|
2020-05-11 17:19:42 +02:00
|
|
|
|
|
|
|
const (
|
2022-03-13 08:20:01 +01:00
|
|
|
Add Op = iota
|
|
|
|
Sub
|
|
|
|
NotOp
|
2022-03-13 11:17:44 +01:00
|
|
|
ComponentWiseMul
|
|
|
|
MatrixMul
|
2022-03-13 08:20:01 +01:00
|
|
|
Div
|
|
|
|
ModOp
|
|
|
|
LeftShift
|
|
|
|
RightShift
|
|
|
|
LessThanOp
|
|
|
|
LessThanEqualOp
|
|
|
|
GreaterThanOp
|
|
|
|
GreaterThanEqualOp
|
|
|
|
EqualOp
|
|
|
|
NotEqualOp
|
2022-07-08 19:26:33 +02:00
|
|
|
VectorEqualOp
|
|
|
|
VectorNotEqualOp
|
2022-03-13 08:20:01 +01:00
|
|
|
And
|
|
|
|
Xor
|
|
|
|
Or
|
|
|
|
AndAnd
|
|
|
|
OrOr
|
2020-05-16 17:25:31 +02:00
|
|
|
)
|
|
|
|
|
2022-03-13 11:17:44 +01: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:
|
2022-03-13 11:17:44 +01:00
|
|
|
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:
|
2022-07-08 19:26:33 +02:00
|
|
|
if lhs.IsVector() || rhs.IsVector() {
|
|
|
|
return VectorEqualOp, true
|
|
|
|
}
|
2020-06-20 16:26:29 +02:00
|
|
|
return EqualOp, true
|
|
|
|
case token.NEQ:
|
2022-07-08 19:26:33 +02:00
|
|
|
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
|
|
|
|
}
|
2022-03-13 08:20:01 +01:00
|
|
|
return 0, false
|
2020-06-20 16:26:29 +02:00
|
|
|
}
|
|
|
|
|
2020-05-16 17:25:31 +02:00
|
|
|
type BuiltinFunc string
|
|
|
|
|
|
|
|
const (
|
2020-08-15 19:07:36 +02:00
|
|
|
Len BuiltinFunc = "len"
|
2020-10-17 16:36:07 +02:00
|
|
|
Cap BuiltinFunc = "cap"
|
2020-08-11 16:04:49 +02:00
|
|
|
BoolF BuiltinFunc = "bool"
|
|
|
|
IntF BuiltinFunc = "int"
|
|
|
|
FloatF BuiltinFunc = "float"
|
2020-08-04 18:41:06 +02:00
|
|
|
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"
|
2020-09-21 21:29:31 +02:00
|
|
|
Atan2 BuiltinFunc = "atan2"
|
2020-08-04 18:41:06 +02:00
|
|
|
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"
|
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) {
|
2020-08-15 19:07:36 +02:00
|
|
|
case Len,
|
2020-10-17 16:36:07 +02:00
|
|
|
Cap,
|
2020-08-15 19:07:36 +02:00
|
|
|
BoolF,
|
2020-08-11 16:04:49 +02:00
|
|
|
IntF,
|
|
|
|
FloatF,
|
|
|
|
Vec2F,
|
2020-05-31 11:11:55 +02:00
|
|
|
Vec3F,
|
|
|
|
Vec4F,
|
|
|
|
Mat2F,
|
|
|
|
Mat3F,
|
|
|
|
Mat4F,
|
|
|
|
Sin,
|
|
|
|
Cos,
|
|
|
|
Tan,
|
|
|
|
Asin,
|
|
|
|
Acos,
|
|
|
|
Atan,
|
2020-09-21 21:29:31 +02:00
|
|
|
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,
|
2020-07-11 14:50:07 +02:00
|
|
|
Texture2DF,
|
|
|
|
Dfdx,
|
|
|
|
Dfdy,
|
|
|
|
Fwidth:
|
2020-05-31 11:11:55 +02:00
|
|
|
return BuiltinFunc(str), true
|
|
|
|
}
|
|
|
|
return "", false
|
|
|
|
}
|
2020-08-08 12:08:07 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2021-07-09 11:11:56 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|