1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SKIASL_TYPE 9 #define SKIASL_TYPE 10 11 #include "include/private/SkSLModifiers.h" 12 #include "include/private/SkSLSymbol.h" 13 #include "src/sksl/SkSLPosition.h" 14 #include "src/sksl/SkSLUtil.h" 15 #include "src/sksl/spirv.h" 16 #include <algorithm> 17 #include <climits> 18 #include <vector> 19 #include <memory> 20 21 namespace SkSL { 22 23 class BuiltinTypes; 24 class Context; 25 26 struct CoercionCost { FreeCoercionCost27 static CoercionCost Free() { return { 0, 0, false }; } NormalCoercionCost28 static CoercionCost Normal(int cost) { return { cost, 0, false }; } NarrowingCoercionCost29 static CoercionCost Narrowing(int cost) { return { 0, cost, false }; } ImpossibleCoercionCost30 static CoercionCost Impossible() { return { 0, 0, true }; } 31 isPossibleCoercionCost32 bool isPossible(bool allowNarrowing) const { 33 return !fImpossible && (fNarrowingCost == 0 || allowNarrowing); 34 } 35 36 // Addition of two costs. Saturates at Impossible(). 37 CoercionCost operator+(CoercionCost rhs) const { 38 if (fImpossible || rhs.fImpossible) { 39 return Impossible(); 40 } 41 return { fNormalCost + rhs.fNormalCost, fNarrowingCost + rhs.fNarrowingCost, false }; 42 } 43 44 bool operator<(CoercionCost rhs) const { 45 return std::tie( fImpossible, fNarrowingCost, fNormalCost) < 46 std::tie(rhs.fImpossible, rhs.fNarrowingCost, rhs.fNormalCost); 47 } 48 49 int fNormalCost; 50 int fNarrowingCost; 51 bool fImpossible; 52 }; 53 54 /** 55 * Represents a type, such as int or float4. 56 */ 57 class Type final : public Symbol { 58 public: 59 static constexpr Kind kSymbolKind = Kind::kType; 60 61 struct Field { FieldField62 Field(Modifiers modifiers, StringFragment name, const Type* type) 63 : fModifiers(modifiers) 64 , fName(name) 65 , fType(std::move(type)) {} 66 descriptionField67 String description() const { 68 return fType->displayName() + " " + fName + ";"; 69 } 70 71 Modifiers fModifiers; 72 StringFragment fName; 73 const Type* fType; 74 }; 75 76 enum class TypeKind { 77 kArray, 78 kEnum, 79 kFragmentProcessor, 80 kGeneric, 81 kMatrix, 82 kOther, 83 kSampler, 84 kSeparateSampler, 85 kScalar, 86 kStruct, 87 kTexture, 88 kVector, 89 kVoid, 90 91 // Types that represent stages in the Skia pipeline 92 kColorFilter, 93 kShader, 94 }; 95 96 enum class NumberKind { 97 kFloat, 98 kSigned, 99 kUnsigned, 100 kBoolean, 101 kNonnumeric 102 }; 103 104 Type(const Type& other) = delete; 105 106 /** Creates an enum type. */ MakeEnumType(String name)107 static std::unique_ptr<Type> MakeEnumType(String name) { 108 return std::unique_ptr<Type>(new Type(std::move(name), "e", TypeKind::kEnum)); 109 } 110 111 /** Creates a struct type with the given fields. */ MakeStructType(int offset,String name,std::vector<Field> fields)112 static std::unique_ptr<Type> MakeStructType(int offset, String name, 113 std::vector<Field> fields) { 114 return std::unique_ptr<Type>(new Type(offset, std::move(name), std::move(fields))); 115 } 116 117 /** Creates an array type. */ 118 static constexpr int kUnsizedArray = -1; MakeArrayType(String name,const Type & componentType,int columns)119 static std::unique_ptr<Type> MakeArrayType(String name, const Type& componentType, 120 int columns) { 121 return std::unique_ptr<Type>(new Type(std::move(name), componentType.abbreviatedName(), 122 TypeKind::kArray, componentType, columns)); 123 } 124 125 /** Creates a clone of this Type, if needed, and inserts it into a different symbol table. */ 126 const Type* clone(SymbolTable* symbolTable) const; 127 128 /** 129 * Returns true if this type is known to come from BuiltinTypes. If this returns true, the Type 130 * will always be available in the root SymbolTable and never needs to be copied to migrate an 131 * Expression from one location to another. If it returns false, the Type might not exist in a 132 * separate SymbolTable and you'll need to consider copying it. 133 */ isInBuiltinTypes()134 bool isInBuiltinTypes() const { 135 return !(this->isArray() || this->isStruct() || this->isEnum()); 136 } 137 displayName()138 String displayName() const { 139 return this->scalarTypeForLiteral().name(); 140 } 141 description()142 String description() const override { 143 return this->displayName(); 144 } 145 isPrivate()146 bool isPrivate() const { 147 return this->name().startsWith("$"); 148 } 149 150 bool operator==(const Type& other) const { 151 return this->name() == other.name(); 152 } 153 154 bool operator!=(const Type& other) const { 155 return this->name() != other.name(); 156 } 157 158 /** 159 * Returns an abbreviated name of the type, meant for name-mangling. (e.g. float4x4 -> f44) 160 */ abbreviatedName()161 const char* abbreviatedName() const { 162 return fAbbreviatedName; 163 } 164 165 /** 166 * Returns the category (scalar, vector, matrix, etc.) of this type. 167 */ typeKind()168 TypeKind typeKind() const { 169 return fTypeKind; 170 } 171 numberKind()172 NumberKind numberKind() const { 173 return fNumberKind; 174 } 175 176 /** 177 * Returns true if this type is a bool. 178 */ isBoolean()179 bool isBoolean() const { 180 return fNumberKind == NumberKind::kBoolean; 181 } 182 183 /** 184 * Returns true if this is a numeric scalar type. 185 */ isNumber()186 bool isNumber() const { 187 return this->isFloat() || this->isInteger(); 188 } 189 190 /** 191 * Returns true if this is a floating-point scalar type (float or half). 192 */ isFloat()193 bool isFloat() const { 194 return fNumberKind == NumberKind::kFloat; 195 } 196 197 /** 198 * Returns true if this is a signed scalar type (int or short). 199 */ isSigned()200 bool isSigned() const { 201 return fNumberKind == NumberKind::kSigned; 202 } 203 204 /** 205 * Returns true if this is an unsigned scalar type (uint or ushort). 206 */ isUnsigned()207 bool isUnsigned() const { 208 return fNumberKind == NumberKind::kUnsigned; 209 } 210 211 /** 212 * Returns true if this is a signed or unsigned integer. 213 */ isInteger()214 bool isInteger() const { 215 return this->isSigned() || this->isUnsigned(); 216 } 217 218 /** 219 * Returns true if this is an "opaque type" (an external object which the shader references in 220 * some fashion), or void. https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)#Opaque_types 221 */ isOpaque()222 bool isOpaque() const { 223 switch (fTypeKind) { 224 case TypeKind::kColorFilter: 225 case TypeKind::kFragmentProcessor: 226 case TypeKind::kOther: 227 case TypeKind::kSampler: 228 case TypeKind::kSeparateSampler: 229 case TypeKind::kShader: 230 case TypeKind::kTexture: 231 case TypeKind::kVoid: 232 return true; 233 default: 234 return false; 235 } 236 } 237 238 /** 239 * Returns the "priority" of a number type, in order of float > half > int > short. 240 * When operating on two number types, the result is the higher-priority type. 241 */ priority()242 int priority() const { 243 return fPriority; 244 } 245 246 /** 247 * Returns true if an instance of this type can be freely coerced (implicitly converted) to 248 * another type. 249 */ canCoerceTo(const Type & other,bool allowNarrowing)250 bool canCoerceTo(const Type& other, bool allowNarrowing) const { 251 return this->coercionCost(other).isPossible(allowNarrowing); 252 } 253 254 /** 255 * Determines the "cost" of coercing (implicitly converting) this type to another type. The cost 256 * is a number with no particular meaning other than that lower costs are preferable to higher 257 * costs. Returns INT_MAX if the coercion is not possible. 258 */ 259 CoercionCost coercionCost(const Type& other) const; 260 261 /** 262 * For matrices and vectors, returns the type of individual cells (e.g. mat2 has a component 263 * type of Float). For arrays, returns the base type. For all other types, returns the type 264 * itself. 265 */ componentType()266 const Type& componentType() const { 267 if (fComponentType) { 268 return *fComponentType; 269 } 270 return *this; 271 } 272 273 /** 274 * For texturesamplers, returns the type of texture it samples (e.g., sampler2D has 275 * a texture type of texture2D). 276 */ textureType()277 const Type& textureType() const { 278 SkASSERT(fTextureType); 279 return *fTextureType; 280 } 281 282 /** 283 * For matrices and vectors, returns the number of columns (e.g. both mat3 and float3 return 3). 284 * For scalars, returns 1. For arrays, returns either the size of the array (if known) or -1. 285 * For all other types, causes an SkASSERTion failure. 286 */ columns()287 int columns() const { 288 SkASSERT(this->isScalar() || this->isVector() || this->isMatrix() || this->isArray()); 289 return fColumns; 290 } 291 292 /** 293 * For matrices, returns the number of rows (e.g. mat2x4 returns 4). For vectors and scalars, 294 * returns 1. For all other types, causes an SkASSERTion failure. 295 */ rows()296 int rows() const { 297 SkASSERT(fRows > 0); 298 return fRows; 299 } 300 301 /** 302 * Returns the number of scalars needed to hold this type. 303 */ slotCount()304 size_t slotCount() const { 305 switch (this->typeKind()) { 306 case Type::TypeKind::kColorFilter: 307 case Type::TypeKind::kFragmentProcessor: 308 case Type::TypeKind::kGeneric: 309 case Type::TypeKind::kOther: 310 case Type::TypeKind::kSampler: 311 case Type::TypeKind::kSeparateSampler: 312 case Type::TypeKind::kShader: 313 case Type::TypeKind::kTexture: 314 case Type::TypeKind::kVoid: 315 return 0; 316 317 case Type::TypeKind::kScalar: 318 case Type::TypeKind::kEnum: 319 return 1; 320 321 case Type::TypeKind::kVector: 322 return this->columns(); 323 324 case Type::TypeKind::kMatrix: 325 return this->columns() * this->rows(); 326 327 case Type::TypeKind::kStruct: { 328 size_t slots = 0; 329 for (const Field& field : this->fields()) { 330 slots += field.fType->slotCount(); 331 } 332 return slots; 333 } 334 case Type::TypeKind::kArray: 335 SkASSERT(this->columns() > 0); 336 return this->columns() * this->componentType().slotCount(); 337 } 338 SkUNREACHABLE; 339 } 340 fields()341 const std::vector<Field>& fields() const { 342 SkASSERT(this->isStruct()); 343 return fFields; 344 } 345 346 /** 347 * For generic types, returns the types that this generic type can substitute for. 348 */ coercibleTypes()349 const std::vector<const Type*>& coercibleTypes() const { 350 SkASSERT(fCoercibleTypes.size() > 0); 351 return fCoercibleTypes; 352 } 353 dimensions()354 SpvDim_ dimensions() const { 355 SkASSERT(TypeKind::kSampler == fTypeKind || TypeKind::kTexture == fTypeKind); 356 return fDimensions; 357 } 358 isDepth()359 bool isDepth() const { 360 SkASSERT(TypeKind::kSampler == fTypeKind || TypeKind::kTexture == fTypeKind); 361 return fIsDepth; 362 } 363 isArrayedTexture()364 bool isArrayedTexture() const { 365 SkASSERT(TypeKind::kSampler == fTypeKind || TypeKind::kTexture == fTypeKind); 366 return fIsArrayed; 367 } 368 isVoid()369 bool isVoid() const { 370 return fTypeKind == TypeKind::kVoid; 371 } 372 isScalar()373 bool isScalar() const { 374 return fTypeKind == TypeKind::kScalar; 375 } 376 isLiteral()377 bool isLiteral() const { 378 return fScalarTypeForLiteral != nullptr; 379 } 380 scalarTypeForLiteral()381 const Type& scalarTypeForLiteral() const { 382 return fScalarTypeForLiteral ? *fScalarTypeForLiteral : *this; 383 } 384 isVector()385 bool isVector() const { 386 return fTypeKind == TypeKind::kVector; 387 } 388 isMatrix()389 bool isMatrix() const { 390 return fTypeKind == TypeKind::kMatrix; 391 } 392 isArray()393 bool isArray() const { 394 return fTypeKind == TypeKind::kArray; 395 } 396 isStruct()397 bool isStruct() const { 398 return fTypeKind == TypeKind::kStruct; 399 } 400 isEnum()401 bool isEnum() const { 402 return fTypeKind == TypeKind::kEnum; 403 } 404 isFragmentProcessor()405 bool isFragmentProcessor() const { 406 return fTypeKind == TypeKind::kFragmentProcessor; 407 } 408 409 // Is this type something that can be bound & sampled from an SkRuntimeEffect? 410 // Includes types that represent stages of the Skia pipeline (colorFilter and shader). isEffectChild()411 bool isEffectChild() const { 412 return fTypeKind == TypeKind::kColorFilter || fTypeKind == TypeKind::kShader; 413 } 414 isMultisampled()415 bool isMultisampled() const { 416 SkASSERT(TypeKind::kSampler == fTypeKind || TypeKind::kTexture == fTypeKind); 417 return fIsMultisampled; 418 } 419 isSampled()420 bool isSampled() const { 421 SkASSERT(TypeKind::kSampler == fTypeKind || TypeKind::kTexture == fTypeKind); 422 return fIsSampled; 423 } 424 hasPrecision()425 bool hasPrecision() const { 426 return this->componentType().isNumber() || fTypeKind == TypeKind::kSampler; 427 } 428 highPrecision()429 bool highPrecision() const { 430 if (fComponentType) { 431 return fComponentType->highPrecision(); 432 } 433 return fHighPrecision; 434 } 435 436 bool isOrContainsArray() const; 437 438 /** 439 * Returns the corresponding vector or matrix type with the specified number of columns and 440 * rows. 441 */ 442 const Type& toCompound(const Context& context, int columns, int rows) const; 443 444 /** 445 * Coerces the passed-in expression to this type. If the types are incompatible, reports an 446 * error and returns null. 447 */ 448 std::unique_ptr<Expression> coerceExpression(std::unique_ptr<Expression> expr, 449 const Context& context) const; 450 451 private: 452 friend class BuiltinTypes; 453 454 using INHERITED = Symbol; 455 456 // Constructor for MakeSpecialType. Type(const char * name,const char * abbrev,TypeKind kind)457 Type(const char* name, const char* abbrev, TypeKind kind) 458 : INHERITED(-1, kSymbolKind, name) 459 , fAbbreviatedName(abbrev) 460 , fTypeKind(kind) 461 , fNumberKind(NumberKind::kNonnumeric) {} 462 463 // Constructor for MakeEnumType. Type(String name,const char * abbrev,TypeKind kind)464 Type(String name, const char* abbrev, TypeKind kind) 465 : INHERITED(-1, kSymbolKind, "") 466 , fAbbreviatedName(abbrev) 467 , fNameString(std::move(name)) 468 , fTypeKind(kind) 469 , fNumberKind(NumberKind::kNonnumeric) { 470 fName = StringFragment(fNameString.c_str(), fNameString.length()); 471 } 472 473 // Constructor for MakeGenericType. Type(const char * name,std::vector<const Type * > types)474 Type(const char* name, std::vector<const Type*> types) 475 : INHERITED(-1, kSymbolKind, name) 476 , fAbbreviatedName("G") 477 , fTypeKind(TypeKind::kGeneric) 478 , fNumberKind(NumberKind::kNonnumeric) 479 , fCoercibleTypes(std::move(types)) {} 480 481 // Constructor for MakeScalarType. Type(const char * name,const char * abbrev,NumberKind numberKind,int priority,bool highPrecision)482 Type(const char* name, const char* abbrev, NumberKind numberKind, 483 int priority, bool highPrecision) 484 : INHERITED(-1, kSymbolKind, name) 485 , fAbbreviatedName(abbrev) 486 , fTypeKind(TypeKind::kScalar) 487 , fNumberKind(numberKind) 488 , fPriority(priority) 489 , fColumns(1) 490 , fRows(1) 491 , fHighPrecision(highPrecision) {} 492 493 // Constructor for MakeLiteralType. Type(const char * name,const Type & scalarType,int priority)494 Type(const char* name, const Type& scalarType, int priority) 495 : INHERITED(-1, kSymbolKind, name) 496 , fAbbreviatedName("L") 497 , fTypeKind(TypeKind::kScalar) 498 , fNumberKind(scalarType.numberKind()) 499 , fPriority(priority) 500 , fColumns(1) 501 , fRows(1) 502 , fHighPrecision(scalarType.highPrecision()) 503 , fScalarTypeForLiteral(&scalarType) {} 504 505 // Constructor shared by MakeVectorType and MakeArrayType. Type(String name,const char * abbrev,TypeKind kind,const Type & componentType,int columns)506 Type(String name, const char* abbrev, TypeKind kind, const Type& componentType, int columns) 507 : INHERITED(-1, kSymbolKind, "") 508 , fAbbreviatedName(abbrev) 509 , fNameString(std::move(name)) 510 , fTypeKind(kind) 511 , fNumberKind(NumberKind::kNonnumeric) 512 , fComponentType(&componentType) 513 , fColumns(columns) 514 , fRows(1) 515 , fDimensions(SpvDim1D) { 516 if (this->isArray()) { 517 // Allow either explicitly-sized or unsized arrays. 518 SkASSERT(this->columns() > 0 || this->columns() == kUnsizedArray); 519 // Disallow multi-dimensional arrays. 520 SkASSERT(!this->componentType().isArray()); 521 } else { 522 SkASSERT(this->columns() > 0); 523 } 524 fName = StringFragment(fNameString.c_str(), fNameString.length()); 525 } 526 527 // Constructor for MakeMatrixType. Type(const char * name,const char * abbrev,const Type & componentType,int columns,int rows)528 Type(const char* name, const char* abbrev, const Type& componentType, int columns, int rows) 529 : INHERITED(-1, kSymbolKind, name) 530 , fAbbreviatedName(abbrev) 531 , fTypeKind(TypeKind::kMatrix) 532 , fNumberKind(NumberKind::kNonnumeric) 533 , fComponentType(&componentType) 534 , fColumns(columns) 535 , fRows(rows) 536 , fDimensions(SpvDim1D) {} 537 538 // Constructor for MakeStructType. Type(int offset,String name,std::vector<Field> fields)539 Type(int offset, String name, std::vector<Field> fields) 540 : INHERITED(offset, kSymbolKind, "") 541 , fAbbreviatedName("S") 542 , fNameString(std::move(name)) 543 , fTypeKind(TypeKind::kStruct) 544 , fNumberKind(NumberKind::kNonnumeric) 545 , fFields(std::move(fields)) { 546 fName = StringFragment(fNameString.c_str(), fNameString.length()); 547 } 548 549 // Constructor for MakeTextureType. Type(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayedTexture,bool isMultisampled,bool isSampled)550 Type(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayedTexture, 551 bool isMultisampled, bool isSampled) 552 : INHERITED(-1, kSymbolKind, name) 553 , fAbbreviatedName("T") 554 , fTypeKind(TypeKind::kTexture) 555 , fNumberKind(NumberKind::kNonnumeric) 556 , fDimensions(dimensions) 557 , fIsDepth(isDepth) 558 , fIsArrayed(isArrayedTexture) 559 , fIsMultisampled(isMultisampled) 560 , fIsSampled(isSampled) {} 561 562 // Constructor for MakeSamplerType. Type(const char * name,const Type & textureType)563 Type(const char* name, const Type& textureType) 564 : INHERITED(-1, kSymbolKind, name) 565 , fAbbreviatedName("Z") 566 , fTypeKind(TypeKind::kSampler) 567 , fNumberKind(NumberKind::kNonnumeric) 568 , fDimensions(textureType.dimensions()) 569 , fIsDepth(textureType.isDepth()) 570 , fIsArrayed(textureType.isArrayedTexture()) 571 , fIsMultisampled(textureType.isMultisampled()) 572 , fIsSampled(textureType.isSampled()) 573 , fTextureType(&textureType) {} 574 575 const char* fAbbreviatedName = ""; 576 String fNameString; 577 TypeKind fTypeKind; 578 // always kNonnumeric_NumberKind for non-scalar values 579 NumberKind fNumberKind; 580 int fPriority = -1; 581 const Type* fComponentType = nullptr; 582 std::vector<const Type*> fCoercibleTypes; 583 int fColumns = -1; 584 int fRows = -1; 585 std::vector<Field> fFields; 586 SpvDim_ fDimensions = SpvDim1D; 587 bool fIsDepth = false; 588 bool fIsArrayed = false; 589 bool fIsMultisampled = false; 590 bool fIsSampled = false; 591 bool fHighPrecision = false; 592 const Type* fTextureType = nullptr; 593 const Type* fScalarTypeForLiteral = nullptr; 594 }; 595 596 } // namespace SkSL 597 598 #endif 599