Home | History | Annotate | Download | only in src
      1 /*
      2     Copyright 2011 Google Inc.
      3 
      4     Licensed under the Apache License, Version 2.0 (the "License");
      5     you may not use this file except in compliance with the License.
      6     You may obtain a copy of the License at
      7 
      8          http://www.apache.org/licenses/LICENSE-2.0
      9 
     10     Unless required by applicable law or agreed to in writing, software
     11     distributed under the License is distributed on an "AS IS" BASIS,
     12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13     See the License for the specific language governing permissions and
     14     limitations under the License.
     15  */
     16 
     17 #include "GrGLProgram.h"
     18 
     19 #include "GrBinHashKey.h"
     20 #include "GrGLConfig.h"
     21 #include "GrMemory.h"
     22 
     23 #include "SkXfermode.h"
     24 
     25 namespace {
     26 
     27 const char* GrPrecision() {
     28     if (GR_GL_SUPPORT_ES2) {
     29         return "mediump";
     30     } else {
     31         return " ";
     32     }
     33 }
     34 
     35 const char* GrShaderPrecision() {
     36     if (GR_GL_SUPPORT_ES2) {
     37         return "precision mediump float;\n";
     38     } else {
     39         return "";
     40     }
     41 }
     42 
     43 }  // namespace
     44 
     45 #define PRINT_SHADERS 0
     46 
     47 #if GR_GL_ATTRIBUTE_MATRICES
     48     #define VIEW_MATRIX_NAME "aViewM"
     49 #else
     50     #define VIEW_MATRIX_NAME "uViewM"
     51 #endif
     52 
     53 #define POS_ATTR_NAME "aPosition"
     54 #define COL_ATTR_NAME "aColor"
     55 #define COL_UNI_NAME "uColor"
     56 #define EDGES_UNI_NAME "uEdges"
     57 #define COL_FILTER_UNI_NAME "uColorFilter"
     58 
     59 static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
     60     *s = "aTexCoord";
     61     s->appendS32(coordIdx);
     62 }
     63 
     64 static inline const char* float_vector_type(int count) {
     65     static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
     66     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
     67     return FLOAT_VECS[count];
     68 }
     69 
     70 static inline const char* vector_homog_coord(int count) {
     71     static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
     72     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
     73     return HOMOGS[count];
     74 }
     75 
     76 static inline const char* vector_nonhomog_coords(int count) {
     77     static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
     78     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
     79     return NONHOMOGS[count];
     80 }
     81 
     82 static inline const char* vector_all_coords(int count) {
     83     static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
     84     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
     85     return ALL[count];
     86 }
     87 
     88 static inline const char* all_ones_vec(int count) {
     89     static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)",
     90                                     "vec3(1,1,1)", "vec4(1,1,1,1)"};
     91     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ONESVEC));
     92     return ONESVEC[count];
     93 }
     94 
     95 static inline const char* all_zeros_vec(int count) {
     96     static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)",
     97                                     "vec3(0,0,0)", "vec4(0,0,0,0)"};
     98     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ZEROSVEC));
     99     return ZEROSVEC[count];
    100 }
    101 
    102 static inline const char* declared_color_output_name() { return "fsColorOut"; }
    103 static inline const char* dual_source_output_name() { return "dualSourceOut"; }
    104 
    105 static void tex_matrix_name(int stage, GrStringBuilder* s) {
    106 #if GR_GL_ATTRIBUTE_MATRICES
    107     *s = "aTexM";
    108 #else
    109     *s = "uTexM";
    110 #endif
    111     s->appendS32(stage);
    112 }
    113 
    114 static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
    115     *s = "uTexelSize";
    116     s->appendS32(stage);
    117 }
    118 
    119 static void sampler_name(int stage, GrStringBuilder* s) {
    120     *s = "uSampler";
    121     s->appendS32(stage);
    122 }
    123 
    124 static void stage_varying_name(int stage, GrStringBuilder* s) {
    125     *s = "vStage";
    126     s->appendS32(stage);
    127 }
    128 
    129 static void radial2_param_name(int stage, GrStringBuilder* s) {
    130     *s = "uRadial2Params";
    131     s->appendS32(stage);
    132 }
    133 
    134 static void radial2_varying_name(int stage, GrStringBuilder* s) {
    135     *s = "vB";
    136     s->appendS32(stage);
    137 }
    138 
    139 static void tex_domain_name(int stage, GrStringBuilder* s) {
    140     *s = "uTexDom";
    141     s->appendS32(stage);
    142 }
    143 
    144 GrGLProgram::GrGLProgram() {
    145 }
    146 
    147 GrGLProgram::~GrGLProgram() {
    148 }
    149 
    150 void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
    151                                 GrBlendCoeff* dstCoeff) const {
    152     switch (fProgramDesc.fDualSrcOutput) {
    153         case ProgramDesc::kNone_DualSrcOutput:
    154             break;
    155         // the prog will write a coverage value to the secondary
    156         // output and the dst is blended by one minus that value.
    157         case ProgramDesc::kCoverage_DualSrcOutput:
    158         case ProgramDesc::kCoverageISA_DualSrcOutput:
    159         case ProgramDesc::kCoverageISC_DualSrcOutput:
    160         *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_BlendCoeff;
    161         break;
    162         default:
    163             GrCrash("Unexpected dual source blend output");
    164             break;
    165     }
    166 }
    167 
    168 void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
    169     // Add stage configuration to the key
    170     key.keyData(reinterpret_cast<const uint32_t*>(&fProgramDesc), sizeof(ProgramDesc));
    171 }
    172 
    173 // assigns modulation of two vars to an output var
    174 // vars can be vec4s or floats (or one of each)
    175 // result is always vec4
    176 // if either var is "" then assign to the other var
    177 // if both are "" then assign all ones
    178 static inline void modulate_helper(const char* outputVar,
    179                                    const char* var0,
    180                                    const char* var1,
    181                                    GrStringBuilder* code) {
    182     GrAssert(NULL != outputVar);
    183     GrAssert(NULL != var0);
    184     GrAssert(NULL != var1);
    185     GrAssert(NULL != code);
    186 
    187     bool has0 = '\0' != *var0;
    188     bool has1 = '\0' != *var1;
    189 
    190     if (!has0 && !has1) {
    191         code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4));
    192     } else if (!has0) {
    193         code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
    194     } else if (!has1) {
    195         code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
    196     } else {
    197         code->appendf("\t%s = vec4(%s * %s);\n", outputVar, var0, var1);
    198     }
    199 }
    200 
    201 // assigns addition of two vars to an output var
    202 // vars can be vec4s or floats (or one of each)
    203 // result is always vec4
    204 // if either var is "" then assign to the other var
    205 // if both are "" then assign all zeros
    206 static inline void add_helper(const char* outputVar,
    207                               const char* var0,
    208                               const char* var1,
    209                               GrStringBuilder* code) {
    210     GrAssert(NULL != outputVar);
    211     GrAssert(NULL != var0);
    212     GrAssert(NULL != var1);
    213     GrAssert(NULL != code);
    214 
    215     bool has0 = '\0' != *var0;
    216     bool has1 = '\0' != *var1;
    217 
    218     if (!has0 && !has1) {
    219         code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4));
    220     } else if (!has0) {
    221         code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
    222     } else if (!has1) {
    223         code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
    224     } else {
    225         code->appendf("\t%s = vec4(%s + %s);\n", outputVar, var0, var1);
    226     }
    227 }
    228 
    229 // given two blend coeffecients determine whether the src
    230 // and/or dst computation can be omitted.
    231 static inline void needBlendInputs(SkXfermode::Coeff srcCoeff,
    232                                    SkXfermode::Coeff dstCoeff,
    233                                    bool* needSrcValue,
    234                                    bool* needDstValue) {
    235     if (SkXfermode::kZero_Coeff == srcCoeff) {
    236         switch (dstCoeff) {
    237             // these all read the src
    238             case SkXfermode::kSC_Coeff:
    239             case SkXfermode::kISC_Coeff:
    240             case SkXfermode::kSA_Coeff:
    241             case SkXfermode::kISA_Coeff:
    242                 *needSrcValue = true;
    243                 break;
    244             default:
    245                 *needSrcValue = false;
    246                 break;
    247         }
    248     } else {
    249         *needSrcValue = true;
    250     }
    251     if (SkXfermode::kZero_Coeff == dstCoeff) {
    252         switch (srcCoeff) {
    253             // these all read the dst
    254             case SkXfermode::kDC_Coeff:
    255             case SkXfermode::kIDC_Coeff:
    256             case SkXfermode::kDA_Coeff:
    257             case SkXfermode::kIDA_Coeff:
    258                 *needDstValue = true;
    259                 break;
    260             default:
    261                 *needDstValue = false;
    262                 break;
    263         }
    264     } else {
    265         *needDstValue = true;
    266     }
    267 }
    268 
    269 /**
    270  * Create a blend_coeff * value string to be used in shader code. Sets empty
    271  * string if result is trivially zero.
    272  */
    273 static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff,
    274                              const char* src, const char* dst,
    275                              const char* value) {
    276     switch (coeff) {
    277     case SkXfermode::kZero_Coeff:    /** 0 */
    278         *str = "";
    279         break;
    280     case SkXfermode::kOne_Coeff:     /** 1 */
    281         *str = value;
    282         break;
    283     case SkXfermode::kSC_Coeff:
    284         str->printf("(%s * %s)", src, value);
    285         break;
    286     case SkXfermode::kISC_Coeff:
    287         str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value);
    288         break;
    289     case SkXfermode::kDC_Coeff:
    290         str->printf("(%s * %s)", dst, value);
    291         break;
    292     case SkXfermode::kIDC_Coeff:
    293         str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value);
    294         break;
    295     case SkXfermode::kSA_Coeff:      /** src alpha */
    296         str->printf("(%s.a * %s)", src, value);
    297         break;
    298     case SkXfermode::kISA_Coeff:     /** inverse src alpha (i.e. 1 - sa) */
    299         str->printf("((1.0 - %s.a) * %s)", src, value);
    300         break;
    301     case SkXfermode::kDA_Coeff:      /** dst alpha */
    302         str->printf("(%s.a * %s)", dst, value);
    303         break;
    304     case SkXfermode::kIDA_Coeff:     /** inverse dst alpha (i.e. 1 - da) */
    305         str->printf("((1.0 - %s.a) * %s)", dst, value);
    306         break;
    307     default:
    308         GrCrash("Unexpected xfer coeff.");
    309         break;
    310     }
    311 }
    312 /**
    313  * Adds a line to the fragment shader code which modifies the color by
    314  * the specified color filter.
    315  */
    316 static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar,
    317                            SkXfermode::Coeff uniformCoeff,
    318                            SkXfermode::Coeff colorCoeff,
    319                            const char* inColor) {
    320     GrStringBuilder colorStr, constStr;
    321     blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME,
    322                     inColor, inColor);
    323     blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME,
    324                     inColor, COL_FILTER_UNI_NAME);
    325 
    326     add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
    327 }
    328 
    329 bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
    330 
    331     ShaderCodeSegments segments;
    332     const uint32_t& layout = fProgramDesc.fVertexLayout;
    333 
    334     programData->fUniLocations.reset();
    335 
    336     SkXfermode::Coeff colorCoeff, uniformCoeff;
    337     // The rest of transfer mode color filters have not been implemented
    338     if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
    339         GR_DEBUGCODE(bool success =)
    340             SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode>
    341                                     (fProgramDesc.fColorFilterXfermode),
    342                                     &uniformCoeff, &colorCoeff);
    343         GR_DEBUGASSERT(success);
    344     } else {
    345         colorCoeff = SkXfermode::kOne_Coeff;
    346         uniformCoeff = SkXfermode::kZero_Coeff;
    347     }
    348 
    349     bool needColorFilterUniform;
    350     bool needComputedColor;
    351     needBlendInputs(uniformCoeff, colorCoeff,
    352                     &needColorFilterUniform, &needComputedColor);
    353 
    354     // the dual source output has no canonical var name, have to
    355     // declare an output, which is incompatible with gl_FragColor/gl_FragData.
    356     const char* fsColorOutput;
    357     bool dualSourceOutputWritten = false;
    358     bool usingDeclaredOutputs = ProgramDesc::kNone_DualSrcOutput !=
    359                                 fProgramDesc.fDualSrcOutput;
    360     if (usingDeclaredOutputs) {
    361         GrAssert(0 == segments.fHeader.size());
    362         segments.fHeader.printf("#version 150\n");
    363         fsColorOutput = declared_color_output_name();
    364         segments.fFSOutputs.appendf("out vec4 %s;\n", fsColorOutput);
    365     } else {
    366         fsColorOutput = "gl_FragColor";
    367     }
    368 
    369 #if GR_GL_ATTRIBUTE_MATRICES
    370     segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
    371     programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
    372 #else
    373     segments.fVSUnis  += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
    374     programData->fUniLocations.fViewMatrixUni = kUseUniform;
    375 #endif
    376     segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
    377 
    378     segments.fVSCode.append(
    379         "void main() {\n"
    380             "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
    381             "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
    382 
    383     // incoming color to current stage being processed.
    384     GrStringBuilder inColor;
    385 
    386     if (needComputedColor) {
    387         switch (fProgramDesc.fColorType) {
    388             case ProgramDesc::kAttribute_ColorType:
    389                 segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
    390                 segments.fVaryings.append("varying vec4 vColor;\n");
    391                 segments.fVSCode.append(    "\tvColor = " COL_ATTR_NAME ";\n");
    392                 inColor = "vColor";
    393                 break;
    394             case ProgramDesc::kUniform_ColorType:
    395                 segments.fFSUnis.append(  "uniform vec4 " COL_UNI_NAME ";\n");
    396                 programData->fUniLocations.fColorUni = kUseUniform;
    397                 inColor = COL_UNI_NAME;
    398                 break;
    399             default:
    400                 GrAssert(ProgramDesc::kNone_ColorType == fProgramDesc.fColorType);
    401                 break;
    402         }
    403     }
    404 
    405     if (fProgramDesc.fEmitsPointSize){
    406         segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
    407     }
    408 
    409     segments.fFSCode.append("void main() {\n");
    410 
    411     // add texture coordinates that are used to the list of vertex attr decls
    412     GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
    413     for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
    414         if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
    415             tex_attr_name(t, texCoordAttrs + t);
    416             segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
    417         }
    418     }
    419 
    420     ///////////////////////////////////////////////////////////////////////////
    421     // compute the final color
    422 
    423     // if we have color stages string them together, feeding the output color
    424     // of each to the next and generating code for each stage.
    425     if (needComputedColor) {
    426         GrStringBuilder outColor;
    427         for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
    428             if (fProgramDesc.fStages[s].isEnabled()) {
    429                 // create var to hold stage result
    430                 outColor = "color";
    431                 outColor.appendS32(s);
    432                 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
    433 
    434                 const char* inCoords;
    435                 // figure out what our input coords are
    436                 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
    437                     layout) {
    438                     inCoords = POS_ATTR_NAME;
    439                 } else {
    440                     int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
    441                      // we better have input tex coordinates if stage is enabled.
    442                     GrAssert(tcIdx >= 0);
    443                     GrAssert(texCoordAttrs[tcIdx].size());
    444                     inCoords = texCoordAttrs[tcIdx].c_str();
    445                 }
    446 
    447                 genStageCode(s,
    448                              fProgramDesc.fStages[s],
    449                              inColor.size() ? inColor.c_str() : NULL,
    450                              outColor.c_str(),
    451                              inCoords,
    452                              &segments,
    453                              &programData->fUniLocations.fStages[s]);
    454                 inColor = outColor;
    455             }
    456         }
    457     }
    458 
    459     // if have all ones for the "dst" input to the color filter then we can make
    460     // additional optimizations.
    461     if (needColorFilterUniform && !inColor.size() &&
    462         (SkXfermode::kIDC_Coeff == uniformCoeff ||
    463          SkXfermode::kIDA_Coeff == uniformCoeff)) {
    464           uniformCoeff = SkXfermode::kZero_Coeff;
    465           bool bogus;
    466           needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
    467                           &needColorFilterUniform, &bogus);
    468     }
    469     if (needColorFilterUniform) {
    470         segments.fFSUnis.append(  "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
    471         programData->fUniLocations.fColorFilterUni = kUseUniform;
    472     }
    473 
    474     bool wroteFragColorZero = false;
    475     if (SkXfermode::kZero_Coeff == uniformCoeff &&
    476         SkXfermode::kZero_Coeff == colorCoeff) {
    477         segments.fFSCode.appendf("\t%s = %s;\n",
    478                                  fsColorOutput,
    479                                  all_zeros_vec(4));
    480         wroteFragColorZero = true;
    481     } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
    482         segments.fFSCode.appendf("\tvec4 filteredColor;\n");
    483         const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4);
    484         addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
    485                        colorCoeff, color);
    486         inColor = "filteredColor";
    487     }
    488 
    489     ///////////////////////////////////////////////////////////////////////////
    490     // compute the partial coverage (coverage stages and edge aa)
    491 
    492     GrStringBuilder inCoverage;
    493 
    494     // we don't need to compute coverage at all if we know the final shader
    495     // output will be zero and we don't have a dual src blend output.
    496     if (!wroteFragColorZero ||
    497         ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
    498         if (fProgramDesc.fEdgeAANumEdges > 0) {
    499             segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[");
    500             segments.fFSUnis.appendS32(fProgramDesc.fEdgeAANumEdges);
    501             segments.fFSUnis.append("];\n");
    502             programData->fUniLocations.fEdgesUni = kUseUniform;
    503             int count = fProgramDesc.fEdgeAANumEdges;
    504             segments.fFSCode.append(
    505                 "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n");
    506             for (int i = 0; i < count; i++) {
    507                 segments.fFSCode.append("\tfloat a");
    508                 segments.fFSCode.appendS32(i);
    509                 segments.fFSCode.append(" = clamp(dot(" EDGES_UNI_NAME "[");
    510                 segments.fFSCode.appendS32(i);
    511                 segments.fFSCode.append("], pos), 0.0, 1.0);\n");
    512             }
    513             segments.fFSCode.append("\tfloat edgeAlpha = ");
    514             for (int i = 0; i < count - 1; i++) {
    515                 segments.fFSCode.append("min(a");
    516                 segments.fFSCode.appendS32(i);
    517                 segments.fFSCode.append(" * a");
    518                 segments.fFSCode.appendS32(i + 1);
    519                 segments.fFSCode.append(", ");
    520             }
    521             segments.fFSCode.append("a");
    522             segments.fFSCode.appendS32(count - 1);
    523             segments.fFSCode.append(" * a0");
    524             for (int i = 0; i < count - 1; i++) {
    525                 segments.fFSCode.append(")");
    526             }
    527             segments.fFSCode.append(";\n");
    528             inCoverage = "edgeAlpha";
    529         }
    530 
    531         GrStringBuilder outCoverage;
    532         const int& startStage = fProgramDesc.fFirstCoverageStage;
    533         for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) {
    534             if (fProgramDesc.fStages[s].isEnabled()) {
    535                 // create var to hold stage output
    536                 outCoverage = "coverage";
    537                 outCoverage.appendS32(s);
    538                 segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
    539 
    540                 const char* inCoords;
    541                 // figure out what our input coords are
    542                 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
    543                     inCoords = POS_ATTR_NAME;
    544                 } else {
    545                     int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
    546                         // we better have input tex coordinates if stage is enabled.
    547                     GrAssert(tcIdx >= 0);
    548                     GrAssert(texCoordAttrs[tcIdx].size());
    549                     inCoords = texCoordAttrs[tcIdx].c_str();
    550                 }
    551 
    552                 genStageCode(s,
    553                              fProgramDesc.fStages[s],
    554                              inCoverage.size() ? inCoverage.c_str() : NULL,
    555                              outCoverage.c_str(),
    556                              inCoords,
    557                              &segments,
    558                              &programData->fUniLocations.fStages[s]);
    559                 inCoverage = outCoverage;
    560             }
    561         }
    562         if (ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
    563             segments.fFSOutputs.appendf("out vec4 %s;\n",
    564                                         dual_source_output_name());
    565             bool outputIsZero = false;
    566             GrStringBuilder coeff;
    567             if (ProgramDesc::kCoverage_DualSrcOutput !=
    568                 fProgramDesc.fDualSrcOutput && !wroteFragColorZero) {
    569                 if (!inColor.size()) {
    570                     outputIsZero = true;
    571                 } else {
    572                     if (fProgramDesc.fDualSrcOutput ==
    573                         ProgramDesc::kCoverageISA_DualSrcOutput) {
    574                         coeff.printf("(1 - %s.a)", inColor.c_str());
    575                     } else {
    576                         coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str());
    577                     }
    578                 }
    579             }
    580             if (outputIsZero) {
    581                 segments.fFSCode.appendf("\t%s = %s;\n",
    582                                          dual_source_output_name(),
    583                                          all_zeros_vec(4));
    584             } else {
    585                 modulate_helper(dual_source_output_name(),
    586                                 coeff.c_str(),
    587                                 inCoverage.c_str(),
    588                                 &segments.fFSCode);
    589             }
    590             dualSourceOutputWritten = true;
    591         }
    592     }
    593 
    594     ///////////////////////////////////////////////////////////////////////////
    595     // combine color and coverage as frag color
    596 
    597     if (!wroteFragColorZero) {
    598         modulate_helper(fsColorOutput,
    599                          inColor.c_str(),
    600                          inCoverage.c_str(),
    601                          &segments.fFSCode);
    602     }
    603 
    604     segments.fVSCode.append("}\n");
    605     segments.fFSCode.append("}\n");
    606 
    607     ///////////////////////////////////////////////////////////////////////////
    608     // compile and setup attribs and unis
    609 
    610     if (!CompileFSAndVS(segments, programData)) {
    611         return false;
    612     }
    613 
    614     if (!this->bindOutputsAttribsAndLinkProgram(texCoordAttrs,
    615                                                 usingDeclaredOutputs,
    616                                                 dualSourceOutputWritten,
    617                                                 programData)) {
    618         return false;
    619     }
    620 
    621     this->getUniformLocationsAndInitCache(programData);
    622 
    623     return true;
    624 }
    625 
    626 bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
    627                                  CachedData* programData) {
    628 
    629     static const int MAX_STRINGS = 6;
    630     const char* strings[MAX_STRINGS];
    631     int lengths[MAX_STRINGS];
    632     int stringCnt = 0;
    633 
    634     if (segments.fHeader.size()) {
    635         strings[stringCnt] = segments.fHeader.c_str();
    636         lengths[stringCnt] = segments.fHeader.size();
    637         ++stringCnt;
    638     }
    639     if (segments.fVSUnis.size()) {
    640         strings[stringCnt] = segments.fVSUnis.c_str();
    641         lengths[stringCnt] = segments.fVSUnis.size();
    642         ++stringCnt;
    643     }
    644     if (segments.fVSAttrs.size()) {
    645         strings[stringCnt] = segments.fVSAttrs.c_str();
    646         lengths[stringCnt] = segments.fVSAttrs.size();
    647         ++stringCnt;
    648     }
    649     if (segments.fVaryings.size()) {
    650         strings[stringCnt] = segments.fVaryings.c_str();
    651         lengths[stringCnt] = segments.fVaryings.size();
    652         ++stringCnt;
    653     }
    654 
    655     GrAssert(segments.fVSCode.size());
    656     strings[stringCnt] = segments.fVSCode.c_str();
    657     lengths[stringCnt] = segments.fVSCode.size();
    658     ++stringCnt;
    659 
    660 #if PRINT_SHADERS
    661     GrPrintf(segments.fHeader.c_str());
    662     GrPrintf(segments.fVSUnis.c_str());
    663     GrPrintf(segments.fVSAttrs.c_str());
    664     GrPrintf(segments.fVaryings.c_str());
    665     GrPrintf(segments.fVSCode.c_str());
    666     GrPrintf("\n");
    667 #endif
    668     GrAssert(stringCnt <= MAX_STRINGS);
    669     programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
    670                                         stringCnt,
    671                                         strings,
    672                                         lengths);
    673 
    674     if (!programData->fVShaderID) {
    675         return false;
    676     }
    677 
    678     stringCnt = 0;
    679 
    680     if (segments.fHeader.size()) {
    681         strings[stringCnt] = segments.fHeader.c_str();
    682         lengths[stringCnt] = segments.fHeader.size();
    683         ++stringCnt;
    684     }
    685     if (strlen(GrShaderPrecision()) > 1) {
    686         strings[stringCnt] = GrShaderPrecision();
    687         lengths[stringCnt] = strlen(GrShaderPrecision());
    688         ++stringCnt;
    689     }
    690     if (segments.fFSUnis.size()) {
    691         strings[stringCnt] = segments.fFSUnis.c_str();
    692         lengths[stringCnt] = segments.fFSUnis.size();
    693         ++stringCnt;
    694     }
    695     if (segments.fVaryings.size()) {
    696         strings[stringCnt] = segments.fVaryings.c_str();
    697         lengths[stringCnt] = segments.fVaryings.size();
    698         ++stringCnt;
    699     }
    700     if (segments.fFSOutputs.size()) {
    701         strings[stringCnt] = segments.fFSOutputs.c_str();
    702         lengths[stringCnt] = segments.fFSOutputs.size();
    703         ++stringCnt;
    704     }
    705 
    706     GrAssert(segments.fFSCode.size());
    707     strings[stringCnt] = segments.fFSCode.c_str();
    708     lengths[stringCnt] = segments.fFSCode.size();
    709     ++stringCnt;
    710 
    711 #if PRINT_SHADERS
    712     GrPrintf(segments.fHeader.c_str());
    713     GrPrintf(GrShaderPrecision());
    714     GrPrintf(segments.fFSUnis.c_str());
    715     GrPrintf(segments.fVaryings.c_str());
    716     GrPrintf(segments.fFSOutputs.c_str());
    717     GrPrintf(segments.fFSCode.c_str());
    718     GrPrintf("\n");
    719 #endif
    720     GrAssert(stringCnt <= MAX_STRINGS);
    721     programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
    722                                             stringCnt,
    723                                             strings,
    724                                             lengths);
    725 
    726     if (!programData->fFShaderID) {
    727         return false;
    728     }
    729 
    730     return true;
    731 }
    732 
    733 GrGLuint GrGLProgram::CompileShader(GrGLenum type,
    734                                       int stringCnt,
    735                                       const char** strings,
    736                                       int* stringLengths) {
    737     GrGLuint shader = GR_GL(CreateShader(type));
    738     if (0 == shader) {
    739         return 0;
    740     }
    741 
    742     GrGLint compiled = GR_GL_INIT_ZERO;
    743     GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
    744     GR_GL(CompileShader(shader));
    745     GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
    746 
    747     if (!compiled) {
    748         GrGLint infoLen = GR_GL_INIT_ZERO;
    749         GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
    750         GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
    751         if (infoLen > 0) {
    752             GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
    753             for (int i = 0; i < stringCnt; ++i) {
    754                 if (NULL == stringLengths || stringLengths[i] < 0) {
    755                     GrPrintf(strings[i]);
    756                 } else {
    757                     GrPrintf("%.*s", stringLengths[i], strings[i]);
    758                 }
    759             }
    760             GrPrintf("\n%s", log.get());
    761         }
    762         GrAssert(!"Shader compilation failed!");
    763         GR_GL(DeleteShader(shader));
    764         return 0;
    765     }
    766     return shader;
    767 }
    768 
    769 bool GrGLProgram::bindOutputsAttribsAndLinkProgram(
    770                                         GrStringBuilder texCoordAttrNames[],
    771                                         bool bindColorOut,
    772                                         bool bindDualSrcOut,
    773                                         CachedData* programData) const {
    774     programData->fProgramID = GR_GL(CreateProgram());
    775     if (!programData->fProgramID) {
    776         return false;
    777     }
    778     const GrGLint& progID = programData->fProgramID;
    779 
    780     GR_GL(AttachShader(progID, programData->fVShaderID));
    781     GR_GL(AttachShader(progID, programData->fFShaderID));
    782 
    783     if (bindColorOut) {
    784         GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
    785                                           0, 0, declared_color_output_name()));
    786     }
    787     if (bindDualSrcOut) {
    788         GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
    789                                           0, 1, dual_source_output_name()));
    790     }
    791 
    792     // Bind the attrib locations to same values for all shaders
    793     GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
    794     for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
    795         if (texCoordAttrNames[t].size()) {
    796             GR_GL(BindAttribLocation(progID,
    797                                      TexCoordAttributeIdx(t),
    798                                      texCoordAttrNames[t].c_str()));
    799         }
    800     }
    801 
    802     if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
    803         GR_GL(BindAttribLocation(progID,
    804                              ViewMatrixAttributeIdx(),
    805                              VIEW_MATRIX_NAME));
    806     }
    807 
    808     for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
    809         const StageUniLocations& unis = programData->fUniLocations.fStages[s];
    810         if (kSetAsAttribute == unis.fTextureMatrixUni) {
    811             GrStringBuilder matName;
    812             tex_matrix_name(s, &matName);
    813             GR_GL(BindAttribLocation(progID,
    814                                      TextureMatrixAttributeIdx(s),
    815                                      matName.c_str()));
    816         }
    817     }
    818 
    819     GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
    820 
    821     GR_GL(LinkProgram(progID));
    822 
    823     GrGLint linked = GR_GL_INIT_ZERO;
    824     GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
    825     if (!linked) {
    826         GrGLint infoLen = GR_GL_INIT_ZERO;
    827         GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
    828         GrAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
    829         if (infoLen > 0) {
    830             GR_GL(GetProgramInfoLog(progID,
    831                                     infoLen+1,
    832                                     NULL,
    833                                     (char*)log.get()));
    834             GrPrintf((char*)log.get());
    835         }
    836         GrAssert(!"Error linking program");
    837         GR_GL(DeleteProgram(progID));
    838         programData->fProgramID = 0;
    839         return false;
    840     }
    841     return true;
    842 }
    843 
    844 void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
    845     const GrGLint& progID = programData->fProgramID;
    846 
    847     if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
    848         programData->fUniLocations.fViewMatrixUni =
    849                         GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
    850         GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
    851     }
    852     if (kUseUniform == programData->fUniLocations.fColorUni) {
    853         programData->fUniLocations.fColorUni =
    854                                 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
    855         GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
    856     }
    857     if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
    858         programData->fUniLocations.fColorFilterUni =
    859                         GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
    860         GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
    861     }
    862 
    863     if (kUseUniform == programData->fUniLocations.fEdgesUni) {
    864         programData->fUniLocations.fEdgesUni =
    865             GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
    866         GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
    867     } else {
    868         programData->fUniLocations.fEdgesUni = kUnusedUniform;
    869     }
    870 
    871     for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
    872         StageUniLocations& locations = programData->fUniLocations.fStages[s];
    873         if (fProgramDesc.fStages[s].isEnabled()) {
    874             if (kUseUniform == locations.fTextureMatrixUni) {
    875                 GrStringBuilder texMName;
    876                 tex_matrix_name(s, &texMName);
    877                 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
    878                                                 progID,
    879                                                 texMName.c_str()));
    880                 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
    881             }
    882 
    883             if (kUseUniform == locations.fSamplerUni) {
    884                 GrStringBuilder samplerName;
    885                 sampler_name(s, &samplerName);
    886                 locations.fSamplerUni = GR_GL(GetUniformLocation(
    887                                                      progID,
    888                                                      samplerName.c_str()));
    889                 GrAssert(kUnusedUniform != locations.fSamplerUni);
    890             }
    891 
    892             if (kUseUniform == locations.fNormalizedTexelSizeUni) {
    893                 GrStringBuilder texelSizeName;
    894                 normalized_texel_size_name(s, &texelSizeName);
    895                 locations.fNormalizedTexelSizeUni =
    896                    GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
    897                 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
    898             }
    899 
    900             if (kUseUniform == locations.fRadial2Uni) {
    901                 GrStringBuilder radial2ParamName;
    902                 radial2_param_name(s, &radial2ParamName);
    903                 locations.fRadial2Uni = GR_GL(GetUniformLocation(
    904                                              progID,
    905                                              radial2ParamName.c_str()));
    906                 GrAssert(kUnusedUniform != locations.fRadial2Uni);
    907             }
    908 
    909             if (kUseUniform == locations.fTexDomUni) {
    910                 GrStringBuilder texDomName;
    911                 tex_domain_name(s, &texDomName);
    912                 locations.fTexDomUni = GR_GL(GetUniformLocation(
    913                                              progID,
    914                                              texDomName.c_str()));
    915                 GrAssert(kUnusedUniform != locations.fTexDomUni);
    916             }
    917         }
    918     }
    919     GR_GL(UseProgram(progID));
    920 
    921     // init sampler unis and set bogus values for state tracking
    922     for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
    923         if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
    924             GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
    925         }
    926         programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
    927         programData->fRadial2CenterX1[s] = GR_ScalarMax;
    928         programData->fRadial2Radius0[s] = -GR_ScalarMax;
    929         programData->fTextureWidth[s] = -1;
    930         programData->fTextureHeight[s] = -1;
    931     }
    932     programData->fViewMatrix = GrMatrix::InvalidMatrix();
    933     programData->fColor = GrColor_ILLEGAL;
    934     programData->fColorFilterColor = GrColor_ILLEGAL;
    935 }
    936 
    937 //============================================================================
    938 // Stage code generation
    939 //============================================================================
    940 
    941 void GrGLProgram::genStageCode(int stageNum,
    942                                const GrGLProgram::ProgramDesc::StageDesc& desc,
    943                                const char* fsInColor, // NULL means no incoming color
    944                                const char* fsOutColor,
    945                                const char* vsInCoord,
    946                                ShaderCodeSegments* segments,
    947                                StageUniLocations* locations) const {
    948 
    949     GrAssert(stageNum >= 0 && stageNum <= 9);
    950 
    951     GrStringBuilder varyingName;
    952     stage_varying_name(stageNum, &varyingName);
    953 
    954     // First decide how many coords are needed to access the texture
    955     // Right now it's always 2 but we could start using 1D textures for
    956     // gradients.
    957     static const int coordDims = 2;
    958     int varyingDims;
    959     /// Vertex Shader Stuff
    960 
    961     // decide whether we need a matrix to transform texture coords
    962     // and whether the varying needs a perspective coord.
    963     GrStringBuilder texMName;
    964     tex_matrix_name(stageNum, &texMName);
    965     if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
    966         varyingDims = coordDims;
    967     } else {
    968     #if GR_GL_ATTRIBUTE_MATRICES
    969         segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
    970         locations->fTextureMatrixUni = kSetAsAttribute;
    971     #else
    972         segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
    973         locations->fTextureMatrixUni = kUseUniform;
    974     #endif
    975         if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
    976             varyingDims = coordDims;
    977         } else {
    978             varyingDims = coordDims + 1;
    979         }
    980     }
    981 
    982     GrStringBuilder samplerName;
    983     sampler_name(stageNum, &samplerName);
    984     segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
    985     locations->fSamplerUni = kUseUniform;
    986 
    987     GrStringBuilder texelSizeName;
    988     if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
    989         normalized_texel_size_name(stageNum, &texelSizeName);
    990         segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
    991     }
    992 
    993     segments->fVaryings.appendf("varying %s %s;\n",
    994                                 float_vector_type(varyingDims), varyingName.c_str());
    995 
    996     if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
    997         GrAssert(varyingDims == coordDims);
    998         segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
    999     } else {
   1000         // varying = texMatrix * texCoord
   1001         segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
   1002                                   varyingName.c_str(), texMName.c_str(),
   1003                                   vsInCoord, vector_all_coords(varyingDims));
   1004     }
   1005 
   1006     GrStringBuilder radial2ParamsName;
   1007     radial2_param_name(stageNum, &radial2ParamsName);
   1008     // for radial grads without perspective we can pass the linear
   1009     // part of the quadratic as a varying.
   1010     GrStringBuilder radial2VaryingName;
   1011     radial2_varying_name(stageNum, &radial2VaryingName);
   1012 
   1013     if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
   1014 
   1015         segments->fVSUnis.appendf("uniform %s float %s[6];\n",
   1016                                   GrPrecision(), radial2ParamsName.c_str());
   1017         segments->fFSUnis.appendf("uniform float %s[6];\n",
   1018                                   radial2ParamsName.c_str());
   1019         locations->fRadial2Uni = kUseUniform;
   1020 
   1021         // if there is perspective we don't interpolate this
   1022         if (varyingDims == coordDims) {
   1023             GrAssert(2 == coordDims);
   1024             segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
   1025 
   1026             // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
   1027             segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
   1028                                       radial2VaryingName.c_str(), radial2ParamsName.c_str(),
   1029                                       varyingName.c_str(), radial2ParamsName.c_str());
   1030         }
   1031     }
   1032 
   1033     /// Fragment Shader Stuff
   1034     GrStringBuilder fsCoordName;
   1035     // function used to access the shader, may be made projective
   1036     GrStringBuilder texFunc("texture2D");
   1037     if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
   1038                           ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
   1039         GrAssert(varyingDims == coordDims);
   1040         fsCoordName = varyingName;
   1041     } else {
   1042         // if we have to do some special op on the varyings to get
   1043         // our final tex coords then when in perspective we have to
   1044         // do an explicit divide. Otherwise, we can use a Proj func.
   1045         if  (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
   1046              ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
   1047             texFunc.append("Proj");
   1048             fsCoordName = varyingName;
   1049         } else {
   1050             fsCoordName = "inCoord";
   1051             fsCoordName.appendS32(stageNum);
   1052             segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
   1053                                        float_vector_type(coordDims),
   1054                                        fsCoordName.c_str(),
   1055                                        varyingName.c_str(),
   1056                                        vector_nonhomog_coords(varyingDims),
   1057                                        varyingName.c_str(),
   1058                                        vector_homog_coord(varyingDims));
   1059         }
   1060     }
   1061 
   1062     GrStringBuilder sampleCoords;
   1063     bool complexCoord = false;
   1064     switch (desc.fCoordMapping) {
   1065     case ProgramDesc::StageDesc::kIdentity_CoordMapping:
   1066         sampleCoords = fsCoordName;
   1067         break;
   1068     case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
   1069         sampleCoords.printf("vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)", fsCoordName.c_str(), fsCoordName.c_str());
   1070         complexCoord = true;
   1071         break;
   1072     case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
   1073         sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
   1074         complexCoord = true;
   1075         break;
   1076     case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
   1077         GrStringBuilder cName("c");
   1078         GrStringBuilder ac4Name("ac4");
   1079         GrStringBuilder rootName("root");
   1080 
   1081         cName.appendS32(stageNum);
   1082         ac4Name.appendS32(stageNum);
   1083         rootName.appendS32(stageNum);
   1084 
   1085         // if we were able to interpolate the linear component bVar is the varying
   1086         // otherwise compute it
   1087         GrStringBuilder bVar;
   1088         if (coordDims == varyingDims) {
   1089             bVar = radial2VaryingName;
   1090             GrAssert(2 == varyingDims);
   1091         } else {
   1092             GrAssert(3 == varyingDims);
   1093             bVar = "b";
   1094             bVar.appendS32(stageNum);
   1095             segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
   1096                                         bVar.c_str(), radial2ParamsName.c_str(),
   1097                                         fsCoordName.c_str(), radial2ParamsName.c_str());
   1098         }
   1099 
   1100         // c = (x^2)+(y^2) - params[4]
   1101         segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
   1102                                   cName.c_str(), fsCoordName.c_str(),
   1103                                   fsCoordName.c_str(),
   1104                                   radial2ParamsName.c_str());
   1105         // ac4 = 4.0 * params[0] * c
   1106         segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
   1107                                   ac4Name.c_str(), radial2ParamsName.c_str(),
   1108                                   cName.c_str());
   1109 
   1110         // root = sqrt(b^2-4ac)
   1111         // (abs to avoid exception due to fp precision)
   1112         segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
   1113                                   rootName.c_str(), bVar.c_str(), bVar.c_str(),
   1114                                   ac4Name.c_str());
   1115 
   1116         // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
   1117         // y coord is 0.5 (texture is effectively 1D)
   1118         sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
   1119                             bVar.c_str(), radial2ParamsName.c_str(),
   1120                             rootName.c_str(), radial2ParamsName.c_str());
   1121         complexCoord = true;
   1122         break;}
   1123     };
   1124 
   1125     const char* smear;
   1126     if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
   1127         smear = ".aaaa";
   1128     } else {
   1129         smear = "";
   1130     }
   1131     GrStringBuilder modulate;
   1132     if (NULL != fsInColor) {
   1133         modulate.printf(" * %s", fsInColor);
   1134     }
   1135 
   1136     if (desc.fOptFlags &
   1137         ProgramDesc::StageDesc::kCustomTextureDomain_OptFlagBit) {
   1138         GrStringBuilder texDomainName;
   1139         tex_domain_name(stageNum, &texDomainName);
   1140         segments->fFSUnis.appendf("uniform %s %s;\n",
   1141                                   float_vector_type(4),
   1142                                   texDomainName.c_str());
   1143         GrStringBuilder coordVar("clampCoord");
   1144         segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
   1145                                   float_vector_type(coordDims),
   1146                                   coordVar.c_str(),
   1147                                   sampleCoords.c_str(),
   1148                                   texDomainName.c_str(),
   1149                                   texDomainName.c_str());
   1150         sampleCoords = coordVar;
   1151         locations->fTexDomUni = kUseUniform;
   1152     }
   1153 
   1154     if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
   1155         locations->fNormalizedTexelSizeUni = kUseUniform;
   1156         if (complexCoord) {
   1157             // assign the coord to a var rather than compute 4x.
   1158             GrStringBuilder coordVar("tCoord");
   1159             coordVar.appendS32(stageNum);
   1160             segments->fFSCode.appendf("\t%s %s = %s;\n",
   1161                                       float_vector_type(coordDims),
   1162                                       coordVar.c_str(), sampleCoords.c_str());
   1163             sampleCoords = coordVar;
   1164         }
   1165         GrAssert(2 == coordDims);
   1166         GrStringBuilder accumVar("accum");
   1167         accumVar.appendS32(stageNum);
   1168         segments->fFSCode.appendf("\tvec4 %s  = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
   1169         segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
   1170         segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
   1171         segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
   1172         segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
   1173     } else {
   1174         segments->fFSCode.appendf("\t%s = %s(%s, %s)%s%s;\n", fsOutColor, texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), smear, modulate.c_str());
   1175     }
   1176 }
   1177