blob: 9a9e3c2f91661b72872fa1a3ca848d9f324a6bc6 [file] [log] [blame]
junov@google.comf93e7172011-03-31 21:26:24 +00001/*
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"
junov@google.comf93e7172011-03-31 21:26:24 +000021#include "GrMemory.h"
junov@google.comf93e7172011-03-31 21:26:24 +000022
Scroggo97c88c22011-05-11 14:05:25 +000023#include "SkXfermode.h"
24
junov@google.comf93e7172011-03-31 21:26:24 +000025namespace {
26
27const char* GrPrecision() {
28 if (GR_GL_SUPPORT_ES2) {
29 return "mediump";
30 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +000031 return " ";
junov@google.comf93e7172011-03-31 21:26:24 +000032 }
33}
34
35const char* GrShaderPrecision() {
36 if (GR_GL_SUPPORT_ES2) {
37 return "precision mediump float;\n";
38 } else {
39 return "";
40 }
41}
42
43} // namespace
44
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000045#define PRINT_SHADERS 0
46
bsalomon@google.com4be283f2011-04-19 21:15:09 +000047#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000048 #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"
bsalomon@google.com4be283f2011-04-19 21:15:09 +000055#define COL_UNI_NAME "uColor"
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +000056#define EDGES_UNI_NAME "uEdges"
Scroggo97c88c22011-05-11 14:05:25 +000057#define COL_FILTER_UNI_NAME "uColorFilter"
junov@google.comf93e7172011-03-31 21:26:24 +000058
junov@google.comf93e7172011-03-31 21:26:24 +000059static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
60 *s = "aTexCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +000061 s->appendS32(coordIdx);
junov@google.comf93e7172011-03-31 21:26:24 +000062}
63
64static 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
70static 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
76static 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
82static 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
bsalomon@google.comf2d91552011-05-16 20:56:06 +000088static 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
95static 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
junov@google.comf93e7172011-03-31 21:26:24 +0000102static void tex_matrix_name(int stage, GrStringBuilder* s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000103#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000104 *s = "aTexM";
105#else
106 *s = "uTexM";
107#endif
bsalomon@google.comfc296292011-05-06 13:53:47 +0000108 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000109}
110
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000111static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
112 *s = "uTexelSize";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000113 s->appendS32(stage);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000114}
115
junov@google.comf93e7172011-03-31 21:26:24 +0000116static void sampler_name(int stage, GrStringBuilder* s) {
117 *s = "uSampler";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000118 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000119}
120
121static void stage_varying_name(int stage, GrStringBuilder* s) {
122 *s = "vStage";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000123 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000124}
125
126static void radial2_param_name(int stage, GrStringBuilder* s) {
127 *s = "uRadial2Params";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000128 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000129}
130
131static void radial2_varying_name(int stage, GrStringBuilder* s) {
132 *s = "vB";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000133 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000134}
135
junov@google.com6acc9b32011-05-16 18:32:07 +0000136static void tex_domain_name(int stage, GrStringBuilder* s) {
137 *s = "uTexDom";
138 s->appendS32(stage);
139}
140
junov@google.comf93e7172011-03-31 21:26:24 +0000141GrGLProgram::GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000142}
143
144GrGLProgram::~GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000145}
146
147void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
148 // Add stage configuration to the key
149 key.keyData(reinterpret_cast<const uint8_t*>(&fProgramDesc), sizeof(ProgramDesc));
junov@google.comf93e7172011-03-31 21:26:24 +0000150}
151
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000152// assigns modulation of two vars to an output var
153// if either var is "" then assign to the other var
154// if both are "" then assign all ones
155static inline void modulate_helper(const char* outputVar,
156 const char* var0,
157 const char* var1,
158 GrStringBuilder* code) {
159 GrAssert(NULL != outputVar);
160 GrAssert(NULL != var0);
161 GrAssert(NULL != var1);
162 GrAssert(NULL != code);
163
164 bool has0 = '\0' != *var0;
165 bool has1 = '\0' != *var1;
166
167 if (!has0 && !has1) {
168 code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4));
169 } else if (!has0) {
170 code->appendf("\t%s = %s;\n", outputVar, var1);
171 } else if (!has1) {
172 code->appendf("\t%s = %s;\n", outputVar, var0);
173 } else {
174 code->appendf("\t%s = %s * %s;\n", outputVar, var0, var1);
175 }
176}
177
178// assigns addition of two vars to an output var
179// if either var is "" then assign to the other var
180// if both are "" then assign all zeros
181static inline void add_helper(const char* outputVar,
182 const char* var0,
183 const char* var1,
184 GrStringBuilder* code) {
185 GrAssert(NULL != outputVar);
186 GrAssert(NULL != var0);
187 GrAssert(NULL != var1);
188 GrAssert(NULL != code);
189
190 bool has0 = '\0' != *var0;
191 bool has1 = '\0' != *var1;
192
193 if (!has0 && !has1) {
194 code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4));
195 } else if (!has0) {
196 code->appendf("\t%s = %s;\n", outputVar, var1);
197 } else if (!has1) {
198 code->appendf("\t%s = %s;\n", outputVar, var0);
199 } else {
200 code->appendf("\t%s = %s + %s;\n", outputVar, var0, var1);
201 }
202}
203
204// given two blend coeffecients determine whether the src
205// and/or dst computation can be omitted.
206static inline void needBlendInputs(SkXfermode::Coeff srcCoeff,
207 SkXfermode::Coeff dstCoeff,
208 bool* needSrcValue,
209 bool* needDstValue) {
210 if (SkXfermode::kZero_Coeff == srcCoeff) {
211 switch (dstCoeff) {
212 // these all read the src
213 case SkXfermode::kSC_Coeff:
214 case SkXfermode::kISC_Coeff:
215 case SkXfermode::kSA_Coeff:
216 case SkXfermode::kISA_Coeff:
217 *needSrcValue = true;
218 break;
219 default:
220 *needSrcValue = false;
221 break;
222 }
223 } else {
224 *needSrcValue = true;
225 }
226 if (SkXfermode::kZero_Coeff == dstCoeff) {
227 switch (srcCoeff) {
228 // these all read the dst
229 case SkXfermode::kDC_Coeff:
230 case SkXfermode::kIDC_Coeff:
231 case SkXfermode::kDA_Coeff:
232 case SkXfermode::kIDA_Coeff:
233 *needDstValue = true;
234 break;
235 default:
236 *needDstValue = false;
237 break;
238 }
239 } else {
240 *needDstValue = true;
Scroggo97c88c22011-05-11 14:05:25 +0000241 }
242}
243
244/**
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000245 * Create a blend_coeff * value string to be used in shader code. Sets empty
246 * string if result is trivially zero.
247 */
248static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff,
249 const char* src, const char* dst,
250 const char* value) {
251
252 switch (coeff) {
253 case SkXfermode::kZero_Coeff: /** 0 */
254 *str = "";
255 break;
256 case SkXfermode::kOne_Coeff: /** 1 */
257 *str = value;
258 break;
259 case SkXfermode::kSC_Coeff:
260 str->printf("(%s * %s)", src, value);
261 break;
262 case SkXfermode::kISC_Coeff:
263 str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value);
264 break;
265 case SkXfermode::kDC_Coeff:
266 str->printf("(%s * %s)", dst, value);
267 break;
268 case SkXfermode::kIDC_Coeff:
269 str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value);
270 break;
271 case SkXfermode::kSA_Coeff: /** src alpha */
272 str->printf("(%s.a * %s)", src, value);
273 break;
274 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
275 str->printf("((1.0 - %s.a) * %s)", src, value);
276 break;
277 case SkXfermode::kDA_Coeff: /** dst alpha */
278 str->printf("(%s.a * %s)", dst, value);
279 break;
280 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
281 str->printf("((1.0 - %s.a) * %s)", dst, value);
282 break;
283 default:
284 GrCrash("Unexpected xfer coeff.");
285 break;
286 }
287}
288/**
Scroggo97c88c22011-05-11 14:05:25 +0000289 * Adds a line to the fragment shader code which modifies the color by
290 * the specified color filter.
291 */
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000292static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar,
293 SkXfermode::Coeff uniformCoeff,
294 SkXfermode::Coeff colorCoeff,
295 const char* inColor) {
296 GrStringBuilder colorStr, constStr;
297 blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME,
298 inColor, inColor);
299 blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME,
300 inColor, COL_FILTER_UNI_NAME);
301
302 add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
Scroggo97c88c22011-05-11 14:05:25 +0000303}
304
bsalomon@google.com91961302011-05-09 18:39:58 +0000305bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000306
307 ShaderCodeSegments segments;
308 const uint32_t& layout = fProgramDesc.fVertexLayout;
309
bsalomon@google.com91961302011-05-09 18:39:58 +0000310 programData->fUniLocations.reset();
junov@google.comf93e7172011-03-31 21:26:24 +0000311
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000312 SkXfermode::Coeff colorCoeff, uniformCoeff;
313 // The rest of transfer mode color filters have not been implemented
314 if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
315 GR_DEBUGCODE(bool success =)
316 SkXfermode::ModeAsCoeff(fProgramDesc.fColorFilterXfermode, &uniformCoeff, &colorCoeff);
317 GR_DEBUGASSERT(success);
318 } else {
319 colorCoeff = SkXfermode::kOne_Coeff;
320 uniformCoeff = SkXfermode::kZero_Coeff;
321 }
322
323 bool needColorFilterUniform;
324 bool needComputedColor;
325 needBlendInputs(uniformCoeff, colorCoeff,
326 &needColorFilterUniform, &needComputedColor);
327
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000328#if GR_GL_ATTRIBUTE_MATRICES
329 segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000330 programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000331#else
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000332 segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000333 programData->fUniLocations.fViewMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000334#endif
335 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000336
bsalomon@google.com91961302011-05-09 18:39:58 +0000337 segments.fVSCode.append(
338 "void main() {\n"
339 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
340 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000341
bsalomon@google.com91961302011-05-09 18:39:58 +0000342 // incoming color to current stage being processed.
343 GrStringBuilder inColor;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000344
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000345 if (needComputedColor) {
346 switch (fProgramDesc.fColorType) {
347 case ProgramDesc::kAttribute_ColorType:
348 segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
349 segments.fVaryings.append("varying vec4 vColor;\n");
350 segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
351 inColor = "vColor";
352 break;
353 case ProgramDesc::kUniform_ColorType:
354 segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
355 programData->fUniLocations.fColorUni = kUseUniform;
356 inColor = COL_UNI_NAME;
357 break;
358 default:
359 GrAssert(ProgramDesc::kNone_ColorType == fProgramDesc.fColorType);
360 break;
361 }
junov@google.comf93e7172011-03-31 21:26:24 +0000362 }
363
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000364 if (fProgramDesc.fEmitsPointSize){
bsalomon@google.com91961302011-05-09 18:39:58 +0000365 segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000366 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000367
bsalomon@google.com91961302011-05-09 18:39:58 +0000368 segments.fFSCode.append("void main() {\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000369
370 // add texture coordinates that are used to the list of vertex attr decls
bsalomon@google.com91961302011-05-09 18:39:58 +0000371 GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
junov@google.comf93e7172011-03-31 21:26:24 +0000372 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000373 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000374 tex_attr_name(t, texCoordAttrs + t);
bsalomon@google.com91961302011-05-09 18:39:58 +0000375 segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000376 }
377 }
378
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000379 ///////////////////////////////////////////////////////////////////////////
380 // compute the final color
Scroggo97c88c22011-05-11 14:05:25 +0000381
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000382 // if we have color stages string them together, feeding the output color
383 // of each to the next and generating code for each stage.
384 if (needComputedColor) {
385 GrStringBuilder outColor;
386 for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
Scroggo97c88c22011-05-11 14:05:25 +0000387 if (fProgramDesc.fStages[s].fEnabled) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000388 // create var to hold stage result
389 outColor = "color";
390 outColor.appendS32(s);
391 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
392
393 const char* inCoords;
394 // figure out what our input coords are
395 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
396 layout) {
397 inCoords = POS_ATTR_NAME;
Scroggo97c88c22011-05-11 14:05:25 +0000398 } else {
399 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
400 // we better have input tex coordinates if stage is enabled.
401 GrAssert(tcIdx >= 0);
402 GrAssert(texCoordAttrs[tcIdx].size());
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000403 inCoords = texCoordAttrs[tcIdx].c_str();
junov@google.comf93e7172011-03-31 21:26:24 +0000404 }
405
406 genStageCode(s,
407 fProgramDesc.fStages[s],
bsalomon@google.comfc296292011-05-06 13:53:47 +0000408 inColor.size() ? inColor.c_str() : NULL,
409 outColor.c_str(),
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000410 inCoords,
junov@google.comf93e7172011-03-31 21:26:24 +0000411 &segments,
412 &programData->fUniLocations.fStages[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000413 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000414 }
415 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000416 }
Scroggo97c88c22011-05-11 14:05:25 +0000417
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000418 // if have all ones for the "dst" input to the color filter then we can make
419 // additional optimizations.
420 if (needColorFilterUniform && !inColor.size() &&
421 (SkXfermode::kIDC_Coeff == uniformCoeff ||
422 SkXfermode::kIDA_Coeff == uniformCoeff)) {
423 uniformCoeff = SkXfermode::kZero_Coeff;
424 bool bogus;
425 needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
426 &needColorFilterUniform, &bogus);
427 }
428 if (needColorFilterUniform) {
429 segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
430 programData->fUniLocations.fColorFilterUni = kUseUniform;
431 }
432
433 bool wroteFragColorZero = false;
434 if (SkXfermode::kZero_Coeff == uniformCoeff &&
435 SkXfermode::kZero_Coeff == colorCoeff) {
436 segments.fFSCode.appendf("\tgl_FragColor = %s;\n", all_zeros_vec(4));
437 wroteFragColorZero = true;
438 } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
439 segments.fFSCode.appendf("\tvec4 filteredColor;\n");
440 const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4);
441 addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
442 colorCoeff, color);
443 inColor = "filteredColor";
444 }
445
446 ///////////////////////////////////////////////////////////////////////////
447 // compute the partial coverage (coverage stages and edge aa)
448
449 GrStringBuilder inCoverage;
450 bool coverageIsScalar = false;
451
452 // we will want to compute coverage for some blend when there is no
453 // color (when dual source blending is enabled). But for now we have this if
454 if (!wroteFragColorZero) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000455 if (fProgramDesc.fEdgeAANumEdges > 0) {
456 segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[");
457 segments.fFSUnis.appendS32(fProgramDesc.fEdgeAANumEdges);
458 segments.fFSUnis.append("];\n");
459 programData->fUniLocations.fEdgesUni = kUseUniform;
460 int count = fProgramDesc.fEdgeAANumEdges;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000461 segments.fFSCode.append(
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000462 "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n");
463 for (int i = 0; i < count; i++) {
464 segments.fFSCode.append("\tfloat a");
465 segments.fFSCode.appendS32(i);
466 segments.fFSCode.append(" = clamp(dot(" EDGES_UNI_NAME "[");
467 segments.fFSCode.appendS32(i);
468 segments.fFSCode.append("], pos), 0.0, 1.0);\n");
469 }
470 segments.fFSCode.append("\tfloat edgeAlpha = ");
471 for (int i = 0; i < count - 1; i++) {
472 segments.fFSCode.append("min(a");
473 segments.fFSCode.appendS32(i);
474 segments.fFSCode.append(" * a");
475 segments.fFSCode.appendS32(i + 1);
476 segments.fFSCode.append(", ");
477 }
478 segments.fFSCode.append("a");
479 segments.fFSCode.appendS32(count - 1);
480 segments.fFSCode.append(" * a0");
481 for (int i = 0; i < count - 1; i++) {
482 segments.fFSCode.append(")");
483 }
484 segments.fFSCode.append(";\n");
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000485 inCoverage = "edgeAlpha";
486 coverageIsScalar = true;
487 }
488
489 GrStringBuilder outCoverage;
490 const int& startStage = fProgramDesc.fFirstCoverageStage;
491 for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) {
492 if (fProgramDesc.fStages[s].fEnabled) {
493
494 // create var to hold stage output
495 outCoverage = "coverage";
496 outCoverage.appendS32(s);
497 segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
498
499 const char* inCoords;
500 // figure out what our input coords are
501 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
502 inCoords = POS_ATTR_NAME;
503 } else {
504 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
505 // we better have input tex coordinates if stage is enabled.
506 GrAssert(tcIdx >= 0);
507 GrAssert(texCoordAttrs[tcIdx].size());
508 inCoords = texCoordAttrs[tcIdx].c_str();
509 }
510
511 genStageCode(s,
512 fProgramDesc.fStages[s],
513 inCoverage.size() ? inCoverage.c_str() : NULL,
514 outCoverage.c_str(),
515 inCoords,
516 &segments,
517 &programData->fUniLocations.fStages[s]);
518 inCoverage = outCoverage;
519 coverageIsScalar = false;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000520 }
521 }
junov@google.comf93e7172011-03-31 21:26:24 +0000522 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000523
524 // TODO: ADD dual source blend output based on coverage here
525
526 ///////////////////////////////////////////////////////////////////////////
527 // combine color and coverage as frag color
528
529 if (!wroteFragColorZero) {
530 if (coverageIsScalar && !inColor.size()) {
531 GrStringBuilder oldCoverage = inCoverage;
532 inCoverage.swap(oldCoverage);
533 inCoverage.printf("vec4(%s,%s,%s,%s)", oldCoverage.c_str(),
534 oldCoverage.c_str(), oldCoverage.c_str(),
535 oldCoverage.c_str());
536 }
537 modulate_helper("gl_FragColor", inColor.c_str(),
538 inCoverage.c_str(), &segments.fFSCode);
539 }
540
bsalomon@google.com91961302011-05-09 18:39:58 +0000541 segments.fVSCode.append("}\n");
542 segments.fFSCode.append("}\n");
543
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000544 ///////////////////////////////////////////////////////////////////////////
545 // compile and setup attribs and unis
546
bsalomon@google.com91961302011-05-09 18:39:58 +0000547 if (!CompileFSAndVS(segments, programData)) {
548 return false;
549 }
550
551 if (!this->bindAttribsAndLinkProgram(texCoordAttrs, programData)) {
552 return false;
553 }
554
555 this->getUniformLocationsAndInitCache(programData);
556
557 return true;
558}
559
560bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
561 CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000562
junov@google.comf93e7172011-03-31 21:26:24 +0000563 const char* strings[4];
564 int lengths[4];
565 int stringCnt = 0;
566
bsalomon@google.comfc296292011-05-06 13:53:47 +0000567 if (segments.fVSUnis.size()) {
568 strings[stringCnt] = segments.fVSUnis.c_str();
569 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000570 ++stringCnt;
571 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000572 if (segments.fVSAttrs.size()) {
573 strings[stringCnt] = segments.fVSAttrs.c_str();
574 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000575 ++stringCnt;
576 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000577 if (segments.fVaryings.size()) {
578 strings[stringCnt] = segments.fVaryings.c_str();
579 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000580 ++stringCnt;
581 }
582
bsalomon@google.comfc296292011-05-06 13:53:47 +0000583 GrAssert(segments.fVSCode.size());
584 strings[stringCnt] = segments.fVSCode.c_str();
585 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000586 ++stringCnt;
587
588#if PRINT_SHADERS
bsalomon@google.comfc296292011-05-06 13:53:47 +0000589 GrPrintf(segments.fVSUnis.c_str());
590 GrPrintf(segments.fVSAttrs.c_str());
591 GrPrintf(segments.fVaryings.c_str());
592 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000593 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000594#endif
595 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
596 stringCnt,
597 strings,
598 lengths);
599
bsalomon@google.com91961302011-05-09 18:39:58 +0000600 if (!programData->fVShaderID) {
601 return false;
602 }
603
junov@google.comf93e7172011-03-31 21:26:24 +0000604 stringCnt = 0;
605
606 if (strlen(GrShaderPrecision()) > 1) {
607 strings[stringCnt] = GrShaderPrecision();
608 lengths[stringCnt] = strlen(GrShaderPrecision());
609 ++stringCnt;
610 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000611 if (segments.fFSUnis.size()) {
612 strings[stringCnt] = segments.fFSUnis.c_str();
613 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000614 ++stringCnt;
615 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000616 if (segments.fVaryings.size()) {
617 strings[stringCnt] = segments.fVaryings.c_str();
618 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000619 ++stringCnt;
620 }
621
bsalomon@google.comfc296292011-05-06 13:53:47 +0000622 GrAssert(segments.fFSCode.size());
623 strings[stringCnt] = segments.fFSCode.c_str();
624 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000625 ++stringCnt;
626
627#if PRINT_SHADERS
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000628 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000629 GrPrintf(segments.fFSUnis.c_str());
630 GrPrintf(segments.fVaryings.c_str());
631 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000632 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000633#endif
634 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
635 stringCnt,
636 strings,
637 lengths);
638
bsalomon@google.com91961302011-05-09 18:39:58 +0000639 if (!programData->fFShaderID) {
640 return false;
junov@google.comf93e7172011-03-31 21:26:24 +0000641 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000642 return true;
junov@google.comf93e7172011-03-31 21:26:24 +0000643}
644
645GrGLuint GrGLProgram::CompileShader(GrGLenum type,
646 int stringCnt,
647 const char** strings,
648 int* stringLengths) {
649 GrGLuint shader = GR_GL(CreateShader(type));
650 if (0 == shader) {
651 return 0;
652 }
653
654 GrGLint compiled = GR_GL_INIT_ZERO;
655 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
656 GR_GL(CompileShader(shader));
657 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
658
659 if (!compiled) {
660 GrGLint infoLen = GR_GL_INIT_ZERO;
661 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
662 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
663 if (infoLen > 0) {
664 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
665 for (int i = 0; i < stringCnt; ++i) {
666 if (NULL == stringLengths || stringLengths[i] < 0) {
667 GrPrintf(strings[i]);
668 } else {
669 GrPrintf("%.*s", stringLengths[i], strings[i]);
670 }
671 }
672 GrPrintf("\n%s", log.get());
673 }
674 GrAssert(!"Shader compilation failed!");
675 GR_GL(DeleteShader(shader));
676 return 0;
677 }
678 return shader;
679}
680
bsalomon@google.com91961302011-05-09 18:39:58 +0000681bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
682 CachedData* programData) const {
683 programData->fProgramID = GR_GL(CreateProgram());
684 if (!programData->fProgramID) {
685 return false;
686 }
687 const GrGLint& progID = programData->fProgramID;
688
689 GR_GL(AttachShader(progID, programData->fVShaderID));
690 GR_GL(AttachShader(progID, programData->fFShaderID));
691
692 // Bind the attrib locations to same values for all shaders
693 GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
694 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
695 if (texCoordAttrNames[t].size()) {
696 GR_GL(BindAttribLocation(progID,
697 TexCoordAttributeIdx(t),
698 texCoordAttrNames[t].c_str()));
699 }
700 }
701
702
703 if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
704 GR_GL(BindAttribLocation(progID,
705 ViewMatrixAttributeIdx(),
706 VIEW_MATRIX_NAME));
707 }
708
709 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
bsalomon@google.com72b4fcb2011-05-09 20:47:34 +0000710 const StageUniLocations& unis = programData->fUniLocations.fStages[s];
711 if (kSetAsAttribute == unis.fTextureMatrixUni) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000712 GrStringBuilder matName;
713 tex_matrix_name(s, &matName);
714 GR_GL(BindAttribLocation(progID,
715 TextureMatrixAttributeIdx(s),
716 matName.c_str()));
717 }
718 }
719
bsalomon@google.com91961302011-05-09 18:39:58 +0000720 GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
721
722 GR_GL(LinkProgram(progID));
723
724 GrGLint linked = GR_GL_INIT_ZERO;
725 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
726 if (!linked) {
727 GrGLint infoLen = GR_GL_INIT_ZERO;
728 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
729 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
730 if (infoLen > 0) {
731 GR_GL(GetProgramInfoLog(progID,
732 infoLen+1,
733 NULL,
734 (char*)log.get()));
735 GrPrintf((char*)log.get());
736 }
737 GrAssert(!"Error linking program");
738 GR_GL(DeleteProgram(progID));
739 programData->fProgramID = 0;
740 return false;
741 }
742 return true;
743}
744
745void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
746 const GrGLint& progID = programData->fProgramID;
747
748 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
749 programData->fUniLocations.fViewMatrixUni =
750 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
751 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
752 }
753 if (kUseUniform == programData->fUniLocations.fColorUni) {
754 programData->fUniLocations.fColorUni =
755 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
756 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
757 }
Scroggo97c88c22011-05-11 14:05:25 +0000758 if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
759 programData->fUniLocations.fColorFilterUni =
760 GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
761 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
762 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000763
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000764 if (kUseUniform == programData->fUniLocations.fEdgesUni) {
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000765 programData->fUniLocations.fEdgesUni =
766 GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
767 GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
768 } else {
769 programData->fUniLocations.fEdgesUni = kUnusedUniform;
770 }
771
bsalomon@google.com91961302011-05-09 18:39:58 +0000772 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
773 StageUniLocations& locations = programData->fUniLocations.fStages[s];
774 if (fProgramDesc.fStages[s].fEnabled) {
775 if (kUseUniform == locations.fTextureMatrixUni) {
776 GrStringBuilder texMName;
777 tex_matrix_name(s, &texMName);
778 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
779 progID,
780 texMName.c_str()));
781 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
782 }
783
784 if (kUseUniform == locations.fSamplerUni) {
785 GrStringBuilder samplerName;
786 sampler_name(s, &samplerName);
787 locations.fSamplerUni = GR_GL(GetUniformLocation(
788 progID,
789 samplerName.c_str()));
790 GrAssert(kUnusedUniform != locations.fSamplerUni);
791 }
792
793 if (kUseUniform == locations.fNormalizedTexelSizeUni) {
794 GrStringBuilder texelSizeName;
795 normalized_texel_size_name(s, &texelSizeName);
796 locations.fNormalizedTexelSizeUni =
797 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
798 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
799 }
800
801 if (kUseUniform == locations.fRadial2Uni) {
802 GrStringBuilder radial2ParamName;
803 radial2_param_name(s, &radial2ParamName);
804 locations.fRadial2Uni = GR_GL(GetUniformLocation(
805 progID,
806 radial2ParamName.c_str()));
807 GrAssert(kUnusedUniform != locations.fRadial2Uni);
808 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000809
810 if (kUseUniform == locations.fTexDomUni) {
811 GrStringBuilder texDomName;
812 tex_domain_name(s, &texDomName);
813 locations.fTexDomUni = GR_GL(GetUniformLocation(
814 progID,
815 texDomName.c_str()));
816 GrAssert(kUnusedUniform != locations.fTexDomUni);
817 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000818 }
819 }
820 GR_GL(UseProgram(progID));
821
822 // init sampler unis and set bogus values for state tracking
823 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
824 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
825 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
826 }
827 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
828 programData->fRadial2CenterX1[s] = GR_ScalarMax;
829 programData->fRadial2Radius0[s] = -GR_ScalarMax;
830 programData->fTextureWidth[s] = -1;
831 programData->fTextureHeight[s] = -1;
832 }
833 programData->fViewMatrix = GrMatrix::InvalidMatrix();
834 programData->fColor = GrColor_ILLEGAL;
Scroggo97c88c22011-05-11 14:05:25 +0000835 programData->fColorFilterColor = GrColor_ILLEGAL;
bsalomon@google.com91961302011-05-09 18:39:58 +0000836}
837
junov@google.comf93e7172011-03-31 21:26:24 +0000838//============================================================================
839// Stage code generation
840//============================================================================
841
842void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000843 const GrGLProgram::ProgramDesc::StageDesc& desc,
844 const char* fsInColor, // NULL means no incoming color
845 const char* fsOutColor,
846 const char* vsInCoord,
847 ShaderCodeSegments* segments,
848 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000849
850 GrAssert(stageNum >= 0 && stageNum <= 9);
851
bsalomon@google.com91961302011-05-09 18:39:58 +0000852 GrStringBuilder varyingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000853 stage_varying_name(stageNum, &varyingName);
854
855 // First decide how many coords are needed to access the texture
856 // Right now it's always 2 but we could start using 1D textures for
857 // gradients.
858 static const int coordDims = 2;
859 int varyingDims;
860 /// Vertex Shader Stuff
861
862 // decide whether we need a matrix to transform texture coords
863 // and whether the varying needs a perspective coord.
bsalomon@google.com91961302011-05-09 18:39:58 +0000864 GrStringBuilder texMName;
junov@google.comf93e7172011-03-31 21:26:24 +0000865 tex_matrix_name(stageNum, &texMName);
866 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
867 varyingDims = coordDims;
868 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000869 #if GR_GL_ATTRIBUTE_MATRICES
bsalomon@google.com91961302011-05-09 18:39:58 +0000870 segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
871 locations->fTextureMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000872 #else
bsalomon@google.com91961302011-05-09 18:39:58 +0000873 segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
874 locations->fTextureMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000875 #endif
876 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
877 varyingDims = coordDims;
878 } else {
879 varyingDims = coordDims + 1;
880 }
881 }
882
bsalomon@google.com91961302011-05-09 18:39:58 +0000883 GrStringBuilder samplerName;
junov@google.comf93e7172011-03-31 21:26:24 +0000884 sampler_name(stageNum, &samplerName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000885 segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
886 locations->fSamplerUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000887
bsalomon@google.com91961302011-05-09 18:39:58 +0000888 GrStringBuilder texelSizeName;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000889 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
890 normalized_texel_size_name(stageNum, &texelSizeName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000891 segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000892 }
893
bsalomon@google.com91961302011-05-09 18:39:58 +0000894 segments->fVaryings.appendf("varying %s %s;\n",
895 float_vector_type(varyingDims), varyingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000896
897 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
898 GrAssert(varyingDims == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000899 segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
junov@google.comf93e7172011-03-31 21:26:24 +0000900 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000901 // varying = texMatrix * texCoord
902 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
903 varyingName.c_str(), texMName.c_str(),
904 vsInCoord, vector_all_coords(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000905 }
906
bsalomon@google.com91961302011-05-09 18:39:58 +0000907 GrStringBuilder radial2ParamsName;
junov@google.comf93e7172011-03-31 21:26:24 +0000908 radial2_param_name(stageNum, &radial2ParamsName);
909 // for radial grads without perspective we can pass the linear
910 // part of the quadratic as a varying.
bsalomon@google.com91961302011-05-09 18:39:58 +0000911 GrStringBuilder radial2VaryingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000912 radial2_varying_name(stageNum, &radial2VaryingName);
913
914 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
915
bsalomon@google.comdcf1b0b2011-05-11 19:00:54 +0000916 segments->fVSUnis.appendf("uniform %s float %s[6];\n",
bsalomon@google.com91961302011-05-09 18:39:58 +0000917 GrPrecision(), radial2ParamsName.c_str());
918 segments->fFSUnis.appendf("uniform float %s[6];\n",
919 radial2ParamsName.c_str());
920 locations->fRadial2Uni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000921
922 // if there is perspective we don't interpolate this
923 if (varyingDims == coordDims) {
924 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000925 segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000926
bsalomon@google.com91961302011-05-09 18:39:58 +0000927 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
928 segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
929 radial2VaryingName.c_str(), radial2ParamsName.c_str(),
930 varyingName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000931 }
932 }
933
934 /// Fragment Shader Stuff
bsalomon@google.com91961302011-05-09 18:39:58 +0000935 GrStringBuilder fsCoordName;
junov@google.comf93e7172011-03-31 21:26:24 +0000936 // function used to access the shader, may be made projective
bsalomon@google.com91961302011-05-09 18:39:58 +0000937 GrStringBuilder texFunc("texture2D");
junov@google.comf93e7172011-03-31 21:26:24 +0000938 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
939 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
940 GrAssert(varyingDims == coordDims);
941 fsCoordName = varyingName;
942 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000943 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +0000944 // our final tex coords then when in perspective we have to
bsalomon@google.com91961302011-05-09 18:39:58 +0000945 // do an explicit divide. Otherwise, we can use a Proj func.
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000946 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
947 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000948 texFunc.append("Proj");
junov@google.comf93e7172011-03-31 21:26:24 +0000949 fsCoordName = varyingName;
950 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000951 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000952 fsCoordName.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000953 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
954 float_vector_type(coordDims),
955 fsCoordName.c_str(),
956 varyingName.c_str(),
957 vector_nonhomog_coords(varyingDims),
958 varyingName.c_str(),
959 vector_homog_coord(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000960 }
961 }
962
bsalomon@google.comfc296292011-05-06 13:53:47 +0000963 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000964 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +0000965 switch (desc.fCoordMapping) {
966 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
967 sampleCoords = fsCoordName;
968 break;
969 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000970 sampleCoords.printf("vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)", fsCoordName.c_str(), fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000971 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000972 break;
973 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000974 sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000975 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000976 break;
977 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.com91961302011-05-09 18:39:58 +0000978 GrStringBuilder cName("c");
979 GrStringBuilder ac4Name("ac4");
980 GrStringBuilder rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +0000981
bsalomon@google.comfc296292011-05-06 13:53:47 +0000982 cName.appendS32(stageNum);
983 ac4Name.appendS32(stageNum);
984 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +0000985
bsalomon@google.com91961302011-05-09 18:39:58 +0000986 // if we were able to interpolate the linear component bVar is the varying
987 // otherwise compute it
988 GrStringBuilder bVar;
junov@google.comf93e7172011-03-31 21:26:24 +0000989 if (coordDims == varyingDims) {
990 bVar = radial2VaryingName;
991 GrAssert(2 == varyingDims);
992 } else {
993 GrAssert(3 == varyingDims);
994 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000995 bVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000996 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
997 bVar.c_str(), radial2ParamsName.c_str(),
998 fsCoordName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000999 }
1000
bsalomon@google.com91961302011-05-09 18:39:58 +00001001 // c = (x^2)+(y^2) - params[4]
1002 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
1003 cName.c_str(), fsCoordName.c_str(),
1004 fsCoordName.c_str(),
1005 radial2ParamsName.c_str());
1006 // ac4 = 4.0 * params[0] * c
1007 segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
1008 ac4Name.c_str(), radial2ParamsName.c_str(),
1009 cName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001010
bsalomon@google.com91961302011-05-09 18:39:58 +00001011 // root = sqrt(b^2-4ac)
1012 // (abs to avoid exception due to fp precision)
1013 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
1014 rootName.c_str(), bVar.c_str(), bVar.c_str(),
1015 ac4Name.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001016
bsalomon@google.com91961302011-05-09 18:39:58 +00001017 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
1018 // y coord is 0.5 (texture is effectively 1D)
1019 sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
1020 bVar.c_str(), radial2ParamsName.c_str(),
1021 rootName.c_str(), radial2ParamsName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001022 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001023 break;}
1024 };
1025
bsalomon@google.com91961302011-05-09 18:39:58 +00001026 const char* smear;
1027 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
1028 smear = ".aaaa";
1029 } else {
1030 smear = "";
1031 }
1032 GrStringBuilder modulate;
1033 if (NULL != fsInColor) {
1034 modulate.printf(" * %s", fsInColor);
1035 }
1036
junov@google.com6acc9b32011-05-16 18:32:07 +00001037 if (desc.fOptFlags &
1038 ProgramDesc::StageDesc::kCustomTextureDomain_OptFlagBit) {
1039 GrStringBuilder texDomainName;
1040 tex_domain_name(stageNum, &texDomainName);
1041 segments->fFSUnis.appendf("uniform %s %s;\n",
1042 float_vector_type(4),
1043 texDomainName.c_str());
1044 GrStringBuilder coordVar("clampCoord");
1045 segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
1046 float_vector_type(coordDims),
1047 coordVar.c_str(),
1048 sampleCoords.c_str(),
1049 texDomainName.c_str(),
1050 texDomainName.c_str());
1051 sampleCoords = coordVar;
1052 locations->fTexDomUni = kUseUniform;
1053 }
1054
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001055 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001056 locations->fNormalizedTexelSizeUni = kUseUniform;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001057 if (complexCoord) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001058 // assign the coord to a var rather than compute 4x.
1059 GrStringBuilder coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +00001060 coordVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001061 segments->fFSCode.appendf("\t%s %s = %s;\n",
1062 float_vector_type(coordDims),
1063 coordVar.c_str(), sampleCoords.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001064 sampleCoords = coordVar;
1065 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001066 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +00001067 GrStringBuilder accumVar("accum");
1068 accumVar.appendS32(stageNum);
1069 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);
1070 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);
1071 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);
1072 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);
1073 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001074 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +00001075 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());
junov@google.comf93e7172011-03-31 21:26:24 +00001076 }
junov@google.comf93e7172011-03-31 21:26:24 +00001077}
1078