blob: e8c6a653cf43a3ffc464d713908c3c184af47db4 [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SKIASL_TYPE
#define SKIASL_TYPE
#include "src/sksl/SkSLPosition.h"
#include "src/sksl/SkSLUtil.h"
#include "src/sksl/ir/SkSLModifiers.h"
#include "src/sksl/ir/SkSLSymbol.h"
#include "src/sksl/spirv.h"
#include <climits>
#include <vector>
#include <memory>
namespace SkSL {
class Context;
/**
* Represents a type, such as int or float4.
*/
class Type : public Symbol {
public:
struct Field {
Field(Modifiers modifiers, StringFragment name, const Type* type)
: fModifiers(modifiers)
, fName(name)
, fType(std::move(type)) {}
const String description() const {
return fType->displayName() + " " + fName + ";";
}
Modifiers fModifiers;
StringFragment fName;
const Type* fType;
};
enum Kind {
kArray_Kind,
kEnum_Kind,
kGeneric_Kind,
kNullable_Kind,
kMatrix_Kind,
kOther_Kind,
kSampler_Kind,
kSeparateSampler_Kind,
kScalar_Kind,
kStruct_Kind,
kTexture_Kind,
kVector_Kind
};
enum NumberKind {
kFloat_NumberKind,
kSigned_NumberKind,
kUnsigned_NumberKind,
kNonnumeric_NumberKind
};
// Create an "other" (special) type with the given name. These types cannot be directly
// referenced from user code.
Type(const char* name)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(name)
, fTypeKind(kOther_Kind)
, fNumberKind(kNonnumeric_NumberKind) {
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
// Create an "other" (special) type that supports field access.
Type(const char* name, std::vector<Field> fields)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(name)
, fTypeKind(kOther_Kind)
, fNumberKind(kNonnumeric_NumberKind)
, fFields(std::move(fields)) {
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
// Create a simple type.
Type(String name, Kind kind)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(std::move(name))
, fTypeKind(kind)
, fNumberKind(kNonnumeric_NumberKind) {
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
// Create a generic type which maps to the listed types.
Type(const char* name, std::vector<const Type*> types)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(name)
, fTypeKind(kGeneric_Kind)
, fNumberKind(kNonnumeric_NumberKind)
, fCoercibleTypes(std::move(types)) {
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
// Create a struct type with the given fields.
Type(int offset, String name, std::vector<Field> fields)
: INHERITED(offset, kType_Kind, StringFragment())
, fNameString(std::move(name))
, fTypeKind(kStruct_Kind)
, fNumberKind(kNonnumeric_NumberKind)
, fFields(std::move(fields)) {
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
// Create a scalar type.
Type(const char* name, NumberKind numberKind, int priority, bool highPrecision = false)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(name)
, fTypeKind(kScalar_Kind)
, fNumberKind(numberKind)
, fPriority(priority)
, fColumns(1)
, fRows(1)
, fHighPrecision(highPrecision) {
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
// 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)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(name)
, fTypeKind(kScalar_Kind)
, fNumberKind(numberKind)
, fPriority(priority)
, fCoercibleTypes(std::move(coercibleTypes))
, fColumns(1)
, fRows(1) {
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
// Create a nullable type.
Type(String name, Kind kind, const Type& componentType)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(std::move(name))
, fTypeKind(kind)
, fNumberKind(kNonnumeric_NumberKind)
, fComponentType(&componentType)
, fColumns(1)
, fRows(1)
, fDimensions(SpvDim1D) {
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
// Create a vector type.
Type(const char* name, const Type& componentType, int columns)
: Type(name, kVector_Kind, componentType, columns) {}
// Create a vector or array type.
Type(String name, Kind kind, const Type& componentType, int columns)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(std::move(name))
, fTypeKind(kind)
, fNumberKind(kNonnumeric_NumberKind)
, fComponentType(&componentType)
, fColumns(columns)
, fRows(1)
, fDimensions(SpvDim1D) {
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
// Create a matrix type.
Type(const char* name, const Type& componentType, int columns, int rows)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(name)
, fTypeKind(kMatrix_Kind)
, fNumberKind(kNonnumeric_NumberKind)
, fComponentType(&componentType)
, fColumns(columns)
, fRows(rows)
, fDimensions(SpvDim1D) {
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
// Create a texture type.
Type(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed, bool isMultisampled,
bool isSampled)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(name)
, fTypeKind(kTexture_Kind)
, fNumberKind(kNonnumeric_NumberKind)
, fDimensions(dimensions)
, fIsDepth(isDepth)
, fIsArrayed(isArrayed)
, fIsMultisampled(isMultisampled)
, fIsSampled(isSampled)
{
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
// Create a sampler type.
Type(const char* name, const Type& textureType)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(name)
, fTypeKind(kSampler_Kind)
, fNumberKind(kNonnumeric_NumberKind)
, fDimensions(textureType.dimensions())
, fIsDepth(textureType.isDepth())
, fIsArrayed(textureType.isArrayed())
, fIsMultisampled(textureType.isMultisampled())
, fIsSampled(textureType.isSampled())
, fTextureType(&textureType)
{
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
const String& name() const {
return fNameString;
}
const String displayName() const {
if (fNameString == "$floatLiteral") {
return "float";
}
if (fNameString == "$intLiteral") {
return "int";
}
return fNameString;
}
String description() const override {
return this->displayName();
}
bool operator==(const Type& other) const {
return fName == other.fName;
}
bool operator!=(const Type& other) const {
return fName != other.fName;
}
/**
* Returns the category (scalar, vector, matrix, etc.) of this type.
*/
Kind kind() const {
return fTypeKind;
}
/**
* Returns true if this is a numeric scalar type.
*/
bool isNumber() const {
return fNumberKind != kNonnumeric_NumberKind;
}
/**
* Returns true if this is a floating-point scalar type (float or half).
*/
bool isFloat() const {
return fNumberKind == kFloat_NumberKind;
}
/**
* Returns true if this is a signed scalar type (int or short).
*/
bool isSigned() const {
return fNumberKind == kSigned_NumberKind;
}
/**
* Returns true if this is an unsigned scalar type (uint or ushort).
*/
bool isUnsigned() const {
return fNumberKind == kUnsigned_NumberKind;
}
/**
* Returns true if this is a signed or unsigned integer.
*/
bool isInteger() const {
return isSigned() || isUnsigned();
}
/**
* Returns the "priority" of a number type, in order of float > half > int > short.
* When operating on two number types, the result is the higher-priority type.
*/
int priority() const {
return fPriority;
}
/**
* Returns true if an instance of this type can be freely coerced (implicitly converted) to
* another type.
*/
bool canCoerceTo(const Type& other) const {
return coercionCost(other) != INT_MAX;
}
/**
* Determines the "cost" of coercing (implicitly converting) this type to another type. The cost
* is a number with no particular meaning other than that lower costs are preferable to higher
* costs. Returns INT_MAX if the coercion is not possible.
*/
int coercionCost(const Type& other) const;
/**
* For matrices and vectors, returns the type of individual cells (e.g. mat2 has a component
* type of kFloat_Type). For all other types, causes an SkASSERTion failure.
*/
const Type& componentType() const {
SkASSERT(fComponentType);
return *fComponentType;
}
/**
* For texturesamplers, returns the type of texture it samples (e.g., sampler2D has
* a texture type of texture2D).
*/
const Type& textureType() const {
SkASSERT(fTextureType);
return *fTextureType;
}
/**
* For nullable types, returns the base type, otherwise returns the type itself.
*/
const Type& nonnullable() const {
if (fTypeKind == kNullable_Kind) {
return this->componentType();
}
return *this;
}
/**
* For matrices and vectors, returns the number of columns (e.g. both mat3 and float3return 3).
* For scalars, returns 1. For arrays, returns either the size of the array (if known) or -1.
* For all other types, causes an SkASSERTion failure.
*/
int columns() const {
SkASSERT(fTypeKind == kScalar_Kind || fTypeKind == kVector_Kind ||
fTypeKind == kMatrix_Kind || fTypeKind == kArray_Kind);
return fColumns;
}
/**
* For matrices, returns the number of rows (e.g. mat2x4 returns 4). For vectors and scalars,
* returns 1. For all other types, causes an SkASSERTion failure.
*/
int rows() const {
SkASSERT(fRows > 0);
return fRows;
}
const std::vector<Field>& fields() const {
SkASSERT(fTypeKind == kStruct_Kind || fTypeKind == kOther_Kind);
return fFields;
}
/**
* For generic types, returns the types that this generic type can substitute for. For other
* types, returns a list of other types that this type can be coerced into.
*/
const std::vector<const Type*>& coercibleTypes() const {
SkASSERT(fCoercibleTypes.size() > 0);
return fCoercibleTypes;
}
SpvDim_ dimensions() const {
SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fDimensions;
}
bool isDepth() const {
SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsDepth;
}
bool isArrayed() const {
SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsArrayed;
}
bool isMultisampled() const {
SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsMultisampled;
}
bool isSampled() const {
SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsSampled;
}
bool highPrecision() const {
if (fComponentType) {
return fComponentType->highPrecision();
}
return fHighPrecision;
}
/**
* Returns the corresponding vector or matrix type with the specified number of columns and
* rows.
*/
const Type& toCompound(const Context& context, int columns, int rows) const;
private:
typedef Symbol INHERITED;
String fNameString;
Kind fTypeKind;
// always kNonnumeric_NumberKind for non-scalar values
NumberKind fNumberKind;
int fPriority = -1;
const Type* fComponentType = nullptr;
std::vector<const Type*> fCoercibleTypes;
int fColumns = -1;
int fRows = -1;
std::vector<Field> fFields;
SpvDim_ fDimensions = SpvDim1D;
bool fIsDepth = false;
bool fIsArrayed = false;
bool fIsMultisampled = false;
bool fIsSampled = false;
bool fHighPrecision = false;
const Type* fTextureType = nullptr;
};
} // namespace
#endif