blob: 76a7f102bf9eb8f90c440e4226b84c6d045c8b89 [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
bsalomon@google.comfc296292011-05-06 13:53:47 +000058typedef GrStringBuilder GrTokenString;
junov@google.comf93e7172011-03-31 21:26:24 +000059
60static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
61 *s = "aTexCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +000062 s->appendS32(coordIdx);
junov@google.comf93e7172011-03-31 21:26:24 +000063}
64
65static inline const char* float_vector_type(int count) {
66 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
67 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
68 return FLOAT_VECS[count];
69}
70
71static inline const char* vector_homog_coord(int count) {
72 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
73 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
74 return HOMOGS[count];
75}
76
77static inline const char* vector_nonhomog_coords(int count) {
78 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
79 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
80 return NONHOMOGS[count];
81}
82
83static inline const char* vector_all_coords(int count) {
84 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
85 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
86 return ALL[count];
87}
88
89static void tex_matrix_name(int stage, GrStringBuilder* s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +000090#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000091 *s = "aTexM";
92#else
93 *s = "uTexM";
94#endif
bsalomon@google.comfc296292011-05-06 13:53:47 +000095 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +000096}
97
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000098static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
99 *s = "uTexelSize";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000100 s->appendS32(stage);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000101}
102
junov@google.comf93e7172011-03-31 21:26:24 +0000103static void sampler_name(int stage, GrStringBuilder* s) {
104 *s = "uSampler";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000105 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000106}
107
108static void stage_varying_name(int stage, GrStringBuilder* s) {
109 *s = "vStage";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000110 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000111}
112
113static void radial2_param_name(int stage, GrStringBuilder* s) {
114 *s = "uRadial2Params";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000115 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000116}
117
118static void radial2_varying_name(int stage, GrStringBuilder* s) {
119 *s = "vB";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000120 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000121}
122
123GrGLProgram::GrGLProgram() {
124 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
125 fStageEffects[stage] = NULL;
126 }
127}
128
129GrGLProgram::~GrGLProgram() {
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);
bsalomon@google.comfc296292011-05-06 13:53:47 +0000250 GrAssert(texCoordAttrs[tcIdx].size());
251 stageInCoords[s] = texCoordAttrs[tcIdx].c_str();
junov@google.comf93e7172011-03-31 21:26:24 +0000252 }
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";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000266 outColor.appendS32(currActiveStage);
junov@google.comf93e7172011-03-31 21:26:24 +0000267 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.comfc296292011-05-06 13:53:47 +0000276 inColor.size() ? inColor.c_str() : NULL,
277 outColor.c_str(),
junov@google.comf93e7172011-03-31 21:26:24 +0000278 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.comfc296292011-05-06 13:53:47 +0000287 if (inColor.size()) {
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
junov@google.comf93e7172011-03-31 21:26:24 +0000297 const char* strings[4];
298 int lengths[4];
299 int stringCnt = 0;
300
bsalomon@google.comfc296292011-05-06 13:53:47 +0000301 if (segments.fVSUnis.size()) {
302 strings[stringCnt] = segments.fVSUnis.c_str();
303 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000304 ++stringCnt;
305 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000306 if (segments.fVSAttrs.size()) {
307 strings[stringCnt] = segments.fVSAttrs.c_str();
308 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000309 ++stringCnt;
310 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000311 if (segments.fVaryings.size()) {
312 strings[stringCnt] = segments.fVaryings.c_str();
313 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000314 ++stringCnt;
315 }
316
bsalomon@google.comfc296292011-05-06 13:53:47 +0000317 GrAssert(segments.fVSCode.size());
318 strings[stringCnt] = segments.fVSCode.c_str();
319 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000320 ++stringCnt;
321
322#if PRINT_SHADERS
bsalomon@google.comfc296292011-05-06 13:53:47 +0000323 GrPrintf(segments.fVSUnis.c_str());
324 GrPrintf(segments.fVSAttrs.c_str());
325 GrPrintf(segments.fVaryings.c_str());
326 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000327 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000328#endif
329 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
330 stringCnt,
331 strings,
332 lengths);
333
334 stringCnt = 0;
335
336 if (strlen(GrShaderPrecision()) > 1) {
337 strings[stringCnt] = GrShaderPrecision();
338 lengths[stringCnt] = strlen(GrShaderPrecision());
339 ++stringCnt;
340 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000341 if (segments.fFSUnis.size()) {
342 strings[stringCnt] = segments.fFSUnis.c_str();
343 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000344 ++stringCnt;
345 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000346 if (segments.fVaryings.size()) {
347 strings[stringCnt] = segments.fVaryings.c_str();
348 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000349 ++stringCnt;
350 }
351
bsalomon@google.comfc296292011-05-06 13:53:47 +0000352 GrAssert(segments.fFSCode.size());
353 strings[stringCnt] = segments.fFSCode.c_str();
354 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000355 ++stringCnt;
356
357#if PRINT_SHADERS
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000358 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000359 GrPrintf(segments.fFSUnis.c_str());
360 GrPrintf(segments.fVaryings.c_str());
361 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000362 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000363#endif
364 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
365 stringCnt,
366 strings,
367 lengths);
368
369 programData->fProgramID = GR_GL(CreateProgram());
370 const GrGLint& progID = programData->fProgramID;
371
372 GR_GL(AttachShader(progID, programData->fVShaderID));
373 GR_GL(AttachShader(progID, programData->fFShaderID));
374
375 // Bind the attrib locations to same values for all shaders
376 GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME));
377 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.comfc296292011-05-06 13:53:47 +0000378 if (texCoordAttrs[t].size()) {
junov@google.comf93e7172011-03-31 21:26:24 +0000379 GR_GL(BindAttribLocation(progID,
380 TEX_ATTR_LOCATION(t),
bsalomon@google.comfc296292011-05-06 13:53:47 +0000381 texCoordAttrs[t].c_str()));
junov@google.comf93e7172011-03-31 21:26:24 +0000382 }
383 }
384
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000385#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000386 // set unis to a bogus value so that checks against -1 before
387 // flushing will pass.
388 GR_GL(BindAttribLocation(progID,
389 VIEWMAT_ATTR_LOCATION,
390 VIEW_MATRIX_NAME));
391
392 program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION;
393
394 for (int s = 0; s < kNumStages; ++s) {
395 if (fProgramDesc.fStages[s].fEnabled) {
396 GrStringBuilder matName;
397 tex_matrix_name(s, &matName);
398 GR_GL(BindAttribLocation(progID,
399 TEXMAT_ATTR_LOCATION(s),
bsalomon@google.comfc296292011-05-06 13:53:47 +0000400 matName.c_str()));
junov@google.comf93e7172011-03-31 21:26:24 +0000401 program->fUniLocations.fStages[s].fTextureMatrixUni =
402 BOGUS_MATRIX_UNI_LOCATION;
403 }
404 }
405#endif
406
407 GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME));
408
409 GR_GL(LinkProgram(progID));
410
411 GrGLint linked = GR_GL_INIT_ZERO;
412 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
413 if (!linked) {
414 GrGLint infoLen = GR_GL_INIT_ZERO;
415 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
416 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
417 if (infoLen > 0) {
418 GR_GL(GetProgramInfoLog(progID,
419 infoLen+1,
420 NULL,
421 (char*)log.get()));
422 GrPrintf((char*)log.get());
423 }
424 GrAssert(!"Error linking program");
425 GR_GL(DeleteProgram(progID));
426 programData->fProgramID = 0;
427 return;
428 }
429
430 // Get uniform locations
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000431#if !GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000432 programData->fUniLocations.fViewMatrixUni =
433 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
434 GrAssert(-1 != programData->fUniLocations.fViewMatrixUni);
435#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000436 if (ProgramDesc::kUniform_ColorType == fProgramDesc.fColorType) {
437 programData->fUniLocations.fColorUni =
438 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
439 GrAssert(-1 != programData->fUniLocations.fColorUni);
440 } else {
441 programData->fUniLocations.fColorUni = -1;
442 }
443
junov@google.comf93e7172011-03-31 21:26:24 +0000444 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
445 StageUniLocations& locations = programData->fUniLocations.fStages[s];
446 if (fProgramDesc.fStages[s].fEnabled) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000447#if !GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000448 if (locations.fTextureMatrixUni) {
449 GrTokenString texMName;
450 tex_matrix_name(s, &texMName);
451 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
452 progID,
bsalomon@google.comfc296292011-05-06 13:53:47 +0000453 texMName.c_str()));
junov@google.comf93e7172011-03-31 21:26:24 +0000454 GrAssert(-1 != locations.fTextureMatrixUni);
455 } else {
456 locations.fTextureMatrixUni = -1;
457
458 }
459#endif
460
461 if (locations.fSamplerUni) {
462 GrTokenString samplerName;
463 sampler_name(s, &samplerName);
464 locations.fSamplerUni = GR_GL(GetUniformLocation(
465 progID,
bsalomon@google.comfc296292011-05-06 13:53:47 +0000466 samplerName.c_str()));
junov@google.comf93e7172011-03-31 21:26:24 +0000467 GrAssert(-1 != locations.fSamplerUni);
468 } else {
469 locations.fSamplerUni = -1;
470 }
471
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000472 if (locations.fNormalizedTexelSizeUni) {
473 GrTokenString texelSizeName;
474 normalized_texel_size_name(s, &texelSizeName);
475 locations.fNormalizedTexelSizeUni =
bsalomon@google.comfc296292011-05-06 13:53:47 +0000476 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000477 GrAssert(-1 != locations.fNormalizedTexelSizeUni);
478 } else {
479 locations.fNormalizedTexelSizeUni = -1;
480 }
481
junov@google.comf93e7172011-03-31 21:26:24 +0000482 if (locations.fRadial2Uni) {
483 GrTokenString radial2ParamName;
484 radial2_param_name(s, &radial2ParamName);
485 locations.fRadial2Uni = GR_GL(GetUniformLocation(
486 progID,
bsalomon@google.comfc296292011-05-06 13:53:47 +0000487 radial2ParamName.c_str()));
junov@google.comf93e7172011-03-31 21:26:24 +0000488 GrAssert(-1 != locations.fRadial2Uni);
489 } else {
490 locations.fRadial2Uni = -1;
491 }
492 } else {
493 locations.fSamplerUni = -1;
494 locations.fRadial2Uni = -1;
495 locations.fTextureMatrixUni = -1;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000496 locations.fNormalizedTexelSizeUni = -1;
junov@google.comf93e7172011-03-31 21:26:24 +0000497 }
498 }
499 GR_GL(UseProgram(progID));
500
501 // init sampler unis and set bogus values for state tracking
502 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
503 if (-1 != programData->fUniLocations.fStages[s].fSamplerUni) {
504 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
505 }
506 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
507 programData->fRadial2CenterX1[s] = GR_ScalarMax;
508 programData->fRadial2Radius0[s] = -GR_ScalarMax;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000509 programData->fTextureWidth[s] = -1;
510 programData->fTextureHeight[s] = -1;
junov@google.comf93e7172011-03-31 21:26:24 +0000511 }
512 programData->fViewMatrix = GrMatrix::InvalidMatrix();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000513 programData->fColor = GrColor_ILLEGAL;
junov@google.comf93e7172011-03-31 21:26:24 +0000514}
515
516GrGLuint GrGLProgram::CompileShader(GrGLenum type,
517 int stringCnt,
518 const char** strings,
519 int* stringLengths) {
520 GrGLuint shader = GR_GL(CreateShader(type));
521 if (0 == shader) {
522 return 0;
523 }
524
525 GrGLint compiled = GR_GL_INIT_ZERO;
526 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
527 GR_GL(CompileShader(shader));
528 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
529
530 if (!compiled) {
531 GrGLint infoLen = GR_GL_INIT_ZERO;
532 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
533 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
534 if (infoLen > 0) {
535 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
536 for (int i = 0; i < stringCnt; ++i) {
537 if (NULL == stringLengths || stringLengths[i] < 0) {
538 GrPrintf(strings[i]);
539 } else {
540 GrPrintf("%.*s", stringLengths[i], strings[i]);
541 }
542 }
543 GrPrintf("\n%s", log.get());
544 }
545 GrAssert(!"Shader compilation failed!");
546 GR_GL(DeleteShader(shader));
547 return 0;
548 }
549 return shader;
550}
551
552//============================================================================
553// Stage code generation
554//============================================================================
555
556void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000557 const GrGLProgram::ProgramDesc::StageDesc& desc,
558 const char* fsInColor, // NULL means no incoming color
559 const char* fsOutColor,
560 const char* vsInCoord,
561 ShaderCodeSegments* segments,
562 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000563
564 GrAssert(stageNum >= 0 && stageNum <= 9);
565
566 GrTokenString varyingName;
567 stage_varying_name(stageNum, &varyingName);
568
569 // First decide how many coords are needed to access the texture
570 // Right now it's always 2 but we could start using 1D textures for
571 // gradients.
572 static const int coordDims = 2;
573 int varyingDims;
574 /// Vertex Shader Stuff
575
576 // decide whether we need a matrix to transform texture coords
577 // and whether the varying needs a perspective coord.
578 GrTokenString texMName;
579 tex_matrix_name(stageNum, &texMName);
580 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
581 varyingDims = coordDims;
582 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000583 #if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000584 segments->fVSAttrs += "attribute mat3 ";
585 segments->fVSAttrs += texMName;
586 segments->fVSAttrs += ";\n";
587 #else
588 segments->fVSUnis += "uniform mat3 ";
589 segments->fVSUnis += texMName;
590 segments->fVSUnis += ";\n";
591 locations->fTextureMatrixUni = 1;
592 #endif
593 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
594 varyingDims = coordDims;
595 } else {
596 varyingDims = coordDims + 1;
597 }
598 }
599
600 GrTokenString samplerName;
601 sampler_name(stageNum, &samplerName);
602 segments->fFSUnis += "uniform sampler2D ";
603 segments->fFSUnis += samplerName;
604 segments->fFSUnis += ";\n";
605 locations->fSamplerUni = 1;
606
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000607 GrTokenString texelSizeName;
608 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
609 normalized_texel_size_name(stageNum, &texelSizeName);
610 segments->fFSUnis += "uniform vec2 ";
611 segments->fFSUnis += texelSizeName;
612 segments->fFSUnis += ";\n";
613 }
614
junov@google.comf93e7172011-03-31 21:26:24 +0000615 segments->fVaryings += "varying ";
616 segments->fVaryings += float_vector_type(varyingDims);
617 segments->fVaryings += " ";
618 segments->fVaryings += varyingName;
619 segments->fVaryings += ";\n";
620
621 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
622 GrAssert(varyingDims == coordDims);
623 segments->fVSCode += "\t";
624 segments->fVSCode += varyingName;
625 segments->fVSCode += " = ";
626 segments->fVSCode += vsInCoord;
627 segments->fVSCode += ";\n";
628 } else {
629 segments->fVSCode += "\t";
630 segments->fVSCode += varyingName;
631 segments->fVSCode += " = (";
632 segments->fVSCode += texMName;
633 segments->fVSCode += " * vec3(";
634 segments->fVSCode += vsInCoord;
635 segments->fVSCode += ", 1))";
636 segments->fVSCode += vector_all_coords(varyingDims);
637 segments->fVSCode += ";\n";
638 }
639
640 GrTokenString radial2ParamsName;
641 radial2_param_name(stageNum, &radial2ParamsName);
642 // for radial grads without perspective we can pass the linear
643 // part of the quadratic as a varying.
644 GrTokenString radial2VaryingName;
645 radial2_varying_name(stageNum, &radial2VaryingName);
646
647 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
648
649 segments->fVSUnis += "uniform ";
650 segments->fVSUnis += GrPrecision();
651 segments->fVSUnis += " float ";
652 segments->fVSUnis += radial2ParamsName;
653 segments->fVSUnis += "[6];\n";
654
655 segments->fFSUnis += "uniform ";
656 segments->fFSUnis += GrPrecision();
657 segments->fFSUnis += " float ";
658 segments->fFSUnis += radial2ParamsName;
659 segments->fFSUnis += "[6];\n";
660 locations->fRadial2Uni = 1;
661
662 // if there is perspective we don't interpolate this
663 if (varyingDims == coordDims) {
664 GrAssert(2 == coordDims);
665 segments->fVaryings += "varying float ";
666 segments->fVaryings += radial2VaryingName;
667 segments->fVaryings += ";\n";
668
669 segments->fVSCode += "\t";
670 segments->fVSCode += radial2VaryingName;
671 segments->fVSCode += " = 2.0 * (";
672 segments->fVSCode += radial2ParamsName;
673 segments->fVSCode += "[2] * ";
674 segments->fVSCode += varyingName;
675 segments->fVSCode += ".x ";
676 segments->fVSCode += " - ";
677 segments->fVSCode += radial2ParamsName;
678 segments->fVSCode += "[3]);\n";
679 }
680 }
681
682 /// Fragment Shader Stuff
683 GrTokenString fsCoordName;
684 // function used to access the shader, may be made projective
685 GrTokenString texFunc("texture2D");
686 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
687 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
688 GrAssert(varyingDims == coordDims);
689 fsCoordName = varyingName;
690 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000691 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +0000692 // our final tex coords then when in perspective we have to
693 // do an explicit divide
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000694 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
695 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
junov@google.comf93e7172011-03-31 21:26:24 +0000696 texFunc += "Proj";
697 fsCoordName = varyingName;
698 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000699 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000700 fsCoordName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +0000701
702 segments->fFSCode += "\t";
703 segments->fFSCode += float_vector_type(coordDims);
704 segments->fFSCode += " ";
705 segments->fFSCode += fsCoordName;
706 segments->fFSCode += " = ";
707 segments->fFSCode += varyingName;
708 segments->fFSCode += vector_nonhomog_coords(varyingDims);
709 segments->fFSCode += " / ";
710 segments->fFSCode += varyingName;
711 segments->fFSCode += vector_homog_coord(varyingDims);
712 segments->fFSCode += ";\n";
713 }
714 }
715
bsalomon@google.comfc296292011-05-06 13:53:47 +0000716 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000717 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +0000718 switch (desc.fCoordMapping) {
719 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
720 sampleCoords = fsCoordName;
721 break;
722 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
723 sampleCoords = "vec2(atan(-";
724 sampleCoords += fsCoordName;
725 sampleCoords += ".y, -";
726 sampleCoords += fsCoordName;
727 sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000728 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000729 break;
730 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
731 sampleCoords = "vec2(length(";
732 sampleCoords += fsCoordName;
733 sampleCoords += ".xy), 0.5)";
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000734 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000735 break;
736 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.comfc296292011-05-06 13:53:47 +0000737 GrTokenString cName("c");
738 GrTokenString ac4Name("ac4");
739 GrTokenString rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +0000740
bsalomon@google.comfc296292011-05-06 13:53:47 +0000741 cName.appendS32(stageNum);
742 ac4Name.appendS32(stageNum);
743 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +0000744
745 GrTokenString bVar;
746 if (coordDims == varyingDims) {
747 bVar = radial2VaryingName;
748 GrAssert(2 == varyingDims);
749 } else {
750 GrAssert(3 == varyingDims);
751 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000752 bVar.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +0000753 segments->fFSCode += "\tfloat ";
754 segments->fFSCode += bVar;
755 segments->fFSCode += " = 2.0 * (";
756 segments->fFSCode += radial2ParamsName;
757 segments->fFSCode += "[2] * ";
758 segments->fFSCode += fsCoordName;
759 segments->fFSCode += ".x ";
760 segments->fFSCode += " - ";
761 segments->fFSCode += radial2ParamsName;
762 segments->fFSCode += "[3]);\n";
763 }
764
765 segments->fFSCode += "\tfloat ";
766 segments->fFSCode += cName;
767 segments->fFSCode += " = dot(";
768 segments->fFSCode += fsCoordName;
769 segments->fFSCode += ", ";
770 segments->fFSCode += fsCoordName;
771 segments->fFSCode += ") + ";
772 segments->fFSCode += " - ";
773 segments->fFSCode += radial2ParamsName;
774 segments->fFSCode += "[4];\n";
775
776 segments->fFSCode += "\tfloat ";
777 segments->fFSCode += ac4Name;
778 segments->fFSCode += " = ";
779 segments->fFSCode += radial2ParamsName;
780 segments->fFSCode += "[0] * 4.0 * ";
781 segments->fFSCode += cName;
782 segments->fFSCode += ";\n";
783
784 segments->fFSCode += "\tfloat ";
785 segments->fFSCode += rootName;
786 segments->fFSCode += " = sqrt(abs(";
787 segments->fFSCode += bVar;
788 segments->fFSCode += " * ";
789 segments->fFSCode += bVar;
790 segments->fFSCode += " - ";
791 segments->fFSCode += ac4Name;
792 segments->fFSCode += "));\n";
793
794 sampleCoords = "vec2((-";
795 sampleCoords += bVar;
796 sampleCoords += " + ";
797 sampleCoords += radial2ParamsName;
798 sampleCoords += "[5] * ";
799 sampleCoords += rootName;
800 sampleCoords += ") * ";
801 sampleCoords += radial2ParamsName;
802 sampleCoords += "[1], 0.5)\n";
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000803 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000804 break;}
805 };
806
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000807 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
808 locations->fNormalizedTexelSizeUni = 1;
809 if (complexCoord) {
810 GrTokenString coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +0000811 coordVar.appendS32(stageNum);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000812 segments->fFSCode += "\t";
813 segments->fFSCode += float_vector_type(coordDims);
814 segments->fFSCode += " ";
815 segments->fFSCode += coordVar;
816 segments->fFSCode += " = ";
817 segments->fFSCode += sampleCoords;
818 segments->fFSCode += ";\n";
819 sampleCoords = coordVar;
820 }
821 static const char sign[] = {'-','+'};
822 GrTokenString stageAccumVar("stage2x2Accum");
bsalomon@google.comfc296292011-05-06 13:53:47 +0000823 stageAccumVar.appendS32(stageNum);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000824 segments->fFSCode += "\tvec4 ";
825 segments->fFSCode += stageAccumVar;
826 segments->fFSCode += " = ";
827 GrAssert(2 == coordDims);
828 for (int y = 0; y < 2; ++y) {
829 for (int x = 0; x < 2; ++x) {
830 segments->fFSCode += texFunc;
831 segments->fFSCode += "(";
832 segments->fFSCode += samplerName;
833 segments->fFSCode += ", ";
834 segments->fFSCode += sampleCoords;
835 segments->fFSCode += " + vec2(";
836 segments->fFSCode += sign[x];
837 segments->fFSCode += texelSizeName;
838 segments->fFSCode += ".x, ";
839 segments->fFSCode += sign[y];
840 segments->fFSCode += texelSizeName;
841 segments->fFSCode += ".y))";
842 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
843 segments->fFSCode += ".aaaa";
844 }
845 segments->fFSCode += ";\n";
846 if (1 != x || 1 !=y ) {
847 segments->fFSCode += "\t";
848 segments->fFSCode += stageAccumVar;
849 segments->fFSCode += " += ";
850 }
851 }
852 }
853 segments->fFSCode += "\t";
854 segments->fFSCode += fsOutColor;
855 segments->fFSCode += " = ";
856 if (NULL != fsInColor) {
857 segments->fFSCode += fsInColor;
858 segments->fFSCode += " * ";
859 }
860 segments->fFSCode += stageAccumVar;
861 segments->fFSCode += " / 4;\n";
862 } else {
863 segments->fFSCode += "\t";
864 segments->fFSCode += fsOutColor;
865 segments->fFSCode += " = ";
866 if (NULL != fsInColor) {
867 segments->fFSCode += fsInColor;
868 segments->fFSCode += " * ";
869 }
870
871 segments->fFSCode += texFunc;
872 segments->fFSCode += "(";
873 segments->fFSCode += samplerName;
874 segments->fFSCode += ", ";
875 segments->fFSCode += sampleCoords;
876 segments->fFSCode += ")";
877 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
878 segments->fFSCode += ".aaaa";
879 }
880 segments->fFSCode += ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000881 }
junov@google.comf93e7172011-03-31 21:26:24 +0000882
883 if(fStageEffects[stageNum]) {
884 fStageEffects[stageNum]->genShaderCode(segments);
885 }
886}
887