blob: 516bc9892ee8390e71396231935464687b442c1d [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
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000150void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
151 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
170 key.keyData(reinterpret_cast<const uint8_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) {
276
277 switch (coeff) {
278 case SkXfermode::kZero_Coeff: /** 0 */
279 *str = "";
280 break;
281 case SkXfermode::kOne_Coeff: /** 1 */
282 *str = value;
283 break;
284 case SkXfermode::kSC_Coeff:
285 str->printf("(%s * %s)", src, value);
286 break;
287 case SkXfermode::kISC_Coeff:
288 str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value);
289 break;
290 case SkXfermode::kDC_Coeff:
291 str->printf("(%s * %s)", dst, value);
292 break;
293 case SkXfermode::kIDC_Coeff:
294 str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value);
295 break;
296 case SkXfermode::kSA_Coeff: /** src alpha */
297 str->printf("(%s.a * %s)", src, value);
298 break;
299 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
300 str->printf("((1.0 - %s.a) * %s)", src, value);
301 break;
302 case SkXfermode::kDA_Coeff: /** dst alpha */
303 str->printf("(%s.a * %s)", dst, value);
304 break;
305 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
306 str->printf("((1.0 - %s.a) * %s)", dst, value);
307 break;
308 default:
309 GrCrash("Unexpected xfer coeff.");
310 break;
311 }
312}
313/**
Scroggo97c88c22011-05-11 14:05:25 +0000314 * Adds a line to the fragment shader code which modifies the color by
315 * the specified color filter.
316 */
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000317static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar,
318 SkXfermode::Coeff uniformCoeff,
319 SkXfermode::Coeff colorCoeff,
320 const char* inColor) {
321 GrStringBuilder colorStr, constStr;
322 blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME,
323 inColor, inColor);
324 blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME,
325 inColor, COL_FILTER_UNI_NAME);
326
327 add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
Scroggo97c88c22011-05-11 14:05:25 +0000328}
329
bsalomon@google.com91961302011-05-09 18:39:58 +0000330bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000331
332 ShaderCodeSegments segments;
333 const uint32_t& layout = fProgramDesc.fVertexLayout;
334
bsalomon@google.com91961302011-05-09 18:39:58 +0000335 programData->fUniLocations.reset();
junov@google.comf93e7172011-03-31 21:26:24 +0000336
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000337 SkXfermode::Coeff colorCoeff, uniformCoeff;
338 // The rest of transfer mode color filters have not been implemented
339 if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
340 GR_DEBUGCODE(bool success =)
341 SkXfermode::ModeAsCoeff(fProgramDesc.fColorFilterXfermode, &uniformCoeff, &colorCoeff);
342 GR_DEBUGASSERT(success);
343 } else {
344 colorCoeff = SkXfermode::kOne_Coeff;
345 uniformCoeff = SkXfermode::kZero_Coeff;
346 }
347
348 bool needColorFilterUniform;
349 bool needComputedColor;
350 needBlendInputs(uniformCoeff, colorCoeff,
351 &needColorFilterUniform, &needComputedColor);
352
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000353 // the dual source output has no canonical var name, have to
354 // declare an output, which is incompatible with gl_FragColor/gl_FragData.
355 const char* fsColorOutput;
356 bool dualSourceOutputWritten = false;
357 bool usingDeclaredOutputs = ProgramDesc::kNone_DualSrcOutput !=
358 fProgramDesc.fDualSrcOutput;
359 if (usingDeclaredOutputs) {
360 GrAssert(0 == segments.fHeader.size());
361 segments.fHeader.printf("#version 150\n");
362 fsColorOutput = declared_color_output_name();
363 segments.fFSOutputs.appendf("out vec4 %s;\n", fsColorOutput);
364 } else {
365 fsColorOutput = "gl_FragColor";
366 }
367
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000368#if GR_GL_ATTRIBUTE_MATRICES
369 segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000370 programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000371#else
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000372 segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
bsalomon@google.com91961302011-05-09 18:39:58 +0000373 programData->fUniLocations.fViewMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000374#endif
375 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
junov@google.comf93e7172011-03-31 21:26:24 +0000376
bsalomon@google.com91961302011-05-09 18:39:58 +0000377 segments.fVSCode.append(
378 "void main() {\n"
379 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
380 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000381
bsalomon@google.com91961302011-05-09 18:39:58 +0000382 // incoming color to current stage being processed.
383 GrStringBuilder inColor;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000384
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000385 if (needComputedColor) {
386 switch (fProgramDesc.fColorType) {
387 case ProgramDesc::kAttribute_ColorType:
388 segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
389 segments.fVaryings.append("varying vec4 vColor;\n");
390 segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
391 inColor = "vColor";
392 break;
393 case ProgramDesc::kUniform_ColorType:
394 segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
395 programData->fUniLocations.fColorUni = kUseUniform;
396 inColor = COL_UNI_NAME;
397 break;
398 default:
399 GrAssert(ProgramDesc::kNone_ColorType == fProgramDesc.fColorType);
400 break;
401 }
junov@google.comf93e7172011-03-31 21:26:24 +0000402 }
403
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000404 if (fProgramDesc.fEmitsPointSize){
bsalomon@google.com91961302011-05-09 18:39:58 +0000405 segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000406 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000407
bsalomon@google.com91961302011-05-09 18:39:58 +0000408 segments.fFSCode.append("void main() {\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000409
410 // add texture coordinates that are used to the list of vertex attr decls
bsalomon@google.com91961302011-05-09 18:39:58 +0000411 GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
junov@google.comf93e7172011-03-31 21:26:24 +0000412 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000413 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000414 tex_attr_name(t, texCoordAttrs + t);
bsalomon@google.com91961302011-05-09 18:39:58 +0000415 segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000416 }
417 }
418
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000419 ///////////////////////////////////////////////////////////////////////////
420 // compute the final color
Scroggo97c88c22011-05-11 14:05:25 +0000421
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000422 // if we have color stages string them together, feeding the output color
423 // of each to the next and generating code for each stage.
424 if (needComputedColor) {
425 GrStringBuilder outColor;
426 for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
Scroggo97c88c22011-05-11 14:05:25 +0000427 if (fProgramDesc.fStages[s].fEnabled) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000428 // create var to hold stage result
429 outColor = "color";
430 outColor.appendS32(s);
431 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
432
433 const char* inCoords;
434 // figure out what our input coords are
435 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
436 layout) {
437 inCoords = POS_ATTR_NAME;
Scroggo97c88c22011-05-11 14:05:25 +0000438 } else {
439 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
440 // we better have input tex coordinates if stage is enabled.
441 GrAssert(tcIdx >= 0);
442 GrAssert(texCoordAttrs[tcIdx].size());
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000443 inCoords = texCoordAttrs[tcIdx].c_str();
junov@google.comf93e7172011-03-31 21:26:24 +0000444 }
445
446 genStageCode(s,
447 fProgramDesc.fStages[s],
bsalomon@google.comfc296292011-05-06 13:53:47 +0000448 inColor.size() ? inColor.c_str() : NULL,
449 outColor.c_str(),
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000450 inCoords,
junov@google.comf93e7172011-03-31 21:26:24 +0000451 &segments,
452 &programData->fUniLocations.fStages[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000453 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000454 }
455 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000456 }
Scroggo97c88c22011-05-11 14:05:25 +0000457
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000458 // if have all ones for the "dst" input to the color filter then we can make
459 // additional optimizations.
460 if (needColorFilterUniform && !inColor.size() &&
461 (SkXfermode::kIDC_Coeff == uniformCoeff ||
462 SkXfermode::kIDA_Coeff == uniformCoeff)) {
463 uniformCoeff = SkXfermode::kZero_Coeff;
464 bool bogus;
465 needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
466 &needColorFilterUniform, &bogus);
467 }
468 if (needColorFilterUniform) {
469 segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
470 programData->fUniLocations.fColorFilterUni = kUseUniform;
471 }
472
473 bool wroteFragColorZero = false;
474 if (SkXfermode::kZero_Coeff == uniformCoeff &&
475 SkXfermode::kZero_Coeff == colorCoeff) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000476 segments.fFSCode.appendf("\t%s = %s;\n",
477 fsColorOutput,
478 all_zeros_vec(4));
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000479 wroteFragColorZero = true;
480 } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
481 segments.fFSCode.appendf("\tvec4 filteredColor;\n");
482 const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4);
483 addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
484 colorCoeff, color);
485 inColor = "filteredColor";
486 }
487
488 ///////////////////////////////////////////////////////////////////////////
489 // compute the partial coverage (coverage stages and edge aa)
490
491 GrStringBuilder inCoverage;
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000492
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000493 // we don't need to compute coverage at all if we know the final shader
494 // output will be zero and we don't have a dual src blend output.
495 if (!wroteFragColorZero ||
496 ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000497 if (fProgramDesc.fEdgeAANumEdges > 0) {
498 segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[");
499 segments.fFSUnis.appendS32(fProgramDesc.fEdgeAANumEdges);
500 segments.fFSUnis.append("];\n");
501 programData->fUniLocations.fEdgesUni = kUseUniform;
502 int count = fProgramDesc.fEdgeAANumEdges;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000503 segments.fFSCode.append(
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000504 "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n");
505 for (int i = 0; i < count; i++) {
506 segments.fFSCode.append("\tfloat a");
507 segments.fFSCode.appendS32(i);
508 segments.fFSCode.append(" = clamp(dot(" EDGES_UNI_NAME "[");
509 segments.fFSCode.appendS32(i);
510 segments.fFSCode.append("], pos), 0.0, 1.0);\n");
511 }
512 segments.fFSCode.append("\tfloat edgeAlpha = ");
513 for (int i = 0; i < count - 1; i++) {
514 segments.fFSCode.append("min(a");
515 segments.fFSCode.appendS32(i);
516 segments.fFSCode.append(" * a");
517 segments.fFSCode.appendS32(i + 1);
518 segments.fFSCode.append(", ");
519 }
520 segments.fFSCode.append("a");
521 segments.fFSCode.appendS32(count - 1);
522 segments.fFSCode.append(" * a0");
523 for (int i = 0; i < count - 1; i++) {
524 segments.fFSCode.append(")");
525 }
526 segments.fFSCode.append(";\n");
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000527 inCoverage = "edgeAlpha";
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000528 }
529
530 GrStringBuilder outCoverage;
531 const int& startStage = fProgramDesc.fFirstCoverageStage;
532 for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) {
533 if (fProgramDesc.fStages[s].fEnabled) {
534
535 // create var to hold stage output
536 outCoverage = "coverage";
537 outCoverage.appendS32(s);
538 segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
539
540 const char* inCoords;
541 // figure out what our input coords are
542 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
543 inCoords = POS_ATTR_NAME;
544 } else {
545 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
546 // we better have input tex coordinates if stage is enabled.
547 GrAssert(tcIdx >= 0);
548 GrAssert(texCoordAttrs[tcIdx].size());
549 inCoords = texCoordAttrs[tcIdx].c_str();
550 }
551
552 genStageCode(s,
553 fProgramDesc.fStages[s],
554 inCoverage.size() ? inCoverage.c_str() : NULL,
555 outCoverage.c_str(),
556 inCoords,
557 &segments,
558 &programData->fUniLocations.fStages[s]);
559 inCoverage = outCoverage;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000560 }
561 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000562 if (ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
563 segments.fFSOutputs.appendf("out vec4 %s;\n",
564 dual_source_output_name());
565 bool outputIsZero = false;
566 GrStringBuilder coeff;
567 if (ProgramDesc::kCoverage_DualSrcOutput !=
568 fProgramDesc.fDualSrcOutput && !wroteFragColorZero) {
569 if (!inColor.size()) {
570 outputIsZero = true;
571 } else {
572 if (fProgramDesc.fDualSrcOutput ==
573 ProgramDesc::kCoverageISA_DualSrcOutput) {
574 coeff.printf("(1 - %s.a)", inColor.c_str());
575 } else {
576 coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str());
577 }
578 }
579 }
580 if (outputIsZero) {
581 segments.fFSCode.appendf("\t%s = %s;\n",
582 dual_source_output_name(),
583 all_zeros_vec(4));
584 } else {
585 modulate_helper(dual_source_output_name(),
586 coeff.c_str(),
587 inCoverage.c_str(),
588 &segments.fFSCode);
589 }
590 dualSourceOutputWritten = true;
591 }
junov@google.comf93e7172011-03-31 21:26:24 +0000592 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000593
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000594 ///////////////////////////////////////////////////////////////////////////
595 // combine color and coverage as frag color
596
597 if (!wroteFragColorZero) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000598 modulate_helper(fsColorOutput,
599 inColor.c_str(),
600 inCoverage.c_str(),
601 &segments.fFSCode);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000602 }
603
bsalomon@google.com91961302011-05-09 18:39:58 +0000604 segments.fVSCode.append("}\n");
605 segments.fFSCode.append("}\n");
606
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000607 ///////////////////////////////////////////////////////////////////////////
608 // compile and setup attribs and unis
609
bsalomon@google.com91961302011-05-09 18:39:58 +0000610 if (!CompileFSAndVS(segments, programData)) {
611 return false;
612 }
613
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000614 if (!this->bindOutputsAttribsAndLinkProgram(texCoordAttrs,
615 usingDeclaredOutputs,
616 dualSourceOutputWritten,
617 programData)) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000618 return false;
619 }
620
621 this->getUniformLocationsAndInitCache(programData);
622
623 return true;
624}
625
626bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
627 CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000628
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000629 static const int MAX_STRINGS = 6;
630 const char* strings[MAX_STRINGS];
631 int lengths[MAX_STRINGS];
junov@google.comf93e7172011-03-31 21:26:24 +0000632 int stringCnt = 0;
633
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000634 if (segments.fHeader.size()) {
635 strings[stringCnt] = segments.fHeader.c_str();
636 lengths[stringCnt] = segments.fHeader.size();
637 ++stringCnt;
638 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000639 if (segments.fVSUnis.size()) {
640 strings[stringCnt] = segments.fVSUnis.c_str();
641 lengths[stringCnt] = segments.fVSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000642 ++stringCnt;
643 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000644 if (segments.fVSAttrs.size()) {
645 strings[stringCnt] = segments.fVSAttrs.c_str();
646 lengths[stringCnt] = segments.fVSAttrs.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000647 ++stringCnt;
648 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000649 if (segments.fVaryings.size()) {
650 strings[stringCnt] = segments.fVaryings.c_str();
651 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000652 ++stringCnt;
653 }
654
bsalomon@google.comfc296292011-05-06 13:53:47 +0000655 GrAssert(segments.fVSCode.size());
656 strings[stringCnt] = segments.fVSCode.c_str();
657 lengths[stringCnt] = segments.fVSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000658 ++stringCnt;
659
660#if PRINT_SHADERS
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000661 GrPrintf(segments.fHeader.c_str());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000662 GrPrintf(segments.fVSUnis.c_str());
663 GrPrintf(segments.fVSAttrs.c_str());
664 GrPrintf(segments.fVaryings.c_str());
665 GrPrintf(segments.fVSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000666 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000667#endif
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000668 GrAssert(stringCnt <= MAX_STRINGS);
junov@google.comf93e7172011-03-31 21:26:24 +0000669 programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
670 stringCnt,
671 strings,
672 lengths);
673
bsalomon@google.com91961302011-05-09 18:39:58 +0000674 if (!programData->fVShaderID) {
675 return false;
676 }
677
junov@google.comf93e7172011-03-31 21:26:24 +0000678 stringCnt = 0;
679
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000680 if (segments.fHeader.size()) {
681 strings[stringCnt] = segments.fHeader.c_str();
682 lengths[stringCnt] = segments.fHeader.size();
683 ++stringCnt;
684 }
junov@google.comf93e7172011-03-31 21:26:24 +0000685 if (strlen(GrShaderPrecision()) > 1) {
686 strings[stringCnt] = GrShaderPrecision();
687 lengths[stringCnt] = strlen(GrShaderPrecision());
688 ++stringCnt;
689 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000690 if (segments.fFSUnis.size()) {
691 strings[stringCnt] = segments.fFSUnis.c_str();
692 lengths[stringCnt] = segments.fFSUnis.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000693 ++stringCnt;
694 }
bsalomon@google.comfc296292011-05-06 13:53:47 +0000695 if (segments.fVaryings.size()) {
696 strings[stringCnt] = segments.fVaryings.c_str();
697 lengths[stringCnt] = segments.fVaryings.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000698 ++stringCnt;
699 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000700 if (segments.fFSOutputs.size()) {
701 strings[stringCnt] = segments.fFSOutputs.c_str();
702 lengths[stringCnt] = segments.fFSOutputs.size();
703 ++stringCnt;
704 }
junov@google.comf93e7172011-03-31 21:26:24 +0000705
bsalomon@google.comfc296292011-05-06 13:53:47 +0000706 GrAssert(segments.fFSCode.size());
707 strings[stringCnt] = segments.fFSCode.c_str();
708 lengths[stringCnt] = segments.fFSCode.size();
junov@google.comf93e7172011-03-31 21:26:24 +0000709 ++stringCnt;
710
711#if PRINT_SHADERS
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000712 GrPrintf(segments.fHeader.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000713 GrPrintf(GrShaderPrecision());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000714 GrPrintf(segments.fFSUnis.c_str());
715 GrPrintf(segments.fVaryings.c_str());
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000716 GrPrintf(segments.fFSOutputs.c_str());
bsalomon@google.comfc296292011-05-06 13:53:47 +0000717 GrPrintf(segments.fFSCode.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000718 GrPrintf("\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000719#endif
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000720 GrAssert(stringCnt <= MAX_STRINGS);
junov@google.comf93e7172011-03-31 21:26:24 +0000721 programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
722 stringCnt,
723 strings,
724 lengths);
725
bsalomon@google.com91961302011-05-09 18:39:58 +0000726 if (!programData->fFShaderID) {
727 return false;
junov@google.comf93e7172011-03-31 21:26:24 +0000728 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000729
bsalomon@google.com91961302011-05-09 18:39:58 +0000730 return true;
junov@google.comf93e7172011-03-31 21:26:24 +0000731}
732
733GrGLuint GrGLProgram::CompileShader(GrGLenum type,
734 int stringCnt,
735 const char** strings,
736 int* stringLengths) {
737 GrGLuint shader = GR_GL(CreateShader(type));
738 if (0 == shader) {
739 return 0;
740 }
741
742 GrGLint compiled = GR_GL_INIT_ZERO;
743 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
744 GR_GL(CompileShader(shader));
745 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
746
747 if (!compiled) {
748 GrGLint infoLen = GR_GL_INIT_ZERO;
749 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
750 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
751 if (infoLen > 0) {
752 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
753 for (int i = 0; i < stringCnt; ++i) {
754 if (NULL == stringLengths || stringLengths[i] < 0) {
755 GrPrintf(strings[i]);
756 } else {
757 GrPrintf("%.*s", stringLengths[i], strings[i]);
758 }
759 }
760 GrPrintf("\n%s", log.get());
761 }
762 GrAssert(!"Shader compilation failed!");
763 GR_GL(DeleteShader(shader));
764 return 0;
765 }
766 return shader;
767}
768
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000769bool GrGLProgram::bindOutputsAttribsAndLinkProgram(
770 GrStringBuilder texCoordAttrNames[],
771 bool bindColorOut,
772 bool bindDualSrcOut,
773 CachedData* programData) const {
bsalomon@google.com91961302011-05-09 18:39:58 +0000774 programData->fProgramID = GR_GL(CreateProgram());
775 if (!programData->fProgramID) {
776 return false;
777 }
778 const GrGLint& progID = programData->fProgramID;
779
780 GR_GL(AttachShader(progID, programData->fVShaderID));
781 GR_GL(AttachShader(progID, programData->fFShaderID));
782
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000783 if (bindColorOut) {
784 GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
785 0, 0, declared_color_output_name()));
786 }
787 if (bindDualSrcOut) {
788 GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
789 0, 1, dual_source_output_name()));
790 }
791
bsalomon@google.com91961302011-05-09 18:39:58 +0000792 // Bind the attrib locations to same values for all shaders
793 GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
794 for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
795 if (texCoordAttrNames[t].size()) {
796 GR_GL(BindAttribLocation(progID,
797 TexCoordAttributeIdx(t),
798 texCoordAttrNames[t].c_str()));
799 }
800 }
801
bsalomon@google.com91961302011-05-09 18:39:58 +0000802 if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
803 GR_GL(BindAttribLocation(progID,
804 ViewMatrixAttributeIdx(),
805 VIEW_MATRIX_NAME));
806 }
807
808 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
bsalomon@google.com72b4fcb2011-05-09 20:47:34 +0000809 const StageUniLocations& unis = programData->fUniLocations.fStages[s];
810 if (kSetAsAttribute == unis.fTextureMatrixUni) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000811 GrStringBuilder matName;
812 tex_matrix_name(s, &matName);
813 GR_GL(BindAttribLocation(progID,
814 TextureMatrixAttributeIdx(s),
815 matName.c_str()));
816 }
817 }
818
bsalomon@google.com91961302011-05-09 18:39:58 +0000819 GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
820
821 GR_GL(LinkProgram(progID));
822
823 GrGLint linked = GR_GL_INIT_ZERO;
824 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
825 if (!linked) {
826 GrGLint infoLen = GR_GL_INIT_ZERO;
827 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
828 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
829 if (infoLen > 0) {
830 GR_GL(GetProgramInfoLog(progID,
831 infoLen+1,
832 NULL,
833 (char*)log.get()));
834 GrPrintf((char*)log.get());
835 }
836 GrAssert(!"Error linking program");
837 GR_GL(DeleteProgram(progID));
838 programData->fProgramID = 0;
839 return false;
840 }
841 return true;
842}
843
844void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
845 const GrGLint& progID = programData->fProgramID;
846
847 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
848 programData->fUniLocations.fViewMatrixUni =
849 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
850 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
851 }
852 if (kUseUniform == programData->fUniLocations.fColorUni) {
853 programData->fUniLocations.fColorUni =
854 GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
855 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
856 }
Scroggo97c88c22011-05-11 14:05:25 +0000857 if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
858 programData->fUniLocations.fColorFilterUni =
859 GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
860 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
861 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000862
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000863 if (kUseUniform == programData->fUniLocations.fEdgesUni) {
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000864 programData->fUniLocations.fEdgesUni =
865 GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
866 GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
867 } else {
868 programData->fUniLocations.fEdgesUni = kUnusedUniform;
869 }
870
bsalomon@google.com91961302011-05-09 18:39:58 +0000871 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
872 StageUniLocations& locations = programData->fUniLocations.fStages[s];
873 if (fProgramDesc.fStages[s].fEnabled) {
874 if (kUseUniform == locations.fTextureMatrixUni) {
875 GrStringBuilder texMName;
876 tex_matrix_name(s, &texMName);
877 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
878 progID,
879 texMName.c_str()));
880 GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
881 }
882
883 if (kUseUniform == locations.fSamplerUni) {
884 GrStringBuilder samplerName;
885 sampler_name(s, &samplerName);
886 locations.fSamplerUni = GR_GL(GetUniformLocation(
887 progID,
888 samplerName.c_str()));
889 GrAssert(kUnusedUniform != locations.fSamplerUni);
890 }
891
892 if (kUseUniform == locations.fNormalizedTexelSizeUni) {
893 GrStringBuilder texelSizeName;
894 normalized_texel_size_name(s, &texelSizeName);
895 locations.fNormalizedTexelSizeUni =
896 GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
897 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
898 }
899
900 if (kUseUniform == locations.fRadial2Uni) {
901 GrStringBuilder radial2ParamName;
902 radial2_param_name(s, &radial2ParamName);
903 locations.fRadial2Uni = GR_GL(GetUniformLocation(
904 progID,
905 radial2ParamName.c_str()));
906 GrAssert(kUnusedUniform != locations.fRadial2Uni);
907 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000908
909 if (kUseUniform == locations.fTexDomUni) {
910 GrStringBuilder texDomName;
911 tex_domain_name(s, &texDomName);
912 locations.fTexDomUni = GR_GL(GetUniformLocation(
913 progID,
914 texDomName.c_str()));
915 GrAssert(kUnusedUniform != locations.fTexDomUni);
916 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000917 }
918 }
919 GR_GL(UseProgram(progID));
920
921 // init sampler unis and set bogus values for state tracking
922 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
923 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
924 GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
925 }
926 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
927 programData->fRadial2CenterX1[s] = GR_ScalarMax;
928 programData->fRadial2Radius0[s] = -GR_ScalarMax;
929 programData->fTextureWidth[s] = -1;
930 programData->fTextureHeight[s] = -1;
931 }
932 programData->fViewMatrix = GrMatrix::InvalidMatrix();
933 programData->fColor = GrColor_ILLEGAL;
Scroggo97c88c22011-05-11 14:05:25 +0000934 programData->fColorFilterColor = GrColor_ILLEGAL;
bsalomon@google.com91961302011-05-09 18:39:58 +0000935}
936
junov@google.comf93e7172011-03-31 21:26:24 +0000937//============================================================================
938// Stage code generation
939//============================================================================
940
941void GrGLProgram::genStageCode(int stageNum,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000942 const GrGLProgram::ProgramDesc::StageDesc& desc,
943 const char* fsInColor, // NULL means no incoming color
944 const char* fsOutColor,
945 const char* vsInCoord,
946 ShaderCodeSegments* segments,
947 StageUniLocations* locations) const {
junov@google.comf93e7172011-03-31 21:26:24 +0000948
949 GrAssert(stageNum >= 0 && stageNum <= 9);
950
bsalomon@google.com91961302011-05-09 18:39:58 +0000951 GrStringBuilder varyingName;
junov@google.comf93e7172011-03-31 21:26:24 +0000952 stage_varying_name(stageNum, &varyingName);
953
954 // First decide how many coords are needed to access the texture
955 // Right now it's always 2 but we could start using 1D textures for
956 // gradients.
957 static const int coordDims = 2;
958 int varyingDims;
959 /// Vertex Shader Stuff
960
961 // decide whether we need a matrix to transform texture coords
962 // and whether the varying needs a perspective coord.
bsalomon@google.com91961302011-05-09 18:39:58 +0000963 GrStringBuilder texMName;
junov@google.comf93e7172011-03-31 21:26:24 +0000964 tex_matrix_name(stageNum, &texMName);
965 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
966 varyingDims = coordDims;
967 } else {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000968 #if GR_GL_ATTRIBUTE_MATRICES
bsalomon@google.com91961302011-05-09 18:39:58 +0000969 segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
970 locations->fTextureMatrixUni = kSetAsAttribute;
junov@google.comf93e7172011-03-31 21:26:24 +0000971 #else
bsalomon@google.com91961302011-05-09 18:39:58 +0000972 segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
973 locations->fTextureMatrixUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000974 #endif
975 if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
976 varyingDims = coordDims;
977 } else {
978 varyingDims = coordDims + 1;
979 }
980 }
981
bsalomon@google.com91961302011-05-09 18:39:58 +0000982 GrStringBuilder samplerName;
junov@google.comf93e7172011-03-31 21:26:24 +0000983 sampler_name(stageNum, &samplerName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000984 segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
985 locations->fSamplerUni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +0000986
bsalomon@google.com91961302011-05-09 18:39:58 +0000987 GrStringBuilder texelSizeName;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000988 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
989 normalized_texel_size_name(stageNum, &texelSizeName);
bsalomon@google.com91961302011-05-09 18:39:58 +0000990 segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000991 }
992
bsalomon@google.com91961302011-05-09 18:39:58 +0000993 segments->fVaryings.appendf("varying %s %s;\n",
994 float_vector_type(varyingDims), varyingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +0000995
996 if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
997 GrAssert(varyingDims == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +0000998 segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
junov@google.comf93e7172011-03-31 21:26:24 +0000999 } else {
bsalomon@google.com91961302011-05-09 18:39:58 +00001000 // varying = texMatrix * texCoord
1001 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
1002 varyingName.c_str(), texMName.c_str(),
1003 vsInCoord, vector_all_coords(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +00001004 }
1005
bsalomon@google.com91961302011-05-09 18:39:58 +00001006 GrStringBuilder radial2ParamsName;
junov@google.comf93e7172011-03-31 21:26:24 +00001007 radial2_param_name(stageNum, &radial2ParamsName);
1008 // for radial grads without perspective we can pass the linear
1009 // part of the quadratic as a varying.
bsalomon@google.com91961302011-05-09 18:39:58 +00001010 GrStringBuilder radial2VaryingName;
junov@google.comf93e7172011-03-31 21:26:24 +00001011 radial2_varying_name(stageNum, &radial2VaryingName);
1012
1013 if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
1014
bsalomon@google.comdcf1b0b2011-05-11 19:00:54 +00001015 segments->fVSUnis.appendf("uniform %s float %s[6];\n",
bsalomon@google.com91961302011-05-09 18:39:58 +00001016 GrPrecision(), radial2ParamsName.c_str());
1017 segments->fFSUnis.appendf("uniform float %s[6];\n",
1018 radial2ParamsName.c_str());
1019 locations->fRadial2Uni = kUseUniform;
junov@google.comf93e7172011-03-31 21:26:24 +00001020
1021 // if there is perspective we don't interpolate this
1022 if (varyingDims == coordDims) {
1023 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +00001024 segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001025
bsalomon@google.com91961302011-05-09 18:39:58 +00001026 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
1027 segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
1028 radial2VaryingName.c_str(), radial2ParamsName.c_str(),
1029 varyingName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001030 }
1031 }
1032
1033 /// Fragment Shader Stuff
bsalomon@google.com91961302011-05-09 18:39:58 +00001034 GrStringBuilder fsCoordName;
junov@google.comf93e7172011-03-31 21:26:24 +00001035 // function used to access the shader, may be made projective
bsalomon@google.com91961302011-05-09 18:39:58 +00001036 GrStringBuilder texFunc("texture2D");
junov@google.comf93e7172011-03-31 21:26:24 +00001037 if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
1038 ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
1039 GrAssert(varyingDims == coordDims);
1040 fsCoordName = varyingName;
1041 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001042 // if we have to do some special op on the varyings to get
junov@google.comf93e7172011-03-31 21:26:24 +00001043 // our final tex coords then when in perspective we have to
bsalomon@google.com91961302011-05-09 18:39:58 +00001044 // do an explicit divide. Otherwise, we can use a Proj func.
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001045 if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
1046 ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001047 texFunc.append("Proj");
junov@google.comf93e7172011-03-31 21:26:24 +00001048 fsCoordName = varyingName;
1049 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001050 fsCoordName = "inCoord";
bsalomon@google.comfc296292011-05-06 13:53:47 +00001051 fsCoordName.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001052 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
1053 float_vector_type(coordDims),
1054 fsCoordName.c_str(),
1055 varyingName.c_str(),
1056 vector_nonhomog_coords(varyingDims),
1057 varyingName.c_str(),
1058 vector_homog_coord(varyingDims));
junov@google.comf93e7172011-03-31 21:26:24 +00001059 }
1060 }
1061
bsalomon@google.comfc296292011-05-06 13:53:47 +00001062 GrStringBuilder sampleCoords;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001063 bool complexCoord = false;
junov@google.comf93e7172011-03-31 21:26:24 +00001064 switch (desc.fCoordMapping) {
1065 case ProgramDesc::StageDesc::kIdentity_CoordMapping:
1066 sampleCoords = fsCoordName;
1067 break;
1068 case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +00001069 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 +00001070 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001071 break;
1072 case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
bsalomon@google.com91961302011-05-09 18:39:58 +00001073 sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001074 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001075 break;
1076 case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
bsalomon@google.com91961302011-05-09 18:39:58 +00001077 GrStringBuilder cName("c");
1078 GrStringBuilder ac4Name("ac4");
1079 GrStringBuilder rootName("root");
junov@google.comf93e7172011-03-31 21:26:24 +00001080
bsalomon@google.comfc296292011-05-06 13:53:47 +00001081 cName.appendS32(stageNum);
1082 ac4Name.appendS32(stageNum);
1083 rootName.appendS32(stageNum);
junov@google.comf93e7172011-03-31 21:26:24 +00001084
bsalomon@google.com91961302011-05-09 18:39:58 +00001085 // if we were able to interpolate the linear component bVar is the varying
1086 // otherwise compute it
1087 GrStringBuilder bVar;
junov@google.comf93e7172011-03-31 21:26:24 +00001088 if (coordDims == varyingDims) {
1089 bVar = radial2VaryingName;
1090 GrAssert(2 == varyingDims);
1091 } else {
1092 GrAssert(3 == varyingDims);
1093 bVar = "b";
bsalomon@google.comfc296292011-05-06 13:53:47 +00001094 bVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001095 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
1096 bVar.c_str(), radial2ParamsName.c_str(),
1097 fsCoordName.c_str(), radial2ParamsName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001098 }
1099
bsalomon@google.com91961302011-05-09 18:39:58 +00001100 // c = (x^2)+(y^2) - params[4]
1101 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
1102 cName.c_str(), fsCoordName.c_str(),
1103 fsCoordName.c_str(),
1104 radial2ParamsName.c_str());
1105 // ac4 = 4.0 * params[0] * c
1106 segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
1107 ac4Name.c_str(), radial2ParamsName.c_str(),
1108 cName.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001109
bsalomon@google.com91961302011-05-09 18:39:58 +00001110 // root = sqrt(b^2-4ac)
1111 // (abs to avoid exception due to fp precision)
1112 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
1113 rootName.c_str(), bVar.c_str(), bVar.c_str(),
1114 ac4Name.c_str());
junov@google.comf93e7172011-03-31 21:26:24 +00001115
bsalomon@google.com91961302011-05-09 18:39:58 +00001116 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
1117 // y coord is 0.5 (texture is effectively 1D)
1118 sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
1119 bVar.c_str(), radial2ParamsName.c_str(),
1120 rootName.c_str(), radial2ParamsName.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001121 complexCoord = true;
junov@google.comf93e7172011-03-31 21:26:24 +00001122 break;}
1123 };
1124
bsalomon@google.com91961302011-05-09 18:39:58 +00001125 const char* smear;
1126 if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
1127 smear = ".aaaa";
1128 } else {
1129 smear = "";
1130 }
1131 GrStringBuilder modulate;
1132 if (NULL != fsInColor) {
1133 modulate.printf(" * %s", fsInColor);
1134 }
1135
junov@google.com6acc9b32011-05-16 18:32:07 +00001136 if (desc.fOptFlags &
1137 ProgramDesc::StageDesc::kCustomTextureDomain_OptFlagBit) {
1138 GrStringBuilder texDomainName;
1139 tex_domain_name(stageNum, &texDomainName);
1140 segments->fFSUnis.appendf("uniform %s %s;\n",
1141 float_vector_type(4),
1142 texDomainName.c_str());
1143 GrStringBuilder coordVar("clampCoord");
1144 segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
1145 float_vector_type(coordDims),
1146 coordVar.c_str(),
1147 sampleCoords.c_str(),
1148 texDomainName.c_str(),
1149 texDomainName.c_str());
1150 sampleCoords = coordVar;
1151 locations->fTexDomUni = kUseUniform;
1152 }
1153
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001154 if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001155 locations->fNormalizedTexelSizeUni = kUseUniform;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001156 if (complexCoord) {
bsalomon@google.com91961302011-05-09 18:39:58 +00001157 // assign the coord to a var rather than compute 4x.
1158 GrStringBuilder coordVar("tCoord");
bsalomon@google.comfc296292011-05-06 13:53:47 +00001159 coordVar.appendS32(stageNum);
bsalomon@google.com91961302011-05-09 18:39:58 +00001160 segments->fFSCode.appendf("\t%s %s = %s;\n",
1161 float_vector_type(coordDims),
1162 coordVar.c_str(), sampleCoords.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001163 sampleCoords = coordVar;
1164 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001165 GrAssert(2 == coordDims);
bsalomon@google.com91961302011-05-09 18:39:58 +00001166 GrStringBuilder accumVar("accum");
1167 accumVar.appendS32(stageNum);
1168 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);
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 += %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);
1172 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001173 } else {
bsalomon@google.com271cffc2011-05-20 14:13:56 +00001174 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 +00001175 }
junov@google.comf93e7172011-03-31 21:26:24 +00001176}
1177