• 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/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