Flutter Engine
The Flutter Engine
SkSLType.cpp
Go to the documentation of this file.
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
9
12#include "src/base/SkMathPriv.h"
13#include "src/base/SkSafeMath.h"
14#include "src/core/SkTHash.h"
20#include "src/sksl/SkSLString.h"
28
29#include <algorithm>
30#include <cstdint>
31#include <limits>
32#include <optional>
33#include <string_view>
34#include <utility>
35
36using namespace skia_private;
37
38namespace SkSL {
39
40static constexpr int kMaxStructDepth = 8;
41
42class AliasType final : public Type {
43public:
44 AliasType(std::string_view name, const Type& targetType)
45 : INHERITED(name, targetType.abbreviatedName(), targetType.typeKind())
46 , fTargetType(targetType) {}
47
48 const Type& resolve() const override {
49 return fTargetType;
50 }
51
52 const Type& componentType() const override {
53 return fTargetType.componentType();
54 }
55
56 NumberKind numberKind() const override {
57 return fTargetType.numberKind();
58 }
59
60 int priority() const override {
61 return fTargetType.priority();
62 }
63
64 int columns() const override {
65 return fTargetType.columns();
66 }
67
68 int rows() const override {
69 return fTargetType.rows();
70 }
71
72 int bitWidth() const override {
73 return fTargetType.bitWidth();
74 }
75
76 bool isAllowedInES2() const override {
77 return fTargetType.isAllowedInES2();
78 }
79
80 size_t slotCount() const override {
81 return fTargetType.slotCount();
82 }
83
84 const Type& slotType(size_t n) const override {
85 return fTargetType.slotType(n);
86 }
87
88 SpvDim_ dimensions() const override {
89 return fTargetType.dimensions();
90 }
91
92 bool isDepth() const override {
93 return fTargetType.isDepth();
94 }
95
96 bool isArrayedTexture() const override {
97 return fTargetType.isArrayedTexture();
98 }
99
100 bool isScalar() const override {
101 return fTargetType.isScalar();
102 }
103
104 bool isLiteral() const override {
105 return fTargetType.isLiteral();
106 }
107
108 bool isVector() const override {
109 return fTargetType.isVector();
110 }
111
112 bool isMatrix() const override {
113 return fTargetType.isMatrix();
114 }
115
116 bool isArray() const override {
117 return fTargetType.isArray();
118 }
119
120 bool isUnsizedArray() const override {
121 return fTargetType.isUnsizedArray();
122 }
123
124 bool isStruct() const override {
125 return fTargetType.isStruct();
126 }
127
128 bool isInterfaceBlock() const override {
129 return fTargetType.isInterfaceBlock();
130 }
131
132 bool isMultisampled() const override {
133 return fTargetType.isMultisampled();
134 }
135
136 TextureAccess textureAccess() const override {
137 return fTargetType.textureAccess();
138 }
139
141 return fTargetType.coercibleTypes();
142 }
143
144private:
145 using INHERITED = Type;
146
147 const Type& fTargetType;
148};
149
150class ArrayType final : public Type {
151public:
152 inline static constexpr TypeKind kTypeKind = TypeKind::kArray;
153
154 ArrayType(std::string_view name, const char* abbrev, const Type& componentType, int count,
155 bool isBuiltin)
156 : INHERITED(name, abbrev, kTypeKind)
157 , fComponentType(componentType)
158 , fCount(count)
159 , fIsBuiltin(isBuiltin) {
161 // Disallow multi-dimensional arrays.
163 }
164
165 bool isArray() const override {
166 return true;
167 }
168
169 bool isBuiltin() const override {
170 return fIsBuiltin;
171 }
172
173 bool isOrContainsArray() const override {
174 return true;
175 }
176
177 bool isOrContainsAtomic() const override {
178 return fComponentType.isOrContainsAtomic();
179 }
180
181 bool isUnsizedArray() const override {
182 return fCount == kUnsizedArray;
183 }
184
185 bool isOrContainsUnsizedArray() const override {
186 return this->isUnsizedArray() || fComponentType.isOrContainsUnsizedArray();
187 }
188
189 const Type& componentType() const override {
190 return fComponentType;
191 }
192
193 int columns() const override {
194 return fCount;
195 }
196
197 int bitWidth() const override {
198 return fComponentType.bitWidth();
199 }
200
201 bool isAllowedInES2() const override {
202 return fComponentType.isAllowedInES2();
203 }
204
205 bool isAllowedInUniform(Position* errorPosition) const override {
206 return fComponentType.isAllowedInUniform(errorPosition);
207 }
208
209 size_t slotCount() const override {
210 SkASSERT(fCount != kUnsizedArray);
211 SkASSERT(fCount > 0);
212 return fCount * fComponentType.slotCount();
213 }
214
215 const Type& slotType(size_t n) const override {
216 SkASSERT(fCount == kUnsizedArray || n < this->slotCount());
217 return fComponentType.slotType(n % fComponentType.slotCount());
218 }
219
220private:
221 using INHERITED = Type;
222
223 const Type& fComponentType;
224 int fCount;
225 bool fIsBuiltin;
226};
227
228class GenericType final : public Type {
229public:
230 inline static constexpr TypeKind kTypeKind = TypeKind::kGeneric;
231
233 : INHERITED(name, "G", kTypeKind)
234 , fSlotType(slotType) {
235 fNumTypes = coercibleTypes.size();
236 SkASSERT(fNumTypes <= std::size(fCoercibleTypes));
237 std::copy(coercibleTypes.begin(), coercibleTypes.end(), fCoercibleTypes);
238 }
239
241 return SkSpan(fCoercibleTypes, fNumTypes);
242 }
243
244 const Type& slotType(size_t) const override {
245 return *fSlotType;
246 }
247
248private:
249 using INHERITED = Type;
250
251 const Type* fCoercibleTypes[9];
252 const Type* fSlotType;
253 size_t fNumTypes;
254};
255
256class LiteralType : public Type {
257public:
258 inline static constexpr TypeKind kTypeKind = TypeKind::kLiteral;
259
260 LiteralType(const char* name, const Type& scalarType, int8_t priority)
261 : INHERITED(name, "L", kTypeKind)
262 , fScalarType(scalarType)
263 , fPriority(priority) {}
264
265 const Type& scalarTypeForLiteral() const override {
266 return fScalarType;
267 }
268
269 int priority() const override {
270 return fPriority;
271 }
272
273 int columns() const override {
274 return 1;
275 }
276
277 int rows() const override {
278 return 1;
279 }
280
281 NumberKind numberKind() const override {
282 return fScalarType.numberKind();
283 }
284
285 int bitWidth() const override {
286 return fScalarType.bitWidth();
287 }
288
289 double minimumValue() const override {
290 return fScalarType.minimumValue();
291 }
292
293 double maximumValue() const override {
294 return fScalarType.maximumValue();
295 }
296
297 bool isScalar() const override {
298 return true;
299 }
300
301 bool isLiteral() const override {
302 return true;
303 }
304
305 size_t slotCount() const override {
306 return 1;
307 }
308
309 const Type& slotType(size_t n) const override {
310 SkASSERT(n == 0);
311 return fScalarType;
312 }
313
314private:
315 using INHERITED = Type;
316
317 const Type& fScalarType;
318 int8_t fPriority;
319};
320
321
322class ScalarType final : public Type {
323public:
324 inline static constexpr TypeKind kTypeKind = TypeKind::kScalar;
325
326 ScalarType(std::string_view name, const char* abbrev, NumberKind numberKind, int8_t priority,
327 int8_t bitWidth)
328 : INHERITED(name, abbrev, kTypeKind)
329 , fNumberKind(numberKind)
330 , fPriority(priority)
331 , fBitWidth(bitWidth) {}
332
333 NumberKind numberKind() const override {
334 return fNumberKind;
335 }
336
337 int priority() const override {
338 return fPriority;
339 }
340
341 int bitWidth() const override {
342 return fBitWidth;
343 }
344
345 int columns() const override {
346 return 1;
347 }
348
349 int rows() const override {
350 return 1;
351 }
352
353 bool isScalar() const override {
354 return true;
355 }
356
357 bool isAllowedInES2() const override {
358 return fNumberKind != NumberKind::kUnsigned;
359 }
360
361 bool isAllowedInUniform(Position*) const override {
362 return fNumberKind != NumberKind::kBoolean;
363 }
364
365 size_t slotCount() const override {
366 return 1;
367 }
368
369 const Type& slotType(size_t n) const override {
370 SkASSERT(n == 0);
371 return *this;
372 }
373
374 using int_limits = std::numeric_limits<int32_t>;
375 using short_limits = std::numeric_limits<int16_t>;
376 using uint_limits = std::numeric_limits<uint32_t>;
377 using ushort_limits = std::numeric_limits<uint16_t>;
378 using float_limits = std::numeric_limits<float>;
379
380 /** Returns the maximum value that can fit in the type. */
381 double minimumValue() const override {
382 switch (this->numberKind()) {
384 return this->highPrecision() ? int_limits::lowest()
385 : short_limits::lowest();
386
388 return 0;
389
391 default:
392 return float_limits::lowest();
393 }
394 }
395
396 /** Returns the maximum value that can fit in the type. */
397 double maximumValue() const override {
398 switch (this->numberKind()) {
400 return this->highPrecision() ? int_limits::max()
402
404 return this->highPrecision() ? uint_limits::max()
406
408 default:
409 return float_limits::max();
410 }
411 }
412
413private:
414 using INHERITED = Type;
415
416 NumberKind fNumberKind;
417 int8_t fPriority;
418 int8_t fBitWidth;
419};
420
421class AtomicType final : public Type {
422public:
423 inline static constexpr TypeKind kTypeKind = TypeKind::kAtomic;
424
425 AtomicType(std::string_view name, const char* abbrev) : INHERITED(name, abbrev, kTypeKind) {}
426
427 bool isAllowedInES2() const override { return false; }
428
429 bool isAllowedInUniform(Position*) const override { return false; }
430
431 bool isOrContainsAtomic() const override { return true; }
432
433 const Type& slotType(size_t n) const override {
434 SkASSERT(n == 0);
435 return *this;
436 }
437
438private:
439 using INHERITED = Type;
440};
441
442class MatrixType final : public Type {
443public:
444 inline static constexpr TypeKind kTypeKind = TypeKind::kMatrix;
445
446 MatrixType(std::string_view name, const char* abbrev, const Type& componentType,
447 int8_t columns, int8_t rows)
448 : INHERITED(name, abbrev, kTypeKind)
449 , fComponentType(componentType.as<ScalarType>())
450 , fColumns(columns)
451 , fRows(rows) {
452 SkASSERT(columns >= 2 && columns <= 4);
453 SkASSERT(rows >= 2 && rows <= 4);
454 }
455
456 const ScalarType& componentType() const override {
457 return fComponentType;
458 }
459
460 int columns() const override {
461 return fColumns;
462 }
463
464 int rows() const override {
465 return fRows;
466 }
467
468 int bitWidth() const override {
469 return this->componentType().bitWidth();
470 }
471
472 bool isMatrix() const override {
473 return true;
474 }
475
476 bool isAllowedInES2() const override {
477 return fColumns == fRows;
478 }
479
480 size_t slotCount() const override {
481 return fColumns * fRows;
482 }
483
484 const Type& slotType(size_t n) const override {
485 SkASSERT(n < this->slotCount());
486 return fComponentType;
487 }
488
489private:
490 using INHERITED = Type;
491
492 const ScalarType& fComponentType;
493 int8_t fColumns;
494 int8_t fRows;
495};
496
497class TextureType final : public Type {
498public:
499 inline static constexpr TypeKind kTypeKind = TypeKind::kTexture;
500
501 TextureType(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed,
503 : INHERITED(name, "T", kTypeKind)
504 , fDimensions(dimensions)
505 , fIsDepth(isDepth)
506 , fIsArrayed(isArrayed)
507 , fIsMultisampled(isMultisampled)
508 , fTextureAccess(textureAccess) {}
509
510 SpvDim_ dimensions() const override {
511 return fDimensions;
512 }
513
514 bool isDepth() const override {
515 return fIsDepth;
516 }
517
518 bool isArrayedTexture() const override {
519 return fIsArrayed;
520 }
521
522 bool isMultisampled() const override {
523 return fIsMultisampled;
524 }
525
526 TextureAccess textureAccess() const override {
527 return fTextureAccess;
528 }
529
530 const Type& slotType(size_t n) const override {
531 SkASSERT(n == 0);
532 return *this;
533 }
534
535private:
536 using INHERITED = Type;
537
538 SpvDim_ fDimensions;
539 bool fIsDepth;
540 bool fIsArrayed;
541 bool fIsMultisampled;
542 TextureAccess fTextureAccess;
543};
544
545class SamplerType final : public Type {
546public:
547 inline static constexpr TypeKind kTypeKind = TypeKind::kSampler;
548
549 SamplerType(const char* name, const Type& textureType)
550 : INHERITED(name, "Z", kTypeKind)
551 , fTextureType(textureType.as<TextureType>()) {
552 // Samplers require sampled texture access.
554 // Subpass inputs cannot be sampled.
556 }
557
558 const TextureType& textureType() const override {
559 return fTextureType;
560 }
561
562 SpvDim_ dimensions() const override {
563 return fTextureType.dimensions();
564 }
565
566 bool isDepth() const override {
567 return fTextureType.isDepth();
568 }
569
570 bool isArrayedTexture() const override {
571 return fTextureType.isArrayedTexture();
572 }
573
574 bool isMultisampled() const override {
575 return fTextureType.isMultisampled();
576 }
577
578 TextureAccess textureAccess() const override {
579 return fTextureType.textureAccess();
580 }
581
582 const Type& slotType(size_t n) const override {
583 SkASSERT(n == 0);
584 return *this;
585 }
586
587private:
588 using INHERITED = Type;
589
590 const TextureType& fTextureType;
591};
592
593class StructType final : public Type {
594public:
595 inline static constexpr TypeKind kTypeKind = TypeKind::kStruct;
596
597 StructType(Position pos, std::string_view name, TArray<Field> fields, int nestingDepth,
598 bool interfaceBlock, bool isBuiltin)
599 : INHERITED(std::move(name), "S", kTypeKind, pos)
600 , fFields(std::move(fields))
601 , fNestingDepth(nestingDepth)
602 , fInterfaceBlock(interfaceBlock)
603 , fIsBuiltin(isBuiltin) {
604 for (const Field& f : fFields) {
605 fContainsArray = fContainsArray || f.fType->isOrContainsArray();
606 fContainsUnsizedArray = fContainsUnsizedArray || f.fType->isOrContainsUnsizedArray();
607 fContainsAtomic = fContainsAtomic || f.fType->isOrContainsAtomic();
608 fIsAllowedInES2 = fIsAllowedInES2 && f.fType->isAllowedInES2();
609 }
610 for (const Field& f : fFields) {
611 Position errorPosition = f.fPosition;
612 if (!f.fType->isAllowedInUniform(&errorPosition)) {
613 fUniformErrorPosition = errorPosition;
614 break;
615 }
616 }
617 if (!fContainsUnsizedArray) {
618 for (const Field& f : fFields) {
619 fSlotCount += f.fType->slotCount();
620 }
621 }
622 }
623
624 SkSpan<const Field> fields() const override {
625 return fFields;
626 }
627
628 bool isStruct() const override {
629 return true;
630 }
631
632 bool isInterfaceBlock() const override {
633 return fInterfaceBlock;
634 }
635
636 bool isBuiltin() const override {
637 return fIsBuiltin;
638 }
639
640 bool isAllowedInES2() const override {
641 return fIsAllowedInES2;
642 }
643
644 bool isAllowedInUniform(Position* errorPosition) const override {
645 if (errorPosition != nullptr) {
646 *errorPosition = fUniformErrorPosition;
647 }
648 return !fUniformErrorPosition.valid();
649 }
650
651 bool isOrContainsArray() const override {
652 return fContainsArray;
653 }
654
655 bool isOrContainsUnsizedArray() const override {
656 return fContainsUnsizedArray;
657 }
658
659 bool isOrContainsAtomic() const override {
660 return fContainsAtomic;
661 }
662
663 size_t slotCount() const override {
664 SkASSERT(!fContainsUnsizedArray);
665 return fSlotCount;
666 }
667
668 int structNestingDepth() const override {
669 return fNestingDepth;
670 }
671
672 const Type& slotType(size_t n) const override {
673 for (const Field& field : fFields) {
674 size_t fieldSlots = field.fType->slotCount();
675 if (n < fieldSlots) {
676 return field.fType->slotType(n);
677 } else {
678 n -= fieldSlots;
679 }
680 }
681 SkDEBUGFAIL("slot index out of range");
682 return *this;
683 }
684
685private:
686 using INHERITED = Type;
687
688 TArray<Field> fFields;
689 size_t fSlotCount = 0;
690 int fNestingDepth = 0;
691 Position fUniformErrorPosition = {};
692 bool fInterfaceBlock = false;
693 bool fContainsArray = false;
694 bool fContainsUnsizedArray = false;
695 bool fContainsAtomic = false;
696 bool fIsBuiltin = false;
697 bool fIsAllowedInES2 = true;
698};
699
700class VectorType final : public Type {
701public:
702 inline static constexpr TypeKind kTypeKind = TypeKind::kVector;
703
704 VectorType(std::string_view name, const char* abbrev, const Type& componentType,
705 int8_t columns)
706 : INHERITED(name, abbrev, kTypeKind)
707 , fComponentType(componentType.as<ScalarType>())
708 , fColumns(columns) {
709 SkASSERT(columns >= 2 && columns <= 4);
710 }
711
712 const ScalarType& componentType() const override {
713 return fComponentType;
714 }
715
716 int columns() const override {
717 return fColumns;
718 }
719
720 int rows() const override {
721 return 1;
722 }
723
724 int bitWidth() const override {
725 return this->componentType().bitWidth();
726 }
727
728 bool isVector() const override {
729 return true;
730 }
731
732 bool isAllowedInES2() const override {
733 return fComponentType.isAllowedInES2();
734 }
735
736 bool isAllowedInUniform(Position* errorPosition) const override {
737 return fComponentType.isAllowedInUniform(errorPosition);
738 }
739
740 size_t slotCount() const override {
741 return fColumns;
742 }
743
744 const Type& slotType(size_t n) const override {
745 SkASSERT(n < SkToSizeT(fColumns));
746 return fComponentType;
747 }
748
749private:
750 using INHERITED = Type;
751
752 const ScalarType& fComponentType;
753 int8_t fColumns;
754};
755
756std::string Type::getArrayName(int arraySize) const {
757 std::string_view name = this->name();
758 if (arraySize == kUnsizedArray) {
759 return String::printf("%.*s[]", (int)name.size(), name.data());
760 }
761 return String::printf("%.*s[%d]", (int)name.size(), name.data(), arraySize);
762}
763
764std::unique_ptr<Type> Type::MakeAliasType(std::string_view name, const Type& targetType) {
765 return std::make_unique<AliasType>(std::move(name), targetType);
766}
767
768std::unique_ptr<Type> Type::MakeArrayType(const Context& context,
769 std::string_view name,
770 const Type& componentType,
771 int columns) {
772 return std::make_unique<ArrayType>(std::move(name), componentType.abbreviatedName(),
773 componentType, columns, context.fConfig->fIsBuiltinCode);
774}
775
776std::unique_ptr<Type> Type::MakeGenericType(const char* name,
778 const Type* slotType) {
779 return std::make_unique<GenericType>(name, types, slotType);
780}
781
782std::unique_ptr<Type> Type::MakeLiteralType(const char* name, const Type& scalarType,
783 int8_t priority) {
784 return std::make_unique<LiteralType>(name, scalarType, priority);
785}
786
787std::unique_ptr<Type> Type::MakeMatrixType(std::string_view name, const char* abbrev,
788 const Type& componentType, int columns, int8_t rows) {
789 return std::make_unique<MatrixType>(name, abbrev, componentType, columns, rows);
790}
791
792std::unique_ptr<Type> Type::MakeSamplerType(const char* name, const Type& textureType) {
793 return std::make_unique<SamplerType>(name, textureType);
794}
795
796std::unique_ptr<Type> Type::MakeSpecialType(const char* name, const char* abbrev,
797 Type::TypeKind typeKind) {
798 return std::unique_ptr<Type>(new Type(name, abbrev, typeKind));
799}
800
801std::unique_ptr<Type> Type::MakeScalarType(std::string_view name, const char* abbrev,
802 Type::NumberKind numberKind, int8_t priority,
803 int8_t bitWidth) {
804 return std::make_unique<ScalarType>(name, abbrev, numberKind, priority, bitWidth);
805}
806
807std::unique_ptr<Type> Type::MakeAtomicType(std::string_view name, const char* abbrev) {
808 return std::make_unique<AtomicType>(name, abbrev);
809}
810
811std::unique_ptr<Type> Type::MakeStructType(const Context& context,
812 Position pos,
813 std::string_view name,
814 TArray<Field> fields,
815 bool interfaceBlock) {
816 const char* const structOrIB = interfaceBlock ? "interface block" : "struct";
817 const char* const aStructOrIB = interfaceBlock ? "an interface block" : "a struct";
818
819 if (fields.empty()) {
820 context.fErrors->error(pos, std::string(structOrIB) + " '" + std::string(name) +
821 "' must contain at least one field");
822 }
823 size_t slots = 0;
824
826 for (const Field& field : fields) {
827 // Add this field name to our set; if the set doesn't grow, we found a duplicate.
828 int numFieldNames = fieldNames.count();
829 fieldNames.add(field.fName);
830 if (fieldNames.count() == numFieldNames) {
831 context.fErrors->error(field.fPosition, "field '" + std::string(field.fName) +
832 "' was already defined in the same " +
833 std::string(structOrIB) + " ('" +
834 std::string(name) + "')");
835 }
836 if (field.fModifierFlags != ModifierFlag::kNone) {
837 std::string desc = field.fModifierFlags.description();
838 context.fErrors->error(field.fPosition, "modifier '" + desc + "' is not permitted on " +
839 std::string(aStructOrIB) + " field");
840 }
841 if (field.fLayout.fFlags & LayoutFlag::kBinding) {
842 context.fErrors->error(field.fPosition, "layout qualifier 'binding' is not permitted "
843 "on " + std::string(aStructOrIB) + " field");
844 }
845 if (field.fLayout.fFlags & LayoutFlag::kSet) {
846 context.fErrors->error(field.fPosition, "layout qualifier 'set' is not permitted on " +
847 std::string(aStructOrIB) + " field");
848 }
849
850 if (field.fType->isVoid()) {
851 context.fErrors->error(field.fPosition, "type 'void' is not permitted in " +
852 std::string(aStructOrIB));
853 }
854 if (field.fType->isOpaque() && !field.fType->isAtomic()) {
855 context.fErrors->error(field.fPosition, "opaque type '" + field.fType->displayName() +
856 "' is not permitted in " +
857 std::string(aStructOrIB));
858 }
859 if (field.fType->isOrContainsUnsizedArray()) {
860 if (!interfaceBlock) {
861 // Reject unsized arrays anywhere in structs.
862 context.fErrors->error(field.fPosition, "unsized arrays are not permitted here");
863 }
864 } else {
865 // If we haven't already exceeded the struct size limit...
866 if (slots < kVariableSlotLimit) {
867 // ... see if this field causes us to exceed the size limit.
868 slots = SkSafeMath::Add(slots, field.fType->slotCount());
869 if (slots >= kVariableSlotLimit) {
870 context.fErrors->error(pos, std::string(structOrIB) + " is too large");
871 }
872 }
873 }
874 }
875 int nestingDepth = 0;
876 for (const Field& field : fields) {
877 nestingDepth = std::max(nestingDepth, field.fType->structNestingDepth());
878 }
879 if (nestingDepth >= kMaxStructDepth) {
880 context.fErrors->error(pos, std::string(structOrIB) + " '" + std::string(name) +
881 "' is too deeply nested");
882 }
883 return std::make_unique<StructType>(pos, name, std::move(fields), nestingDepth + 1,
884 interfaceBlock, context.fConfig->fIsBuiltinCode);
885}
886
887std::unique_ptr<Type> Type::MakeTextureType(const char* name, SpvDim_ dimensions, bool isDepth,
888 bool isArrayedTexture, bool isMultisampled,
889 TextureAccess textureAccess) {
890 return std::make_unique<TextureType>(name, dimensions, isDepth, isArrayedTexture,
892}
893
894std::unique_ptr<Type> Type::MakeVectorType(std::string_view name, const char* abbrev,
895 const Type& componentType, int columns) {
896 return std::make_unique<VectorType>(name, abbrev, componentType, columns);
897}
898
899CoercionCost Type::coercionCost(const Type& other) const {
900 if (this->matches(other)) {
901 return CoercionCost::Free();
902 }
903 if (this->typeKind() == other.typeKind() &&
904 (this->isVector() || this->isMatrix() || this->isArray())) {
905 // Vectors/matrices/arrays of the same size can be coerced if their component type can be.
906 if (this->isMatrix() && (this->rows() != other.rows())) {
908 }
909 if (this->columns() != other.columns()) {
911 }
912 return this->componentType().coercionCost(other.componentType());
913 }
914 if (this->isNumber() && other.isNumber()) {
915 if (this->isLiteral() && this->isInteger()) {
916 return CoercionCost::Free();
917 } else if (this->numberKind() != other.numberKind()) {
919 } else if (other.priority() >= this->priority()) {
920 return CoercionCost::Normal(other.priority() - this->priority());
921 } else {
922 return CoercionCost::Narrowing(this->priority() - other.priority());
923 }
924 }
925 if (fTypeKind == TypeKind::kGeneric) {
927 for (size_t i = 0; i < types.size(); i++) {
928 if (types[i]->matches(other)) {
929 return CoercionCost::Normal((int) i + 1);
930 }
931 }
932 }
934}
935
936const Type* Type::applyQualifiers(const Context& context,
937 ModifierFlags* modifierFlags,
938 Position pos) const {
939 const Type* type;
940 type = this->applyPrecisionQualifiers(context, modifierFlags, pos);
941 type = type->applyAccessQualifiers(context, modifierFlags, pos);
942 return type;
943}
944
945const Type* Type::applyPrecisionQualifiers(const Context& context,
946 ModifierFlags* modifierFlags,
947 Position pos) const {
948 ModifierFlags precisionQualifiers = *modifierFlags & (ModifierFlag::kHighp |
951 if (precisionQualifiers == ModifierFlag::kNone) {
952 // No precision qualifiers here. Return the type as-is.
953 return this;
954 }
955
956 if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
957 // We want to discourage precision modifiers internally. Instead, use the type that
958 // corresponds to the precision you need. (e.g. half vs float, short vs int)
959 context.fErrors->error(pos, "precision qualifiers are not allowed");
960 return context.fTypes.fPoison.get();
961 }
962
963 if (SkPopCount(precisionQualifiers.value()) > 1) {
964 context.fErrors->error(pos, "only one precision qualifier can be used");
965 return context.fTypes.fPoison.get();
966 }
967
968 // We're going to return a whole new type, so the modifier bits can be cleared out.
969 *modifierFlags &= ~(ModifierFlag::kHighp |
972
973 const Type& component = this->componentType();
974 if (component.highPrecision()) {
975 if (precisionQualifiers & ModifierFlag::kHighp) {
976 // Type is already high precision, and we are requesting high precision. Return as-is.
977 return this;
978 }
979
980 // SkSL doesn't support low precision, so `lowp` is interpreted as medium precision.
981 // Ascertain the mediump equivalent type for this type, if any.
982 const Type* mediumpType;
983 switch (component.numberKind()) {
985 mediumpType = context.fTypes.fHalf.get();
986 break;
987
989 mediumpType = context.fTypes.fShort.get();
990 break;
991
993 mediumpType = context.fTypes.fUShort.get();
994 break;
995
996 default:
997 mediumpType = context.fTypes.fPoison.get();
998 break;
999 }
1000
1001 if (mediumpType) {
1002 // Convert the mediump component type into the final vector/matrix/array type as needed.
1003 return this->isArray()
1004 ? context.fSymbolTable->addArrayDimension(context, mediumpType, this->columns())
1005 : &mediumpType->toCompound(context, this->columns(), this->rows());
1006 }
1007 }
1008
1009 context.fErrors->error(pos, "type '" + this->displayName() +
1010 "' does not support precision qualifiers");
1011 return context.fTypes.fPoison.get();
1012}
1013
1014const Type* Type::applyAccessQualifiers(const Context& context,
1015 ModifierFlags* modifierFlags,
1016 Position pos) const {
1017 ModifierFlags accessQualifiers = *modifierFlags & (ModifierFlag::kReadOnly |
1019
1020 // We're going to return a whole new type, so the modifier bits must be cleared out.
1021 *modifierFlags &= ~(ModifierFlag::kReadOnly |
1023
1024 if (this->matches(*context.fTypes.fTexture2D)) {
1025 // We require all texture2Ds to be qualified with `readonly` or `writeonly`.
1026 // (Read-write textures are not yet supported in WGSL.)
1027 if (accessQualifiers == ModifierFlag::kReadOnly) {
1028 return context.fTypes.fReadOnlyTexture2D.get();
1029 }
1030 if (accessQualifiers == ModifierFlag::kWriteOnly) {
1031 return context.fTypes.fWriteOnlyTexture2D.get();
1032 }
1033 context.fErrors->error(
1034 pos,
1035 accessQualifiers
1036 ? "'readonly' and 'writeonly' qualifiers cannot be combined"
1037 : "'texture2D' requires a 'readonly' or 'writeonly' access qualifier");
1038 return this;
1039 }
1040
1041 if (accessQualifiers) {
1042 context.fErrors->error(pos, "type '" + this->displayName() + "' does not support "
1043 "qualifier '" + accessQualifiers.description() + "'");
1044 }
1045
1046 return this;
1047}
1048
1049const Type& Type::toCompound(const Context& context, int columns, int rows) const {
1050 SkASSERT(this->isScalar());
1051 if (columns == 1 && rows == 1) {
1052 return *this;
1053 }
1054 if (this->matches(*context.fTypes.fFloat) || this->matches(*context.fTypes.fFloatLiteral)) {
1055 switch (rows) {
1056 case 1:
1057 switch (columns) {
1058 case 1: return *context.fTypes.fFloat;
1059 case 2: return *context.fTypes.fFloat2;
1060 case 3: return *context.fTypes.fFloat3;
1061 case 4: return *context.fTypes.fFloat4;
1062 default: SK_ABORT("unsupported vector column count (%d)", columns);
1063 }
1064 case 2:
1065 switch (columns) {
1066 case 2: return *context.fTypes.fFloat2x2;
1067 case 3: return *context.fTypes.fFloat3x2;
1068 case 4: return *context.fTypes.fFloat4x2;
1069 default: SK_ABORT("unsupported matrix column count (%d)", columns);
1070 }
1071 case 3:
1072 switch (columns) {
1073 case 2: return *context.fTypes.fFloat2x3;
1074 case 3: return *context.fTypes.fFloat3x3;
1075 case 4: return *context.fTypes.fFloat4x3;
1076 default: SK_ABORT("unsupported matrix column count (%d)", columns);
1077 }
1078 case 4:
1079 switch (columns) {
1080 case 2: return *context.fTypes.fFloat2x4;
1081 case 3: return *context.fTypes.fFloat3x4;
1082 case 4: return *context.fTypes.fFloat4x4;
1083 default: SK_ABORT("unsupported matrix column count (%d)", columns);
1084 }
1085 default: SK_ABORT("unsupported row count (%d)", rows);
1086 }
1087 } else if (this->matches(*context.fTypes.fHalf)) {
1088 switch (rows) {
1089 case 1:
1090 switch (columns) {
1091 case 1: return *context.fTypes.fHalf;
1092 case 2: return *context.fTypes.fHalf2;
1093 case 3: return *context.fTypes.fHalf3;
1094 case 4: return *context.fTypes.fHalf4;
1095 default: SK_ABORT("unsupported vector column count (%d)", columns);
1096 }
1097 case 2:
1098 switch (columns) {
1099 case 2: return *context.fTypes.fHalf2x2;
1100 case 3: return *context.fTypes.fHalf3x2;
1101 case 4: return *context.fTypes.fHalf4x2;
1102 default: SK_ABORT("unsupported matrix column count (%d)", columns);
1103 }
1104 case 3:
1105 switch (columns) {
1106 case 2: return *context.fTypes.fHalf2x3;
1107 case 3: return *context.fTypes.fHalf3x3;
1108 case 4: return *context.fTypes.fHalf4x3;
1109 default: SK_ABORT("unsupported matrix column count (%d)", columns);
1110 }
1111 case 4:
1112 switch (columns) {
1113 case 2: return *context.fTypes.fHalf2x4;
1114 case 3: return *context.fTypes.fHalf3x4;
1115 case 4: return *context.fTypes.fHalf4x4;
1116 default: SK_ABORT("unsupported matrix column count (%d)", columns);
1117 }
1118 default: SK_ABORT("unsupported row count (%d)", rows);
1119 }
1120 } else if (this->matches(*context.fTypes.fInt) || this->matches(*context.fTypes.fIntLiteral)) {
1121 switch (rows) {
1122 case 1:
1123 switch (columns) {
1124 case 1: return *context.fTypes.fInt;
1125 case 2: return *context.fTypes.fInt2;
1126 case 3: return *context.fTypes.fInt3;
1127 case 4: return *context.fTypes.fInt4;
1128 default: SK_ABORT("unsupported vector column count (%d)", columns);
1129 }
1130 default: SK_ABORT("unsupported row count (%d)", rows);
1131 }
1132 } else if (this->matches(*context.fTypes.fShort)) {
1133 switch (rows) {
1134 case 1:
1135 switch (columns) {
1136 case 1: return *context.fTypes.fShort;
1137 case 2: return *context.fTypes.fShort2;
1138 case 3: return *context.fTypes.fShort3;
1139 case 4: return *context.fTypes.fShort4;
1140 default: SK_ABORT("unsupported vector column count (%d)", columns);
1141 }
1142 default: SK_ABORT("unsupported row count (%d)", rows);
1143 }
1144 } else if (this->matches(*context.fTypes.fUInt)) {
1145 switch (rows) {
1146 case 1:
1147 switch (columns) {
1148 case 1: return *context.fTypes.fUInt;
1149 case 2: return *context.fTypes.fUInt2;
1150 case 3: return *context.fTypes.fUInt3;
1151 case 4: return *context.fTypes.fUInt4;
1152 default: SK_ABORT("unsupported vector column count (%d)", columns);
1153 }
1154 default: SK_ABORT("unsupported row count (%d)", rows);
1155 }
1156 } else if (this->matches(*context.fTypes.fUShort)) {
1157 switch (rows) {
1158 case 1:
1159 switch (columns) {
1160 case 1: return *context.fTypes.fUShort;
1161 case 2: return *context.fTypes.fUShort2;
1162 case 3: return *context.fTypes.fUShort3;
1163 case 4: return *context.fTypes.fUShort4;
1164 default: SK_ABORT("unsupported vector column count (%d)", columns);
1165 }
1166 default: SK_ABORT("unsupported row count (%d)", rows);
1167 }
1168 } else if (this->matches(*context.fTypes.fBool)) {
1169 switch (rows) {
1170 case 1:
1171 switch (columns) {
1172 case 1: return *context.fTypes.fBool;
1173 case 2: return *context.fTypes.fBool2;
1174 case 3: return *context.fTypes.fBool3;
1175 case 4: return *context.fTypes.fBool4;
1176 default: SK_ABORT("unsupported vector column count (%d)", columns);
1177 }
1178 default: SK_ABORT("unsupported row count (%d)", rows);
1179 }
1180 }
1181 SkDEBUGFAILF("unsupported toCompound type %s", this->description().c_str());
1182 return *context.fTypes.fVoid;
1183}
1184
1185const Type* Type::clone(const Context& context, SymbolTable* symbolTable) const {
1186 // Many types are built-ins, and exist in every SymbolTable by default.
1187 if (this->isInRootSymbolTable()) {
1188 return this;
1189 }
1190 // If we are compiling a program, and the type comes from the program's module, it is safe to
1191 // assume that the type is in-scope anywhere in the program without actually recursing through
1192 // the SymbolTable hierarchy to prove it.
1193 if (!context.fConfig->fIsBuiltinCode && this->isBuiltin()) {
1194 return this;
1195 }
1196 // Even if the type isn't a built-in, it might already exist in the SymbolTable. Search by name.
1197 const Symbol* existingSymbol = symbolTable->find(this->name());
1198 if (existingSymbol != nullptr) {
1199 const Type* existingType = &existingSymbol->as<Type>();
1200 SkASSERT(existingType->typeKind() == this->typeKind());
1201 return existingType;
1202 }
1203 // This type actually needs to be cloned into the destination SymbolTable.
1204 switch (this->typeKind()) {
1205 case TypeKind::kArray: {
1206 return symbolTable->addArrayDimension(context, &this->componentType(), this->columns());
1207 }
1208 case TypeKind::kStruct: {
1209 // We are cloning an existing struct, so there's no need to call MakeStructType and
1210 // fully error-check it again.
1211 const std::string* name = symbolTable->takeOwnershipOfString(std::string(this->name()));
1212 SkSpan<const Field> fieldSpan = this->fields();
1213 return symbolTable->add(
1214 context,
1215 std::make_unique<StructType>(this->fPosition,
1216 *name,
1217 TArray<Field>(fieldSpan.data(), fieldSpan.size()),
1218 this->structNestingDepth(),
1219 /*interfaceBlock=*/this->isInterfaceBlock(),
1220 /*isBuiltin=*/context.fConfig->fIsBuiltinCode));
1221 }
1222 default:
1223 SkDEBUGFAILF("don't know how to clone type '%s'", this->description().c_str());
1224 return nullptr;
1225 }
1226}
1227
1228std::unique_ptr<Expression> Type::coerceExpression(std::unique_ptr<Expression> expr,
1229 const Context& context) const {
1230 if (!expr || expr->isIncomplete(context)) {
1231 return nullptr;
1232 }
1233 if (expr->type().matches(*this)) {
1234 return expr;
1235 }
1236
1237 const Position pos = expr->fPosition;
1238 const ProgramSettings& settings = context.fConfig->fSettings;
1239 if (!expr->coercionCost(*this).isPossible(settings.fAllowNarrowingConversions)) {
1240 context.fErrors->error(pos, "expected '" + this->displayName() + "', but found '" +
1241 expr->type().displayName() + "'");
1242 return nullptr;
1243 }
1244
1245 if (this->isScalar()) {
1246 return ConstructorScalarCast::Make(context, pos, *this, std::move(expr));
1247 }
1248 if (this->isVector() || this->isMatrix()) {
1249 return ConstructorCompoundCast::Make(context, pos, *this, std::move(expr));
1250 }
1251 if (this->isArray()) {
1252 return ConstructorArrayCast::Make(context, pos, *this, std::move(expr));
1253 }
1254 context.fErrors->error(pos, "cannot construct '" + this->displayName() + "'");
1255 return nullptr;
1256}
1257
1258bool Type::isAllowedInES2(const Context& context) const {
1259 return !context.fConfig->strictES2Mode() || this->isAllowedInES2();
1260}
1261
1262bool Type::checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const {
1263 bool foundError = false;
1264 const Type& baseType = this->componentType();
1265 if (baseType.isNumber()) {
1266 // Replace constant expressions with their corresponding values.
1267 const Expression* valueExpr = ConstantFolder::GetConstantValueForVariable(expr);
1268 if (valueExpr->supportsConstantValues()) {
1269 // Iterate over every constant subexpression in the value.
1270 int numSlots = valueExpr->type().slotCount();
1271 for (int slot = 0; slot < numSlots; ++slot) {
1272 std::optional<double> slotVal = valueExpr->getConstantValue(slot);
1273 // Check for Literal values that are out of range for the base type.
1274 if (slotVal.has_value() &&
1275 baseType.checkForOutOfRangeLiteral(context, *slotVal, valueExpr->fPosition)) {
1276 foundError = true;
1277 }
1278 }
1279 }
1280 }
1281
1282 // We don't need range checks for floats or booleans; any matched-type value is acceptable.
1283 return foundError;
1284}
1285
1286bool Type::checkForOutOfRangeLiteral(const Context& context, double value, Position pos) const {
1287 SkASSERT(this->isScalar());
1288 if (!this->isNumber()) {
1289 return false;
1290 }
1291 if (value >= this->minimumValue() && value <= this->maximumValue()) {
1292 return false;
1293 }
1294 // We found a value that can't fit in our type. Flag it as an error.
1295 context.fErrors->error(pos, SkSL::String::printf("value is out of range for type '%s': %.0f",
1296 this->displayName().c_str(),
1297 value));
1298 return true;
1299}
1300
1301bool Type::checkIfUsableInArray(const Context& context, Position arrayPos) const {
1302 if (this->isArray()) {
1303 context.fErrors->error(arrayPos, "multi-dimensional arrays are not supported");
1304 return false;
1305 }
1306 if (this->isVoid()) {
1307 context.fErrors->error(arrayPos, "type 'void' may not be used in an array");
1308 return false;
1309 }
1310 if (this->isOpaque() && !this->isAtomic()) {
1311 context.fErrors->error(arrayPos, "opaque type '" + std::string(this->name()) +
1312 "' may not be used in an array");
1313 return false;
1314 }
1315 return true;
1316}
1317
1318SKSL_INT Type::convertArraySize(const Context& context,
1319 Position arrayPos,
1320 std::unique_ptr<Expression> size) const {
1321 size = context.fTypes.fInt->coerceExpression(std::move(size), context);
1322 if (!size) {
1323 return 0;
1324 }
1327 context.fErrors->error(size->fPosition, "array size must be an integer");
1328 return 0;
1329 }
1330 return this->convertArraySize(context, arrayPos, size->fPosition, count);
1331}
1332
1333SKSL_INT Type::convertArraySize(const Context& context,
1334 Position arrayPos,
1335 Position sizePos,
1336 SKSL_INT size) const {
1337 if (!this->checkIfUsableInArray(context, arrayPos)) {
1338 // `checkIfUsableInArray` will generate an error for us.
1339 return 0;
1340 }
1341 if (size <= 0) {
1342 context.fErrors->error(sizePos, "array size must be positive");
1343 return 0;
1344 }
1345 // We can't get a meaningful slot count if the interior type contains an unsized array; we'll
1346 // assert if we try. Unsized arrays should only occur in a handful of limited cases (e.g. an
1347 // interface block with a trailing buffer), and will never be valid in a runtime effect.
1348 if (!this->isOrContainsUnsizedArray()) {
1349 if (SkSafeMath::Mul(this->slotCount(), size) > kVariableSlotLimit) {
1350 context.fErrors->error(sizePos, "array size is too large");
1351 return 0;
1352 }
1353 }
1354 return size;
1355}
1356
1357std::string Field::description() const {
1359 ' ' + std::string(fName) + ';';
1360}
1361
1362} // namespace SkSL
int count
Definition: FontMgrTest.cpp:50
SkPoint pos
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
#define SkDEBUGFAILF(fmt,...)
Definition: SkAssert.h:119
#define SkASSERT(cond)
Definition: SkAssert.h:116
static int SkPopCount(uint32_t n)
Definition: SkMathPriv.h:136
int64_t SKSL_INT
Definition: SkSLDefines.h:16
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
Definition: SkSwizzler.cpp:31
constexpr size_t SkToSizeT(S x)
Definition: SkTo.h:31
size_t slotCount() const override
Definition: SkSLType.cpp:80
SpvDim_ dimensions() const override
Definition: SkSLType.cpp:88
bool isStruct() const override
Definition: SkSLType.cpp:124
int bitWidth() const override
Definition: SkSLType.cpp:72
bool isArrayedTexture() const override
Definition: SkSLType.cpp:96
bool isDepth() const override
Definition: SkSLType.cpp:92
bool isVector() const override
Definition: SkSLType.cpp:108
bool isMultisampled() const override
Definition: SkSLType.cpp:132
int columns() const override
Definition: SkSLType.cpp:64
const Type & slotType(size_t n) const override
Definition: SkSLType.cpp:84
int rows() const override
Definition: SkSLType.cpp:68
bool isScalar() const override
Definition: SkSLType.cpp:100
bool isUnsizedArray() const override
Definition: SkSLType.cpp:120
int priority() const override
Definition: SkSLType.cpp:60
TextureAccess textureAccess() const override
Definition: SkSLType.cpp:136
bool isMatrix() const override
Definition: SkSLType.cpp:112
const Type & componentType() const override
Definition: SkSLType.cpp:52
bool isInterfaceBlock() const override
Definition: SkSLType.cpp:128
SkSpan< const Type *const > coercibleTypes() const override
Definition: SkSLType.cpp:140
bool isAllowedInES2() const override
Definition: SkSLType.cpp:76
bool isLiteral() const override
Definition: SkSLType.cpp:104
NumberKind numberKind() const override
Definition: SkSLType.cpp:56
bool isArray() const override
Definition: SkSLType.cpp:116
AliasType(std::string_view name, const Type &targetType)
Definition: SkSLType.cpp:44
const Type & resolve() const override
Definition: SkSLType.cpp:48
int columns() const override
Definition: SkSLType.cpp:193
bool isArray() const override
Definition: SkSLType.cpp:165
const Type & componentType() const override
Definition: SkSLType.cpp:189
bool isOrContainsAtomic() const override
Definition: SkSLType.cpp:177
bool isOrContainsArray() const override
Definition: SkSLType.cpp:173
bool isBuiltin() const override
Definition: SkSLType.cpp:169
bool isUnsizedArray() const override
Definition: SkSLType.cpp:181
bool isAllowedInES2() const override
Definition: SkSLType.cpp:201
const Type & slotType(size_t n) const override
Definition: SkSLType.cpp:215
bool isOrContainsUnsizedArray() const override
Definition: SkSLType.cpp:185
int bitWidth() const override
Definition: SkSLType.cpp:197
size_t slotCount() const override
Definition: SkSLType.cpp:209
static constexpr TypeKind kTypeKind
Definition: SkSLType.cpp:152
ArrayType(std::string_view name, const char *abbrev, const Type &componentType, int count, bool isBuiltin)
Definition: SkSLType.cpp:154
bool isAllowedInUniform(Position *errorPosition) const override
Definition: SkSLType.cpp:205
bool isAllowedInUniform(Position *) const override
Definition: SkSLType.cpp:429
const Type & slotType(size_t n) const override
Definition: SkSLType.cpp:433
AtomicType(std::string_view name, const char *abbrev)
Definition: SkSLType.cpp:425
bool isOrContainsAtomic() const override
Definition: SkSLType.cpp:431
static constexpr TypeKind kTypeKind
Definition: SkSLType.cpp:423
bool isAllowedInES2() const override
Definition: SkSLType.cpp:427
static bool GetConstantInt(const Expression &value, SKSL_INT *out)
static const Expression * GetConstantValueForVariable(const Expression &value)
static std::unique_ptr< Expression > Make(const Context &context, Position pos, const Type &type, std::unique_ptr< Expression > arg)
static std::unique_ptr< Expression > Make(const Context &context, Position pos, const Type &type, std::unique_ptr< Expression > arg)
static std::unique_ptr< Expression > Make(const Context &context, Position pos, const Type &type, std::unique_ptr< Expression > arg)
SkSpan< const Type *const > coercibleTypes() const override
Definition: SkSLType.cpp:240
static constexpr TypeKind kTypeKind
Definition: SkSLType.cpp:230
const Type & slotType(size_t) const override
Definition: SkSLType.cpp:244
GenericType(const char *name, SkSpan< const Type *const > coercibleTypes, const Type *slotType)
Definition: SkSLType.cpp:232
Position fPosition
Definition: SkSLIRNode.h:109
bool isScalar() const override
Definition: SkSLType.cpp:297
const Type & slotType(size_t n) const override
Definition: SkSLType.cpp:309
int priority() const override
Definition: SkSLType.cpp:269
LiteralType(const char *name, const Type &scalarType, int8_t priority)
Definition: SkSLType.cpp:260
double minimumValue() const override
Definition: SkSLType.cpp:289
double maximumValue() const override
Definition: SkSLType.cpp:293
const Type & scalarTypeForLiteral() const override
Definition: SkSLType.cpp:265
NumberKind numberKind() const override
Definition: SkSLType.cpp:281
int bitWidth() const override
Definition: SkSLType.cpp:285
bool isLiteral() const override
Definition: SkSLType.cpp:301
size_t slotCount() const override
Definition: SkSLType.cpp:305
int rows() const override
Definition: SkSLType.cpp:277
static constexpr TypeKind kTypeKind
Definition: SkSLType.cpp:258
int columns() const override
Definition: SkSLType.cpp:273
int rows() const override
Definition: SkSLType.cpp:464
int bitWidth() const override
Definition: SkSLType.cpp:468
MatrixType(std::string_view name, const char *abbrev, const Type &componentType, int8_t columns, int8_t rows)
Definition: SkSLType.cpp:446
int columns() const override
Definition: SkSLType.cpp:460
bool isAllowedInES2() const override
Definition: SkSLType.cpp:476
static constexpr TypeKind kTypeKind
Definition: SkSLType.cpp:444
bool isMatrix() const override
Definition: SkSLType.cpp:472
const Type & slotType(size_t n) const override
Definition: SkSLType.cpp:484
const ScalarType & componentType() const override
Definition: SkSLType.cpp:456
size_t slotCount() const override
Definition: SkSLType.cpp:480
std::string paddedDescription() const
bool valid() const
Definition: SkSLPosition.h:34
const TextureType & textureType() const override
Definition: SkSLType.cpp:558
TextureAccess textureAccess() const override
Definition: SkSLType.cpp:578
bool isDepth() const override
Definition: SkSLType.cpp:566
static constexpr TypeKind kTypeKind
Definition: SkSLType.cpp:547
SamplerType(const char *name, const Type &textureType)
Definition: SkSLType.cpp:549
const Type & slotType(size_t n) const override
Definition: SkSLType.cpp:582
SpvDim_ dimensions() const override
Definition: SkSLType.cpp:562
bool isMultisampled() const override
Definition: SkSLType.cpp:574
bool isArrayedTexture() const override
Definition: SkSLType.cpp:570
bool isAllowedInUniform(Position *) const override
Definition: SkSLType.cpp:361
ScalarType(std::string_view name, const char *abbrev, NumberKind numberKind, int8_t priority, int8_t bitWidth)
Definition: SkSLType.cpp:326
int bitWidth() const override
Definition: SkSLType.cpp:341
std::numeric_limits< float > float_limits
Definition: SkSLType.cpp:378
bool isScalar() const override
Definition: SkSLType.cpp:353
size_t slotCount() const override
Definition: SkSLType.cpp:365
std::numeric_limits< uint16_t > ushort_limits
Definition: SkSLType.cpp:377
int priority() const override
Definition: SkSLType.cpp:337
double minimumValue() const override
Definition: SkSLType.cpp:381
static constexpr TypeKind kTypeKind
Definition: SkSLType.cpp:324
NumberKind numberKind() const override
Definition: SkSLType.cpp:333
int columns() const override
Definition: SkSLType.cpp:345
std::numeric_limits< int32_t > int_limits
Definition: SkSLType.cpp:374
const Type & slotType(size_t n) const override
Definition: SkSLType.cpp:369
std::numeric_limits< uint32_t > uint_limits
Definition: SkSLType.cpp:376
std::numeric_limits< int16_t > short_limits
Definition: SkSLType.cpp:375
bool isAllowedInES2() const override
Definition: SkSLType.cpp:357
double maximumValue() const override
Definition: SkSLType.cpp:397
int rows() const override
Definition: SkSLType.cpp:349
bool isInterfaceBlock() const override
Definition: SkSLType.cpp:632
const Type & slotType(size_t n) const override
Definition: SkSLType.cpp:672
int structNestingDepth() const override
Definition: SkSLType.cpp:668
size_t slotCount() const override
Definition: SkSLType.cpp:663
bool isOrContainsAtomic() const override
Definition: SkSLType.cpp:659
SkSpan< const Field > fields() const override
Definition: SkSLType.cpp:624
StructType(Position pos, std::string_view name, TArray< Field > fields, int nestingDepth, bool interfaceBlock, bool isBuiltin)
Definition: SkSLType.cpp:597
bool isOrContainsArray() const override
Definition: SkSLType.cpp:651
bool isOrContainsUnsizedArray() const override
Definition: SkSLType.cpp:655
bool isAllowedInUniform(Position *errorPosition) const override
Definition: SkSLType.cpp:644
bool isStruct() const override
Definition: SkSLType.cpp:628
bool isAllowedInES2() const override
Definition: SkSLType.cpp:640
static constexpr TypeKind kTypeKind
Definition: SkSLType.cpp:595
bool isBuiltin() const override
Definition: SkSLType.cpp:636
std::string_view name() const
Definition: SkSLSymbol.h:51
Symbol(Position pos, Kind kind, std::string_view name, const Type *type=nullptr)
Definition: SkSLSymbol.h:31
const Type & type() const
Definition: SkSLSymbol.h:42
static constexpr TypeKind kTypeKind
Definition: SkSLType.cpp:499
SpvDim_ dimensions() const override
Definition: SkSLType.cpp:510
const Type & slotType(size_t n) const override
Definition: SkSLType.cpp:530
bool isDepth() const override
Definition: SkSLType.cpp:514
bool isArrayedTexture() const override
Definition: SkSLType.cpp:518
TextureAccess textureAccess() const override
Definition: SkSLType.cpp:526
TextureType(const char *name, SpvDim_ dimensions, bool isDepth, bool isArrayed, bool isMultisampled, TextureAccess textureAccess)
Definition: SkSLType.cpp:501
bool isMultisampled() const override
Definition: SkSLType.cpp:522
virtual const Type & slotType(size_t) const
Definition: SkSLType.h:465
virtual bool isArray() const
Definition: SkSLType.h:532
Type(const Type &other)=delete
static std::unique_ptr< Type > MakeTextureType(const char *name, SpvDim_ dimensions, bool isDepth, bool isArrayedTexture, bool isMultisampled, TextureAccess textureAccess)
const Type * applyPrecisionQualifiers(const Context &context, ModifierFlags *modifierFlags, Position pos) const
bool isInRootSymbolTable() const
Definition: SkSLType.h:655
virtual int bitWidth() const
Definition: SkSLType.h:574
bool highPrecision() const
Definition: SkSLType.h:570
virtual bool isVector() const
Definition: SkSLType.h:524
CoercionCost coercionCost(const Type &other) const
static std::unique_ptr< Type > MakeArrayType(const Context &context, std::string_view name, const Type &componentType, int columns)
virtual int priority() const
Definition: SkSLType.h:379
bool isAllowedInES2(const Context &context) const
std::unique_ptr< Expression > coerceExpression(std::unique_ptr< Expression > expr, const Context &context) const
virtual int rows() const
Definition: SkSLType.h:438
bool isAtomic() const
Definition: SkSLType.h:508
virtual const Type & componentType() const
Definition: SkSLType.h:404
static std::unique_ptr< Type > MakeSpecialType(const char *name, const char *abbrev, Type::TypeKind typeKind)
virtual bool isInterfaceBlock() const
Definition: SkSLType.h:544
static std::unique_ptr< Type > MakeScalarType(std::string_view name, const char *abbrev, Type::NumberKind numberKind, int8_t priority, int8_t bitWidth)
SKSL_INT convertArraySize(const Context &context, Position arrayPos, std::unique_ptr< Expression > size) const
bool isOpaque() const
Definition: SkSLType.h:353
const char * abbreviatedName() const
Definition: SkSLType.h:276
bool isNumber() const
Definition: SkSLType.h:304
virtual SkSpan< const Field > fields() const
Definition: SkSLType.h:469
static std::unique_ptr< Type > MakeGenericType(const char *name, SkSpan< const Type *const > types, const Type *slotType)
bool matches(const Type &other) const
Definition: SkSLType.h:269
virtual bool isMatrix() const
Definition: SkSLType.h:528
virtual bool isDepth() const
Definition: SkSLType.h:486
static std::unique_ptr< Type > MakeLiteralType(const char *name, const Type &scalarType, int8_t priority)
virtual bool isLiteral() const
Definition: SkSLType.h:516
virtual TextureAccess textureAccess() const
Definition: SkSLType.h:561
bool checkIfUsableInArray(const Context &context, Position arrayPos) const
static std::unique_ptr< Type > MakeMatrixType(std::string_view name, const char *abbrev, const Type &componentType, int columns, int8_t rows)
virtual const Type & textureType() const
Definition: SkSLType.h:419
virtual int columns() const
Definition: SkSLType.h:429
virtual size_t slotCount() const
Definition: SkSLType.h:457
bool is() const
Definition: SkSLType.h:205
static constexpr int kUnsizedArray
Definition: SkSLType.h:99
virtual bool isScalar() const
Definition: SkSLType.h:512
virtual NumberKind numberKind() const
Definition: SkSLType.h:290
virtual bool isAllowedInES2() const
Definition: SkSLType.h:246
virtual bool isUnsizedArray() const
Definition: SkSLType.h:536
virtual bool isAllowedInUniform(Position *errorPosition=nullptr) const
Definition: SkSLType.h:257
static std::unique_ptr< Type > MakeAtomicType(std::string_view name, const char *abbrev)
const T & as() const
Definition: SkSLType.h:210
std::string description() const override
Definition: SkSLType.h:238
const Type * applyAccessQualifiers(const Context &context, ModifierFlags *modifierFlags, Position pos) const
virtual double maximumValue() const
Definition: SkSLType.h:449
std::string getArrayName(int arraySize) const
virtual bool isOrContainsAtomic() const
Definition: SkSLType.h:586
virtual bool isMultisampled() const
Definition: SkSLType.h:556
static std::unique_ptr< Type > MakeStructType(const Context &context, Position pos, std::string_view name, skia_private::TArray< Field > fields, bool interfaceBlock=false)
bool isVoid() const
Definition: SkSLType.h:496
virtual SkSpan< const Type *const > coercibleTypes() const
Definition: SkSLType.h:476
virtual bool isArrayedTexture() const
Definition: SkSLType.h:491
bool checkForOutOfRangeLiteral(const Context &context, const Expression &expr) const
std::string displayName() const
Definition: SkSLType.h:234
const Type & toCompound(const Context &context, int columns, int rows) const
TypeKind typeKind() const
Definition: SkSLType.h:283
virtual bool isStruct() const
Definition: SkSLType.h:540
const Type * clone(const Context &context, SymbolTable *symbolTable) const
virtual SpvDim_ dimensions() const
Definition: SkSLType.h:481
static std::unique_ptr< Type > MakeVectorType(std::string_view name, const char *abbrev, const Type &componentType, int columns)
static std::unique_ptr< Type > MakeSamplerType(const char *name, const Type &textureType)
virtual double minimumValue() const
Definition: SkSLType.h:444
bool isInteger() const
Definition: SkSLType.h:339
static std::unique_ptr< Type > MakeAliasType(std::string_view name, const Type &targetType)
virtual bool isOrContainsUnsizedArray() const
Definition: SkSLType.h:582
const Type * applyQualifiers(const Context &context, ModifierFlags *modifierFlags, Position pos) const
bool isAllowedInUniform(Position *errorPosition) const override
Definition: SkSLType.cpp:736
VectorType(std::string_view name, const char *abbrev, const Type &componentType, int8_t columns)
Definition: SkSLType.cpp:704
const ScalarType & componentType() const override
Definition: SkSLType.cpp:712
const Type & slotType(size_t n) const override
Definition: SkSLType.cpp:744
bool isVector() const override
Definition: SkSLType.cpp:728
size_t slotCount() const override
Definition: SkSLType.cpp:740
bool isAllowedInES2() const override
Definition: SkSLType.cpp:732
int bitWidth() const override
Definition: SkSLType.cpp:724
int columns() const override
Definition: SkSLType.cpp:716
int rows() const override
Definition: SkSLType.cpp:720
static constexpr TypeKind kTypeKind
Definition: SkSLType.cpp:702
static size_t Add(size_t x, size_t y)
Definition: SkSafeMath.cpp:10
static size_t Mul(size_t x, size_t y)
Definition: SkSafeMath.cpp:16
constexpr T * data() const
Definition: SkSpan_impl.h:94
constexpr size_t size() const
Definition: SkSpan_impl.h:95
int count() const
Definition: SkTHash.h:579
void add(T item)
Definition: SkTHash.h:592
uint8_t value
static float max(float r, float g, float b)
Definition: hsl.cpp:49
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: SkSLString.cpp:83
static constexpr int kMaxStructDepth
Definition: SkSLType.cpp:40
static constexpr int kVariableSlotLimit
Definition: SkSLDefines.h:43
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: ref_ptr.h:256
SpvDim_
Definition: spirv.h:141
@ SpvDimSubpassData
Definition: spirv.h:148
static CoercionCost Impossible()
Definition: SkSLType.h:42
static CoercionCost Narrowing(int cost)
Definition: SkSLType.h:41
static CoercionCost Free()
Definition: SkSLType.h:39
static CoercionCost Normal(int cost)
Definition: SkSLType.h:40
Layout fLayout
Definition: SkSLType.h:85
std::string_view fName
Definition: SkSLType.h:87
std::string description() const
Definition: SkSLType.cpp:1357
const Type * fType
Definition: SkSLType.h:88
ModifierFlags fModifierFlags
Definition: SkSLType.h:86
std::string paddedDescription() const
static bool IsRuntimeEffect(ProgramKind kind)