blob: 4290c96a6ec23cffb673d246edee4b91d1e9baca [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
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000022#include "SkTrace.h"
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) {
tomhudson@google.com0d831722011-06-02 15:37:14 +000089 static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)",
bsalomon@google.comf2d91552011-05-16 20:56:06 +000090 "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) {
tomhudson@google.com0d831722011-06-02 15:37:14 +000096 static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)",
bsalomon@google.comf2d91552011-05-16 20:56:06 +000097 "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
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000102static inline const char* declared_color_output_name() { return "fsColorOut"; }
103static inline const char* dual_source_output_name() { return "dualSourceOut"; }
104
junov@google.comf93e7172011-03-31 21:26:24 +0000105static void tex_matrix_name(int stage, GrStringBuilder* s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000106#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000107 *s = "aTexM";
108#else
109 *s = "uTexM";
110#endif
bsalomon@google.comfc296292011-05-06 13:53:47 +0000111 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000112}
113
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000114static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
115 *s = "uTexelSize";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000116 s->appendS32(stage);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000117}
118
junov@google.comf93e7172011-03-31 21:26:24 +0000119static void sampler_name(int stage, GrStringBuilder* s) {
120 *s = "uSampler";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000121 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000122}
123
124static void stage_varying_name(int stage, GrStringBuilder* s) {
125 *s = "vStage";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000126 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000127}
128
129static void radial2_param_name(int stage, GrStringBuilder* s) {
130 *s = "uRadial2Params";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000131 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000132}
133
134static void radial2_varying_name(int stage, GrStringBuilder* s) {
135 *s = "vB";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000136 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000137}
138
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000139static void convolve_param_names(int stage, GrStringBuilder* k, GrStringBuilder* i) {
140 *k = "uKernel";
141 k->appendS32(stage);
142 *i = "uImageIncrement";
143 i->appendS32(stage);
144}
145
junov@google.com6acc9b32011-05-16 18:32:07 +0000146static void tex_domain_name(int stage, GrStringBuilder* s) {
147 *s = "uTexDom";
148 s->appendS32(stage);
149}
150
junov@google.comf93e7172011-03-31 21:26:24 +0000151GrGLProgram::GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000152}
153
154GrGLProgram::~GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000155}
156
tomhudson@google.com0d3f1fb2011-06-01 19:27:31 +0000157void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000158 GrBlendCoeff* dstCoeff) const {
159 switch (fProgramDesc.fDualSrcOutput) {
160 case ProgramDesc::kNone_DualSrcOutput:
161 break;
162 // the prog will write a coverage value to the secondary
163 // output and the dst is blended by one minus that value.
164 case ProgramDesc::kCoverage_DualSrcOutput:
165 case ProgramDesc::kCoverageISA_DualSrcOutput:
166 case ProgramDesc::kCoverageISC_DualSrcOutput:
167 *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_BlendCoeff;
168 break;
169 default:
170 GrCrash("Unexpected dual source blend output");
171 break;
172 }
173}
174
junov@google.comf93e7172011-03-31 21:26:24 +0000175void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
176 // Add stage configuration to the key
tomhudson@google.com0d3f1fb2011-06-01 19:27:31 +0000177 key.keyData(reinterpret_cast<const uint32_t*>(&fProgramDesc), sizeof(ProgramDesc));
junov@google.comf93e7172011-03-31 21:26:24 +0000178}
179
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000180// assigns modulation of two vars to an output var
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000181// vars can be vec4s or floats (or one of each)
182// result is always vec4
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000183// if either var is "" then assign to the other var
184// if both are "" then assign all ones
185static inline void modulate_helper(const char* outputVar,
186 const char* var0,
187 const char* var1,
188 GrStringBuilder* code) {
189 GrAssert(NULL != outputVar);
190 GrAssert(NULL != var0);
191 GrAssert(NULL != var1);
192 GrAssert(NULL != code);
193
194 bool has0 = '\0' != *var0;
195 bool has1 = '\0' != *var1;
196
197 if (!has0 && !has1) {
198 code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4));
199 } else if (!has0) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000200 code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000201 } else if (!has1) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000202 code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000203 } else {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000204 code->appendf("\t%s = vec4(%s * %s);\n", outputVar, var0, var1);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000205 }
206}
207
208// assigns addition of two vars to an output var
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000209// vars can be vec4s or floats (or one of each)
210// result is always vec4
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000211// if either var is "" then assign to the other var
212// if both are "" then assign all zeros
213static inline void add_helper(const char* outputVar,
214 const char* var0,
215 const char* var1,
216 GrStringBuilder* code) {
217 GrAssert(NULL != outputVar);
218 GrAssert(NULL != var0);
219 GrAssert(NULL != var1);
220 GrAssert(NULL != code);
221
222 bool has0 = '\0' != *var0;
223 bool has1 = '\0' != *var1;
224
225 if (!has0 && !has1) {
226 code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4));
227 } else if (!has0) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000228 code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000229 } else if (!has1) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000230 code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000231 } else {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000232 code->appendf("\t%s = vec4(%s + %s);\n", outputVar, var0, var1);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000233 }
234}
235
236// given two blend coeffecients determine whether the src
237// and/or dst computation can be omitted.
238static inline void needBlendInputs(SkXfermode::Coeff srcCoeff,
239 SkXfermode::Coeff dstCoeff,
240 bool* needSrcValue,
241 bool* needDstValue) {
242 if (SkXfermode::kZero_Coeff == srcCoeff) {
243 switch (dstCoeff) {
244 // these all read the src
245 case SkXfermode::kSC_Coeff:
246 case SkXfermode::kISC_Coeff:
247 case SkXfermode::kSA_Coeff:
248 case SkXfermode::kISA_Coeff:
249 *needSrcValue = true;
250 break;
251 default:
252 *needSrcValue = false;
253 break;
254 }
255 } else {
256 *needSrcValue = true;
257 }
258 if (SkXfermode::kZero_Coeff == dstCoeff) {
259 switch (srcCoeff) {
260 // these all read the dst
261 case SkXfermode::kDC_Coeff:
262 case SkXfermode::kIDC_Coeff:
263 case SkXfermode::kDA_Coeff:
264 case SkXfermode::kIDA_Coeff:
265 *needDstValue = true;
266 break;
267 default:
268 *needDstValue = false;
269 break;
270 }
271 } else {
272 *needDstValue = true;
Scroggo97c88c22011-05-11 14:05:25 +0000273 }
274}
275
276/**
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000277 * Create a blend_coeff * value string to be used in shader code. Sets empty
278 * string if result is trivially zero.
279 */
280static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff,
281 const char* src, const char* dst,
282 const char* value) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000283 switch (coeff) {
284 case SkXfermode::kZero_Coeff: /** 0 */
285 *str = "";
286 break;
287 case SkXfermode::kOne_Coeff: /** 1 */
288 *str = value;
289 break;
290 case SkXfermode::kSC_Coeff:
291 str->printf("(%s * %s)", src, value);
292 break;
293 case SkXfermode::kISC_Coeff:
294 str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value);
295 break;
296 case SkXfermode::kDC_Coeff:
297 str->printf("(%s * %s)", dst, value);
298 break;
299 case SkXfermode::kIDC_Coeff:
300 str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value);
301 break;
302 case SkXfermode::kSA_Coeff: /** src alpha */
303 str->printf("(%s.a * %s)", src, value);
304 break;
305 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
306 str->printf("((1.0 - %s.a) * %s)", src, value);
307 break;
308 case SkXfermode::kDA_Coeff: /** dst alpha */
309 str->printf("(%s.a * %s)", dst, value);
310 break;
311 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
312 str->printf("((1.0 - %s.a) * %s)", dst, value);
313 break;
314 default:
315 GrCrash("Unexpected xfer coeff.");
316 break;
317 }
318}
319/**
Scroggo97c88c22011-05-11 14:05:25 +0000320 * Adds a line to the fragment shader code which modifies the color by
321 * the specified color filter.
322 */
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000323static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar,
tomhudson@google.com0d3f1fb2011-06-01 19:27:31 +0000324 SkXfermode::Coeff uniformCoeff,
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000325 SkXfermode::Coeff colorCoeff,
326 const char* inColor) {
327 GrStringBuilder colorStr, constStr;
328 blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME,
329 inColor, inColor);
330 blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME,
331 inColor, COL_FILTER_UNI_NAME);
332
333 add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
Scroggo97c88c22011-05-11 14:05:25 +0000334}
335
bsalomon@google.com91961302011-05-09 18:39:58 +0000336bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000337
338 ShaderCodeSegments segments;
339 const uint32_t& layout = fProgramDesc.fVertexLayout;
340
bsalomon@google.com91961302011-05-09 18:39:58 +0000341 programData->fUniLocations.reset();
junov@google.comf93e7172011-03-31 21:26:24 +0000342
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000343 SkXfermode::Coeff colorCoeff, uniformCoeff;
344 // The rest of transfer mode color filters have not been implemented
345 if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
346 GR_DEBUGCODE(bool success =)
tomhudson@google.com0d831722011-06-02 15:37:14 +0000347 SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode>
348 (fProgramDesc.fColorFilterXfermode),
349 &uniformCoeff, &colorCoeff);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000350 GR_DEBUGASSERT(success);
351 } else {
352 colorCoeff = SkXfermode::kOne_Coeff;
353 uniformCoeff = SkXfermode::kZero_Coeff;
354 }
355
356 bool needColorFilterUniform;
357 bool needComputedColor;
358 needBlendInputs(uniformCoeff, colorCoeff,
359 &needColorFilterUniform, &needComputedColor);
360
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000361 // the dual source output has no canonical var name, have to
362 // declare an output, which is incompatible with gl_FragColor/gl_FragData.
363 const char* fsColorOutput;
364 bool dualSourceOutputWritten = false;
tomhudson@google.com0d3f1fb2011-06-01 19:27:31 +0000365 bool usingDeclaredOutputs = ProgramDesc::kNone_DualSrcOutput !=
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000366 fProgramDesc.fDualSrcOutput;
367 if (usingDeclaredOutputs) {
368 GrAssert(0 == segments.fHeader.size());
369 segments.fHeader.printf("#version 150\n");
370 fsColorOutput = declared_color_output_name();
371 segments.fFSOutputs.appendf("out vec4 %s;\n", fsColorOutput);
372 } else {
373 fsColorOutput = "gl_FragColor";
374 }
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
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000412 if (fProgramDesc.fEmitsPointSize){
bsalomon@google.com91961302011-05-09 18:39:58 +0000413 segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000414 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000415
bsalomon@google.com91961302011-05-09 18:39:58 +0000416 segments.fFSCode.append("void main() {\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000417
418 // add texture coordinates that are used to the list of vertex attr decls
bsalomon@google.com91961302011-05-09 18:39:58 +0000419 GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
junov@google.comf93e7172011-03-31 21:26:24 +0000420 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000421 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000422 tex_attr_name(t, texCoordAttrs + t);
bsalomon@google.com91961302011-05-09 18:39:58 +0000423 segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000424 }
425 }
426
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000427 ///////////////////////////////////////////////////////////////////////////
428 // compute the final color
Scroggo97c88c22011-05-11 14:05:25 +0000429
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000430 // if we have color stages string them together, feeding the output color
431 // of each to the next and generating code for each stage.
432 if (needComputedColor) {
433 GrStringBuilder outColor;
434 for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000435 if (fProgramDesc.fStages[s].isEnabled()) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000436 // create var to hold stage result
437 outColor = "color";
438 outColor.appendS32(s);
439 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
440
441 const char* inCoords;
442 // figure out what our input coords are
443 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
444 layout) {
445 inCoords = POS_ATTR_NAME;
Scroggo97c88c22011-05-11 14:05:25 +0000446 } else {
447 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
448 // we better have input tex coordinates if stage is enabled.
449 GrAssert(tcIdx >= 0);
450 GrAssert(texCoordAttrs[tcIdx].size());
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000451 inCoords = texCoordAttrs[tcIdx].c_str();
junov@google.comf93e7172011-03-31 21:26:24 +0000452 }
453
454 genStageCode(s,
455 fProgramDesc.fStages[s],
bsalomon@google.comfc296292011-05-06 13:53:47 +0000456 inColor.size() ? inColor.c_str() : NULL,
457 outColor.c_str(),
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000458 inCoords,
junov@google.comf93e7172011-03-31 21:26:24 +0000459 &segments,
460 &programData->fUniLocations.fStages[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000461 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000462 }
463 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000464 }
Scroggo97c88c22011-05-11 14:05:25 +0000465
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000466 // if have all ones for the "dst" input to the color filter then we can make
467 // additional optimizations.
tomhudson@google.com0d831722011-06-02 15:37:14 +0000468 if (needColorFilterUniform && !inColor.size() &&
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000469 (SkXfermode::kIDC_Coeff == uniformCoeff ||
470 SkXfermode::kIDA_Coeff == uniformCoeff)) {
471 uniformCoeff = SkXfermode::kZero_Coeff;
472 bool bogus;
tomhudson@google.com0d831722011-06-02 15:37:14 +0000473 needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000474 &needColorFilterUniform, &bogus);
475 }
476 if (needColorFilterUniform) {
477 segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
478 programData->fUniLocations.fColorFilterUni = kUseUniform;
479 }
480
481 bool wroteFragColorZero = false;
tomhudson@google.com0d831722011-06-02 15:37:14 +0000482 if (SkXfermode::kZero_Coeff == uniformCoeff &&
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000483 SkXfermode::kZero_Coeff == colorCoeff) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000484 segments.fFSCode.appendf("\t%s = %s;\n",
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000485 fsColorOutput,
486 all_zeros_vec(4));
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000487 wroteFragColorZero = true;
488 } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
489 segments.fFSCode.appendf("\tvec4 filteredColor;\n");
490 const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4);
tomhudson@google.com0d831722011-06-02 15:37:14 +0000491 addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000492 colorCoeff, color);
493 inColor = "filteredColor";
494 }
495
496 ///////////////////////////////////////////////////////////////////////////
497 // compute the partial coverage (coverage stages and edge aa)
498
499 GrStringBuilder inCoverage;
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000500
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000501 // we don't need to compute coverage at all if we know the final shader
502 // output will be zero and we don't have a dual src blend output.
503 if (!wroteFragColorZero ||
504 ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000505 if (fProgramDesc.fEdgeAANumEdges > 0) {
506 segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[");
507 segments.fFSUnis.appendS32(fProgramDesc.fEdgeAANumEdges);
508 segments.fFSUnis.append("];\n");
509 programData->fUniLocations.fEdgesUni = kUseUniform;
510 int count = fProgramDesc.fEdgeAANumEdges;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000511 segments.fFSCode.append(
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000512 "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n");
513 for (int i = 0; i < count; i++) {
514 segments.fFSCode.append("\tfloat a");
515 segments.fFSCode.appendS32(i);
516 segments.fFSCode.append(" = clamp(dot(" EDGES_UNI_NAME "[");
517 segments.fFSCode.appendS32(i);
518 segments.fFSCode.append("], pos), 0.0, 1.0);\n");
519 }
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000520 if (fProgramDesc.fEdgeAAConcave && (count & 0x01) == 0) {
521 // For concave polys, we consider the edges in pairs.
522 segments.fFSFunctions.append("float cross2(vec2 a, vec2 b) {\n");
523 segments.fFSFunctions.append("\treturn dot(a, vec2(b.y, -b.x));\n");
524 segments.fFSFunctions.append("}\n");
525 for (int i = 0; i < count; i += 2) {
526 segments.fFSCode.appendf("\tfloat eb%d;\n", i / 2);
527 segments.fFSCode.appendf("\tif (cross2(" EDGES_UNI_NAME "[%d].xy, " EDGES_UNI_NAME "[%d].xy) < 0.0) {\n", i, i + 1);
528 segments.fFSCode.appendf("\t\teb%d = a%d * a%d;\n", i / 2, i, i + 1);
529 segments.fFSCode.append("\t} else {\n");
530 segments.fFSCode.appendf("\t\teb%d = a%d + a%d - a%d * a%d;\n", i / 2, i, i + 1, i, i + 1);
531 segments.fFSCode.append("\t}\n");
532 }
533 segments.fFSCode.append("\tfloat edgeAlpha = ");
534 for (int i = 0; i < count / 2 - 1; i++) {
535 segments.fFSCode.appendf("min(eb%d, ", i);
536 }
537 segments.fFSCode.appendf("eb%d", count / 2 - 1);
538 for (int i = 0; i < count / 2 - 1; i++) {
539 segments.fFSCode.append(")");
540 }
541 segments.fFSCode.append(";\n");
542 } else {
543 segments.fFSCode.append("\tfloat edgeAlpha = ");
544 for (int i = 0; i < count - 1; i++) {
545 segments.fFSCode.appendf("min(a%d * a%d, ", i, i + 1);
546 }
547 segments.fFSCode.appendf("a%d * a0", count - 1);
548 for (int i = 0; i < count - 1; i++) {
549 segments.fFSCode.append(")");
550 }
551 segments.fFSCode.append(";\n");
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000552 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000553 inCoverage = "edgeAlpha";
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000554 }
555
556 GrStringBuilder outCoverage;
557 const int& startStage = fProgramDesc.fFirstCoverageStage;
558 for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000559 if (fProgramDesc.fStages[s].isEnabled()) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000560 // create var to hold stage output
561 outCoverage = "coverage";
562 outCoverage.appendS32(s);
563 segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
564
565 const char* inCoords;
566 // figure out what our input coords are
567 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
568 inCoords = POS_ATTR_NAME;
569 } else {
570 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
571 // we better have input tex coordinates if stage is enabled.
572 GrAssert(tcIdx >= 0);
573 GrAssert(texCoordAttrs[tcIdx].size());
574 inCoords = texCoordAttrs[tcIdx].c_str();
575 }
576
577 genStageCode(s,
578 fProgramDesc.fStages[s],
579 inCoverage.size() ? inCoverage.c_str() : NULL,
580 outCoverage.c_str(),
581 inCoords,
582 &segments,
583 &programData->fUniLocations.fStages[s]);
584 inCoverage = outCoverage;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000585 }
586 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000587 if (ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000588 segments.fFSOutputs.appendf("out vec4 %s;\n",
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000589 dual_source_output_name());
590 bool outputIsZero = false;
591 GrStringBuilder coeff;
tomhudson@google.com0d831722011-06-02 15:37:14 +0000592 if (ProgramDesc::kCoverage_DualSrcOutput !=
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000593 fProgramDesc.fDualSrcOutput && !wroteFragColorZero) {
594 if (!inColor.size()) {
595 outputIsZero = true;
596 } else {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000597 if (fProgramDesc.fDualSrcOutput ==
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000598 ProgramDesc::kCoverageISA_DualSrcOutput) {
599 coeff.printf("(1 - %s.a)", inColor.c_str());
600 } else {
601 coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str());
602 }
603 }
604 }
605 if (outputIsZero) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000606 segments.fFSCode.appendf("\t%s = %s;\n",
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000607 dual_source_output_name(),
608 all_zeros_vec(4));
609 } else {
610 modulate_helper(dual_source_output_name(),
611 coeff.c_str(),
612 inCoverage.c_str(),
613 &segments.fFSCode);
614 }
615 dualSourceOutputWritten = true;
616 }
junov@google.comf93e7172011-03-31 21:26:24 +0000617 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000618
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000619 ///////////////////////////////////////////////////////////////////////////
620 // combine color and coverage as frag color
621
622 if (!wroteFragColorZero) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000623 modulate_helper(fsColorOutput,
624 inColor.c_str(),
625 inCoverage.c_str(),
626 &segments.fFSCode);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000627 }
628
bsalomon@google.com91961302011-05-09 18:39:58 +0000629 segments.fVSCode.append("}\n");
630 segments.fFSCode.append("}\n");
631
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000632 ///////////////////////////////////////////////////////////////////////////
633 // compile and setup attribs and unis
634
bsalomon@google.com91961302011-05-09 18:39:58 +0000635 if (!CompileFSAndVS(segments, programData)) {
636 return false;
637 }
638
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000639 if (!this->bindOutputsAttribsAndLinkProgram(texCoordAttrs,
640 usingDeclaredOutputs,
641 dualSourceOutputWritten,
642 programData)) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000643 return false;
644 }
645
646 this->getUniformLocationsAndInitCache(programData);
647
648 return true;
649}
650
651bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
652 CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000653
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000654 static const int MAX_STRINGS = 6;
655 const char* strings[MAX_STRINGS];
656 int lengths[MAX_STRINGS];
junov@google.comf93e7172011-03-31 21:26:24 +0000657 int stringCnt = 0;
658
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000659 if (segments.fHeader.size()) {
660 strings[stringCnt] = segments.fHeader.c_str();
661 lengths[stringCnt] = segments.fHeader.size();
662 ++stringCnt;
663 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000664 if (segments.fVSUnis.size()) {
665 strings[stringCnt] = segments.fVSUnis.c_str();
666 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000667 ++stringCnt;
668 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000669 if (segments.fVSAttrs.size()) {
670 strings[stringCnt] = segments.fVSAttrs.c_str();
671 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000672 ++stringCnt;
673 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000674 if (segments.fVaryings.size()) {
675 strings[stringCnt] = segments.fVaryings.c_str();
676 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000677 ++stringCnt;
678 }
679
bsalomon@google.comfc296292011-05-06 13:53:47 +0000680 GrAssert(segments.fVSCode.size());
681 strings[stringCnt] = segments.fVSCode.c_str();
682 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000683 ++stringCnt;
684
685#if PRINT_SHADERS
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000686 GrPrintf(segments.fHeader.c_str());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000687 GrPrintf(segments.fVSUnis.c_str());
688 GrPrintf(segments.fVSAttrs.c_str());
689 GrPrintf(segments.fVaryings.c_str());
690 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000691 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000692#endif
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000693 GrAssert(stringCnt <= MAX_STRINGS);
junov@google.comf93e7172011-03-31 21:26:24 +0000694 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
695 stringCnt,
696 strings,
697 lengths);
698
bsalomon@google.com91961302011-05-09 18:39:58 +0000699 if (!programData->fVShaderID) {
700 return false;
701 }
702
junov@google.comf93e7172011-03-31 21:26:24 +0000703 stringCnt = 0;
704
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000705 if (segments.fHeader.size()) {
706 strings[stringCnt] = segments.fHeader.c_str();
707 lengths[stringCnt] = segments.fHeader.size();
708 ++stringCnt;
709 }
junov@google.comf93e7172011-03-31 21:26:24 +0000710 if (strlen(GrShaderPrecision()) > 1) {
711 strings[stringCnt] = GrShaderPrecision();
712 lengths[stringCnt] = strlen(GrShaderPrecision());
713 ++stringCnt;
714 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000715 if (segments.fFSUnis.size()) {
716 strings[stringCnt] = segments.fFSUnis.c_str();
717 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000718 ++stringCnt;
719 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000720 if (segments.fVaryings.size()) {
721 strings[stringCnt] = segments.fVaryings.c_str();
722 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000723 ++stringCnt;
724 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000725 if (segments.fFSOutputs.size()) {
726 strings[stringCnt] = segments.fFSOutputs.c_str();
727 lengths[stringCnt] = segments.fFSOutputs.size();
728 ++stringCnt;
729 }
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000730 if (segments.fFSFunctions.size()) {
731 strings[stringCnt] = segments.fFSFunctions.c_str();
732 lengths[stringCnt] = segments.fFSFunctions.size();
733 ++stringCnt;
734 }
junov@google.comf93e7172011-03-31 21:26:24 +0000735
bsalomon@google.comfc296292011-05-06 13:53:47 +0000736 GrAssert(segments.fFSCode.size());
737 strings[stringCnt] = segments.fFSCode.c_str();
738 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000739 ++stringCnt;
740
741#if PRINT_SHADERS
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000742 GrPrintf(segments.fHeader.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000743 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000744 GrPrintf(segments.fFSUnis.c_str());
745 GrPrintf(segments.fVaryings.c_str());
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000746 GrPrintf(segments.fFSOutputs.c_str());
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000747 GrPrintf(segments.fFSFunctions.c_str());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000748 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000749 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000750#endif
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000751 GrAssert(stringCnt <= MAX_STRINGS);
junov@google.comf93e7172011-03-31 21:26:24 +0000752 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
753 stringCnt,
754 strings,
755 lengths);
756
bsalomon@google.com91961302011-05-09 18:39:58 +0000757 if (!programData->fFShaderID) {
758 return false;
junov@google.comf93e7172011-03-31 21:26:24 +0000759 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000760
bsalomon@google.com91961302011-05-09 18:39:58 +0000761 return true;
junov@google.comf93e7172011-03-31 21:26:24 +0000762}
763
764GrGLuint GrGLProgram::CompileShader(GrGLenum type,
765 int stringCnt,
766 const char** strings,
767 int* stringLengths) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000768 SK_TRACE_EVENT1("GrGLProgram::CompileShader",
769 "stringCount", SkStringPrintf("%i", stringCnt).c_str());
770
junov@google.comf93e7172011-03-31 21:26:24 +0000771 GrGLuint shader = GR_GL(CreateShader(type));
772 if (0 == shader) {
773 return 0;
774 }
775
776 GrGLint compiled = GR_GL_INIT_ZERO;
777 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
778 GR_GL(CompileShader(shader));
779 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
780
781 if (!compiled) {
782 GrGLint infoLen = GR_GL_INIT_ZERO;
783 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000784 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
junov@google.comf93e7172011-03-31 21:26:24 +0000785 if (infoLen > 0) {
786 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
787 for (int i = 0; i < stringCnt; ++i) {
788 if (NULL == stringLengths || stringLengths[i] < 0) {
789 GrPrintf(strings[i]);
790 } else {
791 GrPrintf("%.*s", stringLengths[i], strings[i]);
792 }
793 }
794 GrPrintf("\n%s", log.get());
795 }
796 GrAssert(!"Shader compilation failed!");
797 GR_GL(DeleteShader(shader));
798 return 0;
799 }
800 return shader;
801}
802
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000803bool GrGLProgram::bindOutputsAttribsAndLinkProgram(
804 GrStringBuilder texCoordAttrNames[],
805 bool bindColorOut,
tomhudson@google.com0d831722011-06-02 15:37:14 +0000806 bool bindDualSrcOut,
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000807 CachedData* programData) const {
bsalomon@google.com91961302011-05-09 18:39:58 +0000808 programData->fProgramID = GR_GL(CreateProgram());
809 if (!programData->fProgramID) {
810 return false;
811 }
812 const GrGLint& progID = programData->fProgramID;
813
814 GR_GL(AttachShader(progID, programData->fVShaderID));
815 GR_GL(AttachShader(progID, programData->fFShaderID));
816
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000817 if (bindColorOut) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000818 GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000819 0, 0, declared_color_output_name()));
820 }
821 if (bindDualSrcOut) {
822 GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
823 0, 1, dual_source_output_name()));
824 }
825
bsalomon@google.com91961302011-05-09 18:39:58 +0000826 // Bind the attrib locations to same values for all shaders
827 GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
828 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
829 if (texCoordAttrNames[t].size()) {
830 GR_GL(BindAttribLocation(progID,
831 TexCoordAttributeIdx(t),
832 texCoordAttrNames[t].c_str()));
833 }
834 }
835
bsalomon@google.com91961302011-05-09 18:39:58 +0000836 if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
837 GR_GL(BindAttribLocation(progID,
838 ViewMatrixAttributeIdx(),
839 VIEW_MATRIX_NAME));
840 }
841
842 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
bsalomon@google.com72b4fcb2011-05-09 20:47:34 +0000843 const StageUniLocations& unis = programData->fUniLocations.fStages[s];
844 if (kSetAsAttribute == unis.fTextureMatrixUni) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000845 GrStringBuilder matName;
846 tex_matrix_name(s, &matName);
847 GR_GL(BindAttribLocation(progID,
848 TextureMatrixAttributeIdx(s),
849 matName.c_str()));
850 }
851 }
852
bsalomon@google.com91961302011-05-09 18:39:58 +0000853 GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
854
855 GR_GL(LinkProgram(progID));
856
857 GrGLint linked = GR_GL_INIT_ZERO;
858 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
859 if (!linked) {
860 GrGLint infoLen = GR_GL_INIT_ZERO;
861 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000862 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
bsalomon@google.com91961302011-05-09 18:39:58 +0000863 if (infoLen > 0) {
864 GR_GL(GetProgramInfoLog(progID,
865 infoLen+1,
866 NULL,
867 (char*)log.get()));
868 GrPrintf((char*)log.get());
869 }
870 GrAssert(!"Error linking program");
871 GR_GL(DeleteProgram(progID));
872 programData->fProgramID = 0;
873 return false;
874 }
875 return true;
876}
877
878void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
879 const GrGLint& progID = programData->fProgramID;
880
881 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
882 programData->fUniLocations.fViewMatrixUni =
883 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
884 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
885 }
886 if (kUseUniform == programData->fUniLocations.fColorUni) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000887 programData->fUniLocations.fColorUni =
bsalomon@google.com91961302011-05-09 18:39:58 +0000888 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
889 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
890 }
Scroggo97c88c22011-05-11 14:05:25 +0000891 if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000892 programData->fUniLocations.fColorFilterUni =
Scroggo97c88c22011-05-11 14:05:25 +0000893 GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
894 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
895 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000896
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000897 if (kUseUniform == programData->fUniLocations.fEdgesUni) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000898 programData->fUniLocations.fEdgesUni =
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000899 GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
900 GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
901 } else {
902 programData->fUniLocations.fEdgesUni = kUnusedUniform;
903 }
904
bsalomon@google.com91961302011-05-09 18:39:58 +0000905 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
906 StageUniLocations& locations = programData->fUniLocations.fStages[s];
tomhudson@google.com0d831722011-06-02 15:37:14 +0000907 if (fProgramDesc.fStages[s].isEnabled()) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000908 if (kUseUniform == locations.fTextureMatrixUni) {
909 GrStringBuilder texMName;
910 tex_matrix_name(s, &texMName);
911 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
912 progID,
913 texMName.c_str()));
914 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
915 }
916
917 if (kUseUniform == locations.fSamplerUni) {
918 GrStringBuilder samplerName;
919 sampler_name(s, &samplerName);
920 locations.fSamplerUni = GR_GL(GetUniformLocation(
921 progID,
922 samplerName.c_str()));
923 GrAssert(kUnusedUniform != locations.fSamplerUni);
924 }
925
926 if (kUseUniform == locations.fNormalizedTexelSizeUni) {
927 GrStringBuilder texelSizeName;
928 normalized_texel_size_name(s, &texelSizeName);
tomhudson@google.com0d831722011-06-02 15:37:14 +0000929 locations.fNormalizedTexelSizeUni =
bsalomon@google.com91961302011-05-09 18:39:58 +0000930 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
931 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
932 }
933
934 if (kUseUniform == locations.fRadial2Uni) {
935 GrStringBuilder radial2ParamName;
936 radial2_param_name(s, &radial2ParamName);
937 locations.fRadial2Uni = GR_GL(GetUniformLocation(
938 progID,
939 radial2ParamName.c_str()));
940 GrAssert(kUnusedUniform != locations.fRadial2Uni);
941 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000942
943 if (kUseUniform == locations.fTexDomUni) {
944 GrStringBuilder texDomName;
945 tex_domain_name(s, &texDomName);
946 locations.fTexDomUni = GR_GL(GetUniformLocation(
947 progID,
948 texDomName.c_str()));
949 GrAssert(kUnusedUniform != locations.fTexDomUni);
950 }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000951
952 GrStringBuilder kernelName, imageIncrementName;
953 convolve_param_names(s, &kernelName, &imageIncrementName);
954 if (kUseUniform == locations.fKernelUni) {
955 locations.fKernelUni = GR_GL(GetUniformLocation(
956 progID,
957 kernelName.c_str()));
958 GrAssert(kUnusedUniform != locations.fKernelUni);
959 }
960
961 if (kUseUniform == locations.fImageIncrementUni) {
962 locations.fImageIncrementUni = GR_GL(GetUniformLocation(
963 progID,
964 imageIncrementName.c_str()));
965 GrAssert(kUnusedUniform != locations.fImageIncrementUni);
966 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000967 }
968 }
969 GR_GL(UseProgram(progID));
970
971 // init sampler unis and set bogus values for state tracking
972 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
973 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
974 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
975 }
976 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
977 programData->fRadial2CenterX1[s] = GR_ScalarMax;
978 programData->fRadial2Radius0[s] = -GR_ScalarMax;
979 programData->fTextureWidth[s] = -1;
980 programData->fTextureHeight[s] = -1;
981 }
982 programData->fViewMatrix = GrMatrix::InvalidMatrix();
983 programData->fColor = GrColor_ILLEGAL;
Scroggo97c88c22011-05-11 14:05:25 +0000984 programData->fColorFilterColor = GrColor_ILLEGAL;
bsalomon@google.com91961302011-05-09 18:39:58 +0000985}
986
junov@google.comf93e7172011-03-31 21:26:24 +0000987//============================================================================
988// Stage code generation
989//============================================================================
990
991void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000992 const GrGLProgram::StageDesc& desc,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000993 const char* fsInColor, // NULL means no incoming color
994 const char* fsOutColor,
995 const char* vsInCoord,
996 ShaderCodeSegments* segments,
997 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000998
999 GrAssert(stageNum >= 0 && stageNum <= 9);
1000
bsalomon@google.com91961302011-05-09 18:39:58 +00001001 GrStringBuilder varyingName;
junov@google.comf93e7172011-03-31 21:26:24 +00001002 stage_varying_name(stageNum, &varyingName);
1003
1004 // First decide how many coords are needed to access the texture
1005 // Right now it's always 2 but we could start using 1D textures for
1006 // gradients.
1007 static const int coordDims = 2;
1008 int varyingDims;
1009 /// Vertex Shader Stuff
1010
1011 // decide whether we need a matrix to transform texture coords
1012 // and whether the varying needs a perspective coord.
bsalomon@google.com91961302011-05-09 18:39:58 +00001013 GrStringBuilder texMName;
junov@google.comf93e7172011-03-31 21:26:24 +00001014 tex_matrix_name(stageNum, &texMName);
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001015 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
junov@google.comf93e7172011-03-31 21:26:24 +00001016 varyingDims = coordDims;
1017 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +00001018 #if GR_GL_ATTRIBUTE_MATRICES
bsalomon@google.com91961302011-05-09 18:39:58 +00001019 segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
1020 locations->fTextureMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +00001021 #else
bsalomon@google.com91961302011-05-09 18:39:58 +00001022 segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
1023 locations->fTextureMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +00001024 #endif
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001025 if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
junov@google.comf93e7172011-03-31 21:26:24 +00001026 varyingDims = coordDims;
1027 } else {
1028 varyingDims = coordDims + 1;
1029 }
1030 }
1031
bsalomon@google.com91961302011-05-09 18:39:58 +00001032 GrStringBuilder samplerName;
junov@google.comf93e7172011-03-31 21:26:24 +00001033 sampler_name(stageNum, &samplerName);
bsalomon@google.com91961302011-05-09 18:39:58 +00001034 segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
1035 locations->fSamplerUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +00001036
bsalomon@google.com91961302011-05-09 18:39:58 +00001037 GrStringBuilder texelSizeName;
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001038 if (StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001039 normalized_texel_size_name(stageNum, &texelSizeName);
bsalomon@google.com91961302011-05-09 18:39:58 +00001040 segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001041 }
1042
tomhudson@google.com0d831722011-06-02 15:37:14 +00001043 segments->fVaryings.appendf("varying %s %s;\n",
bsalomon@google.com91961302011-05-09 18:39:58 +00001044 float_vector_type(varyingDims), varyingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001045
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001046 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
junov@google.comf93e7172011-03-31 21:26:24 +00001047 GrAssert(varyingDims == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +00001048 segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
junov@google.comf93e7172011-03-31 21:26:24 +00001049 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +00001050 // varying = texMatrix * texCoord
1051 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
1052 varyingName.c_str(), texMName.c_str(),
1053 vsInCoord, vector_all_coords(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +00001054 }
1055
bsalomon@google.com91961302011-05-09 18:39:58 +00001056 GrStringBuilder radial2ParamsName;
junov@google.comf93e7172011-03-31 21:26:24 +00001057 radial2_param_name(stageNum, &radial2ParamsName);
1058 // for radial grads without perspective we can pass the linear
1059 // part of the quadratic as a varying.
bsalomon@google.com91961302011-05-09 18:39:58 +00001060 GrStringBuilder radial2VaryingName;
junov@google.comf93e7172011-03-31 21:26:24 +00001061 radial2_varying_name(stageNum, &radial2VaryingName);
1062
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001063 if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping ||
1064 StageDesc::kRadial2GradientDegenerate_CoordMapping == desc.fCoordMapping) {
junov@google.comf93e7172011-03-31 21:26:24 +00001065
tomhudson@google.com0d831722011-06-02 15:37:14 +00001066 segments->fVSUnis.appendf("uniform %s float %s[6];\n",
bsalomon@google.com91961302011-05-09 18:39:58 +00001067 GrPrecision(), radial2ParamsName.c_str());
tomhudson@google.com0d831722011-06-02 15:37:14 +00001068 segments->fFSUnis.appendf("uniform float %s[6];\n",
bsalomon@google.com91961302011-05-09 18:39:58 +00001069 radial2ParamsName.c_str());
1070 locations->fRadial2Uni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +00001071
1072 // if there is perspective we don't interpolate this
1073 if (varyingDims == coordDims) {
1074 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +00001075 segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001076
bsalomon@google.com91961302011-05-09 18:39:58 +00001077 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
1078 segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
1079 radial2VaryingName.c_str(), radial2ParamsName.c_str(),
1080 varyingName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001081 }
1082 }
1083
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001084 GrStringBuilder kernelName, kernelWidthName, imageIncrementName;
1085 convolve_param_names(stageNum, &kernelName, &imageIncrementName);
1086
1087 if (ProgramDesc::StageDesc::kConvolution_FetchMode == desc.fFetchMode) {
1088 segments->fFSUnis.appendf("uniform float %s[%d];\n",
1089 kernelName.c_str(), desc.fKernelWidth);
1090 segments->fFSUnis.appendf("uniform vec2 %s;\n",
1091 imageIncrementName.c_str());
1092 segments->fVSUnis.appendf("uniform vec2 %s;\n",
1093 imageIncrementName.c_str());
1094 locations->fKernelUni = kUseUniform;
1095 locations->fImageIncrementUni = kUseUniform;
1096 float scale = (desc.fKernelWidth - 1) * 0.5f;
1097 segments->fVSCode.appendf("\t%s -= vec2(%g, %g) * %s;\n",
1098 varyingName.c_str(), scale, scale,
1099 imageIncrementName.c_str());
1100}
1101
junov@google.comf93e7172011-03-31 21:26:24 +00001102 /// Fragment Shader Stuff
bsalomon@google.com91961302011-05-09 18:39:58 +00001103 GrStringBuilder fsCoordName;
junov@google.comf93e7172011-03-31 21:26:24 +00001104 // function used to access the shader, may be made projective
bsalomon@google.com91961302011-05-09 18:39:58 +00001105 GrStringBuilder texFunc("texture2D");
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001106 if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
1107 StageDesc::kNoPerspective_OptFlagBit)) {
junov@google.comf93e7172011-03-31 21:26:24 +00001108 GrAssert(varyingDims == coordDims);
1109 fsCoordName = varyingName;
1110 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001111 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +00001112 // our final tex coords then when in perspective we have to
bsalomon@google.com91961302011-05-09 18:39:58 +00001113 // do an explicit divide. Otherwise, we can use a Proj func.
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001114 if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
1115 StageDesc::kSingle_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001116 texFunc.append("Proj");
junov@google.comf93e7172011-03-31 21:26:24 +00001117 fsCoordName = varyingName;
1118 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001119 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +00001120 fsCoordName.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001121 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
1122 float_vector_type(coordDims),
1123 fsCoordName.c_str(),
1124 varyingName.c_str(),
1125 vector_nonhomog_coords(varyingDims),
1126 varyingName.c_str(),
1127 vector_homog_coord(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +00001128 }
1129 }
1130
bsalomon@google.comfc296292011-05-06 13:53:47 +00001131 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001132 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +00001133 switch (desc.fCoordMapping) {
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001134 case StageDesc::kIdentity_CoordMapping:
junov@google.comf93e7172011-03-31 21:26:24 +00001135 sampleCoords = fsCoordName;
1136 break;
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001137 case StageDesc::kSweepGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +00001138 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 +00001139 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001140 break;
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001141 case StageDesc::kRadialGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +00001142 sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001143 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001144 break;
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001145 case StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.com91961302011-05-09 18:39:58 +00001146 GrStringBuilder cName("c");
1147 GrStringBuilder ac4Name("ac4");
1148 GrStringBuilder rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +00001149
bsalomon@google.comfc296292011-05-06 13:53:47 +00001150 cName.appendS32(stageNum);
1151 ac4Name.appendS32(stageNum);
1152 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +00001153
bsalomon@google.com91961302011-05-09 18:39:58 +00001154 // if we were able to interpolate the linear component bVar is the varying
1155 // otherwise compute it
1156 GrStringBuilder bVar;
junov@google.comf93e7172011-03-31 21:26:24 +00001157 if (coordDims == varyingDims) {
1158 bVar = radial2VaryingName;
1159 GrAssert(2 == varyingDims);
1160 } else {
1161 GrAssert(3 == varyingDims);
1162 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +00001163 bVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001164 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
1165 bVar.c_str(), radial2ParamsName.c_str(),
1166 fsCoordName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001167 }
1168
bsalomon@google.com91961302011-05-09 18:39:58 +00001169 // c = (x^2)+(y^2) - params[4]
1170 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
1171 cName.c_str(), fsCoordName.c_str(),
1172 fsCoordName.c_str(),
1173 radial2ParamsName.c_str());
1174 // ac4 = 4.0 * params[0] * c
1175 segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
1176 ac4Name.c_str(), radial2ParamsName.c_str(),
1177 cName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001178
bsalomon@google.com91961302011-05-09 18:39:58 +00001179 // root = sqrt(b^2-4ac)
1180 // (abs to avoid exception due to fp precision)
1181 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
1182 rootName.c_str(), bVar.c_str(), bVar.c_str(),
1183 ac4Name.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001184
bsalomon@google.com91961302011-05-09 18:39:58 +00001185 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
1186 // y coord is 0.5 (texture is effectively 1D)
1187 sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
1188 bVar.c_str(), radial2ParamsName.c_str(),
1189 rootName.c_str(), radial2ParamsName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001190 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001191 break;}
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001192 case StageDesc::kRadial2GradientDegenerate_CoordMapping: {
1193 GrStringBuilder cName("c");
1194
1195 cName.appendS32(stageNum);
1196
1197 // if we were able to interpolate the linear component bVar is the varying
1198 // otherwise compute it
1199 GrStringBuilder bVar;
1200 if (coordDims == varyingDims) {
1201 bVar = radial2VaryingName;
1202 GrAssert(2 == varyingDims);
1203 } else {
1204 GrAssert(3 == varyingDims);
1205 bVar = "b";
1206 bVar.appendS32(stageNum);
1207 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
1208 bVar.c_str(), radial2ParamsName.c_str(),
1209 fsCoordName.c_str(), radial2ParamsName.c_str());
1210 }
1211
1212 // c = (x^2)+(y^2) - params[4]
1213 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
1214 cName.c_str(), fsCoordName.c_str(),
1215 fsCoordName.c_str(),
1216 radial2ParamsName.c_str());
1217
1218 // x coord is: -c/b
1219 // y coord is 0.5 (texture is effectively 1D)
1220 sampleCoords.printf("vec2((-%s / %s), 0.5)", cName.c_str(), bVar.c_str());
1221 complexCoord = true;
1222 break;}
junov@google.comf93e7172011-03-31 21:26:24 +00001223 };
1224
bsalomon@google.com91961302011-05-09 18:39:58 +00001225 const char* smear;
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001226 if (desc.fModulation == StageDesc::kAlpha_Modulation) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001227 smear = ".aaaa";
1228 } else {
1229 smear = "";
1230 }
1231 GrStringBuilder modulate;
1232 if (NULL != fsInColor) {
1233 modulate.printf(" * %s", fsInColor);
1234 }
1235
tomhudson@google.com0d831722011-06-02 15:37:14 +00001236 if (desc.fOptFlags &
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001237 StageDesc::kCustomTextureDomain_OptFlagBit) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001238 GrStringBuilder texDomainName;
1239 tex_domain_name(stageNum, &texDomainName);
tomhudson@google.com0d831722011-06-02 15:37:14 +00001240 segments->fFSUnis.appendf("uniform %s %s;\n",
junov@google.com6acc9b32011-05-16 18:32:07 +00001241 float_vector_type(4),
1242 texDomainName.c_str());
1243 GrStringBuilder coordVar("clampCoord");
1244 segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
1245 float_vector_type(coordDims),
1246 coordVar.c_str(),
1247 sampleCoords.c_str(),
1248 texDomainName.c_str(),
1249 texDomainName.c_str());
1250 sampleCoords = coordVar;
1251 locations->fTexDomUni = kUseUniform;
1252 }
1253
bsalomon@google.com22c5dea2011-07-07 14:38:03 +00001254 if (StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001255 locations->fNormalizedTexelSizeUni = kUseUniform;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001256 if (complexCoord) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001257 // assign the coord to a var rather than compute 4x.
1258 GrStringBuilder coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +00001259 coordVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001260 segments->fFSCode.appendf("\t%s %s = %s;\n",
1261 float_vector_type(coordDims),
1262 coordVar.c_str(), sampleCoords.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001263 sampleCoords = coordVar;
1264 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001265 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +00001266 GrStringBuilder accumVar("accum");
1267 accumVar.appendS32(stageNum);
1268 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);
1269 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);
1270 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);
1271 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);
1272 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001273 } else if (ProgramDesc::StageDesc::kConvolution_FetchMode == desc.fFetchMode) {
1274 segments->fFSCode.append("\tvec4 sum = vec4(0, 0, 0, 0);\n");
1275 segments->fFSCode.appendf("\tvec2 coord = %s;\n", sampleCoords.c_str());
1276 segments->fFSCode.appendf("\tfor (int i = 0; i < %d; i++) {\n", desc.fKernelWidth);
1277 segments->fFSCode.appendf("\t\tsum += %s(%s, coord)%s * %s[i];\n",
1278 texFunc.c_str(), samplerName.c_str(),
1279 smear, kernelName.c_str());
1280 segments->fFSCode.appendf("\t\tcoord += %s;\n",
1281 imageIncrementName.c_str());
1282 segments->fFSCode.appendf("\t}\n");
1283 segments->fFSCode.appendf("\t%s = sum%s;\n", fsOutColor, modulate.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001284 } else {
bsalomon@google.com271cffc2011-05-20 14:13:56 +00001285 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 +00001286 }
junov@google.comf93e7172011-03-31 21:26:24 +00001287}