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