blob: ce4e7dbd038be3d44efaf52a7a9203647fc4f0b8 [file] [log] [blame]
junov@google.comf93e7172011-03-31 21:26:24 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrGLProgram.h"
18
19#include "GrBinHashKey.h"
20#include "GrGLConfig.h"
21#include "GrGLEffect.h"
22#include "GrMemory.h"
junov@google.comf93e7172011-03-31 21:26:24 +000023
Scroggo97c88c22011-05-11 14:05:25 +000024#include "SkXfermode.h"
25
junov@google.comf93e7172011-03-31 21:26:24 +000026namespace {
27
28const char* GrPrecision() {
29 if (GR_GL_SUPPORT_ES2) {
30 return "mediump";
31 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +000032 return " ";
junov@google.comf93e7172011-03-31 21:26:24 +000033 }
34}
35
36const char* GrShaderPrecision() {
37 if (GR_GL_SUPPORT_ES2) {
38 return "precision mediump float;\n";
39 } else {
40 return "";
41 }
42}
43
44} // namespace
45
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000046#define PRINT_SHADERS 0
47
bsalomon@google.com4be283f2011-04-19 21:15:09 +000048#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000049 #define VIEW_MATRIX_NAME "aViewM"
50#else
51 #define VIEW_MATRIX_NAME "uViewM"
52#endif
53
54#define POS_ATTR_NAME "aPosition"
55#define COL_ATTR_NAME "aColor"
bsalomon@google.com4be283f2011-04-19 21:15:09 +000056#define COL_UNI_NAME "uColor"
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +000057#define EDGES_UNI_NAME "uEdges"
Scroggo97c88c22011-05-11 14:05:25 +000058#define COL_FILTER_UNI_NAME "uColorFilter"
junov@google.comf93e7172011-03-31 21:26:24 +000059
junov@google.comf93e7172011-03-31 21:26:24 +000060static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
61 *s = "aTexCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +000062 s->appendS32(coordIdx);
junov@google.comf93e7172011-03-31 21:26:24 +000063}
64
65static inline const char* float_vector_type(int count) {
66 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
67 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
68 return FLOAT_VECS[count];
69}
70
71static inline const char* vector_homog_coord(int count) {
72 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
73 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
74 return HOMOGS[count];
75}
76
77static inline const char* vector_nonhomog_coords(int count) {
78 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
79 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
80 return NONHOMOGS[count];
81}
82
83static inline const char* vector_all_coords(int count) {
84 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
85 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
86 return ALL[count];
87}
88
89static void tex_matrix_name(int stage, GrStringBuilder* s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +000090#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000091 *s = "aTexM";
92#else
93 *s = "uTexM";
94#endif
bsalomon@google.comfc296292011-05-06 13:53:47 +000095 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +000096}
97
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000098static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
99 *s = "uTexelSize";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000100 s->appendS32(stage);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000101}
102
junov@google.comf93e7172011-03-31 21:26:24 +0000103static void sampler_name(int stage, GrStringBuilder* s) {
104 *s = "uSampler";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000105 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000106}
107
108static void stage_varying_name(int stage, GrStringBuilder* s) {
109 *s = "vStage";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000110 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000111}
112
113static void radial2_param_name(int stage, GrStringBuilder* s) {
114 *s = "uRadial2Params";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000115 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000116}
117
118static void radial2_varying_name(int stage, GrStringBuilder* s) {
119 *s = "vB";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000120 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000121}
122
123GrGLProgram::GrGLProgram() {
124 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
125 fStageEffects[stage] = NULL;
126 }
127}
128
129GrGLProgram::~GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000130}
131
132void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
133 // Add stage configuration to the key
134 key.keyData(reinterpret_cast<const uint8_t*>(&fProgramDesc), sizeof(ProgramDesc));
135
136 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
137 // First pass: count effects and write the count to the key.
138 // This may seem like we are adding redundant data to the
139 // key, but in ensures the one key cannot be a prefix of
140 // another key, or identical to the key of a different program.
141 GrGLEffect* currentEffect = fStageEffects[stage];
142 uint8_t effectCount = 0;
143 while (currentEffect) {
144 GrAssert(effectCount < 255); // overflow detection
145 ++effectCount;
146 currentEffect = currentEffect->nextEffect();
147 }
148 key.keyData(reinterpret_cast<const uint8_t*>(&effectCount), sizeof(uint8_t));
149
150 // Second pass: continue building key using the effects
151 currentEffect = fStageEffects[stage];
152 while (currentEffect) {
153 fStageEffects[stage]->buildKey(key);
154 }
155 }
156}
157
158bool GrGLProgram::doGLSetup(GrPrimitiveType type,
159 GrGLProgram::CachedData* programData) const {
160 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
161 GrGLEffect* effect = fStageEffects[stage];
162 if (effect) {
163 if (!effect->doGLSetup(type, programData->fProgramID)) {
164 return false;
165 }
166 }
167 }
168
169 return true;
170}
171
172void GrGLProgram::doGLPost() const {
173 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
174 GrGLEffect* effect = fStageEffects[stage];
175 if (effect) {
176 effect->doGLPost();
177 }
178 }
179}
180
Scroggo97c88c22011-05-11 14:05:25 +0000181/**
182 * Create a text coefficient to be used in fragment shader code.
183 */
184static void coefficientString(GrStringBuilder& str, SkXfermode::Coeff coeff,
185 const char* src, const char* dst) {
186 switch (coeff) {
187 case SkXfermode::kZero_Coeff: /** 0 */
188 str = "0.0";
189 break;
190 case SkXfermode::kOne_Coeff: /** 1 */
191 str = "1.0";
192 break;
193 case SkXfermode::kSA_Coeff: /** src alpha */
194 str.appendf("%s.a", src);
195 break;
196 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
197 str.appendf("(1.0 - %s.a)", src);
198 break;
199 case SkXfermode::kDA_Coeff: /** dst alpha */
200 str.appendf("%s.a", dst);
201 break;
202 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
203 str.appendf("(1.0 - %s.a)", dst);
204 break;
205 case SkXfermode::kSC_Coeff:
206 str.append(src);
207 break;
208 default:
209 break;
210 }
211}
212
213/**
214 * Adds a line to the fragment shader code which modifies the color by
215 * the specified color filter.
216 */
217static void addColorFilter(GrStringBuilder& FSCode, const char * outputVar,
218 SkXfermode::Mode colorFilterXfermode, const char* dstColor) {
219 SkXfermode::Coeff srcCoeff, dstCoeff;
Scroggoa8a57be2011-05-11 18:16:56 +0000220 SkDEBUGCODE(bool success =)
221 SkXfermode::ModeAsCoeff(colorFilterXfermode, &srcCoeff, &dstCoeff);
Scroggo97c88c22011-05-11 14:05:25 +0000222 // We currently do not handle modes that cannot be represented as
223 // coefficients.
224 GrAssert(success);
225 GrStringBuilder srcCoeffStr, dstCoeffStr;
226 coefficientString(srcCoeffStr, srcCoeff, COL_FILTER_UNI_NAME, dstColor);
227 coefficientString(dstCoeffStr, dstCoeff, COL_FILTER_UNI_NAME, dstColor);
228 FSCode.appendf("\t%s = %s*%s + %s*%s;\n", outputVar, srcCoeffStr.c_str(),
229 COL_FILTER_UNI_NAME, dstCoeffStr.c_str(), dstColor);
230}
231
bsalomon@google.com91961302011-05-09 18:39:58 +0000232bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000233
234 ShaderCodeSegments segments;
235 const uint32_t& layout = fProgramDesc.fVertexLayout;
236
bsalomon@google.com91961302011-05-09 18:39:58 +0000237 programData->fUniLocations.reset();
junov@google.comf93e7172011-03-31 21:26:24 +0000238
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000239#if GR_GL_ATTRIBUTE_MATRICES
240 segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000241 programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000242#else
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000243 segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000244 programData->fUniLocations.fViewMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000245#endif
246 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000247
bsalomon@google.com91961302011-05-09 18:39:58 +0000248 segments.fVSCode.append(
249 "void main() {\n"
250 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
251 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000252
bsalomon@google.com91961302011-05-09 18:39:58 +0000253 // incoming color to current stage being processed.
254 GrStringBuilder inColor;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000255
256 switch (fProgramDesc.fColorType) {
257 case ProgramDesc::kAttribute_ColorType:
bsalomon@google.com91961302011-05-09 18:39:58 +0000258 segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
259 segments.fVaryings.append("varying vec4 vColor;\n");
260 segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000261 inColor = "vColor";
262 break;
263 case ProgramDesc::kUniform_ColorType:
bsalomon@google.com91961302011-05-09 18:39:58 +0000264 segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
265 programData->fUniLocations.fColorUni = kUseUniform;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000266 inColor = COL_UNI_NAME;
267 break;
268 case ProgramDesc::kNone_ColorType:
269 inColor = "";
270 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000271 }
272
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000273 if (fProgramDesc.fUsesEdgeAA) {
274 segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[6];\n");
275 }
276
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000277 if (fProgramDesc.fEmitsPointSize){
bsalomon@google.com91961302011-05-09 18:39:58 +0000278 segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000279 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000280
bsalomon@google.com91961302011-05-09 18:39:58 +0000281 segments.fFSCode.append("void main() {\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000282
283 // add texture coordinates that are used to the list of vertex attr decls
bsalomon@google.com91961302011-05-09 18:39:58 +0000284 GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
junov@google.comf93e7172011-03-31 21:26:24 +0000285 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000286 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000287 tex_attr_name(t, texCoordAttrs + t);
bsalomon@google.com91961302011-05-09 18:39:58 +0000288 segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000289 }
290 }
291
Scroggo97c88c22011-05-11 14:05:25 +0000292 bool useColorFilter =
293 // The rest of transfer mode color filters have not been implemented
294 fProgramDesc.fColorFilterXfermode <= SkXfermode::kMultiply_Mode
295 // This mode has no effect.
296 && fProgramDesc.fColorFilterXfermode != SkXfermode::kDst_Mode;
297 bool onlyUseColorFilter = useColorFilter
298 && (fProgramDesc.fColorFilterXfermode == SkXfermode::kClear_Mode
299 || fProgramDesc.fColorFilterXfermode == SkXfermode::kSrc_Mode);
300 if (useColorFilter) {
301 // Set up a uniform for the color
302 segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
303 programData->fUniLocations.fColorFilterUni = kUseUniform;
304 }
305
junov@google.comf93e7172011-03-31 21:26:24 +0000306 // for each enabled stage figure out what the input coordinates are
307 // and count the number of stages in use.
308 const char* stageInCoords[GrDrawTarget::kNumStages];
309 int numActiveStages = 0;
310
Scroggo97c88c22011-05-11 14:05:25 +0000311 if (!onlyUseColorFilter) {
312 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
313 if (fProgramDesc.fStages[s].fEnabled) {
314 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
315 stageInCoords[s] = POS_ATTR_NAME;
316 } else {
317 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
318 // we better have input tex coordinates if stage is enabled.
319 GrAssert(tcIdx >= 0);
320 GrAssert(texCoordAttrs[tcIdx].size());
321 stageInCoords[s] = texCoordAttrs[tcIdx].c_str();
322 }
323 ++numActiveStages;
junov@google.comf93e7172011-03-31 21:26:24 +0000324 }
junov@google.comf93e7172011-03-31 21:26:24 +0000325 }
326 }
327
junov@google.comf93e7172011-03-31 21:26:24 +0000328 // if we have active stages string them together, feeding the output color
329 // of each to the next and generating code for each stage.
330 if (numActiveStages) {
331 int currActiveStage = 0;
Scroggo97c88c22011-05-11 14:05:25 +0000332 GrStringBuilder outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000333 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
334 if (fProgramDesc.fStages[s].fEnabled) {
Scroggo97c88c22011-05-11 14:05:25 +0000335 if (currActiveStage < (numActiveStages - 1) || useColorFilter) {
junov@google.comf93e7172011-03-31 21:26:24 +0000336 outColor = "color";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000337 outColor.appendS32(currActiveStage);
bsalomon@google.com91961302011-05-09 18:39:58 +0000338 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000339 } else {
340 outColor = "gl_FragColor";
341 }
342
343 genStageCode(s,
344 fProgramDesc.fStages[s],
bsalomon@google.comfc296292011-05-06 13:53:47 +0000345 inColor.size() ? inColor.c_str() : NULL,
346 outColor.c_str(),
junov@google.comf93e7172011-03-31 21:26:24 +0000347 stageInCoords[s],
348 &segments,
349 &programData->fUniLocations.fStages[s]);
350 ++currActiveStage;
351 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000352 }
353 }
Scroggo97c88c22011-05-11 14:05:25 +0000354 if (useColorFilter) {
355 addColorFilter(segments.fFSCode, "gl_FragColor",
356 fProgramDesc.fColorFilterXfermode, outColor.c_str());
357 }
358
junov@google.comf93e7172011-03-31 21:26:24 +0000359 } else {
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000360 if (fProgramDesc.fUsesEdgeAA) {
361 // FIXME: put the a's in a loop
362 segments.fFSCode.append(
363 "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n"
364 "\tfloat a0 = clamp(dot(uEdges[0], pos), 0.0, 1.0);\n"
365 "\tfloat a1 = clamp(dot(uEdges[1], pos), 0.0, 1.0);\n"
366 "\tfloat a2 = clamp(dot(uEdges[2], pos), 0.0, 1.0);\n"
367 "\tfloat a3 = clamp(dot(uEdges[3], pos), 0.0, 1.0);\n"
368 "\tfloat a4 = clamp(dot(uEdges[4], pos), 0.0, 1.0);\n"
369 "\tfloat a5 = clamp(dot(uEdges[5], pos), 0.0, 1.0);\n"
370 "\tfloat edgeAlpha = min(min(a0 * a1, a2 * a3), a4 * a5);\n");
371 if (inColor.size()) {
372 inColor.append(" * edgeAlpha");
373 } else {
374 inColor = "vec4(edgeAlpha)";
375 }
376 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000377 // we may not have any incoming color
Scroggo97c88c22011-05-11 14:05:25 +0000378 const char * incomingColor = (inColor.size() ? inColor.c_str()
379 : "vec4(1,1,1,1)");
380 if (useColorFilter) {
381 addColorFilter(segments.fFSCode, "gl_FragColor",
382 fProgramDesc.fColorFilterXfermode, incomingColor);
383 } else {
384 segments.fFSCode.appendf("\tgl_FragColor = %s;\n", incomingColor);
385 }
junov@google.comf93e7172011-03-31 21:26:24 +0000386 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000387 segments.fVSCode.append("}\n");
388 segments.fFSCode.append("}\n");
389
390 if (!CompileFSAndVS(segments, programData)) {
391 return false;
392 }
393
394 if (!this->bindAttribsAndLinkProgram(texCoordAttrs, programData)) {
395 return false;
396 }
397
398 this->getUniformLocationsAndInitCache(programData);
399
400 return true;
401}
402
403bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
404 CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000405
junov@google.comf93e7172011-03-31 21:26:24 +0000406 const char* strings[4];
407 int lengths[4];
408 int stringCnt = 0;
409
bsalomon@google.comfc296292011-05-06 13:53:47 +0000410 if (segments.fVSUnis.size()) {
411 strings[stringCnt] = segments.fVSUnis.c_str();
412 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000413 ++stringCnt;
414 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000415 if (segments.fVSAttrs.size()) {
416 strings[stringCnt] = segments.fVSAttrs.c_str();
417 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000418 ++stringCnt;
419 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000420 if (segments.fVaryings.size()) {
421 strings[stringCnt] = segments.fVaryings.c_str();
422 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000423 ++stringCnt;
424 }
425
bsalomon@google.comfc296292011-05-06 13:53:47 +0000426 GrAssert(segments.fVSCode.size());
427 strings[stringCnt] = segments.fVSCode.c_str();
428 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000429 ++stringCnt;
430
431#if PRINT_SHADERS
bsalomon@google.comfc296292011-05-06 13:53:47 +0000432 GrPrintf(segments.fVSUnis.c_str());
433 GrPrintf(segments.fVSAttrs.c_str());
434 GrPrintf(segments.fVaryings.c_str());
435 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000436 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000437#endif
438 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
439 stringCnt,
440 strings,
441 lengths);
442
bsalomon@google.com91961302011-05-09 18:39:58 +0000443 if (!programData->fVShaderID) {
444 return false;
445 }
446
junov@google.comf93e7172011-03-31 21:26:24 +0000447 stringCnt = 0;
448
449 if (strlen(GrShaderPrecision()) > 1) {
450 strings[stringCnt] = GrShaderPrecision();
451 lengths[stringCnt] = strlen(GrShaderPrecision());
452 ++stringCnt;
453 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000454 if (segments.fFSUnis.size()) {
455 strings[stringCnt] = segments.fFSUnis.c_str();
456 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000457 ++stringCnt;
458 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000459 if (segments.fVaryings.size()) {
460 strings[stringCnt] = segments.fVaryings.c_str();
461 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000462 ++stringCnt;
463 }
464
bsalomon@google.comfc296292011-05-06 13:53:47 +0000465 GrAssert(segments.fFSCode.size());
466 strings[stringCnt] = segments.fFSCode.c_str();
467 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000468 ++stringCnt;
469
470#if PRINT_SHADERS
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000471 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000472 GrPrintf(segments.fFSUnis.c_str());
473 GrPrintf(segments.fVaryings.c_str());
474 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000475 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000476#endif
477 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
478 stringCnt,
479 strings,
480 lengths);
481
bsalomon@google.com91961302011-05-09 18:39:58 +0000482 if (!programData->fFShaderID) {
483 return false;
junov@google.comf93e7172011-03-31 21:26:24 +0000484 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000485 return true;
junov@google.comf93e7172011-03-31 21:26:24 +0000486}
487
488GrGLuint GrGLProgram::CompileShader(GrGLenum type,
489 int stringCnt,
490 const char** strings,
491 int* stringLengths) {
492 GrGLuint shader = GR_GL(CreateShader(type));
493 if (0 == shader) {
494 return 0;
495 }
496
497 GrGLint compiled = GR_GL_INIT_ZERO;
498 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
499 GR_GL(CompileShader(shader));
500 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
501
502 if (!compiled) {
503 GrGLint infoLen = GR_GL_INIT_ZERO;
504 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
505 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
506 if (infoLen > 0) {
507 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
508 for (int i = 0; i < stringCnt; ++i) {
509 if (NULL == stringLengths || stringLengths[i] < 0) {
510 GrPrintf(strings[i]);
511 } else {
512 GrPrintf("%.*s", stringLengths[i], strings[i]);
513 }
514 }
515 GrPrintf("\n%s", log.get());
516 }
517 GrAssert(!"Shader compilation failed!");
518 GR_GL(DeleteShader(shader));
519 return 0;
520 }
521 return shader;
522}
523
bsalomon@google.com91961302011-05-09 18:39:58 +0000524bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
525 CachedData* programData) const {
526 programData->fProgramID = GR_GL(CreateProgram());
527 if (!programData->fProgramID) {
528 return false;
529 }
530 const GrGLint& progID = programData->fProgramID;
531
532 GR_GL(AttachShader(progID, programData->fVShaderID));
533 GR_GL(AttachShader(progID, programData->fFShaderID));
534
535 // Bind the attrib locations to same values for all shaders
536 GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
537 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
538 if (texCoordAttrNames[t].size()) {
539 GR_GL(BindAttribLocation(progID,
540 TexCoordAttributeIdx(t),
541 texCoordAttrNames[t].c_str()));
542 }
543 }
544
545
546 if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
547 GR_GL(BindAttribLocation(progID,
548 ViewMatrixAttributeIdx(),
549 VIEW_MATRIX_NAME));
550 }
551
552 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
bsalomon@google.com72b4fcb2011-05-09 20:47:34 +0000553 const StageUniLocations& unis = programData->fUniLocations.fStages[s];
554 if (kSetAsAttribute == unis.fTextureMatrixUni) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000555 GrStringBuilder matName;
556 tex_matrix_name(s, &matName);
557 GR_GL(BindAttribLocation(progID,
558 TextureMatrixAttributeIdx(s),
559 matName.c_str()));
560 }
561 }
562
563
564 GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
565
566 GR_GL(LinkProgram(progID));
567
568 GrGLint linked = GR_GL_INIT_ZERO;
569 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
570 if (!linked) {
571 GrGLint infoLen = GR_GL_INIT_ZERO;
572 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
573 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
574 if (infoLen > 0) {
575 GR_GL(GetProgramInfoLog(progID,
576 infoLen+1,
577 NULL,
578 (char*)log.get()));
579 GrPrintf((char*)log.get());
580 }
581 GrAssert(!"Error linking program");
582 GR_GL(DeleteProgram(progID));
583 programData->fProgramID = 0;
584 return false;
585 }
586 return true;
587}
588
589void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
590 const GrGLint& progID = programData->fProgramID;
591
592 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
593 programData->fUniLocations.fViewMatrixUni =
594 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
595 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
596 }
597 if (kUseUniform == programData->fUniLocations.fColorUni) {
598 programData->fUniLocations.fColorUni =
599 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
600 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
601 }
Scroggo97c88c22011-05-11 14:05:25 +0000602 if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
603 programData->fUniLocations.fColorFilterUni =
604 GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
605 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
606 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000607
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000608 if (fProgramDesc.fUsesEdgeAA) {
609 programData->fUniLocations.fEdgesUni =
610 GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
611 GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
612 } else {
613 programData->fUniLocations.fEdgesUni = kUnusedUniform;
614 }
615
bsalomon@google.com91961302011-05-09 18:39:58 +0000616 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
617 StageUniLocations& locations = programData->fUniLocations.fStages[s];
618 if (fProgramDesc.fStages[s].fEnabled) {
619 if (kUseUniform == locations.fTextureMatrixUni) {
620 GrStringBuilder texMName;
621 tex_matrix_name(s, &texMName);
622 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
623 progID,
624 texMName.c_str()));
625 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
626 }
627
628 if (kUseUniform == locations.fSamplerUni) {
629 GrStringBuilder samplerName;
630 sampler_name(s, &samplerName);
631 locations.fSamplerUni = GR_GL(GetUniformLocation(
632 progID,
633 samplerName.c_str()));
634 GrAssert(kUnusedUniform != locations.fSamplerUni);
635 }
636
637 if (kUseUniform == locations.fNormalizedTexelSizeUni) {
638 GrStringBuilder texelSizeName;
639 normalized_texel_size_name(s, &texelSizeName);
640 locations.fNormalizedTexelSizeUni =
641 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
642 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
643 }
644
645 if (kUseUniform == locations.fRadial2Uni) {
646 GrStringBuilder radial2ParamName;
647 radial2_param_name(s, &radial2ParamName);
648 locations.fRadial2Uni = GR_GL(GetUniformLocation(
649 progID,
650 radial2ParamName.c_str()));
651 GrAssert(kUnusedUniform != locations.fRadial2Uni);
652 }
653 }
654 }
655 GR_GL(UseProgram(progID));
656
657 // init sampler unis and set bogus values for state tracking
658 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
659 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
660 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
661 }
662 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
663 programData->fRadial2CenterX1[s] = GR_ScalarMax;
664 programData->fRadial2Radius0[s] = -GR_ScalarMax;
665 programData->fTextureWidth[s] = -1;
666 programData->fTextureHeight[s] = -1;
667 }
668 programData->fViewMatrix = GrMatrix::InvalidMatrix();
669 programData->fColor = GrColor_ILLEGAL;
Scroggo97c88c22011-05-11 14:05:25 +0000670 programData->fColorFilterColor = GrColor_ILLEGAL;
bsalomon@google.com91961302011-05-09 18:39:58 +0000671}
672
junov@google.comf93e7172011-03-31 21:26:24 +0000673//============================================================================
674// Stage code generation
675//============================================================================
676
677void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000678 const GrGLProgram::ProgramDesc::StageDesc& desc,
679 const char* fsInColor, // NULL means no incoming color
680 const char* fsOutColor,
681 const char* vsInCoord,
682 ShaderCodeSegments* segments,
683 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000684
685 GrAssert(stageNum >= 0 && stageNum <= 9);
686
bsalomon@google.com91961302011-05-09 18:39:58 +0000687 GrStringBuilder varyingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000688 stage_varying_name(stageNum, &varyingName);
689
690 // First decide how many coords are needed to access the texture
691 // Right now it's always 2 but we could start using 1D textures for
692 // gradients.
693 static const int coordDims = 2;
694 int varyingDims;
695 /// Vertex Shader Stuff
696
697 // decide whether we need a matrix to transform texture coords
698 // and whether the varying needs a perspective coord.
bsalomon@google.com91961302011-05-09 18:39:58 +0000699 GrStringBuilder texMName;
junov@google.comf93e7172011-03-31 21:26:24 +0000700 tex_matrix_name(stageNum, &texMName);
701 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
702 varyingDims = coordDims;
703 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000704 #if GR_GL_ATTRIBUTE_MATRICES
bsalomon@google.com91961302011-05-09 18:39:58 +0000705 segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
706 locations->fTextureMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000707 #else
bsalomon@google.com91961302011-05-09 18:39:58 +0000708 segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
709 locations->fTextureMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000710 #endif
711 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
712 varyingDims = coordDims;
713 } else {
714 varyingDims = coordDims + 1;
715 }
716 }
717
bsalomon@google.com91961302011-05-09 18:39:58 +0000718 GrStringBuilder samplerName;
junov@google.comf93e7172011-03-31 21:26:24 +0000719 sampler_name(stageNum, &samplerName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000720 segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
721 locations->fSamplerUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000722
bsalomon@google.com91961302011-05-09 18:39:58 +0000723 GrStringBuilder texelSizeName;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000724 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
725 normalized_texel_size_name(stageNum, &texelSizeName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000726 segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000727 }
728
bsalomon@google.com91961302011-05-09 18:39:58 +0000729 segments->fVaryings.appendf("varying %s %s;\n",
730 float_vector_type(varyingDims), varyingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000731
732 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
733 GrAssert(varyingDims == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000734 segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
junov@google.comf93e7172011-03-31 21:26:24 +0000735 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000736 // varying = texMatrix * texCoord
737 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
738 varyingName.c_str(), texMName.c_str(),
739 vsInCoord, vector_all_coords(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000740 }
741
bsalomon@google.com91961302011-05-09 18:39:58 +0000742 GrStringBuilder radial2ParamsName;
junov@google.comf93e7172011-03-31 21:26:24 +0000743 radial2_param_name(stageNum, &radial2ParamsName);
744 // for radial grads without perspective we can pass the linear
745 // part of the quadratic as a varying.
bsalomon@google.com91961302011-05-09 18:39:58 +0000746 GrStringBuilder radial2VaryingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000747 radial2_varying_name(stageNum, &radial2VaryingName);
748
749 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
750
bsalomon@google.comdcf1b0b2011-05-11 19:00:54 +0000751 segments->fVSUnis.appendf("uniform %s float %s[6];\n",
bsalomon@google.com91961302011-05-09 18:39:58 +0000752 GrPrecision(), radial2ParamsName.c_str());
753 segments->fFSUnis.appendf("uniform float %s[6];\n",
754 radial2ParamsName.c_str());
755 locations->fRadial2Uni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000756
757 // if there is perspective we don't interpolate this
758 if (varyingDims == coordDims) {
759 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000760 segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000761
bsalomon@google.com91961302011-05-09 18:39:58 +0000762 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
763 segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
764 radial2VaryingName.c_str(), radial2ParamsName.c_str(),
765 varyingName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000766 }
767 }
768
769 /// Fragment Shader Stuff
bsalomon@google.com91961302011-05-09 18:39:58 +0000770 GrStringBuilder fsCoordName;
junov@google.comf93e7172011-03-31 21:26:24 +0000771 // function used to access the shader, may be made projective
bsalomon@google.com91961302011-05-09 18:39:58 +0000772 GrStringBuilder texFunc("texture2D");
junov@google.comf93e7172011-03-31 21:26:24 +0000773 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
774 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
775 GrAssert(varyingDims == coordDims);
776 fsCoordName = varyingName;
777 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000778 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +0000779 // our final tex coords then when in perspective we have to
bsalomon@google.com91961302011-05-09 18:39:58 +0000780 // do an explicit divide. Otherwise, we can use a Proj func.
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000781 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
782 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000783 texFunc.append("Proj");
junov@google.comf93e7172011-03-31 21:26:24 +0000784 fsCoordName = varyingName;
785 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000786 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000787 fsCoordName.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000788 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
789 float_vector_type(coordDims),
790 fsCoordName.c_str(),
791 varyingName.c_str(),
792 vector_nonhomog_coords(varyingDims),
793 varyingName.c_str(),
794 vector_homog_coord(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000795 }
796 }
797
bsalomon@google.comfc296292011-05-06 13:53:47 +0000798 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000799 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +0000800 switch (desc.fCoordMapping) {
801 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
802 sampleCoords = fsCoordName;
803 break;
804 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000805 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 +0000806 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000807 break;
808 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000809 sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000810 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000811 break;
812 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.com91961302011-05-09 18:39:58 +0000813 GrStringBuilder cName("c");
814 GrStringBuilder ac4Name("ac4");
815 GrStringBuilder rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +0000816
bsalomon@google.comfc296292011-05-06 13:53:47 +0000817 cName.appendS32(stageNum);
818 ac4Name.appendS32(stageNum);
819 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +0000820
bsalomon@google.com91961302011-05-09 18:39:58 +0000821 // if we were able to interpolate the linear component bVar is the varying
822 // otherwise compute it
823 GrStringBuilder bVar;
junov@google.comf93e7172011-03-31 21:26:24 +0000824 if (coordDims == varyingDims) {
825 bVar = radial2VaryingName;
826 GrAssert(2 == varyingDims);
827 } else {
828 GrAssert(3 == varyingDims);
829 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000830 bVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000831 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
832 bVar.c_str(), radial2ParamsName.c_str(),
833 fsCoordName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000834 }
835
bsalomon@google.com91961302011-05-09 18:39:58 +0000836 // c = (x^2)+(y^2) - params[4]
837 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
838 cName.c_str(), fsCoordName.c_str(),
839 fsCoordName.c_str(),
840 radial2ParamsName.c_str());
841 // ac4 = 4.0 * params[0] * c
842 segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
843 ac4Name.c_str(), radial2ParamsName.c_str(),
844 cName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000845
bsalomon@google.com91961302011-05-09 18:39:58 +0000846 // root = sqrt(b^2-4ac)
847 // (abs to avoid exception due to fp precision)
848 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
849 rootName.c_str(), bVar.c_str(), bVar.c_str(),
850 ac4Name.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000851
bsalomon@google.com91961302011-05-09 18:39:58 +0000852 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
853 // y coord is 0.5 (texture is effectively 1D)
854 sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
855 bVar.c_str(), radial2ParamsName.c_str(),
856 rootName.c_str(), radial2ParamsName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000857 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000858 break;}
859 };
860
bsalomon@google.com91961302011-05-09 18:39:58 +0000861 const char* smear;
862 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
863 smear = ".aaaa";
864 } else {
865 smear = "";
866 }
867 GrStringBuilder modulate;
868 if (NULL != fsInColor) {
869 modulate.printf(" * %s", fsInColor);
870 }
871
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000872 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000873 locations->fNormalizedTexelSizeUni = kUseUniform;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000874 if (complexCoord) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000875 // assign the coord to a var rather than compute 4x.
876 GrStringBuilder coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +0000877 coordVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000878 segments->fFSCode.appendf("\t%s %s = %s;\n",
879 float_vector_type(coordDims),
880 coordVar.c_str(), sampleCoords.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000881 sampleCoords = coordVar;
882 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000883 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000884 GrStringBuilder accumVar("accum");
885 accumVar.appendS32(stageNum);
886 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);
887 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);
888 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);
889 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);
890 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000891 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000892 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 +0000893 }
junov@google.comf93e7172011-03-31 21:26:24 +0000894
895 if(fStageEffects[stageNum]) {
896 fStageEffects[stageNum]->genShaderCode(segments);
897 }
898}
899