1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#ifndef GrGLShaderVar_DEFINED
10#define GrGLShaderVar_DEFINED
11
12#include "GrGLContextInfo.h"
13#include "GrGLSL.h"
14#include "../GrStringBuilder.h"
15
16#define USE_UNIFORM_FLOAT_ARRAYS true
17
18/**
19 * Represents a variable in a shader
20 */
21class GrGLShaderVar {
22public:
23
24    enum Type {
25        kFloat_Type,
26        kVec2f_Type,
27        kVec3f_Type,
28        kVec4f_Type,
29        kMat33f_Type,
30        kMat44f_Type,
31        kSampler2D_Type,
32    };
33
34    /**
35     * Early versions of GLSL have Varying and Attribute; those are later
36     * deprecated, but we still need to know whether a Varying variable
37     * should be treated as In or Out.
38     */
39    enum TypeModifier {
40        kNone_TypeModifier,
41        kOut_TypeModifier,
42        kIn_TypeModifier,
43        kUniform_TypeModifier,
44        kAttribute_TypeModifier
45    };
46
47    /**
48     * Defaults to a float with no precision specifier
49     */
50    GrGLShaderVar() {
51        fType = kFloat_Type;
52        fTypeModifier = kNone_TypeModifier;
53        fCount = kNonArray;
54        fEmitPrecision = false;
55        fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
56    }
57
58    GrGLShaderVar(const GrGLShaderVar& var)
59        : fType(var.fType)
60        , fTypeModifier(var.fTypeModifier)
61        , fName(var.fName)
62        , fCount(var.fCount)
63        , fEmitPrecision(var.fEmitPrecision)
64        , fUseUniformFloatArrays(var.fUseUniformFloatArrays) {}
65
66    /**
67     * Values for array count that have special meaning. We allow 1-sized arrays.
68     */
69    enum {
70        kNonArray     =  0, // not an array
71        kUnsizedArray = -1, // an unsized array (declared with [])
72    };
73
74    /**
75     * Sets as a non-array.
76     */
77    void set(Type type,
78             TypeModifier typeModifier,
79             const GrStringBuilder& name,
80             bool emitPrecision = false,
81             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
82        fType = type;
83        fTypeModifier = typeModifier;
84        fName = name;
85        fCount = kNonArray;
86        fEmitPrecision = emitPrecision;
87        fUseUniformFloatArrays = useUniformFloatArrays;
88    }
89
90    /**
91     * Sets as a non-array.
92     */
93    void set(Type type,
94             TypeModifier typeModifier,
95             const char* name,
96             bool specifyPrecision = false,
97             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
98        fType = type;
99        fTypeModifier = typeModifier;
100        fName = name;
101        fCount = kNonArray;
102        fEmitPrecision = specifyPrecision;
103        fUseUniformFloatArrays = useUniformFloatArrays;
104    }
105
106    /**
107     * Set all var options
108     */
109    void set(Type type,
110             TypeModifier typeModifier,
111             const GrStringBuilder& name,
112             int count,
113             bool specifyPrecision = false,
114             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
115        fType = type;
116        fTypeModifier = typeModifier;
117        fName = name;
118        fCount = count;
119        fEmitPrecision = specifyPrecision;
120        fUseUniformFloatArrays = useUniformFloatArrays;
121    }
122
123    /**
124     * Set all var options
125     */
126    void set(Type type,
127             TypeModifier typeModifier,
128             const char* name,
129             int count,
130             bool specifyPrecision = false,
131             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
132        fType = type;
133        fTypeModifier = typeModifier;
134        fName = name;
135        fCount = count;
136        fEmitPrecision = specifyPrecision;
137        fUseUniformFloatArrays = useUniformFloatArrays;
138    }
139
140    /**
141     * Is the var an array.
142     */
143    bool isArray() const { return kNonArray != fCount; }
144    /**
145     * Is this an unsized array, (i.e. declared with []).
146     */
147    bool isUnsizedArray() const { return kUnsizedArray == fCount; }
148    /**
149     * Get the array length of the var.
150     */
151    int getArrayCount() const { return fCount; }
152    /**
153     * Set the array length of the var
154     */
155    void setArrayCount(int count) { fCount = count; }
156    /**
157     * Set to be a non-array.
158     */
159    void setNonArray() { fCount = kNonArray; }
160    /**
161     * Set to be an unsized array.
162     */
163    void setUnsizedArray() { fCount = kUnsizedArray; }
164
165    /**
166     * Access the var name as a writable string
167     */
168    GrStringBuilder* accessName() { return &fName; }
169    /**
170     * Set the var name
171     */
172    void setName(const GrStringBuilder& n) { fName = n; }
173    void setName(const char* n) { fName = n; }
174    /**
175     * Get the var name.
176     */
177    const GrStringBuilder& getName() const { return fName; }
178
179    /**
180     * Get the type of the var
181     */
182    Type getType() const { return fType; }
183    /**
184     * Set the type of the var
185     */
186    void setType(Type type) { fType = type; }
187
188    TypeModifier getTypeModifier() const { return fTypeModifier; }
189    void setTypeModifier(TypeModifier type) { fTypeModifier = type; }
190
191    /**
192     * Must the variable declaration emit a precision specifier
193     */
194    bool emitsPrecision() const { return fEmitPrecision; }
195    /**
196     * Specify whether the declaration should specify precision
197     */
198    void setEmitPrecision(bool p) { fEmitPrecision = p; }
199
200    /**
201     * Write a declaration of this variable to out.
202     */
203    void appendDecl(const GrGLContextInfo& gl, GrStringBuilder* out) const {
204        if (this->getTypeModifier() != kNone_TypeModifier) {
205           out->append(TypeModifierString(this->getTypeModifier(),
206                                          gl.glslGeneration()));
207           out->append(" ");
208        }
209        if (this->emitsPrecision()) {
210            out->append(GrGetGLSLVarPrecisionDeclType(gl.binding()));
211            out->append(" ");
212        }
213        Type effectiveType = this->getType();
214        if (this->isArray()) {
215            if (this->isUnsizedArray()) {
216                out->appendf("%s %s[]",
217                             TypeString(effectiveType),
218                             this->getName().c_str());
219            } else {
220                GrAssert(this->getArrayCount() > 0);
221                out->appendf("%s %s[%d]",
222                             TypeString(effectiveType),
223                             this->getName().c_str(),
224                             this->getArrayCount());
225            }
226        } else {
227            out->appendf("%s %s",
228                         TypeString(effectiveType),
229                         this->getName().c_str());
230        }
231        out->append(";\n");
232    }
233
234    static const char* TypeString(Type t) {
235        switch (t) {
236            case kFloat_Type:
237                return "float";
238            case kVec2f_Type:
239                return "vec2";
240            case kVec3f_Type:
241                return "vec3";
242            case kVec4f_Type:
243                return "vec4";
244            case kMat33f_Type:
245                return "mat3";
246            case kMat44f_Type:
247                return "mat4";
248            case kSampler2D_Type:
249                return "sampler2D";
250            default:
251                GrCrash("Unknown shader var type.");
252                return ""; // suppress warning
253        }
254    }
255
256    void appendArrayAccess(int index, GrStringBuilder* out) {
257        out->appendf("%s[%d]%s",
258                     this->getName().c_str(),
259                     index,
260                     fUseUniformFloatArrays ? "" : ".x");
261    }
262
263    void appendArrayAccess(const char* indexName, GrStringBuilder* out) {
264        out->appendf("%s[%s]%s",
265                     this->getName().c_str(),
266                     indexName,
267                     fUseUniformFloatArrays ? "" : ".x");
268    }
269
270private:
271    static const char* TypeModifierString(TypeModifier t,
272                                          GrGLSLGeneration gen) {
273        switch (t) {
274            case kNone_TypeModifier:
275                return "";
276            case kOut_TypeModifier:
277                return k110_GrGLSLGeneration == gen ? "varying" : "out";
278            case kIn_TypeModifier:
279                return k110_GrGLSLGeneration == gen ? "varying" : "in";
280            case kUniform_TypeModifier:
281                return "uniform";
282            case kAttribute_TypeModifier:
283                return k110_GrGLSLGeneration == gen ? "attribute" : "in";
284            default:
285                GrCrash("Unknown shader variable type modifier.");
286                return ""; // suppress warning
287        }
288    }
289
290    Type            fType;
291    TypeModifier    fTypeModifier;
292    GrStringBuilder fName;
293    int             fCount;
294    bool            fEmitPrecision;
295    /// Work around driver bugs on some hardware that don't correctly
296    /// support uniform float []
297    bool            fUseUniformFloatArrays;
298};
299
300#endif
301