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                  GrSLPrecision precision = kDefault_GrSLPrecision)
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, GrSLPrecision precision = kDefault_GrSLPrecision)
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             GrSLPrecision precision = kDefault_GrSLPrecision,
87             Origin origin = kDefault_Origin,
88             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
89        SkASSERT(kVoid_GrSLType != type);
90        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsFloatType(type));
91        INHERITED::set(type, name, typeModifier, precision);
92        fOrigin = origin;
93        fUseUniformFloatArrays = useUniformFloatArrays;
94    }
95
96    /**
97     * Sets as a non-array.
98     */
99    void set(GrSLType type,
100             TypeModifier typeModifier,
101             const char* name,
102             GrSLPrecision precision = kDefault_GrSLPrecision,
103             Origin origin = kDefault_Origin,
104             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
105        SkASSERT(kVoid_GrSLType != type);
106        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsFloatType(type));
107        INHERITED::set(type, name, typeModifier, precision);
108        fOrigin = origin;
109        fUseUniformFloatArrays = useUniformFloatArrays;
110    }
111
112    /**
113     * Set all var options
114     */
115    void set(GrSLType type,
116             TypeModifier typeModifier,
117             const SkString& name,
118             int count,
119             GrSLPrecision precision = kDefault_GrSLPrecision,
120             Origin origin = kDefault_Origin,
121             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
122        SkASSERT(kVoid_GrSLType != type);
123        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsFloatType(type));
124        INHERITED::set(type, name, typeModifier, precision, count);
125        fOrigin = origin;
126        fUseUniformFloatArrays = useUniformFloatArrays;
127    }
128
129    /**
130     * Set all var options
131     */
132    void set(GrSLType type,
133             TypeModifier typeModifier,
134             const char* name,
135             int count,
136             GrSLPrecision precision = kDefault_GrSLPrecision,
137             Origin origin = kDefault_Origin,
138             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
139        SkASSERT(kVoid_GrSLType != type);
140        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsFloatType(type));
141        INHERITED::set(type, name, typeModifier, precision, count);
142        fOrigin = origin;
143        fUseUniformFloatArrays = useUniformFloatArrays;
144    }
145
146    /**
147     * Get the origin of the var
148     */
149    Origin getOrigin() const { return fOrigin; }
150
151    /**
152     * Set the origin of the var
153     */
154    void setOrigin(Origin origin) { fOrigin = origin; }
155
156    /**
157     * Write a declaration of this variable to out.
158     */
159    void appendDecl(const GrGLContextInfo& ctxInfo, SkString* out) const {
160        SkASSERT(kDefault_GrSLPrecision == fPrecision || GrSLTypeIsFloatType(fType));
161        if (kUpperLeft_Origin == fOrigin) {
162            // this is the only place where we specify a layout modifier. If we use other layout
163            // modifiers in the future then they should be placed in a list.
164            out->append("layout(origin_upper_left) ");
165        }
166        if (this->getTypeModifier() != kNone_TypeModifier) {
167           out->append(TypeModifierString(this->getTypeModifier(), ctxInfo.glslGeneration()));
168           out->append(" ");
169        }
170        out->append(PrecisionString(fPrecision, ctxInfo.standard()));
171        GrSLType effectiveType = this->getType();
172        if (this->isArray()) {
173            if (this->isUnsizedArray()) {
174                out->appendf("%s %s[]",
175                             GrGLSLTypeString(effectiveType),
176                             this->getName().c_str());
177            } else {
178                SkASSERT(this->getArrayCount() > 0);
179                out->appendf("%s %s[%d]",
180                             GrGLSLTypeString(effectiveType),
181                             this->getName().c_str(),
182                             this->getArrayCount());
183            }
184        } else {
185            out->appendf("%s %s",
186                         GrGLSLTypeString(effectiveType),
187                         this->getName().c_str());
188        }
189    }
190
191    void appendArrayAccess(int index, SkString* out) const {
192        out->appendf("%s[%d]%s",
193                     this->getName().c_str(),
194                     index,
195                     fUseUniformFloatArrays ? "" : ".x");
196    }
197
198    void appendArrayAccess(const char* indexName, SkString* out) const {
199        out->appendf("%s[%s]%s",
200                     this->getName().c_str(),
201                     indexName,
202                     fUseUniformFloatArrays ? "" : ".x");
203    }
204
205    static const char* PrecisionString(GrSLPrecision p, GrGLStandard standard) {
206        // Desktop GLSL has added precision qualifiers but they don't do anything.
207        if (kGLES_GrGLStandard == standard) {
208            switch (p) {
209                case kLow_GrSLPrecision:
210                    return "lowp ";
211                case kMedium_GrSLPrecision:
212                    return "mediump ";
213                case kHigh_GrSLPrecision:
214                    return "highp ";
215                default:
216                    SkFAIL("Unexpected precision type.");
217            }
218        }
219        return "";
220    }
221
222private:
223    static const char* TypeModifierString(TypeModifier t, GrGLSLGeneration gen) {
224        switch (t) {
225            case kNone_TypeModifier:
226                return "";
227            case kIn_TypeModifier:
228                return "in";
229            case kInOut_TypeModifier:
230                return "inout";
231            case kOut_TypeModifier:
232                return "out";
233            case kUniform_TypeModifier:
234                return "uniform";
235            case kAttribute_TypeModifier:
236                return k110_GrGLSLGeneration == gen ? "attribute" : "in";
237            case kVaryingIn_TypeModifier:
238                return k110_GrGLSLGeneration == gen ? "varying" : "in";
239            case kVaryingOut_TypeModifier:
240                return k110_GrGLSLGeneration == gen ? "varying" : "out";
241            default:
242                SkFAIL("Unknown shader variable type modifier.");
243                return ""; // suppress warning
244        }
245    }
246
247    Origin          fOrigin;
248    /// Work around driver bugs on some hardware that don't correctly
249    /// support uniform float []
250    bool            fUseUniformFloatArrays;
251
252    typedef GrShaderVar INHERITED;
253};
254
255#endif
256