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