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 SKIASL_TYPE
9#define SKIASL_TYPE
10
11#include "src/sksl/SkSLPosition.h"
12#include "src/sksl/SkSLUtil.h"
13#include "src/sksl/ir/SkSLModifiers.h"
14#include "src/sksl/ir/SkSLSymbol.h"
15#include "src/sksl/spirv.h"
16#include <climits>
17#include <vector>
18#include <memory>
19
20namespace SkSL {
21
22class Context;
23
24/**
25 * Represents a type, such as int or float4.
26 */
27class Type : public Symbol {
28public:
29 struct Field {
30 Field(Modifiers modifiers, StringFragment name, const Type* type)
31 : fModifiers(modifiers)
32 , fName(name)
33 , fType(std::move(type)) {}
34
35 const String description() const {
36 return fType->displayName() + " " + fName + ";";
37 }
38
39 Modifiers fModifiers;
40 StringFragment fName;
41 const Type* fType;
42 };
43
44 enum Kind {
45 kArray_Kind,
46 kEnum_Kind,
47 kGeneric_Kind,
48 kNullable_Kind,
49 kMatrix_Kind,
50 kOther_Kind,
51 kSampler_Kind,
52 kSeparateSampler_Kind,
53 kScalar_Kind,
54 kStruct_Kind,
55 kTexture_Kind,
56 kVector_Kind
57 };
58
59 enum NumberKind {
60 kFloat_NumberKind,
61 kSigned_NumberKind,
62 kUnsigned_NumberKind,
63 kNonnumeric_NumberKind
64 };
65
66 // Create an "other" (special) type with the given name. These types cannot be directly
67 // referenced from user code.
68 Type(const char* name)
69 : INHERITED(-1, kType_Kind, StringFragment())
70 , fNameString(name)
71 , fTypeKind(kOther_Kind)
72 , fNumberKind(kNonnumeric_NumberKind) {
73 fName.fChars = fNameString.c_str();
74 fName.fLength = fNameString.size();
75 }
76
77 // Create an "other" (special) type that supports field access.
78 Type(const char* name, std::vector<Field> fields)
79 : INHERITED(-1, kType_Kind, StringFragment())
80 , fNameString(name)
81 , fTypeKind(kOther_Kind)
82 , fNumberKind(kNonnumeric_NumberKind)
83 , fFields(std::move(fields)) {
84 fName.fChars = fNameString.c_str();
85 fName.fLength = fNameString.size();
86 }
87
88 // Create a simple type.
89 Type(String name, Kind kind)
90 : INHERITED(-1, kType_Kind, StringFragment())
91 , fNameString(std::move(name))
92 , fTypeKind(kind)
93 , fNumberKind(kNonnumeric_NumberKind) {
94 fName.fChars = fNameString.c_str();
95 fName.fLength = fNameString.size();
96 }
97
98 // Create a generic type which maps to the listed types.
99 Type(const char* name, std::vector<const Type*> types)
100 : INHERITED(-1, kType_Kind, StringFragment())
101 , fNameString(name)
102 , fTypeKind(kGeneric_Kind)
103 , fNumberKind(kNonnumeric_NumberKind)
104 , fCoercibleTypes(std::move(types)) {
105 fName.fChars = fNameString.c_str();
106 fName.fLength = fNameString.size();
107 }
108
109 // Create a struct type with the given fields.
110 Type(int offset, String name, std::vector<Field> fields)
111 : INHERITED(offset, kType_Kind, StringFragment())
112 , fNameString(std::move(name))
113 , fTypeKind(kStruct_Kind)
114 , fNumberKind(kNonnumeric_NumberKind)
115 , fFields(std::move(fields)) {
116 fName.fChars = fNameString.c_str();
117 fName.fLength = fNameString.size();
118 }
119
120 // Create a scalar type.
121 Type(const char* name, NumberKind numberKind, int priority, bool highPrecision = false)
122 : INHERITED(-1, kType_Kind, StringFragment())
123 , fNameString(name)
124 , fTypeKind(kScalar_Kind)
125 , fNumberKind(numberKind)
126 , fPriority(priority)
127 , fColumns(1)
128 , fRows(1)
129 , fHighPrecision(highPrecision) {
130 fName.fChars = fNameString.c_str();
131 fName.fLength = fNameString.size();
132 }
133
134 // Create a scalar type which can be coerced to the listed types.
135 Type(const char* name,
136 NumberKind numberKind,
137 int priority,
138 std::vector<const Type*> coercibleTypes)
139 : INHERITED(-1, kType_Kind, StringFragment())
140 , fNameString(name)
141 , fTypeKind(kScalar_Kind)
142 , fNumberKind(numberKind)
143 , fPriority(priority)
144 , fCoercibleTypes(std::move(coercibleTypes))
145 , fColumns(1)
146 , fRows(1) {
147 fName.fChars = fNameString.c_str();
148 fName.fLength = fNameString.size();
149 }
150
151 // Create a nullable type.
152 Type(String name, Kind kind, const Type& componentType)
153 : INHERITED(-1, kType_Kind, StringFragment())
154 , fNameString(std::move(name))
155 , fTypeKind(kind)
156 , fNumberKind(kNonnumeric_NumberKind)
157 , fComponentType(&componentType)
158 , fColumns(1)
159 , fRows(1)
160 , fDimensions(SpvDim1D) {
161 fName.fChars = fNameString.c_str();
162 fName.fLength = fNameString.size();
163 }
164
165 // Create a vector type.
166 Type(const char* name, const Type& componentType, int columns)
167 : Type(name, kVector_Kind, componentType, columns) {}
168
169 // Create a vector or array type.
170 Type(String name, Kind kind, const Type& componentType, int columns)
171 : INHERITED(-1, kType_Kind, StringFragment())
172 , fNameString(std::move(name))
173 , fTypeKind(kind)
174 , fNumberKind(kNonnumeric_NumberKind)
175 , fComponentType(&componentType)
176 , fColumns(columns)
177 , fRows(1)
178 , fDimensions(SpvDim1D) {
179 fName.fChars = fNameString.c_str();
180 fName.fLength = fNameString.size();
181 }
182
183 // Create a matrix type.
184 Type(const char* name, const Type& componentType, int columns, int rows)
185 : INHERITED(-1, kType_Kind, StringFragment())
186 , fNameString(name)
187 , fTypeKind(kMatrix_Kind)
188 , fNumberKind(kNonnumeric_NumberKind)
189 , fComponentType(&componentType)
190 , fColumns(columns)
191 , fRows(rows)
192 , fDimensions(SpvDim1D) {
193 fName.fChars = fNameString.c_str();
194 fName.fLength = fNameString.size();
195 }
196
197 // Create a texture type.
198 Type(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed, bool isMultisampled,
199 bool isSampled)
200 : INHERITED(-1, kType_Kind, StringFragment())
201 , fNameString(name)
202 , fTypeKind(kTexture_Kind)
203 , fNumberKind(kNonnumeric_NumberKind)
204 , fDimensions(dimensions)
205 , fIsDepth(isDepth)
206 , fIsArrayed(isArrayed)
207 , fIsMultisampled(isMultisampled)
208 , fIsSampled(isSampled)
209 {
210 fName.fChars = fNameString.c_str();
211 fName.fLength = fNameString.size();
212 }
213
214 // Create a sampler type.
215 Type(const char* name, const Type& textureType)
216 : INHERITED(-1, kType_Kind, StringFragment())
217 , fNameString(name)
218 , fTypeKind(kSampler_Kind)
219 , fNumberKind(kNonnumeric_NumberKind)
220 , fDimensions(textureType.dimensions())
221 , fIsDepth(textureType.isDepth())
222 , fIsArrayed(textureType.isArrayed())
223 , fIsMultisampled(textureType.isMultisampled())
224 , fIsSampled(textureType.isSampled())
225 , fTextureType(&textureType)
226 {
227 fName.fChars = fNameString.c_str();
228 fName.fLength = fNameString.size();
229 }
230
231 const String& name() const {
232 return fNameString;
233 }
234
235 const String displayName() const {
236 if (fNameString == "$floatLiteral") {
237 return "float";
238 }
239 if (fNameString == "$intLiteral") {
240 return "int";
241 }
242 return fNameString;
243 }
244
245#ifdef SK_DEBUG
246 String description() const override {
247 return this->displayName();
248 }
249#endif
250
251 bool operator==(const Type& other) const {
252 return fName == other.fName;
253 }
254
255 bool operator!=(const Type& other) const {
256 return fName != other.fName;
257 }
258
259 /**
260 * Returns the category (scalar, vector, matrix, etc.) of this type.
261 */
262 Kind kind() const {
263 return fTypeKind;
264 }
265
266 /**
267 * Returns true if this is a numeric scalar type.
268 */
269 bool isNumber() const {
270 return fNumberKind != kNonnumeric_NumberKind;
271 }
272
273 /**
274 * Returns true if this is a floating-point scalar type (float, half, or double).
275 */
276 bool isFloat() const {
277 return fNumberKind == kFloat_NumberKind;
278 }
279
280 /**
281 * Returns true if this is a signed scalar type (int or short).
282 */
283 bool isSigned() const {
284 return fNumberKind == kSigned_NumberKind;
285 }
286
287 /**
288 * Returns true if this is an unsigned scalar type (uint or ushort).
289 */
290 bool isUnsigned() const {
291 return fNumberKind == kUnsigned_NumberKind;
292 }
293
294 /**
295 * Returns true if this is a signed or unsigned integer.
296 */
297 bool isInteger() const {
298 return isSigned() || isUnsigned();
299 }
300
301 /**
302 * Returns the "priority" of a number type, in order of double > float > half > int > short.
303 * When operating on two number types, the result is the higher-priority type.
304 */
305 int priority() const {
306 return fPriority;
307 }
308
309 /**
310 * Returns true if an instance of this type can be freely coerced (implicitly converted) to
311 * another type.
312 */
313 bool canCoerceTo(const Type& other) const {
314 return coercionCost(other) != INT_MAX;
315 }
316
317 /**
318 * Determines the "cost" of coercing (implicitly converting) this type to another type. The cost
319 * is a number with no particular meaning other than that lower costs are preferable to higher
320 * costs. Returns INT_MAX if the coercion is not possible.
321 */
322 int coercionCost(const Type& other) const;
323
324 /**
325 * For matrices and vectors, returns the type of individual cells (e.g. mat2 has a component
326 * type of kFloat_Type). For all other types, causes an SkASSERTion failure.
327 */
328 const Type& componentType() const {
329 SkASSERT(fComponentType);
330 return *fComponentType;
331 }
332
333 /**
334 * For texturesamplers, returns the type of texture it samples (e.g., sampler2D has
335 * a texture type of texture2D).
336 */
337 const Type& textureType() const {
338 SkASSERT(fTextureType);
339 return *fTextureType;
340 }
341
342 /**
343 * For nullable types, returns the base type, otherwise returns the type itself.
344 */
345 const Type& nonnullable() const {
346 if (fTypeKind == kNullable_Kind) {
347 return this->componentType();
348 }
349 return *this;
350 }
351
352 /**
353 * For matrices and vectors, returns the number of columns (e.g. both mat3 and float3return 3).
354 * For scalars, returns 1. For arrays, returns either the size of the array (if known) or -1.
355 * For all other types, causes an SkASSERTion failure.
356 */
357 int columns() const {
358 SkASSERT(fTypeKind == kScalar_Kind || fTypeKind == kVector_Kind ||
359 fTypeKind == kMatrix_Kind || fTypeKind == kArray_Kind);
360 return fColumns;
361 }
362
363 /**
364 * For matrices, returns the number of rows (e.g. mat2x4 returns 4). For vectors and scalars,
365 * returns 1. For all other types, causes an SkASSERTion failure.
366 */
367 int rows() const {
368 SkASSERT(fRows > 0);
369 return fRows;
370 }
371
372 const std::vector<Field>& fields() const {
373 SkASSERT(fTypeKind == kStruct_Kind || fTypeKind == kOther_Kind);
374 return fFields;
375 }
376
377 /**
378 * For generic types, returns the types that this generic type can substitute for. For other
379 * types, returns a list of other types that this type can be coerced into.
380 */
381 const std::vector<const Type*>& coercibleTypes() const {
382 SkASSERT(fCoercibleTypes.size() > 0);
383 return fCoercibleTypes;
384 }
385
386 SpvDim_ dimensions() const {
387 SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
388 return fDimensions;
389 }
390
391 bool isDepth() const {
392 SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
393 return fIsDepth;
394 }
395
396 bool isArrayed() const {
397 SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
398 return fIsArrayed;
399 }
400
401 bool isMultisampled() const {
402 SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
403 return fIsMultisampled;
404 }
405
406 bool isSampled() const {
407 SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
408 return fIsSampled;
409 }
410
411 bool highPrecision() const {
412 if (fComponentType) {
413 return fComponentType->highPrecision();
414 }
415 return fHighPrecision;
416 }
417
418 /**
419 * Returns the corresponding vector or matrix type with the specified number of columns and
420 * rows.
421 */
422 const Type& toCompound(const Context& context, int columns, int rows) const;
423
424private:
425 typedef Symbol INHERITED;
426
427 String fNameString;
428 Kind fTypeKind;
429 // always kNonnumeric_NumberKind for non-scalar values
430 NumberKind fNumberKind;
431 int fPriority = -1;
432 const Type* fComponentType = nullptr;
433 std::vector<const Type*> fCoercibleTypes;
434 int fColumns = -1;
435 int fRows = -1;
436 std::vector<Field> fFields;
437 SpvDim_ fDimensions = SpvDim1D;
438 bool fIsDepth = false;
439 bool fIsArrayed = false;
440 bool fIsMultisampled = false;
441 bool fIsSampled = false;
442 bool fHighPrecision = false;
443 const Type* fTextureType = nullptr;
444};
445
446} // namespace
447
448#endif
449