blob: abed0437355eba4f956320beb9e4fcbfd51497c8 [file] [log] [blame]
junov@google.comf93e7172011-03-31 21:26:24 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrGLProgram.h"
18
19#include "GrBinHashKey.h"
20#include "GrGLConfig.h"
21#include "GrGLEffect.h"
22#include "GrMemory.h"
junov@google.comf93e7172011-03-31 21:26:24 +000023
24namespace {
25
26const char* GrPrecision() {
27 if (GR_GL_SUPPORT_ES2) {
28 return "mediump";
29 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +000030 return " ";
junov@google.comf93e7172011-03-31 21:26:24 +000031 }
32}
33
34const char* GrShaderPrecision() {
35 if (GR_GL_SUPPORT_ES2) {
36 return "precision mediump float;\n";
37 } else {
38 return "";
39 }
40}
41
42} // namespace
43
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000044#define PRINT_SHADERS 0
45
bsalomon@google.com4be283f2011-04-19 21:15:09 +000046#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000047 #define VIEW_MATRIX_NAME "aViewM"
48#else
49 #define VIEW_MATRIX_NAME "uViewM"
50#endif
51
52#define POS_ATTR_NAME "aPosition"
53#define COL_ATTR_NAME "aColor"
bsalomon@google.com4be283f2011-04-19 21:15:09 +000054#define COL_UNI_NAME "uColor"
junov@google.comf93e7172011-03-31 21:26:24 +000055
junov@google.comf93e7172011-03-31 21:26:24 +000056static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
57 *s = "aTexCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +000058 s->appendS32(coordIdx);
junov@google.comf93e7172011-03-31 21:26:24 +000059}
60
61static inline const char* float_vector_type(int count) {
62 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
63 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
64 return FLOAT_VECS[count];
65}
66
67static inline const char* vector_homog_coord(int count) {
68 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
69 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
70 return HOMOGS[count];
71}
72
73static inline const char* vector_nonhomog_coords(int count) {
74 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
75 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
76 return NONHOMOGS[count];
77}
78
79static inline const char* vector_all_coords(int count) {
80 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
81 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
82 return ALL[count];
83}
84
85static void tex_matrix_name(int stage, GrStringBuilder* s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +000086#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000087 *s = "aTexM";
88#else
89 *s = "uTexM";
90#endif
bsalomon@google.comfc296292011-05-06 13:53:47 +000091 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +000092}
93
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000094static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
95 *s = "uTexelSize";
bsalomon@google.comfc296292011-05-06 13:53:47 +000096 s->appendS32(stage);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000097}
98
junov@google.comf93e7172011-03-31 21:26:24 +000099static void sampler_name(int stage, GrStringBuilder* s) {
100 *s = "uSampler";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000101 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000102}
103
104static void stage_varying_name(int stage, GrStringBuilder* s) {
105 *s = "vStage";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000106 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000107}
108
109static void radial2_param_name(int stage, GrStringBuilder* s) {
110 *s = "uRadial2Params";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000111 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000112}
113
114static void radial2_varying_name(int stage, GrStringBuilder* s) {
115 *s = "vB";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000116 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000117}
118
119GrGLProgram::GrGLProgram() {
120 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
121 fStageEffects[stage] = NULL;
122 }
123}
124
125GrGLProgram::~GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000126}
127
128void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
129 // Add stage configuration to the key
130 key.keyData(reinterpret_cast<const uint8_t*>(&fProgramDesc), sizeof(ProgramDesc));
131
132 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
133 // First pass: count effects and write the count to the key.
134 // This may seem like we are adding redundant data to the
135 // key, but in ensures the one key cannot be a prefix of
136 // another key, or identical to the key of a different program.
137 GrGLEffect* currentEffect = fStageEffects[stage];
138 uint8_t effectCount = 0;
139 while (currentEffect) {
140 GrAssert(effectCount < 255); // overflow detection
141 ++effectCount;
142 currentEffect = currentEffect->nextEffect();
143 }
144 key.keyData(reinterpret_cast<const uint8_t*>(&effectCount), sizeof(uint8_t));
145
146 // Second pass: continue building key using the effects
147 currentEffect = fStageEffects[stage];
148 while (currentEffect) {
149 fStageEffects[stage]->buildKey(key);
150 }
151 }
152}
153
154bool GrGLProgram::doGLSetup(GrPrimitiveType type,
155 GrGLProgram::CachedData* programData) const {
156 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
157 GrGLEffect* effect = fStageEffects[stage];
158 if (effect) {
159 if (!effect->doGLSetup(type, programData->fProgramID)) {
160 return false;
161 }
162 }
163 }
164
165 return true;
166}
167
168void GrGLProgram::doGLPost() const {
169 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
170 GrGLEffect* effect = fStageEffects[stage];
171 if (effect) {
172 effect->doGLPost();
173 }
174 }
175}
176
bsalomon@google.com91961302011-05-09 18:39:58 +0000177bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000178
179 ShaderCodeSegments segments;
180 const uint32_t& layout = fProgramDesc.fVertexLayout;
181
bsalomon@google.com91961302011-05-09 18:39:58 +0000182 programData->fUniLocations.reset();
junov@google.comf93e7172011-03-31 21:26:24 +0000183
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000184#if GR_GL_ATTRIBUTE_MATRICES
185 segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000186 programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000187#else
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000188 segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000189 programData->fUniLocations.fViewMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000190#endif
191 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000192
bsalomon@google.com91961302011-05-09 18:39:58 +0000193 segments.fVSCode.append(
194 "void main() {\n"
195 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
196 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000197
bsalomon@google.com91961302011-05-09 18:39:58 +0000198 // incoming color to current stage being processed.
199 GrStringBuilder inColor;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000200
201 switch (fProgramDesc.fColorType) {
202 case ProgramDesc::kAttribute_ColorType:
bsalomon@google.com91961302011-05-09 18:39:58 +0000203 segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
204 segments.fVaryings.append("varying vec4 vColor;\n");
205 segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000206 inColor = "vColor";
207 break;
208 case ProgramDesc::kUniform_ColorType:
bsalomon@google.com91961302011-05-09 18:39:58 +0000209 segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
210 programData->fUniLocations.fColorUni = kUseUniform;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000211 inColor = COL_UNI_NAME;
212 break;
213 case ProgramDesc::kNone_ColorType:
214 inColor = "";
215 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000216 }
217
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000218 if (fProgramDesc.fEmitsPointSize){
bsalomon@google.com91961302011-05-09 18:39:58 +0000219 segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000220 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000221
bsalomon@google.com91961302011-05-09 18:39:58 +0000222 segments.fFSCode.append("void main() {\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000223
224 // add texture coordinates that are used to the list of vertex attr decls
bsalomon@google.com91961302011-05-09 18:39:58 +0000225 GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
junov@google.comf93e7172011-03-31 21:26:24 +0000226 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000227 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000228 tex_attr_name(t, texCoordAttrs + t);
bsalomon@google.com91961302011-05-09 18:39:58 +0000229 segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000230 }
231 }
232
233 // for each enabled stage figure out what the input coordinates are
234 // and count the number of stages in use.
235 const char* stageInCoords[GrDrawTarget::kNumStages];
236 int numActiveStages = 0;
237
238 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
239 if (fProgramDesc.fStages[s].fEnabled) {
240 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
241 stageInCoords[s] = POS_ATTR_NAME;
242 } else {
243 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
244 // we better have input tex coordinates if stage is enabled.
245 GrAssert(tcIdx >= 0);
bsalomon@google.comfc296292011-05-06 13:53:47 +0000246 GrAssert(texCoordAttrs[tcIdx].size());
247 stageInCoords[s] = texCoordAttrs[tcIdx].c_str();
junov@google.comf93e7172011-03-31 21:26:24 +0000248 }
249 ++numActiveStages;
250 }
251 }
252
junov@google.comf93e7172011-03-31 21:26:24 +0000253 // if we have active stages string them together, feeding the output color
254 // of each to the next and generating code for each stage.
255 if (numActiveStages) {
256 int currActiveStage = 0;
257 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
258 if (fProgramDesc.fStages[s].fEnabled) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000259 GrStringBuilder outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000260 if (currActiveStage < (numActiveStages - 1)) {
261 outColor = "color";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000262 outColor.appendS32(currActiveStage);
bsalomon@google.com91961302011-05-09 18:39:58 +0000263 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000264 } else {
265 outColor = "gl_FragColor";
266 }
267
268 genStageCode(s,
269 fProgramDesc.fStages[s],
bsalomon@google.comfc296292011-05-06 13:53:47 +0000270 inColor.size() ? inColor.c_str() : NULL,
271 outColor.c_str(),
junov@google.comf93e7172011-03-31 21:26:24 +0000272 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 {
bsalomon@google.com91961302011-05-09 18:39:58 +0000280 // we may not have any incoming color
281 segments.fFSCode.appendf("\tgl_FragColor = %s;\n", (inColor.size() ? inColor.c_str() : "vec4(1,1,1,1);\n"));
junov@google.comf93e7172011-03-31 21:26:24 +0000282 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000283 segments.fVSCode.append("}\n");
284 segments.fFSCode.append("}\n");
285
286 if (!CompileFSAndVS(segments, programData)) {
287 return false;
288 }
289
290 if (!this->bindAttribsAndLinkProgram(texCoordAttrs, programData)) {
291 return false;
292 }
293
294 this->getUniformLocationsAndInitCache(programData);
295
296 return true;
297}
298
299bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
300 CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000301
junov@google.comf93e7172011-03-31 21:26:24 +0000302 const char* strings[4];
303 int lengths[4];
304 int stringCnt = 0;
305
bsalomon@google.comfc296292011-05-06 13:53:47 +0000306 if (segments.fVSUnis.size()) {
307 strings[stringCnt] = segments.fVSUnis.c_str();
308 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000309 ++stringCnt;
310 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000311 if (segments.fVSAttrs.size()) {
312 strings[stringCnt] = segments.fVSAttrs.c_str();
313 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000314 ++stringCnt;
315 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000316 if (segments.fVaryings.size()) {
317 strings[stringCnt] = segments.fVaryings.c_str();
318 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000319 ++stringCnt;
320 }
321
bsalomon@google.comfc296292011-05-06 13:53:47 +0000322 GrAssert(segments.fVSCode.size());
323 strings[stringCnt] = segments.fVSCode.c_str();
324 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000325 ++stringCnt;
326
327#if PRINT_SHADERS
bsalomon@google.comfc296292011-05-06 13:53:47 +0000328 GrPrintf(segments.fVSUnis.c_str());
329 GrPrintf(segments.fVSAttrs.c_str());
330 GrPrintf(segments.fVaryings.c_str());
331 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000332 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000333#endif
334 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
335 stringCnt,
336 strings,
337 lengths);
338
bsalomon@google.com91961302011-05-09 18:39:58 +0000339 if (!programData->fVShaderID) {
340 return false;
341 }
342
junov@google.comf93e7172011-03-31 21:26:24 +0000343 stringCnt = 0;
344
345 if (strlen(GrShaderPrecision()) > 1) {
346 strings[stringCnt] = GrShaderPrecision();
347 lengths[stringCnt] = strlen(GrShaderPrecision());
348 ++stringCnt;
349 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000350 if (segments.fFSUnis.size()) {
351 strings[stringCnt] = segments.fFSUnis.c_str();
352 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000353 ++stringCnt;
354 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000355 if (segments.fVaryings.size()) {
356 strings[stringCnt] = segments.fVaryings.c_str();
357 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000358 ++stringCnt;
359 }
360
bsalomon@google.comfc296292011-05-06 13:53:47 +0000361 GrAssert(segments.fFSCode.size());
362 strings[stringCnt] = segments.fFSCode.c_str();
363 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000364 ++stringCnt;
365
366#if PRINT_SHADERS
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000367 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000368 GrPrintf(segments.fFSUnis.c_str());
369 GrPrintf(segments.fVaryings.c_str());
370 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000371 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000372#endif
373 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
374 stringCnt,
375 strings,
376 lengths);
377
bsalomon@google.com91961302011-05-09 18:39:58 +0000378 if (!programData->fFShaderID) {
379 return false;
junov@google.comf93e7172011-03-31 21:26:24 +0000380 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000381 return true;
junov@google.comf93e7172011-03-31 21:26:24 +0000382}
383
384GrGLuint GrGLProgram::CompileShader(GrGLenum type,
385 int stringCnt,
386 const char** strings,
387 int* stringLengths) {
388 GrGLuint shader = GR_GL(CreateShader(type));
389 if (0 == shader) {
390 return 0;
391 }
392
393 GrGLint compiled = GR_GL_INIT_ZERO;
394 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
395 GR_GL(CompileShader(shader));
396 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
397
398 if (!compiled) {
399 GrGLint infoLen = GR_GL_INIT_ZERO;
400 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
401 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
402 if (infoLen > 0) {
403 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
404 for (int i = 0; i < stringCnt; ++i) {
405 if (NULL == stringLengths || stringLengths[i] < 0) {
406 GrPrintf(strings[i]);
407 } else {
408 GrPrintf("%.*s", stringLengths[i], strings[i]);
409 }
410 }
411 GrPrintf("\n%s", log.get());
412 }
413 GrAssert(!"Shader compilation failed!");
414 GR_GL(DeleteShader(shader));
415 return 0;
416 }
417 return shader;
418}
419
bsalomon@google.com91961302011-05-09 18:39:58 +0000420bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
421 CachedData* programData) const {
422 programData->fProgramID = GR_GL(CreateProgram());
423 if (!programData->fProgramID) {
424 return false;
425 }
426 const GrGLint& progID = programData->fProgramID;
427
428 GR_GL(AttachShader(progID, programData->fVShaderID));
429 GR_GL(AttachShader(progID, programData->fFShaderID));
430
431 // Bind the attrib locations to same values for all shaders
432 GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
433 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
434 if (texCoordAttrNames[t].size()) {
435 GR_GL(BindAttribLocation(progID,
436 TexCoordAttributeIdx(t),
437 texCoordAttrNames[t].c_str()));
438 }
439 }
440
441
442 if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
443 GR_GL(BindAttribLocation(progID,
444 ViewMatrixAttributeIdx(),
445 VIEW_MATRIX_NAME));
446 }
447
448 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
bsalomon@google.com72b4fcb2011-05-09 20:47:34 +0000449 const StageUniLocations& unis = programData->fUniLocations.fStages[s];
450 if (kSetAsAttribute == unis.fTextureMatrixUni) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000451 GrStringBuilder matName;
452 tex_matrix_name(s, &matName);
453 GR_GL(BindAttribLocation(progID,
454 TextureMatrixAttributeIdx(s),
455 matName.c_str()));
456 }
457 }
458
459
460 GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
461
462 GR_GL(LinkProgram(progID));
463
464 GrGLint linked = GR_GL_INIT_ZERO;
465 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
466 if (!linked) {
467 GrGLint infoLen = GR_GL_INIT_ZERO;
468 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
469 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
470 if (infoLen > 0) {
471 GR_GL(GetProgramInfoLog(progID,
472 infoLen+1,
473 NULL,
474 (char*)log.get()));
475 GrPrintf((char*)log.get());
476 }
477 GrAssert(!"Error linking program");
478 GR_GL(DeleteProgram(progID));
479 programData->fProgramID = 0;
480 return false;
481 }
482 return true;
483}
484
485void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
486 const GrGLint& progID = programData->fProgramID;
487
488 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
489 programData->fUniLocations.fViewMatrixUni =
490 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
491 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
492 }
493 if (kUseUniform == programData->fUniLocations.fColorUni) {
494 programData->fUniLocations.fColorUni =
495 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
496 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
497 }
498
499 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
500 StageUniLocations& locations = programData->fUniLocations.fStages[s];
501 if (fProgramDesc.fStages[s].fEnabled) {
502 if (kUseUniform == locations.fTextureMatrixUni) {
503 GrStringBuilder texMName;
504 tex_matrix_name(s, &texMName);
505 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
506 progID,
507 texMName.c_str()));
508 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
509 }
510
511 if (kUseUniform == locations.fSamplerUni) {
512 GrStringBuilder samplerName;
513 sampler_name(s, &samplerName);
514 locations.fSamplerUni = GR_GL(GetUniformLocation(
515 progID,
516 samplerName.c_str()));
517 GrAssert(kUnusedUniform != locations.fSamplerUni);
518 }
519
520 if (kUseUniform == locations.fNormalizedTexelSizeUni) {
521 GrStringBuilder texelSizeName;
522 normalized_texel_size_name(s, &texelSizeName);
523 locations.fNormalizedTexelSizeUni =
524 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
525 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
526 }
527
528 if (kUseUniform == locations.fRadial2Uni) {
529 GrStringBuilder radial2ParamName;
530 radial2_param_name(s, &radial2ParamName);
531 locations.fRadial2Uni = GR_GL(GetUniformLocation(
532 progID,
533 radial2ParamName.c_str()));
534 GrAssert(kUnusedUniform != locations.fRadial2Uni);
535 }
536 }
537 }
538 GR_GL(UseProgram(progID));
539
540 // init sampler unis and set bogus values for state tracking
541 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
542 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
543 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
544 }
545 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
546 programData->fRadial2CenterX1[s] = GR_ScalarMax;
547 programData->fRadial2Radius0[s] = -GR_ScalarMax;
548 programData->fTextureWidth[s] = -1;
549 programData->fTextureHeight[s] = -1;
550 }
551 programData->fViewMatrix = GrMatrix::InvalidMatrix();
552 programData->fColor = GrColor_ILLEGAL;
553}
554
junov@google.comf93e7172011-03-31 21:26:24 +0000555//============================================================================
556// Stage code generation
557//============================================================================
558
559void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000560 const GrGLProgram::ProgramDesc::StageDesc& desc,
561 const char* fsInColor, // NULL means no incoming color
562 const char* fsOutColor,
563 const char* vsInCoord,
564 ShaderCodeSegments* segments,
565 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000566
567 GrAssert(stageNum >= 0 && stageNum <= 9);
568
bsalomon@google.com91961302011-05-09 18:39:58 +0000569 GrStringBuilder varyingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000570 stage_varying_name(stageNum, &varyingName);
571
572 // First decide how many coords are needed to access the texture
573 // Right now it's always 2 but we could start using 1D textures for
574 // gradients.
575 static const int coordDims = 2;
576 int varyingDims;
577 /// Vertex Shader Stuff
578
579 // decide whether we need a matrix to transform texture coords
580 // and whether the varying needs a perspective coord.
bsalomon@google.com91961302011-05-09 18:39:58 +0000581 GrStringBuilder texMName;
junov@google.comf93e7172011-03-31 21:26:24 +0000582 tex_matrix_name(stageNum, &texMName);
583 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
584 varyingDims = coordDims;
585 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000586 #if GR_GL_ATTRIBUTE_MATRICES
bsalomon@google.com91961302011-05-09 18:39:58 +0000587 segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
588 locations->fTextureMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000589 #else
bsalomon@google.com91961302011-05-09 18:39:58 +0000590 segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
591 locations->fTextureMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000592 #endif
593 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
594 varyingDims = coordDims;
595 } else {
596 varyingDims = coordDims + 1;
597 }
598 }
599
bsalomon@google.com91961302011-05-09 18:39:58 +0000600 GrStringBuilder samplerName;
junov@google.comf93e7172011-03-31 21:26:24 +0000601 sampler_name(stageNum, &samplerName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000602 segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
603 locations->fSamplerUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000604
bsalomon@google.com91961302011-05-09 18:39:58 +0000605 GrStringBuilder texelSizeName;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000606 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
607 normalized_texel_size_name(stageNum, &texelSizeName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000608 segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000609 }
610
bsalomon@google.com91961302011-05-09 18:39:58 +0000611 segments->fVaryings.appendf("varying %s %s;\n",
612 float_vector_type(varyingDims), varyingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000613
614 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
615 GrAssert(varyingDims == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000616 segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
junov@google.comf93e7172011-03-31 21:26:24 +0000617 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000618 // varying = texMatrix * texCoord
619 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
620 varyingName.c_str(), texMName.c_str(),
621 vsInCoord, vector_all_coords(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000622 }
623
bsalomon@google.com91961302011-05-09 18:39:58 +0000624 GrStringBuilder radial2ParamsName;
junov@google.comf93e7172011-03-31 21:26:24 +0000625 radial2_param_name(stageNum, &radial2ParamsName);
626 // for radial grads without perspective we can pass the linear
627 // part of the quadratic as a varying.
bsalomon@google.com91961302011-05-09 18:39:58 +0000628 GrStringBuilder radial2VaryingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000629 radial2_varying_name(stageNum, &radial2VaryingName);
630
631 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
632
bsalomon@google.com91961302011-05-09 18:39:58 +0000633 segments->fVSUnis.appendf("uniform %sfloat %s[6];\n",
634 GrPrecision(), radial2ParamsName.c_str());
635 segments->fFSUnis.appendf("uniform float %s[6];\n",
636 radial2ParamsName.c_str());
637 locations->fRadial2Uni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000638
639 // if there is perspective we don't interpolate this
640 if (varyingDims == coordDims) {
641 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000642 segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000643
bsalomon@google.com91961302011-05-09 18:39:58 +0000644 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
645 segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
646 radial2VaryingName.c_str(), radial2ParamsName.c_str(),
647 varyingName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000648 }
649 }
650
651 /// Fragment Shader Stuff
bsalomon@google.com91961302011-05-09 18:39:58 +0000652 GrStringBuilder fsCoordName;
junov@google.comf93e7172011-03-31 21:26:24 +0000653 // function used to access the shader, may be made projective
bsalomon@google.com91961302011-05-09 18:39:58 +0000654 GrStringBuilder texFunc("texture2D");
junov@google.comf93e7172011-03-31 21:26:24 +0000655 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
656 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
657 GrAssert(varyingDims == coordDims);
658 fsCoordName = varyingName;
659 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000660 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +0000661 // our final tex coords then when in perspective we have to
bsalomon@google.com91961302011-05-09 18:39:58 +0000662 // do an explicit divide. Otherwise, we can use a Proj func.
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000663 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
664 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000665 texFunc.append("Proj");
junov@google.comf93e7172011-03-31 21:26:24 +0000666 fsCoordName = varyingName;
667 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000668 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000669 fsCoordName.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000670 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
671 float_vector_type(coordDims),
672 fsCoordName.c_str(),
673 varyingName.c_str(),
674 vector_nonhomog_coords(varyingDims),
675 varyingName.c_str(),
676 vector_homog_coord(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000677 }
678 }
679
bsalomon@google.comfc296292011-05-06 13:53:47 +0000680 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000681 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +0000682 switch (desc.fCoordMapping) {
683 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
684 sampleCoords = fsCoordName;
685 break;
686 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000687 sampleCoords.printf("vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)", fsCoordName.c_str(), fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000688 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000689 break;
690 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000691 sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000692 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000693 break;
694 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.com91961302011-05-09 18:39:58 +0000695 GrStringBuilder cName("c");
696 GrStringBuilder ac4Name("ac4");
697 GrStringBuilder rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +0000698
bsalomon@google.comfc296292011-05-06 13:53:47 +0000699 cName.appendS32(stageNum);
700 ac4Name.appendS32(stageNum);
701 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +0000702
bsalomon@google.com91961302011-05-09 18:39:58 +0000703 // if we were able to interpolate the linear component bVar is the varying
704 // otherwise compute it
705 GrStringBuilder bVar;
junov@google.comf93e7172011-03-31 21:26:24 +0000706 if (coordDims == varyingDims) {
707 bVar = radial2VaryingName;
708 GrAssert(2 == varyingDims);
709 } else {
710 GrAssert(3 == varyingDims);
711 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000712 bVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000713 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
714 bVar.c_str(), radial2ParamsName.c_str(),
715 fsCoordName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000716 }
717
bsalomon@google.com91961302011-05-09 18:39:58 +0000718 // c = (x^2)+(y^2) - params[4]
719 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
720 cName.c_str(), fsCoordName.c_str(),
721 fsCoordName.c_str(),
722 radial2ParamsName.c_str());
723 // ac4 = 4.0 * params[0] * c
724 segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
725 ac4Name.c_str(), radial2ParamsName.c_str(),
726 cName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000727
bsalomon@google.com91961302011-05-09 18:39:58 +0000728 // root = sqrt(b^2-4ac)
729 // (abs to avoid exception due to fp precision)
730 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
731 rootName.c_str(), bVar.c_str(), bVar.c_str(),
732 ac4Name.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000733
bsalomon@google.com91961302011-05-09 18:39:58 +0000734 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
735 // y coord is 0.5 (texture is effectively 1D)
736 sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
737 bVar.c_str(), radial2ParamsName.c_str(),
738 rootName.c_str(), radial2ParamsName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000739 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000740 break;}
741 };
742
bsalomon@google.com91961302011-05-09 18:39:58 +0000743 const char* smear;
744 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
745 smear = ".aaaa";
746 } else {
747 smear = "";
748 }
749 GrStringBuilder modulate;
750 if (NULL != fsInColor) {
751 modulate.printf(" * %s", fsInColor);
752 }
753
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000754 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000755 locations->fNormalizedTexelSizeUni = kUseUniform;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000756 if (complexCoord) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000757 // assign the coord to a var rather than compute 4x.
758 GrStringBuilder coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +0000759 coordVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000760 segments->fFSCode.appendf("\t%s %s = %s;\n",
761 float_vector_type(coordDims),
762 coordVar.c_str(), sampleCoords.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000763 sampleCoords = coordVar;
764 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000765 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000766 GrStringBuilder accumVar("accum");
767 accumVar.appendS32(stageNum);
768 segments->fFSCode.appendf("\tvec4 %s = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
769 segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
770 segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
771 segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
772 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000773 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000774 segments->fFSCode.appendf("\t%s = %s(%s, %s)%s %s;\n", fsOutColor, texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), smear, modulate.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000775 }
junov@google.comf93e7172011-03-31 21:26:24 +0000776
777 if(fStageEffects[stageNum]) {
778 fStageEffects[stageNum]->genShaderCode(segments);
779 }
780}
781