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