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