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 }