1/*
2 * Copyright 2011 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 GrGLShaderVar_DEFINED
9#define GrGLShaderVar_DEFINED
10
11#include "GrGLContext.h"
12#include "GrGLSL.h"
13#include "SkString.h"
14
15#define USE_UNIFORM_FLOAT_ARRAYS true
16
17/**
18 * Represents a variable in a shader
19 */
20class GrGLShaderVar {
21public:
22
23    /**
24     * Early versions of GLSL have Varying and Attribute; those are later
25     * deprecated, but we still need to know whether a Varying variable
26     * should be treated as In or Out.
27     */
28    enum TypeModifier {
29        kNone_TypeModifier,
30        kOut_TypeModifier,
31        kIn_TypeModifier,
32        kInOut_TypeModifier,
33        kUniform_TypeModifier,
34        kAttribute_TypeModifier,
35        kVaryingIn_TypeModifier,
36        kVaryingOut_TypeModifier
37    };
38
39    enum Precision {
40        kLow_Precision,         // lowp
41        kMedium_Precision,      // mediump
42        kHigh_Precision,        // highp
43        kDefault_Precision,     // Default for the current context. We make
44                                // fragment shaders default to mediump on ES2
45                                // because highp support is not guaranteed (and
46                                // we haven't been motivated to test for it).
47                                // Otherwise, highp.
48    };
49
50    /**
51     * See GL_ARB_fragment_coord_conventions.
52     */
53    enum Origin {
54        kDefault_Origin,        // when set to kDefault the origin field is ignored.
55        kUpperLeft_Origin,      // only used to declare vec4 in gl_FragCoord.
56    };
57
58    /**
59     * Defaults to a float with no precision specifier
60     */
61    GrGLShaderVar() {
62        fType = kFloat_GrSLType;
63        fTypeModifier = kNone_TypeModifier;
64        fCount = kNonArray;
65        fPrecision = kDefault_Precision;
66        fOrigin = kDefault_Origin;
67        fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
68    }
69
70    GrGLShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray,
71                  Precision precision = kDefault_Precision) {
72        SkASSERT(kVoid_GrSLType != type);
73        fType = type;
74        fTypeModifier = kNone_TypeModifier;
75        fCount = arrayCount;
76        fPrecision = precision;
77        fOrigin = kDefault_Origin;
78        fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
79        fName = name;
80    }
81
82    GrGLShaderVar(const GrGLShaderVar& var)
83        : fType(var.fType)
84        , fTypeModifier(var.fTypeModifier)
85        , fName(var.fName)
86        , fCount(var.fCount)
87        , fPrecision(var.fPrecision)
88        , fOrigin(var.fOrigin)
89        , fUseUniformFloatArrays(var.fUseUniformFloatArrays) {
90        SkASSERT(kVoid_GrSLType != var.fType);
91    }
92
93    /**
94     * Values for array count that have special meaning. We allow 1-sized arrays.
95     */
96    enum {
97        kNonArray     =  0, // not an array
98        kUnsizedArray = -1, // an unsized array (declared with [])
99    };
100
101    /**
102     * Sets as a non-array.
103     */
104    void set(GrSLType type,
105             TypeModifier typeModifier,
106             const SkString& name,
107             Precision precision = kDefault_Precision,
108             Origin origin = kDefault_Origin,
109             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
110        SkASSERT(kVoid_GrSLType != type);
111        fType = type;
112        fTypeModifier = typeModifier;
113        fName = name;
114        fCount = kNonArray;
115        fPrecision = precision;
116        fOrigin = origin;
117        fUseUniformFloatArrays = useUniformFloatArrays;
118    }
119
120    /**
121     * Sets as a non-array.
122     */
123    void set(GrSLType type,
124             TypeModifier typeModifier,
125             const char* name,
126             Precision precision = kDefault_Precision,
127             Origin origin = kDefault_Origin,
128             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
129        SkASSERT(kVoid_GrSLType != type);
130        fType = type;
131        fTypeModifier = typeModifier;
132        fName = name;
133        fCount = kNonArray;
134        fPrecision = precision;
135        fOrigin = origin;
136        fUseUniformFloatArrays = useUniformFloatArrays;
137    }
138
139    /**
140     * Set all var options
141     */
142    void set(GrSLType type,
143             TypeModifier typeModifier,
144             const SkString& name,
145             int count,
146             Precision precision = kDefault_Precision,
147             Origin origin = kDefault_Origin,
148             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
149        SkASSERT(kVoid_GrSLType != type);
150        fType = type;
151        fTypeModifier = typeModifier;
152        fName = name;
153        fCount = count;
154        fPrecision = precision;
155        fOrigin = origin;
156        fUseUniformFloatArrays = useUniformFloatArrays;
157    }
158
159    /**
160     * Set all var options
161     */
162    void set(GrSLType type,
163             TypeModifier typeModifier,
164             const char* name,
165             int count,
166             Precision precision = kDefault_Precision,
167             Origin origin = kDefault_Origin,
168             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
169        SkASSERT(kVoid_GrSLType != type);
170        fType = type;
171        fTypeModifier = typeModifier;
172        fName = name;
173        fCount = count;
174        fPrecision = precision;
175        fOrigin = origin;
176        fUseUniformFloatArrays = useUniformFloatArrays;
177    }
178
179    /**
180     * Is the var an array.
181     */
182    bool isArray() const { return kNonArray != fCount; }
183    /**
184     * Is this an unsized array, (i.e. declared with []).
185     */
186    bool isUnsizedArray() const { return kUnsizedArray == fCount; }
187    /**
188     * Get the array length of the var.
189     */
190    int getArrayCount() const { return fCount; }
191    /**
192     * Set the array length of the var
193     */
194    void setArrayCount(int count) { fCount = count; }
195    /**
196     * Set to be a non-array.
197     */
198    void setNonArray() { fCount = kNonArray; }
199    /**
200     * Set to be an unsized array.
201     */
202    void setUnsizedArray() { fCount = kUnsizedArray; }
203
204    /**
205     * Access the var name as a writable string
206     */
207    SkString* accessName() { return &fName; }
208    /**
209     * Set the var name
210     */
211    void setName(const SkString& n) { fName = n; }
212    void setName(const char* n) { fName = n; }
213
214    /**
215     * Get the var name.
216     */
217    const SkString& getName() const { return fName; }
218
219    /**
220     * Shortcut for this->getName().c_str();
221     */
222    const char* c_str() const { return this->getName().c_str(); }
223
224    /**
225     * Get the type of the var
226     */
227    GrSLType getType() const { return fType; }
228    /**
229     * Set the type of the var
230     */
231    void setType(GrSLType type) { fType = type; }
232
233    TypeModifier getTypeModifier() const { return fTypeModifier; }
234    void setTypeModifier(TypeModifier type) { fTypeModifier = type; }
235
236    /**
237     * Get the precision of the var
238     */
239    Precision getPrecision() const { return fPrecision; }
240
241    /**
242     * Set the precision of the var
243     */
244    void setPrecision(Precision p) { fPrecision = p; }
245
246    /**
247     * Get the origin of the var
248     */
249    Origin getOrigin() const { return fOrigin; }
250
251    /**
252     * Set the origin of the var
253     */
254    void setOrigin(Origin origin) { fOrigin = origin; }
255
256    /**
257     * Write a declaration of this variable to out.
258     */
259    void appendDecl(const GrGLContextInfo& ctxInfo, SkString* out) const {
260        if (kUpperLeft_Origin == fOrigin) {
261            // this is the only place where we specify a layout modifier. If we use other layout
262            // modifiers in the future then they should be placed in a list.
263            out->append("layout(origin_upper_left) ");
264        }
265        if (this->getTypeModifier() != kNone_TypeModifier) {
266           out->append(TypeModifierString(this->getTypeModifier(),
267                                          ctxInfo.glslGeneration()));
268           out->append(" ");
269        }
270        out->append(PrecisionString(fPrecision, ctxInfo.standard()));
271        GrSLType effectiveType = this->getType();
272        if (this->isArray()) {
273            if (this->isUnsizedArray()) {
274                out->appendf("%s %s[]",
275                             GrGLSLTypeString(effectiveType),
276                             this->getName().c_str());
277            } else {
278                SkASSERT(this->getArrayCount() > 0);
279                out->appendf("%s %s[%d]",
280                             GrGLSLTypeString(effectiveType),
281                             this->getName().c_str(),
282                             this->getArrayCount());
283            }
284        } else {
285            out->appendf("%s %s",
286                         GrGLSLTypeString(effectiveType),
287                         this->getName().c_str());
288        }
289    }
290
291    void appendArrayAccess(int index, SkString* out) const {
292        out->appendf("%s[%d]%s",
293                     this->getName().c_str(),
294                     index,
295                     fUseUniformFloatArrays ? "" : ".x");
296    }
297
298    void appendArrayAccess(const char* indexName, SkString* out) const {
299        out->appendf("%s[%s]%s",
300                     this->getName().c_str(),
301                     indexName,
302                     fUseUniformFloatArrays ? "" : ".x");
303    }
304
305    static const char* PrecisionString(Precision p, GrGLStandard standard) {
306        // Desktop GLSL has added precision qualifiers but they don't do anything.
307        if (kGLES_GrGLStandard == standard) {
308            switch (p) {
309                case kLow_Precision:
310                    return "lowp ";
311                case kMedium_Precision:
312                    return "mediump ";
313                case kHigh_Precision:
314                    return "highp ";
315                case kDefault_Precision:
316                    return "";
317                default:
318                    SkFAIL("Unexpected precision type.");
319            }
320        }
321        return "";
322    }
323
324private:
325    static const char* TypeModifierString(TypeModifier t, GrGLSLGeneration gen) {
326        switch (t) {
327            case kNone_TypeModifier:
328                return "";
329            case kIn_TypeModifier:
330                return "in";
331            case kInOut_TypeModifier:
332                return "inout";
333            case kOut_TypeModifier:
334                return "out";
335            case kUniform_TypeModifier:
336                return "uniform";
337            case kAttribute_TypeModifier:
338                return k110_GrGLSLGeneration == gen ? "attribute" : "in";
339            case kVaryingIn_TypeModifier:
340                return k110_GrGLSLGeneration == gen ? "varying" : "in";
341            case kVaryingOut_TypeModifier:
342                return k110_GrGLSLGeneration == gen ? "varying" : "out";
343            default:
344                SkFAIL("Unknown shader variable type modifier.");
345                return ""; // suppress warning
346        }
347    }
348
349    GrSLType        fType;
350    TypeModifier    fTypeModifier;
351    SkString        fName;
352    int             fCount;
353    Precision       fPrecision;
354    Origin          fOrigin;
355    /// Work around driver bugs on some hardware that don't correctly
356    /// support uniform float []
357    bool            fUseUniformFloatArrays;
358};
359
360#endif
361