blob: 03654703877a89ae75971071bf19aa8628b5694f [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"
23#include "GrStringBuilder.h"
24
25namespace {
26
27const char* GrPrecision() {
28 if (GR_GL_SUPPORT_ES2) {
29 return "mediump";
30 } else {
31 return "";
32 }
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.com4be283f2011-04-19 21:15:09 +000045#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000046 #define VIEW_MATRIX_NAME "aViewM"
47#else
48 #define VIEW_MATRIX_NAME "uViewM"
49#endif
50
51#define POS_ATTR_NAME "aPosition"
52#define COL_ATTR_NAME "aColor"
bsalomon@google.com4be283f2011-04-19 21:15:09 +000053#define COL_UNI_NAME "uColor"
junov@google.comf93e7172011-03-31 21:26:24 +000054
55// for variable names etc
56typedef GrSStringBuilder<16> GrTokenString;
57
58static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
59 *s = "aTexCoord";
60 s->appendInt(coordIdx);
61}
62
63static inline const char* float_vector_type(int count) {
64 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
65 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
66 return FLOAT_VECS[count];
67}
68
69static inline const char* vector_homog_coord(int count) {
70 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
71 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
72 return HOMOGS[count];
73}
74
75static inline const char* vector_nonhomog_coords(int count) {
76 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
77 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
78 return NONHOMOGS[count];
79}
80
81static inline const char* vector_all_coords(int count) {
82 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
83 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
84 return ALL[count];
85}
86
87static void tex_matrix_name(int stage, GrStringBuilder* s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +000088#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000089 *s = "aTexM";
90#else
91 *s = "uTexM";
92#endif
93 s->appendInt(stage);
94}
95
96static void sampler_name(int stage, GrStringBuilder* s) {
97 *s = "uSampler";
98 s->appendInt(stage);
99}
100
101static void stage_varying_name(int stage, GrStringBuilder* s) {
102 *s = "vStage";
103 s->appendInt(stage);
104}
105
106static void radial2_param_name(int stage, GrStringBuilder* s) {
107 *s = "uRadial2Params";
108 s->appendInt(stage);
109}
110
111static void radial2_varying_name(int stage, GrStringBuilder* s) {
112 *s = "vB";
113 s->appendInt(stage);
114}
115
116GrGLProgram::GrGLProgram() {
117 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
118 fStageEffects[stage] = NULL;
119 }
120}
121
122GrGLProgram::~GrGLProgram() {
123
124}
125
126void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
127 // Add stage configuration to the key
128 key.keyData(reinterpret_cast<const uint8_t*>(&fProgramDesc), sizeof(ProgramDesc));
129
130 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
131 // First pass: count effects and write the count to the key.
132 // This may seem like we are adding redundant data to the
133 // key, but in ensures the one key cannot be a prefix of
134 // another key, or identical to the key of a different program.
135 GrGLEffect* currentEffect = fStageEffects[stage];
136 uint8_t effectCount = 0;
137 while (currentEffect) {
138 GrAssert(effectCount < 255); // overflow detection
139 ++effectCount;
140 currentEffect = currentEffect->nextEffect();
141 }
142 key.keyData(reinterpret_cast<const uint8_t*>(&effectCount), sizeof(uint8_t));
143
144 // Second pass: continue building key using the effects
145 currentEffect = fStageEffects[stage];
146 while (currentEffect) {
147 fStageEffects[stage]->buildKey(key);
148 }
149 }
150}
151
152bool GrGLProgram::doGLSetup(GrPrimitiveType type,
153 GrGLProgram::CachedData* programData) const {
154 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
155 GrGLEffect* effect = fStageEffects[stage];
156 if (effect) {
157 if (!effect->doGLSetup(type, programData->fProgramID)) {
158 return false;
159 }
160 }
161 }
162
163 return true;
164}
165
166void GrGLProgram::doGLPost() const {
167 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
168 GrGLEffect* effect = fStageEffects[stage];
169 if (effect) {
170 effect->doGLPost();
171 }
172 }
173}
174
175void GrGLProgram::genProgram(GrGLProgram::CachedData* programData,
176 const GrDrawTarget* target) const {
177
178 ShaderCodeSegments segments;
179 const uint32_t& layout = fProgramDesc.fVertexLayout;
180
181 memset(&programData->fUniLocations, 0, sizeof(UniLocations));
182
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000183#if GR_GL_ATTRIBUTE_MATRICES
184 segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000185#else
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000186 segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000187#endif
188 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000189
190 segments.fVSCode = "void main() {\n"
191 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n"
192 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n";
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000193
194 // incoming color to current stage being processed.
195 GrTokenString inColor;
196
197 switch (fProgramDesc.fColorType) {
198 case ProgramDesc::kAttribute_ColorType:
199 segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n";
200 segments.fVaryings += "varying vec4 vColor;\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000201 segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n";
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000202 inColor = "vColor";
203 break;
204 case ProgramDesc::kUniform_ColorType:
205 segments.fFSUnis += "uniform vec4 " COL_UNI_NAME ";\n";
206 inColor = COL_UNI_NAME;
207 break;
208 case ProgramDesc::kNone_ColorType:
209 inColor = "";
210 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000211 }
212
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000213 if (fProgramDesc.fEmitsPointSize){
junov@google.comf93e7172011-03-31 21:26:24 +0000214 segments.fVSCode += "\tgl_PointSize = 1.0;\n";
215 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000216
junov@google.comf93e7172011-03-31 21:26:24 +0000217 segments.fFSCode = "void main() {\n";
218
219 // add texture coordinates that are used to the list of vertex attr decls
220 GrTokenString texCoordAttrs[GrDrawTarget::kMaxTexCoords];
221 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
222 if (target->VertexUsesTexCoordIdx(t, layout)) {
223 tex_attr_name(t, texCoordAttrs + t);
224
225 segments.fVSAttrs += "attribute vec2 ";
226 segments.fVSAttrs += texCoordAttrs[t];
227 segments.fVSAttrs += ";\n";
228 }
229 }
230
231 // for each enabled stage figure out what the input coordinates are
232 // and count the number of stages in use.
233 const char* stageInCoords[GrDrawTarget::kNumStages];
234 int numActiveStages = 0;
235
236 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
237 if (fProgramDesc.fStages[s].fEnabled) {
238 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
239 stageInCoords[s] = POS_ATTR_NAME;
240 } else {
241 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
242 // we better have input tex coordinates if stage is enabled.
243 GrAssert(tcIdx >= 0);
244 GrAssert(texCoordAttrs[tcIdx].length());
245 stageInCoords[s] = texCoordAttrs[tcIdx].cstr();
246 }
247 ++numActiveStages;
248 }
249 }
250
junov@google.comf93e7172011-03-31 21:26:24 +0000251 // if we have active stages string them together, feeding the output color
252 // of each to the next and generating code for each stage.
253 if (numActiveStages) {
254 int currActiveStage = 0;
255 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
256 if (fProgramDesc.fStages[s].fEnabled) {
257 GrTokenString outColor;
258 if (currActiveStage < (numActiveStages - 1)) {
259 outColor = "color";
260 outColor.appendInt(currActiveStage);
261 segments.fFSCode += "\tvec4 ";
262 segments.fFSCode += outColor;
263 segments.fFSCode += ";\n";
264 } else {
265 outColor = "gl_FragColor";
266 }
267
268 genStageCode(s,
269 fProgramDesc.fStages[s],
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000270 inColor.length() ? inColor.cstr() : NULL,
junov@google.comf93e7172011-03-31 21:26:24 +0000271 outColor.cstr(),
272 stageInCoords[s],
273 &segments,
274 &programData->fUniLocations.fStages[s]);
275 ++currActiveStage;
276 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000277 }
278 }
279 } else {
280 segments.fFSCode += "\tgl_FragColor = ";
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000281 if (inColor.length()) {
junov@google.comf93e7172011-03-31 21:26:24 +0000282 segments.fFSCode += inColor;
283 } else {
284 segments.fFSCode += "vec4(1,1,1,1)";
285 }
286 segments.fFSCode += ";\n";
287 }
288 segments.fFSCode += "}\n";
289 segments.fVSCode += "}\n";
290
291
292 const char* strings[4];
293 int lengths[4];
294 int stringCnt = 0;
295
296 if (segments.fVSUnis.length()) {
297 strings[stringCnt] = segments.fVSUnis.cstr();
298 lengths[stringCnt] = segments.fVSUnis.length();
299 ++stringCnt;
300 }
301 if (segments.fVSAttrs.length()) {
302 strings[stringCnt] = segments.fVSAttrs.cstr();
303 lengths[stringCnt] = segments.fVSAttrs.length();
304 ++stringCnt;
305 }
306 if (segments.fVaryings.length()) {
307 strings[stringCnt] = segments.fVaryings.cstr();
308 lengths[stringCnt] = segments.fVaryings.length();
309 ++stringCnt;
310 }
311
312 GrAssert(segments.fVSCode.length());
313 strings[stringCnt] = segments.fVSCode.cstr();
314 lengths[stringCnt] = segments.fVSCode.length();
315 ++stringCnt;
316
317#if PRINT_SHADERS
318 GrPrintf("%s%s%s%s\n",
319 segments.fVSUnis.cstr(),
320 segments.fVSAttrs.cstr(),
321 segments.fVaryings.cstr(),
322 segments.fVSCode.cstr());
323#endif
324 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
325 stringCnt,
326 strings,
327 lengths);
328
329 stringCnt = 0;
330
331 if (strlen(GrShaderPrecision()) > 1) {
332 strings[stringCnt] = GrShaderPrecision();
333 lengths[stringCnt] = strlen(GrShaderPrecision());
334 ++stringCnt;
335 }
336 if (segments.fFSUnis.length()) {
337 strings[stringCnt] = segments.fFSUnis.cstr();
338 lengths[stringCnt] = segments.fFSUnis.length();
339 ++stringCnt;
340 }
341 if (segments.fVaryings.length()) {
342 strings[stringCnt] = segments.fVaryings.cstr();
343 lengths[stringCnt] = segments.fVaryings.length();
344 ++stringCnt;
345 }
346
347 GrAssert(segments.fFSCode.length());
348 strings[stringCnt] = segments.fFSCode.cstr();
349 lengths[stringCnt] = segments.fFSCode.length();
350 ++stringCnt;
351
352#if PRINT_SHADERS
353 GrPrintf("%s%s%s%s\n",
354 GR_SHADER_PRECISION,
355 segments.fFSUnis.cstr(),
356 segments.fVaryings.cstr(),
357 segments.fFSCode.cstr());
358#endif
359 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
360 stringCnt,
361 strings,
362 lengths);
363
364 programData->fProgramID = GR_GL(CreateProgram());
365 const GrGLint& progID = programData->fProgramID;
366
367 GR_GL(AttachShader(progID, programData->fVShaderID));
368 GR_GL(AttachShader(progID, programData->fFShaderID));
369
370 // Bind the attrib locations to same values for all shaders
371 GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME));
372 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
373 if (texCoordAttrs[t].length()) {
374 GR_GL(BindAttribLocation(progID,
375 TEX_ATTR_LOCATION(t),
376 texCoordAttrs[t].cstr()));
377 }
378 }
379
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000380#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000381 // set unis to a bogus value so that checks against -1 before
382 // flushing will pass.
383 GR_GL(BindAttribLocation(progID,
384 VIEWMAT_ATTR_LOCATION,
385 VIEW_MATRIX_NAME));
386
387 program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION;
388
389 for (int s = 0; s < kNumStages; ++s) {
390 if (fProgramDesc.fStages[s].fEnabled) {
391 GrStringBuilder matName;
392 tex_matrix_name(s, &matName);
393 GR_GL(BindAttribLocation(progID,
394 TEXMAT_ATTR_LOCATION(s),
395 matName.cstr()));
396 program->fUniLocations.fStages[s].fTextureMatrixUni =
397 BOGUS_MATRIX_UNI_LOCATION;
398 }
399 }
400#endif
401
402 GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME));
403
404 GR_GL(LinkProgram(progID));
405
406 GrGLint linked = GR_GL_INIT_ZERO;
407 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
408 if (!linked) {
409 GrGLint infoLen = GR_GL_INIT_ZERO;
410 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
411 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
412 if (infoLen > 0) {
413 GR_GL(GetProgramInfoLog(progID,
414 infoLen+1,
415 NULL,
416 (char*)log.get()));
417 GrPrintf((char*)log.get());
418 }
419 GrAssert(!"Error linking program");
420 GR_GL(DeleteProgram(progID));
421 programData->fProgramID = 0;
422 return;
423 }
424
425 // Get uniform locations
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000426#if !GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000427 programData->fUniLocations.fViewMatrixUni =
428 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
429 GrAssert(-1 != programData->fUniLocations.fViewMatrixUni);
430#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000431 if (ProgramDesc::kUniform_ColorType == fProgramDesc.fColorType) {
432 programData->fUniLocations.fColorUni =
433 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
434 GrAssert(-1 != programData->fUniLocations.fColorUni);
435 } else {
436 programData->fUniLocations.fColorUni = -1;
437 }
438
junov@google.comf93e7172011-03-31 21:26:24 +0000439 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
440 StageUniLocations& locations = programData->fUniLocations.fStages[s];
441 if (fProgramDesc.fStages[s].fEnabled) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000442#if !GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000443 if (locations.fTextureMatrixUni) {
444 GrTokenString texMName;
445 tex_matrix_name(s, &texMName);
446 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
447 progID,
448 texMName.cstr()));
449 GrAssert(-1 != locations.fTextureMatrixUni);
450 } else {
451 locations.fTextureMatrixUni = -1;
452
453 }
454#endif
455
456 if (locations.fSamplerUni) {
457 GrTokenString samplerName;
458 sampler_name(s, &samplerName);
459 locations.fSamplerUni = GR_GL(GetUniformLocation(
460 progID,
461 samplerName.cstr()));
462 GrAssert(-1 != locations.fSamplerUni);
463 } else {
464 locations.fSamplerUni = -1;
465 }
466
467 if (locations.fRadial2Uni) {
468 GrTokenString radial2ParamName;
469 radial2_param_name(s, &radial2ParamName);
470 locations.fRadial2Uni = GR_GL(GetUniformLocation(
471 progID,
472 radial2ParamName.cstr()));
473 GrAssert(-1 != locations.fRadial2Uni);
474 } else {
475 locations.fRadial2Uni = -1;
476 }
477 } else {
478 locations.fSamplerUni = -1;
479 locations.fRadial2Uni = -1;
480 locations.fTextureMatrixUni = -1;
481 }
482 }
483 GR_GL(UseProgram(progID));
484
485 // init sampler unis and set bogus values for state tracking
486 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
487 if (-1 != programData->fUniLocations.fStages[s].fSamplerUni) {
488 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
489 }
490 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
491 programData->fRadial2CenterX1[s] = GR_ScalarMax;
492 programData->fRadial2Radius0[s] = -GR_ScalarMax;
493 }
494 programData->fViewMatrix = GrMatrix::InvalidMatrix();
495}
496
497GrGLuint GrGLProgram::CompileShader(GrGLenum type,
498 int stringCnt,
499 const char** strings,
500 int* stringLengths) {
501 GrGLuint shader = GR_GL(CreateShader(type));
502 if (0 == shader) {
503 return 0;
504 }
505
506 GrGLint compiled = GR_GL_INIT_ZERO;
507 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
508 GR_GL(CompileShader(shader));
509 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
510
511 if (!compiled) {
512 GrGLint infoLen = GR_GL_INIT_ZERO;
513 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
514 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
515 if (infoLen > 0) {
516 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
517 for (int i = 0; i < stringCnt; ++i) {
518 if (NULL == stringLengths || stringLengths[i] < 0) {
519 GrPrintf(strings[i]);
520 } else {
521 GrPrintf("%.*s", stringLengths[i], strings[i]);
522 }
523 }
524 GrPrintf("\n%s", log.get());
525 }
526 GrAssert(!"Shader compilation failed!");
527 GR_GL(DeleteShader(shader));
528 return 0;
529 }
530 return shader;
531}
532
533//============================================================================
534// Stage code generation
535//============================================================================
536
537void GrGLProgram::genStageCode(int stageNum,
538 const GrGLProgram::ProgramDesc::StageDesc& desc,
539 const char* fsInColor, // NULL means no incoming color
540 const char* fsOutColor,
541 const char* vsInCoord,
542 ShaderCodeSegments* segments,
543 StageUniLocations* locations) const {
544
545 GrAssert(stageNum >= 0 && stageNum <= 9);
546
547 GrTokenString varyingName;
548 stage_varying_name(stageNum, &varyingName);
549
550 // First decide how many coords are needed to access the texture
551 // Right now it's always 2 but we could start using 1D textures for
552 // gradients.
553 static const int coordDims = 2;
554 int varyingDims;
555 /// Vertex Shader Stuff
556
557 // decide whether we need a matrix to transform texture coords
558 // and whether the varying needs a perspective coord.
559 GrTokenString texMName;
560 tex_matrix_name(stageNum, &texMName);
561 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
562 varyingDims = coordDims;
563 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000564 #if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000565 segments->fVSAttrs += "attribute mat3 ";
566 segments->fVSAttrs += texMName;
567 segments->fVSAttrs += ";\n";
568 #else
569 segments->fVSUnis += "uniform mat3 ";
570 segments->fVSUnis += texMName;
571 segments->fVSUnis += ";\n";
572 locations->fTextureMatrixUni = 1;
573 #endif
574 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
575 varyingDims = coordDims;
576 } else {
577 varyingDims = coordDims + 1;
578 }
579 }
580
581 GrTokenString samplerName;
582 sampler_name(stageNum, &samplerName);
583 segments->fFSUnis += "uniform sampler2D ";
584 segments->fFSUnis += samplerName;
585 segments->fFSUnis += ";\n";
586 locations->fSamplerUni = 1;
587
588 segments->fVaryings += "varying ";
589 segments->fVaryings += float_vector_type(varyingDims);
590 segments->fVaryings += " ";
591 segments->fVaryings += varyingName;
592 segments->fVaryings += ";\n";
593
594 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
595 GrAssert(varyingDims == coordDims);
596 segments->fVSCode += "\t";
597 segments->fVSCode += varyingName;
598 segments->fVSCode += " = ";
599 segments->fVSCode += vsInCoord;
600 segments->fVSCode += ";\n";
601 } else {
602 segments->fVSCode += "\t";
603 segments->fVSCode += varyingName;
604 segments->fVSCode += " = (";
605 segments->fVSCode += texMName;
606 segments->fVSCode += " * vec3(";
607 segments->fVSCode += vsInCoord;
608 segments->fVSCode += ", 1))";
609 segments->fVSCode += vector_all_coords(varyingDims);
610 segments->fVSCode += ";\n";
611 }
612
613 GrTokenString radial2ParamsName;
614 radial2_param_name(stageNum, &radial2ParamsName);
615 // for radial grads without perspective we can pass the linear
616 // part of the quadratic as a varying.
617 GrTokenString radial2VaryingName;
618 radial2_varying_name(stageNum, &radial2VaryingName);
619
620 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
621
622 segments->fVSUnis += "uniform ";
623 segments->fVSUnis += GrPrecision();
624 segments->fVSUnis += " float ";
625 segments->fVSUnis += radial2ParamsName;
626 segments->fVSUnis += "[6];\n";
627
628 segments->fFSUnis += "uniform ";
629 segments->fFSUnis += GrPrecision();
630 segments->fFSUnis += " float ";
631 segments->fFSUnis += radial2ParamsName;
632 segments->fFSUnis += "[6];\n";
633 locations->fRadial2Uni = 1;
634
635 // if there is perspective we don't interpolate this
636 if (varyingDims == coordDims) {
637 GrAssert(2 == coordDims);
638 segments->fVaryings += "varying float ";
639 segments->fVaryings += radial2VaryingName;
640 segments->fVaryings += ";\n";
641
642 segments->fVSCode += "\t";
643 segments->fVSCode += radial2VaryingName;
644 segments->fVSCode += " = 2.0 * (";
645 segments->fVSCode += radial2ParamsName;
646 segments->fVSCode += "[2] * ";
647 segments->fVSCode += varyingName;
648 segments->fVSCode += ".x ";
649 segments->fVSCode += " - ";
650 segments->fVSCode += radial2ParamsName;
651 segments->fVSCode += "[3]);\n";
652 }
653 }
654
655 /// Fragment Shader Stuff
656 GrTokenString fsCoordName;
657 // function used to access the shader, may be made projective
658 GrTokenString texFunc("texture2D");
659 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
660 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
661 GrAssert(varyingDims == coordDims);
662 fsCoordName = varyingName;
663 } else {
664 // if we have to do some non-matrix op on the varyings to get
665 // our final tex coords then when in perspective we have to
666 // do an explicit divide
667 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) {
668 texFunc += "Proj";
669 fsCoordName = varyingName;
670 } else {
671 fsCoordName = "tCoord";
672 fsCoordName.appendInt(stageNum);
673
674 segments->fFSCode += "\t";
675 segments->fFSCode += float_vector_type(coordDims);
676 segments->fFSCode += " ";
677 segments->fFSCode += fsCoordName;
678 segments->fFSCode += " = ";
679 segments->fFSCode += varyingName;
680 segments->fFSCode += vector_nonhomog_coords(varyingDims);
681 segments->fFSCode += " / ";
682 segments->fFSCode += varyingName;
683 segments->fFSCode += vector_homog_coord(varyingDims);
684 segments->fFSCode += ";\n";
685 }
686 }
687
688 GrSStringBuilder<96> sampleCoords;
689 switch (desc.fCoordMapping) {
690 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
691 sampleCoords = fsCoordName;
692 break;
693 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
694 sampleCoords = "vec2(atan(-";
695 sampleCoords += fsCoordName;
696 sampleCoords += ".y, -";
697 sampleCoords += fsCoordName;
698 sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
699 break;
700 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
701 sampleCoords = "vec2(length(";
702 sampleCoords += fsCoordName;
703 sampleCoords += ".xy), 0.5)";
704 break;
705 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
706 GrTokenString cName = "c";
707 GrTokenString ac4Name = "ac4";
708 GrTokenString rootName = "root";
709
710 cName.appendInt(stageNum);
711 ac4Name.appendInt(stageNum);
712 rootName.appendInt(stageNum);
713
714 GrTokenString bVar;
715 if (coordDims == varyingDims) {
716 bVar = radial2VaryingName;
717 GrAssert(2 == varyingDims);
718 } else {
719 GrAssert(3 == varyingDims);
720 bVar = "b";
721 bVar.appendInt(stageNum);
722 segments->fFSCode += "\tfloat ";
723 segments->fFSCode += bVar;
724 segments->fFSCode += " = 2.0 * (";
725 segments->fFSCode += radial2ParamsName;
726 segments->fFSCode += "[2] * ";
727 segments->fFSCode += fsCoordName;
728 segments->fFSCode += ".x ";
729 segments->fFSCode += " - ";
730 segments->fFSCode += radial2ParamsName;
731 segments->fFSCode += "[3]);\n";
732 }
733
734 segments->fFSCode += "\tfloat ";
735 segments->fFSCode += cName;
736 segments->fFSCode += " = dot(";
737 segments->fFSCode += fsCoordName;
738 segments->fFSCode += ", ";
739 segments->fFSCode += fsCoordName;
740 segments->fFSCode += ") + ";
741 segments->fFSCode += " - ";
742 segments->fFSCode += radial2ParamsName;
743 segments->fFSCode += "[4];\n";
744
745 segments->fFSCode += "\tfloat ";
746 segments->fFSCode += ac4Name;
747 segments->fFSCode += " = ";
748 segments->fFSCode += radial2ParamsName;
749 segments->fFSCode += "[0] * 4.0 * ";
750 segments->fFSCode += cName;
751 segments->fFSCode += ";\n";
752
753 segments->fFSCode += "\tfloat ";
754 segments->fFSCode += rootName;
755 segments->fFSCode += " = sqrt(abs(";
756 segments->fFSCode += bVar;
757 segments->fFSCode += " * ";
758 segments->fFSCode += bVar;
759 segments->fFSCode += " - ";
760 segments->fFSCode += ac4Name;
761 segments->fFSCode += "));\n";
762
763 sampleCoords = "vec2((-";
764 sampleCoords += bVar;
765 sampleCoords += " + ";
766 sampleCoords += radial2ParamsName;
767 sampleCoords += "[5] * ";
768 sampleCoords += rootName;
769 sampleCoords += ") * ";
770 sampleCoords += radial2ParamsName;
771 sampleCoords += "[1], 0.5)\n";
772 break;}
773 };
774
775 segments->fFSCode += "\t";
776 segments->fFSCode += fsOutColor;
777 segments->fFSCode += " = ";
778 if (NULL != fsInColor) {
779 segments->fFSCode += fsInColor;
780 segments->fFSCode += " * ";
781 }
782 segments->fFSCode += texFunc;
783 segments->fFSCode += "(";
784 segments->fFSCode += samplerName;
785 segments->fFSCode += ", ";
786 segments->fFSCode += sampleCoords;
787 segments->fFSCode += ")";
788 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
789 segments->fFSCode += ".aaaa";
790 }
791 segments->fFSCode += ";\n";
792
793 if(fStageEffects[stageNum]) {
794 fStageEffects[stageNum]->genShaderCode(segments);
795 }
796}
797