blob: ce4f00034f1094de8364a90d56758694c6fb2b35 [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.com6aef1fb2011-05-05 12:33:22 +000045#define PRINT_SHADERS 0
46
bsalomon@google.com4be283f2011-04-19 21:15:09 +000047#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000048 #define VIEW_MATRIX_NAME "aViewM"
49#else
50 #define VIEW_MATRIX_NAME "uViewM"
51#endif
52
53#define POS_ATTR_NAME "aPosition"
54#define COL_ATTR_NAME "aColor"
bsalomon@google.com4be283f2011-04-19 21:15:09 +000055#define COL_UNI_NAME "uColor"
junov@google.comf93e7172011-03-31 21:26:24 +000056
57// for variable names etc
58typedef GrSStringBuilder<16> GrTokenString;
59
60static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
61 *s = "aTexCoord";
62 s->appendInt(coordIdx);
63}
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
95 s->appendInt(stage);
96}
97
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000098static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
99 *s = "uTexelSize";
100 s->appendInt(stage);
101}
102
junov@google.comf93e7172011-03-31 21:26:24 +0000103static void sampler_name(int stage, GrStringBuilder* s) {
104 *s = "uSampler";
105 s->appendInt(stage);
106}
107
108static void stage_varying_name(int stage, GrStringBuilder* s) {
109 *s = "vStage";
110 s->appendInt(stage);
111}
112
113static void radial2_param_name(int stage, GrStringBuilder* s) {
114 *s = "uRadial2Params";
115 s->appendInt(stage);
116}
117
118static void radial2_varying_name(int stage, GrStringBuilder* s) {
119 *s = "vB";
120 s->appendInt(stage);
121}
122
123GrGLProgram::GrGLProgram() {
124 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
125 fStageEffects[stage] = NULL;
126 }
127}
128
129GrGLProgram::~GrGLProgram() {
130
131}
132
133void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
134 // Add stage configuration to the key
135 key.keyData(reinterpret_cast<const uint8_t*>(&fProgramDesc), sizeof(ProgramDesc));
136
137 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
138 // First pass: count effects and write the count to the key.
139 // This may seem like we are adding redundant data to the
140 // key, but in ensures the one key cannot be a prefix of
141 // another key, or identical to the key of a different program.
142 GrGLEffect* currentEffect = fStageEffects[stage];
143 uint8_t effectCount = 0;
144 while (currentEffect) {
145 GrAssert(effectCount < 255); // overflow detection
146 ++effectCount;
147 currentEffect = currentEffect->nextEffect();
148 }
149 key.keyData(reinterpret_cast<const uint8_t*>(&effectCount), sizeof(uint8_t));
150
151 // Second pass: continue building key using the effects
152 currentEffect = fStageEffects[stage];
153 while (currentEffect) {
154 fStageEffects[stage]->buildKey(key);
155 }
156 }
157}
158
159bool GrGLProgram::doGLSetup(GrPrimitiveType type,
160 GrGLProgram::CachedData* programData) const {
161 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
162 GrGLEffect* effect = fStageEffects[stage];
163 if (effect) {
164 if (!effect->doGLSetup(type, programData->fProgramID)) {
165 return false;
166 }
167 }
168 }
169
170 return true;
171}
172
173void GrGLProgram::doGLPost() const {
174 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
175 GrGLEffect* effect = fStageEffects[stage];
176 if (effect) {
177 effect->doGLPost();
178 }
179 }
180}
181
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000182void GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000183
184 ShaderCodeSegments segments;
185 const uint32_t& layout = fProgramDesc.fVertexLayout;
186
187 memset(&programData->fUniLocations, 0, sizeof(UniLocations));
188
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000189#if GR_GL_ATTRIBUTE_MATRICES
190 segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000191#else
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000192 segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000193#endif
194 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000195
196 segments.fVSCode = "void main() {\n"
197 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n"
198 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n";
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000199
200 // incoming color to current stage being processed.
201 GrTokenString inColor;
202
203 switch (fProgramDesc.fColorType) {
204 case ProgramDesc::kAttribute_ColorType:
205 segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n";
206 segments.fVaryings += "varying vec4 vColor;\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000207 segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n";
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000208 inColor = "vColor";
209 break;
210 case ProgramDesc::kUniform_ColorType:
211 segments.fFSUnis += "uniform vec4 " COL_UNI_NAME ";\n";
212 inColor = COL_UNI_NAME;
213 break;
214 case ProgramDesc::kNone_ColorType:
215 inColor = "";
216 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000217 }
218
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000219 if (fProgramDesc.fEmitsPointSize){
junov@google.comf93e7172011-03-31 21:26:24 +0000220 segments.fVSCode += "\tgl_PointSize = 1.0;\n";
221 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000222
junov@google.comf93e7172011-03-31 21:26:24 +0000223 segments.fFSCode = "void main() {\n";
224
225 // add texture coordinates that are used to the list of vertex attr decls
226 GrTokenString texCoordAttrs[GrDrawTarget::kMaxTexCoords];
227 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000228 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000229 tex_attr_name(t, texCoordAttrs + t);
230
231 segments.fVSAttrs += "attribute vec2 ";
232 segments.fVSAttrs += texCoordAttrs[t];
233 segments.fVSAttrs += ";\n";
234 }
235 }
236
237 // for each enabled stage figure out what the input coordinates are
238 // and count the number of stages in use.
239 const char* stageInCoords[GrDrawTarget::kNumStages];
240 int numActiveStages = 0;
241
242 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
243 if (fProgramDesc.fStages[s].fEnabled) {
244 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
245 stageInCoords[s] = POS_ATTR_NAME;
246 } else {
247 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
248 // we better have input tex coordinates if stage is enabled.
249 GrAssert(tcIdx >= 0);
250 GrAssert(texCoordAttrs[tcIdx].length());
251 stageInCoords[s] = texCoordAttrs[tcIdx].cstr();
252 }
253 ++numActiveStages;
254 }
255 }
256
junov@google.comf93e7172011-03-31 21:26:24 +0000257 // if we have active stages string them together, feeding the output color
258 // of each to the next and generating code for each stage.
259 if (numActiveStages) {
260 int currActiveStage = 0;
261 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
262 if (fProgramDesc.fStages[s].fEnabled) {
263 GrTokenString outColor;
264 if (currActiveStage < (numActiveStages - 1)) {
265 outColor = "color";
266 outColor.appendInt(currActiveStage);
267 segments.fFSCode += "\tvec4 ";
268 segments.fFSCode += outColor;
269 segments.fFSCode += ";\n";
270 } else {
271 outColor = "gl_FragColor";
272 }
273
274 genStageCode(s,
275 fProgramDesc.fStages[s],
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000276 inColor.length() ? inColor.cstr() : NULL,
junov@google.comf93e7172011-03-31 21:26:24 +0000277 outColor.cstr(),
278 stageInCoords[s],
279 &segments,
280 &programData->fUniLocations.fStages[s]);
281 ++currActiveStage;
282 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000283 }
284 }
285 } else {
286 segments.fFSCode += "\tgl_FragColor = ";
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000287 if (inColor.length()) {
junov@google.comf93e7172011-03-31 21:26:24 +0000288 segments.fFSCode += inColor;
289 } else {
290 segments.fFSCode += "vec4(1,1,1,1)";
291 }
292 segments.fFSCode += ";\n";
293 }
294 segments.fFSCode += "}\n";
295 segments.fVSCode += "}\n";
296
297
298 const char* strings[4];
299 int lengths[4];
300 int stringCnt = 0;
301
302 if (segments.fVSUnis.length()) {
303 strings[stringCnt] = segments.fVSUnis.cstr();
304 lengths[stringCnt] = segments.fVSUnis.length();
305 ++stringCnt;
306 }
307 if (segments.fVSAttrs.length()) {
308 strings[stringCnt] = segments.fVSAttrs.cstr();
309 lengths[stringCnt] = segments.fVSAttrs.length();
310 ++stringCnt;
311 }
312 if (segments.fVaryings.length()) {
313 strings[stringCnt] = segments.fVaryings.cstr();
314 lengths[stringCnt] = segments.fVaryings.length();
315 ++stringCnt;
316 }
317
318 GrAssert(segments.fVSCode.length());
319 strings[stringCnt] = segments.fVSCode.cstr();
320 lengths[stringCnt] = segments.fVSCode.length();
321 ++stringCnt;
322
323#if PRINT_SHADERS
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000324 GrPrintf(segments.fVSUnis.cstr());
325 GrPrintf(segments.fVSAttrs.cstr());
326 GrPrintf(segments.fVaryings.cstr());
327 GrPrintf(segments.fVSCode.cstr());
328 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000329#endif
330 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
331 stringCnt,
332 strings,
333 lengths);
334
335 stringCnt = 0;
336
337 if (strlen(GrShaderPrecision()) > 1) {
338 strings[stringCnt] = GrShaderPrecision();
339 lengths[stringCnt] = strlen(GrShaderPrecision());
340 ++stringCnt;
341 }
342 if (segments.fFSUnis.length()) {
343 strings[stringCnt] = segments.fFSUnis.cstr();
344 lengths[stringCnt] = segments.fFSUnis.length();
345 ++stringCnt;
346 }
347 if (segments.fVaryings.length()) {
348 strings[stringCnt] = segments.fVaryings.cstr();
349 lengths[stringCnt] = segments.fVaryings.length();
350 ++stringCnt;
351 }
352
353 GrAssert(segments.fFSCode.length());
354 strings[stringCnt] = segments.fFSCode.cstr();
355 lengths[stringCnt] = segments.fFSCode.length();
356 ++stringCnt;
357
358#if PRINT_SHADERS
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000359 GrPrintf(GrShaderPrecision());
360 GrPrintf(segments.fFSUnis.cstr());
361 GrPrintf(segments.fVaryings.cstr());
362 GrPrintf(segments.fFSCode.cstr());
363 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000364#endif
365 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
366 stringCnt,
367 strings,
368 lengths);
369
370 programData->fProgramID = GR_GL(CreateProgram());
371 const GrGLint& progID = programData->fProgramID;
372
373 GR_GL(AttachShader(progID, programData->fVShaderID));
374 GR_GL(AttachShader(progID, programData->fFShaderID));
375
376 // Bind the attrib locations to same values for all shaders
377 GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME));
378 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
379 if (texCoordAttrs[t].length()) {
380 GR_GL(BindAttribLocation(progID,
381 TEX_ATTR_LOCATION(t),
382 texCoordAttrs[t].cstr()));
383 }
384 }
385
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000386#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000387 // set unis to a bogus value so that checks against -1 before
388 // flushing will pass.
389 GR_GL(BindAttribLocation(progID,
390 VIEWMAT_ATTR_LOCATION,
391 VIEW_MATRIX_NAME));
392
393 program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION;
394
395 for (int s = 0; s < kNumStages; ++s) {
396 if (fProgramDesc.fStages[s].fEnabled) {
397 GrStringBuilder matName;
398 tex_matrix_name(s, &matName);
399 GR_GL(BindAttribLocation(progID,
400 TEXMAT_ATTR_LOCATION(s),
401 matName.cstr()));
402 program->fUniLocations.fStages[s].fTextureMatrixUni =
403 BOGUS_MATRIX_UNI_LOCATION;
404 }
405 }
406#endif
407
408 GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME));
409
410 GR_GL(LinkProgram(progID));
411
412 GrGLint linked = GR_GL_INIT_ZERO;
413 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
414 if (!linked) {
415 GrGLint infoLen = GR_GL_INIT_ZERO;
416 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
417 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
418 if (infoLen > 0) {
419 GR_GL(GetProgramInfoLog(progID,
420 infoLen+1,
421 NULL,
422 (char*)log.get()));
423 GrPrintf((char*)log.get());
424 }
425 GrAssert(!"Error linking program");
426 GR_GL(DeleteProgram(progID));
427 programData->fProgramID = 0;
428 return;
429 }
430
431 // Get uniform locations
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000432#if !GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000433 programData->fUniLocations.fViewMatrixUni =
434 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
435 GrAssert(-1 != programData->fUniLocations.fViewMatrixUni);
436#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000437 if (ProgramDesc::kUniform_ColorType == fProgramDesc.fColorType) {
438 programData->fUniLocations.fColorUni =
439 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
440 GrAssert(-1 != programData->fUniLocations.fColorUni);
441 } else {
442 programData->fUniLocations.fColorUni = -1;
443 }
444
junov@google.comf93e7172011-03-31 21:26:24 +0000445 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
446 StageUniLocations& locations = programData->fUniLocations.fStages[s];
447 if (fProgramDesc.fStages[s].fEnabled) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000448#if !GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000449 if (locations.fTextureMatrixUni) {
450 GrTokenString texMName;
451 tex_matrix_name(s, &texMName);
452 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
453 progID,
454 texMName.cstr()));
455 GrAssert(-1 != locations.fTextureMatrixUni);
456 } else {
457 locations.fTextureMatrixUni = -1;
458
459 }
460#endif
461
462 if (locations.fSamplerUni) {
463 GrTokenString samplerName;
464 sampler_name(s, &samplerName);
465 locations.fSamplerUni = GR_GL(GetUniformLocation(
466 progID,
467 samplerName.cstr()));
468 GrAssert(-1 != locations.fSamplerUni);
469 } else {
470 locations.fSamplerUni = -1;
471 }
472
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000473 if (locations.fNormalizedTexelSizeUni) {
474 GrTokenString texelSizeName;
475 normalized_texel_size_name(s, &texelSizeName);
476 locations.fNormalizedTexelSizeUni =
477 GR_GL(GetUniformLocation(progID, texelSizeName.cstr()));
478 GrAssert(-1 != locations.fNormalizedTexelSizeUni);
479 } else {
480 locations.fNormalizedTexelSizeUni = -1;
481 }
482
junov@google.comf93e7172011-03-31 21:26:24 +0000483 if (locations.fRadial2Uni) {
484 GrTokenString radial2ParamName;
485 radial2_param_name(s, &radial2ParamName);
486 locations.fRadial2Uni = GR_GL(GetUniformLocation(
487 progID,
488 radial2ParamName.cstr()));
489 GrAssert(-1 != locations.fRadial2Uni);
490 } else {
491 locations.fRadial2Uni = -1;
492 }
493 } else {
494 locations.fSamplerUni = -1;
495 locations.fRadial2Uni = -1;
496 locations.fTextureMatrixUni = -1;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000497 locations.fNormalizedTexelSizeUni = -1;
junov@google.comf93e7172011-03-31 21:26:24 +0000498 }
499 }
500 GR_GL(UseProgram(progID));
501
502 // init sampler unis and set bogus values for state tracking
503 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
504 if (-1 != programData->fUniLocations.fStages[s].fSamplerUni) {
505 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
506 }
507 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
508 programData->fRadial2CenterX1[s] = GR_ScalarMax;
509 programData->fRadial2Radius0[s] = -GR_ScalarMax;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000510 programData->fTextureWidth[s] = -1;
511 programData->fTextureHeight[s] = -1;
junov@google.comf93e7172011-03-31 21:26:24 +0000512 }
513 programData->fViewMatrix = GrMatrix::InvalidMatrix();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000514 programData->fColor = GrColor_ILLEGAL;
junov@google.comf93e7172011-03-31 21:26:24 +0000515}
516
517GrGLuint GrGLProgram::CompileShader(GrGLenum type,
518 int stringCnt,
519 const char** strings,
520 int* stringLengths) {
521 GrGLuint shader = GR_GL(CreateShader(type));
522 if (0 == shader) {
523 return 0;
524 }
525
526 GrGLint compiled = GR_GL_INIT_ZERO;
527 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
528 GR_GL(CompileShader(shader));
529 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
530
531 if (!compiled) {
532 GrGLint infoLen = GR_GL_INIT_ZERO;
533 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
534 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
535 if (infoLen > 0) {
536 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
537 for (int i = 0; i < stringCnt; ++i) {
538 if (NULL == stringLengths || stringLengths[i] < 0) {
539 GrPrintf(strings[i]);
540 } else {
541 GrPrintf("%.*s", stringLengths[i], strings[i]);
542 }
543 }
544 GrPrintf("\n%s", log.get());
545 }
546 GrAssert(!"Shader compilation failed!");
547 GR_GL(DeleteShader(shader));
548 return 0;
549 }
550 return shader;
551}
552
553//============================================================================
554// Stage code generation
555//============================================================================
556
557void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000558 const GrGLProgram::ProgramDesc::StageDesc& desc,
559 const char* fsInColor, // NULL means no incoming color
560 const char* fsOutColor,
561 const char* vsInCoord,
562 ShaderCodeSegments* segments,
563 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000564
565 GrAssert(stageNum >= 0 && stageNum <= 9);
566
567 GrTokenString varyingName;
568 stage_varying_name(stageNum, &varyingName);
569
570 // First decide how many coords are needed to access the texture
571 // Right now it's always 2 but we could start using 1D textures for
572 // gradients.
573 static const int coordDims = 2;
574 int varyingDims;
575 /// Vertex Shader Stuff
576
577 // decide whether we need a matrix to transform texture coords
578 // and whether the varying needs a perspective coord.
579 GrTokenString texMName;
580 tex_matrix_name(stageNum, &texMName);
581 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
582 varyingDims = coordDims;
583 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000584 #if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000585 segments->fVSAttrs += "attribute mat3 ";
586 segments->fVSAttrs += texMName;
587 segments->fVSAttrs += ";\n";
588 #else
589 segments->fVSUnis += "uniform mat3 ";
590 segments->fVSUnis += texMName;
591 segments->fVSUnis += ";\n";
592 locations->fTextureMatrixUni = 1;
593 #endif
594 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
595 varyingDims = coordDims;
596 } else {
597 varyingDims = coordDims + 1;
598 }
599 }
600
601 GrTokenString samplerName;
602 sampler_name(stageNum, &samplerName);
603 segments->fFSUnis += "uniform sampler2D ";
604 segments->fFSUnis += samplerName;
605 segments->fFSUnis += ";\n";
606 locations->fSamplerUni = 1;
607
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000608 GrTokenString texelSizeName;
609 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
610 normalized_texel_size_name(stageNum, &texelSizeName);
611 segments->fFSUnis += "uniform vec2 ";
612 segments->fFSUnis += texelSizeName;
613 segments->fFSUnis += ";\n";
614 }
615
junov@google.comf93e7172011-03-31 21:26:24 +0000616 segments->fVaryings += "varying ";
617 segments->fVaryings += float_vector_type(varyingDims);
618 segments->fVaryings += " ";
619 segments->fVaryings += varyingName;
620 segments->fVaryings += ";\n";
621
622 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
623 GrAssert(varyingDims == coordDims);
624 segments->fVSCode += "\t";
625 segments->fVSCode += varyingName;
626 segments->fVSCode += " = ";
627 segments->fVSCode += vsInCoord;
628 segments->fVSCode += ";\n";
629 } else {
630 segments->fVSCode += "\t";
631 segments->fVSCode += varyingName;
632 segments->fVSCode += " = (";
633 segments->fVSCode += texMName;
634 segments->fVSCode += " * vec3(";
635 segments->fVSCode += vsInCoord;
636 segments->fVSCode += ", 1))";
637 segments->fVSCode += vector_all_coords(varyingDims);
638 segments->fVSCode += ";\n";
639 }
640
641 GrTokenString radial2ParamsName;
642 radial2_param_name(stageNum, &radial2ParamsName);
643 // for radial grads without perspective we can pass the linear
644 // part of the quadratic as a varying.
645 GrTokenString radial2VaryingName;
646 radial2_varying_name(stageNum, &radial2VaryingName);
647
648 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
649
650 segments->fVSUnis += "uniform ";
651 segments->fVSUnis += GrPrecision();
652 segments->fVSUnis += " float ";
653 segments->fVSUnis += radial2ParamsName;
654 segments->fVSUnis += "[6];\n";
655
656 segments->fFSUnis += "uniform ";
657 segments->fFSUnis += GrPrecision();
658 segments->fFSUnis += " float ";
659 segments->fFSUnis += radial2ParamsName;
660 segments->fFSUnis += "[6];\n";
661 locations->fRadial2Uni = 1;
662
663 // if there is perspective we don't interpolate this
664 if (varyingDims == coordDims) {
665 GrAssert(2 == coordDims);
666 segments->fVaryings += "varying float ";
667 segments->fVaryings += radial2VaryingName;
668 segments->fVaryings += ";\n";
669
670 segments->fVSCode += "\t";
671 segments->fVSCode += radial2VaryingName;
672 segments->fVSCode += " = 2.0 * (";
673 segments->fVSCode += radial2ParamsName;
674 segments->fVSCode += "[2] * ";
675 segments->fVSCode += varyingName;
676 segments->fVSCode += ".x ";
677 segments->fVSCode += " - ";
678 segments->fVSCode += radial2ParamsName;
679 segments->fVSCode += "[3]);\n";
680 }
681 }
682
683 /// Fragment Shader Stuff
684 GrTokenString fsCoordName;
685 // function used to access the shader, may be made projective
686 GrTokenString texFunc("texture2D");
687 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
688 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
689 GrAssert(varyingDims == coordDims);
690 fsCoordName = varyingName;
691 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000692 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +0000693 // our final tex coords then when in perspective we have to
694 // do an explicit divide
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000695 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
696 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
junov@google.comf93e7172011-03-31 21:26:24 +0000697 texFunc += "Proj";
698 fsCoordName = varyingName;
699 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000700 fsCoordName = "inCoord";
junov@google.comf93e7172011-03-31 21:26:24 +0000701 fsCoordName.appendInt(stageNum);
702
703 segments->fFSCode += "\t";
704 segments->fFSCode += float_vector_type(coordDims);
705 segments->fFSCode += " ";
706 segments->fFSCode += fsCoordName;
707 segments->fFSCode += " = ";
708 segments->fFSCode += varyingName;
709 segments->fFSCode += vector_nonhomog_coords(varyingDims);
710 segments->fFSCode += " / ";
711 segments->fFSCode += varyingName;
712 segments->fFSCode += vector_homog_coord(varyingDims);
713 segments->fFSCode += ";\n";
714 }
715 }
716
717 GrSStringBuilder<96> sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000718 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +0000719 switch (desc.fCoordMapping) {
720 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
721 sampleCoords = fsCoordName;
722 break;
723 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
724 sampleCoords = "vec2(atan(-";
725 sampleCoords += fsCoordName;
726 sampleCoords += ".y, -";
727 sampleCoords += fsCoordName;
728 sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000729 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000730 break;
731 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
732 sampleCoords = "vec2(length(";
733 sampleCoords += fsCoordName;
734 sampleCoords += ".xy), 0.5)";
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000735 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000736 break;
737 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
738 GrTokenString cName = "c";
739 GrTokenString ac4Name = "ac4";
740 GrTokenString rootName = "root";
741
742 cName.appendInt(stageNum);
743 ac4Name.appendInt(stageNum);
744 rootName.appendInt(stageNum);
745
746 GrTokenString bVar;
747 if (coordDims == varyingDims) {
748 bVar = radial2VaryingName;
749 GrAssert(2 == varyingDims);
750 } else {
751 GrAssert(3 == varyingDims);
752 bVar = "b";
753 bVar.appendInt(stageNum);
754 segments->fFSCode += "\tfloat ";
755 segments->fFSCode += bVar;
756 segments->fFSCode += " = 2.0 * (";
757 segments->fFSCode += radial2ParamsName;
758 segments->fFSCode += "[2] * ";
759 segments->fFSCode += fsCoordName;
760 segments->fFSCode += ".x ";
761 segments->fFSCode += " - ";
762 segments->fFSCode += radial2ParamsName;
763 segments->fFSCode += "[3]);\n";
764 }
765
766 segments->fFSCode += "\tfloat ";
767 segments->fFSCode += cName;
768 segments->fFSCode += " = dot(";
769 segments->fFSCode += fsCoordName;
770 segments->fFSCode += ", ";
771 segments->fFSCode += fsCoordName;
772 segments->fFSCode += ") + ";
773 segments->fFSCode += " - ";
774 segments->fFSCode += radial2ParamsName;
775 segments->fFSCode += "[4];\n";
776
777 segments->fFSCode += "\tfloat ";
778 segments->fFSCode += ac4Name;
779 segments->fFSCode += " = ";
780 segments->fFSCode += radial2ParamsName;
781 segments->fFSCode += "[0] * 4.0 * ";
782 segments->fFSCode += cName;
783 segments->fFSCode += ";\n";
784
785 segments->fFSCode += "\tfloat ";
786 segments->fFSCode += rootName;
787 segments->fFSCode += " = sqrt(abs(";
788 segments->fFSCode += bVar;
789 segments->fFSCode += " * ";
790 segments->fFSCode += bVar;
791 segments->fFSCode += " - ";
792 segments->fFSCode += ac4Name;
793 segments->fFSCode += "));\n";
794
795 sampleCoords = "vec2((-";
796 sampleCoords += bVar;
797 sampleCoords += " + ";
798 sampleCoords += radial2ParamsName;
799 sampleCoords += "[5] * ";
800 sampleCoords += rootName;
801 sampleCoords += ") * ";
802 sampleCoords += radial2ParamsName;
803 sampleCoords += "[1], 0.5)\n";
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000804 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000805 break;}
806 };
807
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000808 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
809 locations->fNormalizedTexelSizeUni = 1;
810 if (complexCoord) {
811 GrTokenString coordVar("tCoord");
812 coordVar.appendInt(stageNum);
813 segments->fFSCode += "\t";
814 segments->fFSCode += float_vector_type(coordDims);
815 segments->fFSCode += " ";
816 segments->fFSCode += coordVar;
817 segments->fFSCode += " = ";
818 segments->fFSCode += sampleCoords;
819 segments->fFSCode += ";\n";
820 sampleCoords = coordVar;
821 }
822 static const char sign[] = {'-','+'};
823 GrTokenString stageAccumVar("stage2x2Accum");
824 stageAccumVar.appendInt(stageNum);
825 segments->fFSCode += "\tvec4 ";
826 segments->fFSCode += stageAccumVar;
827 segments->fFSCode += " = ";
828 GrAssert(2 == coordDims);
829 for (int y = 0; y < 2; ++y) {
830 for (int x = 0; x < 2; ++x) {
831 segments->fFSCode += texFunc;
832 segments->fFSCode += "(";
833 segments->fFSCode += samplerName;
834 segments->fFSCode += ", ";
835 segments->fFSCode += sampleCoords;
836 segments->fFSCode += " + vec2(";
837 segments->fFSCode += sign[x];
838 segments->fFSCode += texelSizeName;
839 segments->fFSCode += ".x, ";
840 segments->fFSCode += sign[y];
841 segments->fFSCode += texelSizeName;
842 segments->fFSCode += ".y))";
843 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
844 segments->fFSCode += ".aaaa";
845 }
846 segments->fFSCode += ";\n";
847 if (1 != x || 1 !=y ) {
848 segments->fFSCode += "\t";
849 segments->fFSCode += stageAccumVar;
850 segments->fFSCode += " += ";
851 }
852 }
853 }
854 segments->fFSCode += "\t";
855 segments->fFSCode += fsOutColor;
856 segments->fFSCode += " = ";
857 if (NULL != fsInColor) {
858 segments->fFSCode += fsInColor;
859 segments->fFSCode += " * ";
860 }
861 segments->fFSCode += stageAccumVar;
862 segments->fFSCode += " / 4;\n";
863 } else {
864 segments->fFSCode += "\t";
865 segments->fFSCode += fsOutColor;
866 segments->fFSCode += " = ";
867 if (NULL != fsInColor) {
868 segments->fFSCode += fsInColor;
869 segments->fFSCode += " * ";
870 }
871
872 segments->fFSCode += texFunc;
873 segments->fFSCode += "(";
874 segments->fFSCode += samplerName;
875 segments->fFSCode += ", ";
876 segments->fFSCode += sampleCoords;
877 segments->fFSCode += ")";
878 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
879 segments->fFSCode += ".aaaa";
880 }
881 segments->fFSCode += ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000882 }
junov@google.comf93e7172011-03-31 21:26:24 +0000883
884 if(fStageEffects[stageNum]) {
885 fStageEffects[stageNum]->genShaderCode(segments);
886 }
887}
888