aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/sksl/ir/SkSLType.h
blob: ed4b8d5abee33fa316b05b8ca43b8b8432786679 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/*
 * 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 "SkSLModifiers.h"
#include "SkSLSymbol.h"
#include "../SkSLPosition.h"
#include "../SkSLUtil.h"
#include "../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->description() + " " + fName + ";";
        }

        Modifiers fModifiers;
        StringFragment fName;
        const Type* fType;
    };

    enum Kind {
        kArray_Kind,
        kEnum_Kind,
        kGeneric_Kind,
        kMatrix_Kind,
        kOther_Kind,
        kSampler_Kind,
        kScalar_Kind,
        kStruct_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(String name)
    : INHERITED(-1, kType_Kind, StringFragment())
    , fNameString(std::move(name))
    , fTypeKind(kOther_Kind)
    , fNumberKind(kNonnumeric_NumberKind) {
        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(String name, std::vector<const Type*> types)
    : INHERITED(-1, kType_Kind, StringFragment())
    , fNameString(std::move(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(String name, NumberKind numberKind, int priority)
    : INHERITED(-1, kType_Kind, StringFragment())
    , fNameString(std::move(name))
    , fTypeKind(kScalar_Kind)
    , fNumberKind(numberKind)
    , fPriority(priority)
    , fColumns(1)
    , fRows(1) {
        fName.fChars = fNameString.c_str();
        fName.fLength = fNameString.size();
    }

    // Create a scalar type which can be coerced to the listed types.
    Type(String name, NumberKind numberKind, int priority, std::vector<const Type*> coercibleTypes)
    : INHERITED(-1, kType_Kind, StringFragment())
    , fNameString(std::move(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 vector type.
    Type(String 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(String name, const Type& componentType, int columns, int rows)
    : INHERITED(-1, kType_Kind, StringFragment())
    , fNameString(std::move(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 sampler type.
    Type(String name, SpvDim_ dimensions, bool isDepth, bool isArrayed, bool isMultisampled,
         bool isSampled)
    : INHERITED(-1, kType_Kind, StringFragment())
    , fNameString(std::move(name))
    , fTypeKind(kSampler_Kind)
    , fNumberKind(kNonnumeric_NumberKind)
    , fDimensions(dimensions)
    , fIsDepth(isDepth)
    , fIsArrayed(isArrayed)
    , fIsMultisampled(isMultisampled)
    , fIsSampled(isSampled) {
        fName.fChars = fNameString.c_str();
        fName.fLength = fNameString.size();
    }

    const String& name() const {
        return fNameString;
    }

    String description() const override {
        return fNameString;
    }

    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, half, or double).
     */
    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 double > 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 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);
        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);
        return fDimensions;
    }

    bool isDepth() const {
        SkASSERT(kSampler_Kind == fTypeKind);
        return fIsDepth;
    }

    bool isArrayed() const {
        SkASSERT(kSampler_Kind == fTypeKind);
        return fIsArrayed;
    }

    bool isMultisampled() const {
        SkASSERT(kSampler_Kind == fTypeKind);
        return fIsMultisampled;
    }

    bool isSampled() const {
        SkASSERT(kSampler_Kind == fTypeKind);
        return fIsSampled;
    }

    /**
     * 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;
};

} // namespace

#endif