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 "GrShaderVar.h"
14
15#define USE_UNIFORM_FLOAT_ARRAYS true
16
17/**
18 * Represents a variable in a shader
19 */
20class GrGLShaderVar : public GrShaderVar {
21public:
22    /**
23     * See GL_ARB_fragment_coord_conventions.
24     */
25    enum Origin {
26        kDefault_Origin,        // when set to kDefault the origin field is ignored.
27        kUpperLeft_Origin,      // only used to declare vec4 in gl_FragCoord.
28    };
29
30    /**
31     * Defaults to a float with no precision specifier
32     */
33    GrGLShaderVar()
34        : GrShaderVar()
35        , fOrigin(kDefault_Origin)
36        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
37    }
38
39    GrGLShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray,
40                  Precision precision = kDefault_Precision)
41        : GrShaderVar(name, type, arrayCount, precision)
42        , fOrigin(kDefault_Origin)
43        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
44        SkASSERT(kVoid_GrSLType != type);
45        fOrigin = kDefault_Origin;
46        fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
47    }
48
49    GrGLShaderVar(const char* name, GrSLType type, TypeModifier typeModifier,
50                  int arrayCount = kNonArray, Precision precision = kDefault_Precision)
51        : GrShaderVar(name, type, typeModifier, arrayCount, precision)
52        , fOrigin(kDefault_Origin)
53        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
54        SkASSERT(kVoid_GrSLType != type);
55    }
56
57    GrGLShaderVar(const GrShaderVar& var)
58        : GrShaderVar(var)
59        , fOrigin(kDefault_Origin)
60        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
61        SkASSERT(kVoid_GrSLType != var.getType());
62    }
63
64    GrGLShaderVar(const GrGLShaderVar& var)
65        : GrShaderVar(var.c_str(), var.getType(), var.getTypeModifier(),
66                      var.getArrayCount(), var.getPrecision())
67        , fOrigin(var.fOrigin)
68        , fUseUniformFloatArrays(var.fUseUniformFloatArrays) {
69        SkASSERT(kVoid_GrSLType != var.getType());
70    }
71
72    /**
73     * Values for array count that have special meaning. We allow 1-sized arrays.
74     */
75    enum {
76        kNonArray     =  0, // not an array
77        kUnsizedArray = -1, // an unsized array (declared with [])
78    };
79
80    /**
81     * Sets as a non-array.
82     */
83    void set(GrSLType type,
84             TypeModifier typeModifier,
85             const SkString& name,
86             Precision precision = kDefault_Precision,
87             Origin origin = kDefault_Origin,
88             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
89        SkASSERT(kVoid_GrSLType != type);
90        INHERITED::set(type, typeModifier, name, precision);
91        fOrigin = origin;
92        fUseUniformFloatArrays = useUniformFloatArrays;
93    }
94
95    /**
96     * Sets as a non-array.
97     */
98    void set(GrSLType type,
99             TypeModifier typeModifier,
100             const char* name,
101             Precision precision = kDefault_Precision,
102             Origin origin = kDefault_Origin,
103             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
104        SkASSERT(kVoid_GrSLType != type);
105        INHERITED::set(type, typeModifier, name, precision);
106        fOrigin = origin;
107        fUseUniformFloatArrays = useUniformFloatArrays;
108    }
109
110    /**
111     * Set all var options
112     */
113    void set(GrSLType type,
114             TypeModifier typeModifier,
115             const SkString& name,
116             int count,
117             Precision precision = kDefault_Precision,
118             Origin origin = kDefault_Origin,
119             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
120        SkASSERT(kVoid_GrSLType != type);
121        INHERITED::set(type, typeModifier, name, count, precision);
122        fOrigin = origin;
123        fUseUniformFloatArrays = useUniformFloatArrays;
124    }
125
126    /**
127     * Set all var options
128     */
129    void set(GrSLType type,
130             TypeModifier typeModifier,
131             const char* name,
132             int count,
133             Precision precision = kDefault_Precision,
134             Origin origin = kDefault_Origin,
135             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
136        SkASSERT(kVoid_GrSLType != type);
137        INHERITED::set(type, typeModifier, name, count, precision);
138        fOrigin = origin;
139        fUseUniformFloatArrays = useUniformFloatArrays;
140    }
141
142    /**
143     * Get the origin of the var
144     */
145    Origin getOrigin() const { return fOrigin; }
146
147    /**
148     * Set the origin of the var
149     */
150    void setOrigin(Origin origin) { fOrigin = origin; }
151
152    /**
153     * Write a declaration of this variable to out.
154     */
155    void appendDecl(const GrGLContextInfo& ctxInfo, SkString* out) const {
156        if (kUpperLeft_Origin == fOrigin) {
157            // this is the only place where we specify a layout modifier. If we use other layout
158            // modifiers in the future then they should be placed in a list.
159            out->append("layout(origin_upper_left) ");
160        }
161        if (this->getTypeModifier() != kNone_TypeModifier) {
162           out->append(TypeModifierString(this->getTypeModifier(),
163                                          ctxInfo.glslGeneration()));
164           out->append(" ");
165        }
166        out->append(PrecisionString(fPrecision, ctxInfo.standard()));
167        GrSLType effectiveType = this->getType();
168        if (this->isArray()) {
169            if (this->isUnsizedArray()) {
170                out->appendf("%s %s[]",
171                             GrGLSLTypeString(effectiveType),
172                             this->getName().c_str());
173            } else {
174                SkASSERT(this->getArrayCount() > 0);
175                out->appendf("%s %s[%d]",
176                             GrGLSLTypeString(effectiveType),
177                             this->getName().c_str(),
178                             this->getArrayCount());
179            }
180        } else {
181            out->appendf("%s %s",
182                         GrGLSLTypeString(effectiveType),
183                         this->getName().c_str());
184        }
185    }
186
187    void appendArrayAccess(int index, SkString* out) const {
188        out->appendf("%s[%d]%s",
189                     this->getName().c_str(),
190                     index,
191                     fUseUniformFloatArrays ? "" : ".x");
192    }
193
194    void appendArrayAccess(const char* indexName, SkString* out) const {
195        out->appendf("%s[%s]%s",
196                     this->getName().c_str(),
197                     indexName,
198                     fUseUniformFloatArrays ? "" : ".x");
199    }
200
201    static const char* PrecisionString(Precision p, GrGLStandard standard) {
202        // Desktop GLSL has added precision qualifiers but they don't do anything.
203        if (kGLES_GrGLStandard == standard) {
204            switch (p) {
205                case kLow_Precision:
206                    return "lowp ";
207                case kMedium_Precision:
208                    return "mediump ";
209                case kHigh_Precision:
210                    return "highp ";
211                case kDefault_Precision:
212                    return "";
213                default:
214                    SkFAIL("Unexpected precision type.");
215            }
216        }
217        return "";
218    }
219
220private:
221    static const char* TypeModifierString(TypeModifier t, GrGLSLGeneration gen) {
222        switch (t) {
223            case kNone_TypeModifier:
224                return "";
225            case kIn_TypeModifier:
226                return "in";
227            case kInOut_TypeModifier:
228                return "inout";
229            case kOut_TypeModifier:
230                return "out";
231            case kUniform_TypeModifier:
232                return "uniform";
233            case kAttribute_TypeModifier:
234                return k110_GrGLSLGeneration == gen ? "attribute" : "in";
235            case kVaryingIn_TypeModifier:
236                return k110_GrGLSLGeneration == gen ? "varying" : "in";
237            case kVaryingOut_TypeModifier:
238                return k110_GrGLSLGeneration == gen ? "varying" : "out";
239            default:
240                SkFAIL("Unknown shader variable type modifier.");
241                return ""; // suppress warning
242        }
243    }
244
245    Origin          fOrigin;
246    /// Work around driver bugs on some hardware that don't correctly
247    /// support uniform float []
248    bool            fUseUniformFloatArrays;
249
250    typedef GrShaderVar INHERITED;
251};
252
253#endif
254