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 GrShaderVar_DEFINED
9#define GrShaderVar_DEFINED
10
11#include "SkString.h"
12#include "GrTypesPriv.h"
13
14class GrShaderCaps;
15
16#define USE_UNIFORM_FLOAT_ARRAYS true
17
18/**
19 * Represents a variable in a shader
20 */
21class GrShaderVar {
22public:
23    enum TypeModifier {
24        kNone_TypeModifier,
25        kOut_TypeModifier,
26        kIn_TypeModifier,
27        kInOut_TypeModifier,
28        kUniform_TypeModifier,
29    };
30
31    /**
32     * Values for array count that have special meaning. We allow 1-sized arrays.git
33     */
34    enum {
35        kNonArray     =  0, // not an array
36        kUnsizedArray = -1, // an unsized array (declared with [])
37    };
38
39    /**
40     * Defaults to a non-arry half with no type modifier or layout qualifier.
41     */
42    GrShaderVar()
43        : fType(kHalf_GrSLType)
44        , fTypeModifier(kNone_TypeModifier)
45        , fCount(kNonArray)
46        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
47    }
48
49    GrShaderVar(const SkString& name, GrSLType type, int arrayCount = kNonArray,
50                GrSLPrecision precision = kDefault_GrSLPrecision)
51        : fType(type)
52        , fTypeModifier(kNone_TypeModifier)
53        , fCount(arrayCount)
54        , fPrecision(precision)
55        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
56        , fName(name) {
57        SkASSERT(kVoid_GrSLType != type);
58        fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
59    }
60
61    GrShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray,
62                GrSLPrecision precision = kDefault_GrSLPrecision)
63        : fType(type)
64        , fTypeModifier(kNone_TypeModifier)
65        , fCount(arrayCount)
66        , fPrecision(precision)
67        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
68        , fName(name) {
69        SkASSERT(kVoid_GrSLType != type);
70        fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
71    }
72
73    GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier,
74                GrSLPrecision precision = kDefault_GrSLPrecision)
75        : fType(type)
76        , fTypeModifier(typeModifier)
77        , fCount(kNonArray)
78        , fPrecision(precision)
79        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
80        , fName(name) {
81        SkASSERT(kVoid_GrSLType != type);
82    }
83
84    GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier,
85                int arrayCount, GrSLPrecision precision = kDefault_GrSLPrecision)
86        : fType(type)
87        , fTypeModifier(typeModifier)
88        , fCount(arrayCount)
89        , fPrecision(precision)
90        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
91        , fName(name) {
92        SkASSERT(kVoid_GrSLType != type);
93    }
94
95    GrShaderVar(const GrShaderVar& that)
96        : fType(that.fType)
97        , fTypeModifier(that.fTypeModifier)
98        , fCount(that.fCount)
99        , fPrecision(that.fPrecision)
100        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
101        , fName(that.fName)
102        , fLayoutQualifier(that.fLayoutQualifier)
103        , fExtraModifiers(that.fExtraModifiers) {
104        SkASSERT(kVoid_GrSLType != that.getType());
105    }
106
107    /**
108     * Sets as a non-array.
109     */
110    void set(GrSLType type,
111             const SkString& name,
112             TypeModifier typeModifier = kNone_TypeModifier,
113             GrSLPrecision precision = kDefault_GrSLPrecision,
114             const char* layoutQualifier = nullptr,
115             const char* extraModifiers = nullptr,
116             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
117        SkASSERT(kVoid_GrSLType != type);
118        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeTemporarilyAcceptsPrecision(type));
119        fType = type;
120        fTypeModifier = typeModifier;
121        fName = name;
122        fCount = kNonArray;
123        fPrecision = precision;
124        fLayoutQualifier = layoutQualifier;
125        if (extraModifiers) {
126            fExtraModifiers.printf("%s ", extraModifiers);
127        }
128        fUseUniformFloatArrays = useUniformFloatArrays;
129    }
130
131    /**
132     * Sets as a non-array.
133     */
134    void set(GrSLType type,
135             const char* name,
136             TypeModifier typeModifier = kNone_TypeModifier,
137             GrSLPrecision precision = kDefault_GrSLPrecision,
138             const char* layoutQualifier = nullptr,
139             const char* extraModifiers = nullptr,
140             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
141        SkASSERT(kVoid_GrSLType != type);
142        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeTemporarilyAcceptsPrecision(type));
143        fType = type;
144        fTypeModifier = typeModifier;
145        fName = name;
146        fCount = kNonArray;
147        fPrecision = precision;
148        fLayoutQualifier = layoutQualifier;
149        if (extraModifiers) {
150            fExtraModifiers.printf("%s ", extraModifiers);
151        }
152        fUseUniformFloatArrays = useUniformFloatArrays;
153    }
154
155    /**
156     * Set all var options
157     */
158    void set(GrSLType type,
159             const SkString& name,
160             int count,
161             TypeModifier typeModifier,
162             GrSLPrecision precision = kDefault_GrSLPrecision,
163             const char* layoutQualifier = nullptr,
164             const char* extraModifiers = nullptr,
165             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
166        SkASSERT(kVoid_GrSLType != type);
167        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeTemporarilyAcceptsPrecision(type));
168        fType = type;
169        fTypeModifier = typeModifier;
170        fName = name;
171        fCount = count;
172        fPrecision = precision;
173        fLayoutQualifier = layoutQualifier;
174        if (extraModifiers) {
175            fExtraModifiers.printf("%s ", extraModifiers);
176        }
177        fUseUniformFloatArrays = useUniformFloatArrays;
178    }
179
180    /**
181     * Set all var options
182     */
183    void set(GrSLType type,
184             const char* name,
185             int count,
186             TypeModifier typeModifier,
187             GrSLPrecision precision = kDefault_GrSLPrecision,
188             const char* layoutQualifier = nullptr,
189             const char* extraModifiers = nullptr,
190             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
191        SkASSERT(kVoid_GrSLType != type);
192        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeTemporarilyAcceptsPrecision(type));
193        fType = type;
194        fTypeModifier = typeModifier;
195        fName = name;
196        fCount = count;
197        fPrecision = precision;
198        fLayoutQualifier = layoutQualifier;
199        if (extraModifiers) {
200            fExtraModifiers.printf("%s ", extraModifiers);
201        }
202        fUseUniformFloatArrays = useUniformFloatArrays;
203    }
204
205    /**
206     * Is the var an array.
207     */
208    bool isArray() const { return kNonArray != fCount; }
209    /**
210     * Is this an unsized array, (i.e. declared with []).
211     */
212    bool isUnsizedArray() const { return kUnsizedArray == fCount; }
213    /**
214     * Get the array length of the var.
215     */
216    int getArrayCount() const { return fCount; }
217    /**
218     * Set the array length of the var
219     */
220    void setArrayCount(int count) { fCount = count; }
221    /**
222     * Set to be a non-array.
223     */
224    void setNonArray() { fCount = kNonArray; }
225    /**
226     * Set to be an unsized array.
227     */
228    void setUnsizedArray() { fCount = kUnsizedArray; }
229
230    /**
231     * Access the var name as a writable string
232     */
233    SkString* accessName() { return &fName; }
234    /**
235     * Set the var name
236     */
237    void setName(const SkString& n) { fName = n; }
238    void setName(const char* n) { fName = n; }
239
240    /**
241     * Get the var name.
242     */
243    const SkString& getName() const { return fName; }
244
245    /**
246     * Shortcut for this->getName().c_str();
247     */
248    const char* c_str() const { return this->getName().c_str(); }
249
250    /**
251     * Get the type of the var
252     */
253    GrSLType getType() const { return fType; }
254    /**
255     * Set the type of the var
256     */
257    void setType(GrSLType type) { fType = type; }
258
259    TypeModifier getTypeModifier() const { return fTypeModifier; }
260    void setTypeModifier(TypeModifier type) { fTypeModifier = type; }
261
262    /**
263     * Get the precision of the var
264     */
265    GrSLPrecision getPrecision() const { return fPrecision; }
266
267    /**
268     * Set the precision of the var
269     */
270    void setPrecision(GrSLPrecision p) { fPrecision = p; }
271
272    /**
273     * Appends to the layout qualifier
274     */
275    void addLayoutQualifier(const char* layoutQualifier) {
276        if (!layoutQualifier || !strlen(layoutQualifier)) {
277            return;
278        }
279        if (fLayoutQualifier.isEmpty()) {
280            fLayoutQualifier = layoutQualifier;
281        } else {
282            fLayoutQualifier.appendf(", %s", layoutQualifier);
283        }
284    }
285
286    void setIOType(GrIOType);
287
288    void addModifier(const char* modifier) {
289        if (modifier) {
290            fExtraModifiers.appendf("%s ", modifier);
291        }
292    }
293
294    /**
295     * Write a declaration of this variable to out.
296     */
297    void appendDecl(const GrShaderCaps*, SkString* out) const;
298
299    void appendArrayAccess(int index, SkString* out) const {
300        out->appendf("%s[%d]%s",
301                     this->getName().c_str(),
302                     index,
303                     fUseUniformFloatArrays ? "" : ".x");
304    }
305
306    void appendArrayAccess(const char* indexName, SkString* out) const {
307        out->appendf("%s[%s]%s",
308                     this->getName().c_str(),
309                     indexName,
310                     fUseUniformFloatArrays ? "" : ".x");
311    }
312
313private:
314    GrSLType        fType;
315    TypeModifier    fTypeModifier;
316    int             fCount;
317    GrSLPrecision   fPrecision;
318    /// Work around driver bugs on some hardware that don't correctly
319    /// support uniform float []
320    bool            fUseUniformFloatArrays;
321
322    SkString        fName;
323    SkString        fLayoutQualifier;
324    SkString        fExtraModifiers;
325};
326
327#endif
328