blob: ab327d0e7d565cfea5864199a0c2ed86efc2aaab [file] [log] [blame]
junov@google.comf93e7172011-03-31 21:26:24 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrGLProgram.h"
18
19#include "GrBinHashKey.h"
20#include "GrGLConfig.h"
21#include "GrGLEffect.h"
22#include "GrMemory.h"
junov@google.comf93e7172011-03-31 21:26:24 +000023
Scroggo97c88c22011-05-11 14:05:25 +000024#include "SkXfermode.h"
25
junov@google.comf93e7172011-03-31 21:26:24 +000026namespace {
27
28const char* GrPrecision() {
29 if (GR_GL_SUPPORT_ES2) {
30 return "mediump";
31 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +000032 return " ";
junov@google.comf93e7172011-03-31 21:26:24 +000033 }
34}
35
36const char* GrShaderPrecision() {
37 if (GR_GL_SUPPORT_ES2) {
38 return "precision mediump float;\n";
39 } else {
40 return "";
41 }
42}
43
44} // namespace
45
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000046#define PRINT_SHADERS 0
47
bsalomon@google.com4be283f2011-04-19 21:15:09 +000048#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +000049 #define VIEW_MATRIX_NAME "aViewM"
50#else
51 #define VIEW_MATRIX_NAME "uViewM"
52#endif
53
54#define POS_ATTR_NAME "aPosition"
55#define COL_ATTR_NAME "aColor"
bsalomon@google.com4be283f2011-04-19 21:15:09 +000056#define COL_UNI_NAME "uColor"
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +000057#define EDGES_UNI_NAME "uEdges"
Scroggo97c88c22011-05-11 14:05:25 +000058#define COL_FILTER_UNI_NAME "uColorFilter"
junov@google.comf93e7172011-03-31 21:26:24 +000059
junov@google.comf93e7172011-03-31 21:26:24 +000060static 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
junov@google.com6acc9b32011-05-16 18:32:07 +0000123static void tex_domain_name(int stage, GrStringBuilder* s) {
124 *s = "uTexDom";
125 s->appendS32(stage);
126}
127
junov@google.comf93e7172011-03-31 21:26:24 +0000128GrGLProgram::GrGLProgram() {
129 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
130 fStageEffects[stage] = NULL;
131 }
132}
133
134GrGLProgram::~GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000135}
136
137void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
138 // Add stage configuration to the key
139 key.keyData(reinterpret_cast<const uint8_t*>(&fProgramDesc), sizeof(ProgramDesc));
140
141 for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
142 // First pass: count effects and write the count to the key.
143 // This may seem like we are adding redundant data to the
144 // key, but in ensures the one key cannot be a prefix of
145 // another key, or identical to the key of a different program.
146 GrGLEffect* currentEffect = fStageEffects[stage];
147 uint8_t effectCount = 0;
148 while (currentEffect) {
149 GrAssert(effectCount < 255); // overflow detection
150 ++effectCount;
151 currentEffect = currentEffect->nextEffect();
152 }
153 key.keyData(reinterpret_cast<const uint8_t*>(&effectCount), sizeof(uint8_t));
154
155 // Second pass: continue building key using the effects
156 currentEffect = fStageEffects[stage];
157 while (currentEffect) {
158 fStageEffects[stage]->buildKey(key);
159 }
160 }
161}
162
163bool GrGLProgram::doGLSetup(GrPrimitiveType type,
164 GrGLProgram::CachedData* programData) const {
165 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
166 GrGLEffect* effect = fStageEffects[stage];
167 if (effect) {
168 if (!effect->doGLSetup(type, programData->fProgramID)) {
169 return false;
170 }
171 }
172 }
173
174 return true;
175}
176
177void GrGLProgram::doGLPost() const {
178 for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
179 GrGLEffect* effect = fStageEffects[stage];
180 if (effect) {
181 effect->doGLPost();
182 }
183 }
184}
185
Scroggo97c88c22011-05-11 14:05:25 +0000186/**
187 * Create a text coefficient to be used in fragment shader code.
188 */
Scroggo5d757402011-05-12 18:27:05 +0000189static void coefficientString(GrStringBuilder* str, SkXfermode::Coeff coeff,
Scroggo97c88c22011-05-11 14:05:25 +0000190 const char* src, const char* dst) {
191 switch (coeff) {
192 case SkXfermode::kZero_Coeff: /** 0 */
Scroggo5d757402011-05-12 18:27:05 +0000193 *str = "0.0";
Scroggo97c88c22011-05-11 14:05:25 +0000194 break;
195 case SkXfermode::kOne_Coeff: /** 1 */
Scroggo5d757402011-05-12 18:27:05 +0000196 *str = "1.0";
Scroggo97c88c22011-05-11 14:05:25 +0000197 break;
198 case SkXfermode::kSA_Coeff: /** src alpha */
Scroggo5d757402011-05-12 18:27:05 +0000199 str->appendf("%s.a", src);
Scroggo97c88c22011-05-11 14:05:25 +0000200 break;
201 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
Scroggo5d757402011-05-12 18:27:05 +0000202 str->appendf("(1.0 - %s.a)", src);
Scroggo97c88c22011-05-11 14:05:25 +0000203 break;
204 case SkXfermode::kDA_Coeff: /** dst alpha */
Scroggo5d757402011-05-12 18:27:05 +0000205 str->appendf("%s.a", dst);
Scroggo97c88c22011-05-11 14:05:25 +0000206 break;
207 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
Scroggo5d757402011-05-12 18:27:05 +0000208 str->appendf("(1.0 - %s.a)", dst);
Scroggo97c88c22011-05-11 14:05:25 +0000209 break;
210 case SkXfermode::kSC_Coeff:
Scroggo5d757402011-05-12 18:27:05 +0000211 str->append(src);
Scroggo97c88c22011-05-11 14:05:25 +0000212 break;
213 default:
214 break;
215 }
216}
217
218/**
219 * Adds a line to the fragment shader code which modifies the color by
220 * the specified color filter.
221 */
Scroggo5d757402011-05-12 18:27:05 +0000222static void addColorFilter(GrStringBuilder* FSCode, const char * outputVar,
Scroggo97c88c22011-05-11 14:05:25 +0000223 SkXfermode::Mode colorFilterXfermode, const char* dstColor) {
224 SkXfermode::Coeff srcCoeff, dstCoeff;
Scroggoa8a57be2011-05-11 18:16:56 +0000225 SkDEBUGCODE(bool success =)
226 SkXfermode::ModeAsCoeff(colorFilterXfermode, &srcCoeff, &dstCoeff);
Scroggo97c88c22011-05-11 14:05:25 +0000227 // We currently do not handle modes that cannot be represented as
228 // coefficients.
229 GrAssert(success);
230 GrStringBuilder srcCoeffStr, dstCoeffStr;
Scroggo5d757402011-05-12 18:27:05 +0000231 coefficientString(&srcCoeffStr, srcCoeff, COL_FILTER_UNI_NAME, dstColor);
232 coefficientString(&dstCoeffStr, dstCoeff, COL_FILTER_UNI_NAME, dstColor);
233 FSCode->appendf("\t%s = %s*%s + %s*%s;\n", outputVar, srcCoeffStr.c_str(),
Scroggo97c88c22011-05-11 14:05:25 +0000234 COL_FILTER_UNI_NAME, dstCoeffStr.c_str(), dstColor);
235}
236
bsalomon@google.com91961302011-05-09 18:39:58 +0000237bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000238
239 ShaderCodeSegments segments;
240 const uint32_t& layout = fProgramDesc.fVertexLayout;
241
bsalomon@google.com91961302011-05-09 18:39:58 +0000242 programData->fUniLocations.reset();
junov@google.comf93e7172011-03-31 21:26:24 +0000243
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000244#if GR_GL_ATTRIBUTE_MATRICES
245 segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000246 programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000247#else
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000248 segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000249 programData->fUniLocations.fViewMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000250#endif
251 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000252
bsalomon@google.com91961302011-05-09 18:39:58 +0000253 segments.fVSCode.append(
254 "void main() {\n"
255 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
256 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000257
bsalomon@google.com91961302011-05-09 18:39:58 +0000258 // incoming color to current stage being processed.
259 GrStringBuilder inColor;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000260
261 switch (fProgramDesc.fColorType) {
262 case ProgramDesc::kAttribute_ColorType:
bsalomon@google.com91961302011-05-09 18:39:58 +0000263 segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
264 segments.fVaryings.append("varying vec4 vColor;\n");
265 segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000266 inColor = "vColor";
267 break;
268 case ProgramDesc::kUniform_ColorType:
bsalomon@google.com91961302011-05-09 18:39:58 +0000269 segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
270 programData->fUniLocations.fColorUni = kUseUniform;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000271 inColor = COL_UNI_NAME;
272 break;
273 case ProgramDesc::kNone_ColorType:
274 inColor = "";
275 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000276 }
277
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000278 if (fProgramDesc.fUsesEdgeAA) {
279 segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[6];\n");
280 }
281
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000282 if (fProgramDesc.fEmitsPointSize){
bsalomon@google.com91961302011-05-09 18:39:58 +0000283 segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000284 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000285
bsalomon@google.com91961302011-05-09 18:39:58 +0000286 segments.fFSCode.append("void main() {\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000287
288 // add texture coordinates that are used to the list of vertex attr decls
bsalomon@google.com91961302011-05-09 18:39:58 +0000289 GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
junov@google.comf93e7172011-03-31 21:26:24 +0000290 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000291 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000292 tex_attr_name(t, texCoordAttrs + t);
bsalomon@google.com91961302011-05-09 18:39:58 +0000293 segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000294 }
295 }
296
Scroggo97c88c22011-05-11 14:05:25 +0000297 bool useColorFilter =
298 // The rest of transfer mode color filters have not been implemented
299 fProgramDesc.fColorFilterXfermode <= SkXfermode::kMultiply_Mode
300 // This mode has no effect.
301 && fProgramDesc.fColorFilterXfermode != SkXfermode::kDst_Mode;
302 bool onlyUseColorFilter = useColorFilter
303 && (fProgramDesc.fColorFilterXfermode == SkXfermode::kClear_Mode
304 || fProgramDesc.fColorFilterXfermode == SkXfermode::kSrc_Mode);
305 if (useColorFilter) {
306 // Set up a uniform for the color
307 segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
308 programData->fUniLocations.fColorFilterUni = kUseUniform;
309 }
310
junov@google.comf93e7172011-03-31 21:26:24 +0000311 // for each enabled stage figure out what the input coordinates are
312 // and count the number of stages in use.
313 const char* stageInCoords[GrDrawTarget::kNumStages];
314 int numActiveStages = 0;
315
Scroggo97c88c22011-05-11 14:05:25 +0000316 if (!onlyUseColorFilter) {
317 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
318 if (fProgramDesc.fStages[s].fEnabled) {
319 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
320 stageInCoords[s] = POS_ATTR_NAME;
321 } else {
322 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
323 // we better have input tex coordinates if stage is enabled.
324 GrAssert(tcIdx >= 0);
325 GrAssert(texCoordAttrs[tcIdx].size());
326 stageInCoords[s] = texCoordAttrs[tcIdx].c_str();
327 }
328 ++numActiveStages;
junov@google.comf93e7172011-03-31 21:26:24 +0000329 }
junov@google.comf93e7172011-03-31 21:26:24 +0000330 }
331 }
332
junov@google.comf93e7172011-03-31 21:26:24 +0000333 // if we have active stages string them together, feeding the output color
334 // of each to the next and generating code for each stage.
335 if (numActiveStages) {
336 int currActiveStage = 0;
Scroggo97c88c22011-05-11 14:05:25 +0000337 GrStringBuilder outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000338 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
339 if (fProgramDesc.fStages[s].fEnabled) {
Scroggo97c88c22011-05-11 14:05:25 +0000340 if (currActiveStage < (numActiveStages - 1) || useColorFilter) {
junov@google.comf93e7172011-03-31 21:26:24 +0000341 outColor = "color";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000342 outColor.appendS32(currActiveStage);
bsalomon@google.com91961302011-05-09 18:39:58 +0000343 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000344 } else {
345 outColor = "gl_FragColor";
346 }
347
348 genStageCode(s,
349 fProgramDesc.fStages[s],
bsalomon@google.comfc296292011-05-06 13:53:47 +0000350 inColor.size() ? inColor.c_str() : NULL,
351 outColor.c_str(),
junov@google.comf93e7172011-03-31 21:26:24 +0000352 stageInCoords[s],
353 &segments,
354 &programData->fUniLocations.fStages[s]);
355 ++currActiveStage;
356 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000357 }
358 }
Scroggo97c88c22011-05-11 14:05:25 +0000359 if (useColorFilter) {
Scroggo5d757402011-05-12 18:27:05 +0000360 addColorFilter(&segments.fFSCode, "gl_FragColor",
Scroggo97c88c22011-05-11 14:05:25 +0000361 fProgramDesc.fColorFilterXfermode, outColor.c_str());
362 }
363
junov@google.comf93e7172011-03-31 21:26:24 +0000364 } else {
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000365 if (fProgramDesc.fUsesEdgeAA) {
366 // FIXME: put the a's in a loop
367 segments.fFSCode.append(
368 "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n"
369 "\tfloat a0 = clamp(dot(uEdges[0], pos), 0.0, 1.0);\n"
370 "\tfloat a1 = clamp(dot(uEdges[1], pos), 0.0, 1.0);\n"
371 "\tfloat a2 = clamp(dot(uEdges[2], pos), 0.0, 1.0);\n"
372 "\tfloat a3 = clamp(dot(uEdges[3], pos), 0.0, 1.0);\n"
373 "\tfloat a4 = clamp(dot(uEdges[4], pos), 0.0, 1.0);\n"
374 "\tfloat a5 = clamp(dot(uEdges[5], pos), 0.0, 1.0);\n"
375 "\tfloat edgeAlpha = min(min(a0 * a1, a2 * a3), a4 * a5);\n");
376 if (inColor.size()) {
377 inColor.append(" * edgeAlpha");
378 } else {
379 inColor = "vec4(edgeAlpha)";
380 }
381 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000382 // we may not have any incoming color
Scroggo97c88c22011-05-11 14:05:25 +0000383 const char * incomingColor = (inColor.size() ? inColor.c_str()
384 : "vec4(1,1,1,1)");
385 if (useColorFilter) {
Scroggo5d757402011-05-12 18:27:05 +0000386 addColorFilter(&segments.fFSCode, "gl_FragColor",
Scroggo97c88c22011-05-11 14:05:25 +0000387 fProgramDesc.fColorFilterXfermode, incomingColor);
388 } else {
389 segments.fFSCode.appendf("\tgl_FragColor = %s;\n", incomingColor);
390 }
junov@google.comf93e7172011-03-31 21:26:24 +0000391 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000392 segments.fVSCode.append("}\n");
393 segments.fFSCode.append("}\n");
394
395 if (!CompileFSAndVS(segments, programData)) {
396 return false;
397 }
398
399 if (!this->bindAttribsAndLinkProgram(texCoordAttrs, programData)) {
400 return false;
401 }
402
403 this->getUniformLocationsAndInitCache(programData);
404
405 return true;
406}
407
408bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
409 CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000410
junov@google.comf93e7172011-03-31 21:26:24 +0000411 const char* strings[4];
412 int lengths[4];
413 int stringCnt = 0;
414
bsalomon@google.comfc296292011-05-06 13:53:47 +0000415 if (segments.fVSUnis.size()) {
416 strings[stringCnt] = segments.fVSUnis.c_str();
417 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000418 ++stringCnt;
419 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000420 if (segments.fVSAttrs.size()) {
421 strings[stringCnt] = segments.fVSAttrs.c_str();
422 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000423 ++stringCnt;
424 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000425 if (segments.fVaryings.size()) {
426 strings[stringCnt] = segments.fVaryings.c_str();
427 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000428 ++stringCnt;
429 }
430
bsalomon@google.comfc296292011-05-06 13:53:47 +0000431 GrAssert(segments.fVSCode.size());
432 strings[stringCnt] = segments.fVSCode.c_str();
433 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000434 ++stringCnt;
435
436#if PRINT_SHADERS
bsalomon@google.comfc296292011-05-06 13:53:47 +0000437 GrPrintf(segments.fVSUnis.c_str());
438 GrPrintf(segments.fVSAttrs.c_str());
439 GrPrintf(segments.fVaryings.c_str());
440 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000441 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000442#endif
443 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
444 stringCnt,
445 strings,
446 lengths);
447
bsalomon@google.com91961302011-05-09 18:39:58 +0000448 if (!programData->fVShaderID) {
449 return false;
450 }
451
junov@google.comf93e7172011-03-31 21:26:24 +0000452 stringCnt = 0;
453
454 if (strlen(GrShaderPrecision()) > 1) {
455 strings[stringCnt] = GrShaderPrecision();
456 lengths[stringCnt] = strlen(GrShaderPrecision());
457 ++stringCnt;
458 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000459 if (segments.fFSUnis.size()) {
460 strings[stringCnt] = segments.fFSUnis.c_str();
461 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000462 ++stringCnt;
463 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000464 if (segments.fVaryings.size()) {
465 strings[stringCnt] = segments.fVaryings.c_str();
466 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000467 ++stringCnt;
468 }
469
bsalomon@google.comfc296292011-05-06 13:53:47 +0000470 GrAssert(segments.fFSCode.size());
471 strings[stringCnt] = segments.fFSCode.c_str();
472 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000473 ++stringCnt;
474
475#if PRINT_SHADERS
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000476 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000477 GrPrintf(segments.fFSUnis.c_str());
478 GrPrintf(segments.fVaryings.c_str());
479 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000480 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000481#endif
482 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
483 stringCnt,
484 strings,
485 lengths);
486
bsalomon@google.com91961302011-05-09 18:39:58 +0000487 if (!programData->fFShaderID) {
488 return false;
junov@google.comf93e7172011-03-31 21:26:24 +0000489 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000490 return true;
junov@google.comf93e7172011-03-31 21:26:24 +0000491}
492
493GrGLuint GrGLProgram::CompileShader(GrGLenum type,
494 int stringCnt,
495 const char** strings,
496 int* stringLengths) {
497 GrGLuint shader = GR_GL(CreateShader(type));
498 if (0 == shader) {
499 return 0;
500 }
501
502 GrGLint compiled = GR_GL_INIT_ZERO;
503 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
504 GR_GL(CompileShader(shader));
505 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
506
507 if (!compiled) {
508 GrGLint infoLen = GR_GL_INIT_ZERO;
509 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
510 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
511 if (infoLen > 0) {
512 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
513 for (int i = 0; i < stringCnt; ++i) {
514 if (NULL == stringLengths || stringLengths[i] < 0) {
515 GrPrintf(strings[i]);
516 } else {
517 GrPrintf("%.*s", stringLengths[i], strings[i]);
518 }
519 }
520 GrPrintf("\n%s", log.get());
521 }
522 GrAssert(!"Shader compilation failed!");
523 GR_GL(DeleteShader(shader));
524 return 0;
525 }
526 return shader;
527}
528
bsalomon@google.com91961302011-05-09 18:39:58 +0000529bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
530 CachedData* programData) const {
531 programData->fProgramID = GR_GL(CreateProgram());
532 if (!programData->fProgramID) {
533 return false;
534 }
535 const GrGLint& progID = programData->fProgramID;
536
537 GR_GL(AttachShader(progID, programData->fVShaderID));
538 GR_GL(AttachShader(progID, programData->fFShaderID));
539
540 // Bind the attrib locations to same values for all shaders
541 GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
542 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
543 if (texCoordAttrNames[t].size()) {
544 GR_GL(BindAttribLocation(progID,
545 TexCoordAttributeIdx(t),
546 texCoordAttrNames[t].c_str()));
547 }
548 }
549
550
551 if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
552 GR_GL(BindAttribLocation(progID,
553 ViewMatrixAttributeIdx(),
554 VIEW_MATRIX_NAME));
555 }
556
557 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
bsalomon@google.com72b4fcb2011-05-09 20:47:34 +0000558 const StageUniLocations& unis = programData->fUniLocations.fStages[s];
559 if (kSetAsAttribute == unis.fTextureMatrixUni) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000560 GrStringBuilder matName;
561 tex_matrix_name(s, &matName);
562 GR_GL(BindAttribLocation(progID,
563 TextureMatrixAttributeIdx(s),
564 matName.c_str()));
565 }
566 }
567
568
569 GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
570
571 GR_GL(LinkProgram(progID));
572
573 GrGLint linked = GR_GL_INIT_ZERO;
574 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
575 if (!linked) {
576 GrGLint infoLen = GR_GL_INIT_ZERO;
577 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
578 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
579 if (infoLen > 0) {
580 GR_GL(GetProgramInfoLog(progID,
581 infoLen+1,
582 NULL,
583 (char*)log.get()));
584 GrPrintf((char*)log.get());
585 }
586 GrAssert(!"Error linking program");
587 GR_GL(DeleteProgram(progID));
588 programData->fProgramID = 0;
589 return false;
590 }
591 return true;
592}
593
594void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
595 const GrGLint& progID = programData->fProgramID;
596
597 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
598 programData->fUniLocations.fViewMatrixUni =
599 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
600 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
601 }
602 if (kUseUniform == programData->fUniLocations.fColorUni) {
603 programData->fUniLocations.fColorUni =
604 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
605 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
606 }
Scroggo97c88c22011-05-11 14:05:25 +0000607 if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
608 programData->fUniLocations.fColorFilterUni =
609 GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
610 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
611 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000612
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000613 if (fProgramDesc.fUsesEdgeAA) {
614 programData->fUniLocations.fEdgesUni =
615 GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
616 GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
617 } else {
618 programData->fUniLocations.fEdgesUni = kUnusedUniform;
619 }
620
bsalomon@google.com91961302011-05-09 18:39:58 +0000621 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
622 StageUniLocations& locations = programData->fUniLocations.fStages[s];
623 if (fProgramDesc.fStages[s].fEnabled) {
624 if (kUseUniform == locations.fTextureMatrixUni) {
625 GrStringBuilder texMName;
626 tex_matrix_name(s, &texMName);
627 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
628 progID,
629 texMName.c_str()));
630 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
631 }
632
633 if (kUseUniform == locations.fSamplerUni) {
634 GrStringBuilder samplerName;
635 sampler_name(s, &samplerName);
636 locations.fSamplerUni = GR_GL(GetUniformLocation(
637 progID,
638 samplerName.c_str()));
639 GrAssert(kUnusedUniform != locations.fSamplerUni);
640 }
641
642 if (kUseUniform == locations.fNormalizedTexelSizeUni) {
643 GrStringBuilder texelSizeName;
644 normalized_texel_size_name(s, &texelSizeName);
645 locations.fNormalizedTexelSizeUni =
646 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
647 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
648 }
649
650 if (kUseUniform == locations.fRadial2Uni) {
651 GrStringBuilder radial2ParamName;
652 radial2_param_name(s, &radial2ParamName);
653 locations.fRadial2Uni = GR_GL(GetUniformLocation(
654 progID,
655 radial2ParamName.c_str()));
656 GrAssert(kUnusedUniform != locations.fRadial2Uni);
657 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000658
659 if (kUseUniform == locations.fTexDomUni) {
660 GrStringBuilder texDomName;
661 tex_domain_name(s, &texDomName);
662 locations.fTexDomUni = GR_GL(GetUniformLocation(
663 progID,
664 texDomName.c_str()));
665 GrAssert(kUnusedUniform != locations.fTexDomUni);
666 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000667 }
668 }
669 GR_GL(UseProgram(progID));
670
671 // init sampler unis and set bogus values for state tracking
672 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
673 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
674 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
675 }
676 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
677 programData->fRadial2CenterX1[s] = GR_ScalarMax;
678 programData->fRadial2Radius0[s] = -GR_ScalarMax;
679 programData->fTextureWidth[s] = -1;
680 programData->fTextureHeight[s] = -1;
681 }
682 programData->fViewMatrix = GrMatrix::InvalidMatrix();
683 programData->fColor = GrColor_ILLEGAL;
Scroggo97c88c22011-05-11 14:05:25 +0000684 programData->fColorFilterColor = GrColor_ILLEGAL;
bsalomon@google.com91961302011-05-09 18:39:58 +0000685}
686
junov@google.comf93e7172011-03-31 21:26:24 +0000687//============================================================================
688// Stage code generation
689//============================================================================
690
691void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000692 const GrGLProgram::ProgramDesc::StageDesc& desc,
693 const char* fsInColor, // NULL means no incoming color
694 const char* fsOutColor,
695 const char* vsInCoord,
696 ShaderCodeSegments* segments,
697 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000698
699 GrAssert(stageNum >= 0 && stageNum <= 9);
700
bsalomon@google.com91961302011-05-09 18:39:58 +0000701 GrStringBuilder varyingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000702 stage_varying_name(stageNum, &varyingName);
703
704 // First decide how many coords are needed to access the texture
705 // Right now it's always 2 but we could start using 1D textures for
706 // gradients.
707 static const int coordDims = 2;
708 int varyingDims;
709 /// Vertex Shader Stuff
710
711 // decide whether we need a matrix to transform texture coords
712 // and whether the varying needs a perspective coord.
bsalomon@google.com91961302011-05-09 18:39:58 +0000713 GrStringBuilder texMName;
junov@google.comf93e7172011-03-31 21:26:24 +0000714 tex_matrix_name(stageNum, &texMName);
715 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
716 varyingDims = coordDims;
717 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000718 #if GR_GL_ATTRIBUTE_MATRICES
bsalomon@google.com91961302011-05-09 18:39:58 +0000719 segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
720 locations->fTextureMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000721 #else
bsalomon@google.com91961302011-05-09 18:39:58 +0000722 segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
723 locations->fTextureMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000724 #endif
725 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
726 varyingDims = coordDims;
727 } else {
728 varyingDims = coordDims + 1;
729 }
730 }
731
bsalomon@google.com91961302011-05-09 18:39:58 +0000732 GrStringBuilder samplerName;
junov@google.comf93e7172011-03-31 21:26:24 +0000733 sampler_name(stageNum, &samplerName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000734 segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
735 locations->fSamplerUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000736
bsalomon@google.com91961302011-05-09 18:39:58 +0000737 GrStringBuilder texelSizeName;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000738 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
739 normalized_texel_size_name(stageNum, &texelSizeName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000740 segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000741 }
742
bsalomon@google.com91961302011-05-09 18:39:58 +0000743 segments->fVaryings.appendf("varying %s %s;\n",
744 float_vector_type(varyingDims), varyingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000745
746 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
747 GrAssert(varyingDims == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000748 segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
junov@google.comf93e7172011-03-31 21:26:24 +0000749 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000750 // varying = texMatrix * texCoord
751 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
752 varyingName.c_str(), texMName.c_str(),
753 vsInCoord, vector_all_coords(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000754 }
755
bsalomon@google.com91961302011-05-09 18:39:58 +0000756 GrStringBuilder radial2ParamsName;
junov@google.comf93e7172011-03-31 21:26:24 +0000757 radial2_param_name(stageNum, &radial2ParamsName);
758 // for radial grads without perspective we can pass the linear
759 // part of the quadratic as a varying.
bsalomon@google.com91961302011-05-09 18:39:58 +0000760 GrStringBuilder radial2VaryingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000761 radial2_varying_name(stageNum, &radial2VaryingName);
762
763 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
764
bsalomon@google.comdcf1b0b2011-05-11 19:00:54 +0000765 segments->fVSUnis.appendf("uniform %s float %s[6];\n",
bsalomon@google.com91961302011-05-09 18:39:58 +0000766 GrPrecision(), radial2ParamsName.c_str());
767 segments->fFSUnis.appendf("uniform float %s[6];\n",
768 radial2ParamsName.c_str());
769 locations->fRadial2Uni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000770
771 // if there is perspective we don't interpolate this
772 if (varyingDims == coordDims) {
773 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000774 segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000775
bsalomon@google.com91961302011-05-09 18:39:58 +0000776 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
777 segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
778 radial2VaryingName.c_str(), radial2ParamsName.c_str(),
779 varyingName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000780 }
781 }
782
783 /// Fragment Shader Stuff
bsalomon@google.com91961302011-05-09 18:39:58 +0000784 GrStringBuilder fsCoordName;
junov@google.comf93e7172011-03-31 21:26:24 +0000785 // function used to access the shader, may be made projective
bsalomon@google.com91961302011-05-09 18:39:58 +0000786 GrStringBuilder texFunc("texture2D");
junov@google.comf93e7172011-03-31 21:26:24 +0000787 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
788 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
789 GrAssert(varyingDims == coordDims);
790 fsCoordName = varyingName;
791 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000792 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +0000793 // our final tex coords then when in perspective we have to
bsalomon@google.com91961302011-05-09 18:39:58 +0000794 // do an explicit divide. Otherwise, we can use a Proj func.
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000795 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
796 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000797 texFunc.append("Proj");
junov@google.comf93e7172011-03-31 21:26:24 +0000798 fsCoordName = varyingName;
799 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000800 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000801 fsCoordName.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000802 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
803 float_vector_type(coordDims),
804 fsCoordName.c_str(),
805 varyingName.c_str(),
806 vector_nonhomog_coords(varyingDims),
807 varyingName.c_str(),
808 vector_homog_coord(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +0000809 }
810 }
811
bsalomon@google.comfc296292011-05-06 13:53:47 +0000812 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000813 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +0000814 switch (desc.fCoordMapping) {
815 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
816 sampleCoords = fsCoordName;
817 break;
818 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000819 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 +0000820 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000821 break;
822 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +0000823 sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000824 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000825 break;
826 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.com91961302011-05-09 18:39:58 +0000827 GrStringBuilder cName("c");
828 GrStringBuilder ac4Name("ac4");
829 GrStringBuilder rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +0000830
bsalomon@google.comfc296292011-05-06 13:53:47 +0000831 cName.appendS32(stageNum);
832 ac4Name.appendS32(stageNum);
833 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +0000834
bsalomon@google.com91961302011-05-09 18:39:58 +0000835 // if we were able to interpolate the linear component bVar is the varying
836 // otherwise compute it
837 GrStringBuilder bVar;
junov@google.comf93e7172011-03-31 21:26:24 +0000838 if (coordDims == varyingDims) {
839 bVar = radial2VaryingName;
840 GrAssert(2 == varyingDims);
841 } else {
842 GrAssert(3 == varyingDims);
843 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000844 bVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000845 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
846 bVar.c_str(), radial2ParamsName.c_str(),
847 fsCoordName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000848 }
849
bsalomon@google.com91961302011-05-09 18:39:58 +0000850 // c = (x^2)+(y^2) - params[4]
851 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
852 cName.c_str(), fsCoordName.c_str(),
853 fsCoordName.c_str(),
854 radial2ParamsName.c_str());
855 // ac4 = 4.0 * params[0] * c
856 segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
857 ac4Name.c_str(), radial2ParamsName.c_str(),
858 cName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000859
bsalomon@google.com91961302011-05-09 18:39:58 +0000860 // root = sqrt(b^2-4ac)
861 // (abs to avoid exception due to fp precision)
862 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
863 rootName.c_str(), bVar.c_str(), bVar.c_str(),
864 ac4Name.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000865
bsalomon@google.com91961302011-05-09 18:39:58 +0000866 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
867 // y coord is 0.5 (texture is effectively 1D)
868 sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
869 bVar.c_str(), radial2ParamsName.c_str(),
870 rootName.c_str(), radial2ParamsName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000871 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000872 break;}
873 };
874
bsalomon@google.com91961302011-05-09 18:39:58 +0000875 const char* smear;
876 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
877 smear = ".aaaa";
878 } else {
879 smear = "";
880 }
881 GrStringBuilder modulate;
882 if (NULL != fsInColor) {
883 modulate.printf(" * %s", fsInColor);
884 }
885
junov@google.com6acc9b32011-05-16 18:32:07 +0000886 if (desc.fOptFlags &
887 ProgramDesc::StageDesc::kCustomTextureDomain_OptFlagBit) {
888 GrStringBuilder texDomainName;
889 tex_domain_name(stageNum, &texDomainName);
890 segments->fFSUnis.appendf("uniform %s %s;\n",
891 float_vector_type(4),
892 texDomainName.c_str());
893 GrStringBuilder coordVar("clampCoord");
894 segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
895 float_vector_type(coordDims),
896 coordVar.c_str(),
897 sampleCoords.c_str(),
898 texDomainName.c_str(),
899 texDomainName.c_str());
900 sampleCoords = coordVar;
901 locations->fTexDomUni = kUseUniform;
902 }
903
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000904 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000905 locations->fNormalizedTexelSizeUni = kUseUniform;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000906 if (complexCoord) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000907 // assign the coord to a var rather than compute 4x.
908 GrStringBuilder coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +0000909 coordVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +0000910 segments->fFSCode.appendf("\t%s %s = %s;\n",
911 float_vector_type(coordDims),
912 coordVar.c_str(), sampleCoords.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000913 sampleCoords = coordVar;
914 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000915 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000916 GrStringBuilder accumVar("accum");
917 accumVar.appendS32(stageNum);
918 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);
919 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);
920 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);
921 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);
922 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000923 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000924 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 +0000925 }
junov@google.comf93e7172011-03-31 21:26:24 +0000926
927 if(fStageEffects[stageNum]) {
928 fStageEffects[stageNum]->genShaderCode(segments);
929 }
930}
931