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 SKSL_TYPE 9 #define SKSL_TYPE 10 11 #include "include/core/SkSpan.h" 12 #include "include/core/SkTypes.h" 13 #include "include/private/base/SkTArray.h" 14 #include "src/sksl/SkSLDefines.h" 15 #include "src/sksl/SkSLPosition.h" 16 #include "src/sksl/ir/SkSLIRNode.h" 17 #include "src/sksl/ir/SkSLLayout.h" 18 #include "src/sksl/ir/SkSLModifierFlags.h" 19 #include "src/sksl/ir/SkSLSymbol.h" 20 #include "src/sksl/spirv.h" 21 22 #include <cmath> 23 #include <cstddef> 24 #include <cstdint> 25 #include <cstring> 26 #include <memory> 27 #include <string> 28 #include <string_view> 29 #include <tuple> 30 31 namespace SkSL { 32 33 class Context; 34 class Expression; 35 class SymbolTable; 36 class Type; 37 38 struct CoercionCost { FreeCoercionCost39 static CoercionCost Free() { return { 0, 0, false }; } NormalCoercionCost40 static CoercionCost Normal(int cost) { return { cost, 0, false }; } NarrowingCoercionCost41 static CoercionCost Narrowing(int cost) { return { 0, cost, false }; } ImpossibleCoercionCost42 static CoercionCost Impossible() { return { 0, 0, true }; } 43 isPossibleCoercionCost44 bool isPossible(bool allowNarrowing) const { 45 return !fImpossible && (fNarrowingCost == 0 || allowNarrowing); 46 } 47 48 // Addition of two costs. Saturates at Impossible(). 49 CoercionCost operator+(CoercionCost rhs) const { 50 if (fImpossible || rhs.fImpossible) { 51 return Impossible(); 52 } 53 return { fNormalCost + rhs.fNormalCost, fNarrowingCost + rhs.fNarrowingCost, false }; 54 } 55 56 bool operator<(CoercionCost rhs) const { 57 return std::tie( fImpossible, fNarrowingCost, fNormalCost) < 58 std::tie(rhs.fImpossible, rhs.fNarrowingCost, rhs.fNormalCost); 59 } 60 61 bool operator<=(CoercionCost rhs) const { 62 return std::tie( fImpossible, fNarrowingCost, fNormalCost) <= 63 std::tie(rhs.fImpossible, rhs.fNarrowingCost, rhs.fNormalCost); 64 } 65 66 int fNormalCost; 67 int fNarrowingCost; 68 bool fImpossible; 69 }; 70 71 /** 72 * Represents a single field in a struct type. 73 */ 74 struct Field { FieldField75 Field(Position pos, Layout layout, ModifierFlags flags, std::string_view name, const Type* type) 76 : fPosition(pos) 77 , fLayout(layout) 78 , fModifierFlags(flags) 79 , fName(name) 80 , fType(type) {} 81 82 std::string description() const; 83 84 Position fPosition; 85 Layout fLayout; 86 ModifierFlags fModifierFlags; 87 std::string_view fName; 88 const Type* fType; 89 }; 90 91 /** 92 * Represents a type, such as int or float4. 93 */ 94 class Type : public Symbol { 95 public: 96 inline static constexpr Kind kIRNodeKind = Kind::kType; 97 inline static constexpr int kMaxAbbrevLength = 3; 98 // Represents unspecified array dimensions, as in `int[]`. 99 inline static constexpr int kUnsizedArray = -1; 100 101 enum class TypeKind : int8_t { 102 kArray, 103 kAtomic, 104 kGeneric, 105 kLiteral, 106 kMatrix, 107 kOther, 108 kSampler, 109 kSeparateSampler, 110 kScalar, 111 kStruct, 112 kTexture, 113 kVector, 114 kVoid, 115 116 // Types that represent stages in the Skia pipeline 117 kColorFilter, 118 kShader, 119 kBlender, 120 }; 121 122 enum class NumberKind : int8_t { 123 kFloat, 124 kSigned, 125 kUnsigned, 126 kBoolean, 127 kNonnumeric 128 }; 129 130 enum class TextureAccess : int8_t { 131 kSample, // `kSample` access level allows both sampling and reading 132 kRead, 133 kWrite, 134 kReadWrite, 135 }; 136 137 Type(const Type& other) = delete; 138 139 /** Creates an array type. `columns` may be kUnsizedArray. */ 140 static std::unique_ptr<Type> MakeArrayType(const Context& context, std::string_view name, 141 const Type& componentType, int columns); 142 143 /** Converts a component type and a size (float, 10) into an array name ("float[10]"). */ 144 std::string getArrayName(int arraySize) const; 145 146 /** 147 * Creates an alias which maps to another type. 148 */ 149 static std::unique_ptr<Type> MakeAliasType(std::string_view name, const Type& targetType); 150 151 /** 152 * Create a generic type which maps to the listed types--e.g. $genType is a generic type which 153 * can match float, float2, float3 or float4. 154 */ 155 static std::unique_ptr<Type> MakeGenericType(const char* name, 156 SkSpan<const Type* const> types, 157 const Type* slotType); 158 159 /** Create a type for literal scalars. */ 160 static std::unique_ptr<Type> MakeLiteralType(const char* name, const Type& scalarType, 161 int8_t priority); 162 163 /** Create a matrix type. */ 164 static std::unique_ptr<Type> MakeMatrixType(std::string_view name, const char* abbrev, 165 const Type& componentType, int columns, 166 int8_t rows); 167 168 /** Create a sampler type. */ 169 static std::unique_ptr<Type> MakeSamplerType(const char* name, const Type& textureType); 170 171 /** Create a scalar type. */ 172 static std::unique_ptr<Type> MakeScalarType(std::string_view name, const char* abbrev, 173 Type::NumberKind numberKind, int8_t priority, 174 int8_t bitWidth); 175 176 /** 177 * Create a "special" type with the given name, abbreviation, and TypeKind. 178 */ 179 static std::unique_ptr<Type> MakeSpecialType(const char* name, const char* abbrev, 180 Type::TypeKind typeKind); 181 182 /** 183 * Creates a struct type with the given fields. Reports an error if the struct is not 184 * well-formed. 185 */ 186 static std::unique_ptr<Type> MakeStructType(const Context& context, 187 Position pos, 188 std::string_view name, 189 skia_private::TArray<Field> fields, 190 bool interfaceBlock = false); 191 192 /** Create a texture type. */ 193 static std::unique_ptr<Type> MakeTextureType(const char* name, SpvDim_ dimensions, bool isDepth, 194 bool isArrayedTexture, bool isMultisampled, 195 TextureAccess textureAccess); 196 197 /** Create a vector type. */ 198 static std::unique_ptr<Type> MakeVectorType(std::string_view name, const char* abbrev, 199 const Type& componentType, int columns); 200 201 /** Create an atomic type. */ 202 static std::unique_ptr<Type> MakeAtomicType(std::string_view name, const char* abbrev); 203 204 template <typename T> is()205 bool is() const { 206 return this->typeKind() == T::kTypeKind; 207 } 208 209 template <typename T> as()210 const T& as() const { 211 SkASSERT(this->is<T>()); 212 return static_cast<const T&>(*this); 213 } 214 215 template <typename T> as()216 T& as() { 217 SkASSERT(this->is<T>()); 218 return static_cast<T&>(*this); 219 } 220 221 /** Creates a clone of this Type, if needed, and inserts it into a different symbol table. */ 222 const Type* clone(const Context& context, SymbolTable* symbolTable) const; 223 224 /** 225 * Returns true if this type is known to come from BuiltinTypes, or is declared in a module. If 226 * this returns true, the Type will always be available in the root SymbolTable and never needs 227 * to be copied to migrate an Expression from one location to another. If it returns false, the 228 * Type might not exist in a separate SymbolTable and you'll need to consider cloning it. 229 */ isBuiltin()230 virtual bool isBuiltin() const { 231 return true; 232 } 233 displayName()234 std::string displayName() const { 235 return std::string(this->scalarTypeForLiteral().name()); 236 } 237 description()238 std::string description() const override { 239 return this->displayName(); 240 } 241 242 /** Returns true if the program supports this type. Strict ES2 programs can't use ES3 types. */ 243 bool isAllowedInES2(const Context& context) const; 244 245 /** Returns true if this type is legal to use in a strict-ES2 program. */ isAllowedInES2()246 virtual bool isAllowedInES2() const { 247 return true; 248 } 249 250 /** 251 * Returns true if this type is legal to use as a uniform. If false is returned, the 252 * `errorPosition` field may be populated; if it is, this position can be used to emit an extra 253 * diagnostic "caused by: <a field>" for nested types. 254 * Note that runtime effects enforce additional, much stricter rules about uniforms; these 255 * limitations are not handled here. 256 */ 257 virtual bool isAllowedInUniform(Position* errorPosition = nullptr) const { 258 // We don't allow samplers, textures or atomics to be marked as uniforms. 259 // This rules out all opaque types. 260 return !this->isOpaque(); 261 } 262 263 /** If this is an alias, returns the underlying type, otherwise returns this. */ resolve()264 virtual const Type& resolve() const { 265 return *this; 266 } 267 268 /** Returns true if these types are equal after alias resolution. */ matches(const Type & that)269 virtual bool matches(const Type& that) const { 270 return &this->resolve() == &that.resolve(); 271 } 272 273 /** 274 * Returns an abbreviated name of the type, meant for name-mangling. (e.g. float4x4 -> f44) 275 */ abbreviatedName()276 const char* abbreviatedName() const { 277 return fAbbreviatedName; 278 } 279 280 /** 281 * Returns the category (scalar, vector, matrix, etc.) of this type. 282 */ typeKind()283 TypeKind typeKind() const { 284 return fTypeKind; 285 } 286 287 /** 288 * Returns the NumberKind of this type (always kNonnumeric for non-scalar values). 289 */ numberKind()290 virtual NumberKind numberKind() const { 291 return NumberKind::kNonnumeric; 292 } 293 294 /** 295 * Returns true if this type is a bool. 296 */ isBoolean()297 bool isBoolean() const { 298 return this->numberKind() == NumberKind::kBoolean; 299 } 300 301 /** 302 * Returns true if this is a numeric scalar type. 303 */ isNumber()304 bool isNumber() const { 305 switch (this->numberKind()) { 306 case NumberKind::kFloat: 307 case NumberKind::kSigned: 308 case NumberKind::kUnsigned: 309 return true; 310 default: 311 return false; 312 } 313 } 314 315 /** 316 * Returns true if this is a floating-point scalar type (float or half). 317 */ isFloat()318 bool isFloat() const { 319 return this->numberKind() == NumberKind::kFloat; 320 } 321 322 /** 323 * Returns true if this is a signed scalar type (int or short). 324 */ isSigned()325 bool isSigned() const { 326 return this->numberKind() == NumberKind::kSigned; 327 } 328 329 /** 330 * Returns true if this is an unsigned scalar type (uint or ushort). 331 */ isUnsigned()332 bool isUnsigned() const { 333 return this->numberKind() == NumberKind::kUnsigned; 334 } 335 336 /** 337 * Returns true if this is a signed or unsigned integer. 338 */ isInteger()339 bool isInteger() const { 340 switch (this->numberKind()) { 341 case NumberKind::kSigned: 342 case NumberKind::kUnsigned: 343 return true; 344 default: 345 return false; 346 } 347 } 348 349 /** 350 * Returns true if this is an "opaque type" (an external object which the shader references in 351 * some fashion). https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)#Opaque_types 352 */ isOpaque()353 bool isOpaque() const { 354 switch (fTypeKind) { 355 case TypeKind::kAtomic: 356 case TypeKind::kBlender: 357 case TypeKind::kColorFilter: 358 #ifndef SKSL_EXT 359 case TypeKind::kSampler: 360 #endif 361 case TypeKind::kSeparateSampler: 362 case TypeKind::kShader: 363 case TypeKind::kTexture: 364 return true; 365 default: 366 return false; 367 } 368 } 369 370 /** 371 * Returns true if this is a storage texture. 372 */ isStorageTexture()373 bool isStorageTexture() const { 374 return fTypeKind == TypeKind::kTexture && this->dimensions() != SpvDimSubpassData; 375 } 376 377 /** 378 * Returns the "priority" of a number type, in order of float > half > int > short. 379 * When operating on two number types, the result is the higher-priority type. 380 */ priority()381 virtual int priority() const { 382 SkDEBUGFAIL("not a number type"); 383 return -1; 384 } 385 386 /** 387 * Returns true if an instance of this type can be freely coerced (implicitly converted) to 388 * another type. 389 */ canCoerceTo(const Type & other,bool allowNarrowing)390 bool canCoerceTo(const Type& other, bool allowNarrowing) const { 391 return this->coercionCost(other).isPossible(allowNarrowing); 392 } 393 394 /** 395 * Determines the "cost" of coercing (implicitly converting) this type to another type. The cost 396 * is a number with no particular meaning other than that lower costs are preferable to higher 397 * costs. Returns INT_MAX if the coercion is not possible. 398 */ 399 CoercionCost coercionCost(const Type& other) const; 400 401 /** 402 * For matrices and vectors, returns the type of individual cells (e.g. mat2 has a component 403 * type of Float). For arrays, returns the base type. For all other types, returns the type 404 * itself. 405 */ componentType()406 virtual const Type& componentType() const { 407 return *this; 408 } 409 410 /** 411 * For matrix types, returns the type of a single column (`m[n]`). Asserts for all other types. 412 */ columnType(const Context & context)413 const Type& columnType(const Context& context) const { 414 return this->componentType().toCompound(context, this->rows(), /*rows=*/1); 415 } 416 417 /** 418 * For texture samplers, returns the type of texture it samples (e.g., sampler2D has 419 * a texture type of texture2D). 420 */ textureType()421 virtual const Type& textureType() const { 422 SkDEBUGFAIL("not a sampler type"); 423 return *this; 424 } 425 426 /** 427 * For matrices and vectors, returns the number of columns (e.g. both mat3 and float3 return 3). 428 * For scalars, returns 1. For arrays, returns either the size of the array (if known) or -1. 429 * For all other types, causes an assertion failure. 430 */ columns()431 virtual int columns() const { 432 SkDEBUGFAIL("type does not have columns"); 433 return -1; 434 } 435 436 /** 437 * For matrices, returns the number of rows (e.g. mat2x4 returns 4). For vectors and scalars, 438 * returns 1. For all other types, causes an assertion failure. 439 */ rows()440 virtual int rows() const { 441 SkDEBUGFAIL("type does not have rows"); 442 return -1; 443 } 444 445 /** Returns the minimum value that can fit in the type. */ minimumValue()446 virtual double minimumValue() const { 447 SkDEBUGFAIL("type does not have a minimum value"); 448 return -INFINITY; 449 } 450 maximumValue()451 virtual double maximumValue() const { 452 SkDEBUGFAIL("type does not have a maximum value"); 453 return +INFINITY; 454 } 455 456 /** 457 * Returns the number of scalars needed to hold this type. 458 */ slotCount()459 virtual size_t slotCount() const { 460 return 0; 461 } 462 463 /** 464 * Returns the type of the value in the nth slot. For scalar, vector and matrix types, should 465 * always match `componentType()`. 466 */ slotType(size_t)467 virtual const Type& slotType(size_t) const { 468 return *this; 469 } 470 fields()471 virtual SkSpan<const Field> fields() const { 472 SK_ABORT("Internal error: not a struct"); 473 } 474 475 /** 476 * For generic types, returns the types that this generic type can substitute for. 477 */ coercibleTypes()478 virtual SkSpan<const Type* const> coercibleTypes() const { 479 SkDEBUGFAIL("Internal error: not a generic type"); 480 return {}; 481 } 482 dimensions()483 virtual SpvDim_ dimensions() const { 484 SkDEBUGFAIL("Internal error: not a texture type"); 485 return SpvDim1D; 486 } 487 isDepth()488 virtual bool isDepth() const { 489 SkDEBUGFAIL("Internal error: not a texture type"); 490 return false; 491 } 492 isArrayedTexture()493 virtual bool isArrayedTexture() const { 494 SkDEBUGFAIL("Internal error: not a texture type"); 495 return false; 496 } 497 isVoid()498 bool isVoid() const { 499 return fTypeKind == TypeKind::kVoid; 500 } 501 isGeneric()502 bool isGeneric() const { 503 return fTypeKind == TypeKind::kGeneric; 504 } 505 isSampler()506 bool isSampler() const { 507 return fTypeKind == TypeKind::kSampler; 508 } 509 isAtomic()510 bool isAtomic() const { 511 return this->typeKind() == TypeKind::kAtomic; 512 } 513 isScalar()514 virtual bool isScalar() const { 515 return false; 516 } 517 isLiteral()518 virtual bool isLiteral() const { 519 return false; 520 } 521 scalarTypeForLiteral()522 virtual const Type& scalarTypeForLiteral() const { 523 return *this; 524 } 525 isVector()526 virtual bool isVector() const { 527 return false; 528 } 529 isMatrix()530 virtual bool isMatrix() const { 531 return false; 532 } 533 isArray()534 virtual bool isArray() const { 535 return false; 536 } 537 isUnsizedArray()538 virtual bool isUnsizedArray() const { 539 return false; 540 } 541 isStruct()542 virtual bool isStruct() const { 543 return false; 544 } 545 isInterfaceBlock()546 virtual bool isInterfaceBlock() const { 547 return false; 548 } 549 550 // Is this type something that can be bound & sampled from an SkRuntimeEffect? 551 // Includes types that represent stages of the Skia pipeline (colorFilter, shader, blender). isEffectChild()552 bool isEffectChild() const { 553 return fTypeKind == TypeKind::kColorFilter || 554 fTypeKind == TypeKind::kShader || 555 fTypeKind == TypeKind::kBlender; 556 } 557 isMultisampled()558 virtual bool isMultisampled() const { 559 SkDEBUGFAIL("not a texture type"); 560 return false; 561 } 562 textureAccess()563 virtual TextureAccess textureAccess() const { 564 SkDEBUGFAIL("not a texture type"); 565 return TextureAccess::kSample; 566 } 567 hasPrecision()568 bool hasPrecision() const { 569 #ifdef SKSL_EXT 570 return this->componentType().isNumber() || 571 this->componentType().isSampler(); 572 #else 573 return this->componentType().isNumber() || this->isSampler(); 574 #endif 575 } 576 highPrecision()577 bool highPrecision() const { 578 return this->bitWidth() >= 32; 579 } 580 bitWidth()581 virtual int bitWidth() const { 582 return 0; 583 } 584 isOrContainsArray()585 virtual bool isOrContainsArray() const { 586 return false; 587 } 588 isOrContainsUnsizedArray()589 virtual bool isOrContainsUnsizedArray() const { 590 return false; 591 } 592 isOrContainsAtomic()593 virtual bool isOrContainsAtomic() const { 594 return false; 595 } 596 isOrContainsBool()597 virtual bool isOrContainsBool() const { 598 return false; 599 } 600 601 /** 602 * Returns the corresponding vector or matrix type with the specified number of columns and 603 * rows. 604 */ 605 const Type& toCompound(const Context& context, int columns, int rows) const; 606 607 /** 608 * Returns a type which honors the precision and access-level qualifiers set in ModifierFlags. 609 * For example: 610 * - Modifier `mediump` + Type `float2`: Type `half2` 611 * - Modifier `readonly` + Type `texture2D`: Type `readonlyTexture2D` 612 * Generates an error if the qualifiers don't make sense (`highp bool`, `writeonly MyStruct`) 613 */ 614 const Type* applyQualifiers(const Context& context, 615 ModifierFlags* modifierFlags, 616 Position pos) const; 617 618 /** 619 * Coerces the passed-in expression to this type. If the types are incompatible, reports an 620 * error and returns null. 621 */ 622 std::unique_ptr<Expression> coerceExpression(std::unique_ptr<Expression> expr, 623 const Context& context) const; 624 625 /** Detects any IntLiterals in the expression which can't fit in this type. */ 626 bool checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const; 627 628 /** Checks if `value` can fit in this type. The type must be scalar. */ 629 bool checkForOutOfRangeLiteral(const Context& context, double value, Position pos) const; 630 631 /** 632 * Reports errors and returns false if this type cannot be used as the base type for an array. 633 */ 634 bool checkIfUsableInArray(const Context& context, Position arrayPos) const; 635 636 /** 637 * Verifies that the expression is a valid constant array size for this type. Returns the array 638 * size, or reports errors and returns zero if the expression isn't a valid literal value. 639 */ 640 SKSL_INT convertArraySize(const Context& context, 641 Position arrayPos, 642 std::unique_ptr<Expression> size) const; 643 644 SKSL_INT convertArraySize(const Context& context, 645 Position arrayPos, 646 Position sizePos, 647 SKSL_INT size) const; 648 649 protected: 650 Type(std::string_view name, const char* abbrev, TypeKind kind, Position pos = Position()) INHERITED(pos,kIRNodeKind,name)651 : INHERITED(pos, kIRNodeKind, name) 652 , fTypeKind(kind) { 653 SkASSERT(strlen(abbrev) <= kMaxAbbrevLength); 654 strcpy(fAbbreviatedName, abbrev); 655 } 656 657 const Type* applyPrecisionQualifiers(const Context& context, 658 ModifierFlags* modifierFlags, 659 Position pos) const; 660 661 const Type* applyAccessQualifiers(const Context& context, 662 ModifierFlags* modifierFlags, 663 Position pos) const; 664 665 /** Only structs and arrays can be created in code; all other types exist in the root. */ isInRootSymbolTable()666 bool isInRootSymbolTable() const { 667 return !(this->isArray() || this->isStruct()); 668 } 669 670 /** If the type is a struct, returns the depth of the struct's most deeply-nested field. */ structNestingDepth()671 virtual int structNestingDepth() const { 672 return 0; 673 } 674 675 private: 676 using INHERITED = Symbol; 677 678 char fAbbreviatedName[kMaxAbbrevLength + 1] = {}; 679 TypeKind fTypeKind; 680 }; 681 682 } // namespace SkSL 683 684 #endif 685