blob: af838018ec4a46e05346df6bfbb5996ccbb72aec [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"
junov@google.comf93e7172011-03-31 21:26:24 +000021#include "GrMemory.h"
junov@google.comf93e7172011-03-31 21:26:24 +000022
Scroggo97c88c22011-05-11 14:05:25 +000023#include "SkXfermode.h"
24
junov@google.comf93e7172011-03-31 21:26:24 +000025namespace {
26
27const char* GrPrecision() {
28 if (GR_GL_SUPPORT_ES2) {
29 return "mediump";
30 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +000031 return " ";
junov@google.comf93e7172011-03-31 21:26:24 +000032 }
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"
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +000056#define EDGES_UNI_NAME "uEdges"
Scroggo97c88c22011-05-11 14:05:25 +000057#define COL_FILTER_UNI_NAME "uColorFilter"
junov@google.comf93e7172011-03-31 21:26:24 +000058
junov@google.comf93e7172011-03-31 21:26:24 +000059static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
60 *s = "aTexCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +000061 s->appendS32(coordIdx);
junov@google.comf93e7172011-03-31 21:26:24 +000062}
63
64static inline const char* float_vector_type(int count) {
65 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
66 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
67 return FLOAT_VECS[count];
68}
69
70static inline const char* vector_homog_coord(int count) {
71 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
72 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
73 return HOMOGS[count];
74}
75
76static inline const char* vector_nonhomog_coords(int count) {
77 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
78 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
79 return NONHOMOGS[count];
80}
81
82static inline const char* vector_all_coords(int count) {
83 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
84 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
85 return ALL[count];
86}
87
bsalomon@google.comf2d91552011-05-16 20:56:06 +000088static inline const char* all_ones_vec(int count) {
89 static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)",
90 "vec3(1,1,1)", "vec4(1,1,1,1)"};
91 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ONESVEC));
92 return ONESVEC[count];
93}
94
95static inline const char* all_zeros_vec(int count) {
96 static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)",
97 "vec3(0,0,0)", "vec4(0,0,0,0)"};
98 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ZEROSVEC));
99 return ZEROSVEC[count];
100}
101
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000102static inline const char* declared_color_output_name() { return "fsColorOut"; }
103static inline const char* dual_source_output_name() { return "dualSourceOut"; }
104
junov@google.comf93e7172011-03-31 21:26:24 +0000105static void tex_matrix_name(int stage, GrStringBuilder* s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000106#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000107 *s = "aTexM";
108#else
109 *s = "uTexM";
110#endif
bsalomon@google.comfc296292011-05-06 13:53:47 +0000111 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000112}
113
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000114static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
115 *s = "uTexelSize";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000116 s->appendS32(stage);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000117}
118
junov@google.comf93e7172011-03-31 21:26:24 +0000119static void sampler_name(int stage, GrStringBuilder* s) {
120 *s = "uSampler";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000121 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000122}
123
124static void stage_varying_name(int stage, GrStringBuilder* s) {
125 *s = "vStage";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000126 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000127}
128
129static void radial2_param_name(int stage, GrStringBuilder* s) {
130 *s = "uRadial2Params";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000131 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000132}
133
134static void radial2_varying_name(int stage, GrStringBuilder* s) {
135 *s = "vB";
bsalomon@google.comfc296292011-05-06 13:53:47 +0000136 s->appendS32(stage);
junov@google.comf93e7172011-03-31 21:26:24 +0000137}
138
junov@google.com6acc9b32011-05-16 18:32:07 +0000139static void tex_domain_name(int stage, GrStringBuilder* s) {
140 *s = "uTexDom";
141 s->appendS32(stage);
142}
143
junov@google.comf93e7172011-03-31 21:26:24 +0000144GrGLProgram::GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000145}
146
147GrGLProgram::~GrGLProgram() {
junov@google.comf93e7172011-03-31 21:26:24 +0000148}
149
tomhudson@google.com0d3f1fb2011-06-01 19:27:31 +0000150void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000151 GrBlendCoeff* dstCoeff) const {
152 switch (fProgramDesc.fDualSrcOutput) {
153 case ProgramDesc::kNone_DualSrcOutput:
154 break;
155 // the prog will write a coverage value to the secondary
156 // output and the dst is blended by one minus that value.
157 case ProgramDesc::kCoverage_DualSrcOutput:
158 case ProgramDesc::kCoverageISA_DualSrcOutput:
159 case ProgramDesc::kCoverageISC_DualSrcOutput:
160 *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_BlendCoeff;
161 break;
162 default:
163 GrCrash("Unexpected dual source blend output");
164 break;
165 }
166}
167
junov@google.comf93e7172011-03-31 21:26:24 +0000168void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
169 // Add stage configuration to the key
tomhudson@google.com0d3f1fb2011-06-01 19:27:31 +0000170 key.keyData(reinterpret_cast<const uint32_t*>(&fProgramDesc), sizeof(ProgramDesc));
junov@google.comf93e7172011-03-31 21:26:24 +0000171}
172
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000173// assigns modulation of two vars to an output var
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000174// vars can be vec4s or floats (or one of each)
175// result is always vec4
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000176// if either var is "" then assign to the other var
177// if both are "" then assign all ones
178static inline void modulate_helper(const char* outputVar,
179 const char* var0,
180 const char* var1,
181 GrStringBuilder* code) {
182 GrAssert(NULL != outputVar);
183 GrAssert(NULL != var0);
184 GrAssert(NULL != var1);
185 GrAssert(NULL != code);
186
187 bool has0 = '\0' != *var0;
188 bool has1 = '\0' != *var1;
189
190 if (!has0 && !has1) {
191 code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4));
192 } else if (!has0) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000193 code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000194 } else if (!has1) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000195 code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000196 } else {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000197 code->appendf("\t%s = vec4(%s * %s);\n", outputVar, var0, var1);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000198 }
199}
200
201// assigns addition of two vars to an output var
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000202// vars can be vec4s or floats (or one of each)
203// result is always vec4
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000204// if either var is "" then assign to the other var
205// if both are "" then assign all zeros
206static inline void add_helper(const char* outputVar,
207 const char* var0,
208 const char* var1,
209 GrStringBuilder* code) {
210 GrAssert(NULL != outputVar);
211 GrAssert(NULL != var0);
212 GrAssert(NULL != var1);
213 GrAssert(NULL != code);
214
215 bool has0 = '\0' != *var0;
216 bool has1 = '\0' != *var1;
217
218 if (!has0 && !has1) {
219 code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4));
220 } else if (!has0) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000221 code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000222 } else if (!has1) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000223 code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000224 } else {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000225 code->appendf("\t%s = vec4(%s + %s);\n", outputVar, var0, var1);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000226 }
227}
228
229// given two blend coeffecients determine whether the src
230// and/or dst computation can be omitted.
231static inline void needBlendInputs(SkXfermode::Coeff srcCoeff,
232 SkXfermode::Coeff dstCoeff,
233 bool* needSrcValue,
234 bool* needDstValue) {
235 if (SkXfermode::kZero_Coeff == srcCoeff) {
236 switch (dstCoeff) {
237 // these all read the src
238 case SkXfermode::kSC_Coeff:
239 case SkXfermode::kISC_Coeff:
240 case SkXfermode::kSA_Coeff:
241 case SkXfermode::kISA_Coeff:
242 *needSrcValue = true;
243 break;
244 default:
245 *needSrcValue = false;
246 break;
247 }
248 } else {
249 *needSrcValue = true;
250 }
251 if (SkXfermode::kZero_Coeff == dstCoeff) {
252 switch (srcCoeff) {
253 // these all read the dst
254 case SkXfermode::kDC_Coeff:
255 case SkXfermode::kIDC_Coeff:
256 case SkXfermode::kDA_Coeff:
257 case SkXfermode::kIDA_Coeff:
258 *needDstValue = true;
259 break;
260 default:
261 *needDstValue = false;
262 break;
263 }
264 } else {
265 *needDstValue = true;
Scroggo97c88c22011-05-11 14:05:25 +0000266 }
267}
268
269/**
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000270 * Create a blend_coeff * value string to be used in shader code. Sets empty
271 * string if result is trivially zero.
272 */
273static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff,
274 const char* src, const char* dst,
275 const char* value) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000276 switch (coeff) {
277 case SkXfermode::kZero_Coeff: /** 0 */
278 *str = "";
279 break;
280 case SkXfermode::kOne_Coeff: /** 1 */
281 *str = value;
282 break;
283 case SkXfermode::kSC_Coeff:
284 str->printf("(%s * %s)", src, value);
285 break;
286 case SkXfermode::kISC_Coeff:
287 str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value);
288 break;
289 case SkXfermode::kDC_Coeff:
290 str->printf("(%s * %s)", dst, value);
291 break;
292 case SkXfermode::kIDC_Coeff:
293 str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value);
294 break;
295 case SkXfermode::kSA_Coeff: /** src alpha */
296 str->printf("(%s.a * %s)", src, value);
297 break;
298 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
299 str->printf("((1.0 - %s.a) * %s)", src, value);
300 break;
301 case SkXfermode::kDA_Coeff: /** dst alpha */
302 str->printf("(%s.a * %s)", dst, value);
303 break;
304 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
305 str->printf("((1.0 - %s.a) * %s)", dst, value);
306 break;
307 default:
308 GrCrash("Unexpected xfer coeff.");
309 break;
310 }
311}
312/**
Scroggo97c88c22011-05-11 14:05:25 +0000313 * Adds a line to the fragment shader code which modifies the color by
314 * the specified color filter.
315 */
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000316static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar,
tomhudson@google.com0d3f1fb2011-06-01 19:27:31 +0000317 SkXfermode::Coeff uniformCoeff,
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000318 SkXfermode::Coeff colorCoeff,
319 const char* inColor) {
320 GrStringBuilder colorStr, constStr;
321 blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME,
322 inColor, inColor);
323 blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME,
324 inColor, COL_FILTER_UNI_NAME);
325
326 add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
Scroggo97c88c22011-05-11 14:05:25 +0000327}
328
bsalomon@google.com91961302011-05-09 18:39:58 +0000329bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000330
331 ShaderCodeSegments segments;
332 const uint32_t& layout = fProgramDesc.fVertexLayout;
333
bsalomon@google.com91961302011-05-09 18:39:58 +0000334 programData->fUniLocations.reset();
junov@google.comf93e7172011-03-31 21:26:24 +0000335
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000336 SkXfermode::Coeff colorCoeff, uniformCoeff;
337 // The rest of transfer mode color filters have not been implemented
338 if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
339 GR_DEBUGCODE(bool success =)
340 SkXfermode::ModeAsCoeff(fProgramDesc.fColorFilterXfermode, &uniformCoeff, &colorCoeff);
341 GR_DEBUGASSERT(success);
342 } else {
343 colorCoeff = SkXfermode::kOne_Coeff;
344 uniformCoeff = SkXfermode::kZero_Coeff;
345 }
346
347 bool needColorFilterUniform;
348 bool needComputedColor;
349 needBlendInputs(uniformCoeff, colorCoeff,
350 &needColorFilterUniform, &needComputedColor);
351
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000352 // the dual source output has no canonical var name, have to
353 // declare an output, which is incompatible with gl_FragColor/gl_FragData.
354 const char* fsColorOutput;
355 bool dualSourceOutputWritten = false;
tomhudson@google.com0d3f1fb2011-06-01 19:27:31 +0000356 bool usingDeclaredOutputs = ProgramDesc::kNone_DualSrcOutput !=
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000357 fProgramDesc.fDualSrcOutput;
358 if (usingDeclaredOutputs) {
359 GrAssert(0 == segments.fHeader.size());
360 segments.fHeader.printf("#version 150\n");
361 fsColorOutput = declared_color_output_name();
362 segments.fFSOutputs.appendf("out vec4 %s;\n", fsColorOutput);
363 } else {
364 fsColorOutput = "gl_FragColor";
365 }
366
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000367#if GR_GL_ATTRIBUTE_MATRICES
368 segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000369 programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000370#else
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000371 segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000372 programData->fUniLocations.fViewMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000373#endif
374 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000375
bsalomon@google.com91961302011-05-09 18:39:58 +0000376 segments.fVSCode.append(
377 "void main() {\n"
378 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
379 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000380
bsalomon@google.com91961302011-05-09 18:39:58 +0000381 // incoming color to current stage being processed.
382 GrStringBuilder inColor;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000383
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000384 if (needComputedColor) {
385 switch (fProgramDesc.fColorType) {
386 case ProgramDesc::kAttribute_ColorType:
387 segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
388 segments.fVaryings.append("varying vec4 vColor;\n");
389 segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
390 inColor = "vColor";
391 break;
392 case ProgramDesc::kUniform_ColorType:
393 segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
394 programData->fUniLocations.fColorUni = kUseUniform;
395 inColor = COL_UNI_NAME;
396 break;
397 default:
398 GrAssert(ProgramDesc::kNone_ColorType == fProgramDesc.fColorType);
399 break;
400 }
junov@google.comf93e7172011-03-31 21:26:24 +0000401 }
402
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000403 if (fProgramDesc.fEmitsPointSize){
bsalomon@google.com91961302011-05-09 18:39:58 +0000404 segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000405 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000406
bsalomon@google.com91961302011-05-09 18:39:58 +0000407 segments.fFSCode.append("void main() {\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000408
409 // add texture coordinates that are used to the list of vertex attr decls
bsalomon@google.com91961302011-05-09 18:39:58 +0000410 GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
junov@google.comf93e7172011-03-31 21:26:24 +0000411 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000412 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000413 tex_attr_name(t, texCoordAttrs + t);
bsalomon@google.com91961302011-05-09 18:39:58 +0000414 segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000415 }
416 }
417
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000418 ///////////////////////////////////////////////////////////////////////////
419 // compute the final color
Scroggo97c88c22011-05-11 14:05:25 +0000420
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000421 // if we have color stages string them together, feeding the output color
422 // of each to the next and generating code for each stage.
423 if (needComputedColor) {
424 GrStringBuilder outColor;
425 for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
Scroggo97c88c22011-05-11 14:05:25 +0000426 if (fProgramDesc.fStages[s].fEnabled) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000427 // create var to hold stage result
428 outColor = "color";
429 outColor.appendS32(s);
430 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
431
432 const char* inCoords;
433 // figure out what our input coords are
434 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
435 layout) {
436 inCoords = POS_ATTR_NAME;
Scroggo97c88c22011-05-11 14:05:25 +0000437 } else {
438 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
439 // we better have input tex coordinates if stage is enabled.
440 GrAssert(tcIdx >= 0);
441 GrAssert(texCoordAttrs[tcIdx].size());
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000442 inCoords = texCoordAttrs[tcIdx].c_str();
junov@google.comf93e7172011-03-31 21:26:24 +0000443 }
444
445 genStageCode(s,
446 fProgramDesc.fStages[s],
bsalomon@google.comfc296292011-05-06 13:53:47 +0000447 inColor.size() ? inColor.c_str() : NULL,
448 outColor.c_str(),
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000449 inCoords,
junov@google.comf93e7172011-03-31 21:26:24 +0000450 &segments,
451 &programData->fUniLocations.fStages[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000452 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000453 }
454 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000455 }
Scroggo97c88c22011-05-11 14:05:25 +0000456
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000457 // if have all ones for the "dst" input to the color filter then we can make
458 // additional optimizations.
459 if (needColorFilterUniform && !inColor.size() &&
460 (SkXfermode::kIDC_Coeff == uniformCoeff ||
461 SkXfermode::kIDA_Coeff == uniformCoeff)) {
462 uniformCoeff = SkXfermode::kZero_Coeff;
463 bool bogus;
464 needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
465 &needColorFilterUniform, &bogus);
466 }
467 if (needColorFilterUniform) {
468 segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
469 programData->fUniLocations.fColorFilterUni = kUseUniform;
470 }
471
472 bool wroteFragColorZero = false;
473 if (SkXfermode::kZero_Coeff == uniformCoeff &&
474 SkXfermode::kZero_Coeff == colorCoeff) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000475 segments.fFSCode.appendf("\t%s = %s;\n",
476 fsColorOutput,
477 all_zeros_vec(4));
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000478 wroteFragColorZero = true;
479 } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
480 segments.fFSCode.appendf("\tvec4 filteredColor;\n");
481 const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4);
482 addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
483 colorCoeff, color);
484 inColor = "filteredColor";
485 }
486
487 ///////////////////////////////////////////////////////////////////////////
488 // compute the partial coverage (coverage stages and edge aa)
489
490 GrStringBuilder inCoverage;
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000491
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000492 // we don't need to compute coverage at all if we know the final shader
493 // output will be zero and we don't have a dual src blend output.
494 if (!wroteFragColorZero ||
495 ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000496 if (fProgramDesc.fEdgeAANumEdges > 0) {
497 segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[");
498 segments.fFSUnis.appendS32(fProgramDesc.fEdgeAANumEdges);
499 segments.fFSUnis.append("];\n");
500 programData->fUniLocations.fEdgesUni = kUseUniform;
501 int count = fProgramDesc.fEdgeAANumEdges;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000502 segments.fFSCode.append(
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000503 "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n");
504 for (int i = 0; i < count; i++) {
505 segments.fFSCode.append("\tfloat a");
506 segments.fFSCode.appendS32(i);
507 segments.fFSCode.append(" = clamp(dot(" EDGES_UNI_NAME "[");
508 segments.fFSCode.appendS32(i);
509 segments.fFSCode.append("], pos), 0.0, 1.0);\n");
510 }
511 segments.fFSCode.append("\tfloat edgeAlpha = ");
512 for (int i = 0; i < count - 1; i++) {
513 segments.fFSCode.append("min(a");
514 segments.fFSCode.appendS32(i);
515 segments.fFSCode.append(" * a");
516 segments.fFSCode.appendS32(i + 1);
517 segments.fFSCode.append(", ");
518 }
519 segments.fFSCode.append("a");
520 segments.fFSCode.appendS32(count - 1);
521 segments.fFSCode.append(" * a0");
522 for (int i = 0; i < count - 1; i++) {
523 segments.fFSCode.append(")");
524 }
525 segments.fFSCode.append(";\n");
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000526 inCoverage = "edgeAlpha";
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000527 }
528
529 GrStringBuilder outCoverage;
530 const int& startStage = fProgramDesc.fFirstCoverageStage;
531 for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) {
532 if (fProgramDesc.fStages[s].fEnabled) {
533
534 // create var to hold stage output
535 outCoverage = "coverage";
536 outCoverage.appendS32(s);
537 segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
538
539 const char* inCoords;
540 // figure out what our input coords are
541 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
542 inCoords = POS_ATTR_NAME;
543 } else {
544 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
545 // we better have input tex coordinates if stage is enabled.
546 GrAssert(tcIdx >= 0);
547 GrAssert(texCoordAttrs[tcIdx].size());
548 inCoords = texCoordAttrs[tcIdx].c_str();
549 }
550
551 genStageCode(s,
552 fProgramDesc.fStages[s],
553 inCoverage.size() ? inCoverage.c_str() : NULL,
554 outCoverage.c_str(),
555 inCoords,
556 &segments,
557 &programData->fUniLocations.fStages[s]);
558 inCoverage = outCoverage;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000559 }
560 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000561 if (ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
562 segments.fFSOutputs.appendf("out vec4 %s;\n",
563 dual_source_output_name());
564 bool outputIsZero = false;
565 GrStringBuilder coeff;
566 if (ProgramDesc::kCoverage_DualSrcOutput !=
567 fProgramDesc.fDualSrcOutput && !wroteFragColorZero) {
568 if (!inColor.size()) {
569 outputIsZero = true;
570 } else {
571 if (fProgramDesc.fDualSrcOutput ==
572 ProgramDesc::kCoverageISA_DualSrcOutput) {
573 coeff.printf("(1 - %s.a)", inColor.c_str());
574 } else {
575 coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str());
576 }
577 }
578 }
579 if (outputIsZero) {
580 segments.fFSCode.appendf("\t%s = %s;\n",
581 dual_source_output_name(),
582 all_zeros_vec(4));
583 } else {
584 modulate_helper(dual_source_output_name(),
585 coeff.c_str(),
586 inCoverage.c_str(),
587 &segments.fFSCode);
588 }
589 dualSourceOutputWritten = true;
590 }
junov@google.comf93e7172011-03-31 21:26:24 +0000591 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000592
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000593 ///////////////////////////////////////////////////////////////////////////
594 // combine color and coverage as frag color
595
596 if (!wroteFragColorZero) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000597 modulate_helper(fsColorOutput,
598 inColor.c_str(),
599 inCoverage.c_str(),
600 &segments.fFSCode);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000601 }
602
bsalomon@google.com91961302011-05-09 18:39:58 +0000603 segments.fVSCode.append("}\n");
604 segments.fFSCode.append("}\n");
605
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000606 ///////////////////////////////////////////////////////////////////////////
607 // compile and setup attribs and unis
608
bsalomon@google.com91961302011-05-09 18:39:58 +0000609 if (!CompileFSAndVS(segments, programData)) {
610 return false;
611 }
612
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000613 if (!this->bindOutputsAttribsAndLinkProgram(texCoordAttrs,
614 usingDeclaredOutputs,
615 dualSourceOutputWritten,
616 programData)) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000617 return false;
618 }
619
620 this->getUniformLocationsAndInitCache(programData);
621
622 return true;
623}
624
625bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
626 CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000627
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000628 static const int MAX_STRINGS = 6;
629 const char* strings[MAX_STRINGS];
630 int lengths[MAX_STRINGS];
junov@google.comf93e7172011-03-31 21:26:24 +0000631 int stringCnt = 0;
632
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000633 if (segments.fHeader.size()) {
634 strings[stringCnt] = segments.fHeader.c_str();
635 lengths[stringCnt] = segments.fHeader.size();
636 ++stringCnt;
637 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000638 if (segments.fVSUnis.size()) {
639 strings[stringCnt] = segments.fVSUnis.c_str();
640 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000641 ++stringCnt;
642 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000643 if (segments.fVSAttrs.size()) {
644 strings[stringCnt] = segments.fVSAttrs.c_str();
645 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000646 ++stringCnt;
647 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000648 if (segments.fVaryings.size()) {
649 strings[stringCnt] = segments.fVaryings.c_str();
650 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000651 ++stringCnt;
652 }
653
bsalomon@google.comfc296292011-05-06 13:53:47 +0000654 GrAssert(segments.fVSCode.size());
655 strings[stringCnt] = segments.fVSCode.c_str();
656 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000657 ++stringCnt;
658
659#if PRINT_SHADERS
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000660 GrPrintf(segments.fHeader.c_str());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000661 GrPrintf(segments.fVSUnis.c_str());
662 GrPrintf(segments.fVSAttrs.c_str());
663 GrPrintf(segments.fVaryings.c_str());
664 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000665 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000666#endif
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000667 GrAssert(stringCnt <= MAX_STRINGS);
junov@google.comf93e7172011-03-31 21:26:24 +0000668 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
669 stringCnt,
670 strings,
671 lengths);
672
bsalomon@google.com91961302011-05-09 18:39:58 +0000673 if (!programData->fVShaderID) {
674 return false;
675 }
676
junov@google.comf93e7172011-03-31 21:26:24 +0000677 stringCnt = 0;
678
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000679 if (segments.fHeader.size()) {
680 strings[stringCnt] = segments.fHeader.c_str();
681 lengths[stringCnt] = segments.fHeader.size();
682 ++stringCnt;
683 }
junov@google.comf93e7172011-03-31 21:26:24 +0000684 if (strlen(GrShaderPrecision()) > 1) {
685 strings[stringCnt] = GrShaderPrecision();
686 lengths[stringCnt] = strlen(GrShaderPrecision());
687 ++stringCnt;
688 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000689 if (segments.fFSUnis.size()) {
690 strings[stringCnt] = segments.fFSUnis.c_str();
691 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000692 ++stringCnt;
693 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000694 if (segments.fVaryings.size()) {
695 strings[stringCnt] = segments.fVaryings.c_str();
696 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000697 ++stringCnt;
698 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000699 if (segments.fFSOutputs.size()) {
700 strings[stringCnt] = segments.fFSOutputs.c_str();
701 lengths[stringCnt] = segments.fFSOutputs.size();
702 ++stringCnt;
703 }
junov@google.comf93e7172011-03-31 21:26:24 +0000704
bsalomon@google.comfc296292011-05-06 13:53:47 +0000705 GrAssert(segments.fFSCode.size());
706 strings[stringCnt] = segments.fFSCode.c_str();
707 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000708 ++stringCnt;
709
710#if PRINT_SHADERS
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000711 GrPrintf(segments.fHeader.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000712 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000713 GrPrintf(segments.fFSUnis.c_str());
714 GrPrintf(segments.fVaryings.c_str());
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000715 GrPrintf(segments.fFSOutputs.c_str());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000716 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000717 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000718#endif
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000719 GrAssert(stringCnt <= MAX_STRINGS);
junov@google.comf93e7172011-03-31 21:26:24 +0000720 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
721 stringCnt,
722 strings,
723 lengths);
724
bsalomon@google.com91961302011-05-09 18:39:58 +0000725 if (!programData->fFShaderID) {
726 return false;
junov@google.comf93e7172011-03-31 21:26:24 +0000727 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000728
bsalomon@google.com91961302011-05-09 18:39:58 +0000729 return true;
junov@google.comf93e7172011-03-31 21:26:24 +0000730}
731
732GrGLuint GrGLProgram::CompileShader(GrGLenum type,
733 int stringCnt,
734 const char** strings,
735 int* stringLengths) {
736 GrGLuint shader = GR_GL(CreateShader(type));
737 if (0 == shader) {
738 return 0;
739 }
740
741 GrGLint compiled = GR_GL_INIT_ZERO;
742 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
743 GR_GL(CompileShader(shader));
744 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
745
746 if (!compiled) {
747 GrGLint infoLen = GR_GL_INIT_ZERO;
748 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
749 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
750 if (infoLen > 0) {
751 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
752 for (int i = 0; i < stringCnt; ++i) {
753 if (NULL == stringLengths || stringLengths[i] < 0) {
754 GrPrintf(strings[i]);
755 } else {
756 GrPrintf("%.*s", stringLengths[i], strings[i]);
757 }
758 }
759 GrPrintf("\n%s", log.get());
760 }
761 GrAssert(!"Shader compilation failed!");
762 GR_GL(DeleteShader(shader));
763 return 0;
764 }
765 return shader;
766}
767
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000768bool GrGLProgram::bindOutputsAttribsAndLinkProgram(
769 GrStringBuilder texCoordAttrNames[],
770 bool bindColorOut,
771 bool bindDualSrcOut,
772 CachedData* programData) const {
bsalomon@google.com91961302011-05-09 18:39:58 +0000773 programData->fProgramID = GR_GL(CreateProgram());
774 if (!programData->fProgramID) {
775 return false;
776 }
777 const GrGLint& progID = programData->fProgramID;
778
779 GR_GL(AttachShader(progID, programData->fVShaderID));
780 GR_GL(AttachShader(progID, programData->fFShaderID));
781
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000782 if (bindColorOut) {
783 GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
784 0, 0, declared_color_output_name()));
785 }
786 if (bindDualSrcOut) {
787 GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
788 0, 1, dual_source_output_name()));
789 }
790
bsalomon@google.com91961302011-05-09 18:39:58 +0000791 // Bind the attrib locations to same values for all shaders
792 GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
793 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
794 if (texCoordAttrNames[t].size()) {
795 GR_GL(BindAttribLocation(progID,
796 TexCoordAttributeIdx(t),
797 texCoordAttrNames[t].c_str()));
798 }
799 }
800
bsalomon@google.com91961302011-05-09 18:39:58 +0000801 if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
802 GR_GL(BindAttribLocation(progID,
803 ViewMatrixAttributeIdx(),
804 VIEW_MATRIX_NAME));
805 }
806
807 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
bsalomon@google.com72b4fcb2011-05-09 20:47:34 +0000808 const StageUniLocations& unis = programData->fUniLocations.fStages[s];
809 if (kSetAsAttribute == unis.fTextureMatrixUni) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000810 GrStringBuilder matName;
811 tex_matrix_name(s, &matName);
812 GR_GL(BindAttribLocation(progID,
813 TextureMatrixAttributeIdx(s),
814 matName.c_str()));
815 }
816 }
817
bsalomon@google.com91961302011-05-09 18:39:58 +0000818 GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
819
820 GR_GL(LinkProgram(progID));
821
822 GrGLint linked = GR_GL_INIT_ZERO;
823 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
824 if (!linked) {
825 GrGLint infoLen = GR_GL_INIT_ZERO;
826 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
827 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
828 if (infoLen > 0) {
829 GR_GL(GetProgramInfoLog(progID,
830 infoLen+1,
831 NULL,
832 (char*)log.get()));
833 GrPrintf((char*)log.get());
834 }
835 GrAssert(!"Error linking program");
836 GR_GL(DeleteProgram(progID));
837 programData->fProgramID = 0;
838 return false;
839 }
840 return true;
841}
842
843void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
844 const GrGLint& progID = programData->fProgramID;
845
846 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
847 programData->fUniLocations.fViewMatrixUni =
848 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
849 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
850 }
851 if (kUseUniform == programData->fUniLocations.fColorUni) {
852 programData->fUniLocations.fColorUni =
853 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
854 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
855 }
Scroggo97c88c22011-05-11 14:05:25 +0000856 if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
857 programData->fUniLocations.fColorFilterUni =
858 GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
859 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
860 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000861
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000862 if (kUseUniform == programData->fUniLocations.fEdgesUni) {
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000863 programData->fUniLocations.fEdgesUni =
864 GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
865 GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
866 } else {
867 programData->fUniLocations.fEdgesUni = kUnusedUniform;
868 }
869
bsalomon@google.com91961302011-05-09 18:39:58 +0000870 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
871 StageUniLocations& locations = programData->fUniLocations.fStages[s];
872 if (fProgramDesc.fStages[s].fEnabled) {
873 if (kUseUniform == locations.fTextureMatrixUni) {
874 GrStringBuilder texMName;
875 tex_matrix_name(s, &texMName);
876 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
877 progID,
878 texMName.c_str()));
879 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
880 }
881
882 if (kUseUniform == locations.fSamplerUni) {
883 GrStringBuilder samplerName;
884 sampler_name(s, &samplerName);
885 locations.fSamplerUni = GR_GL(GetUniformLocation(
886 progID,
887 samplerName.c_str()));
888 GrAssert(kUnusedUniform != locations.fSamplerUni);
889 }
890
891 if (kUseUniform == locations.fNormalizedTexelSizeUni) {
892 GrStringBuilder texelSizeName;
893 normalized_texel_size_name(s, &texelSizeName);
894 locations.fNormalizedTexelSizeUni =
895 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
896 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
897 }
898
899 if (kUseUniform == locations.fRadial2Uni) {
900 GrStringBuilder radial2ParamName;
901 radial2_param_name(s, &radial2ParamName);
902 locations.fRadial2Uni = GR_GL(GetUniformLocation(
903 progID,
904 radial2ParamName.c_str()));
905 GrAssert(kUnusedUniform != locations.fRadial2Uni);
906 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000907
908 if (kUseUniform == locations.fTexDomUni) {
909 GrStringBuilder texDomName;
910 tex_domain_name(s, &texDomName);
911 locations.fTexDomUni = GR_GL(GetUniformLocation(
912 progID,
913 texDomName.c_str()));
914 GrAssert(kUnusedUniform != locations.fTexDomUni);
915 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000916 }
917 }
918 GR_GL(UseProgram(progID));
919
920 // init sampler unis and set bogus values for state tracking
921 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
922 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
923 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
924 }
925 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
926 programData->fRadial2CenterX1[s] = GR_ScalarMax;
927 programData->fRadial2Radius0[s] = -GR_ScalarMax;
928 programData->fTextureWidth[s] = -1;
929 programData->fTextureHeight[s] = -1;
930 }
931 programData->fViewMatrix = GrMatrix::InvalidMatrix();
932 programData->fColor = GrColor_ILLEGAL;
Scroggo97c88c22011-05-11 14:05:25 +0000933 programData->fColorFilterColor = GrColor_ILLEGAL;
bsalomon@google.com91961302011-05-09 18:39:58 +0000934}
935
junov@google.comf93e7172011-03-31 21:26:24 +0000936//============================================================================
937// Stage code generation
938//============================================================================
939
940void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000941 const GrGLProgram::ProgramDesc::StageDesc& desc,
942 const char* fsInColor, // NULL means no incoming color
943 const char* fsOutColor,
944 const char* vsInCoord,
945 ShaderCodeSegments* segments,
946 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000947
948 GrAssert(stageNum >= 0 && stageNum <= 9);
949
bsalomon@google.com91961302011-05-09 18:39:58 +0000950 GrStringBuilder varyingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000951 stage_varying_name(stageNum, &varyingName);
952
953 // First decide how many coords are needed to access the texture
954 // Right now it's always 2 but we could start using 1D textures for
955 // gradients.
956 static const int coordDims = 2;
957 int varyingDims;
958 /// Vertex Shader Stuff
959
960 // decide whether we need a matrix to transform texture coords
961 // and whether the varying needs a perspective coord.
bsalomon@google.com91961302011-05-09 18:39:58 +0000962 GrStringBuilder texMName;
junov@google.comf93e7172011-03-31 21:26:24 +0000963 tex_matrix_name(stageNum, &texMName);
964 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
965 varyingDims = coordDims;
966 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000967 #if GR_GL_ATTRIBUTE_MATRICES
bsalomon@google.com91961302011-05-09 18:39:58 +0000968 segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
969 locations->fTextureMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000970 #else
bsalomon@google.com91961302011-05-09 18:39:58 +0000971 segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
972 locations->fTextureMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000973 #endif
974 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
975 varyingDims = coordDims;
976 } else {
977 varyingDims = coordDims + 1;
978 }
979 }
980
bsalomon@google.com91961302011-05-09 18:39:58 +0000981 GrStringBuilder samplerName;
junov@google.comf93e7172011-03-31 21:26:24 +0000982 sampler_name(stageNum, &samplerName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000983 segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
984 locations->fSamplerUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000985
bsalomon@google.com91961302011-05-09 18:39:58 +0000986 GrStringBuilder texelSizeName;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000987 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
988 normalized_texel_size_name(stageNum, &texelSizeName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000989 segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000990 }
991
bsalomon@google.com91961302011-05-09 18:39:58 +0000992 segments->fVaryings.appendf("varying %s %s;\n",
993 float_vector_type(varyingDims), varyingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000994
995 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
996 GrAssert(varyingDims == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000997 segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
junov@google.comf93e7172011-03-31 21:26:24 +0000998 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +0000999 // varying = texMatrix * texCoord
1000 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
1001 varyingName.c_str(), texMName.c_str(),
1002 vsInCoord, vector_all_coords(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +00001003 }
1004
bsalomon@google.com91961302011-05-09 18:39:58 +00001005 GrStringBuilder radial2ParamsName;
junov@google.comf93e7172011-03-31 21:26:24 +00001006 radial2_param_name(stageNum, &radial2ParamsName);
1007 // for radial grads without perspective we can pass the linear
1008 // part of the quadratic as a varying.
bsalomon@google.com91961302011-05-09 18:39:58 +00001009 GrStringBuilder radial2VaryingName;
junov@google.comf93e7172011-03-31 21:26:24 +00001010 radial2_varying_name(stageNum, &radial2VaryingName);
1011
1012 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
1013
bsalomon@google.comdcf1b0b2011-05-11 19:00:54 +00001014 segments->fVSUnis.appendf("uniform %s float %s[6];\n",
bsalomon@google.com91961302011-05-09 18:39:58 +00001015 GrPrecision(), radial2ParamsName.c_str());
1016 segments->fFSUnis.appendf("uniform float %s[6];\n",
1017 radial2ParamsName.c_str());
1018 locations->fRadial2Uni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +00001019
1020 // if there is perspective we don't interpolate this
1021 if (varyingDims == coordDims) {
1022 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +00001023 segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001024
bsalomon@google.com91961302011-05-09 18:39:58 +00001025 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
1026 segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
1027 radial2VaryingName.c_str(), radial2ParamsName.c_str(),
1028 varyingName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001029 }
1030 }
1031
1032 /// Fragment Shader Stuff
bsalomon@google.com91961302011-05-09 18:39:58 +00001033 GrStringBuilder fsCoordName;
junov@google.comf93e7172011-03-31 21:26:24 +00001034 // function used to access the shader, may be made projective
bsalomon@google.com91961302011-05-09 18:39:58 +00001035 GrStringBuilder texFunc("texture2D");
junov@google.comf93e7172011-03-31 21:26:24 +00001036 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
1037 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
1038 GrAssert(varyingDims == coordDims);
1039 fsCoordName = varyingName;
1040 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001041 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +00001042 // our final tex coords then when in perspective we have to
bsalomon@google.com91961302011-05-09 18:39:58 +00001043 // do an explicit divide. Otherwise, we can use a Proj func.
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001044 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
1045 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001046 texFunc.append("Proj");
junov@google.comf93e7172011-03-31 21:26:24 +00001047 fsCoordName = varyingName;
1048 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001049 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +00001050 fsCoordName.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001051 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
1052 float_vector_type(coordDims),
1053 fsCoordName.c_str(),
1054 varyingName.c_str(),
1055 vector_nonhomog_coords(varyingDims),
1056 varyingName.c_str(),
1057 vector_homog_coord(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +00001058 }
1059 }
1060
bsalomon@google.comfc296292011-05-06 13:53:47 +00001061 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001062 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +00001063 switch (desc.fCoordMapping) {
1064 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
1065 sampleCoords = fsCoordName;
1066 break;
1067 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +00001068 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 +00001069 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001070 break;
1071 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +00001072 sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001073 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001074 break;
1075 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.com91961302011-05-09 18:39:58 +00001076 GrStringBuilder cName("c");
1077 GrStringBuilder ac4Name("ac4");
1078 GrStringBuilder rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +00001079
bsalomon@google.comfc296292011-05-06 13:53:47 +00001080 cName.appendS32(stageNum);
1081 ac4Name.appendS32(stageNum);
1082 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +00001083
bsalomon@google.com91961302011-05-09 18:39:58 +00001084 // if we were able to interpolate the linear component bVar is the varying
1085 // otherwise compute it
1086 GrStringBuilder bVar;
junov@google.comf93e7172011-03-31 21:26:24 +00001087 if (coordDims == varyingDims) {
1088 bVar = radial2VaryingName;
1089 GrAssert(2 == varyingDims);
1090 } else {
1091 GrAssert(3 == varyingDims);
1092 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +00001093 bVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001094 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
1095 bVar.c_str(), radial2ParamsName.c_str(),
1096 fsCoordName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001097 }
1098
bsalomon@google.com91961302011-05-09 18:39:58 +00001099 // c = (x^2)+(y^2) - params[4]
1100 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
1101 cName.c_str(), fsCoordName.c_str(),
1102 fsCoordName.c_str(),
1103 radial2ParamsName.c_str());
1104 // ac4 = 4.0 * params[0] * c
1105 segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
1106 ac4Name.c_str(), radial2ParamsName.c_str(),
1107 cName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001108
bsalomon@google.com91961302011-05-09 18:39:58 +00001109 // root = sqrt(b^2-4ac)
1110 // (abs to avoid exception due to fp precision)
1111 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
1112 rootName.c_str(), bVar.c_str(), bVar.c_str(),
1113 ac4Name.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001114
bsalomon@google.com91961302011-05-09 18:39:58 +00001115 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
1116 // y coord is 0.5 (texture is effectively 1D)
1117 sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
1118 bVar.c_str(), radial2ParamsName.c_str(),
1119 rootName.c_str(), radial2ParamsName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001120 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001121 break;}
1122 };
1123
bsalomon@google.com91961302011-05-09 18:39:58 +00001124 const char* smear;
1125 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
1126 smear = ".aaaa";
1127 } else {
1128 smear = "";
1129 }
1130 GrStringBuilder modulate;
1131 if (NULL != fsInColor) {
1132 modulate.printf(" * %s", fsInColor);
1133 }
1134
junov@google.com6acc9b32011-05-16 18:32:07 +00001135 if (desc.fOptFlags &
1136 ProgramDesc::StageDesc::kCustomTextureDomain_OptFlagBit) {
1137 GrStringBuilder texDomainName;
1138 tex_domain_name(stageNum, &texDomainName);
1139 segments->fFSUnis.appendf("uniform %s %s;\n",
1140 float_vector_type(4),
1141 texDomainName.c_str());
1142 GrStringBuilder coordVar("clampCoord");
1143 segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
1144 float_vector_type(coordDims),
1145 coordVar.c_str(),
1146 sampleCoords.c_str(),
1147 texDomainName.c_str(),
1148 texDomainName.c_str());
1149 sampleCoords = coordVar;
1150 locations->fTexDomUni = kUseUniform;
1151 }
1152
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001153 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001154 locations->fNormalizedTexelSizeUni = kUseUniform;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001155 if (complexCoord) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001156 // assign the coord to a var rather than compute 4x.
1157 GrStringBuilder coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +00001158 coordVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001159 segments->fFSCode.appendf("\t%s %s = %s;\n",
1160 float_vector_type(coordDims),
1161 coordVar.c_str(), sampleCoords.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001162 sampleCoords = coordVar;
1163 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001164 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +00001165 GrStringBuilder accumVar("accum");
1166 accumVar.appendS32(stageNum);
1167 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);
1168 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);
1169 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);
1170 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);
1171 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001172 } else {
bsalomon@google.com271cffc2011-05-20 14:13:56 +00001173 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 +00001174 }
junov@google.comf93e7172011-03-31 21:26:24 +00001175}