zorldo

Goofing around with Ebiten
git clone git://bsandro.tech/zorldo
Log | Files | Refs | README

program.go (8801B)


      1 // Copyright 2020 The Ebiten Authors
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // Package shaderir offers intermediate representation for shader programs.
     16 package shaderir
     17 
     18 import (
     19 	"go/constant"
     20 	"go/token"
     21 	"strings"
     22 )
     23 
     24 type Program struct {
     25 	UniformNames []string
     26 	Uniforms     []Type
     27 	TextureNum   int
     28 	Attributes   []Type
     29 	Varyings     []Type
     30 	Funcs        []Func
     31 	VertexFunc   VertexFunc
     32 	FragmentFunc FragmentFunc
     33 }
     34 
     35 type Func struct {
     36 	Index     int
     37 	InParams  []Type
     38 	OutParams []Type
     39 	Return    Type
     40 	Block     *Block
     41 }
     42 
     43 // VertexFunc takes pseudo params, and the number if len(attributes) + len(varyings) + 1.
     44 // If 0 <= index < len(attributes), the params are in-params and represent attribute variables.
     45 // If index == len(attributes), the param is an out-param and repesents the position in vec4 (gl_Position in GLSL)
     46 // If len(attributes) + 1 <= index < len(attributes) + len(varyings) + 1, the params are out-params and represent
     47 // varying variables.
     48 type VertexFunc struct {
     49 	Block *Block
     50 }
     51 
     52 // FragmentFunc takes pseudo params, and the number is len(varyings) + 2.
     53 // If index == 0, the param represents the coordinate of the fragment (gl_FragCoord in GLSL).
     54 // If index == len(varyings), the param represents (index-1)th verying variable.
     55 // If index == len(varyings)+1, the param is an out-param representing the color of the pixel (gl_FragColor in GLSL).
     56 type FragmentFunc struct {
     57 	Block *Block
     58 }
     59 
     60 type Block struct {
     61 	LocalVars           []Type
     62 	LocalVarIndexOffset int
     63 	Stmts               []Stmt
     64 }
     65 
     66 type Stmt struct {
     67 	Type        StmtType
     68 	Exprs       []Expr
     69 	Blocks      []*Block
     70 	ForVarType  Type
     71 	ForVarIndex int
     72 	ForInit     constant.Value
     73 	ForEnd      constant.Value
     74 	ForOp       Op
     75 	ForDelta    constant.Value
     76 	InitIndex   int
     77 }
     78 
     79 type StmtType int
     80 
     81 const (
     82 	ExprStmt StmtType = iota
     83 	BlockStmt
     84 	Assign
     85 	Init
     86 	If
     87 	For
     88 	Continue
     89 	Break
     90 	Return
     91 	Discard
     92 )
     93 
     94 type ConstType int
     95 
     96 const (
     97 	ConstTypeNone ConstType = iota
     98 	ConstTypeBool
     99 	ConstTypeInt
    100 	ConstTypeFloat
    101 )
    102 
    103 type Expr struct {
    104 	Type        ExprType
    105 	Exprs       []Expr
    106 	Const       constant.Value
    107 	ConstType   ConstType
    108 	BuiltinFunc BuiltinFunc
    109 	Swizzling   string
    110 	Index       int
    111 	Op          Op
    112 }
    113 
    114 type ExprType int
    115 
    116 const (
    117 	Blank ExprType = iota
    118 	NumberExpr
    119 	UniformVariable
    120 	TextureVariable
    121 	LocalVariable
    122 	StructMember
    123 	BuiltinFuncExpr
    124 	SwizzlingExpr
    125 	FunctionExpr
    126 	Unary
    127 	Binary
    128 	Selection
    129 	Call
    130 	FieldSelector
    131 	Index
    132 )
    133 
    134 type Op string
    135 
    136 const (
    137 	Add                Op = "+"
    138 	Sub                Op = "-"
    139 	NotOp              Op = "!"
    140 	Mul                Op = "*"
    141 	Div                Op = "/"
    142 	ModOp              Op = "%"
    143 	LeftShift          Op = "<<"
    144 	RightShift         Op = ">>"
    145 	LessThanOp         Op = "<"
    146 	LessThanEqualOp    Op = "<="
    147 	GreaterThanOp      Op = ">"
    148 	GreaterThanEqualOp Op = ">="
    149 	EqualOp            Op = "=="
    150 	NotEqualOp         Op = "!="
    151 	And                Op = "&"
    152 	Xor                Op = "^"
    153 	Or                 Op = "|"
    154 	AndAnd             Op = "&&"
    155 	OrOr               Op = "||"
    156 )
    157 
    158 func OpFromToken(t token.Token) (Op, bool) {
    159 	switch t {
    160 	case token.ADD:
    161 		return Add, true
    162 	case token.SUB:
    163 		return Sub, true
    164 	case token.NOT:
    165 		return NotOp, true
    166 	case token.MUL:
    167 		return Mul, true
    168 	case token.QUO:
    169 		return Div, true
    170 	case token.REM:
    171 		return ModOp, true
    172 	case token.SHL:
    173 		return LeftShift, true
    174 	case token.SHR:
    175 		return RightShift, true
    176 	case token.LSS:
    177 		return LessThanOp, true
    178 	case token.LEQ:
    179 		return LessThanEqualOp, true
    180 	case token.GTR:
    181 		return GreaterThanOp, true
    182 	case token.GEQ:
    183 		return GreaterThanEqualOp, true
    184 	case token.EQL:
    185 		return EqualOp, true
    186 	case token.NEQ:
    187 		return NotEqualOp, true
    188 	case token.AND:
    189 		return And, true
    190 	case token.XOR:
    191 		return Xor, true
    192 	case token.OR:
    193 		return Or, true
    194 	case token.LAND:
    195 		return AndAnd, true
    196 	case token.LOR:
    197 		return OrOr, true
    198 	}
    199 	return "", false
    200 }
    201 
    202 type BuiltinFunc string
    203 
    204 const (
    205 	Len         BuiltinFunc = "len"
    206 	Cap         BuiltinFunc = "cap"
    207 	BoolF       BuiltinFunc = "bool"
    208 	IntF        BuiltinFunc = "int"
    209 	FloatF      BuiltinFunc = "float"
    210 	Vec2F       BuiltinFunc = "vec2"
    211 	Vec3F       BuiltinFunc = "vec3"
    212 	Vec4F       BuiltinFunc = "vec4"
    213 	Mat2F       BuiltinFunc = "mat2"
    214 	Mat3F       BuiltinFunc = "mat3"
    215 	Mat4F       BuiltinFunc = "mat4"
    216 	Radians     BuiltinFunc = "radians"
    217 	Degrees     BuiltinFunc = "degrees"
    218 	Sin         BuiltinFunc = "sin"
    219 	Cos         BuiltinFunc = "cos"
    220 	Tan         BuiltinFunc = "tan"
    221 	Asin        BuiltinFunc = "asin"
    222 	Acos        BuiltinFunc = "acos"
    223 	Atan        BuiltinFunc = "atan"
    224 	Atan2       BuiltinFunc = "atan2"
    225 	Pow         BuiltinFunc = "pow"
    226 	Exp         BuiltinFunc = "exp"
    227 	Log         BuiltinFunc = "log"
    228 	Exp2        BuiltinFunc = "exp2"
    229 	Log2        BuiltinFunc = "log2"
    230 	Sqrt        BuiltinFunc = "sqrt"
    231 	Inversesqrt BuiltinFunc = "inversesqrt"
    232 	Abs         BuiltinFunc = "abs"
    233 	Sign        BuiltinFunc = "sign"
    234 	Floor       BuiltinFunc = "floor"
    235 	Ceil        BuiltinFunc = "ceil"
    236 	Fract       BuiltinFunc = "fract"
    237 	Mod         BuiltinFunc = "mod"
    238 	Min         BuiltinFunc = "min"
    239 	Max         BuiltinFunc = "max"
    240 	Clamp       BuiltinFunc = "clamp"
    241 	Mix         BuiltinFunc = "mix"
    242 	Step        BuiltinFunc = "step"
    243 	Smoothstep  BuiltinFunc = "smoothstep"
    244 	Length      BuiltinFunc = "length"
    245 	Distance    BuiltinFunc = "distance"
    246 	Dot         BuiltinFunc = "dot"
    247 	Cross       BuiltinFunc = "cross"
    248 	Normalize   BuiltinFunc = "normalize"
    249 	Faceforward BuiltinFunc = "faceforward"
    250 	Reflect     BuiltinFunc = "reflect"
    251 	Transpose   BuiltinFunc = "transpose"
    252 	Texture2DF  BuiltinFunc = "texture2D"
    253 	Dfdx        BuiltinFunc = "dfdx"
    254 	Dfdy        BuiltinFunc = "dfdy"
    255 	Fwidth      BuiltinFunc = "fwidth"
    256 )
    257 
    258 func ParseBuiltinFunc(str string) (BuiltinFunc, bool) {
    259 	switch BuiltinFunc(str) {
    260 	case Len,
    261 		Cap,
    262 		BoolF,
    263 		IntF,
    264 		FloatF,
    265 		Vec2F,
    266 		Vec3F,
    267 		Vec4F,
    268 		Mat2F,
    269 		Mat3F,
    270 		Mat4F,
    271 		Sin,
    272 		Cos,
    273 		Tan,
    274 		Asin,
    275 		Acos,
    276 		Atan,
    277 		Atan2,
    278 		Pow,
    279 		Exp,
    280 		Log,
    281 		Exp2,
    282 		Log2,
    283 		Sqrt,
    284 		Inversesqrt,
    285 		Abs,
    286 		Sign,
    287 		Floor,
    288 		Ceil,
    289 		Fract,
    290 		Mod,
    291 		Min,
    292 		Max,
    293 		Clamp,
    294 		Mix,
    295 		Step,
    296 		Smoothstep,
    297 		Length,
    298 		Distance,
    299 		Dot,
    300 		Cross,
    301 		Normalize,
    302 		Faceforward,
    303 		Reflect,
    304 		Transpose,
    305 		Texture2DF,
    306 		Dfdx,
    307 		Dfdy,
    308 		Fwidth:
    309 		return BuiltinFunc(str), true
    310 	}
    311 	return "", false
    312 }
    313 
    314 func IsValidSwizzling(s string) bool {
    315 	if len(s) < 1 || 4 < len(s) {
    316 		return false
    317 	}
    318 
    319 	const (
    320 		xyzw = "xyzw"
    321 		rgba = "rgba"
    322 		strq = "strq"
    323 	)
    324 
    325 	switch {
    326 	case strings.IndexByte(xyzw, s[0]) >= 0:
    327 		for _, c := range s {
    328 			if strings.IndexRune(xyzw, c) == -1 {
    329 				return false
    330 			}
    331 		}
    332 		return true
    333 	case strings.IndexByte(rgba, s[0]) >= 0:
    334 		for _, c := range s {
    335 			if strings.IndexRune(rgba, c) == -1 {
    336 				return false
    337 			}
    338 		}
    339 		return true
    340 	case strings.IndexByte(strq, s[0]) >= 0:
    341 		for _, c := range s {
    342 			if strings.IndexRune(strq, c) == -1 {
    343 				return false
    344 			}
    345 		}
    346 		return true
    347 	}
    348 	return false
    349 }
    350 
    351 func (p *Program) ReferredFuncIndicesInVertexShader() []int {
    352 	return p.referredFuncIndicesInBlockEntryPoint(p.VertexFunc.Block)
    353 }
    354 
    355 func (p *Program) ReferredFuncIndicesInFragmentShader() []int {
    356 	return p.referredFuncIndicesInBlockEntryPoint(p.FragmentFunc.Block)
    357 }
    358 
    359 func (p *Program) referredFuncIndicesInBlockEntryPoint(b *Block) []int {
    360 	indexToFunc := map[int]*Func{}
    361 	for _, f := range p.Funcs {
    362 		f := f
    363 		indexToFunc[f.Index] = &f
    364 	}
    365 	visited := map[int]struct{}{}
    366 	return referredFuncIndicesInBlock(b, indexToFunc, visited)
    367 }
    368 
    369 func referredFuncIndicesInBlock(b *Block, indexToFunc map[int]*Func, visited map[int]struct{}) []int {
    370 	if b == nil {
    371 		return nil
    372 	}
    373 
    374 	var fs []int
    375 
    376 	for _, s := range b.Stmts {
    377 		for _, e := range s.Exprs {
    378 			fs = append(fs, referredFuncIndicesInExpr(&e, indexToFunc, visited)...)
    379 		}
    380 		for _, bb := range s.Blocks {
    381 			fs = append(fs, referredFuncIndicesInBlock(bb, indexToFunc, visited)...)
    382 		}
    383 	}
    384 	return fs
    385 }
    386 
    387 func referredFuncIndicesInExpr(e *Expr, indexToFunc map[int]*Func, visited map[int]struct{}) []int {
    388 	var fs []int
    389 
    390 	if e.Type == FunctionExpr {
    391 		if _, ok := visited[e.Index]; !ok {
    392 			fs = append(fs, e.Index)
    393 			visited[e.Index] = struct{}{}
    394 			fs = append(fs, referredFuncIndicesInBlock(indexToFunc[e.Index].Block, indexToFunc, visited)...)
    395 		}
    396 	}
    397 	for _, ee := range e.Exprs {
    398 		fs = append(fs, referredFuncIndicesInExpr(&ee, indexToFunc, visited)...)
    399 	}
    400 	return fs
    401 }