blob: 01a39b94016485d52df7ef0e3939821f2092116d [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
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000364 if (fProgramDesc.fUsesEdgeAA) {
365 segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[6];\n");
366 }
367
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000368 if (fProgramDesc.fEmitsPointSize){
bsalomon@google.com91961302011-05-09 18:39:58 +0000369 segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000370 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000371
bsalomon@google.com91961302011-05-09 18:39:58 +0000372 segments.fFSCode.append("void main() {\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000373
374 // add texture coordinates that are used to the list of vertex attr decls
bsalomon@google.com91961302011-05-09 18:39:58 +0000375 GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
junov@google.comf93e7172011-03-31 21:26:24 +0000376 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000377 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000378 tex_attr_name(t, texCoordAttrs + t);
bsalomon@google.com91961302011-05-09 18:39:58 +0000379 segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000380 }
381 }
382
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000383 ///////////////////////////////////////////////////////////////////////////
384 // compute the final color
Scroggo97c88c22011-05-11 14:05:25 +0000385
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000386 // if we have color stages string them together, feeding the output color
387 // of each to the next and generating code for each stage.
388 if (needComputedColor) {
389 GrStringBuilder outColor;
390 for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
Scroggo97c88c22011-05-11 14:05:25 +0000391 if (fProgramDesc.fStages[s].fEnabled) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000392 // create var to hold stage result
393 outColor = "color";
394 outColor.appendS32(s);
395 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
396
397 const char* inCoords;
398 // figure out what our input coords are
399 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
400 layout) {
401 inCoords = POS_ATTR_NAME;
Scroggo97c88c22011-05-11 14:05:25 +0000402 } else {
403 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
404 // we better have input tex coordinates if stage is enabled.
405 GrAssert(tcIdx >= 0);
406 GrAssert(texCoordAttrs[tcIdx].size());
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000407 inCoords = texCoordAttrs[tcIdx].c_str();
junov@google.comf93e7172011-03-31 21:26:24 +0000408 }
409
410 genStageCode(s,
411 fProgramDesc.fStages[s],
bsalomon@google.comfc296292011-05-06 13:53:47 +0000412 inColor.size() ? inColor.c_str() : NULL,
413 outColor.c_str(),
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000414 inCoords,
junov@google.comf93e7172011-03-31 21:26:24 +0000415 &segments,
416 &programData->fUniLocations.fStages[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000417 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000418 }
419 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000420 }
Scroggo97c88c22011-05-11 14:05:25 +0000421
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000422 // if have all ones for the "dst" input to the color filter then we can make
423 // additional optimizations.
424 if (needColorFilterUniform && !inColor.size() &&
425 (SkXfermode::kIDC_Coeff == uniformCoeff ||
426 SkXfermode::kIDA_Coeff == uniformCoeff)) {
427 uniformCoeff = SkXfermode::kZero_Coeff;
428 bool bogus;
429 needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
430 &needColorFilterUniform, &bogus);
431 }
432 if (needColorFilterUniform) {
433 segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
434 programData->fUniLocations.fColorFilterUni = kUseUniform;
435 }
436
437 bool wroteFragColorZero = false;
438 if (SkXfermode::kZero_Coeff == uniformCoeff &&
439 SkXfermode::kZero_Coeff == colorCoeff) {
440 segments.fFSCode.appendf("\tgl_FragColor = %s;\n", all_zeros_vec(4));
441 wroteFragColorZero = true;
442 } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
443 segments.fFSCode.appendf("\tvec4 filteredColor;\n");
444 const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4);
445 addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
446 colorCoeff, color);
447 inColor = "filteredColor";
448 }
449
450 ///////////////////////////////////////////////////////////////////////////
451 // compute the partial coverage (coverage stages and edge aa)
452
453 GrStringBuilder inCoverage;
454 bool coverageIsScalar = false;
455
456 // we will want to compute coverage for some blend when there is no
457 // color (when dual source blending is enabled). But for now we have this if
458 if (!wroteFragColorZero) {
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000459 if (fProgramDesc.fUsesEdgeAA) {
460 // FIXME: put the a's in a loop
461 segments.fFSCode.append(
462 "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n"
463 "\tfloat a0 = clamp(dot(uEdges[0], pos), 0.0, 1.0);\n"
464 "\tfloat a1 = clamp(dot(uEdges[1], pos), 0.0, 1.0);\n"
465 "\tfloat a2 = clamp(dot(uEdges[2], pos), 0.0, 1.0);\n"
466 "\tfloat a3 = clamp(dot(uEdges[3], pos), 0.0, 1.0);\n"
467 "\tfloat a4 = clamp(dot(uEdges[4], pos), 0.0, 1.0);\n"
468 "\tfloat a5 = clamp(dot(uEdges[5], pos), 0.0, 1.0);\n"
469 "\tfloat edgeAlpha = min(min(a0 * a1, a2 * a3), a4 * a5);\n");
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000470 inCoverage = "edgeAlpha";
471 coverageIsScalar = true;
472 }
473
474 GrStringBuilder outCoverage;
475 const int& startStage = fProgramDesc.fFirstCoverageStage;
476 for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) {
477 if (fProgramDesc.fStages[s].fEnabled) {
478
479 // create var to hold stage output
480 outCoverage = "coverage";
481 outCoverage.appendS32(s);
482 segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
483
484 const char* inCoords;
485 // figure out what our input coords are
486 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
487 inCoords = POS_ATTR_NAME;
488 } else {
489 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
490 // we better have input tex coordinates if stage is enabled.
491 GrAssert(tcIdx >= 0);
492 GrAssert(texCoordAttrs[tcIdx].size());
493 inCoords = texCoordAttrs[tcIdx].c_str();
494 }
495
496 genStageCode(s,
497 fProgramDesc.fStages[s],
498 inCoverage.size() ? inCoverage.c_str() : NULL,
499 outCoverage.c_str(),
500 inCoords,
501 &segments,
502 &programData->fUniLocations.fStages[s]);
503 inCoverage = outCoverage;
504 coverageIsScalar = false;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000505 }
506 }
junov@google.comf93e7172011-03-31 21:26:24 +0000507 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000508
509 // TODO: ADD dual source blend output based on coverage here
510
511 ///////////////////////////////////////////////////////////////////////////
512 // combine color and coverage as frag color
513
514 if (!wroteFragColorZero) {
515 if (coverageIsScalar && !inColor.size()) {
516 GrStringBuilder oldCoverage = inCoverage;
517 inCoverage.swap(oldCoverage);
518 inCoverage.printf("vec4(%s,%s,%s,%s)", oldCoverage.c_str(),
519 oldCoverage.c_str(), oldCoverage.c_str(),
520 oldCoverage.c_str());
521 }
522 modulate_helper("gl_FragColor", inColor.c_str(),
523 inCoverage.c_str(), &segments.fFSCode);
524 }
525
bsalomon@google.com91961302011-05-09 18:39:58 +0000526 segments.fVSCode.append("}\n");
527 segments.fFSCode.append("}\n");
528
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000529 ///////////////////////////////////////////////////////////////////////////
530 // compile and setup attribs and unis
531
bsalomon@google.com91961302011-05-09 18:39:58 +0000532 if (!CompileFSAndVS(segments, programData)) {
533 return false;
534 }
535
536 if (!this->bindAttribsAndLinkProgram(texCoordAttrs, programData)) {
537 return false;
538 }
539
540 this->getUniformLocationsAndInitCache(programData);
541
542 return true;
543}
544
545bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
546 CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000547
junov@google.comf93e7172011-03-31 21:26:24 +0000548 const char* strings[4];
549 int lengths[4];
550 int stringCnt = 0;
551
bsalomon@google.comfc296292011-05-06 13:53:47 +0000552 if (segments.fVSUnis.size()) {
553 strings[stringCnt] = segments.fVSUnis.c_str();
554 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000555 ++stringCnt;
556 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000557 if (segments.fVSAttrs.size()) {
558 strings[stringCnt] = segments.fVSAttrs.c_str();
559 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000560 ++stringCnt;
561 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000562 if (segments.fVaryings.size()) {
563 strings[stringCnt] = segments.fVaryings.c_str();
564 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000565 ++stringCnt;
566 }
567
bsalomon@google.comfc296292011-05-06 13:53:47 +0000568 GrAssert(segments.fVSCode.size());
569 strings[stringCnt] = segments.fVSCode.c_str();
570 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000571 ++stringCnt;
572
573#if PRINT_SHADERS
bsalomon@google.comfc296292011-05-06 13:53:47 +0000574 GrPrintf(segments.fVSUnis.c_str());
575 GrPrintf(segments.fVSAttrs.c_str());
576 GrPrintf(segments.fVaryings.c_str());
577 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000578 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000579#endif
580 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
581 stringCnt,
582 strings,
583 lengths);
584
bsalomon@google.com91961302011-05-09 18:39:58 +0000585 if (!programData->fVShaderID) {
586 return false;
587 }
588
junov@google.comf93e7172011-03-31 21:26:24 +0000589 stringCnt = 0;
590
591 if (strlen(GrShaderPrecision()) > 1) {
592 strings[stringCnt] = GrShaderPrecision();
593 lengths[stringCnt] = strlen(GrShaderPrecision());
594 ++stringCnt;
595 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000596 if (segments.fFSUnis.size()) {
597 strings[stringCnt] = segments.fFSUnis.c_str();
598 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000599 ++stringCnt;
600 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000601 if (segments.fVaryings.size()) {
602 strings[stringCnt] = segments.fVaryings.c_str();
603 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000604 ++stringCnt;
605 }
606
bsalomon@google.comfc296292011-05-06 13:53:47 +0000607 GrAssert(segments.fFSCode.size());
608 strings[stringCnt] = segments.fFSCode.c_str();
609 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000610 ++stringCnt;
611
612#if PRINT_SHADERS
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000613 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000614 GrPrintf(segments.fFSUnis.c_str());
615 GrPrintf(segments.fVaryings.c_str());
616 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000617 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000618#endif
619 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
620 stringCnt,
621 strings,
622 lengths);
623
bsalomon@google.com91961302011-05-09 18:39:58 +0000624 if (!programData->fFShaderID) {
625 return false;
junov@google.comf93e7172011-03-31 21:26:24 +0000626 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000627 return true;
junov@google.comf93e7172011-03-31 21:26:24 +0000628}
629
630GrGLuint GrGLProgram::CompileShader(GrGLenum type,
631 int stringCnt,
632 const char** strings,
633 int* stringLengths) {
634 GrGLuint shader = GR_GL(CreateShader(type));
635 if (0 == shader) {
636 return 0;
637 }
638
639 GrGLint compiled = GR_GL_INIT_ZERO;
640 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
641 GR_GL(CompileShader(shader));
642 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
643
644 if (!compiled) {
645 GrGLint infoLen = GR_GL_INIT_ZERO;
646 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
647 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
648 if (infoLen > 0) {
649 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
650 for (int i = 0; i < stringCnt; ++i) {
651 if (NULL == stringLengths || stringLengths[i] < 0) {
652 GrPrintf(strings[i]);
653 } else {
654 GrPrintf("%.*s", stringLengths[i], strings[i]);
655 }
656 }
657 GrPrintf("\n%s", log.get());
658 }
659 GrAssert(!"Shader compilation failed!");
660 GR_GL(DeleteShader(shader));
661 return 0;
662 }
663 return shader;
664}
665
bsalomon@google.com91961302011-05-09 18:39:58 +0000666bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
667 CachedData* programData) const {
668 programData->fProgramID = GR_GL(CreateProgram());
669 if (!programData->fProgramID) {
670 return false;
671 }
672 const GrGLint& progID = programData->fProgramID;
673
674 GR_GL(AttachShader(progID, programData->fVShaderID));
675 GR_GL(AttachShader(progID, programData->fFShaderID));
676
677 // Bind the attrib locations to same values for all shaders
678 GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
679 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
680 if (texCoordAttrNames[t].size()) {
681 GR_GL(BindAttribLocation(progID,
682 TexCoordAttributeIdx(t),
683 texCoordAttrNames[t].c_str()));
684 }
685 }
686
687
688 if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
689 GR_GL(BindAttribLocation(progID,
690 ViewMatrixAttributeIdx(),
691 VIEW_MATRIX_NAME));
692 }
693
694 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
bsalomon@google.com72b4fcb2011-05-09 20:47:34 +0000695 const StageUniLocations& unis = programData->fUniLocations.fStages[s];
696 if (kSetAsAttribute == unis.fTextureMatrixUni) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000697 GrStringBuilder matName;
698 tex_matrix_name(s, &matName);
699 GR_GL(BindAttribLocation(progID,
700 TextureMatrixAttributeIdx(s),
701 matName.c_str()));
702 }
703 }
704
bsalomon@google.com91961302011-05-09 18:39:58 +0000705 GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
706
707 GR_GL(LinkProgram(progID));
708
709 GrGLint linked = GR_GL_INIT_ZERO;
710 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
711 if (!linked) {
712 GrGLint infoLen = GR_GL_INIT_ZERO;
713 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
714 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
715 if (infoLen > 0) {
716 GR_GL(GetProgramInfoLog(progID,
717 infoLen+1,
718 NULL,
719 (char*)log.get()));
720 GrPrintf((char*)log.get());
721 }
722 GrAssert(!"Error linking program");
723 GR_GL(DeleteProgram(progID));
724 programData->fProgramID = 0;
725 return false;
726 }
727 return true;
728}
729
730void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
731 const GrGLint& progID = programData->fProgramID;
732
733 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
734 programData->fUniLocations.fViewMatrixUni =
735 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
736 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
737 }
738 if (kUseUniform == programData->fUniLocations.fColorUni) {
739 programData->fUniLocations.fColorUni =
740 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
741 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
742 }
Scroggo97c88c22011-05-11 14:05:25 +0000743 if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
744 programData->fUniLocations.fColorFilterUni =
745 GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
746 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
747 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000748
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000749 if (kUseUniform == programData->fUniLocations.fEdgesUni) {
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000750 programData->fUniLocations.fEdgesUni =
751 GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
752 GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
753 } else {
754 programData->fUniLocations.fEdgesUni = kUnusedUniform;
755 }
756
bsalomon@google.com91961302011-05-09 18:39:58 +0000757 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
758 StageUniLocations& locations = programData->fUniLocations.fStages[s];
759 if (fProgramDesc.fStages[s].fEnabled) {
760 if (kUseUniform == locations.fTextureMatrixUni) {
761 GrStringBuilder texMName;
762 tex_matrix_name(s, &texMName);
763 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
764 progID,
765 texMName.c_str()));
766 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
767 }
768
769 if (kUseUniform == locations.fSamplerUni) {
770 GrStringBuilder samplerName;
771 sampler_name(s, &samplerName);
772 locations.fSamplerUni = GR_GL(GetUniformLocation(
773 progID,
774 samplerName.c_str()));
775 GrAssert(kUnusedUniform != locations.fSamplerUni);
776 }
777
778 if (kUseUniform == locations.fNormalizedTexelSizeUni) {
779 GrStringBuilder texelSizeName;
780 normalized_texel_size_name(s, &texelSizeName);
781 locations.fNormalizedTexelSizeUni =
782 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
783 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
784 }
785
786 if (kUseUniform == locations.fRadial2Uni) {
787 GrStringBuilder radial2ParamName;
788 radial2_param_name(s, &radial2ParamName);
789 locations.fRadial2Uni = GR_GL(GetUniformLocation(
790 progID,
791 radial2ParamName.c_str()));
792 GrAssert(kUnusedUniform != locations.fRadial2Uni);
793 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000794
795 if (kUseUniform == locations.fTexDomUni) {
796 GrStringBuilder texDomName;
797 tex_domain_name(s, &texDomName);
798 locations.fTexDomUni = GR_GL(GetUniformLocation(
799 progID,
800 texDomName.c_str()));
801 GrAssert(kUnusedUniform != locations.fTexDomUni);
802 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000803 }
804 }
805 GR_GL(UseProgram(progID));
806
807 // init sampler unis and set bogus values for state tracking
808 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
809 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
810 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
811 }
812 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
813 programData->fRadial2CenterX1[s] = GR_ScalarMax;
814 programData->fRadial2Radius0[s] = -GR_ScalarMax;
815 programData->fTextureWidth[s] = -1;
816 programData->fTextureHeight[s] = -1;
817 }
818 programData->fViewMatrix = GrMatrix::InvalidMatrix();
819 programData->fColor = GrColor_ILLEGAL;
Scroggo97c88c22011-05-11 14:05:25 +0000820 programData->fColorFilterColor = GrColor_ILLEGAL;
bsalomon@google.com91961302011-05-09 18:39:58 +0000821}
822
junov@google.comf93e7172011-03-31 21:26:24 +0000823//============================================================================
824// Stage code generation
825//============================================================================
826
827void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000828 const GrGLProgram::ProgramDesc::StageDesc& desc,
829 const char* fsInColor, // NULL means no incoming color
830 const char* fsOutColor,
831 const char* vsInCoord,
832 ShaderCodeSegments* segments,
833 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000834
835 GrAssert(stageNum >= 0 && stageNum <= 9);
836
bsalomon@google.com91961302011-05-09 18:39:58 +0000837 GrStringBuilder varyingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000838 stage_varying_name(stageNum, &varyingName);
839
840 // First decide how many coords are needed to access the texture
841 // Right now it's always 2 but we could start using 1D textures for
842 // gradients.
843 static const int coordDims = 2;
844 int varyingDims;
845 /// Vertex Shader Stuff
846
847 // decide whether we need a matrix to transform texture coords
848 // and whether the varying needs a perspective coord.
bsalomon@google.com91961302011-05-09 18:39:58 +0000849 GrStringBuilder texMName;
junov@google.comf93e7172011-03-31 21:26:24 +0000850 tex_matrix_name(stageNum, &texMName);
851 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
852 varyingDims = coordDims;
853 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000854 #if GR_GL_ATTRIBUTE_MATRICES
bsalomon@google.com91961302011-05-09 18:39:58 +0000855 segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
856 locations->fTextureMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000857 #else
bsalomon@google.com91961302011-05-09 18:39:58 +0000858 segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
859 locations->fTextureMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000860 #endif
861 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
862 varyingDims = coordDims;
863 } else {
864 varyingDims = coordDims + 1;
865 }
866 }
867
bsalomon@google.com91961302011-05-09 18:39:58 +0000868 GrStringBuilder samplerName;
junov@google.comf93e7172011-03-31 21:26:24 +0000869 sampler_name(stageNum, &samplerName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000870 segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
871 locations->fSamplerUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000872
bsalomon@google.com91961302011-05-09 18:39:58 +0000873 GrStringBuilder texelSizeName;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000874 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
875 normalized_texel_size_name(stageNum, &texelSizeName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000876 segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000877 }
878
bsalomon@google.com91961302011-05-09 18:39:58 +0000879 segments->fVaryings.appendf("varying %s %s;\n",
880 float_vector_type(varyingDims), varyingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000881
882 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
883 GrAssert(varyingDims == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000884 segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
junov@google.comf93e7172011-03-31 21:26:24 +0000885 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000886 // varying = texMatrix * texCoord
887 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
888 varyingName.c_str(), texMName.c_str(),
889 vsInCoord, vector_all_coords(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000890 }
891
bsalomon@google.com91961302011-05-09 18:39:58 +0000892 GrStringBuilder radial2ParamsName;
junov@google.comf93e7172011-03-31 21:26:24 +0000893 radial2_param_name(stageNum, &radial2ParamsName);
894 // for radial grads without perspective we can pass the linear
895 // part of the quadratic as a varying.
bsalomon@google.com91961302011-05-09 18:39:58 +0000896 GrStringBuilder radial2VaryingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000897 radial2_varying_name(stageNum, &radial2VaryingName);
898
899 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
900
bsalomon@google.comdcf1b0b2011-05-11 19:00:54 +0000901 segments->fVSUnis.appendf("uniform %s float %s[6];\n",
bsalomon@google.com91961302011-05-09 18:39:58 +0000902 GrPrecision(), radial2ParamsName.c_str());
903 segments->fFSUnis.appendf("uniform float %s[6];\n",
904 radial2ParamsName.c_str());
905 locations->fRadial2Uni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000906
907 // if there is perspective we don't interpolate this
908 if (varyingDims == coordDims) {
909 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000910 segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000911
bsalomon@google.com91961302011-05-09 18:39:58 +0000912 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
913 segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
914 radial2VaryingName.c_str(), radial2ParamsName.c_str(),
915 varyingName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000916 }
917 }
918
919 /// Fragment Shader Stuff
bsalomon@google.com91961302011-05-09 18:39:58 +0000920 GrStringBuilder fsCoordName;
junov@google.comf93e7172011-03-31 21:26:24 +0000921 // function used to access the shader, may be made projective
bsalomon@google.com91961302011-05-09 18:39:58 +0000922 GrStringBuilder texFunc("texture2D");
junov@google.comf93e7172011-03-31 21:26:24 +0000923 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
924 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
925 GrAssert(varyingDims == coordDims);
926 fsCoordName = varyingName;
927 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000928 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +0000929 // our final tex coords then when in perspective we have to
bsalomon@google.com91961302011-05-09 18:39:58 +0000930 // do an explicit divide. Otherwise, we can use a Proj func.
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000931 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
932 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000933 texFunc.append("Proj");
junov@google.comf93e7172011-03-31 21:26:24 +0000934 fsCoordName = varyingName;
935 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000936 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000937 fsCoordName.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000938 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
939 float_vector_type(coordDims),
940 fsCoordName.c_str(),
941 varyingName.c_str(),
942 vector_nonhomog_coords(varyingDims),
943 varyingName.c_str(),
944 vector_homog_coord(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000945 }
946 }
947
bsalomon@google.comfc296292011-05-06 13:53:47 +0000948 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000949 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +0000950 switch (desc.fCoordMapping) {
951 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
952 sampleCoords = fsCoordName;
953 break;
954 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000955 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 +0000956 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000957 break;
958 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000959 sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000960 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000961 break;
962 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.com91961302011-05-09 18:39:58 +0000963 GrStringBuilder cName("c");
964 GrStringBuilder ac4Name("ac4");
965 GrStringBuilder rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +0000966
bsalomon@google.comfc296292011-05-06 13:53:47 +0000967 cName.appendS32(stageNum);
968 ac4Name.appendS32(stageNum);
969 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +0000970
bsalomon@google.com91961302011-05-09 18:39:58 +0000971 // if we were able to interpolate the linear component bVar is the varying
972 // otherwise compute it
973 GrStringBuilder bVar;
junov@google.comf93e7172011-03-31 21:26:24 +0000974 if (coordDims == varyingDims) {
975 bVar = radial2VaryingName;
976 GrAssert(2 == varyingDims);
977 } else {
978 GrAssert(3 == varyingDims);
979 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000980 bVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000981 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
982 bVar.c_str(), radial2ParamsName.c_str(),
983 fsCoordName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000984 }
985
bsalomon@google.com91961302011-05-09 18:39:58 +0000986 // c = (x^2)+(y^2) - params[4]
987 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
988 cName.c_str(), fsCoordName.c_str(),
989 fsCoordName.c_str(),
990 radial2ParamsName.c_str());
991 // ac4 = 4.0 * params[0] * c
992 segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
993 ac4Name.c_str(), radial2ParamsName.c_str(),
994 cName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000995
bsalomon@google.com91961302011-05-09 18:39:58 +0000996 // root = sqrt(b^2-4ac)
997 // (abs to avoid exception due to fp precision)
998 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
999 rootName.c_str(), bVar.c_str(), bVar.c_str(),
1000 ac4Name.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001001
bsalomon@google.com91961302011-05-09 18:39:58 +00001002 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
1003 // y coord is 0.5 (texture is effectively 1D)
1004 sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
1005 bVar.c_str(), radial2ParamsName.c_str(),
1006 rootName.c_str(), radial2ParamsName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001007 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001008 break;}
1009 };
1010
bsalomon@google.com91961302011-05-09 18:39:58 +00001011 const char* smear;
1012 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
1013 smear = ".aaaa";
1014 } else {
1015 smear = "";
1016 }
1017 GrStringBuilder modulate;
1018 if (NULL != fsInColor) {
1019 modulate.printf(" * %s", fsInColor);
1020 }
1021
junov@google.com6acc9b32011-05-16 18:32:07 +00001022 if (desc.fOptFlags &
1023 ProgramDesc::StageDesc::kCustomTextureDomain_OptFlagBit) {
1024 GrStringBuilder texDomainName;
1025 tex_domain_name(stageNum, &texDomainName);
1026 segments->fFSUnis.appendf("uniform %s %s;\n",
1027 float_vector_type(4),
1028 texDomainName.c_str());
1029 GrStringBuilder coordVar("clampCoord");
1030 segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
1031 float_vector_type(coordDims),
1032 coordVar.c_str(),
1033 sampleCoords.c_str(),
1034 texDomainName.c_str(),
1035 texDomainName.c_str());
1036 sampleCoords = coordVar;
1037 locations->fTexDomUni = kUseUniform;
1038 }
1039
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001040 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001041 locations->fNormalizedTexelSizeUni = kUseUniform;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001042 if (complexCoord) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001043 // assign the coord to a var rather than compute 4x.
1044 GrStringBuilder coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +00001045 coordVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001046 segments->fFSCode.appendf("\t%s %s = %s;\n",
1047 float_vector_type(coordDims),
1048 coordVar.c_str(), sampleCoords.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001049 sampleCoords = coordVar;
1050 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001051 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +00001052 GrStringBuilder accumVar("accum");
1053 accumVar.appendS32(stageNum);
1054 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);
1055 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);
1056 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);
1057 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);
1058 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001059 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +00001060 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 +00001061 }
junov@google.comf93e7172011-03-31 21:26:24 +00001062}
1063