blob: 0f82d2a40c3f25782c924c4faa09bfddde3ffe83 [file] [log] [blame]
junov@google.comf93e7172011-03-31 21:26:24 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrGLProgram.h"
18
19#include "GrBinHashKey.h"
20#include "GrGLConfig.h"
junov@google.comf93e7172011-03-31 21:26:24 +000021#include "GrMemory.h"
junov@google.comf93e7172011-03-31 21:26:24 +000022
Scroggo97c88c22011-05-11 14:05:25 +000023#include "SkXfermode.h"
24
junov@google.comf93e7172011-03-31 21:26:24 +000025namespace {
26
27const char* GrPrecision() {
28 if (GR_GL_SUPPORT_ES2) {
29 return "mediump";
30 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +000031 return " ";
junov@google.comf93e7172011-03-31 21:26:24 +000032 }
33}
34
35const char* GrShaderPrecision() {
36 if (GR_GL_SUPPORT_ES2) {
37 return "precision mediump float;\n";
38 } else {
39 return "";
40 }
41}
42
43} // namespace
44
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000045#define PRINT_SHADERS 0
46
bsalomon@google.com4be283f2011-04-19 21:15:09 +000047#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000048 #define VIEW_MATRIX_NAME "aViewM"
49#else
50 #define VIEW_MATRIX_NAME "uViewM"
51#endif
52
53#define POS_ATTR_NAME "aPosition"
54#define COL_ATTR_NAME "aColor"
bsalomon@google.com4be283f2011-04-19 21:15:09 +000055#define COL_UNI_NAME "uColor"
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +000056#define EDGES_UNI_NAME "uEdges"
Scroggo97c88c22011-05-11 14:05:25 +000057#define COL_FILTER_UNI_NAME "uColorFilter"
junov@google.comf93e7172011-03-31 21:26:24 +000058
junov@google.comf93e7172011-03-31 21:26:24 +000059static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
60 *s = "aTexCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +000061 s->appendS32(coordIdx);
junov@google.comf93e7172011-03-31 21:26:24 +000062}
63
64static inline const char* float_vector_type(int count) {
65 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
66 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
67 return FLOAT_VECS[count];
68}
69
70static inline const char* vector_homog_coord(int count) {
71 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
72 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
73 return HOMOGS[count];
74}
75
76static inline const char* vector_nonhomog_coords(int count) {
77 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
78 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
79 return NONHOMOGS[count];
80}
81
82static inline const char* vector_all_coords(int count) {
83 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
84 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
85 return ALL[count];
86}
87
bsalomon@google.comf2d91552011-05-16 20:56:06 +000088static inline const char* all_ones_vec(int count) {
89 static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)",
90 "vec3(1,1,1)", "vec4(1,1,1,1)"};
91 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ONESVEC));
92 return ONESVEC[count];
93}
94
95static inline const char* all_zeros_vec(int count) {
96 static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)",
97 "vec3(0,0,0)", "vec4(0,0,0,0)"};
98 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ZEROSVEC));
99 return ZEROSVEC[count];
100}
101
junov@google.comf93e7172011-03-31 21:26:24 +0000102static void tex_matrix_name(int stage, GrStringBuilder* s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000103#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000104 *s = "aTexM";
105#else
106 *s = "uTexM";
107#endif
bsalomon@google.comfc296292011-05-06 13:53:47 +0000108 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000109}
110
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000111static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
112 *s = "uTexelSize";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000113 s->appendS32(stage);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000114}
115
junov@google.comf93e7172011-03-31 21:26:24 +0000116static void sampler_name(int stage, GrStringBuilder* s) {
117 *s = "uSampler";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000118 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000119}
120
121static void stage_varying_name(int stage, GrStringBuilder* s) {
122 *s = "vStage";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000123 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000124}
125
126static void radial2_param_name(int stage, GrStringBuilder* s) {
127 *s = "uRadial2Params";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000128 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000129}
130
131static void radial2_varying_name(int stage, GrStringBuilder* s) {
132 *s = "vB";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000133 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000134}
135
junov@google.com6acc9b32011-05-16 18:32:07 +0000136static void tex_domain_name(int stage, GrStringBuilder* s) {
137 *s = "uTexDom";
138 s->appendS32(stage);
139}
140
junov@google.comf93e7172011-03-31 21:26:24 +0000141GrGLProgram::GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000142}
143
144GrGLProgram::~GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000145}
146
147void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
148 // Add stage configuration to the key
149 key.keyData(reinterpret_cast<const uint8_t*>(&fProgramDesc), sizeof(ProgramDesc));
junov@google.comf93e7172011-03-31 21:26:24 +0000150}
151
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000152// assigns modulation of two vars to an output var
153// if either var is "" then assign to the other var
154// if both are "" then assign all ones
155static inline void modulate_helper(const char* outputVar,
156 const char* var0,
157 const char* var1,
158 GrStringBuilder* code) {
159 GrAssert(NULL != outputVar);
160 GrAssert(NULL != var0);
161 GrAssert(NULL != var1);
162 GrAssert(NULL != code);
163
164 bool has0 = '\0' != *var0;
165 bool has1 = '\0' != *var1;
166
167 if (!has0 && !has1) {
168 code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4));
169 } else if (!has0) {
170 code->appendf("\t%s = %s;\n", outputVar, var1);
171 } else if (!has1) {
172 code->appendf("\t%s = %s;\n", outputVar, var0);
173 } else {
174 code->appendf("\t%s = %s * %s;\n", outputVar, var0, var1);
175 }
176}
177
178// assigns addition of two vars to an output var
179// if either var is "" then assign to the other var
180// if both are "" then assign all zeros
181static inline void add_helper(const char* outputVar,
182 const char* var0,
183 const char* var1,
184 GrStringBuilder* code) {
185 GrAssert(NULL != outputVar);
186 GrAssert(NULL != var0);
187 GrAssert(NULL != var1);
188 GrAssert(NULL != code);
189
190 bool has0 = '\0' != *var0;
191 bool has1 = '\0' != *var1;
192
193 if (!has0 && !has1) {
194 code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4));
195 } else if (!has0) {
196 code->appendf("\t%s = %s;\n", outputVar, var1);
197 } else if (!has1) {
198 code->appendf("\t%s = %s;\n", outputVar, var0);
199 } else {
200 code->appendf("\t%s = %s + %s;\n", outputVar, var0, var1);
201 }
202}
203
204// given two blend coeffecients determine whether the src
205// and/or dst computation can be omitted.
206static inline void needBlendInputs(SkXfermode::Coeff srcCoeff,
207 SkXfermode::Coeff dstCoeff,
208 bool* needSrcValue,
209 bool* needDstValue) {
210 if (SkXfermode::kZero_Coeff == srcCoeff) {
211 switch (dstCoeff) {
212 // these all read the src
213 case SkXfermode::kSC_Coeff:
214 case SkXfermode::kISC_Coeff:
215 case SkXfermode::kSA_Coeff:
216 case SkXfermode::kISA_Coeff:
217 *needSrcValue = true;
218 break;
219 default:
220 *needSrcValue = false;
221 break;
222 }
223 } else {
224 *needSrcValue = true;
225 }
226 if (SkXfermode::kZero_Coeff == dstCoeff) {
227 switch (srcCoeff) {
228 // these all read the dst
229 case SkXfermode::kDC_Coeff:
230 case SkXfermode::kIDC_Coeff:
231 case SkXfermode::kDA_Coeff:
232 case SkXfermode::kIDA_Coeff:
233 *needDstValue = true;
234 break;
235 default:
236 *needDstValue = false;
237 break;
238 }
239 } else {
240 *needDstValue = true;
Scroggo97c88c22011-05-11 14:05:25 +0000241 }
242}
243
244/**
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000245 * Create a blend_coeff * value string to be used in shader code. Sets empty
246 * string if result is trivially zero.
247 */
248static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff,
249 const char* src, const char* dst,
250 const char* value) {
251
252 switch (coeff) {
253 case SkXfermode::kZero_Coeff: /** 0 */
254 *str = "";
255 break;
256 case SkXfermode::kOne_Coeff: /** 1 */
257 *str = value;
258 break;
259 case SkXfermode::kSC_Coeff:
260 str->printf("(%s * %s)", src, value);
261 break;
262 case SkXfermode::kISC_Coeff:
263 str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value);
264 break;
265 case SkXfermode::kDC_Coeff:
266 str->printf("(%s * %s)", dst, value);
267 break;
268 case SkXfermode::kIDC_Coeff:
269 str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value);
270 break;
271 case SkXfermode::kSA_Coeff: /** src alpha */
272 str->printf("(%s.a * %s)", src, value);
273 break;
274 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
275 str->printf("((1.0 - %s.a) * %s)", src, value);
276 break;
277 case SkXfermode::kDA_Coeff: /** dst alpha */
278 str->printf("(%s.a * %s)", dst, value);
279 break;
280 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
281 str->printf("((1.0 - %s.a) * %s)", dst, value);
282 break;
283 default:
284 GrCrash("Unexpected xfer coeff.");
285 break;
286 }
287}
288/**
Scroggo97c88c22011-05-11 14:05:25 +0000289 * Adds a line to the fragment shader code which modifies the color by
290 * the specified color filter.
291 */
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000292static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar,
293 SkXfermode::Coeff uniformCoeff,
294 SkXfermode::Coeff colorCoeff,
295 const char* inColor) {
296 GrStringBuilder colorStr, constStr;
297 blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME,
298 inColor, inColor);
299 blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME,
300 inColor, COL_FILTER_UNI_NAME);
301
302 add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
Scroggo97c88c22011-05-11 14:05:25 +0000303}
304
bsalomon@google.com91961302011-05-09 18:39:58 +0000305bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000306
307 ShaderCodeSegments segments;
308 const uint32_t& layout = fProgramDesc.fVertexLayout;
309
bsalomon@google.com91961302011-05-09 18:39:58 +0000310 programData->fUniLocations.reset();
junov@google.comf93e7172011-03-31 21:26:24 +0000311
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000312 SkXfermode::Coeff colorCoeff, uniformCoeff;
313 // The rest of transfer mode color filters have not been implemented
314 if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
315 GR_DEBUGCODE(bool success =)
316 SkXfermode::ModeAsCoeff(fProgramDesc.fColorFilterXfermode, &uniformCoeff, &colorCoeff);
317 GR_DEBUGASSERT(success);
318 } else {
319 colorCoeff = SkXfermode::kOne_Coeff;
320 uniformCoeff = SkXfermode::kZero_Coeff;
321 }
322
323 bool needColorFilterUniform;
324 bool needComputedColor;
325 needBlendInputs(uniformCoeff, colorCoeff,
326 &needColorFilterUniform, &needComputedColor);
327
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000328#if GR_GL_ATTRIBUTE_MATRICES
329 segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000330 programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000331#else
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000332 segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000333 programData->fUniLocations.fViewMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000334#endif
335 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000336
bsalomon@google.com91961302011-05-09 18:39:58 +0000337 segments.fVSCode.append(
338 "void main() {\n"
339 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
340 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000341
bsalomon@google.com91961302011-05-09 18:39:58 +0000342 // incoming color to current stage being processed.
343 GrStringBuilder inColor;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000344
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000345 if (needComputedColor) {
346 switch (fProgramDesc.fColorType) {
347 case ProgramDesc::kAttribute_ColorType:
348 segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
349 segments.fVaryings.append("varying vec4 vColor;\n");
350 segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
351 inColor = "vColor";
352 break;
353 case ProgramDesc::kUniform_ColorType:
354 segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
355 programData->fUniLocations.fColorUni = kUseUniform;
356 inColor = COL_UNI_NAME;
357 break;
358 default:
359 GrAssert(ProgramDesc::kNone_ColorType == fProgramDesc.fColorType);
360 break;
361 }
junov@google.comf93e7172011-03-31 21:26:24 +0000362 }
363
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000364 if (fProgramDesc.fUsesEdgeAA) {
365 segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[6];\n");
senorblanco@chromium.orgdb2566b2011-05-17 19:11:04 +0000366 programData->fUniLocations.fEdgesUni = kUseUniform;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000367 }
368
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000369 if (fProgramDesc.fEmitsPointSize){
bsalomon@google.com91961302011-05-09 18:39:58 +0000370 segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000371 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000372
bsalomon@google.com91961302011-05-09 18:39:58 +0000373 segments.fFSCode.append("void main() {\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000374
375 // add texture coordinates that are used to the list of vertex attr decls
bsalomon@google.com91961302011-05-09 18:39:58 +0000376 GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
junov@google.comf93e7172011-03-31 21:26:24 +0000377 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000378 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000379 tex_attr_name(t, texCoordAttrs + t);
bsalomon@google.com91961302011-05-09 18:39:58 +0000380 segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000381 }
382 }
383
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000384 ///////////////////////////////////////////////////////////////////////////
385 // compute the final color
Scroggo97c88c22011-05-11 14:05:25 +0000386
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000387 // if we have color stages string them together, feeding the output color
388 // of each to the next and generating code for each stage.
389 if (needComputedColor) {
390 GrStringBuilder outColor;
391 for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
Scroggo97c88c22011-05-11 14:05:25 +0000392 if (fProgramDesc.fStages[s].fEnabled) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000393 // create var to hold stage result
394 outColor = "color";
395 outColor.appendS32(s);
396 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
397
398 const char* inCoords;
399 // figure out what our input coords are
400 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
401 layout) {
402 inCoords = POS_ATTR_NAME;
Scroggo97c88c22011-05-11 14:05:25 +0000403 } else {
404 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
405 // we better have input tex coordinates if stage is enabled.
406 GrAssert(tcIdx >= 0);
407 GrAssert(texCoordAttrs[tcIdx].size());
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000408 inCoords = texCoordAttrs[tcIdx].c_str();
junov@google.comf93e7172011-03-31 21:26:24 +0000409 }
410
411 genStageCode(s,
412 fProgramDesc.fStages[s],
bsalomon@google.comfc296292011-05-06 13:53:47 +0000413 inColor.size() ? inColor.c_str() : NULL,
414 outColor.c_str(),
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000415 inCoords,
junov@google.comf93e7172011-03-31 21:26:24 +0000416 &segments,
417 &programData->fUniLocations.fStages[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000418 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000419 }
420 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000421 }
Scroggo97c88c22011-05-11 14:05:25 +0000422
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000423 // if have all ones for the "dst" input to the color filter then we can make
424 // additional optimizations.
425 if (needColorFilterUniform && !inColor.size() &&
426 (SkXfermode::kIDC_Coeff == uniformCoeff ||
427 SkXfermode::kIDA_Coeff == uniformCoeff)) {
428 uniformCoeff = SkXfermode::kZero_Coeff;
429 bool bogus;
430 needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
431 &needColorFilterUniform, &bogus);
432 }
433 if (needColorFilterUniform) {
434 segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
435 programData->fUniLocations.fColorFilterUni = kUseUniform;
436 }
437
438 bool wroteFragColorZero = false;
439 if (SkXfermode::kZero_Coeff == uniformCoeff &&
440 SkXfermode::kZero_Coeff == colorCoeff) {
441 segments.fFSCode.appendf("\tgl_FragColor = %s;\n", all_zeros_vec(4));
442 wroteFragColorZero = true;
443 } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
444 segments.fFSCode.appendf("\tvec4 filteredColor;\n");
445 const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4);
446 addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
447 colorCoeff, color);
448 inColor = "filteredColor";
449 }
450
451 ///////////////////////////////////////////////////////////////////////////
452 // compute the partial coverage (coverage stages and edge aa)
453
454 GrStringBuilder inCoverage;
455 bool coverageIsScalar = false;
456
457 // we will want to compute coverage for some blend when there is no
458 // color (when dual source blending is enabled). But for now we have this if
459 if (!wroteFragColorZero) {
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000460 if (fProgramDesc.fUsesEdgeAA) {
461 // FIXME: put the a's in a loop
462 segments.fFSCode.append(
463 "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n"
464 "\tfloat a0 = clamp(dot(uEdges[0], pos), 0.0, 1.0);\n"
465 "\tfloat a1 = clamp(dot(uEdges[1], pos), 0.0, 1.0);\n"
466 "\tfloat a2 = clamp(dot(uEdges[2], pos), 0.0, 1.0);\n"
467 "\tfloat a3 = clamp(dot(uEdges[3], pos), 0.0, 1.0);\n"
468 "\tfloat a4 = clamp(dot(uEdges[4], pos), 0.0, 1.0);\n"
469 "\tfloat a5 = clamp(dot(uEdges[5], pos), 0.0, 1.0);\n"
470 "\tfloat edgeAlpha = min(min(a0 * a1, a2 * a3), a4 * a5);\n");
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000471 inCoverage = "edgeAlpha";
472 coverageIsScalar = true;
473 }
474
475 GrStringBuilder outCoverage;
476 const int& startStage = fProgramDesc.fFirstCoverageStage;
477 for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) {
478 if (fProgramDesc.fStages[s].fEnabled) {
479
480 // create var to hold stage output
481 outCoverage = "coverage";
482 outCoverage.appendS32(s);
483 segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
484
485 const char* inCoords;
486 // figure out what our input coords are
487 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
488 inCoords = POS_ATTR_NAME;
489 } else {
490 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
491 // we better have input tex coordinates if stage is enabled.
492 GrAssert(tcIdx >= 0);
493 GrAssert(texCoordAttrs[tcIdx].size());
494 inCoords = texCoordAttrs[tcIdx].c_str();
495 }
496
497 genStageCode(s,
498 fProgramDesc.fStages[s],
499 inCoverage.size() ? inCoverage.c_str() : NULL,
500 outCoverage.c_str(),
501 inCoords,
502 &segments,
503 &programData->fUniLocations.fStages[s]);
504 inCoverage = outCoverage;
505 coverageIsScalar = false;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000506 }
507 }
junov@google.comf93e7172011-03-31 21:26:24 +0000508 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000509
510 // TODO: ADD dual source blend output based on coverage here
511
512 ///////////////////////////////////////////////////////////////////////////
513 // combine color and coverage as frag color
514
515 if (!wroteFragColorZero) {
516 if (coverageIsScalar && !inColor.size()) {
517 GrStringBuilder oldCoverage = inCoverage;
518 inCoverage.swap(oldCoverage);
519 inCoverage.printf("vec4(%s,%s,%s,%s)", oldCoverage.c_str(),
520 oldCoverage.c_str(), oldCoverage.c_str(),
521 oldCoverage.c_str());
522 }
523 modulate_helper("gl_FragColor", inColor.c_str(),
524 inCoverage.c_str(), &segments.fFSCode);
525 }
526
bsalomon@google.com91961302011-05-09 18:39:58 +0000527 segments.fVSCode.append("}\n");
528 segments.fFSCode.append("}\n");
529
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000530 ///////////////////////////////////////////////////////////////////////////
531 // compile and setup attribs and unis
532
bsalomon@google.com91961302011-05-09 18:39:58 +0000533 if (!CompileFSAndVS(segments, programData)) {
534 return false;
535 }
536
537 if (!this->bindAttribsAndLinkProgram(texCoordAttrs, programData)) {
538 return false;
539 }
540
541 this->getUniformLocationsAndInitCache(programData);
542
543 return true;
544}
545
546bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
547 CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000548
junov@google.comf93e7172011-03-31 21:26:24 +0000549 const char* strings[4];
550 int lengths[4];
551 int stringCnt = 0;
552
bsalomon@google.comfc296292011-05-06 13:53:47 +0000553 if (segments.fVSUnis.size()) {
554 strings[stringCnt] = segments.fVSUnis.c_str();
555 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000556 ++stringCnt;
557 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000558 if (segments.fVSAttrs.size()) {
559 strings[stringCnt] = segments.fVSAttrs.c_str();
560 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000561 ++stringCnt;
562 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000563 if (segments.fVaryings.size()) {
564 strings[stringCnt] = segments.fVaryings.c_str();
565 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000566 ++stringCnt;
567 }
568
bsalomon@google.comfc296292011-05-06 13:53:47 +0000569 GrAssert(segments.fVSCode.size());
570 strings[stringCnt] = segments.fVSCode.c_str();
571 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000572 ++stringCnt;
573
574#if PRINT_SHADERS
bsalomon@google.comfc296292011-05-06 13:53:47 +0000575 GrPrintf(segments.fVSUnis.c_str());
576 GrPrintf(segments.fVSAttrs.c_str());
577 GrPrintf(segments.fVaryings.c_str());
578 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000579 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000580#endif
581 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
582 stringCnt,
583 strings,
584 lengths);
585
bsalomon@google.com91961302011-05-09 18:39:58 +0000586 if (!programData->fVShaderID) {
587 return false;
588 }
589
junov@google.comf93e7172011-03-31 21:26:24 +0000590 stringCnt = 0;
591
592 if (strlen(GrShaderPrecision()) > 1) {
593 strings[stringCnt] = GrShaderPrecision();
594 lengths[stringCnt] = strlen(GrShaderPrecision());
595 ++stringCnt;
596 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000597 if (segments.fFSUnis.size()) {
598 strings[stringCnt] = segments.fFSUnis.c_str();
599 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000600 ++stringCnt;
601 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000602 if (segments.fVaryings.size()) {
603 strings[stringCnt] = segments.fVaryings.c_str();
604 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000605 ++stringCnt;
606 }
607
bsalomon@google.comfc296292011-05-06 13:53:47 +0000608 GrAssert(segments.fFSCode.size());
609 strings[stringCnt] = segments.fFSCode.c_str();
610 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000611 ++stringCnt;
612
613#if PRINT_SHADERS
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000614 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000615 GrPrintf(segments.fFSUnis.c_str());
616 GrPrintf(segments.fVaryings.c_str());
617 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000618 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000619#endif
620 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
621 stringCnt,
622 strings,
623 lengths);
624
bsalomon@google.com91961302011-05-09 18:39:58 +0000625 if (!programData->fFShaderID) {
626 return false;
junov@google.comf93e7172011-03-31 21:26:24 +0000627 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000628 return true;
junov@google.comf93e7172011-03-31 21:26:24 +0000629}
630
631GrGLuint GrGLProgram::CompileShader(GrGLenum type,
632 int stringCnt,
633 const char** strings,
634 int* stringLengths) {
635 GrGLuint shader = GR_GL(CreateShader(type));
636 if (0 == shader) {
637 return 0;
638 }
639
640 GrGLint compiled = GR_GL_INIT_ZERO;
641 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
642 GR_GL(CompileShader(shader));
643 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
644
645 if (!compiled) {
646 GrGLint infoLen = GR_GL_INIT_ZERO;
647 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
648 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
649 if (infoLen > 0) {
650 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
651 for (int i = 0; i < stringCnt; ++i) {
652 if (NULL == stringLengths || stringLengths[i] < 0) {
653 GrPrintf(strings[i]);
654 } else {
655 GrPrintf("%.*s", stringLengths[i], strings[i]);
656 }
657 }
658 GrPrintf("\n%s", log.get());
659 }
660 GrAssert(!"Shader compilation failed!");
661 GR_GL(DeleteShader(shader));
662 return 0;
663 }
664 return shader;
665}
666
bsalomon@google.com91961302011-05-09 18:39:58 +0000667bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
668 CachedData* programData) const {
669 programData->fProgramID = GR_GL(CreateProgram());
670 if (!programData->fProgramID) {
671 return false;
672 }
673 const GrGLint& progID = programData->fProgramID;
674
675 GR_GL(AttachShader(progID, programData->fVShaderID));
676 GR_GL(AttachShader(progID, programData->fFShaderID));
677
678 // Bind the attrib locations to same values for all shaders
679 GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
680 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
681 if (texCoordAttrNames[t].size()) {
682 GR_GL(BindAttribLocation(progID,
683 TexCoordAttributeIdx(t),
684 texCoordAttrNames[t].c_str()));
685 }
686 }
687
688
689 if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
690 GR_GL(BindAttribLocation(progID,
691 ViewMatrixAttributeIdx(),
692 VIEW_MATRIX_NAME));
693 }
694
695 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
bsalomon@google.com72b4fcb2011-05-09 20:47:34 +0000696 const StageUniLocations& unis = programData->fUniLocations.fStages[s];
697 if (kSetAsAttribute == unis.fTextureMatrixUni) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000698 GrStringBuilder matName;
699 tex_matrix_name(s, &matName);
700 GR_GL(BindAttribLocation(progID,
701 TextureMatrixAttributeIdx(s),
702 matName.c_str()));
703 }
704 }
705
bsalomon@google.com91961302011-05-09 18:39:58 +0000706 GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
707
708 GR_GL(LinkProgram(progID));
709
710 GrGLint linked = GR_GL_INIT_ZERO;
711 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
712 if (!linked) {
713 GrGLint infoLen = GR_GL_INIT_ZERO;
714 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
715 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
716 if (infoLen > 0) {
717 GR_GL(GetProgramInfoLog(progID,
718 infoLen+1,
719 NULL,
720 (char*)log.get()));
721 GrPrintf((char*)log.get());
722 }
723 GrAssert(!"Error linking program");
724 GR_GL(DeleteProgram(progID));
725 programData->fProgramID = 0;
726 return false;
727 }
728 return true;
729}
730
731void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
732 const GrGLint& progID = programData->fProgramID;
733
734 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
735 programData->fUniLocations.fViewMatrixUni =
736 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
737 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
738 }
739 if (kUseUniform == programData->fUniLocations.fColorUni) {
740 programData->fUniLocations.fColorUni =
741 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
742 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
743 }
Scroggo97c88c22011-05-11 14:05:25 +0000744 if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
745 programData->fUniLocations.fColorFilterUni =
746 GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
747 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
748 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000749
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000750 if (kUseUniform == programData->fUniLocations.fEdgesUni) {
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000751 programData->fUniLocations.fEdgesUni =
752 GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
753 GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
754 } else {
755 programData->fUniLocations.fEdgesUni = kUnusedUniform;
756 }
757
bsalomon@google.com91961302011-05-09 18:39:58 +0000758 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
759 StageUniLocations& locations = programData->fUniLocations.fStages[s];
760 if (fProgramDesc.fStages[s].fEnabled) {
761 if (kUseUniform == locations.fTextureMatrixUni) {
762 GrStringBuilder texMName;
763 tex_matrix_name(s, &texMName);
764 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
765 progID,
766 texMName.c_str()));
767 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
768 }
769
770 if (kUseUniform == locations.fSamplerUni) {
771 GrStringBuilder samplerName;
772 sampler_name(s, &samplerName);
773 locations.fSamplerUni = GR_GL(GetUniformLocation(
774 progID,
775 samplerName.c_str()));
776 GrAssert(kUnusedUniform != locations.fSamplerUni);
777 }
778
779 if (kUseUniform == locations.fNormalizedTexelSizeUni) {
780 GrStringBuilder texelSizeName;
781 normalized_texel_size_name(s, &texelSizeName);
782 locations.fNormalizedTexelSizeUni =
783 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
784 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
785 }
786
787 if (kUseUniform == locations.fRadial2Uni) {
788 GrStringBuilder radial2ParamName;
789 radial2_param_name(s, &radial2ParamName);
790 locations.fRadial2Uni = GR_GL(GetUniformLocation(
791 progID,
792 radial2ParamName.c_str()));
793 GrAssert(kUnusedUniform != locations.fRadial2Uni);
794 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000795
796 if (kUseUniform == locations.fTexDomUni) {
797 GrStringBuilder texDomName;
798 tex_domain_name(s, &texDomName);
799 locations.fTexDomUni = GR_GL(GetUniformLocation(
800 progID,
801 texDomName.c_str()));
802 GrAssert(kUnusedUniform != locations.fTexDomUni);
803 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000804 }
805 }
806 GR_GL(UseProgram(progID));
807
808 // init sampler unis and set bogus values for state tracking
809 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
810 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
811 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
812 }
813 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
814 programData->fRadial2CenterX1[s] = GR_ScalarMax;
815 programData->fRadial2Radius0[s] = -GR_ScalarMax;
816 programData->fTextureWidth[s] = -1;
817 programData->fTextureHeight[s] = -1;
818 }
819 programData->fViewMatrix = GrMatrix::InvalidMatrix();
820 programData->fColor = GrColor_ILLEGAL;
Scroggo97c88c22011-05-11 14:05:25 +0000821 programData->fColorFilterColor = GrColor_ILLEGAL;
bsalomon@google.com91961302011-05-09 18:39:58 +0000822}
823
junov@google.comf93e7172011-03-31 21:26:24 +0000824//============================================================================
825// Stage code generation
826//============================================================================
827
828void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000829 const GrGLProgram::ProgramDesc::StageDesc& desc,
830 const char* fsInColor, // NULL means no incoming color
831 const char* fsOutColor,
832 const char* vsInCoord,
833 ShaderCodeSegments* segments,
834 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000835
836 GrAssert(stageNum >= 0 && stageNum <= 9);
837
bsalomon@google.com91961302011-05-09 18:39:58 +0000838 GrStringBuilder varyingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000839 stage_varying_name(stageNum, &varyingName);
840
841 // First decide how many coords are needed to access the texture
842 // Right now it's always 2 but we could start using 1D textures for
843 // gradients.
844 static const int coordDims = 2;
845 int varyingDims;
846 /// Vertex Shader Stuff
847
848 // decide whether we need a matrix to transform texture coords
849 // and whether the varying needs a perspective coord.
bsalomon@google.com91961302011-05-09 18:39:58 +0000850 GrStringBuilder texMName;
junov@google.comf93e7172011-03-31 21:26:24 +0000851 tex_matrix_name(stageNum, &texMName);
852 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
853 varyingDims = coordDims;
854 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000855 #if GR_GL_ATTRIBUTE_MATRICES
bsalomon@google.com91961302011-05-09 18:39:58 +0000856 segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
857 locations->fTextureMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000858 #else
bsalomon@google.com91961302011-05-09 18:39:58 +0000859 segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
860 locations->fTextureMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000861 #endif
862 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
863 varyingDims = coordDims;
864 } else {
865 varyingDims = coordDims + 1;
866 }
867 }
868
bsalomon@google.com91961302011-05-09 18:39:58 +0000869 GrStringBuilder samplerName;
junov@google.comf93e7172011-03-31 21:26:24 +0000870 sampler_name(stageNum, &samplerName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000871 segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
872 locations->fSamplerUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000873
bsalomon@google.com91961302011-05-09 18:39:58 +0000874 GrStringBuilder texelSizeName;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000875 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
876 normalized_texel_size_name(stageNum, &texelSizeName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000877 segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000878 }
879
bsalomon@google.com91961302011-05-09 18:39:58 +0000880 segments->fVaryings.appendf("varying %s %s;\n",
881 float_vector_type(varyingDims), varyingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000882
883 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
884 GrAssert(varyingDims == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000885 segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
junov@google.comf93e7172011-03-31 21:26:24 +0000886 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000887 // varying = texMatrix * texCoord
888 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
889 varyingName.c_str(), texMName.c_str(),
890 vsInCoord, vector_all_coords(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000891 }
892
bsalomon@google.com91961302011-05-09 18:39:58 +0000893 GrStringBuilder radial2ParamsName;
junov@google.comf93e7172011-03-31 21:26:24 +0000894 radial2_param_name(stageNum, &radial2ParamsName);
895 // for radial grads without perspective we can pass the linear
896 // part of the quadratic as a varying.
bsalomon@google.com91961302011-05-09 18:39:58 +0000897 GrStringBuilder radial2VaryingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000898 radial2_varying_name(stageNum, &radial2VaryingName);
899
900 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
901
bsalomon@google.comdcf1b0b2011-05-11 19:00:54 +0000902 segments->fVSUnis.appendf("uniform %s float %s[6];\n",
bsalomon@google.com91961302011-05-09 18:39:58 +0000903 GrPrecision(), radial2ParamsName.c_str());
904 segments->fFSUnis.appendf("uniform float %s[6];\n",
905 radial2ParamsName.c_str());
906 locations->fRadial2Uni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000907
908 // if there is perspective we don't interpolate this
909 if (varyingDims == coordDims) {
910 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000911 segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000912
bsalomon@google.com91961302011-05-09 18:39:58 +0000913 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
914 segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
915 radial2VaryingName.c_str(), radial2ParamsName.c_str(),
916 varyingName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000917 }
918 }
919
920 /// Fragment Shader Stuff
bsalomon@google.com91961302011-05-09 18:39:58 +0000921 GrStringBuilder fsCoordName;
junov@google.comf93e7172011-03-31 21:26:24 +0000922 // function used to access the shader, may be made projective
bsalomon@google.com91961302011-05-09 18:39:58 +0000923 GrStringBuilder texFunc("texture2D");
junov@google.comf93e7172011-03-31 21:26:24 +0000924 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
925 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
926 GrAssert(varyingDims == coordDims);
927 fsCoordName = varyingName;
928 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000929 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +0000930 // our final tex coords then when in perspective we have to
bsalomon@google.com91961302011-05-09 18:39:58 +0000931 // do an explicit divide. Otherwise, we can use a Proj func.
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000932 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
933 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000934 texFunc.append("Proj");
junov@google.comf93e7172011-03-31 21:26:24 +0000935 fsCoordName = varyingName;
936 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000937 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000938 fsCoordName.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000939 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
940 float_vector_type(coordDims),
941 fsCoordName.c_str(),
942 varyingName.c_str(),
943 vector_nonhomog_coords(varyingDims),
944 varyingName.c_str(),
945 vector_homog_coord(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000946 }
947 }
948
bsalomon@google.comfc296292011-05-06 13:53:47 +0000949 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000950 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +0000951 switch (desc.fCoordMapping) {
952 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
953 sampleCoords = fsCoordName;
954 break;
955 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000956 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 +0000957 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000958 break;
959 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000960 sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000961 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000962 break;
963 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.com91961302011-05-09 18:39:58 +0000964 GrStringBuilder cName("c");
965 GrStringBuilder ac4Name("ac4");
966 GrStringBuilder rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +0000967
bsalomon@google.comfc296292011-05-06 13:53:47 +0000968 cName.appendS32(stageNum);
969 ac4Name.appendS32(stageNum);
970 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +0000971
bsalomon@google.com91961302011-05-09 18:39:58 +0000972 // if we were able to interpolate the linear component bVar is the varying
973 // otherwise compute it
974 GrStringBuilder bVar;
junov@google.comf93e7172011-03-31 21:26:24 +0000975 if (coordDims == varyingDims) {
976 bVar = radial2VaryingName;
977 GrAssert(2 == varyingDims);
978 } else {
979 GrAssert(3 == varyingDims);
980 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000981 bVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000982 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
983 bVar.c_str(), radial2ParamsName.c_str(),
984 fsCoordName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000985 }
986
bsalomon@google.com91961302011-05-09 18:39:58 +0000987 // c = (x^2)+(y^2) - params[4]
988 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
989 cName.c_str(), fsCoordName.c_str(),
990 fsCoordName.c_str(),
991 radial2ParamsName.c_str());
992 // ac4 = 4.0 * params[0] * c
993 segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
994 ac4Name.c_str(), radial2ParamsName.c_str(),
995 cName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000996
bsalomon@google.com91961302011-05-09 18:39:58 +0000997 // root = sqrt(b^2-4ac)
998 // (abs to avoid exception due to fp precision)
999 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
1000 rootName.c_str(), bVar.c_str(), bVar.c_str(),
1001 ac4Name.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001002
bsalomon@google.com91961302011-05-09 18:39:58 +00001003 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
1004 // y coord is 0.5 (texture is effectively 1D)
1005 sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
1006 bVar.c_str(), radial2ParamsName.c_str(),
1007 rootName.c_str(), radial2ParamsName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001008 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001009 break;}
1010 };
1011
bsalomon@google.com91961302011-05-09 18:39:58 +00001012 const char* smear;
1013 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
1014 smear = ".aaaa";
1015 } else {
1016 smear = "";
1017 }
1018 GrStringBuilder modulate;
1019 if (NULL != fsInColor) {
1020 modulate.printf(" * %s", fsInColor);
1021 }
1022
junov@google.com6acc9b32011-05-16 18:32:07 +00001023 if (desc.fOptFlags &
1024 ProgramDesc::StageDesc::kCustomTextureDomain_OptFlagBit) {
1025 GrStringBuilder texDomainName;
1026 tex_domain_name(stageNum, &texDomainName);
1027 segments->fFSUnis.appendf("uniform %s %s;\n",
1028 float_vector_type(4),
1029 texDomainName.c_str());
1030 GrStringBuilder coordVar("clampCoord");
1031 segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
1032 float_vector_type(coordDims),
1033 coordVar.c_str(),
1034 sampleCoords.c_str(),
1035 texDomainName.c_str(),
1036 texDomainName.c_str());
1037 sampleCoords = coordVar;
1038 locations->fTexDomUni = kUseUniform;
1039 }
1040
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001041 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001042 locations->fNormalizedTexelSizeUni = kUseUniform;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001043 if (complexCoord) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001044 // assign the coord to a var rather than compute 4x.
1045 GrStringBuilder coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +00001046 coordVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001047 segments->fFSCode.appendf("\t%s %s = %s;\n",
1048 float_vector_type(coordDims),
1049 coordVar.c_str(), sampleCoords.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001050 sampleCoords = coordVar;
1051 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001052 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +00001053 GrStringBuilder accumVar("accum");
1054 accumVar.appendS32(stageNum);
1055 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);
1056 segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
1057 segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
1058 segments->fFSCode.appendf("\t%s += %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);
1059 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001060 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +00001061 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 +00001062 }
junov@google.comf93e7172011-03-31 21:26:24 +00001063}
1064