blob: bd95f3cb8c54559c1900a55c433b882722482530 [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"
21#include "GrGLEffect.h"
22#include "GrMemory.h"
junov@google.comf93e7172011-03-31 21:26:24 +000023
Scroggo97c88c22011-05-11 14:05:25 +000024#include "SkXfermode.h"
25
junov@google.comf93e7172011-03-31 21:26:24 +000026namespace {
27
28const char* GrPrecision() {
29 if (GR_GL_SUPPORT_ES2) {
30 return "mediump";
31 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +000032 return " ";
junov@google.comf93e7172011-03-31 21:26:24 +000033 }
34}
35
36const char* GrShaderPrecision() {
37 if (GR_GL_SUPPORT_ES2) {
38 return "precision mediump float;\n";
39 } else {
40 return "";
41 }
42}
43
44} // namespace
45
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000046#define PRINT_SHADERS 0
47
bsalomon@google.com4be283f2011-04-19 21:15:09 +000048#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000049 #define VIEW_MATRIX_NAME "aViewM"
50#else
51 #define VIEW_MATRIX_NAME "uViewM"
52#endif
53
54#define POS_ATTR_NAME "aPosition"
55#define COL_ATTR_NAME "aColor"
bsalomon@google.com4be283f2011-04-19 21:15:09 +000056#define COL_UNI_NAME "uColor"
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +000057#define EDGES_UNI_NAME "uEdges"
Scroggo97c88c22011-05-11 14:05:25 +000058#define COL_FILTER_UNI_NAME "uColorFilter"
junov@google.comf93e7172011-03-31 21:26:24 +000059
junov@google.comf93e7172011-03-31 21:26:24 +000060static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
61 *s = "aTexCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +000062 s->appendS32(coordIdx);
junov@google.comf93e7172011-03-31 21:26:24 +000063}
64
65static inline const char* float_vector_type(int count) {
66 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
67 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
68 return FLOAT_VECS[count];
69}
70
71static inline const char* vector_homog_coord(int count) {
72 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
73 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
74 return HOMOGS[count];
75}
76
77static inline const char* vector_nonhomog_coords(int count) {
78 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
79 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
80 return NONHOMOGS[count];
81}
82
83static inline const char* vector_all_coords(int count) {
84 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
85 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
86 return ALL[count];
87}
88
bsalomon@google.comf2d91552011-05-16 20:56:06 +000089static inline const char* all_ones_vec(int count) {
90 static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)",
91 "vec3(1,1,1)", "vec4(1,1,1,1)"};
92 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ONESVEC));
93 return ONESVEC[count];
94}
95
96static inline const char* all_zeros_vec(int count) {
97 static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)",
98 "vec3(0,0,0)", "vec4(0,0,0,0)"};
99 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ZEROSVEC));
100 return ZEROSVEC[count];
101}
102
junov@google.comf93e7172011-03-31 21:26:24 +0000103static void tex_matrix_name(int stage, GrStringBuilder* s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000104#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000105 *s = "aTexM";
106#else
107 *s = "uTexM";
108#endif
bsalomon@google.comfc296292011-05-06 13:53:47 +0000109 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000110}
111
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000112static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
113 *s = "uTexelSize";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000114 s->appendS32(stage);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000115}
116
junov@google.comf93e7172011-03-31 21:26:24 +0000117static void sampler_name(int stage, GrStringBuilder* s) {
118 *s = "uSampler";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000119 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000120}
121
122static void stage_varying_name(int stage, GrStringBuilder* s) {
123 *s = "vStage";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000124 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000125}
126
127static void radial2_param_name(int stage, GrStringBuilder* s) {
128 *s = "uRadial2Params";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000129 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000130}
131
132static void radial2_varying_name(int stage, GrStringBuilder* s) {
133 *s = "vB";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000134 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000135}
136
junov@google.com6acc9b32011-05-16 18:32:07 +0000137static void tex_domain_name(int stage, GrStringBuilder* s) {
138 *s = "uTexDom";
139 s->appendS32(stage);
140}
141
junov@google.comf93e7172011-03-31 21:26:24 +0000142GrGLProgram::GrGLProgram() {
143 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
144 fStageEffects[stage] = NULL;
145 }
146}
147
148GrGLProgram::~GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000149}
150
151void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
152 // Add stage configuration to the key
153 key.keyData(reinterpret_cast<const uint8_t*>(&fProgramDesc), sizeof(ProgramDesc));
154
155 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
156 // First pass: count effects and write the count to the key.
157 // This may seem like we are adding redundant data to the
158 // key, but in ensures the one key cannot be a prefix of
159 // another key, or identical to the key of a different program.
160 GrGLEffect* currentEffect = fStageEffects[stage];
161 uint8_t effectCount = 0;
162 while (currentEffect) {
163 GrAssert(effectCount < 255); // overflow detection
164 ++effectCount;
165 currentEffect = currentEffect->nextEffect();
166 }
167 key.keyData(reinterpret_cast<const uint8_t*>(&effectCount), sizeof(uint8_t));
168
169 // Second pass: continue building key using the effects
170 currentEffect = fStageEffects[stage];
171 while (currentEffect) {
172 fStageEffects[stage]->buildKey(key);
173 }
174 }
175}
176
177bool GrGLProgram::doGLSetup(GrPrimitiveType type,
178 GrGLProgram::CachedData* programData) const {
179 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
180 GrGLEffect* effect = fStageEffects[stage];
181 if (effect) {
182 if (!effect->doGLSetup(type, programData->fProgramID)) {
183 return false;
184 }
185 }
186 }
187
188 return true;
189}
190
191void GrGLProgram::doGLPost() const {
192 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
193 GrGLEffect* effect = fStageEffects[stage];
194 if (effect) {
195 effect->doGLPost();
196 }
197 }
198}
199
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000200// assigns modulation of two vars to an output var
201// if either var is "" then assign to the other var
202// if both are "" then assign all ones
203static inline void modulate_helper(const char* outputVar,
204 const char* var0,
205 const char* var1,
206 GrStringBuilder* code) {
207 GrAssert(NULL != outputVar);
208 GrAssert(NULL != var0);
209 GrAssert(NULL != var1);
210 GrAssert(NULL != code);
211
212 bool has0 = '\0' != *var0;
213 bool has1 = '\0' != *var1;
214
215 if (!has0 && !has1) {
216 code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4));
217 } else if (!has0) {
218 code->appendf("\t%s = %s;\n", outputVar, var1);
219 } else if (!has1) {
220 code->appendf("\t%s = %s;\n", outputVar, var0);
221 } else {
222 code->appendf("\t%s = %s * %s;\n", outputVar, var0, var1);
223 }
224}
225
226// assigns addition of two vars to an output var
227// if either var is "" then assign to the other var
228// if both are "" then assign all zeros
229static inline void add_helper(const char* outputVar,
230 const char* var0,
231 const char* var1,
232 GrStringBuilder* code) {
233 GrAssert(NULL != outputVar);
234 GrAssert(NULL != var0);
235 GrAssert(NULL != var1);
236 GrAssert(NULL != code);
237
238 bool has0 = '\0' != *var0;
239 bool has1 = '\0' != *var1;
240
241 if (!has0 && !has1) {
242 code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4));
243 } else if (!has0) {
244 code->appendf("\t%s = %s;\n", outputVar, var1);
245 } else if (!has1) {
246 code->appendf("\t%s = %s;\n", outputVar, var0);
247 } else {
248 code->appendf("\t%s = %s + %s;\n", outputVar, var0, var1);
249 }
250}
251
252// given two blend coeffecients determine whether the src
253// and/or dst computation can be omitted.
254static inline void needBlendInputs(SkXfermode::Coeff srcCoeff,
255 SkXfermode::Coeff dstCoeff,
256 bool* needSrcValue,
257 bool* needDstValue) {
258 if (SkXfermode::kZero_Coeff == srcCoeff) {
259 switch (dstCoeff) {
260 // these all read the src
261 case SkXfermode::kSC_Coeff:
262 case SkXfermode::kISC_Coeff:
263 case SkXfermode::kSA_Coeff:
264 case SkXfermode::kISA_Coeff:
265 *needSrcValue = true;
266 break;
267 default:
268 *needSrcValue = false;
269 break;
270 }
271 } else {
272 *needSrcValue = true;
273 }
274 if (SkXfermode::kZero_Coeff == dstCoeff) {
275 switch (srcCoeff) {
276 // these all read the dst
277 case SkXfermode::kDC_Coeff:
278 case SkXfermode::kIDC_Coeff:
279 case SkXfermode::kDA_Coeff:
280 case SkXfermode::kIDA_Coeff:
281 *needDstValue = true;
282 break;
283 default:
284 *needDstValue = false;
285 break;
286 }
287 } else {
288 *needDstValue = true;
Scroggo97c88c22011-05-11 14:05:25 +0000289 }
290}
291
292/**
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000293 * Create a blend_coeff * value string to be used in shader code. Sets empty
294 * string if result is trivially zero.
295 */
296static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff,
297 const char* src, const char* dst,
298 const char* value) {
299
300 switch (coeff) {
301 case SkXfermode::kZero_Coeff: /** 0 */
302 *str = "";
303 break;
304 case SkXfermode::kOne_Coeff: /** 1 */
305 *str = value;
306 break;
307 case SkXfermode::kSC_Coeff:
308 str->printf("(%s * %s)", src, value);
309 break;
310 case SkXfermode::kISC_Coeff:
311 str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value);
312 break;
313 case SkXfermode::kDC_Coeff:
314 str->printf("(%s * %s)", dst, value);
315 break;
316 case SkXfermode::kIDC_Coeff:
317 str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value);
318 break;
319 case SkXfermode::kSA_Coeff: /** src alpha */
320 str->printf("(%s.a * %s)", src, value);
321 break;
322 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
323 str->printf("((1.0 - %s.a) * %s)", src, value);
324 break;
325 case SkXfermode::kDA_Coeff: /** dst alpha */
326 str->printf("(%s.a * %s)", dst, value);
327 break;
328 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
329 str->printf("((1.0 - %s.a) * %s)", dst, value);
330 break;
331 default:
332 GrCrash("Unexpected xfer coeff.");
333 break;
334 }
335}
336/**
Scroggo97c88c22011-05-11 14:05:25 +0000337 * Adds a line to the fragment shader code which modifies the color by
338 * the specified color filter.
339 */
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000340static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar,
341 SkXfermode::Coeff uniformCoeff,
342 SkXfermode::Coeff colorCoeff,
343 const char* inColor) {
344 GrStringBuilder colorStr, constStr;
345 blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME,
346 inColor, inColor);
347 blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME,
348 inColor, COL_FILTER_UNI_NAME);
349
350 add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
Scroggo97c88c22011-05-11 14:05:25 +0000351}
352
bsalomon@google.com91961302011-05-09 18:39:58 +0000353bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000354
355 ShaderCodeSegments segments;
356 const uint32_t& layout = fProgramDesc.fVertexLayout;
357
bsalomon@google.com91961302011-05-09 18:39:58 +0000358 programData->fUniLocations.reset();
junov@google.comf93e7172011-03-31 21:26:24 +0000359
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000360 SkXfermode::Coeff colorCoeff, uniformCoeff;
361 // The rest of transfer mode color filters have not been implemented
362 if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
363 GR_DEBUGCODE(bool success =)
364 SkXfermode::ModeAsCoeff(fProgramDesc.fColorFilterXfermode, &uniformCoeff, &colorCoeff);
365 GR_DEBUGASSERT(success);
366 } else {
367 colorCoeff = SkXfermode::kOne_Coeff;
368 uniformCoeff = SkXfermode::kZero_Coeff;
369 }
370
371 bool needColorFilterUniform;
372 bool needComputedColor;
373 needBlendInputs(uniformCoeff, colorCoeff,
374 &needColorFilterUniform, &needComputedColor);
375
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000376#if GR_GL_ATTRIBUTE_MATRICES
377 segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000378 programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000379#else
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000380 segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000381 programData->fUniLocations.fViewMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000382#endif
383 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000384
bsalomon@google.com91961302011-05-09 18:39:58 +0000385 segments.fVSCode.append(
386 "void main() {\n"
387 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
388 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000389
bsalomon@google.com91961302011-05-09 18:39:58 +0000390 // incoming color to current stage being processed.
391 GrStringBuilder inColor;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000392
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000393 if (needComputedColor) {
394 switch (fProgramDesc.fColorType) {
395 case ProgramDesc::kAttribute_ColorType:
396 segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
397 segments.fVaryings.append("varying vec4 vColor;\n");
398 segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
399 inColor = "vColor";
400 break;
401 case ProgramDesc::kUniform_ColorType:
402 segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
403 programData->fUniLocations.fColorUni = kUseUniform;
404 inColor = COL_UNI_NAME;
405 break;
406 default:
407 GrAssert(ProgramDesc::kNone_ColorType == fProgramDesc.fColorType);
408 break;
409 }
junov@google.comf93e7172011-03-31 21:26:24 +0000410 }
411
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000412 if (fProgramDesc.fUsesEdgeAA) {
413 segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[6];\n");
414 }
415
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000416 if (fProgramDesc.fEmitsPointSize){
bsalomon@google.com91961302011-05-09 18:39:58 +0000417 segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000418 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000419
bsalomon@google.com91961302011-05-09 18:39:58 +0000420 segments.fFSCode.append("void main() {\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000421
422 // add texture coordinates that are used to the list of vertex attr decls
bsalomon@google.com91961302011-05-09 18:39:58 +0000423 GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
junov@google.comf93e7172011-03-31 21:26:24 +0000424 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000425 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000426 tex_attr_name(t, texCoordAttrs + t);
bsalomon@google.com91961302011-05-09 18:39:58 +0000427 segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000428 }
429 }
430
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000431 ///////////////////////////////////////////////////////////////////////////
432 // compute the final color
Scroggo97c88c22011-05-11 14:05:25 +0000433
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000434 // if we have color stages string them together, feeding the output color
435 // of each to the next and generating code for each stage.
436 if (needComputedColor) {
437 GrStringBuilder outColor;
438 for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
Scroggo97c88c22011-05-11 14:05:25 +0000439 if (fProgramDesc.fStages[s].fEnabled) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000440 // create var to hold stage result
441 outColor = "color";
442 outColor.appendS32(s);
443 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
444
445 const char* inCoords;
446 // figure out what our input coords are
447 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
448 layout) {
449 inCoords = POS_ATTR_NAME;
Scroggo97c88c22011-05-11 14:05:25 +0000450 } else {
451 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
452 // we better have input tex coordinates if stage is enabled.
453 GrAssert(tcIdx >= 0);
454 GrAssert(texCoordAttrs[tcIdx].size());
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000455 inCoords = texCoordAttrs[tcIdx].c_str();
junov@google.comf93e7172011-03-31 21:26:24 +0000456 }
457
458 genStageCode(s,
459 fProgramDesc.fStages[s],
bsalomon@google.comfc296292011-05-06 13:53:47 +0000460 inColor.size() ? inColor.c_str() : NULL,
461 outColor.c_str(),
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000462 inCoords,
junov@google.comf93e7172011-03-31 21:26:24 +0000463 &segments,
464 &programData->fUniLocations.fStages[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000465 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000466 }
467 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000468 }
Scroggo97c88c22011-05-11 14:05:25 +0000469
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000470 // if have all ones for the "dst" input to the color filter then we can make
471 // additional optimizations.
472 if (needColorFilterUniform && !inColor.size() &&
473 (SkXfermode::kIDC_Coeff == uniformCoeff ||
474 SkXfermode::kIDA_Coeff == uniformCoeff)) {
475 uniformCoeff = SkXfermode::kZero_Coeff;
476 bool bogus;
477 needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
478 &needColorFilterUniform, &bogus);
479 }
480 if (needColorFilterUniform) {
481 segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
482 programData->fUniLocations.fColorFilterUni = kUseUniform;
483 }
484
485 bool wroteFragColorZero = false;
486 if (SkXfermode::kZero_Coeff == uniformCoeff &&
487 SkXfermode::kZero_Coeff == colorCoeff) {
488 segments.fFSCode.appendf("\tgl_FragColor = %s;\n", all_zeros_vec(4));
489 wroteFragColorZero = true;
490 } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
491 segments.fFSCode.appendf("\tvec4 filteredColor;\n");
492 const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4);
493 addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
494 colorCoeff, color);
495 inColor = "filteredColor";
496 }
497
498 ///////////////////////////////////////////////////////////////////////////
499 // compute the partial coverage (coverage stages and edge aa)
500
501 GrStringBuilder inCoverage;
502 bool coverageIsScalar = false;
503
504 // we will want to compute coverage for some blend when there is no
505 // color (when dual source blending is enabled). But for now we have this if
506 if (!wroteFragColorZero) {
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000507 if (fProgramDesc.fUsesEdgeAA) {
508 // FIXME: put the a's in a loop
509 segments.fFSCode.append(
510 "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n"
511 "\tfloat a0 = clamp(dot(uEdges[0], pos), 0.0, 1.0);\n"
512 "\tfloat a1 = clamp(dot(uEdges[1], pos), 0.0, 1.0);\n"
513 "\tfloat a2 = clamp(dot(uEdges[2], pos), 0.0, 1.0);\n"
514 "\tfloat a3 = clamp(dot(uEdges[3], pos), 0.0, 1.0);\n"
515 "\tfloat a4 = clamp(dot(uEdges[4], pos), 0.0, 1.0);\n"
516 "\tfloat a5 = clamp(dot(uEdges[5], pos), 0.0, 1.0);\n"
517 "\tfloat edgeAlpha = min(min(a0 * a1, a2 * a3), a4 * a5);\n");
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000518 inCoverage = "edgeAlpha";
519 coverageIsScalar = true;
520 }
521
522 GrStringBuilder outCoverage;
523 const int& startStage = fProgramDesc.fFirstCoverageStage;
524 for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) {
525 if (fProgramDesc.fStages[s].fEnabled) {
526
527 // create var to hold stage output
528 outCoverage = "coverage";
529 outCoverage.appendS32(s);
530 segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
531
532 const char* inCoords;
533 // figure out what our input coords are
534 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
535 inCoords = POS_ATTR_NAME;
536 } else {
537 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
538 // we better have input tex coordinates if stage is enabled.
539 GrAssert(tcIdx >= 0);
540 GrAssert(texCoordAttrs[tcIdx].size());
541 inCoords = texCoordAttrs[tcIdx].c_str();
542 }
543
544 genStageCode(s,
545 fProgramDesc.fStages[s],
546 inCoverage.size() ? inCoverage.c_str() : NULL,
547 outCoverage.c_str(),
548 inCoords,
549 &segments,
550 &programData->fUniLocations.fStages[s]);
551 inCoverage = outCoverage;
552 coverageIsScalar = false;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000553 }
554 }
junov@google.comf93e7172011-03-31 21:26:24 +0000555 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000556
557 // TODO: ADD dual source blend output based on coverage here
558
559 ///////////////////////////////////////////////////////////////////////////
560 // combine color and coverage as frag color
561
562 if (!wroteFragColorZero) {
563 if (coverageIsScalar && !inColor.size()) {
564 GrStringBuilder oldCoverage = inCoverage;
565 inCoverage.swap(oldCoverage);
566 inCoverage.printf("vec4(%s,%s,%s,%s)", oldCoverage.c_str(),
567 oldCoverage.c_str(), oldCoverage.c_str(),
568 oldCoverage.c_str());
569 }
570 modulate_helper("gl_FragColor", inColor.c_str(),
571 inCoverage.c_str(), &segments.fFSCode);
572 }
573
bsalomon@google.com91961302011-05-09 18:39:58 +0000574 segments.fVSCode.append("}\n");
575 segments.fFSCode.append("}\n");
576
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000577 ///////////////////////////////////////////////////////////////////////////
578 // compile and setup attribs and unis
579
bsalomon@google.com91961302011-05-09 18:39:58 +0000580 if (!CompileFSAndVS(segments, programData)) {
581 return false;
582 }
583
584 if (!this->bindAttribsAndLinkProgram(texCoordAttrs, programData)) {
585 return false;
586 }
587
588 this->getUniformLocationsAndInitCache(programData);
589
590 return true;
591}
592
593bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
594 CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000595
junov@google.comf93e7172011-03-31 21:26:24 +0000596 const char* strings[4];
597 int lengths[4];
598 int stringCnt = 0;
599
bsalomon@google.comfc296292011-05-06 13:53:47 +0000600 if (segments.fVSUnis.size()) {
601 strings[stringCnt] = segments.fVSUnis.c_str();
602 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000603 ++stringCnt;
604 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000605 if (segments.fVSAttrs.size()) {
606 strings[stringCnt] = segments.fVSAttrs.c_str();
607 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000608 ++stringCnt;
609 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000610 if (segments.fVaryings.size()) {
611 strings[stringCnt] = segments.fVaryings.c_str();
612 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000613 ++stringCnt;
614 }
615
bsalomon@google.comfc296292011-05-06 13:53:47 +0000616 GrAssert(segments.fVSCode.size());
617 strings[stringCnt] = segments.fVSCode.c_str();
618 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000619 ++stringCnt;
620
621#if PRINT_SHADERS
bsalomon@google.comfc296292011-05-06 13:53:47 +0000622 GrPrintf(segments.fVSUnis.c_str());
623 GrPrintf(segments.fVSAttrs.c_str());
624 GrPrintf(segments.fVaryings.c_str());
625 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000626 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000627#endif
628 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
629 stringCnt,
630 strings,
631 lengths);
632
bsalomon@google.com91961302011-05-09 18:39:58 +0000633 if (!programData->fVShaderID) {
634 return false;
635 }
636
junov@google.comf93e7172011-03-31 21:26:24 +0000637 stringCnt = 0;
638
639 if (strlen(GrShaderPrecision()) > 1) {
640 strings[stringCnt] = GrShaderPrecision();
641 lengths[stringCnt] = strlen(GrShaderPrecision());
642 ++stringCnt;
643 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000644 if (segments.fFSUnis.size()) {
645 strings[stringCnt] = segments.fFSUnis.c_str();
646 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000647 ++stringCnt;
648 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000649 if (segments.fVaryings.size()) {
650 strings[stringCnt] = segments.fVaryings.c_str();
651 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000652 ++stringCnt;
653 }
654
bsalomon@google.comfc296292011-05-06 13:53:47 +0000655 GrAssert(segments.fFSCode.size());
656 strings[stringCnt] = segments.fFSCode.c_str();
657 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000658 ++stringCnt;
659
660#if PRINT_SHADERS
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000661 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000662 GrPrintf(segments.fFSUnis.c_str());
663 GrPrintf(segments.fVaryings.c_str());
664 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000665 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000666#endif
667 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
668 stringCnt,
669 strings,
670 lengths);
671
bsalomon@google.com91961302011-05-09 18:39:58 +0000672 if (!programData->fFShaderID) {
673 return false;
junov@google.comf93e7172011-03-31 21:26:24 +0000674 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000675 return true;
junov@google.comf93e7172011-03-31 21:26:24 +0000676}
677
678GrGLuint GrGLProgram::CompileShader(GrGLenum type,
679 int stringCnt,
680 const char** strings,
681 int* stringLengths) {
682 GrGLuint shader = GR_GL(CreateShader(type));
683 if (0 == shader) {
684 return 0;
685 }
686
687 GrGLint compiled = GR_GL_INIT_ZERO;
688 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
689 GR_GL(CompileShader(shader));
690 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
691
692 if (!compiled) {
693 GrGLint infoLen = GR_GL_INIT_ZERO;
694 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
695 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
696 if (infoLen > 0) {
697 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
698 for (int i = 0; i < stringCnt; ++i) {
699 if (NULL == stringLengths || stringLengths[i] < 0) {
700 GrPrintf(strings[i]);
701 } else {
702 GrPrintf("%.*s", stringLengths[i], strings[i]);
703 }
704 }
705 GrPrintf("\n%s", log.get());
706 }
707 GrAssert(!"Shader compilation failed!");
708 GR_GL(DeleteShader(shader));
709 return 0;
710 }
711 return shader;
712}
713
bsalomon@google.com91961302011-05-09 18:39:58 +0000714bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
715 CachedData* programData) const {
716 programData->fProgramID = GR_GL(CreateProgram());
717 if (!programData->fProgramID) {
718 return false;
719 }
720 const GrGLint& progID = programData->fProgramID;
721
722 GR_GL(AttachShader(progID, programData->fVShaderID));
723 GR_GL(AttachShader(progID, programData->fFShaderID));
724
725 // Bind the attrib locations to same values for all shaders
726 GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
727 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
728 if (texCoordAttrNames[t].size()) {
729 GR_GL(BindAttribLocation(progID,
730 TexCoordAttributeIdx(t),
731 texCoordAttrNames[t].c_str()));
732 }
733 }
734
735
736 if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
737 GR_GL(BindAttribLocation(progID,
738 ViewMatrixAttributeIdx(),
739 VIEW_MATRIX_NAME));
740 }
741
742 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
bsalomon@google.com72b4fcb2011-05-09 20:47:34 +0000743 const StageUniLocations& unis = programData->fUniLocations.fStages[s];
744 if (kSetAsAttribute == unis.fTextureMatrixUni) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000745 GrStringBuilder matName;
746 tex_matrix_name(s, &matName);
747 GR_GL(BindAttribLocation(progID,
748 TextureMatrixAttributeIdx(s),
749 matName.c_str()));
750 }
751 }
752
bsalomon@google.com91961302011-05-09 18:39:58 +0000753 GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
754
755 GR_GL(LinkProgram(progID));
756
757 GrGLint linked = GR_GL_INIT_ZERO;
758 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
759 if (!linked) {
760 GrGLint infoLen = GR_GL_INIT_ZERO;
761 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
762 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
763 if (infoLen > 0) {
764 GR_GL(GetProgramInfoLog(progID,
765 infoLen+1,
766 NULL,
767 (char*)log.get()));
768 GrPrintf((char*)log.get());
769 }
770 GrAssert(!"Error linking program");
771 GR_GL(DeleteProgram(progID));
772 programData->fProgramID = 0;
773 return false;
774 }
775 return true;
776}
777
778void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
779 const GrGLint& progID = programData->fProgramID;
780
781 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
782 programData->fUniLocations.fViewMatrixUni =
783 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
784 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
785 }
786 if (kUseUniform == programData->fUniLocations.fColorUni) {
787 programData->fUniLocations.fColorUni =
788 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
789 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
790 }
Scroggo97c88c22011-05-11 14:05:25 +0000791 if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
792 programData->fUniLocations.fColorFilterUni =
793 GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
794 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
795 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000796
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000797 if (kUseUniform == programData->fUniLocations.fEdgesUni) {
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000798 programData->fUniLocations.fEdgesUni =
799 GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
800 GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
801 } else {
802 programData->fUniLocations.fEdgesUni = kUnusedUniform;
803 }
804
bsalomon@google.com91961302011-05-09 18:39:58 +0000805 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
806 StageUniLocations& locations = programData->fUniLocations.fStages[s];
807 if (fProgramDesc.fStages[s].fEnabled) {
808 if (kUseUniform == locations.fTextureMatrixUni) {
809 GrStringBuilder texMName;
810 tex_matrix_name(s, &texMName);
811 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
812 progID,
813 texMName.c_str()));
814 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
815 }
816
817 if (kUseUniform == locations.fSamplerUni) {
818 GrStringBuilder samplerName;
819 sampler_name(s, &samplerName);
820 locations.fSamplerUni = GR_GL(GetUniformLocation(
821 progID,
822 samplerName.c_str()));
823 GrAssert(kUnusedUniform != locations.fSamplerUni);
824 }
825
826 if (kUseUniform == locations.fNormalizedTexelSizeUni) {
827 GrStringBuilder texelSizeName;
828 normalized_texel_size_name(s, &texelSizeName);
829 locations.fNormalizedTexelSizeUni =
830 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
831 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
832 }
833
834 if (kUseUniform == locations.fRadial2Uni) {
835 GrStringBuilder radial2ParamName;
836 radial2_param_name(s, &radial2ParamName);
837 locations.fRadial2Uni = GR_GL(GetUniformLocation(
838 progID,
839 radial2ParamName.c_str()));
840 GrAssert(kUnusedUniform != locations.fRadial2Uni);
841 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000842
843 if (kUseUniform == locations.fTexDomUni) {
844 GrStringBuilder texDomName;
845 tex_domain_name(s, &texDomName);
846 locations.fTexDomUni = GR_GL(GetUniformLocation(
847 progID,
848 texDomName.c_str()));
849 GrAssert(kUnusedUniform != locations.fTexDomUni);
850 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000851 }
852 }
853 GR_GL(UseProgram(progID));
854
855 // init sampler unis and set bogus values for state tracking
856 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
857 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
858 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
859 }
860 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
861 programData->fRadial2CenterX1[s] = GR_ScalarMax;
862 programData->fRadial2Radius0[s] = -GR_ScalarMax;
863 programData->fTextureWidth[s] = -1;
864 programData->fTextureHeight[s] = -1;
865 }
866 programData->fViewMatrix = GrMatrix::InvalidMatrix();
867 programData->fColor = GrColor_ILLEGAL;
Scroggo97c88c22011-05-11 14:05:25 +0000868 programData->fColorFilterColor = GrColor_ILLEGAL;
bsalomon@google.com91961302011-05-09 18:39:58 +0000869}
870
junov@google.comf93e7172011-03-31 21:26:24 +0000871//============================================================================
872// Stage code generation
873//============================================================================
874
875void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000876 const GrGLProgram::ProgramDesc::StageDesc& desc,
877 const char* fsInColor, // NULL means no incoming color
878 const char* fsOutColor,
879 const char* vsInCoord,
880 ShaderCodeSegments* segments,
881 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000882
883 GrAssert(stageNum >= 0 && stageNum <= 9);
884
bsalomon@google.com91961302011-05-09 18:39:58 +0000885 GrStringBuilder varyingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000886 stage_varying_name(stageNum, &varyingName);
887
888 // First decide how many coords are needed to access the texture
889 // Right now it's always 2 but we could start using 1D textures for
890 // gradients.
891 static const int coordDims = 2;
892 int varyingDims;
893 /// Vertex Shader Stuff
894
895 // decide whether we need a matrix to transform texture coords
896 // and whether the varying needs a perspective coord.
bsalomon@google.com91961302011-05-09 18:39:58 +0000897 GrStringBuilder texMName;
junov@google.comf93e7172011-03-31 21:26:24 +0000898 tex_matrix_name(stageNum, &texMName);
899 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
900 varyingDims = coordDims;
901 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000902 #if GR_GL_ATTRIBUTE_MATRICES
bsalomon@google.com91961302011-05-09 18:39:58 +0000903 segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
904 locations->fTextureMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000905 #else
bsalomon@google.com91961302011-05-09 18:39:58 +0000906 segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
907 locations->fTextureMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000908 #endif
909 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
910 varyingDims = coordDims;
911 } else {
912 varyingDims = coordDims + 1;
913 }
914 }
915
bsalomon@google.com91961302011-05-09 18:39:58 +0000916 GrStringBuilder samplerName;
junov@google.comf93e7172011-03-31 21:26:24 +0000917 sampler_name(stageNum, &samplerName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000918 segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
919 locations->fSamplerUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000920
bsalomon@google.com91961302011-05-09 18:39:58 +0000921 GrStringBuilder texelSizeName;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000922 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
923 normalized_texel_size_name(stageNum, &texelSizeName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000924 segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000925 }
926
bsalomon@google.com91961302011-05-09 18:39:58 +0000927 segments->fVaryings.appendf("varying %s %s;\n",
928 float_vector_type(varyingDims), varyingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000929
930 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
931 GrAssert(varyingDims == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000932 segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
junov@google.comf93e7172011-03-31 21:26:24 +0000933 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000934 // varying = texMatrix * texCoord
935 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
936 varyingName.c_str(), texMName.c_str(),
937 vsInCoord, vector_all_coords(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000938 }
939
bsalomon@google.com91961302011-05-09 18:39:58 +0000940 GrStringBuilder radial2ParamsName;
junov@google.comf93e7172011-03-31 21:26:24 +0000941 radial2_param_name(stageNum, &radial2ParamsName);
942 // for radial grads without perspective we can pass the linear
943 // part of the quadratic as a varying.
bsalomon@google.com91961302011-05-09 18:39:58 +0000944 GrStringBuilder radial2VaryingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000945 radial2_varying_name(stageNum, &radial2VaryingName);
946
947 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
948
bsalomon@google.comdcf1b0b2011-05-11 19:00:54 +0000949 segments->fVSUnis.appendf("uniform %s float %s[6];\n",
bsalomon@google.com91961302011-05-09 18:39:58 +0000950 GrPrecision(), radial2ParamsName.c_str());
951 segments->fFSUnis.appendf("uniform float %s[6];\n",
952 radial2ParamsName.c_str());
953 locations->fRadial2Uni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000954
955 // if there is perspective we don't interpolate this
956 if (varyingDims == coordDims) {
957 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000958 segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000959
bsalomon@google.com91961302011-05-09 18:39:58 +0000960 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
961 segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
962 radial2VaryingName.c_str(), radial2ParamsName.c_str(),
963 varyingName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000964 }
965 }
966
967 /// Fragment Shader Stuff
bsalomon@google.com91961302011-05-09 18:39:58 +0000968 GrStringBuilder fsCoordName;
junov@google.comf93e7172011-03-31 21:26:24 +0000969 // function used to access the shader, may be made projective
bsalomon@google.com91961302011-05-09 18:39:58 +0000970 GrStringBuilder texFunc("texture2D");
junov@google.comf93e7172011-03-31 21:26:24 +0000971 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
972 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
973 GrAssert(varyingDims == coordDims);
974 fsCoordName = varyingName;
975 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000976 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +0000977 // our final tex coords then when in perspective we have to
bsalomon@google.com91961302011-05-09 18:39:58 +0000978 // do an explicit divide. Otherwise, we can use a Proj func.
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000979 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
980 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000981 texFunc.append("Proj");
junov@google.comf93e7172011-03-31 21:26:24 +0000982 fsCoordName = varyingName;
983 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000984 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000985 fsCoordName.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000986 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
987 float_vector_type(coordDims),
988 fsCoordName.c_str(),
989 varyingName.c_str(),
990 vector_nonhomog_coords(varyingDims),
991 varyingName.c_str(),
992 vector_homog_coord(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000993 }
994 }
995
bsalomon@google.comfc296292011-05-06 13:53:47 +0000996 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000997 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +0000998 switch (desc.fCoordMapping) {
999 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
1000 sampleCoords = fsCoordName;
1001 break;
1002 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +00001003 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 +00001004 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001005 break;
1006 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +00001007 sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001008 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001009 break;
1010 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.com91961302011-05-09 18:39:58 +00001011 GrStringBuilder cName("c");
1012 GrStringBuilder ac4Name("ac4");
1013 GrStringBuilder rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +00001014
bsalomon@google.comfc296292011-05-06 13:53:47 +00001015 cName.appendS32(stageNum);
1016 ac4Name.appendS32(stageNum);
1017 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +00001018
bsalomon@google.com91961302011-05-09 18:39:58 +00001019 // if we were able to interpolate the linear component bVar is the varying
1020 // otherwise compute it
1021 GrStringBuilder bVar;
junov@google.comf93e7172011-03-31 21:26:24 +00001022 if (coordDims == varyingDims) {
1023 bVar = radial2VaryingName;
1024 GrAssert(2 == varyingDims);
1025 } else {
1026 GrAssert(3 == varyingDims);
1027 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +00001028 bVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001029 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
1030 bVar.c_str(), radial2ParamsName.c_str(),
1031 fsCoordName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001032 }
1033
bsalomon@google.com91961302011-05-09 18:39:58 +00001034 // c = (x^2)+(y^2) - params[4]
1035 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
1036 cName.c_str(), fsCoordName.c_str(),
1037 fsCoordName.c_str(),
1038 radial2ParamsName.c_str());
1039 // ac4 = 4.0 * params[0] * c
1040 segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
1041 ac4Name.c_str(), radial2ParamsName.c_str(),
1042 cName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001043
bsalomon@google.com91961302011-05-09 18:39:58 +00001044 // root = sqrt(b^2-4ac)
1045 // (abs to avoid exception due to fp precision)
1046 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
1047 rootName.c_str(), bVar.c_str(), bVar.c_str(),
1048 ac4Name.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001049
bsalomon@google.com91961302011-05-09 18:39:58 +00001050 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
1051 // y coord is 0.5 (texture is effectively 1D)
1052 sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
1053 bVar.c_str(), radial2ParamsName.c_str(),
1054 rootName.c_str(), radial2ParamsName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001055 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001056 break;}
1057 };
1058
bsalomon@google.com91961302011-05-09 18:39:58 +00001059 const char* smear;
1060 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
1061 smear = ".aaaa";
1062 } else {
1063 smear = "";
1064 }
1065 GrStringBuilder modulate;
1066 if (NULL != fsInColor) {
1067 modulate.printf(" * %s", fsInColor);
1068 }
1069
junov@google.com6acc9b32011-05-16 18:32:07 +00001070 if (desc.fOptFlags &
1071 ProgramDesc::StageDesc::kCustomTextureDomain_OptFlagBit) {
1072 GrStringBuilder texDomainName;
1073 tex_domain_name(stageNum, &texDomainName);
1074 segments->fFSUnis.appendf("uniform %s %s;\n",
1075 float_vector_type(4),
1076 texDomainName.c_str());
1077 GrStringBuilder coordVar("clampCoord");
1078 segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
1079 float_vector_type(coordDims),
1080 coordVar.c_str(),
1081 sampleCoords.c_str(),
1082 texDomainName.c_str(),
1083 texDomainName.c_str());
1084 sampleCoords = coordVar;
1085 locations->fTexDomUni = kUseUniform;
1086 }
1087
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001088 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001089 locations->fNormalizedTexelSizeUni = kUseUniform;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001090 if (complexCoord) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001091 // assign the coord to a var rather than compute 4x.
1092 GrStringBuilder coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +00001093 coordVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001094 segments->fFSCode.appendf("\t%s %s = %s;\n",
1095 float_vector_type(coordDims),
1096 coordVar.c_str(), sampleCoords.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001097 sampleCoords = coordVar;
1098 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001099 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +00001100 GrStringBuilder accumVar("accum");
1101 accumVar.appendS32(stageNum);
1102 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);
1103 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);
1104 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);
1105 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);
1106 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001107 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +00001108 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 +00001109 }
junov@google.comf93e7172011-03-31 21:26:24 +00001110
1111 if(fStageEffects[stageNum]) {
1112 fStageEffects[stageNum]->genShaderCode(segments);
1113 }
1114}
1115