• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GrPrecision()27 const char* GrPrecision() {
28     if (GR_GL_SUPPORT_ES2) {
29         return "mediump";
30     } else {
31         return " ";
32     }
33 }
34 
GrShaderPrecision()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 
tex_attr_name(int coordIdx,GrStringBuilder * s)59 static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
60     *s = "aTexCoord";
61     s->appendS32(coordIdx);
62 }
63 
float_vector_type(int count)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 
vector_homog_coord(int count)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 
vector_nonhomog_coords(int count)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 
vector_all_coords(int count)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 
all_ones_vec(int count)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 
all_zeros_vec(int count)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 
declared_color_output_name()102 static inline const char* declared_color_output_name() { return "fsColorOut"; }
dual_source_output_name()103 static inline const char* dual_source_output_name() { return "dualSourceOut"; }
104 
tex_matrix_name(int stage,GrStringBuilder * s)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 
normalized_texel_size_name(int stage,GrStringBuilder * s)114 static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
115     *s = "uTexelSize";
116     s->appendS32(stage);
117 }
118 
sampler_name(int stage,GrStringBuilder * s)119 static void sampler_name(int stage, GrStringBuilder* s) {
120     *s = "uSampler";
121     s->appendS32(stage);
122 }
123 
stage_varying_name(int stage,GrStringBuilder * s)124 static void stage_varying_name(int stage, GrStringBuilder* s) {
125     *s = "vStage";
126     s->appendS32(stage);
127 }
128 
radial2_param_name(int stage,GrStringBuilder * s)129 static void radial2_param_name(int stage, GrStringBuilder* s) {
130     *s = "uRadial2Params";
131     s->appendS32(stage);
132 }
133 
radial2_varying_name(int stage,GrStringBuilder * s)134 static void radial2_varying_name(int stage, GrStringBuilder* s) {
135     *s = "vB";
136     s->appendS32(stage);
137 }
138 
tex_domain_name(int stage,GrStringBuilder * s)139 static void tex_domain_name(int stage, GrStringBuilder* s) {
140     *s = "uTexDom";
141     s->appendS32(stage);
142 }
143 
GrGLProgram()144 GrGLProgram::GrGLProgram() {
145 }
146 
~GrGLProgram()147 GrGLProgram::~GrGLProgram() {
148 }
149 
overrideBlend(GrBlendCoeff * srcCoeff,GrBlendCoeff * dstCoeff) const150 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 
buildKey(GrBinHashKeyBuilder & key) const168 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
modulate_helper(const char * outputVar,const char * var0,const char * var1,GrStringBuilder * code)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
add_helper(const char * outputVar,const char * var0,const char * var1,GrStringBuilder * code)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.
needBlendInputs(SkXfermode::Coeff srcCoeff,SkXfermode::Coeff dstCoeff,bool * needSrcValue,bool * needDstValue)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  */
blendTermString(GrStringBuilder * str,SkXfermode::Coeff coeff,const char * src,const char * dst,const char * value)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  */
addColorFilter(GrStringBuilder * fsCode,const char * outputVar,SkXfermode::Coeff uniformCoeff,SkXfermode::Coeff colorCoeff,const char * inColor)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 
genProgram(GrGLProgram::CachedData * programData) const329 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 
CompileFSAndVS(const ShaderCodeSegments & segments,CachedData * programData)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 
CompileShader(GrGLenum type,int stringCnt,const char ** strings,int * stringLengths)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 
bindOutputsAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],bool bindColorOut,bool bindDualSrcOut,CachedData * programData) const769 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 
getUniformLocationsAndInitCache(CachedData * programData) const844 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 
genStageCode(int stageNum,const GrGLProgram::ProgramDesc::StageDesc & desc,const char * fsInColor,const char * fsOutColor,const char * vsInCoord,ShaderCodeSegments * segments,StageUniLocations * locations) const941 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