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