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 GrGLSLShaderVar_DEFINED
9#define GrGLSLShaderVar_DEFINED
10
11#include "GrShaderVar.h"
12#include "../glsl/GrGLSL.h"
13#include "../glsl/GrGLSLCaps.h"
14
15#define USE_UNIFORM_FLOAT_ARRAYS true
16
17/**
18 * Represents a variable in a shader
19 */
20class GrGLSLShaderVar : public GrShaderVar {
21public:
22    /**
23     * Defaults to a float with no precision specifier
24     */
25    GrGLSLShaderVar()
26        : GrShaderVar()
27        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
28    }
29
30    GrGLSLShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray,
31                    GrSLPrecision precision = kDefault_GrSLPrecision)
32        : GrShaderVar(name, type, arrayCount, precision)
33        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
34        SkASSERT(kVoid_GrSLType != type);
35        fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
36    }
37
38    GrGLSLShaderVar(const char* name, GrSLType type, TypeModifier typeModifier,
39                    int arrayCount = kNonArray, GrSLPrecision precision = kDefault_GrSLPrecision)
40        : GrShaderVar(name, type, typeModifier, arrayCount, precision)
41        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
42        SkASSERT(kVoid_GrSLType != type);
43    }
44
45    GrGLSLShaderVar(const GrShaderVar& var)
46        : GrShaderVar(var)
47        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
48        SkASSERT(kVoid_GrSLType != var.getType());
49    }
50
51    GrGLSLShaderVar(const GrGLSLShaderVar& var)
52        : GrShaderVar(var.c_str(), var.getType(), var.getTypeModifier(),
53                      var.getArrayCount(), var.getPrecision())
54        , fUseUniformFloatArrays(var.fUseUniformFloatArrays)
55        , fLayoutQualifier(var.fLayoutQualifier)
56        , fExtraModifiers(var.fExtraModifiers) {
57        SkASSERT(kVoid_GrSLType != var.getType());
58    }
59
60    /**
61     * Values for array count that have special meaning. We allow 1-sized arrays.
62     */
63    enum {
64        kNonArray     =  0, // not an array
65        kUnsizedArray = -1, // an unsized array (declared with [])
66    };
67
68    /**
69     * Sets as a non-array.
70     */
71    void set(GrSLType type,
72             TypeModifier typeModifier,
73             const SkString& name,
74             GrSLPrecision precision = kDefault_GrSLPrecision,
75             const char* layoutQualifier = nullptr,
76             const char* extraModifiers = nullptr,
77             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
78        SkASSERT(kVoid_GrSLType != type);
79        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type));
80        INHERITED::set(type, name, typeModifier, precision);
81        fLayoutQualifier = layoutQualifier;
82        if (extraModifiers) {
83            fExtraModifiers.printf("%s ", extraModifiers);
84        }
85        fUseUniformFloatArrays = useUniformFloatArrays;
86    }
87
88    /**
89     * Sets as a non-array.
90     */
91    void set(GrSLType type,
92             TypeModifier typeModifier,
93             const char* name,
94             GrSLPrecision precision = kDefault_GrSLPrecision,
95             const char* layoutQualifier = nullptr,
96             const char* extraModifiers = nullptr,
97             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
98        SkASSERT(kVoid_GrSLType != type);
99        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type));
100        INHERITED::set(type, name, typeModifier, precision);
101        fLayoutQualifier = layoutQualifier;
102        if (extraModifiers) {
103            fExtraModifiers.printf("%s ", extraModifiers);
104        }
105        fUseUniformFloatArrays = useUniformFloatArrays;
106    }
107
108    /**
109     * Set all var options
110     */
111    void set(GrSLType type,
112             TypeModifier typeModifier,
113             const SkString& name,
114             int count,
115             GrSLPrecision precision = kDefault_GrSLPrecision,
116             const char* layoutQualifier = nullptr,
117             const char* extraModifiers = nullptr,
118             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
119        SkASSERT(kVoid_GrSLType != type);
120        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type));
121        INHERITED::set(type, name, typeModifier, precision, count);
122        fLayoutQualifier = layoutQualifier;
123        if (extraModifiers) {
124            fExtraModifiers.printf("%s ", extraModifiers);
125        }
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             const char* layoutQualifier = nullptr,
138             const char* extraModifiers = nullptr,
139             bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
140        SkASSERT(kVoid_GrSLType != type);
141        SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type));
142        INHERITED::set(type, name, typeModifier, precision, count);
143        fLayoutQualifier = layoutQualifier;
144        if (extraModifiers) {
145            fExtraModifiers.printf("%s ", extraModifiers);
146        }
147        fUseUniformFloatArrays = useUniformFloatArrays;
148    }
149
150    /**
151     * Set the layout qualifier
152     */
153    void setLayoutQualifier(const char* layoutQualifier) {
154        fLayoutQualifier = layoutQualifier;
155    }
156
157    void addModifier(const char* modifier) {
158        if (modifier) {
159            fExtraModifiers.appendf("%s ", modifier);
160        }
161    }
162
163    /**
164     * Write a declaration of this variable to out.
165     */
166    void appendDecl(const GrGLSLCaps* glslCaps, SkString* out) const {
167        SkASSERT(kDefault_GrSLPrecision == fPrecision || GrSLTypeIsNumeric(fType));
168        if (!fLayoutQualifier.isEmpty()) {
169            out->appendf("layout(%s) ", fLayoutQualifier.c_str());
170        }
171        out->append(fExtraModifiers);
172        if (this->getTypeModifier() != kNone_TypeModifier) {
173            out->append(TypeModifierString(glslCaps, this->getTypeModifier()));
174            out->append(" ");
175        }
176        GrSLType effectiveType = this->getType();
177        if (effectiveType != kBool_GrSLType) {
178            out->append(PrecisionString(glslCaps, fPrecision));
179        }
180        if (this->isArray()) {
181            if (this->isUnsizedArray()) {
182                out->appendf("%s %s[]",
183                             GrGLSLTypeString(effectiveType),
184                             this->getName().c_str());
185            } else {
186                SkASSERT(this->getArrayCount() > 0);
187                out->appendf("%s %s[%d]",
188                             GrGLSLTypeString(effectiveType),
189                             this->getName().c_str(),
190                             this->getArrayCount());
191            }
192        } else {
193            out->appendf("%s %s",
194                         GrGLSLTypeString(effectiveType),
195                         this->getName().c_str());
196        }
197    }
198
199    void appendArrayAccess(int index, SkString* out) const {
200        out->appendf("%s[%d]%s",
201                     this->getName().c_str(),
202                     index,
203                     fUseUniformFloatArrays ? "" : ".x");
204    }
205
206    void appendArrayAccess(const char* indexName, SkString* out) const {
207        out->appendf("%s[%s]%s",
208                     this->getName().c_str(),
209                     indexName,
210                     fUseUniformFloatArrays ? "" : ".x");
211    }
212
213    static const char* PrecisionString(const GrGLSLCaps* glslCaps, GrSLPrecision p) {
214        // Desktop GLSL has added precision qualifiers but they don't do anything.
215        if (glslCaps->usesPrecisionModifiers()) {
216            switch (p) {
217                case kLow_GrSLPrecision:
218                    return "lowp ";
219                case kMedium_GrSLPrecision:
220                    return "mediump ";
221                case kHigh_GrSLPrecision:
222                    return "highp ";
223                default:
224                    SkFAIL("Unexpected precision type.");
225            }
226        }
227        return "";
228    }
229
230private:
231    static const char* TypeModifierString(const GrGLSLCaps* glslCaps, TypeModifier t) {
232        GrGLSLGeneration gen = glslCaps->generation();
233        switch (t) {
234            case kNone_TypeModifier:
235                return "";
236            case kIn_TypeModifier:
237                return "in";
238            case kInOut_TypeModifier:
239                return "inout";
240            case kOut_TypeModifier:
241                return "out";
242            case kUniform_TypeModifier:
243                return "uniform";
244            case kAttribute_TypeModifier:
245                return k110_GrGLSLGeneration == gen ? "attribute" : "in";
246            case kVaryingIn_TypeModifier:
247                return k110_GrGLSLGeneration == gen ? "varying" : "in";
248            case kVaryingOut_TypeModifier:
249                return k110_GrGLSLGeneration == gen ? "varying" : "out";
250            default:
251                SkFAIL("Unknown shader variable type modifier.");
252                return ""; // suppress warning
253        }
254    }
255
256    /// Work around driver bugs on some hardware that don't correctly
257    /// support uniform float []
258    bool        fUseUniformFloatArrays;
259
260    SkString    fLayoutQualifier;
261    SkString    fExtraModifiers;
262
263    typedef GrShaderVar INHERITED;
264};
265
266#endif
267