xref: /aosp_15_r20/external/skia/src/sksl/ir/SkSLType.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/base/SkTArray.h"
14 #include "src/sksl/SkSLDefines.h"
15 #include "src/sksl/SkSLPosition.h"
16 #include "src/sksl/ir/SkSLIRNode.h"
17 #include "src/sksl/ir/SkSLLayout.h"
18 #include "src/sksl/ir/SkSLModifierFlags.h"
19 #include "src/sksl/ir/SkSLSymbol.h"
20 #include "src/sksl/spirv.h"
21 
22 #include <cmath>
23 #include <cstddef>
24 #include <cstdint>
25 #include <cstring>
26 #include <memory>
27 #include <string>
28 #include <string_view>
29 #include <tuple>
30 
31 namespace SkSL {
32 
33 class Context;
34 class Expression;
35 class SymbolTable;
36 class Type;
37 
38 struct CoercionCost {
FreeCoercionCost39     static CoercionCost Free()              { return {    0,    0, false }; }
NormalCoercionCost40     static CoercionCost Normal(int cost)    { return { cost,    0, false }; }
NarrowingCoercionCost41     static CoercionCost Narrowing(int cost) { return {    0, cost, false }; }
ImpossibleCoercionCost42     static CoercionCost Impossible()        { return {    0,    0,  true }; }
43 
isPossibleCoercionCost44     bool isPossible(bool allowNarrowing) const {
45         return !fImpossible && (fNarrowingCost == 0 || allowNarrowing);
46     }
47 
48     // Addition of two costs. Saturates at Impossible().
49     CoercionCost operator+(CoercionCost rhs) const {
50         if (fImpossible || rhs.fImpossible) {
51             return Impossible();
52         }
53         return { fNormalCost + rhs.fNormalCost, fNarrowingCost + rhs.fNarrowingCost, false };
54     }
55 
56     bool operator<(CoercionCost rhs) const {
57         return std::tie(    fImpossible,     fNarrowingCost,     fNormalCost) <
58                std::tie(rhs.fImpossible, rhs.fNarrowingCost, rhs.fNormalCost);
59     }
60 
61     bool operator<=(CoercionCost rhs) const {
62         return std::tie(    fImpossible,     fNarrowingCost,     fNormalCost) <=
63                std::tie(rhs.fImpossible, rhs.fNarrowingCost, rhs.fNormalCost);
64     }
65 
66     int  fNormalCost;
67     int  fNarrowingCost;
68     bool fImpossible;
69 };
70 
71 /**
72  * Represents a single field in a struct type.
73  */
74 struct Field {
FieldField75     Field(Position pos, Layout layout, ModifierFlags flags, std::string_view name, const Type* type)
76             : fPosition(pos)
77             , fLayout(layout)
78             , fModifierFlags(flags)
79             , fName(name)
80             , fType(type) {}
81 
82     std::string description() const;
83 
84     Position fPosition;
85     Layout fLayout;
86     ModifierFlags fModifierFlags;
87     std::string_view fName;
88     const Type* fType;
89 };
90 
91 /**
92  * Represents a type, such as int or float4.
93  */
94 class Type : public Symbol {
95 public:
96     inline static constexpr Kind kIRNodeKind = Kind::kType;
97     inline static constexpr int kMaxAbbrevLength = 3;
98     // Represents unspecified array dimensions, as in `int[]`.
99     inline static constexpr int kUnsizedArray = -1;
100 
101     enum class TypeKind : int8_t {
102         kArray,
103         kAtomic,
104         kGeneric,
105         kLiteral,
106         kMatrix,
107         kOther,
108         kSampler,
109         kSeparateSampler,
110         kScalar,
111         kStruct,
112         kTexture,
113         kVector,
114         kVoid,
115 
116         // Types that represent stages in the Skia pipeline
117         kColorFilter,
118         kShader,
119         kBlender,
120     };
121 
122     enum class NumberKind : int8_t {
123         kFloat,
124         kSigned,
125         kUnsigned,
126         kBoolean,
127         kNonnumeric
128     };
129 
130     enum class TextureAccess : int8_t {
131         kSample,  // `kSample` access level allows both sampling and reading
132         kRead,
133         kWrite,
134         kReadWrite,
135     };
136 
137     Type(const Type& other) = delete;
138 
139     /** Creates an array type. `columns` may be kUnsizedArray. */
140     static std::unique_ptr<Type> MakeArrayType(const Context& context, std::string_view name,
141                                                const Type& componentType, int columns);
142 
143     /** Converts a component type and a size (float, 10) into an array name ("float[10]"). */
144     std::string getArrayName(int arraySize) const;
145 
146     /**
147      * Creates an alias which maps to another type.
148      */
149     static std::unique_ptr<Type> MakeAliasType(std::string_view name, const Type& targetType);
150 
151     /**
152      * Create a generic type which maps to the listed types--e.g. $genType is a generic type which
153      * can match float, float2, float3 or float4.
154      */
155     static std::unique_ptr<Type> MakeGenericType(const char* name,
156                                                  SkSpan<const Type* const> types,
157                                                  const Type* slotType);
158 
159     /** Create a type for literal scalars. */
160     static std::unique_ptr<Type> MakeLiteralType(const char* name, const Type& scalarType,
161                                                  int8_t priority);
162 
163     /** Create a matrix type. */
164     static std::unique_ptr<Type> MakeMatrixType(std::string_view name, const char* abbrev,
165                                                 const Type& componentType, int columns,
166                                                 int8_t rows);
167 
168     /** Create a sampler type. */
169     static std::unique_ptr<Type> MakeSamplerType(const char* name, const Type& textureType);
170 
171     /** Create a scalar type. */
172     static std::unique_ptr<Type> MakeScalarType(std::string_view name, const char* abbrev,
173                                                 Type::NumberKind numberKind, int8_t priority,
174                                                 int8_t bitWidth);
175 
176     /**
177      * Create a "special" type with the given name, abbreviation, and TypeKind.
178      */
179     static std::unique_ptr<Type> MakeSpecialType(const char* name, const char* abbrev,
180                                                  Type::TypeKind typeKind);
181 
182     /**
183      * Creates a struct type with the given fields. Reports an error if the struct is not
184      * well-formed.
185      */
186     static std::unique_ptr<Type> MakeStructType(const Context& context,
187                                                 Position pos,
188                                                 std::string_view name,
189                                                 skia_private::TArray<Field> fields,
190                                                 bool interfaceBlock = false);
191 
192     /** Create a texture type. */
193     static std::unique_ptr<Type> MakeTextureType(const char* name, SpvDim_ dimensions, bool isDepth,
194                                                  bool isArrayedTexture, bool isMultisampled,
195                                                  TextureAccess textureAccess);
196 
197     /** Create a vector type. */
198     static std::unique_ptr<Type> MakeVectorType(std::string_view name, const char* abbrev,
199                                                 const Type& componentType, int columns);
200 
201     /** Create an atomic type. */
202     static std::unique_ptr<Type> MakeAtomicType(std::string_view name, const char* abbrev);
203 
204     template <typename T>
is()205     bool is() const {
206         return this->typeKind() == T::kTypeKind;
207     }
208 
209     template <typename T>
as()210     const T& as() const {
211         SkASSERT(this->is<T>());
212         return static_cast<const T&>(*this);
213     }
214 
215     template <typename T>
as()216     T& as() {
217         SkASSERT(this->is<T>());
218         return static_cast<T&>(*this);
219     }
220 
221     /** Creates a clone of this Type, if needed, and inserts it into a different symbol table. */
222     const Type* clone(const Context& context, SymbolTable* symbolTable) const;
223 
224     /**
225      * Returns true if this type is known to come from BuiltinTypes, or is declared in a module. If
226      * this returns true, the Type will always be available in the root SymbolTable and never needs
227      * to be copied to migrate an Expression from one location to another. If it returns false, the
228      * Type might not exist in a separate SymbolTable and you'll need to consider cloning it.
229      */
isBuiltin()230     virtual bool isBuiltin() const {
231         return true;
232     }
233 
displayName()234     std::string displayName() const {
235         return std::string(this->scalarTypeForLiteral().name());
236     }
237 
description()238     std::string description() const override {
239         return this->displayName();
240     }
241 
242     /** Returns true if the program supports this type. Strict ES2 programs can't use ES3 types. */
243     bool isAllowedInES2(const Context& context) const;
244 
245     /** Returns true if this type is legal to use in a strict-ES2 program. */
isAllowedInES2()246     virtual bool isAllowedInES2() const {
247         return true;
248     }
249 
250     /**
251      * Returns true if this type is legal to use as a uniform. If false is returned, the
252      * `errorPosition` field may be populated; if it is, this position can be used to emit an extra
253      * diagnostic "caused by: <a field>" for nested types.
254      * Note that runtime effects enforce additional, much stricter rules about uniforms; these
255      * limitations are not handled here.
256      */
257     virtual bool isAllowedInUniform(Position* errorPosition = nullptr) const {
258         // We don't allow samplers, textures or atomics to be marked as uniforms.
259         // This rules out all opaque types.
260         return !this->isOpaque();
261     }
262 
263     /** If this is an alias, returns the underlying type, otherwise returns this. */
resolve()264     virtual const Type& resolve() const {
265         return *this;
266     }
267 
268     /** Returns true if these types are equal after alias resolution. */
matches(const Type & that)269     virtual bool matches(const Type& that) const {
270         return &this->resolve() == &that.resolve();
271     }
272 
273     /**
274      * Returns an abbreviated name of the type, meant for name-mangling. (e.g. float4x4 -> f44)
275      */
abbreviatedName()276     const char* abbreviatedName() const {
277         return fAbbreviatedName;
278     }
279 
280     /**
281      * Returns the category (scalar, vector, matrix, etc.) of this type.
282      */
typeKind()283     TypeKind typeKind() const {
284         return fTypeKind;
285     }
286 
287     /**
288      * Returns the NumberKind of this type (always kNonnumeric for non-scalar values).
289      */
numberKind()290     virtual NumberKind numberKind() const {
291         return NumberKind::kNonnumeric;
292     }
293 
294     /**
295      * Returns true if this type is a bool.
296      */
isBoolean()297     bool isBoolean() const {
298         return this->numberKind() == NumberKind::kBoolean;
299     }
300 
301     /**
302      * Returns true if this is a numeric scalar type.
303      */
isNumber()304     bool isNumber() const {
305         switch (this->numberKind()) {
306             case NumberKind::kFloat:
307             case NumberKind::kSigned:
308             case NumberKind::kUnsigned:
309                 return true;
310             default:
311                 return false;
312         }
313     }
314 
315     /**
316      * Returns true if this is a floating-point scalar type (float or half).
317      */
isFloat()318     bool isFloat() const {
319         return this->numberKind() == NumberKind::kFloat;
320     }
321 
322     /**
323      * Returns true if this is a signed scalar type (int or short).
324      */
isSigned()325     bool isSigned() const {
326         return this->numberKind() == NumberKind::kSigned;
327     }
328 
329     /**
330      * Returns true if this is an unsigned scalar type (uint or ushort).
331      */
isUnsigned()332     bool isUnsigned() const {
333         return this->numberKind() == NumberKind::kUnsigned;
334     }
335 
336     /**
337      * Returns true if this is a signed or unsigned integer.
338      */
isInteger()339     bool isInteger() const {
340         switch (this->numberKind()) {
341             case NumberKind::kSigned:
342             case NumberKind::kUnsigned:
343                 return true;
344             default:
345                 return false;
346         }
347     }
348 
349     /**
350      * Returns true if this is an "opaque type" (an external object which the shader references in
351      * some fashion). https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)#Opaque_types
352      */
isOpaque()353     bool isOpaque() const {
354         switch (fTypeKind) {
355             case TypeKind::kAtomic:
356             case TypeKind::kBlender:
357             case TypeKind::kColorFilter:
358             case TypeKind::kSampler:
359             case TypeKind::kSeparateSampler:
360             case TypeKind::kShader:
361             case TypeKind::kTexture:
362                 return true;
363             default:
364                 return false;
365         }
366     }
367 
368     /**
369      * Returns true if this is a storage texture.
370      */
isStorageTexture()371     bool isStorageTexture() const {
372         return fTypeKind == TypeKind::kTexture && this->dimensions() != SpvDimSubpassData;
373     }
374 
375     /**
376      * Returns the "priority" of a number type, in order of float > half > int > short.
377      * When operating on two number types, the result is the higher-priority type.
378      */
priority()379     virtual int priority() const {
380         SkDEBUGFAIL("not a number type");
381         return -1;
382     }
383 
384     /**
385      * Returns true if an instance of this type can be freely coerced (implicitly converted) to
386      * another type.
387      */
canCoerceTo(const Type & other,bool allowNarrowing)388     bool canCoerceTo(const Type& other, bool allowNarrowing) const {
389         return this->coercionCost(other).isPossible(allowNarrowing);
390     }
391 
392     /**
393      * Determines the "cost" of coercing (implicitly converting) this type to another type. The cost
394      * is a number with no particular meaning other than that lower costs are preferable to higher
395      * costs. Returns INT_MAX if the coercion is not possible.
396      */
397     CoercionCost coercionCost(const Type& other) const;
398 
399     /**
400      * For matrices and vectors, returns the type of individual cells (e.g. mat2 has a component
401      * type of Float). For arrays, returns the base type. For all other types, returns the type
402      * itself.
403      */
componentType()404     virtual const Type& componentType() const {
405         return *this;
406     }
407 
408     /**
409      * For matrix types, returns the type of a single column (`m[n]`). Asserts for all other types.
410      */
columnType(const Context & context)411     const Type& columnType(const Context& context) const {
412         return this->componentType().toCompound(context, this->rows(), /*rows=*/1);
413     }
414 
415     /**
416      * For texture samplers, returns the type of texture it samples (e.g., sampler2D has
417      * a texture type of texture2D).
418      */
textureType()419     virtual const Type& textureType() const {
420         SkDEBUGFAIL("not a sampler type");
421         return *this;
422     }
423 
424     /**
425      * For matrices and vectors, returns the number of columns (e.g. both mat3 and float3 return 3).
426      * For scalars, returns 1. For arrays, returns either the size of the array (if known) or -1.
427      * For all other types, causes an assertion failure.
428      */
columns()429     virtual int columns() const {
430         SkDEBUGFAIL("type does not have columns");
431         return -1;
432     }
433 
434     /**
435      * For matrices, returns the number of rows (e.g. mat2x4 returns 4). For vectors and scalars,
436      * returns 1. For all other types, causes an assertion failure.
437      */
rows()438     virtual int rows() const {
439         SkDEBUGFAIL("type does not have rows");
440         return -1;
441     }
442 
443     /** Returns the minimum value that can fit in the type. */
minimumValue()444     virtual double minimumValue() const {
445         SkDEBUGFAIL("type does not have a minimum value");
446         return -INFINITY;
447     }
448 
maximumValue()449     virtual double maximumValue() const {
450         SkDEBUGFAIL("type does not have a maximum value");
451         return +INFINITY;
452     }
453 
454     /**
455      * Returns the number of scalars needed to hold this type.
456      */
slotCount()457     virtual size_t slotCount() const {
458         return 0;
459     }
460 
461     /**
462      * Returns the type of the value in the nth slot. For scalar, vector and matrix types, should
463      * always match `componentType()`.
464      */
slotType(size_t)465     virtual const Type& slotType(size_t) const {
466         return *this;
467     }
468 
fields()469     virtual SkSpan<const Field> fields() const {
470         SK_ABORT("Internal error: not a struct");
471     }
472 
473     /**
474      * For generic types, returns the types that this generic type can substitute for.
475      */
coercibleTypes()476     virtual SkSpan<const Type* const> coercibleTypes() const {
477         SkDEBUGFAIL("Internal error: not a generic type");
478         return {};
479     }
480 
dimensions()481     virtual SpvDim_ dimensions() const {
482         SkDEBUGFAIL("Internal error: not a texture type");
483         return SpvDim1D;
484     }
485 
isDepth()486     virtual bool isDepth() const {
487         SkDEBUGFAIL("Internal error: not a texture type");
488         return false;
489     }
490 
isArrayedTexture()491     virtual bool isArrayedTexture() const {
492         SkDEBUGFAIL("Internal error: not a texture type");
493         return false;
494     }
495 
isVoid()496     bool isVoid() const {
497         return fTypeKind == TypeKind::kVoid;
498     }
499 
isGeneric()500     bool isGeneric() const {
501         return fTypeKind == TypeKind::kGeneric;
502     }
503 
isSampler()504     bool isSampler() const {
505         return fTypeKind == TypeKind::kSampler;
506     }
507 
isAtomic()508     bool isAtomic() const {
509         return this->typeKind() == TypeKind::kAtomic;
510     }
511 
isScalar()512     virtual bool isScalar() const {
513         return false;
514     }
515 
isLiteral()516     virtual bool isLiteral() const {
517         return false;
518     }
519 
scalarTypeForLiteral()520     virtual const Type& scalarTypeForLiteral() const {
521         return *this;
522     }
523 
isVector()524     virtual bool isVector() const {
525         return false;
526     }
527 
isMatrix()528     virtual bool isMatrix() const {
529         return false;
530     }
531 
isArray()532     virtual bool isArray() const {
533         return false;
534     }
535 
isUnsizedArray()536     virtual bool isUnsizedArray() const {
537         return false;
538     }
539 
isStruct()540     virtual bool isStruct() const {
541         return false;
542     }
543 
isInterfaceBlock()544     virtual bool isInterfaceBlock() const {
545         return false;
546     }
547 
548     // Is this type something that can be bound & sampled from an SkRuntimeEffect?
549     // Includes types that represent stages of the Skia pipeline (colorFilter, shader, blender).
isEffectChild()550     bool isEffectChild() const {
551         return fTypeKind == TypeKind::kColorFilter ||
552                fTypeKind == TypeKind::kShader ||
553                fTypeKind == TypeKind::kBlender;
554     }
555 
isMultisampled()556     virtual bool isMultisampled() const {
557         SkDEBUGFAIL("not a texture type");
558         return false;
559     }
560 
textureAccess()561     virtual TextureAccess textureAccess() const {
562         SkDEBUGFAIL("not a texture type");
563         return TextureAccess::kSample;
564     }
565 
hasPrecision()566     bool hasPrecision() const {
567         return this->componentType().isNumber() || this->isSampler();
568     }
569 
highPrecision()570     bool highPrecision() const {
571         return this->bitWidth() >= 32;
572     }
573 
bitWidth()574     virtual int bitWidth() const {
575         return 0;
576     }
577 
isOrContainsArray()578     virtual bool isOrContainsArray() const {
579         return false;
580     }
581 
isOrContainsUnsizedArray()582     virtual bool isOrContainsUnsizedArray() const {
583         return false;
584     }
585 
isOrContainsAtomic()586     virtual bool isOrContainsAtomic() const {
587         return false;
588     }
589 
isOrContainsBool()590     virtual bool isOrContainsBool() const {
591         return false;
592     }
593 
594     /**
595      * Returns the corresponding vector or matrix type with the specified number of columns and
596      * rows.
597      */
598     const Type& toCompound(const Context& context, int columns, int rows) const;
599 
600     /**
601      * Returns a type which honors the precision and access-level qualifiers set in ModifierFlags.
602      * For example:
603      *  - Modifier `mediump` + Type `float2`:     Type `half2`
604      *  - Modifier `readonly` + Type `texture2D`: Type `readonlyTexture2D`
605      * Generates an error if the qualifiers don't make sense (`highp bool`, `writeonly MyStruct`)
606      */
607     const Type* applyQualifiers(const Context& context,
608                                 ModifierFlags* modifierFlags,
609                                 Position pos) const;
610 
611     /**
612      * Coerces the passed-in expression to this type. If the types are incompatible, reports an
613      * error and returns null.
614      */
615     std::unique_ptr<Expression> coerceExpression(std::unique_ptr<Expression> expr,
616                                                  const Context& context) const;
617 
618     /** Detects any IntLiterals in the expression which can't fit in this type. */
619     bool checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const;
620 
621     /** Checks if `value` can fit in this type. The type must be scalar. */
622     bool checkForOutOfRangeLiteral(const Context& context, double value, Position pos) const;
623 
624     /**
625      * Reports errors and returns false if this type cannot be used as the base type for an array.
626      */
627     bool checkIfUsableInArray(const Context& context, Position arrayPos) const;
628 
629     /**
630      * Verifies that the expression is a valid constant array size for this type. Returns the array
631      * size, or reports errors and returns zero if the expression isn't a valid literal value.
632      */
633     SKSL_INT convertArraySize(const Context& context,
634                               Position arrayPos,
635                               std::unique_ptr<Expression> size) const;
636 
637     SKSL_INT convertArraySize(const Context& context,
638                               Position arrayPos,
639                               Position sizePos,
640                               SKSL_INT size) const;
641 
642 protected:
643     Type(std::string_view name, const char* abbrev, TypeKind kind, Position pos = Position())
INHERITED(pos,kIRNodeKind,name)644             : INHERITED(pos, kIRNodeKind, name)
645             , fTypeKind(kind) {
646         SkASSERT(strlen(abbrev) <= kMaxAbbrevLength);
647         strcpy(fAbbreviatedName, abbrev);
648     }
649 
650     const Type* applyPrecisionQualifiers(const Context& context,
651                                          ModifierFlags* modifierFlags,
652                                          Position pos) const;
653 
654     const Type* applyAccessQualifiers(const Context& context,
655                                       ModifierFlags* modifierFlags,
656                                       Position pos) const;
657 
658     /** Only structs and arrays can be created in code; all other types exist in the root. */
isInRootSymbolTable()659     bool isInRootSymbolTable() const {
660         return !(this->isArray() || this->isStruct());
661     }
662 
663     /** If the type is a struct, returns the depth of the struct's most deeply-nested field. */
structNestingDepth()664     virtual int structNestingDepth() const {
665         return 0;
666     }
667 
668 private:
669     using INHERITED = Symbol;
670 
671     char fAbbreviatedName[kMaxAbbrevLength + 1] = {};
672     TypeKind fTypeKind;
673 };
674 
675 }  // namespace SkSL
676 
677 #endif
678