blob: 1c0db251b7b3cd7dadf9146208184a65b6e7a220 [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"
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
88static void tex_matrix_name(int stage, GrStringBuilder* s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +000089#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000090 *s = "aTexM";
91#else
92 *s = "uTexM";
93#endif
bsalomon@google.comfc296292011-05-06 13:53:47 +000094 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +000095}
96
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000097static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
98 *s = "uTexelSize";
bsalomon@google.comfc296292011-05-06 13:53:47 +000099 s->appendS32(stage);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000100}
101
junov@google.comf93e7172011-03-31 21:26:24 +0000102static void sampler_name(int stage, GrStringBuilder* s) {
103 *s = "uSampler";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000104 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000105}
106
107static void stage_varying_name(int stage, GrStringBuilder* s) {
108 *s = "vStage";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000109 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000110}
111
112static void radial2_param_name(int stage, GrStringBuilder* s) {
113 *s = "uRadial2Params";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000114 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000115}
116
117static void radial2_varying_name(int stage, GrStringBuilder* s) {
118 *s = "vB";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000119 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000120}
121
122GrGLProgram::GrGLProgram() {
123 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
124 fStageEffects[stage] = NULL;
125 }
126}
127
128GrGLProgram::~GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000129}
130
131void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
132 // Add stage configuration to the key
133 key.keyData(reinterpret_cast<const uint8_t*>(&fProgramDesc), sizeof(ProgramDesc));
134
135 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
136 // First pass: count effects and write the count to the key.
137 // This may seem like we are adding redundant data to the
138 // key, but in ensures the one key cannot be a prefix of
139 // another key, or identical to the key of a different program.
140 GrGLEffect* currentEffect = fStageEffects[stage];
141 uint8_t effectCount = 0;
142 while (currentEffect) {
143 GrAssert(effectCount < 255); // overflow detection
144 ++effectCount;
145 currentEffect = currentEffect->nextEffect();
146 }
147 key.keyData(reinterpret_cast<const uint8_t*>(&effectCount), sizeof(uint8_t));
148
149 // Second pass: continue building key using the effects
150 currentEffect = fStageEffects[stage];
151 while (currentEffect) {
152 fStageEffects[stage]->buildKey(key);
153 }
154 }
155}
156
157bool GrGLProgram::doGLSetup(GrPrimitiveType type,
158 GrGLProgram::CachedData* programData) const {
159 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
160 GrGLEffect* effect = fStageEffects[stage];
161 if (effect) {
162 if (!effect->doGLSetup(type, programData->fProgramID)) {
163 return false;
164 }
165 }
166 }
167
168 return true;
169}
170
171void GrGLProgram::doGLPost() const {
172 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
173 GrGLEffect* effect = fStageEffects[stage];
174 if (effect) {
175 effect->doGLPost();
176 }
177 }
178}
179
Scroggo97c88c22011-05-11 14:05:25 +0000180/**
181 * Create a text coefficient to be used in fragment shader code.
182 */
183static void coefficientString(GrStringBuilder& str, SkXfermode::Coeff coeff,
184 const char* src, const char* dst) {
185 switch (coeff) {
186 case SkXfermode::kZero_Coeff: /** 0 */
187 str = "0.0";
188 break;
189 case SkXfermode::kOne_Coeff: /** 1 */
190 str = "1.0";
191 break;
192 case SkXfermode::kSA_Coeff: /** src alpha */
193 str.appendf("%s.a", src);
194 break;
195 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
196 str.appendf("(1.0 - %s.a)", src);
197 break;
198 case SkXfermode::kDA_Coeff: /** dst alpha */
199 str.appendf("%s.a", dst);
200 break;
201 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
202 str.appendf("(1.0 - %s.a)", dst);
203 break;
204 case SkXfermode::kSC_Coeff:
205 str.append(src);
206 break;
207 default:
208 break;
209 }
210}
211
212/**
213 * Adds a line to the fragment shader code which modifies the color by
214 * the specified color filter.
215 */
216static void addColorFilter(GrStringBuilder& FSCode, const char * outputVar,
217 SkXfermode::Mode colorFilterXfermode, const char* dstColor) {
218 SkXfermode::Coeff srcCoeff, dstCoeff;
Scroggoa8a57be2011-05-11 18:16:56 +0000219 SkDEBUGCODE(bool success =)
220 SkXfermode::ModeAsCoeff(colorFilterXfermode, &srcCoeff, &dstCoeff);
Scroggo97c88c22011-05-11 14:05:25 +0000221 // We currently do not handle modes that cannot be represented as
222 // coefficients.
223 GrAssert(success);
224 GrStringBuilder srcCoeffStr, dstCoeffStr;
225 coefficientString(srcCoeffStr, srcCoeff, COL_FILTER_UNI_NAME, dstColor);
226 coefficientString(dstCoeffStr, dstCoeff, COL_FILTER_UNI_NAME, dstColor);
227 FSCode.appendf("\t%s = %s*%s + %s*%s;\n", outputVar, srcCoeffStr.c_str(),
228 COL_FILTER_UNI_NAME, dstCoeffStr.c_str(), dstColor);
229}
230
bsalomon@google.com91961302011-05-09 18:39:58 +0000231bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000232
233 ShaderCodeSegments segments;
234 const uint32_t& layout = fProgramDesc.fVertexLayout;
235
bsalomon@google.com91961302011-05-09 18:39:58 +0000236 programData->fUniLocations.reset();
junov@google.comf93e7172011-03-31 21:26:24 +0000237
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000238#if GR_GL_ATTRIBUTE_MATRICES
239 segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000240 programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000241#else
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000242 segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000243 programData->fUniLocations.fViewMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000244#endif
245 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000246
bsalomon@google.com91961302011-05-09 18:39:58 +0000247 segments.fVSCode.append(
248 "void main() {\n"
249 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
250 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000251
bsalomon@google.com91961302011-05-09 18:39:58 +0000252 // incoming color to current stage being processed.
253 GrStringBuilder inColor;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000254
255 switch (fProgramDesc.fColorType) {
256 case ProgramDesc::kAttribute_ColorType:
bsalomon@google.com91961302011-05-09 18:39:58 +0000257 segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
258 segments.fVaryings.append("varying vec4 vColor;\n");
259 segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000260 inColor = "vColor";
261 break;
262 case ProgramDesc::kUniform_ColorType:
bsalomon@google.com91961302011-05-09 18:39:58 +0000263 segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
264 programData->fUniLocations.fColorUni = kUseUniform;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000265 inColor = COL_UNI_NAME;
266 break;
267 case ProgramDesc::kNone_ColorType:
268 inColor = "";
269 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000270 }
271
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000272 if (fProgramDesc.fEmitsPointSize){
bsalomon@google.com91961302011-05-09 18:39:58 +0000273 segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000274 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000275
bsalomon@google.com91961302011-05-09 18:39:58 +0000276 segments.fFSCode.append("void main() {\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000277
278 // add texture coordinates that are used to the list of vertex attr decls
bsalomon@google.com91961302011-05-09 18:39:58 +0000279 GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
junov@google.comf93e7172011-03-31 21:26:24 +0000280 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000281 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000282 tex_attr_name(t, texCoordAttrs + t);
bsalomon@google.com91961302011-05-09 18:39:58 +0000283 segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000284 }
285 }
286
Scroggo97c88c22011-05-11 14:05:25 +0000287 bool useColorFilter =
288 // The rest of transfer mode color filters have not been implemented
289 fProgramDesc.fColorFilterXfermode <= SkXfermode::kMultiply_Mode
290 // This mode has no effect.
291 && fProgramDesc.fColorFilterXfermode != SkXfermode::kDst_Mode;
292 bool onlyUseColorFilter = useColorFilter
293 && (fProgramDesc.fColorFilterXfermode == SkXfermode::kClear_Mode
294 || fProgramDesc.fColorFilterXfermode == SkXfermode::kSrc_Mode);
295 if (useColorFilter) {
296 // Set up a uniform for the color
297 segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
298 programData->fUniLocations.fColorFilterUni = kUseUniform;
299 }
300
junov@google.comf93e7172011-03-31 21:26:24 +0000301 // for each enabled stage figure out what the input coordinates are
302 // and count the number of stages in use.
303 const char* stageInCoords[GrDrawTarget::kNumStages];
304 int numActiveStages = 0;
305
Scroggo97c88c22011-05-11 14:05:25 +0000306 if (!onlyUseColorFilter) {
307 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
308 if (fProgramDesc.fStages[s].fEnabled) {
309 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
310 stageInCoords[s] = POS_ATTR_NAME;
311 } else {
312 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
313 // we better have input tex coordinates if stage is enabled.
314 GrAssert(tcIdx >= 0);
315 GrAssert(texCoordAttrs[tcIdx].size());
316 stageInCoords[s] = texCoordAttrs[tcIdx].c_str();
317 }
318 ++numActiveStages;
junov@google.comf93e7172011-03-31 21:26:24 +0000319 }
junov@google.comf93e7172011-03-31 21:26:24 +0000320 }
321 }
322
junov@google.comf93e7172011-03-31 21:26:24 +0000323 // if we have active stages string them together, feeding the output color
324 // of each to the next and generating code for each stage.
325 if (numActiveStages) {
326 int currActiveStage = 0;
Scroggo97c88c22011-05-11 14:05:25 +0000327 GrStringBuilder outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000328 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
329 if (fProgramDesc.fStages[s].fEnabled) {
Scroggo97c88c22011-05-11 14:05:25 +0000330 if (currActiveStage < (numActiveStages - 1) || useColorFilter) {
junov@google.comf93e7172011-03-31 21:26:24 +0000331 outColor = "color";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000332 outColor.appendS32(currActiveStage);
bsalomon@google.com91961302011-05-09 18:39:58 +0000333 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000334 } else {
335 outColor = "gl_FragColor";
336 }
337
338 genStageCode(s,
339 fProgramDesc.fStages[s],
bsalomon@google.comfc296292011-05-06 13:53:47 +0000340 inColor.size() ? inColor.c_str() : NULL,
341 outColor.c_str(),
junov@google.comf93e7172011-03-31 21:26:24 +0000342 stageInCoords[s],
343 &segments,
344 &programData->fUniLocations.fStages[s]);
345 ++currActiveStage;
346 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000347 }
348 }
Scroggo97c88c22011-05-11 14:05:25 +0000349 if (useColorFilter) {
350 addColorFilter(segments.fFSCode, "gl_FragColor",
351 fProgramDesc.fColorFilterXfermode, outColor.c_str());
352 }
353
junov@google.comf93e7172011-03-31 21:26:24 +0000354 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000355 // we may not have any incoming color
Scroggo97c88c22011-05-11 14:05:25 +0000356 const char * incomingColor = (inColor.size() ? inColor.c_str()
357 : "vec4(1,1,1,1)");
358 if (useColorFilter) {
359 addColorFilter(segments.fFSCode, "gl_FragColor",
360 fProgramDesc.fColorFilterXfermode, incomingColor);
361 } else {
362 segments.fFSCode.appendf("\tgl_FragColor = %s;\n", incomingColor);
363 }
junov@google.comf93e7172011-03-31 21:26:24 +0000364 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000365 segments.fVSCode.append("}\n");
366 segments.fFSCode.append("}\n");
367
368 if (!CompileFSAndVS(segments, programData)) {
369 return false;
370 }
371
372 if (!this->bindAttribsAndLinkProgram(texCoordAttrs, programData)) {
373 return false;
374 }
375
376 this->getUniformLocationsAndInitCache(programData);
377
378 return true;
379}
380
381bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
382 CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000383
junov@google.comf93e7172011-03-31 21:26:24 +0000384 const char* strings[4];
385 int lengths[4];
386 int stringCnt = 0;
387
bsalomon@google.comfc296292011-05-06 13:53:47 +0000388 if (segments.fVSUnis.size()) {
389 strings[stringCnt] = segments.fVSUnis.c_str();
390 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000391 ++stringCnt;
392 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000393 if (segments.fVSAttrs.size()) {
394 strings[stringCnt] = segments.fVSAttrs.c_str();
395 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000396 ++stringCnt;
397 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000398 if (segments.fVaryings.size()) {
399 strings[stringCnt] = segments.fVaryings.c_str();
400 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000401 ++stringCnt;
402 }
403
bsalomon@google.comfc296292011-05-06 13:53:47 +0000404 GrAssert(segments.fVSCode.size());
405 strings[stringCnt] = segments.fVSCode.c_str();
406 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000407 ++stringCnt;
408
409#if PRINT_SHADERS
bsalomon@google.comfc296292011-05-06 13:53:47 +0000410 GrPrintf(segments.fVSUnis.c_str());
411 GrPrintf(segments.fVSAttrs.c_str());
412 GrPrintf(segments.fVaryings.c_str());
413 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000414 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000415#endif
416 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
417 stringCnt,
418 strings,
419 lengths);
420
bsalomon@google.com91961302011-05-09 18:39:58 +0000421 if (!programData->fVShaderID) {
422 return false;
423 }
424
junov@google.comf93e7172011-03-31 21:26:24 +0000425 stringCnt = 0;
426
427 if (strlen(GrShaderPrecision()) > 1) {
428 strings[stringCnt] = GrShaderPrecision();
429 lengths[stringCnt] = strlen(GrShaderPrecision());
430 ++stringCnt;
431 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000432 if (segments.fFSUnis.size()) {
433 strings[stringCnt] = segments.fFSUnis.c_str();
434 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000435 ++stringCnt;
436 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000437 if (segments.fVaryings.size()) {
438 strings[stringCnt] = segments.fVaryings.c_str();
439 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000440 ++stringCnt;
441 }
442
bsalomon@google.comfc296292011-05-06 13:53:47 +0000443 GrAssert(segments.fFSCode.size());
444 strings[stringCnt] = segments.fFSCode.c_str();
445 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000446 ++stringCnt;
447
448#if PRINT_SHADERS
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000449 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000450 GrPrintf(segments.fFSUnis.c_str());
451 GrPrintf(segments.fVaryings.c_str());
452 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000453 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000454#endif
455 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
456 stringCnt,
457 strings,
458 lengths);
459
bsalomon@google.com91961302011-05-09 18:39:58 +0000460 if (!programData->fFShaderID) {
461 return false;
junov@google.comf93e7172011-03-31 21:26:24 +0000462 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000463 return true;
junov@google.comf93e7172011-03-31 21:26:24 +0000464}
465
466GrGLuint GrGLProgram::CompileShader(GrGLenum type,
467 int stringCnt,
468 const char** strings,
469 int* stringLengths) {
470 GrGLuint shader = GR_GL(CreateShader(type));
471 if (0 == shader) {
472 return 0;
473 }
474
475 GrGLint compiled = GR_GL_INIT_ZERO;
476 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
477 GR_GL(CompileShader(shader));
478 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
479
480 if (!compiled) {
481 GrGLint infoLen = GR_GL_INIT_ZERO;
482 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
483 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
484 if (infoLen > 0) {
485 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
486 for (int i = 0; i < stringCnt; ++i) {
487 if (NULL == stringLengths || stringLengths[i] < 0) {
488 GrPrintf(strings[i]);
489 } else {
490 GrPrintf("%.*s", stringLengths[i], strings[i]);
491 }
492 }
493 GrPrintf("\n%s", log.get());
494 }
495 GrAssert(!"Shader compilation failed!");
496 GR_GL(DeleteShader(shader));
497 return 0;
498 }
499 return shader;
500}
501
bsalomon@google.com91961302011-05-09 18:39:58 +0000502bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
503 CachedData* programData) const {
504 programData->fProgramID = GR_GL(CreateProgram());
505 if (!programData->fProgramID) {
506 return false;
507 }
508 const GrGLint& progID = programData->fProgramID;
509
510 GR_GL(AttachShader(progID, programData->fVShaderID));
511 GR_GL(AttachShader(progID, programData->fFShaderID));
512
513 // Bind the attrib locations to same values for all shaders
514 GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
515 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
516 if (texCoordAttrNames[t].size()) {
517 GR_GL(BindAttribLocation(progID,
518 TexCoordAttributeIdx(t),
519 texCoordAttrNames[t].c_str()));
520 }
521 }
522
523
524 if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
525 GR_GL(BindAttribLocation(progID,
526 ViewMatrixAttributeIdx(),
527 VIEW_MATRIX_NAME));
528 }
529
530 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
bsalomon@google.com72b4fcb2011-05-09 20:47:34 +0000531 const StageUniLocations& unis = programData->fUniLocations.fStages[s];
532 if (kSetAsAttribute == unis.fTextureMatrixUni) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000533 GrStringBuilder matName;
534 tex_matrix_name(s, &matName);
535 GR_GL(BindAttribLocation(progID,
536 TextureMatrixAttributeIdx(s),
537 matName.c_str()));
538 }
539 }
540
541
542 GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
543
544 GR_GL(LinkProgram(progID));
545
546 GrGLint linked = GR_GL_INIT_ZERO;
547 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
548 if (!linked) {
549 GrGLint infoLen = GR_GL_INIT_ZERO;
550 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
551 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
552 if (infoLen > 0) {
553 GR_GL(GetProgramInfoLog(progID,
554 infoLen+1,
555 NULL,
556 (char*)log.get()));
557 GrPrintf((char*)log.get());
558 }
559 GrAssert(!"Error linking program");
560 GR_GL(DeleteProgram(progID));
561 programData->fProgramID = 0;
562 return false;
563 }
564 return true;
565}
566
567void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
568 const GrGLint& progID = programData->fProgramID;
569
570 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
571 programData->fUniLocations.fViewMatrixUni =
572 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
573 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
574 }
575 if (kUseUniform == programData->fUniLocations.fColorUni) {
576 programData->fUniLocations.fColorUni =
577 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
578 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
579 }
Scroggo97c88c22011-05-11 14:05:25 +0000580 if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
581 programData->fUniLocations.fColorFilterUni =
582 GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
583 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
584 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000585
586 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
587 StageUniLocations& locations = programData->fUniLocations.fStages[s];
588 if (fProgramDesc.fStages[s].fEnabled) {
589 if (kUseUniform == locations.fTextureMatrixUni) {
590 GrStringBuilder texMName;
591 tex_matrix_name(s, &texMName);
592 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
593 progID,
594 texMName.c_str()));
595 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
596 }
597
598 if (kUseUniform == locations.fSamplerUni) {
599 GrStringBuilder samplerName;
600 sampler_name(s, &samplerName);
601 locations.fSamplerUni = GR_GL(GetUniformLocation(
602 progID,
603 samplerName.c_str()));
604 GrAssert(kUnusedUniform != locations.fSamplerUni);
605 }
606
607 if (kUseUniform == locations.fNormalizedTexelSizeUni) {
608 GrStringBuilder texelSizeName;
609 normalized_texel_size_name(s, &texelSizeName);
610 locations.fNormalizedTexelSizeUni =
611 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
612 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
613 }
614
615 if (kUseUniform == locations.fRadial2Uni) {
616 GrStringBuilder radial2ParamName;
617 radial2_param_name(s, &radial2ParamName);
618 locations.fRadial2Uni = GR_GL(GetUniformLocation(
619 progID,
620 radial2ParamName.c_str()));
621 GrAssert(kUnusedUniform != locations.fRadial2Uni);
622 }
623 }
624 }
625 GR_GL(UseProgram(progID));
626
627 // init sampler unis and set bogus values for state tracking
628 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
629 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
630 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
631 }
632 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
633 programData->fRadial2CenterX1[s] = GR_ScalarMax;
634 programData->fRadial2Radius0[s] = -GR_ScalarMax;
635 programData->fTextureWidth[s] = -1;
636 programData->fTextureHeight[s] = -1;
637 }
638 programData->fViewMatrix = GrMatrix::InvalidMatrix();
639 programData->fColor = GrColor_ILLEGAL;
Scroggo97c88c22011-05-11 14:05:25 +0000640 programData->fColorFilterColor = GrColor_ILLEGAL;
bsalomon@google.com91961302011-05-09 18:39:58 +0000641}
642
junov@google.comf93e7172011-03-31 21:26:24 +0000643//============================================================================
644// Stage code generation
645//============================================================================
646
647void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000648 const GrGLProgram::ProgramDesc::StageDesc& desc,
649 const char* fsInColor, // NULL means no incoming color
650 const char* fsOutColor,
651 const char* vsInCoord,
652 ShaderCodeSegments* segments,
653 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000654
655 GrAssert(stageNum >= 0 && stageNum <= 9);
656
bsalomon@google.com91961302011-05-09 18:39:58 +0000657 GrStringBuilder varyingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000658 stage_varying_name(stageNum, &varyingName);
659
660 // First decide how many coords are needed to access the texture
661 // Right now it's always 2 but we could start using 1D textures for
662 // gradients.
663 static const int coordDims = 2;
664 int varyingDims;
665 /// Vertex Shader Stuff
666
667 // decide whether we need a matrix to transform texture coords
668 // and whether the varying needs a perspective coord.
bsalomon@google.com91961302011-05-09 18:39:58 +0000669 GrStringBuilder texMName;
junov@google.comf93e7172011-03-31 21:26:24 +0000670 tex_matrix_name(stageNum, &texMName);
671 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
672 varyingDims = coordDims;
673 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000674 #if GR_GL_ATTRIBUTE_MATRICES
bsalomon@google.com91961302011-05-09 18:39:58 +0000675 segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
676 locations->fTextureMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000677 #else
bsalomon@google.com91961302011-05-09 18:39:58 +0000678 segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
679 locations->fTextureMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000680 #endif
681 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
682 varyingDims = coordDims;
683 } else {
684 varyingDims = coordDims + 1;
685 }
686 }
687
bsalomon@google.com91961302011-05-09 18:39:58 +0000688 GrStringBuilder samplerName;
junov@google.comf93e7172011-03-31 21:26:24 +0000689 sampler_name(stageNum, &samplerName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000690 segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
691 locations->fSamplerUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000692
bsalomon@google.com91961302011-05-09 18:39:58 +0000693 GrStringBuilder texelSizeName;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000694 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
695 normalized_texel_size_name(stageNum, &texelSizeName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000696 segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000697 }
698
bsalomon@google.com91961302011-05-09 18:39:58 +0000699 segments->fVaryings.appendf("varying %s %s;\n",
700 float_vector_type(varyingDims), varyingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000701
702 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
703 GrAssert(varyingDims == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000704 segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
junov@google.comf93e7172011-03-31 21:26:24 +0000705 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000706 // varying = texMatrix * texCoord
707 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
708 varyingName.c_str(), texMName.c_str(),
709 vsInCoord, vector_all_coords(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000710 }
711
bsalomon@google.com91961302011-05-09 18:39:58 +0000712 GrStringBuilder radial2ParamsName;
junov@google.comf93e7172011-03-31 21:26:24 +0000713 radial2_param_name(stageNum, &radial2ParamsName);
714 // for radial grads without perspective we can pass the linear
715 // part of the quadratic as a varying.
bsalomon@google.com91961302011-05-09 18:39:58 +0000716 GrStringBuilder radial2VaryingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000717 radial2_varying_name(stageNum, &radial2VaryingName);
718
719 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
720
bsalomon@google.comdcf1b0b2011-05-11 19:00:54 +0000721 segments->fVSUnis.appendf("uniform %s float %s[6];\n",
bsalomon@google.com91961302011-05-09 18:39:58 +0000722 GrPrecision(), radial2ParamsName.c_str());
723 segments->fFSUnis.appendf("uniform float %s[6];\n",
724 radial2ParamsName.c_str());
725 locations->fRadial2Uni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000726
727 // if there is perspective we don't interpolate this
728 if (varyingDims == coordDims) {
729 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000730 segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000731
bsalomon@google.com91961302011-05-09 18:39:58 +0000732 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
733 segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
734 radial2VaryingName.c_str(), radial2ParamsName.c_str(),
735 varyingName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000736 }
737 }
738
739 /// Fragment Shader Stuff
bsalomon@google.com91961302011-05-09 18:39:58 +0000740 GrStringBuilder fsCoordName;
junov@google.comf93e7172011-03-31 21:26:24 +0000741 // function used to access the shader, may be made projective
bsalomon@google.com91961302011-05-09 18:39:58 +0000742 GrStringBuilder texFunc("texture2D");
junov@google.comf93e7172011-03-31 21:26:24 +0000743 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
744 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
745 GrAssert(varyingDims == coordDims);
746 fsCoordName = varyingName;
747 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000748 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +0000749 // our final tex coords then when in perspective we have to
bsalomon@google.com91961302011-05-09 18:39:58 +0000750 // do an explicit divide. Otherwise, we can use a Proj func.
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000751 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
752 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000753 texFunc.append("Proj");
junov@google.comf93e7172011-03-31 21:26:24 +0000754 fsCoordName = varyingName;
755 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000756 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000757 fsCoordName.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000758 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
759 float_vector_type(coordDims),
760 fsCoordName.c_str(),
761 varyingName.c_str(),
762 vector_nonhomog_coords(varyingDims),
763 varyingName.c_str(),
764 vector_homog_coord(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000765 }
766 }
767
bsalomon@google.comfc296292011-05-06 13:53:47 +0000768 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000769 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +0000770 switch (desc.fCoordMapping) {
771 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
772 sampleCoords = fsCoordName;
773 break;
774 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000775 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 +0000776 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000777 break;
778 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000779 sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000780 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000781 break;
782 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.com91961302011-05-09 18:39:58 +0000783 GrStringBuilder cName("c");
784 GrStringBuilder ac4Name("ac4");
785 GrStringBuilder rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +0000786
bsalomon@google.comfc296292011-05-06 13:53:47 +0000787 cName.appendS32(stageNum);
788 ac4Name.appendS32(stageNum);
789 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +0000790
bsalomon@google.com91961302011-05-09 18:39:58 +0000791 // if we were able to interpolate the linear component bVar is the varying
792 // otherwise compute it
793 GrStringBuilder bVar;
junov@google.comf93e7172011-03-31 21:26:24 +0000794 if (coordDims == varyingDims) {
795 bVar = radial2VaryingName;
796 GrAssert(2 == varyingDims);
797 } else {
798 GrAssert(3 == varyingDims);
799 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000800 bVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000801 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
802 bVar.c_str(), radial2ParamsName.c_str(),
803 fsCoordName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000804 }
805
bsalomon@google.com91961302011-05-09 18:39:58 +0000806 // c = (x^2)+(y^2) - params[4]
807 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
808 cName.c_str(), fsCoordName.c_str(),
809 fsCoordName.c_str(),
810 radial2ParamsName.c_str());
811 // ac4 = 4.0 * params[0] * c
812 segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
813 ac4Name.c_str(), radial2ParamsName.c_str(),
814 cName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000815
bsalomon@google.com91961302011-05-09 18:39:58 +0000816 // root = sqrt(b^2-4ac)
817 // (abs to avoid exception due to fp precision)
818 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
819 rootName.c_str(), bVar.c_str(), bVar.c_str(),
820 ac4Name.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000821
bsalomon@google.com91961302011-05-09 18:39:58 +0000822 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
823 // y coord is 0.5 (texture is effectively 1D)
824 sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
825 bVar.c_str(), radial2ParamsName.c_str(),
826 rootName.c_str(), radial2ParamsName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000827 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000828 break;}
829 };
830
bsalomon@google.com91961302011-05-09 18:39:58 +0000831 const char* smear;
832 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
833 smear = ".aaaa";
834 } else {
835 smear = "";
836 }
837 GrStringBuilder modulate;
838 if (NULL != fsInColor) {
839 modulate.printf(" * %s", fsInColor);
840 }
841
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000842 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000843 locations->fNormalizedTexelSizeUni = kUseUniform;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000844 if (complexCoord) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000845 // assign the coord to a var rather than compute 4x.
846 GrStringBuilder coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +0000847 coordVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000848 segments->fFSCode.appendf("\t%s %s = %s;\n",
849 float_vector_type(coordDims),
850 coordVar.c_str(), sampleCoords.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000851 sampleCoords = coordVar;
852 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000853 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000854 GrStringBuilder accumVar("accum");
855 accumVar.appendS32(stageNum);
856 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);
857 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);
858 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);
859 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);
860 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000861 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000862 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 +0000863 }
junov@google.comf93e7172011-03-31 21:26:24 +0000864
865 if(fStageEffects[stageNum]) {
866 fStageEffects[stageNum]->genShaderCode(segments);
867 }
868}
869