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 case TypeKind::kSampler: 359 case TypeKind::kSeparateSampler: 360 case TypeKind::kShader: 361 case TypeKind::kTexture: 362 return true; 363 default: 364 return false; 365 } 366 } 367 368 /** 369 * Returns true if this is a storage texture. 370 */ isStorageTexture()371 bool isStorageTexture() const { 372 return fTypeKind == TypeKind::kTexture && this->dimensions() != SpvDimSubpassData; 373 } 374 375 /** 376 * Returns the "priority" of a number type, in order of float > half > int > short. 377 * When operating on two number types, the result is the higher-priority type. 378 */ priority()379 virtual int priority() const { 380 SkDEBUGFAIL("not a number type"); 381 return -1; 382 } 383 384 /** 385 * Returns true if an instance of this type can be freely coerced (implicitly converted) to 386 * another type. 387 */ canCoerceTo(const Type & other,bool allowNarrowing)388 bool canCoerceTo(const Type& other, bool allowNarrowing) const { 389 return this->coercionCost(other).isPossible(allowNarrowing); 390 } 391 392 /** 393 * Determines the "cost" of coercing (implicitly converting) this type to another type. The cost 394 * is a number with no particular meaning other than that lower costs are preferable to higher 395 * costs. Returns INT_MAX if the coercion is not possible. 396 */ 397 CoercionCost coercionCost(const Type& other) const; 398 399 /** 400 * For matrices and vectors, returns the type of individual cells (e.g. mat2 has a component 401 * type of Float). For arrays, returns the base type. For all other types, returns the type 402 * itself. 403 */ componentType()404 virtual const Type& componentType() const { 405 return *this; 406 } 407 408 /** 409 * For matrix types, returns the type of a single column (`m[n]`). Asserts for all other types. 410 */ columnType(const Context & context)411 const Type& columnType(const Context& context) const { 412 return this->componentType().toCompound(context, this->rows(), /*rows=*/1); 413 } 414 415 /** 416 * For texture samplers, returns the type of texture it samples (e.g., sampler2D has 417 * a texture type of texture2D). 418 */ textureType()419 virtual const Type& textureType() const { 420 SkDEBUGFAIL("not a sampler type"); 421 return *this; 422 } 423 424 /** 425 * For matrices and vectors, returns the number of columns (e.g. both mat3 and float3 return 3). 426 * For scalars, returns 1. For arrays, returns either the size of the array (if known) or -1. 427 * For all other types, causes an assertion failure. 428 */ columns()429 virtual int columns() const { 430 SkDEBUGFAIL("type does not have columns"); 431 return -1; 432 } 433 434 /** 435 * For matrices, returns the number of rows (e.g. mat2x4 returns 4). For vectors and scalars, 436 * returns 1. For all other types, causes an assertion failure. 437 */ rows()438 virtual int rows() const { 439 SkDEBUGFAIL("type does not have rows"); 440 return -1; 441 } 442 443 /** Returns the minimum value that can fit in the type. */ minimumValue()444 virtual double minimumValue() const { 445 SkDEBUGFAIL("type does not have a minimum value"); 446 return -INFINITY; 447 } 448 maximumValue()449 virtual double maximumValue() const { 450 SkDEBUGFAIL("type does not have a maximum value"); 451 return +INFINITY; 452 } 453 454 /** 455 * Returns the number of scalars needed to hold this type. 456 */ slotCount()457 virtual size_t slotCount() const { 458 return 0; 459 } 460 461 /** 462 * Returns the type of the value in the nth slot. For scalar, vector and matrix types, should 463 * always match `componentType()`. 464 */ slotType(size_t)465 virtual const Type& slotType(size_t) const { 466 return *this; 467 } 468 fields()469 virtual SkSpan<const Field> fields() const { 470 SK_ABORT("Internal error: not a struct"); 471 } 472 473 /** 474 * For generic types, returns the types that this generic type can substitute for. 475 */ coercibleTypes()476 virtual SkSpan<const Type* const> coercibleTypes() const { 477 SkDEBUGFAIL("Internal error: not a generic type"); 478 return {}; 479 } 480 dimensions()481 virtual SpvDim_ dimensions() const { 482 SkDEBUGFAIL("Internal error: not a texture type"); 483 return SpvDim1D; 484 } 485 isDepth()486 virtual bool isDepth() const { 487 SkDEBUGFAIL("Internal error: not a texture type"); 488 return false; 489 } 490 isArrayedTexture()491 virtual bool isArrayedTexture() const { 492 SkDEBUGFAIL("Internal error: not a texture type"); 493 return false; 494 } 495 isVoid()496 bool isVoid() const { 497 return fTypeKind == TypeKind::kVoid; 498 } 499 isGeneric()500 bool isGeneric() const { 501 return fTypeKind == TypeKind::kGeneric; 502 } 503 isSampler()504 bool isSampler() const { 505 return fTypeKind == TypeKind::kSampler; 506 } 507 isAtomic()508 bool isAtomic() const { 509 return this->typeKind() == TypeKind::kAtomic; 510 } 511 isScalar()512 virtual bool isScalar() const { 513 return false; 514 } 515 isLiteral()516 virtual bool isLiteral() const { 517 return false; 518 } 519 scalarTypeForLiteral()520 virtual const Type& scalarTypeForLiteral() const { 521 return *this; 522 } 523 isVector()524 virtual bool isVector() const { 525 return false; 526 } 527 isMatrix()528 virtual bool isMatrix() const { 529 return false; 530 } 531 isArray()532 virtual bool isArray() const { 533 return false; 534 } 535 isUnsizedArray()536 virtual bool isUnsizedArray() const { 537 return false; 538 } 539 isStruct()540 virtual bool isStruct() const { 541 return false; 542 } 543 isInterfaceBlock()544 virtual bool isInterfaceBlock() const { 545 return false; 546 } 547 548 // Is this type something that can be bound & sampled from an SkRuntimeEffect? 549 // Includes types that represent stages of the Skia pipeline (colorFilter, shader, blender). isEffectChild()550 bool isEffectChild() const { 551 return fTypeKind == TypeKind::kColorFilter || 552 fTypeKind == TypeKind::kShader || 553 fTypeKind == TypeKind::kBlender; 554 } 555 isMultisampled()556 virtual bool isMultisampled() const { 557 SkDEBUGFAIL("not a texture type"); 558 return false; 559 } 560 textureAccess()561 virtual TextureAccess textureAccess() const { 562 SkDEBUGFAIL("not a texture type"); 563 return TextureAccess::kSample; 564 } 565 hasPrecision()566 bool hasPrecision() const { 567 return this->componentType().isNumber() || this->isSampler(); 568 } 569 highPrecision()570 bool highPrecision() const { 571 return this->bitWidth() >= 32; 572 } 573 bitWidth()574 virtual int bitWidth() const { 575 return 0; 576 } 577 isOrContainsArray()578 virtual bool isOrContainsArray() const { 579 return false; 580 } 581 isOrContainsUnsizedArray()582 virtual bool isOrContainsUnsizedArray() const { 583 return false; 584 } 585 isOrContainsAtomic()586 virtual bool isOrContainsAtomic() const { 587 return false; 588 } 589 isOrContainsBool()590 virtual bool isOrContainsBool() const { 591 return false; 592 } 593 594 /** 595 * Returns the corresponding vector or matrix type with the specified number of columns and 596 * rows. 597 */ 598 const Type& toCompound(const Context& context, int columns, int rows) const; 599 600 /** 601 * Returns a type which honors the precision and access-level qualifiers set in ModifierFlags. 602 * For example: 603 * - Modifier `mediump` + Type `float2`: Type `half2` 604 * - Modifier `readonly` + Type `texture2D`: Type `readonlyTexture2D` 605 * Generates an error if the qualifiers don't make sense (`highp bool`, `writeonly MyStruct`) 606 */ 607 const Type* applyQualifiers(const Context& context, 608 ModifierFlags* modifierFlags, 609 Position pos) const; 610 611 /** 612 * Coerces the passed-in expression to this type. If the types are incompatible, reports an 613 * error and returns null. 614 */ 615 std::unique_ptr<Expression> coerceExpression(std::unique_ptr<Expression> expr, 616 const Context& context) const; 617 618 /** Detects any IntLiterals in the expression which can't fit in this type. */ 619 bool checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const; 620 621 /** Checks if `value` can fit in this type. The type must be scalar. */ 622 bool checkForOutOfRangeLiteral(const Context& context, double value, Position pos) const; 623 624 /** 625 * Reports errors and returns false if this type cannot be used as the base type for an array. 626 */ 627 bool checkIfUsableInArray(const Context& context, Position arrayPos) const; 628 629 /** 630 * Verifies that the expression is a valid constant array size for this type. Returns the array 631 * size, or reports errors and returns zero if the expression isn't a valid literal value. 632 */ 633 SKSL_INT convertArraySize(const Context& context, 634 Position arrayPos, 635 std::unique_ptr<Expression> size) const; 636 637 SKSL_INT convertArraySize(const Context& context, 638 Position arrayPos, 639 Position sizePos, 640 SKSL_INT size) const; 641 642 protected: 643 Type(std::string_view name, const char* abbrev, TypeKind kind, Position pos = Position()) INHERITED(pos,kIRNodeKind,name)644 : INHERITED(pos, kIRNodeKind, name) 645 , fTypeKind(kind) { 646 SkASSERT(strlen(abbrev) <= kMaxAbbrevLength); 647 strcpy(fAbbreviatedName, abbrev); 648 } 649 650 const Type* applyPrecisionQualifiers(const Context& context, 651 ModifierFlags* modifierFlags, 652 Position pos) const; 653 654 const Type* applyAccessQualifiers(const Context& context, 655 ModifierFlags* modifierFlags, 656 Position pos) const; 657 658 /** Only structs and arrays can be created in code; all other types exist in the root. */ isInRootSymbolTable()659 bool isInRootSymbolTable() const { 660 return !(this->isArray() || this->isStruct()); 661 } 662 663 /** If the type is a struct, returns the depth of the struct's most deeply-nested field. */ structNestingDepth()664 virtual int structNestingDepth() const { 665 return 0; 666 } 667 668 private: 669 using INHERITED = Symbol; 670 671 char fAbbreviatedName[kMaxAbbrevLength + 1] = {}; 672 TypeKind fTypeKind; 673 }; 674 675 } // namespace SkSL 676 677 #endif 678