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