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