GrGLShaderBuilder.cpp revision 777c3aab0a902b0917871080d99b0a249ec06298
1/*
2 * Copyright 2012 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#include "gl/GrGLShaderBuilder.h"
9#include "gl/GrGLProgram.h"
10#include "gl/GrGLUniformHandle.h"
11
12// number of each input/output type in a single allocation block
13static const int kVarsPerBlock = 8;
14
15// except FS outputs where we expect 2 at most.
16static const int kMaxFSOutputs = 2;
17
18// ES2 FS only guarantees mediump and lowp support
19static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
20
21typedef GrGLUniformManager::UniformHandle UniformHandle;
22///////////////////////////////////////////////////////////////////////////////
23
24// Architectural assumption: always 2-d input coords.
25// Likely to become non-constant and non-static, perhaps even
26// varying by stage, if we use 1D textures for gradients!
27//const int GrGLShaderBuilder::fCoordDims = 2;
28
29GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctx, GrGLUniformManager& uniformManager)
30    : fUniforms(kVarsPerBlock)
31    , fVSAttrs(kVarsPerBlock)
32    , fVSOutputs(kVarsPerBlock)
33    , fGSInputs(kVarsPerBlock)
34    , fGSOutputs(kVarsPerBlock)
35    , fFSInputs(kVarsPerBlock)
36    , fFSOutputs(kMaxFSOutputs)
37    , fUsesGS(false)
38    , fVaryingDims(0)
39    , fComplexCoord(false)
40    , fContext(ctx)
41    , fUniformManager(uniformManager)
42    , fCurrentStage(kNonStageIdx) {
43}
44
45void GrGLShaderBuilder::computeSwizzle(uint32_t configFlags) {
46   static const uint32_t kMulByAlphaMask =
47        (GrGLProgram::StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
48         GrGLProgram::StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag);
49
50    fSwizzle = "";
51    if (configFlags & GrGLProgram::StageDesc::kSwapRAndB_InConfigFlag) {
52        GrAssert(!(configFlags &
53                   GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
54        GrAssert(!(configFlags &
55                   GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
56        fSwizzle = ".bgra";
57    } else if (configFlags & GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag) {
58        GrAssert(!(configFlags & kMulByAlphaMask));
59        GrAssert(!(configFlags &
60                   GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
61        fSwizzle = ".aaaa";
62    } else if (configFlags & GrGLProgram::StageDesc::kSmearRed_InConfigFlag) {
63        GrAssert(!(configFlags & kMulByAlphaMask));
64        GrAssert(!(configFlags &
65                   GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
66        fSwizzle = ".rrrr";
67    }
68}
69
70void GrGLShaderBuilder::computeModulate(const char* fsInColor) {
71    if (NULL != fsInColor) {
72        fModulate.printf(" * %s", fsInColor);
73    } else {
74        fModulate.reset();
75    }
76}
77
78void GrGLShaderBuilder::setupTextureAccess(SamplerMode samplerMode,
79                                           int stageNum) {
80    SkString retval;
81
82    fTexFunc = "texture2D";
83    switch (samplerMode) {
84        case kDefault_SamplerMode:
85            GrAssert(fVaryingDims == fCoordDims);
86            // Do nothing
87            break;
88        case kProj_SamplerMode:
89            fTexFunc.append("Proj");
90            break;
91        case kExplicitDivide_SamplerMode:
92            retval = "inCoord";
93            retval.appendS32(stageNum);
94            fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
95                GrGLShaderVar::TypeString
96                    (GrSLFloatVectorType(fCoordDims)),
97                retval.c_str(),
98                fSampleCoords.c_str(),
99                GrGLSLVectorNonhomogCoords(fVaryingDims),
100                fSampleCoords.c_str(),
101                GrGLSLVectorHomogCoord(fVaryingDims));
102            fSampleCoords = retval;
103            break;
104    }
105    fComplexCoord = false;
106}
107
108void GrGLShaderBuilder::emitTextureLookup(const char* samplerName,
109                                          const char* coordName) {
110    if (NULL == coordName) {
111        coordName = fSampleCoords.c_str();
112    }
113    fFSCode.appendf("%s(%s, %s)", fTexFunc.c_str(), samplerName, coordName);
114}
115
116void GrGLShaderBuilder::emitDefaultFetch(const char* outColor,
117                                         const char* samplerName) {
118    fFSCode.appendf("\t%s = ", outColor);
119    this->emitTextureLookup(samplerName);
120    fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str());
121}
122
123GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_t visibility,
124                                                                     GrSLType type,
125                                                                     const char* name,
126                                                                     int count,
127                                                                     const char** outName) {
128    GrAssert(name && strlen(name));
129    static const uint32_t kVisibilityMask = kVertex_ShaderType | kFragment_ShaderType;
130    GrAssert(0 == (~kVisibilityMask & visibility));
131    GrAssert(0 != visibility);
132
133    BuilderUniform& uni = fUniforms.push_back();
134    UniformHandle h = index_to_handle(fUniforms.count() - 1);
135    GR_DEBUGCODE(UniformHandle h2 =)
136    fUniformManager.appendUniform(type, count);
137    // We expect the uniform manager to initially have no uniforms and that all uniforms are added
138    // by this function. Therefore, the handles should match.
139    GrAssert(h2 == h);
140    uni.fVariable.setType(type);
141    uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
142    SkString* uniName = uni.fVariable.accessName();
143    if (kNonStageIdx == fCurrentStage) {
144        uniName->printf("u%s", name);
145    } else {
146        uniName->printf("u%s%d", name, fCurrentStage);
147    }
148    uni.fVariable.setArrayCount(count);
149    uni.fVisibility = visibility;
150
151    // If it is visible in both the VS and FS, the precision must match.
152    // We declare a default FS precision, but not a default VS. So set the var
153    // to use the default FS precision.
154    if ((kVertex_ShaderType | kFragment_ShaderType) == visibility) {
155        // the fragment and vertex precisions must match
156        uni.fVariable.setPrecision(kDefaultFragmentPrecision);
157    }
158
159    if (NULL != outName) {
160        *outName = uni.fVariable.c_str();
161    }
162
163    return h;
164}
165
166const GrGLShaderVar& GrGLShaderBuilder::getUniformVariable(UniformHandle u) const {
167    return fUniforms[handle_to_index(u)].fVariable;
168}
169
170void GrGLShaderBuilder::addVarying(GrSLType type,
171                                   const char* name,
172                                   const char** vsOutName,
173                                   const char** fsInName) {
174    fVSOutputs.push_back();
175    fVSOutputs.back().setType(type);
176    fVSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
177    if (kNonStageIdx == fCurrentStage) {
178        fVSOutputs.back().accessName()->printf("v%s", name);
179    } else {
180        fVSOutputs.back().accessName()->printf("v%s%d", name, fCurrentStage);
181    }
182    if (vsOutName) {
183        *vsOutName = fVSOutputs.back().getName().c_str();
184    }
185    // input to FS comes either from VS or GS
186    const SkString* fsName;
187    if (fUsesGS) {
188        // if we have a GS take each varying in as an array
189        // and output as non-array.
190        fGSInputs.push_back();
191        fGSInputs.back().setType(type);
192        fGSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
193        fGSInputs.back().setUnsizedArray();
194        *fGSInputs.back().accessName() = fVSOutputs.back().getName();
195        fGSOutputs.push_back();
196        fGSOutputs.back().setType(type);
197        fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
198        fGSOutputs.back().accessName()->printf("g%s", name);
199        fsName = fGSOutputs.back().accessName();
200    } else {
201        fsName = fVSOutputs.back().accessName();
202    }
203    fFSInputs.push_back();
204    fFSInputs.back().setType(type);
205    fFSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
206    fFSInputs.back().setName(*fsName);
207    if (fsInName) {
208        *fsInName = fsName->c_str();
209    }
210}
211
212
213namespace {
214
215inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
216                                               GrGLBinding binding,
217                                               SkString* str) {
218    // Desktop GLSL has added precision qualifiers but they don't do anything.
219    if (kES2_GrGLBinding == binding) {
220        switch (p) {
221            case GrGLShaderVar::kHigh_Precision:
222                str->append("precision highp float;\n");
223                break;
224            case GrGLShaderVar::kMedium_Precision:
225                str->append("precision mediump float;\n");
226                break;
227            case GrGLShaderVar::kLow_Precision:
228                str->append("precision lowp float;\n");
229                break;
230            case GrGLShaderVar::kDefault_Precision:
231                GrCrash("Default precision now allowed.");
232            default:
233                GrCrash("Unknown precision value.");
234        }
235    }
236}
237}
238
239void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
240    for (int i = 0; i < vars.count(); ++i) {
241        vars[i].appendDecl(fContext, out);
242    }
243}
244
245void GrGLShaderBuilder::appendUniformDecls(ShaderType stype, SkString* out) const {
246    for (int i = 0; i < fUniforms.count(); ++i) {
247        if (fUniforms[i].fVisibility & stype) {
248            fUniforms[i].fVariable.appendDecl(fContext, out);
249        }
250    }
251}
252
253void GrGLShaderBuilder::getShader(ShaderType type, SkString* shaderStr) const {
254    switch (type) {
255        case kVertex_ShaderType:
256            *shaderStr = fHeader;
257            this->appendUniformDecls(kVertex_ShaderType, shaderStr);
258            this->appendDecls(fVSAttrs, shaderStr);
259            this->appendDecls(fVSOutputs, shaderStr);
260            shaderStr->append(fVSCode);
261            break;
262        case kGeometry_ShaderType:
263            if (fUsesGS) {
264                *shaderStr = fHeader;
265                shaderStr->append(fGSHeader);
266                this->appendDecls(fGSInputs, shaderStr);
267                this->appendDecls(fGSOutputs, shaderStr);
268                shaderStr->append(fGSCode);
269            } else {
270                shaderStr->reset();
271            }
272            break;
273        case kFragment_ShaderType:
274            *shaderStr = fHeader;
275            append_default_precision_qualifier(kDefaultFragmentPrecision,
276                                               fContext.binding(),
277                                               shaderStr);
278            this->appendUniformDecls(kFragment_ShaderType, shaderStr);
279            this->appendDecls(fFSInputs, shaderStr);
280            // We shouldn't have declared outputs on 1.10
281            GrAssert(k110_GrGLSLGeneration != fContext.glslGeneration() || fFSOutputs.empty());
282            this->appendDecls(fFSOutputs, shaderStr);
283            shaderStr->append(fFSFunctions);
284            shaderStr->append(fFSCode);
285            break;
286    }
287 }
288
289void GrGLShaderBuilder::finished(GrGLuint programID) {
290    fUniformManager.getUniformLocations(programID, fUniforms);
291}
292