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 20 namespace SkSL { 21 22 class Context; 23 24 /** 25 * Represents a type, such as int or float4. 26 */ 27 class Type : public Symbol { 28 public: 29 struct Field { FieldField30 Field(Modifiers modifiers, StringFragment name, const Type* type) 31 : fModifiers(modifiers) 32 , fName(name) 33 , fType(std::move(type)) {} 34 descriptionField35 const String description() const { 36 return fType->description() + " " + 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. Type(const char * name)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. Type(const char * name,std::vector<Field> fields)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. Type(String name,Kind kind)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. Type(const char * name,std::vector<const Type * > 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. Type(int offset,String name,std::vector<Field> 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. Type(const char * name,NumberKind numberKind,int priority,std::vector<const Type * > coercibleTypes)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. Type(String name,Kind kind,const Type & componentType)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. Type(const char * name,const Type & componentType,int columns)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. Type(String name,Kind kind,const Type & componentType,int columns)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. Type(const char * name,const Type & componentType,int columns,int rows)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. Type(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayed,bool isMultisampled,bool isSampled)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. Type(const char * name,const Type & textureType)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 name()231 const String& name() const { 232 return fNameString; 233 } 234 description()235 String description() const override { 236 if (fNameString == "$floatLiteral") { 237 return "float"; 238 } 239 if (fNameString == "$intLiteral") { 240 return "int"; 241 } 242 return fNameString; 243 } 244 245 bool operator==(const Type& other) const { 246 return fName == other.fName; 247 } 248 249 bool operator!=(const Type& other) const { 250 return fName != other.fName; 251 } 252 253 /** 254 * Returns the category (scalar, vector, matrix, etc.) of this type. 255 */ kind()256 Kind kind() const { 257 return fTypeKind; 258 } 259 260 /** 261 * Returns true if this is a numeric scalar type. 262 */ isNumber()263 bool isNumber() const { 264 return fNumberKind != kNonnumeric_NumberKind; 265 } 266 267 /** 268 * Returns true if this is a floating-point scalar type (float, half, or double). 269 */ isFloat()270 bool isFloat() const { 271 return fNumberKind == kFloat_NumberKind; 272 } 273 274 /** 275 * Returns true if this is a signed scalar type (int or short). 276 */ isSigned()277 bool isSigned() const { 278 return fNumberKind == kSigned_NumberKind; 279 } 280 281 /** 282 * Returns true if this is an unsigned scalar type (uint or ushort). 283 */ isUnsigned()284 bool isUnsigned() const { 285 return fNumberKind == kUnsigned_NumberKind; 286 } 287 288 /** 289 * Returns true if this is a signed or unsigned integer. 290 */ isInteger()291 bool isInteger() const { 292 return isSigned() || isUnsigned(); 293 } 294 295 /** 296 * Returns the "priority" of a number type, in order of double > float > half > int > short. 297 * When operating on two number types, the result is the higher-priority type. 298 */ priority()299 int priority() const { 300 return fPriority; 301 } 302 303 /** 304 * Returns true if an instance of this type can be freely coerced (implicitly converted) to 305 * another type. 306 */ canCoerceTo(const Type & other)307 bool canCoerceTo(const Type& other) const { 308 return coercionCost(other) != INT_MAX; 309 } 310 311 /** 312 * Determines the "cost" of coercing (implicitly converting) this type to another type. The cost 313 * is a number with no particular meaning other than that lower costs are preferable to higher 314 * costs. Returns INT_MAX if the coercion is not possible. 315 */ 316 int coercionCost(const Type& other) const; 317 318 /** 319 * For matrices and vectors, returns the type of individual cells (e.g. mat2 has a component 320 * type of kFloat_Type). For all other types, causes an SkASSERTion failure. 321 */ componentType()322 const Type& componentType() const { 323 SkASSERT(fComponentType); 324 return *fComponentType; 325 } 326 327 /** 328 * For texturesamplers, returns the type of texture it samples (e.g., sampler2D has 329 * a texture type of texture2D). 330 */ textureType()331 const Type& textureType() const { 332 SkASSERT(fTextureType); 333 return *fTextureType; 334 } 335 336 /** 337 * For nullable types, returns the base type, otherwise returns the type itself. 338 */ nonnullable()339 const Type& nonnullable() const { 340 if (fTypeKind == kNullable_Kind) { 341 return this->componentType(); 342 } 343 return *this; 344 } 345 346 /** 347 * For matrices and vectors, returns the number of columns (e.g. both mat3 and float3return 3). 348 * For scalars, returns 1. For arrays, returns either the size of the array (if known) or -1. 349 * For all other types, causes an SkASSERTion failure. 350 */ columns()351 int columns() const { 352 SkASSERT(fTypeKind == kScalar_Kind || fTypeKind == kVector_Kind || 353 fTypeKind == kMatrix_Kind || fTypeKind == kArray_Kind); 354 return fColumns; 355 } 356 357 /** 358 * For matrices, returns the number of rows (e.g. mat2x4 returns 4). For vectors and scalars, 359 * returns 1. For all other types, causes an SkASSERTion failure. 360 */ rows()361 int rows() const { 362 SkASSERT(fRows > 0); 363 return fRows; 364 } 365 fields()366 const std::vector<Field>& fields() const { 367 SkASSERT(fTypeKind == kStruct_Kind || fTypeKind == kOther_Kind); 368 return fFields; 369 } 370 371 /** 372 * For generic types, returns the types that this generic type can substitute for. For other 373 * types, returns a list of other types that this type can be coerced into. 374 */ coercibleTypes()375 const std::vector<const Type*>& coercibleTypes() const { 376 SkASSERT(fCoercibleTypes.size() > 0); 377 return fCoercibleTypes; 378 } 379 dimensions()380 SpvDim_ dimensions() const { 381 SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind); 382 return fDimensions; 383 } 384 isDepth()385 bool isDepth() const { 386 SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind); 387 return fIsDepth; 388 } 389 isArrayed()390 bool isArrayed() const { 391 SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind); 392 return fIsArrayed; 393 } 394 isMultisampled()395 bool isMultisampled() const { 396 SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind); 397 return fIsMultisampled; 398 } 399 isSampled()400 bool isSampled() const { 401 SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind); 402 return fIsSampled; 403 } 404 highPrecision()405 bool highPrecision() const { 406 if (fComponentType) { 407 return fComponentType->highPrecision(); 408 } 409 return fHighPrecision; 410 } 411 412 /** 413 * Returns the corresponding vector or matrix type with the specified number of columns and 414 * rows. 415 */ 416 const Type& toCompound(const Context& context, int columns, int rows) const; 417 418 private: 419 typedef Symbol INHERITED; 420 421 String fNameString; 422 Kind fTypeKind; 423 // always kNonnumeric_NumberKind for non-scalar values 424 NumberKind fNumberKind; 425 int fPriority = -1; 426 const Type* fComponentType = nullptr; 427 std::vector<const Type*> fCoercibleTypes; 428 int fColumns = -1; 429 int fRows = -1; 430 std::vector<Field> fFields; 431 SpvDim_ fDimensions = SpvDim1D; 432 bool fIsDepth = false; 433 bool fIsArrayed = false; 434 bool fIsMultisampled = false; 435 bool fIsSampled = false; 436 bool fHighPrecision = false; 437 const Type* fTextureType = nullptr; 438 }; 439 440 } // namespace 441 442 #endif 443