GrGLProgram.cpp revision 5259814305e3290dea3b197301f7824a14c5fa6f
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#include "GrGLProgram.h"
9
10#include "GrAllocator.h"
11#include "GrCustomStage.h"
12#include "GrGLProgramStage.h"
13#include "gl/GrGLShaderBuilder.h"
14#include "GrGLShaderVar.h"
15#include "GrProgramStageFactory.h"
16#include "SkTrace.h"
17#include "SkXfermode.h"
18
19namespace {
20
21enum {
22    /// Used to mark a StageUniLocation field that should be bound
23    /// to a uniform during getUniformLocationsAndInitCache().
24    kUseUniform = 2000
25};
26
27}  // namespace
28
29#define PRINT_SHADERS 0
30
31typedef GrGLProgram::ProgramDesc::StageDesc StageDesc;
32
33#define VIEW_MATRIX_NAME "uViewM"
34
35#define POS_ATTR_NAME "aPosition"
36#define COL_ATTR_NAME "aColor"
37#define COV_ATTR_NAME "aCoverage"
38#define EDGE_ATTR_NAME "aEdge"
39#define COL_UNI_NAME "uColor"
40#define COV_UNI_NAME "uCoverage"
41#define EDGES_UNI_NAME "uEdges"
42#define COL_FILTER_UNI_NAME "uColorFilter"
43#define COL_MATRIX_UNI_NAME "uColorMatrix"
44#define COL_MATRIX_VEC_UNI_NAME "uColorMatrixVec"
45
46namespace {
47inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
48    *s = "aTexCoord";
49    s->appendS32(coordIdx);
50}
51
52inline const char* float_vector_type_str(int count) {
53    return GrGLShaderVar::TypeString(GrSLFloatVectorType(count));
54}
55
56inline const char* vector_all_coords(int count) {
57    static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
58    GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
59    return ALL[count];
60}
61
62inline const char* all_ones_vec(int count) {
63    static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)",
64                                    "vec3(1,1,1)", "vec4(1,1,1,1)"};
65    GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ONESVEC));
66    return ONESVEC[count];
67}
68
69inline const char* all_zeros_vec(int count) {
70    static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)",
71                                    "vec3(0,0,0)", "vec4(0,0,0,0)"};
72    GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ZEROSVEC));
73    return ZEROSVEC[count];
74}
75
76inline const char* declared_color_output_name() { return "fsColorOut"; }
77inline const char* dual_source_output_name() { return "dualSourceOut"; }
78
79inline void tex_matrix_name(int stage, GrStringBuilder* s) {
80    *s = "uTexM";
81    s->appendS32(stage);
82}
83
84inline void normalized_texel_size_name(int stage, GrStringBuilder* s) {
85    *s = "uTexelSize";
86    s->appendS32(stage);
87}
88
89inline void sampler_name(int stage, GrStringBuilder* s) {
90    *s = "uSampler";
91    s->appendS32(stage);
92}
93
94inline void radial2_param_name(int stage, GrStringBuilder* s) {
95    *s = "uRadial2Params";
96    s->appendS32(stage);
97}
98
99inline void convolve_param_names(int stage, GrStringBuilder* k, GrStringBuilder* i) {
100    *k = "uKernel";
101    k->appendS32(stage);
102    *i = "uImageIncrement";
103    i->appendS32(stage);
104}
105
106inline void image_increment_param_name(int stage, GrStringBuilder* i) {
107    *i = "uImageIncrement";
108    i->appendS32(stage);
109}
110
111inline void tex_domain_name(int stage, GrStringBuilder* s) {
112    *s = "uTexDom";
113    s->appendS32(stage);
114}
115}
116
117GrGLProgram::GrGLProgram() {
118}
119
120GrGLProgram::~GrGLProgram() {
121}
122
123void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
124                                GrBlendCoeff* dstCoeff) const {
125    switch (fProgramDesc.fDualSrcOutput) {
126        case ProgramDesc::kNone_DualSrcOutput:
127            break;
128        // the prog will write a coverage value to the secondary
129        // output and the dst is blended by one minus that value.
130        case ProgramDesc::kCoverage_DualSrcOutput:
131        case ProgramDesc::kCoverageISA_DualSrcOutput:
132        case ProgramDesc::kCoverageISC_DualSrcOutput:
133        *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_BlendCoeff;
134        break;
135        default:
136            GrCrash("Unexpected dual source blend output");
137            break;
138    }
139}
140
141// assigns modulation of two vars to an output var
142// vars can be vec4s or floats (or one of each)
143// result is always vec4
144// if either var is "" then assign to the other var
145// if both are "" then assign all ones
146static inline void modulate_helper(const char* outputVar,
147                                   const char* var0,
148                                   const char* var1,
149                                   GrStringBuilder* code) {
150    GrAssert(NULL != outputVar);
151    GrAssert(NULL != var0);
152    GrAssert(NULL != var1);
153    GrAssert(NULL != code);
154
155    bool has0 = '\0' != *var0;
156    bool has1 = '\0' != *var1;
157
158    if (!has0 && !has1) {
159        code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4));
160    } else if (!has0) {
161        code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
162    } else if (!has1) {
163        code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
164    } else {
165        code->appendf("\t%s = vec4(%s * %s);\n", outputVar, var0, var1);
166    }
167}
168
169// assigns addition of two vars to an output var
170// vars can be vec4s or floats (or one of each)
171// result is always vec4
172// if either var is "" then assign to the other var
173// if both are "" then assign all zeros
174static inline void add_helper(const char* outputVar,
175                              const char* var0,
176                              const char* var1,
177                              GrStringBuilder* code) {
178    GrAssert(NULL != outputVar);
179    GrAssert(NULL != var0);
180    GrAssert(NULL != var1);
181    GrAssert(NULL != code);
182
183    bool has0 = '\0' != *var0;
184    bool has1 = '\0' != *var1;
185
186    if (!has0 && !has1) {
187        code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4));
188    } else if (!has0) {
189        code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
190    } else if (!has1) {
191        code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
192    } else {
193        code->appendf("\t%s = vec4(%s + %s);\n", outputVar, var0, var1);
194    }
195}
196
197// given two blend coeffecients determine whether the src
198// and/or dst computation can be omitted.
199static inline void needBlendInputs(SkXfermode::Coeff srcCoeff,
200                                   SkXfermode::Coeff dstCoeff,
201                                   bool* needSrcValue,
202                                   bool* needDstValue) {
203    if (SkXfermode::kZero_Coeff == srcCoeff) {
204        switch (dstCoeff) {
205            // these all read the src
206            case SkXfermode::kSC_Coeff:
207            case SkXfermode::kISC_Coeff:
208            case SkXfermode::kSA_Coeff:
209            case SkXfermode::kISA_Coeff:
210                *needSrcValue = true;
211                break;
212            default:
213                *needSrcValue = false;
214                break;
215        }
216    } else {
217        *needSrcValue = true;
218    }
219    if (SkXfermode::kZero_Coeff == dstCoeff) {
220        switch (srcCoeff) {
221            // these all read the dst
222            case SkXfermode::kDC_Coeff:
223            case SkXfermode::kIDC_Coeff:
224            case SkXfermode::kDA_Coeff:
225            case SkXfermode::kIDA_Coeff:
226                *needDstValue = true;
227                break;
228            default:
229                *needDstValue = false;
230                break;
231        }
232    } else {
233        *needDstValue = true;
234    }
235}
236
237/**
238 * Create a blend_coeff * value string to be used in shader code. Sets empty
239 * string if result is trivially zero.
240 */
241static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff,
242                             const char* src, const char* dst,
243                             const char* value) {
244    switch (coeff) {
245    case SkXfermode::kZero_Coeff:    /** 0 */
246        *str = "";
247        break;
248    case SkXfermode::kOne_Coeff:     /** 1 */
249        *str = value;
250        break;
251    case SkXfermode::kSC_Coeff:
252        str->printf("(%s * %s)", src, value);
253        break;
254    case SkXfermode::kISC_Coeff:
255        str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value);
256        break;
257    case SkXfermode::kDC_Coeff:
258        str->printf("(%s * %s)", dst, value);
259        break;
260    case SkXfermode::kIDC_Coeff:
261        str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value);
262        break;
263    case SkXfermode::kSA_Coeff:      /** src alpha */
264        str->printf("(%s.a * %s)", src, value);
265        break;
266    case SkXfermode::kISA_Coeff:     /** inverse src alpha (i.e. 1 - sa) */
267        str->printf("((1.0 - %s.a) * %s)", src, value);
268        break;
269    case SkXfermode::kDA_Coeff:      /** dst alpha */
270        str->printf("(%s.a * %s)", dst, value);
271        break;
272    case SkXfermode::kIDA_Coeff:     /** inverse dst alpha (i.e. 1 - da) */
273        str->printf("((1.0 - %s.a) * %s)", dst, value);
274        break;
275    default:
276        GrCrash("Unexpected xfer coeff.");
277        break;
278    }
279}
280/**
281 * Adds a line to the fragment shader code which modifies the color by
282 * the specified color filter.
283 */
284static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar,
285                           SkXfermode::Coeff uniformCoeff,
286                           SkXfermode::Coeff colorCoeff,
287                           const char* inColor) {
288    GrStringBuilder colorStr, constStr;
289    blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME,
290                    inColor, inColor);
291    blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME,
292                    inColor, COL_FILTER_UNI_NAME);
293
294    add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
295}
296/**
297 * Adds code to the fragment shader code which modifies the color by
298 * the specified color matrix.
299 */
300static void addColorMatrix(GrStringBuilder* fsCode, const char * outputVar,
301                           const char* inColor) {
302    fsCode->appendf("\t%s = %s * vec4(%s.rgb / %s.a, %s.a) + %s;\n", outputVar, COL_MATRIX_UNI_NAME, inColor, inColor, inColor, COL_MATRIX_VEC_UNI_NAME);
303    fsCode->appendf("\t%s.rgb *= %s.a;\n", outputVar, outputVar);
304}
305
306void GrGLProgram::genEdgeCoverage(const GrGLContextInfo& gl,
307                                  GrVertexLayout layout,
308                                  CachedData* programData,
309                                  GrStringBuilder* coverageVar,
310                                  GrGLShaderBuilder* segments) const {
311    if (layout & GrDrawTarget::kEdge_VertexLayoutBit) {
312        const char *vsName, *fsName;
313        segments->appendVarying(kVec4f_GrSLType, "Edge", &vsName, &fsName);
314        segments->fVSAttrs.push_back().set(kVec4f_GrSLType,
315            GrGLShaderVar::kAttribute_TypeModifier, EDGE_ATTR_NAME);
316        segments->fVSCode.appendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
317        switch (fProgramDesc.fVertexEdgeType) {
318        case GrDrawState::kHairLine_EdgeType:
319            segments->fFSCode.appendf("\tfloat edgeAlpha = abs(dot(vec3(gl_FragCoord.xy,1), %s.xyz));\n", fsName);
320            segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
321            break;
322        case GrDrawState::kQuad_EdgeType:
323            segments->fFSCode.append("\tfloat edgeAlpha;\n");
324            // keep the derivative instructions outside the conditional
325            segments->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
326            segments->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
327            segments->fFSCode.appendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
328            // today we know z and w are in device space. We could use derivatives
329            segments->fFSCode.appendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName);
330            segments->fFSCode.append ("\t} else {\n");
331            segments->fFSCode.appendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
332                                      "\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
333                                      fsName, fsName);
334            segments->fFSCode.appendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
335            segments->fFSCode.append("\t\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n"
336                                      "\t}\n");
337            if (kES2_GrGLBinding == gl.binding()) {
338                segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
339            }
340            break;
341        case GrDrawState::kHairQuad_EdgeType:
342            segments->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
343            segments->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
344            segments->fFSCode.appendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
345                                      "\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
346                                      fsName, fsName);
347            segments->fFSCode.appendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
348            segments->fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
349            segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
350            if (kES2_GrGLBinding == gl.binding()) {
351                segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
352            }
353            break;
354        case GrDrawState::kCircle_EdgeType:
355            segments->fFSCode.append("\tfloat edgeAlpha;\n");
356            segments->fFSCode.appendf("\tfloat d = distance(gl_FragCoord.xy, %s.xy);\n", fsName);
357            segments->fFSCode.appendf("\tfloat outerAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
358            segments->fFSCode.appendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName);
359            segments->fFSCode.append("\tedgeAlpha = outerAlpha * innerAlpha;\n");
360            break;
361        default:
362            GrCrash("Unknown Edge Type!");
363            break;
364        }
365        *coverageVar = "edgeAlpha";
366    } else {
367        coverageVar->reset();
368    }
369}
370
371namespace {
372
373void genInputColor(GrGLProgram::ProgramDesc::ColorInput colorInput,
374                   GrGLProgram::CachedData* programData,
375                   GrGLShaderBuilder* segments,
376                   GrStringBuilder* inColor) {
377    switch (colorInput) {
378        case GrGLProgram::ProgramDesc::kAttribute_ColorInput: {
379            segments->fVSAttrs.push_back().set(kVec4f_GrSLType,
380                GrGLShaderVar::kAttribute_TypeModifier,
381                COL_ATTR_NAME);
382            const char *vsName, *fsName;
383            segments->appendVarying(kVec4f_GrSLType, "Color", &vsName, &fsName);
384            segments->fVSCode.appendf("\t%s = " COL_ATTR_NAME ";\n", vsName);
385            *inColor = fsName;
386            } break;
387        case GrGLProgram::ProgramDesc::kUniform_ColorInput:
388            segments->fFSUnis.push_back().set(kVec4f_GrSLType,
389                GrGLShaderVar::kUniform_TypeModifier,
390                COL_UNI_NAME);
391            programData->fUniLocations.fColorUni = kUseUniform;
392            *inColor = COL_UNI_NAME;
393            break;
394        case GrGLProgram::ProgramDesc::kTransBlack_ColorInput:
395            GrAssert(!"needComputedColor should be false.");
396            break;
397        case GrGLProgram::ProgramDesc::kSolidWhite_ColorInput:
398            break;
399        default:
400            GrCrash("Unknown color type.");
401            break;
402    }
403}
404
405void genAttributeCoverage(GrGLShaderBuilder* segments,
406                          GrStringBuilder* inOutCoverage) {
407    segments->fVSAttrs.push_back().set(kVec4f_GrSLType,
408                                       GrGLShaderVar::kAttribute_TypeModifier,
409                                       COV_ATTR_NAME);
410    const char *vsName, *fsName;
411    segments->appendVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
412    segments->fVSCode.appendf("\t%s = " COV_ATTR_NAME ";\n", vsName);
413    if (inOutCoverage->size()) {
414        segments->fFSCode.appendf("\tvec4 attrCoverage = %s * %s;\n",
415                                  fsName, inOutCoverage->c_str());
416        *inOutCoverage = "attrCoverage";
417    } else {
418        *inOutCoverage = fsName;
419    }
420}
421
422void genUniformCoverage(GrGLShaderBuilder* segments,
423                        GrGLProgram::CachedData* programData,
424                        GrStringBuilder* inOutCoverage) {
425    segments->fFSUnis.push_back().set(kVec4f_GrSLType,
426                                      GrGLShaderVar::kUniform_TypeModifier,
427                                      COV_UNI_NAME);
428    programData->fUniLocations.fCoverageUni = kUseUniform;
429    if (inOutCoverage->size()) {
430        segments->fFSCode.appendf("\tvec4 uniCoverage = %s * %s;\n",
431                                  COV_UNI_NAME, inOutCoverage->c_str());
432        *inOutCoverage = "uniCoverage";
433    } else {
434        *inOutCoverage = COV_UNI_NAME;
435    }
436}
437
438}
439
440void GrGLProgram::genGeometryShader(const GrGLContextInfo& gl,
441                                    GrGLShaderBuilder* segments) const {
442#if GR_GL_EXPERIMENTAL_GS
443    if (fProgramDesc.fExperimentalGS) {
444        GrAssert(gl.glslGeneration() >= k150_GrGLSLGeneration);
445        segments->fGSHeader.append("layout(triangles) in;\n"
446                                   "layout(triangle_strip, max_vertices = 6) out;\n");
447        segments->fGSCode.append("void main() {\n"
448                                 "\tfor (int i = 0; i < 3; ++i) {\n"
449                                  "\t\tgl_Position = gl_in[i].gl_Position;\n");
450        if (this->fProgramDesc.fEmitsPointSize) {
451            segments->fGSCode.append("\t\tgl_PointSize = 1.0;\n");
452        }
453        GrAssert(segments->fGSInputs.count() == segments->fGSOutputs.count());
454        int count = segments->fGSInputs.count();
455        for (int i = 0; i < count; ++i) {
456            segments->fGSCode.appendf("\t\t%s = %s[i];\n",
457                                      segments->fGSOutputs[i].getName().c_str(),
458                                      segments->fGSInputs[i].getName().c_str());
459        }
460        segments->fGSCode.append("\t\tEmitVertex();\n"
461                                 "\t}\n"
462                                 "\tEndPrimitive();\n"
463                                 "}\n");
464    }
465#endif
466}
467
468const char* GrGLProgram::adjustInColor(const GrStringBuilder& inColor) const {
469    if (inColor.size()) {
470          return inColor.c_str();
471    } else {
472        if (ProgramDesc::kSolidWhite_ColorInput == fProgramDesc.fColorInput) {
473            return all_ones_vec(4);
474        } else {
475            return all_zeros_vec(4);
476        }
477    }
478}
479
480// If this destructor is in the header file, we must include GrGLProgramStage
481// instead of just forward-declaring it.
482GrGLProgram::CachedData::~CachedData() {
483    for (int i = 0; i < GrDrawState::kNumStages; ++i) {
484        delete fCustomStage[i];
485    }
486}
487
488
489bool GrGLProgram::genProgram(const GrGLContextInfo& gl,
490                             GrCustomStage** customStages,
491                             GrGLProgram::CachedData* programData) const {
492    GrGLShaderBuilder segments;
493    const uint32_t& layout = fProgramDesc.fVertexLayout;
494
495    programData->fUniLocations.reset();
496
497#if GR_GL_EXPERIMENTAL_GS
498    segments.fUsesGS = fProgramDesc.fExperimentalGS;
499#endif
500
501    SkXfermode::Coeff colorCoeff, uniformCoeff;
502    bool applyColorMatrix = SkToBool(fProgramDesc.fColorMatrixEnabled);
503    // The rest of transfer mode color filters have not been implemented
504    if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
505        GR_DEBUGCODE(bool success =)
506            SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode>
507                                    (fProgramDesc.fColorFilterXfermode),
508                                    &uniformCoeff, &colorCoeff);
509        GR_DEBUGASSERT(success);
510    } else {
511        colorCoeff = SkXfermode::kOne_Coeff;
512        uniformCoeff = SkXfermode::kZero_Coeff;
513    }
514
515    // no need to do the color filter / matrix at all if coverage is 0. The
516    // output color is scaled by the coverage. All the dual source outputs are
517    // scaled by the coverage as well.
518    if (ProgramDesc::kTransBlack_ColorInput == fProgramDesc.fCoverageInput) {
519        colorCoeff = SkXfermode::kZero_Coeff;
520        uniformCoeff = SkXfermode::kZero_Coeff;
521        applyColorMatrix = false;
522    }
523
524    // If we know the final color is going to be all zeros then we can
525    // simplify the color filter coeffecients. needComputedColor will then
526    // come out false below.
527    if (ProgramDesc::kTransBlack_ColorInput == fProgramDesc.fColorInput) {
528        colorCoeff = SkXfermode::kZero_Coeff;
529        if (SkXfermode::kDC_Coeff == uniformCoeff ||
530            SkXfermode::kDA_Coeff == uniformCoeff) {
531            uniformCoeff = SkXfermode::kZero_Coeff;
532        } else if (SkXfermode::kIDC_Coeff == uniformCoeff ||
533                   SkXfermode::kIDA_Coeff == uniformCoeff) {
534            uniformCoeff = SkXfermode::kOne_Coeff;
535        }
536    }
537
538    bool needColorFilterUniform;
539    bool needComputedColor;
540    needBlendInputs(uniformCoeff, colorCoeff,
541                    &needColorFilterUniform, &needComputedColor);
542
543    // the dual source output has no canonical var name, have to
544    // declare an output, which is incompatible with gl_FragColor/gl_FragData.
545    bool dualSourceOutputWritten = false;
546    segments.fHeader.printf(GrGetGLSLVersionDecl(gl.binding(),
547                                                 gl.glslGeneration()));
548
549    GrGLShaderVar colorOutput;
550    bool isColorDeclared = GrGLSLSetupFSColorOuput(gl.glslGeneration(),
551                                                   declared_color_output_name(),
552                                                   &colorOutput);
553    if (isColorDeclared) {
554        segments.fFSOutputs.push_back(colorOutput);
555    }
556
557    segments.fVSUnis.push_back().set(kMat33f_GrSLType,
558        GrGLShaderVar::kUniform_TypeModifier, VIEW_MATRIX_NAME);
559    programData->fUniLocations.fViewMatrixUni = kUseUniform;
560
561    segments.fVSAttrs.push_back().set(kVec2f_GrSLType,
562        GrGLShaderVar::kAttribute_TypeModifier, POS_ATTR_NAME);
563
564    segments.fVSCode.append(
565        "void main() {\n"
566            "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
567            "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
568
569    // incoming color to current stage being processed.
570    GrStringBuilder inColor;
571
572    if (needComputedColor) {
573        genInputColor((ProgramDesc::ColorInput) fProgramDesc.fColorInput,
574                      programData, &segments, &inColor);
575    }
576
577    // we output point size in the GS if present
578    if (fProgramDesc.fEmitsPointSize && !segments.fUsesGS){
579        segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
580    }
581
582    segments.fFSCode.append("void main() {\n");
583
584    // add texture coordinates that are used to the list of vertex attr decls
585    GrStringBuilder texCoordAttrs[GrDrawState::kMaxTexCoords];
586    for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
587        if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
588            tex_attr_name(t, texCoordAttrs + t);
589            segments.fVSAttrs.push_back().set(kVec2f_GrSLType,
590                GrGLShaderVar::kAttribute_TypeModifier,
591                texCoordAttrs[t].c_str());
592        }
593    }
594
595    ///////////////////////////////////////////////////////////////////////////
596    // We need to convert generic effect representations to GL-specific
597    // backends so they can be accesseed in genStageCode() and in subsequent,
598    // uses of programData, but it's safest to do so below when we're *sure*
599    // we need them.
600    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
601        programData->fCustomStage[s] = NULL;
602    }
603
604    ///////////////////////////////////////////////////////////////////////////
605    // compute the final color
606
607    // if we have color stages string them together, feeding the output color
608    // of each to the next and generating code for each stage.
609    if (needComputedColor) {
610        GrStringBuilder outColor;
611        for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
612            if (fProgramDesc.fStages[s].isEnabled()) {
613                // create var to hold stage result
614                outColor = "color";
615                outColor.appendS32(s);
616                segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
617
618                const char* inCoords;
619                // figure out what our input coords are
620                if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
621                    layout) {
622                    inCoords = POS_ATTR_NAME;
623                } else {
624                    int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
625                     // we better have input tex coordinates if stage is enabled.
626                    GrAssert(tcIdx >= 0);
627                    GrAssert(texCoordAttrs[tcIdx].size());
628                    inCoords = texCoordAttrs[tcIdx].c_str();
629                }
630
631                if (NULL != customStages[s]) {
632                    const GrProgramStageFactory& factory =
633                        customStages[s]->getFactory();
634                    programData->fCustomStage[s] =
635                        factory.createGLInstance(customStages[s]);
636                }
637                this->genStageCode(gl,
638                                   s,
639                                   fProgramDesc.fStages[s],
640                                   inColor.size() ? inColor.c_str() : NULL,
641                                   outColor.c_str(),
642                                   inCoords,
643                                   &segments,
644                                   &programData->fUniLocations.fStages[s],
645                                   programData->fCustomStage[s]);
646                inColor = outColor;
647            }
648        }
649    }
650
651    // if have all ones or zeros for the "dst" input to the color filter then we
652    // may be able to make additional optimizations.
653    if (needColorFilterUniform && needComputedColor && !inColor.size()) {
654        GrAssert(ProgramDesc::kSolidWhite_ColorInput == fProgramDesc.fColorInput);
655        bool uniformCoeffIsZero = SkXfermode::kIDC_Coeff == uniformCoeff ||
656                                  SkXfermode::kIDA_Coeff == uniformCoeff;
657        if (uniformCoeffIsZero) {
658            uniformCoeff = SkXfermode::kZero_Coeff;
659            bool bogus;
660            needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
661                            &needColorFilterUniform, &bogus);
662        }
663    }
664    if (needColorFilterUniform) {
665        segments.fFSUnis.push_back().set(kVec4f_GrSLType,
666                                         GrGLShaderVar::kUniform_TypeModifier,
667                                         COL_FILTER_UNI_NAME);
668        programData->fUniLocations.fColorFilterUni = kUseUniform;
669    }
670    bool wroteFragColorZero = false;
671    if (SkXfermode::kZero_Coeff == uniformCoeff &&
672        SkXfermode::kZero_Coeff == colorCoeff &&
673        !applyColorMatrix) {
674        segments.fFSCode.appendf("\t%s = %s;\n",
675                                 colorOutput.getName().c_str(),
676                                 all_zeros_vec(4));
677        wroteFragColorZero = true;
678    } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
679        segments.fFSCode.append("\tvec4 filteredColor;\n");
680        const char* color = adjustInColor(inColor);
681        addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
682                       colorCoeff, color);
683        inColor = "filteredColor";
684    }
685    if (applyColorMatrix) {
686        segments.fFSUnis.push_back().set(kMat44f_GrSLType,
687                                         GrGLShaderVar::kUniform_TypeModifier,
688                                         COL_MATRIX_UNI_NAME);
689        segments.fFSUnis.push_back().set(kVec4f_GrSLType,
690                                         GrGLShaderVar::kUniform_TypeModifier,
691                                         COL_MATRIX_VEC_UNI_NAME);
692        programData->fUniLocations.fColorMatrixUni = kUseUniform;
693        programData->fUniLocations.fColorMatrixVecUni = kUseUniform;
694        segments.fFSCode.append("\tvec4 matrixedColor;\n");
695        const char* color = adjustInColor(inColor);
696        addColorMatrix(&segments.fFSCode, "matrixedColor", color);
697        inColor = "matrixedColor";
698    }
699
700    ///////////////////////////////////////////////////////////////////////////
701    // compute the partial coverage (coverage stages and edge aa)
702
703    GrStringBuilder inCoverage;
704    bool coverageIsZero = ProgramDesc::kTransBlack_ColorInput ==
705                          fProgramDesc.fCoverageInput;
706    // we don't need to compute coverage at all if we know the final shader
707    // output will be zero and we don't have a dual src blend output.
708    if (!wroteFragColorZero ||
709        ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
710
711        if (!coverageIsZero) {
712            this->genEdgeCoverage(gl,
713                                  layout,
714                                  programData,
715                                  &inCoverage,
716                                  &segments);
717
718            switch (fProgramDesc.fCoverageInput) {
719                case ProgramDesc::kSolidWhite_ColorInput:
720                    // empty string implies solid white
721                    break;
722                case ProgramDesc::kAttribute_ColorInput:
723                    genAttributeCoverage(&segments, &inCoverage);
724                    break;
725                case ProgramDesc::kUniform_ColorInput:
726                    genUniformCoverage(&segments, programData, &inCoverage);
727                    break;
728                default:
729                    GrCrash("Unexpected input coverage.");
730            }
731
732            GrStringBuilder outCoverage;
733            const int& startStage = fProgramDesc.fFirstCoverageStage;
734            for (int s = startStage; s < GrDrawState::kNumStages; ++s) {
735                if (fProgramDesc.fStages[s].isEnabled()) {
736                    // create var to hold stage output
737                    outCoverage = "coverage";
738                    outCoverage.appendS32(s);
739                    segments.fFSCode.appendf("\tvec4 %s;\n",
740                                             outCoverage.c_str());
741
742                    const char* inCoords;
743                    // figure out what our input coords are
744                    if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
745                        layout) {
746                        inCoords = POS_ATTR_NAME;
747                    } else {
748                        int tcIdx =
749                            GrDrawTarget::VertexTexCoordsForStage(s, layout);
750                        // we better have input tex coordinates if stage is
751                        // enabled.
752                        GrAssert(tcIdx >= 0);
753                        GrAssert(texCoordAttrs[tcIdx].size());
754                        inCoords = texCoordAttrs[tcIdx].c_str();
755                    }
756
757                    if (NULL != customStages[s]) {
758                        const GrProgramStageFactory& factory =
759                            customStages[s]->getFactory();
760                        programData->fCustomStage[s] =
761                            factory.createGLInstance(customStages[s]);
762                    }
763                    this->genStageCode(gl, s,
764                        fProgramDesc.fStages[s],
765                        inCoverage.size() ? inCoverage.c_str() : NULL,
766                        outCoverage.c_str(),
767                        inCoords,
768                        &segments,
769                        &programData->fUniLocations.fStages[s],
770                        programData->fCustomStage[s]);
771                    inCoverage = outCoverage;
772                }
773            }
774        }
775        if (ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
776            segments.fFSOutputs.push_back().set(kVec4f_GrSLType,
777                GrGLShaderVar::kOut_TypeModifier,
778                dual_source_output_name());
779            bool outputIsZero = coverageIsZero;
780            GrStringBuilder coeff;
781            if (!outputIsZero &&
782                ProgramDesc::kCoverage_DualSrcOutput !=
783                fProgramDesc.fDualSrcOutput && !wroteFragColorZero) {
784                if (!inColor.size()) {
785                    outputIsZero = true;
786                } else {
787                    if (fProgramDesc.fDualSrcOutput ==
788                        ProgramDesc::kCoverageISA_DualSrcOutput) {
789                        coeff.printf("(1 - %s.a)", inColor.c_str());
790                    } else {
791                        coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str());
792                    }
793                }
794            }
795            if (outputIsZero) {
796                segments.fFSCode.appendf("\t%s = %s;\n",
797                                         dual_source_output_name(),
798                                         all_zeros_vec(4));
799            } else {
800                modulate_helper(dual_source_output_name(),
801                                coeff.c_str(),
802                                inCoverage.c_str(),
803                                &segments.fFSCode);
804            }
805            dualSourceOutputWritten = true;
806        }
807    }
808
809    ///////////////////////////////////////////////////////////////////////////
810    // combine color and coverage as frag color
811
812    if (!wroteFragColorZero) {
813        if (coverageIsZero) {
814            segments.fFSCode.appendf("\t%s = %s;\n",
815                                     colorOutput.getName().c_str(),
816                                     all_zeros_vec(4));
817        } else {
818            modulate_helper(colorOutput.getName().c_str(),
819                            inColor.c_str(),
820                            inCoverage.c_str(),
821                            &segments.fFSCode);
822        }
823        if (ProgramDesc::kUnpremultiplied_RoundDown_OutputConfig ==
824            fProgramDesc.fOutputConfig) {
825            segments.fFSCode.appendf("\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.rgb / %s.a * 255.0)/255.0, %s.a);\n",
826                                        colorOutput.getName().c_str(),
827                                        colorOutput.getName().c_str(),
828                                        colorOutput.getName().c_str(),
829                                        colorOutput.getName().c_str(),
830                                        colorOutput.getName().c_str());
831        } else if (ProgramDesc::kUnpremultiplied_RoundUp_OutputConfig ==
832                   fProgramDesc.fOutputConfig) {
833            segments.fFSCode.appendf("\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.rgb / %s.a * 255.0)/255.0, %s.a);\n",
834                                        colorOutput.getName().c_str(),
835                                        colorOutput.getName().c_str(),
836                                        colorOutput.getName().c_str(),
837                                        colorOutput.getName().c_str(),
838                                        colorOutput.getName().c_str());
839        }
840    }
841
842    segments.fVSCode.append("}\n");
843    segments.fFSCode.append("}\n");
844
845    ///////////////////////////////////////////////////////////////////////////
846    // insert GS
847#if GR_DEBUG
848    this->genGeometryShader(gl, &segments);
849#endif
850
851    ///////////////////////////////////////////////////////////////////////////
852    // compile and setup attribs and unis
853
854    if (!CompileShaders(gl, segments, programData)) {
855        return false;
856    }
857
858    if (!this->bindOutputsAttribsAndLinkProgram(gl, texCoordAttrs,
859                                                isColorDeclared,
860                                                dualSourceOutputWritten,
861                                                programData)) {
862        return false;
863    }
864
865    this->getUniformLocationsAndInitCache(gl, programData);
866
867    return true;
868}
869
870namespace {
871
872inline void expand_decls(const VarArray& vars,
873                         const GrGLContextInfo& gl,
874                         GrStringBuilder* string) {
875    const int count = vars.count();
876    for (int i = 0; i < count; ++i) {
877        vars[i].appendDecl(gl, string);
878    }
879}
880
881inline void print_shader(int stringCnt,
882                         const char** strings,
883                         int* stringLengths) {
884    for (int i = 0; i < stringCnt; ++i) {
885        if (NULL == stringLengths || stringLengths[i] < 0) {
886            GrPrintf(strings[i]);
887        } else {
888            GrPrintf("%.*s", stringLengths[i], strings[i]);
889        }
890    }
891}
892
893typedef SkTArray<const char*, true>         StrArray;
894#define PREALLOC_STR_ARRAY(N) SkSTArray<(N), const char*, true>
895
896typedef SkTArray<int, true>                 LengthArray;
897#define PREALLOC_LENGTH_ARRAY(N) SkSTArray<(N), int, true>
898
899// these shouldn't relocate
900typedef GrTAllocator<GrStringBuilder>       TempArray;
901#define PREALLOC_TEMP_ARRAY(N) GrSTAllocator<(N), GrStringBuilder>
902
903inline void append_string(const GrStringBuilder& str,
904                          StrArray* strings,
905                          LengthArray* lengths) {
906    int length = (int) str.size();
907    if (length) {
908        strings->push_back(str.c_str());
909        lengths->push_back(length);
910    }
911    GrAssert(strings->count() == lengths->count());
912}
913
914inline void append_decls(const VarArray& vars,
915                         const GrGLContextInfo& gl,
916                         StrArray* strings,
917                         LengthArray* lengths,
918                         TempArray* temp) {
919    expand_decls(vars, gl, &temp->push_back());
920    append_string(temp->back(), strings, lengths);
921}
922
923}
924
925bool GrGLProgram::CompileShaders(const GrGLContextInfo& gl,
926                                 const GrGLShaderBuilder& segments,
927                                 CachedData* programData) {
928    enum { kPreAllocStringCnt = 8 };
929
930    PREALLOC_STR_ARRAY(kPreAllocStringCnt)    strs;
931    PREALLOC_LENGTH_ARRAY(kPreAllocStringCnt) lengths;
932    PREALLOC_TEMP_ARRAY(kPreAllocStringCnt)   temps;
933
934    GrStringBuilder unis;
935    GrStringBuilder inputs;
936    GrStringBuilder outputs;
937
938    append_string(segments.fHeader, &strs, &lengths);
939    append_decls(segments.fVSUnis, gl, &strs, &lengths, &temps);
940    append_decls(segments.fVSAttrs, gl, &strs, &lengths, &temps);
941    append_decls(segments.fVSOutputs, gl, &strs, &lengths, &temps);
942    append_string(segments.fVSCode, &strs, &lengths);
943
944#if PRINT_SHADERS
945    print_shader(strs.count(), &strs[0], &lengths[0]);
946    GrPrintf("\n");
947#endif
948
949    programData->fVShaderID =
950        CompileShader(gl, GR_GL_VERTEX_SHADER, strs.count(),
951                      &strs[0], &lengths[0]);
952
953    if (!programData->fVShaderID) {
954        return false;
955    }
956    if (segments.fUsesGS) {
957        strs.reset();
958        lengths.reset();
959        temps.reset();
960        append_string(segments.fHeader, &strs, &lengths);
961        append_string(segments.fGSHeader, &strs, &lengths);
962        append_decls(segments.fGSInputs, gl, &strs, &lengths, &temps);
963        append_decls(segments.fGSOutputs, gl, &strs, &lengths, &temps);
964        append_string(segments.fGSCode, &strs, &lengths);
965#if PRINT_SHADERS
966        print_shader(strs.count(), &strs[0], &lengths[0]);
967        GrPrintf("\n");
968#endif
969        programData->fGShaderID =
970            CompileShader(gl, GR_GL_GEOMETRY_SHADER, strs.count(),
971                          &strs[0], &lengths[0]);
972    } else {
973        programData->fGShaderID = 0;
974    }
975
976    strs.reset();
977    lengths.reset();
978    temps.reset();
979
980    append_string(segments.fHeader, &strs, &lengths);
981    GrStringBuilder precisionStr(GrGetGLSLShaderPrecisionDecl(gl.binding()));
982    append_string(precisionStr, &strs, &lengths);
983    append_decls(segments.fFSUnis, gl, &strs, &lengths, &temps);
984    append_decls(segments.fFSInputs, gl, &strs, &lengths, &temps);
985    // We shouldn't have declared outputs on 1.10
986    GrAssert(k110_GrGLSLGeneration != gl.glslGeneration() ||
987             segments.fFSOutputs.empty());
988    append_decls(segments.fFSOutputs, gl, &strs, &lengths, &temps);
989    append_string(segments.fFSFunctions, &strs, &lengths);
990    append_string(segments.fFSCode, &strs, &lengths);
991
992#if PRINT_SHADERS
993    print_shader(strs.count(), &strs[0], &lengths[0]);
994    GrPrintf("\n");
995#endif
996
997    programData->fFShaderID =
998        CompileShader(gl, GR_GL_FRAGMENT_SHADER, strs.count(),
999                      &strs[0], &lengths[0]);
1000
1001    if (!programData->fFShaderID) {
1002        return false;
1003    }
1004
1005    return true;
1006}
1007
1008#define GL_CALL(X) GR_GL_CALL(gl.interface(), X)
1009#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gl.interface(), R, X)
1010
1011GrGLuint GrGLProgram::CompileShader(const GrGLContextInfo& gl,
1012                                    GrGLenum type,
1013                                    int stringCnt,
1014                                    const char** strings,
1015                                    int* stringLengths) {
1016    SK_TRACE_EVENT1("GrGLProgram::CompileShader",
1017                    "stringCount", SkStringPrintf("%i", stringCnt).c_str());
1018
1019    GrGLuint shader;
1020    GL_CALL_RET(shader, CreateShader(type));
1021    if (0 == shader) {
1022        return 0;
1023    }
1024
1025    GrGLint compiled = GR_GL_INIT_ZERO;
1026    GL_CALL(ShaderSource(shader, stringCnt, strings, stringLengths));
1027    GL_CALL(CompileShader(shader));
1028    GL_CALL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
1029
1030    if (!compiled) {
1031        GrGLint infoLen = GR_GL_INIT_ZERO;
1032        GL_CALL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
1033        SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
1034        if (infoLen > 0) {
1035            // retrieve length even though we don't need it to workaround
1036            // bug in chrome cmd buffer param validation.
1037            GrGLsizei length = GR_GL_INIT_ZERO;
1038            GL_CALL(GetShaderInfoLog(shader, infoLen+1,
1039                                         &length, (char*)log.get()));
1040            print_shader(stringCnt, strings, stringLengths);
1041            GrPrintf("\n%s", log.get());
1042        }
1043        GrAssert(!"Shader compilation failed!");
1044        GL_CALL(DeleteShader(shader));
1045        return 0;
1046    }
1047    return shader;
1048}
1049
1050bool GrGLProgram::bindOutputsAttribsAndLinkProgram(
1051                                        const GrGLContextInfo& gl,
1052                                        GrStringBuilder texCoordAttrNames[],
1053                                        bool bindColorOut,
1054                                        bool bindDualSrcOut,
1055                                        CachedData* programData) const {
1056    GL_CALL_RET(programData->fProgramID, CreateProgram());
1057    if (!programData->fProgramID) {
1058        return false;
1059    }
1060    const GrGLint& progID = programData->fProgramID;
1061
1062    GL_CALL(AttachShader(progID, programData->fVShaderID));
1063    if (programData->fGShaderID) {
1064        GL_CALL(AttachShader(progID, programData->fGShaderID));
1065    }
1066    GL_CALL(AttachShader(progID, programData->fFShaderID));
1067
1068    if (bindColorOut) {
1069        GL_CALL(BindFragDataLocation(programData->fProgramID,
1070                                     0, declared_color_output_name()));
1071    }
1072    if (bindDualSrcOut) {
1073        GL_CALL(BindFragDataLocationIndexed(programData->fProgramID,
1074                                            0, 1, dual_source_output_name()));
1075    }
1076
1077    // Bind the attrib locations to same values for all shaders
1078    GL_CALL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
1079    for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
1080        if (texCoordAttrNames[t].size()) {
1081            GL_CALL(BindAttribLocation(progID,
1082                                       TexCoordAttributeIdx(t),
1083                                       texCoordAttrNames[t].c_str()));
1084        }
1085    }
1086
1087    GL_CALL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
1088    GL_CALL(BindAttribLocation(progID, CoverageAttributeIdx(), COV_ATTR_NAME));
1089    GL_CALL(BindAttribLocation(progID, EdgeAttributeIdx(), EDGE_ATTR_NAME));
1090
1091    GL_CALL(LinkProgram(progID));
1092
1093    GrGLint linked = GR_GL_INIT_ZERO;
1094    GL_CALL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
1095    if (!linked) {
1096        GrGLint infoLen = GR_GL_INIT_ZERO;
1097        GL_CALL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
1098        SkAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
1099        if (infoLen > 0) {
1100            // retrieve length even though we don't need it to workaround
1101            // bug in chrome cmd buffer param validation.
1102            GrGLsizei length = GR_GL_INIT_ZERO;
1103            GL_CALL(GetProgramInfoLog(progID,
1104                                      infoLen+1,
1105                                      &length,
1106                                      (char*)log.get()));
1107            GrPrintf((char*)log.get());
1108        }
1109        GrAssert(!"Error linking program");
1110        GL_CALL(DeleteProgram(progID));
1111        programData->fProgramID = 0;
1112        return false;
1113    }
1114    return true;
1115}
1116
1117void GrGLProgram::getUniformLocationsAndInitCache(const GrGLContextInfo& gl,
1118                                                  CachedData* programData) const {
1119    const GrGLint& progID = programData->fProgramID;
1120
1121    if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
1122        GL_CALL_RET(programData->fUniLocations.fViewMatrixUni,
1123                    GetUniformLocation(progID, VIEW_MATRIX_NAME));
1124        GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
1125    }
1126    if (kUseUniform == programData->fUniLocations.fColorUni) {
1127        GL_CALL_RET(programData->fUniLocations.fColorUni,
1128                    GetUniformLocation(progID, COL_UNI_NAME));
1129        GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
1130    }
1131    if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
1132        GL_CALL_RET(programData->fUniLocations.fColorFilterUni,
1133                    GetUniformLocation(progID, COL_FILTER_UNI_NAME));
1134        GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
1135    }
1136
1137    if (kUseUniform == programData->fUniLocations.fColorMatrixUni) {
1138        GL_CALL_RET(programData->fUniLocations.fColorMatrixUni,
1139                    GetUniformLocation(progID, COL_MATRIX_UNI_NAME));
1140    }
1141
1142    if (kUseUniform == programData->fUniLocations.fColorMatrixVecUni) {
1143        GL_CALL_RET(programData->fUniLocations.fColorMatrixVecUni,
1144                    GetUniformLocation(progID, COL_MATRIX_VEC_UNI_NAME));
1145    }
1146    if (kUseUniform == programData->fUniLocations.fCoverageUni) {
1147        GL_CALL_RET(programData->fUniLocations.fCoverageUni,
1148                    GetUniformLocation(progID, COV_UNI_NAME));
1149        GrAssert(kUnusedUniform != programData->fUniLocations.fCoverageUni);
1150    }
1151
1152    if (kUseUniform == programData->fUniLocations.fEdgesUni) {
1153        GL_CALL_RET(programData->fUniLocations.fEdgesUni,
1154                    GetUniformLocation(progID, EDGES_UNI_NAME));
1155        GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
1156    } else {
1157        programData->fUniLocations.fEdgesUni = kUnusedUniform;
1158    }
1159
1160    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
1161        StageUniLocations& locations = programData->fUniLocations.fStages[s];
1162        if (fProgramDesc.fStages[s].isEnabled()) {
1163            if (kUseUniform == locations.fTextureMatrixUni) {
1164                GrStringBuilder texMName;
1165                tex_matrix_name(s, &texMName);
1166                GL_CALL_RET(locations.fTextureMatrixUni,
1167                            GetUniformLocation(progID, texMName.c_str()));
1168                GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
1169            }
1170
1171            if (kUseUniform == locations.fSamplerUni) {
1172                GrStringBuilder samplerName;
1173                sampler_name(s, &samplerName);
1174                GL_CALL_RET(locations.fSamplerUni,
1175                            GetUniformLocation(progID,samplerName.c_str()));
1176                GrAssert(kUnusedUniform != locations.fSamplerUni);
1177            }
1178
1179            if (kUseUniform == locations.fNormalizedTexelSizeUni) {
1180                GrStringBuilder texelSizeName;
1181                normalized_texel_size_name(s, &texelSizeName);
1182                GL_CALL_RET(locations.fNormalizedTexelSizeUni,
1183                            GetUniformLocation(progID, texelSizeName.c_str()));
1184                GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
1185            }
1186
1187            if (kUseUniform == locations.fRadial2Uni) {
1188                GrStringBuilder radial2ParamName;
1189                radial2_param_name(s, &radial2ParamName);
1190                GL_CALL_RET(locations.fRadial2Uni,
1191                            GetUniformLocation(progID, radial2ParamName.c_str()));
1192                GrAssert(kUnusedUniform != locations.fRadial2Uni);
1193            }
1194
1195            if (kUseUniform == locations.fTexDomUni) {
1196                GrStringBuilder texDomName;
1197                tex_domain_name(s, &texDomName);
1198                GL_CALL_RET(locations.fTexDomUni,
1199                            GetUniformLocation(progID, texDomName.c_str()));
1200                GrAssert(kUnusedUniform != locations.fTexDomUni);
1201            }
1202
1203            GrStringBuilder kernelName, imageIncrementName;
1204            convolve_param_names(s, &kernelName, &imageIncrementName);
1205            if (kUseUniform == locations.fKernelUni) {
1206                GL_CALL_RET(locations.fKernelUni,
1207                            GetUniformLocation(progID, kernelName.c_str()));
1208                GrAssert(kUnusedUniform != locations.fKernelUni);
1209            }
1210
1211            if (kUseUniform == locations.fImageIncrementUni) {
1212                GL_CALL_RET(locations.fImageIncrementUni,
1213                            GetUniformLocation(progID,
1214                                               imageIncrementName.c_str()));
1215                GrAssert(kUnusedUniform != locations.fImageIncrementUni);
1216            }
1217
1218            if (NULL != programData->fCustomStage[s]) {
1219                programData->fCustomStage[s]->
1220                    initUniforms(gl.interface(), progID);
1221            }
1222        }
1223    }
1224    GL_CALL(UseProgram(progID));
1225
1226    // init sampler unis and set bogus values for state tracking
1227    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
1228        if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
1229            GL_CALL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
1230        }
1231        programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
1232        programData->fRadial2CenterX1[s] = GR_ScalarMax;
1233        programData->fRadial2Radius0[s] = -GR_ScalarMax;
1234        programData->fTextureWidth[s] = -1;
1235        programData->fTextureHeight[s] = -1;
1236        programData->fTextureDomain[s].setEmpty();
1237        // Must not reset fStageOverride[] here.
1238    }
1239    programData->fViewMatrix = GrMatrix::InvalidMatrix();
1240    programData->fColor = GrColor_ILLEGAL;
1241    programData->fColorFilterColor = GrColor_ILLEGAL;
1242}
1243
1244//============================================================================
1245// Stage code generation
1246//============================================================================
1247
1248namespace {
1249
1250bool isRadialMapping(GrGLProgram::StageDesc::CoordMapping mapping) {
1251    return
1252       (GrGLProgram::StageDesc::kRadial2Gradient_CoordMapping == mapping ||
1253        GrGLProgram::StageDesc::kRadial2GradientDegenerate_CoordMapping == mapping);
1254}
1255
1256GrGLShaderVar* genRadialVS(int stageNum,
1257                        GrGLShaderBuilder* segments,
1258                        GrGLProgram::StageUniLocations* locations,
1259                        const char** radial2VaryingVSName,
1260                        const char** radial2VaryingFSName,
1261                        const char* varyingVSName) {
1262
1263    GrGLShaderVar* radial2FSParams = &segments->fFSUnis.push_back();
1264    radial2FSParams->setType(kFloat_GrSLType);
1265    radial2FSParams->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
1266    radial2FSParams->setArrayCount(6);
1267    radial2_param_name(stageNum, radial2FSParams->accessName());
1268    segments->fVSUnis.push_back(*radial2FSParams).setEmitPrecision(true);
1269
1270    locations->fRadial2Uni = kUseUniform;
1271
1272    // for radial grads without perspective we can pass the linear
1273    // part of the quadratic as a varying.
1274    if (segments->fVaryingDims == segments->fCoordDims) {
1275        GrAssert(2 == segments->fCoordDims);
1276        segments->appendVarying(kFloat_GrSLType,
1277                                "Radial2BCoeff",
1278                                stageNum,
1279                                radial2VaryingVSName,
1280                                radial2VaryingFSName);
1281
1282        GrStringBuilder radial2p2;
1283        GrStringBuilder radial2p3;
1284        radial2FSParams->appendArrayAccess(2, &radial2p2);
1285        radial2FSParams->appendArrayAccess(3, &radial2p3);
1286
1287        // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
1288        const char* r2ParamName = radial2FSParams->getName().c_str();
1289        segments->fVSCode.appendf("\t%s = 2.0 *(%s * %s.x - %s);\n",
1290                                  *radial2VaryingVSName, radial2p2.c_str(),
1291                                  varyingVSName, radial2p3.c_str());
1292    }
1293
1294    return radial2FSParams;
1295}
1296
1297void genRadial2GradientCoordMapping(int stageNum,
1298                                    GrGLShaderBuilder* segments,
1299                                    const char* radial2VaryingFSName,
1300                                    GrGLShaderVar* radial2Params) {
1301    GrStringBuilder cName("c");
1302    GrStringBuilder ac4Name("ac4");
1303    GrStringBuilder rootName("root");
1304
1305    cName.appendS32(stageNum);
1306    ac4Name.appendS32(stageNum);
1307    rootName.appendS32(stageNum);
1308
1309    GrStringBuilder radial2p0;
1310    GrStringBuilder radial2p1;
1311    GrStringBuilder radial2p2;
1312    GrStringBuilder radial2p3;
1313    GrStringBuilder radial2p4;
1314    GrStringBuilder radial2p5;
1315    radial2Params->appendArrayAccess(0, &radial2p0);
1316    radial2Params->appendArrayAccess(1, &radial2p1);
1317    radial2Params->appendArrayAccess(2, &radial2p2);
1318    radial2Params->appendArrayAccess(3, &radial2p3);
1319    radial2Params->appendArrayAccess(4, &radial2p4);
1320    radial2Params->appendArrayAccess(5, &radial2p5);
1321
1322    // if we were able to interpolate the linear component bVar is the varying
1323    // otherwise compute it
1324    GrStringBuilder bVar;
1325    if (segments->fCoordDims == segments->fVaryingDims) {
1326        bVar = radial2VaryingFSName;
1327        GrAssert(2 == segments->fVaryingDims);
1328    } else {
1329        GrAssert(3 == segments->fVaryingDims);
1330        bVar = "b";
1331        bVar.appendS32(stageNum);
1332        segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
1333                                    bVar.c_str(), radial2p2.c_str(),
1334                                    segments->fSampleCoords.c_str(), radial2p3.c_str());
1335    }
1336
1337    // c = (x^2)+(y^2) - params[4]
1338    segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s;\n",
1339                              cName.c_str(), segments->fSampleCoords.c_str(),
1340                              segments->fSampleCoords.c_str(),
1341                              radial2p4.c_str());
1342    // ac4 = 4.0 * params[0] * c
1343    segments->fFSCode.appendf("\tfloat %s = %s * 4.0 * %s;\n",
1344                              ac4Name.c_str(), radial2p0.c_str(),
1345                              cName.c_str());
1346
1347    // root = sqrt(b^2-4ac)
1348    // (abs to avoid exception due to fp precision)
1349    segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
1350                              rootName.c_str(), bVar.c_str(), bVar.c_str(),
1351                              ac4Name.c_str());
1352
1353    // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
1354    // y coord is 0.5 (texture is effectively 1D)
1355    segments->fSampleCoords.printf("vec2((-%s + %s * %s) * %s, 0.5)",
1356                        bVar.c_str(), radial2p5.c_str(),
1357                        rootName.c_str(), radial2p1.c_str());
1358    segments->fComplexCoord = true;
1359}
1360
1361void genRadial2GradientDegenerateCoordMapping(int stageNum,
1362                                              GrGLShaderBuilder* segments,
1363                                              const char* radial2VaryingFSName,
1364                                              GrGLShaderVar* radial2Params) {
1365    GrStringBuilder cName("c");
1366
1367    cName.appendS32(stageNum);
1368
1369    GrStringBuilder radial2p2;
1370    GrStringBuilder radial2p3;
1371    GrStringBuilder radial2p4;
1372    radial2Params->appendArrayAccess(2, &radial2p2);
1373    radial2Params->appendArrayAccess(3, &radial2p3);
1374    radial2Params->appendArrayAccess(4, &radial2p4);
1375
1376    // if we were able to interpolate the linear component bVar is the varying
1377    // otherwise compute it
1378    GrStringBuilder bVar;
1379    if (segments->fCoordDims == segments->fVaryingDims) {
1380        bVar = radial2VaryingFSName;
1381        GrAssert(2 == segments->fVaryingDims);
1382    } else {
1383        GrAssert(3 == segments->fVaryingDims);
1384        bVar = "b";
1385        bVar.appendS32(stageNum);
1386        segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
1387                                    bVar.c_str(), radial2p2.c_str(),
1388                                    segments->fSampleCoords.c_str(), radial2p3.c_str());
1389    }
1390
1391    // c = (x^2)+(y^2) - params[4]
1392    segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s;\n",
1393                              cName.c_str(), segments->fSampleCoords.c_str(),
1394                              segments->fSampleCoords.c_str(),
1395                              radial2p4.c_str());
1396
1397    // x coord is: -c/b
1398    // y coord is 0.5 (texture is effectively 1D)
1399    segments->fSampleCoords.printf("vec2((-%s / %s), 0.5)", cName.c_str(), bVar.c_str());
1400    segments->fComplexCoord = true;
1401}
1402
1403void gen2x2FS(int stageNum,
1404              GrGLShaderBuilder* segments,
1405              GrGLProgram::StageUniLocations* locations,
1406              const char* samplerName,
1407              const char* texelSizeName,
1408              const char* fsOutColor,
1409              GrStringBuilder& texFunc) {
1410    locations->fNormalizedTexelSizeUni = kUseUniform;
1411    if (segments->fComplexCoord) {
1412        // assign the coord to a var rather than compute 4x.
1413        GrStringBuilder coordVar("tCoord");
1414        coordVar.appendS32(stageNum);
1415        segments->fFSCode.appendf("\t%s %s = %s;\n",
1416                            float_vector_type_str(segments->fCoordDims),
1417                            coordVar.c_str(), segments->fSampleCoords.c_str());
1418        segments->fSampleCoords = coordVar;
1419    }
1420    GrAssert(2 == segments->fCoordDims);
1421    GrStringBuilder accumVar("accum");
1422    accumVar.appendS32(stageNum);
1423    segments->fFSCode.appendf("\tvec4 %s  = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str());
1424    segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str());
1425    segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str());
1426    segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str());
1427    segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), segments->fModulate.c_str());
1428
1429}
1430
1431void genMorphologyVS(int stageNum,
1432                     const StageDesc& desc,
1433                     GrGLShaderBuilder* segments,
1434                     GrGLProgram::StageUniLocations* locations,
1435                     const char** imageIncrementName,
1436                     const char* varyingVSName) {
1437    GrGLShaderVar* imgInc = &segments->fFSUnis.push_back();
1438    imgInc->setType(kVec2f_GrSLType);
1439    imgInc->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
1440
1441    image_increment_param_name(stageNum, imgInc->accessName());
1442    *imageIncrementName = imgInc->getName().c_str();
1443
1444    // need image increment in both VS and FS
1445    segments->fVSUnis.push_back(*imgInc).setEmitPrecision(true);
1446
1447    locations->fImageIncrementUni = kUseUniform;
1448    segments->fVSCode.appendf("\t%s -= vec2(%d, %d) * %s;\n",
1449                                  varyingVSName, desc.fKernelWidth,
1450                                  desc.fKernelWidth, *imageIncrementName);
1451}
1452
1453void genMorphologyFS(int stageNum,
1454                     const StageDesc& desc,
1455                     GrGLShaderBuilder* segments,
1456                     const char* samplerName,
1457                     const char* imageIncrementName,
1458                     const char* fsOutColor,
1459                     GrStringBuilder& texFunc) {
1460    GrStringBuilder valueVar("value");
1461    valueVar.appendS32(stageNum);
1462    GrStringBuilder coordVar("coord");
1463    coordVar.appendS32(stageNum);
1464    bool isDilate = StageDesc::kDilate_FetchMode == desc.fFetchMode;
1465
1466   if (isDilate) {
1467        segments->fFSCode.appendf("\tvec4 %s = vec4(0, 0, 0, 0);\n",
1468                                  valueVar.c_str());
1469    } else {
1470        segments->fFSCode.appendf("\tvec4 %s = vec4(1, 1, 1, 1);\n",
1471                                  valueVar.c_str());
1472    }
1473    segments->fFSCode.appendf("\tvec2 %s = %s;\n",
1474                              coordVar.c_str(),
1475                              segments->fSampleCoords.c_str());
1476    segments->fFSCode.appendf("\tfor (int i = 0; i < %d; i++) {\n",
1477                              desc.fKernelWidth * 2 + 1);
1478    segments->fFSCode.appendf("\t\t%s = %s(%s, %s(%s, %s)%s);\n",
1479                              valueVar.c_str(), isDilate ? "max" : "min",
1480                              valueVar.c_str(), texFunc.c_str(),
1481                              samplerName, coordVar.c_str(),
1482                              segments->fSwizzle.c_str());
1483    segments->fFSCode.appendf("\t\t%s += %s;\n",
1484                              coordVar.c_str(),
1485                              imageIncrementName);
1486    segments->fFSCode.appendf("\t}\n");
1487    segments->fFSCode.appendf("\t%s = %s%s;\n", fsOutColor,
1488                              valueVar.c_str(), segments->fModulate.c_str());
1489}
1490
1491}
1492
1493void GrGLProgram::genStageCode(const GrGLContextInfo& gl,
1494                               int stageNum,
1495                               const GrGLProgram::StageDesc& desc,
1496                               const char* fsInColor, // NULL means no incoming color
1497                               const char* fsOutColor,
1498                               const char* vsInCoord,
1499                               GrGLShaderBuilder* segments,
1500                               StageUniLocations* locations,
1501                               GrGLProgramStage* customStage) const {
1502
1503    GrAssert(stageNum >= 0 && stageNum <= GrDrawState::kNumStages);
1504    GrAssert((desc.fInConfigFlags & StageDesc::kInConfigBitMask) ==
1505             desc.fInConfigFlags);
1506
1507    /// Vertex Shader Stuff
1508
1509    if (NULL != customStage) {
1510        customStage->setupVSUnis(&segments->fVSUnis, stageNum);
1511    }
1512
1513    // decide whether we need a matrix to transform texture coords
1514    // and whether the varying needs a perspective coord.
1515    const char* matName = NULL;
1516    if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
1517        segments->fVaryingDims = segments->fCoordDims;
1518    } else {
1519        GrGLShaderVar* mat;
1520        mat = &segments->fVSUnis.push_back();
1521        mat->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
1522        locations->fTextureMatrixUni = kUseUniform;
1523
1524        tex_matrix_name(stageNum, mat->accessName());
1525        mat->setType(kMat33f_GrSLType);
1526        matName = mat->getName().c_str();
1527
1528        if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
1529            segments->fVaryingDims = segments->fCoordDims;
1530        } else {
1531            segments->fVaryingDims = segments->fCoordDims + 1;
1532        }
1533    }
1534    GrAssert(segments->fVaryingDims > 0);
1535
1536    segments->fFSUnis.push_back().set(kSampler2D_GrSLType,
1537        GrGLShaderVar::kUniform_TypeModifier, "");
1538    sampler_name(stageNum, segments->fFSUnis.back().accessName());
1539    locations->fSamplerUni = kUseUniform;
1540    const char* samplerName = segments->fFSUnis.back().getName().c_str();
1541
1542    const char* texelSizeName = NULL;
1543    if (StageDesc::k2x2_FetchMode == desc.fFetchMode) {
1544        segments->fFSUnis.push_back().set(kVec2f_GrSLType,
1545            GrGLShaderVar::kUniform_TypeModifier, "");
1546        normalized_texel_size_name(stageNum, segments->fFSUnis.back().accessName());
1547        texelSizeName = segments->fFSUnis.back().getName().c_str();
1548    }
1549
1550    const char *varyingVSName, *varyingFSName;
1551    segments->appendVarying(GrSLFloatVectorType(segments->fVaryingDims),
1552                            "Stage",
1553                           stageNum,
1554                           &varyingVSName,
1555                           &varyingFSName);
1556
1557    if (!matName) {
1558        GrAssert(segments->fVaryingDims == segments->fCoordDims);
1559        segments->fVSCode.appendf("\t%s = %s;\n", varyingVSName, vsInCoord);
1560    } else {
1561        // varying = texMatrix * texCoord
1562        segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
1563                                  varyingVSName, matName, vsInCoord,
1564                                  vector_all_coords(segments->fVaryingDims));
1565    }
1566
1567    GrGLShaderVar* radial2Params = NULL;
1568    const char* radial2VaryingVSName = NULL;
1569    const char* radial2VaryingFSName = NULL;
1570
1571    if (isRadialMapping((StageDesc::CoordMapping) desc.fCoordMapping)) {
1572        radial2Params = genRadialVS(stageNum, segments,
1573                                    locations,
1574                                    &radial2VaryingVSName,
1575                                    &radial2VaryingFSName,
1576                                    varyingVSName);
1577    }
1578
1579    GrGLShaderVar* kernel = NULL;
1580    const char* imageIncrementName = NULL;
1581    if (StageDesc::kDilate_FetchMode == desc.fFetchMode ||
1582               StageDesc::kErode_FetchMode == desc.fFetchMode) {
1583        genMorphologyVS(stageNum, desc, segments, locations,
1584                        &imageIncrementName, varyingVSName);
1585    }
1586
1587    if (NULL != customStage) {
1588        segments->fVSCode.appendf("\t{ // stage %d %s\n",
1589                                  stageNum, customStage->name());
1590        customStage->emitVS(segments, varyingVSName);
1591        segments->fVSCode.appendf("\t}\n");
1592    }
1593
1594    /// Fragment Shader Stuff
1595
1596    if (NULL != customStage) {
1597        customStage->setupFSUnis(&segments->fFSUnis, stageNum);
1598    }
1599
1600    // Function used to access the shader, may be made projective.
1601    GrStringBuilder texFunc("texture2D");
1602    if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
1603                          StageDesc::kNoPerspective_OptFlagBit)) {
1604        GrAssert(segments->fVaryingDims == segments->fCoordDims);
1605        segments->fSampleCoords = varyingFSName;
1606    } else {
1607        // If we have to do some special op on the varyings to get
1608        // our final tex coords then when in perspective we have to
1609        // do an explicit divide. Otherwise, we can use a Proj func.
1610        if  (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
1611             StageDesc::kSingle_FetchMode == desc.fFetchMode) {
1612            texFunc.append("Proj");
1613            segments->fSampleCoords = varyingFSName;
1614        } else {
1615            // This block is replicated in GrGLProgramStage::emitTextureLookup()
1616            segments->fSampleCoords = "inCoord";
1617            segments->fSampleCoords.appendS32(stageNum);
1618            segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
1619                GrGLShaderVar::TypeString(GrSLFloatVectorType(segments->fCoordDims)),
1620                segments->fSampleCoords.c_str(),
1621                varyingFSName,
1622                GrGLSLVectorNonhomogCoords(segments->fVaryingDims),
1623                varyingFSName,
1624                GrGLSLVectorHomogCoord(segments->fVaryingDims));
1625        }
1626    }
1627
1628    segments->fComplexCoord = false;
1629    // NOTE: GrGLProgramStages will soon responsible for mapping
1630    //if (NULL == customStage) {
1631        switch (desc.fCoordMapping) {
1632        case StageDesc::kIdentity_CoordMapping:
1633            // Do nothing
1634            break;
1635        case StageDesc::kSweepGradient_CoordMapping:
1636            segments->fSampleCoords.printf("vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)", segments->fSampleCoords.c_str(), segments->fSampleCoords.c_str());
1637            segments->fComplexCoord = true;
1638            break;
1639        case StageDesc::kRadialGradient_CoordMapping:
1640            segments->fSampleCoords.printf("vec2(length(%s.xy), 0.5)", segments->fSampleCoords.c_str());
1641            segments->fComplexCoord = true;
1642            break;
1643        case StageDesc::kRadial2Gradient_CoordMapping:
1644            genRadial2GradientCoordMapping(
1645                               stageNum, segments,
1646                               radial2VaryingFSName, radial2Params);
1647            break;
1648        case StageDesc::kRadial2GradientDegenerate_CoordMapping:
1649            genRadial2GradientDegenerateCoordMapping(
1650                               stageNum, segments,
1651                               radial2VaryingFSName, radial2Params);
1652            break;
1653        }
1654    //}
1655
1656    static const uint32_t kMulByAlphaMask =
1657        (StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
1658         StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag);
1659
1660    segments->computeSwizzle(desc.fInConfigFlags);
1661    segments->computeModulate(fsInColor);
1662
1663    if (desc.fOptFlags &
1664        StageDesc::kCustomTextureDomain_OptFlagBit) {
1665        GrStringBuilder texDomainName;
1666        tex_domain_name(stageNum, &texDomainName);
1667        segments->fFSUnis.push_back().set(kVec4f_GrSLType,
1668            GrGLShaderVar::kUniform_TypeModifier, texDomainName);
1669        GrStringBuilder coordVar("clampCoord");
1670        segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
1671                                  float_vector_type_str(segments->fCoordDims),
1672                                  coordVar.c_str(),
1673                                  segments->fSampleCoords.c_str(),
1674                                  texDomainName.c_str(),
1675                                  texDomainName.c_str());
1676        segments->fSampleCoords = coordVar;
1677        locations->fTexDomUni = kUseUniform;
1678    }
1679
1680    if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
1681                          StageDesc::kNoPerspective_OptFlagBit)) {
1682        segments->setSamplerMode(GrGLShaderBuilder::kDefault_SamplerMode);
1683    } else if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
1684               StageDesc::kSingle_FetchMode == desc.fFetchMode) {
1685        segments->setSamplerMode(GrGLShaderBuilder::kProj_SamplerMode);
1686    } else {
1687        segments->setSamplerMode(
1688            GrGLShaderBuilder::kExplicitDivide_SamplerMode);
1689    }
1690
1691    // NOTE: GrGLProgramStages are now responsible for fetching
1692    if (NULL == customStage) {
1693        switch (desc.fFetchMode) {
1694        case StageDesc::k2x2_FetchMode:
1695            GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
1696            gen2x2FS(stageNum, segments, locations,
1697                samplerName, texelSizeName, fsOutColor, texFunc);
1698            break;
1699        case StageDesc::kConvolution_FetchMode:
1700            GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
1701            break;
1702        case StageDesc::kDilate_FetchMode:
1703        case StageDesc::kErode_FetchMode:
1704            GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
1705            genMorphologyFS(stageNum, desc, segments,
1706                samplerName, imageIncrementName, fsOutColor, texFunc);
1707            break;
1708        default:
1709            if (desc.fInConfigFlags & kMulByAlphaMask) {
1710                // only one of the mul by alpha flags should be set
1711                GrAssert(GrIsPow2(kMulByAlphaMask & desc.fInConfigFlags));
1712                GrAssert(!(desc.fInConfigFlags &
1713                           StageDesc::kSmearAlpha_InConfigFlag));
1714                GrAssert(!(desc.fInConfigFlags &
1715                           StageDesc::kSmearRed_InConfigFlag));
1716                segments->fFSCode.appendf("\t%s = %s(%s, %s)%s;\n",
1717                                          fsOutColor, texFunc.c_str(),
1718                                          samplerName,
1719                                          segments->fSampleCoords.c_str(),
1720                                          segments->fSwizzle.c_str());
1721                if (desc.fInConfigFlags &
1722                    StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag) {
1723                    segments->fFSCode.appendf("\t%s = vec4(ceil(%s.rgb*%s.a*255.0)/255.0,%s.a)%s;\n",
1724                                              fsOutColor, fsOutColor, fsOutColor,
1725                                              fsOutColor, segments->fModulate.c_str());
1726                } else {
1727                    segments->fFSCode.appendf("\t%s = vec4(floor(%s.rgb*%s.a*255.0)/255.0,%s.a)%s;\n",
1728                                              fsOutColor, fsOutColor, fsOutColor,
1729                                              fsOutColor, segments->fModulate.c_str());
1730                }
1731            } else {
1732                segments->emitDefaultFetch(fsOutColor, samplerName);
1733            }
1734        }
1735    }
1736
1737    if (NULL != customStage) {
1738        // Enclose custom code in a block to avoid namespace conflicts
1739        segments->fFSCode.appendf("\t{ // stage %d %s \n",
1740                                  stageNum, customStage->name());
1741        segments->emitTextureSetup();
1742        customStage->emitFS(segments, fsOutColor, fsInColor, samplerName);
1743        segments->fFSCode.appendf("\t}\n");
1744    }
1745}
1746
1747
1748