• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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