• 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/private/SkSLModifiers.h"
12 #include "include/private/SkSLSymbol.h"
13 #include "src/sksl/SkSLUtil.h"
14 #include "src/sksl/spirv.h"
15 #include <algorithm>
16 #include <climits>
17 #include <string_view>
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, std::string_view name, const Type* type)
64         : fModifiers(modifiers)
65         , fName(name)
66         , fType(std::move(type)) {}
67 
descriptionField68         std::string description() const {
69             return fType->displayName() + " " + std::string(fName) + ";";
70         }
71 
72         Modifiers fModifiers;
73         std::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(std::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     std::string getArrayName(int arraySize) const;
113 
114     /**
115      * Creates an alias which maps to another type.
116      */
117     static std::unique_ptr<Type> MakeAliasType(std::string_view name, const Type& targetType);
118 
119     /**
120      * Create a generic type which maps to the listed types--e.g. $genType is a generic type which
121      * can match float, float2, float3 or float4.
122      */
123     static std::unique_ptr<Type> MakeGenericType(const char* name, std::vector<const Type*> types);
124 
125     /** Create a type for literal scalars. */
126     static std::unique_ptr<Type> MakeLiteralType(const char* name, const Type& scalarType,
127                                                  int8_t priority);
128 
129     /** Create a matrix type. */
130     static std::unique_ptr<Type> MakeMatrixType(std::string_view name, const char* abbrev,
131                                                 const Type& componentType, int columns,
132                                                 int8_t rows);
133 
134     /** Create a sampler type. */
135     static std::unique_ptr<Type> MakeSamplerType(const char* name, const Type& textureType);
136 
137     /** Create a scalar type. */
138     static std::unique_ptr<Type> MakeScalarType(std::string_view name, const char* abbrev,
139                                                 Type::NumberKind numberKind, int8_t priority,
140                                                 int8_t bitWidth);
141 
142     /**
143      * Create a "special" type with the given name, abbreviation, and TypeKind.
144      */
145     static std::unique_ptr<Type> MakeSpecialType(const char* name, const char* abbrev,
146                                                  Type::TypeKind typeKind);
147 
148     /** Creates a struct type with the given fields. */
149     static std::unique_ptr<Type> MakeStructType(int line,
150                                                 std::string_view name,
151                                                 std::vector<Field> fields,
152                                                 bool interfaceBlock = false);
153 
154     /** Create a texture type. */
155     static std::unique_ptr<Type> MakeTextureType(const char* name, SpvDim_ dimensions,
156                                                  bool isDepth, bool isArrayedTexture,
157                                                  bool isMultisampled, bool isSampled);
158 
159     /** Create a vector type. */
160     static std::unique_ptr<Type> MakeVectorType(std::string_view name, const char* abbrev,
161                                                 const Type& componentType, int columns);
162 
163     template <typename T>
is()164     bool is() const {
165         return this->typeKind() == T::kTypeKind;
166     }
167 
168     template <typename T>
as()169     const T& as() const {
170         SkASSERT(this->is<T>());
171         return static_cast<const T&>(*this);
172     }
173 
174     template <typename T>
as()175     T& as() {
176         SkASSERT(this->is<T>());
177         return static_cast<T&>(*this);
178     }
179 
180     /** Creates a clone of this Type, if needed, and inserts it into a different symbol table. */
181     const Type* clone(SymbolTable* symbolTable) const;
182 
183     /**
184      * Returns true if this type is known to come from BuiltinTypes. If this returns true, the Type
185      * will always be available in the root SymbolTable and never needs to be copied to migrate an
186      * Expression from one location to another. If it returns false, the Type might not exist in a
187      * separate SymbolTable and you'll need to consider copying it.
188      */
isInBuiltinTypes()189     bool isInBuiltinTypes() const {
190         return !(this->isArray() || this->isStruct());
191     }
192 
displayName()193     std::string displayName() const {
194         return std::string(this->scalarTypeForLiteral().name());
195     }
196 
description()197     std::string description() const override {
198         return this->displayName();
199     }
200 
201     /** Returns true if the program supports this type. Strict ES2 programs can't use ES3 types. */
202     bool isAllowedInES2(const Context& context) const;
203 
204     /** Returns true if this type is legal to use in a strict-ES2 program. */
isAllowedInES2()205     virtual bool isAllowedInES2() const {
206         return true;
207     }
208 
209     /** Returns true if this type is either private, or contains a private field (recursively). */
210     virtual bool isPrivate() const;
211 
212     /** If this is an alias, returns the underlying type, otherwise returns this. */
resolve()213     virtual const Type& resolve() const {
214         return *this;
215     }
216 
217     /** Returns true if these types are equal after alias resolution. */
matches(const Type & other)218     bool matches(const Type& other) const {
219         return this->resolve().name() == other.resolve().name();
220     }
221 
222     /**
223      * Returns an abbreviated name of the type, meant for name-mangling. (e.g. float4x4 -> f44)
224      */
abbreviatedName()225     const char* abbreviatedName() const {
226         return fAbbreviatedName;
227     }
228 
229     /**
230      * Returns the category (scalar, vector, matrix, etc.) of this type.
231      */
typeKind()232     TypeKind typeKind() const {
233         return fTypeKind;
234     }
235 
236     /**
237      * Returns the NumberKind of this type (always kNonnumeric for non-scalar values).
238      */
numberKind()239     virtual NumberKind numberKind() const {
240         return NumberKind::kNonnumeric;
241     }
242 
243     /**
244      * Returns true if this type is a bool.
245      */
isBoolean()246     bool isBoolean() const {
247         return this->numberKind() == NumberKind::kBoolean;
248     }
249 
250     /**
251      * Returns true if this is a numeric scalar type.
252      */
isNumber()253     bool isNumber() const {
254         switch (this->numberKind()) {
255             case NumberKind::kFloat:
256             case NumberKind::kSigned:
257             case NumberKind::kUnsigned:
258                 return true;
259             default:
260                 return false;
261         }
262     }
263 
264     /**
265      * Returns true if this is a floating-point scalar type (float or half).
266      */
isFloat()267     bool isFloat() const {
268         return this->numberKind() == NumberKind::kFloat;
269     }
270 
271     /**
272      * Returns true if this is a signed scalar type (int or short).
273      */
isSigned()274     bool isSigned() const {
275         return this->numberKind() == NumberKind::kSigned;
276     }
277 
278     /**
279      * Returns true if this is an unsigned scalar type (uint or ushort).
280      */
isUnsigned()281     bool isUnsigned() const {
282         return this->numberKind() == NumberKind::kUnsigned;
283     }
284 
285     /**
286      * Returns true if this is a signed or unsigned integer.
287      */
isInteger()288     bool isInteger() const {
289         switch (this->numberKind()) {
290             case NumberKind::kSigned:
291             case NumberKind::kUnsigned:
292                 return true;
293             default:
294                 return false;
295         }
296     }
297 
298     /**
299      * Returns true if this is an "opaque type" (an external object which the shader references in
300      * some fashion). https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)#Opaque_types
301      */
isOpaque()302     bool isOpaque() const {
303         switch (fTypeKind) {
304             case TypeKind::kBlender:
305             case TypeKind::kColorFilter:
306             case TypeKind::kSampler:
307             case TypeKind::kSeparateSampler:
308             case TypeKind::kShader:
309             case TypeKind::kTexture:
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 
isStruct()453     virtual bool isStruct() const {
454         return false;
455     }
456 
isInterfaceBlock()457     virtual bool isInterfaceBlock() const {
458         return false;
459     }
460 
461     // Is this type something that can be bound & sampled from an SkRuntimeEffect?
462     // Includes types that represent stages of the Skia pipeline (colorFilter, shader, blender).
isEffectChild()463     bool isEffectChild() const {
464         return fTypeKind == TypeKind::kColorFilter ||
465                fTypeKind == TypeKind::kShader ||
466                fTypeKind == TypeKind::kBlender;
467     }
468 
isMultisampled()469     virtual bool isMultisampled() const {
470         SkASSERT(false);
471         return false;
472     }
473 
isSampled()474     virtual bool isSampled() const {
475         SkASSERT(false);
476         return false;
477     }
478 
hasPrecision()479     bool hasPrecision() const {
480         return this->componentType().isNumber() || fTypeKind == TypeKind::kSampler;
481     }
482 
highPrecision()483     bool highPrecision() const {
484         return this->bitWidth() >= 32;
485     }
486 
bitWidth()487     virtual int bitWidth() const {
488         return 0;
489     }
490 
491     bool isOrContainsArray() const;
492 
493     /**
494      * Returns true if this type is a struct that is too deeply nested.
495      */
496     bool isTooDeeplyNested() const;
497 
498     /**
499      * Returns the corresponding vector or matrix type with the specified number of columns and
500      * rows.
501      */
502     const Type& toCompound(const Context& context, int columns, int rows) const;
503 
504     /**
505      * Returns a type which honors the precision qualifiers set in Modifiers. e.g., kMediump_Flag
506      * when applied to `float2` will return `half2`. Generates an error if the precision qualifiers
507      * don't make sense, e.g. `highp bool` or `mediump MyStruct`.
508      */
509     const Type* applyPrecisionQualifiers(const Context& context,
510                                          Modifiers* modifiers,
511                                          SymbolTable* symbols,
512                                          int line) const;
513 
514     /**
515      * Coerces the passed-in expression to this type. If the types are incompatible, reports an
516      * error and returns null.
517      */
518     std::unique_ptr<Expression> coerceExpression(std::unique_ptr<Expression> expr,
519                                                  const Context& context) const;
520 
521     /** Detects any IntLiterals in the expression which can't fit in this type. */
522     bool checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const;
523 
524     /** Checks if `value` can fit in this type. The type must be scalar. */
525     bool checkForOutOfRangeLiteral(const Context& context, double value, int line) const;
526 
527     /**
528      * Verifies that the expression is a valid constant array size for this type. Returns the array
529      * size, or zero if the expression isn't a valid literal value.
530      */
531     SKSL_INT convertArraySize(const Context& context, std::unique_ptr<Expression> size) const;
532 
533 protected:
534     Type(std::string_view name, const char* abbrev, TypeKind kind, int line = -1)
INHERITED(line,kSymbolKind,name)535         : INHERITED(line, kSymbolKind, name)
536         , fTypeKind(kind) {
537         SkASSERT(strlen(abbrev) <= kMaxAbbrevLength);
538         strcpy(fAbbreviatedName, abbrev);
539     }
540 
541 private:
542     bool isTooDeeplyNested(int limit) const;
543 
544     using INHERITED = Symbol;
545 
546     char fAbbreviatedName[kMaxAbbrevLength + 1] = {};
547     TypeKind fTypeKind;
548 };
549 
550 }  // namespace SkSL
551 
552 #endif
553