GrGLProgram.cpp revision 23cb2299ddf8fc87df0d3f9bda78934382cf714d
1/* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "GrGLProgram.h" 9 10#include "GrAllocator.h" 11#include "GrCustomStage.h" 12#include "GrGLProgramStage.h" 13#include "gl/GrGLShaderBuilder.h" 14#include "GrGLShaderVar.h" 15#include "GrProgramStageFactory.h" 16#include "SkTrace.h" 17#include "SkXfermode.h" 18 19namespace { 20 21enum { 22 /// Used to mark a StageUniLocation field that should be bound 23 /// to a uniform during getUniformLocationsAndInitCache(). 24 kUseUniform = 2000 25}; 26 27} // namespace 28 29#define PRINT_SHADERS 0 30 31typedef GrGLProgram::ProgramDesc::StageDesc StageDesc; 32 33#define VIEW_MATRIX_NAME "uViewM" 34 35#define POS_ATTR_NAME "aPosition" 36#define COL_ATTR_NAME "aColor" 37#define COV_ATTR_NAME "aCoverage" 38#define EDGE_ATTR_NAME "aEdge" 39#define COL_UNI_NAME "uColor" 40#define COV_UNI_NAME "uCoverage" 41#define COL_FILTER_UNI_NAME "uColorFilter" 42#define COL_MATRIX_UNI_NAME "uColorMatrix" 43#define COL_MATRIX_VEC_UNI_NAME "uColorMatrixVec" 44 45namespace { 46inline void tex_attr_name(int coordIdx, GrStringBuilder* s) { 47 *s = "aTexCoord"; 48 s->appendS32(coordIdx); 49} 50 51inline const char* float_vector_type_str(int count) { 52 return GrGLShaderVar::TypeString(GrSLFloatVectorType(count)); 53} 54 55inline const char* vector_all_coords(int count) { 56 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"}; 57 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL)); 58 return ALL[count]; 59} 60 61inline const char* all_ones_vec(int count) { 62 static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)", 63 "vec3(1,1,1)", "vec4(1,1,1,1)"}; 64 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ONESVEC)); 65 return ONESVEC[count]; 66} 67 68inline const char* all_zeros_vec(int count) { 69 static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)", 70 "vec3(0,0,0)", "vec4(0,0,0,0)"}; 71 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ZEROSVEC)); 72 return ZEROSVEC[count]; 73} 74 75inline const char* declared_color_output_name() { return "fsColorOut"; } 76inline const char* dual_source_output_name() { return "dualSourceOut"; } 77 78inline void tex_matrix_name(int stage, GrStringBuilder* s) { 79 *s = "uTexM"; 80 s->appendS32(stage); 81} 82 83inline void normalized_texel_size_name(int stage, GrStringBuilder* s) { 84 *s = "uTexelSize"; 85 s->appendS32(stage); 86} 87 88inline void sampler_name(int stage, GrStringBuilder* s) { 89 *s = "uSampler"; 90 s->appendS32(stage); 91} 92 93inline void radial2_param_name(int stage, GrStringBuilder* s) { 94 *s = "uRadial2Params"; 95 s->appendS32(stage); 96} 97 98inline void convolve_param_names(int stage, GrStringBuilder* k, GrStringBuilder* i) { 99 *k = "uKernel"; 100 k->appendS32(stage); 101 *i = "uImageIncrement"; 102 i->appendS32(stage); 103} 104 105inline void image_increment_param_name(int stage, GrStringBuilder* i) { 106 *i = "uImageIncrement"; 107 i->appendS32(stage); 108} 109 110inline void tex_domain_name(int stage, GrStringBuilder* s) { 111 *s = "uTexDom"; 112 s->appendS32(stage); 113} 114} 115 116GrGLProgram::GrGLProgram() { 117} 118 119GrGLProgram::~GrGLProgram() { 120} 121 122void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff, 123 GrBlendCoeff* dstCoeff) const { 124 switch (fProgramDesc.fDualSrcOutput) { 125 case ProgramDesc::kNone_DualSrcOutput: 126 break; 127 // the prog will write a coverage value to the secondary 128 // output and the dst is blended by one minus that value. 129 case ProgramDesc::kCoverage_DualSrcOutput: 130 case ProgramDesc::kCoverageISA_DualSrcOutput: 131 case ProgramDesc::kCoverageISC_DualSrcOutput: 132 *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_BlendCoeff; 133 break; 134 default: 135 GrCrash("Unexpected dual source blend output"); 136 break; 137 } 138} 139 140// assigns modulation of two vars to an output var 141// vars can be vec4s or floats (or one of each) 142// result is always vec4 143// if either var is "" then assign to the other var 144// if both are "" then assign all ones 145static inline void modulate_helper(const char* outputVar, 146 const char* var0, 147 const char* var1, 148 GrStringBuilder* code) { 149 GrAssert(NULL != outputVar); 150 GrAssert(NULL != var0); 151 GrAssert(NULL != var1); 152 GrAssert(NULL != code); 153 154 bool has0 = '\0' != *var0; 155 bool has1 = '\0' != *var1; 156 157 if (!has0 && !has1) { 158 code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4)); 159 } else if (!has0) { 160 code->appendf("\t%s = vec4(%s);\n", outputVar, var1); 161 } else if (!has1) { 162 code->appendf("\t%s = vec4(%s);\n", outputVar, var0); 163 } else { 164 code->appendf("\t%s = vec4(%s * %s);\n", outputVar, var0, var1); 165 } 166} 167 168// assigns addition of two vars to an output var 169// vars can be vec4s or floats (or one of each) 170// result is always vec4 171// if either var is "" then assign to the other var 172// if both are "" then assign all zeros 173static inline void add_helper(const char* outputVar, 174 const char* var0, 175 const char* var1, 176 GrStringBuilder* code) { 177 GrAssert(NULL != outputVar); 178 GrAssert(NULL != var0); 179 GrAssert(NULL != var1); 180 GrAssert(NULL != code); 181 182 bool has0 = '\0' != *var0; 183 bool has1 = '\0' != *var1; 184 185 if (!has0 && !has1) { 186 code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4)); 187 } else if (!has0) { 188 code->appendf("\t%s = vec4(%s);\n", outputVar, var1); 189 } else if (!has1) { 190 code->appendf("\t%s = vec4(%s);\n", outputVar, var0); 191 } else { 192 code->appendf("\t%s = vec4(%s + %s);\n", outputVar, var0, var1); 193 } 194} 195 196// given two blend coeffecients determine whether the src 197// and/or dst computation can be omitted. 198static inline void needBlendInputs(SkXfermode::Coeff srcCoeff, 199 SkXfermode::Coeff dstCoeff, 200 bool* needSrcValue, 201 bool* needDstValue) { 202 if (SkXfermode::kZero_Coeff == srcCoeff) { 203 switch (dstCoeff) { 204 // these all read the src 205 case SkXfermode::kSC_Coeff: 206 case SkXfermode::kISC_Coeff: 207 case SkXfermode::kSA_Coeff: 208 case SkXfermode::kISA_Coeff: 209 *needSrcValue = true; 210 break; 211 default: 212 *needSrcValue = false; 213 break; 214 } 215 } else { 216 *needSrcValue = true; 217 } 218 if (SkXfermode::kZero_Coeff == dstCoeff) { 219 switch (srcCoeff) { 220 // these all read the dst 221 case SkXfermode::kDC_Coeff: 222 case SkXfermode::kIDC_Coeff: 223 case SkXfermode::kDA_Coeff: 224 case SkXfermode::kIDA_Coeff: 225 *needDstValue = true; 226 break; 227 default: 228 *needDstValue = false; 229 break; 230 } 231 } else { 232 *needDstValue = true; 233 } 234} 235 236/** 237 * Create a blend_coeff * value string to be used in shader code. Sets empty 238 * string if result is trivially zero. 239 */ 240static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff, 241 const char* src, const char* dst, 242 const char* value) { 243 switch (coeff) { 244 case SkXfermode::kZero_Coeff: /** 0 */ 245 *str = ""; 246 break; 247 case SkXfermode::kOne_Coeff: /** 1 */ 248 *str = value; 249 break; 250 case SkXfermode::kSC_Coeff: 251 str->printf("(%s * %s)", src, value); 252 break; 253 case SkXfermode::kISC_Coeff: 254 str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value); 255 break; 256 case SkXfermode::kDC_Coeff: 257 str->printf("(%s * %s)", dst, value); 258 break; 259 case SkXfermode::kIDC_Coeff: 260 str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value); 261 break; 262 case SkXfermode::kSA_Coeff: /** src alpha */ 263 str->printf("(%s.a * %s)", src, value); 264 break; 265 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */ 266 str->printf("((1.0 - %s.a) * %s)", src, value); 267 break; 268 case SkXfermode::kDA_Coeff: /** dst alpha */ 269 str->printf("(%s.a * %s)", dst, value); 270 break; 271 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */ 272 str->printf("((1.0 - %s.a) * %s)", dst, value); 273 break; 274 default: 275 GrCrash("Unexpected xfer coeff."); 276 break; 277 } 278} 279/** 280 * Adds a line to the fragment shader code which modifies the color by 281 * the specified color filter. 282 */ 283static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar, 284 SkXfermode::Coeff uniformCoeff, 285 SkXfermode::Coeff colorCoeff, 286 const char* inColor) { 287 GrStringBuilder colorStr, constStr; 288 blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME, 289 inColor, inColor); 290 blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME, 291 inColor, COL_FILTER_UNI_NAME); 292 293 add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode); 294} 295/** 296 * Adds code to the fragment shader code which modifies the color by 297 * the specified color matrix. 298 */ 299static void addColorMatrix(GrStringBuilder* fsCode, const char * outputVar, 300 const char* inColor) { 301 fsCode->appendf("\t%s = %s * vec4(%s.rgb / %s.a, %s.a) + %s;\n", outputVar, COL_MATRIX_UNI_NAME, inColor, inColor, inColor, COL_MATRIX_VEC_UNI_NAME); 302 fsCode->appendf("\t%s.rgb *= %s.a;\n", outputVar, outputVar); 303} 304 305void GrGLProgram::genEdgeCoverage(const GrGLContextInfo& gl, 306 GrVertexLayout layout, 307 CachedData* programData, 308 GrStringBuilder* coverageVar, 309 GrGLShaderBuilder* segments) const { 310 if (layout & GrDrawTarget::kEdge_VertexLayoutBit) { 311 const char *vsName, *fsName; 312 segments->addVarying(kVec4f_GrSLType, "Edge", &vsName, &fsName); 313 segments->fVSAttrs.push_back().set(kVec4f_GrSLType, 314 GrGLShaderVar::kAttribute_TypeModifier, EDGE_ATTR_NAME); 315 segments->fVSCode.appendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName); 316 switch (fProgramDesc.fVertexEdgeType) { 317 case GrDrawState::kHairLine_EdgeType: 318 segments->fFSCode.appendf("\tfloat edgeAlpha = abs(dot(vec3(gl_FragCoord.xy,1), %s.xyz));\n", fsName); 319 segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n"); 320 break; 321 case GrDrawState::kQuad_EdgeType: 322 segments->fFSCode.append("\tfloat edgeAlpha;\n"); 323 // keep the derivative instructions outside the conditional 324 segments->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName); 325 segments->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName); 326 segments->fFSCode.appendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName); 327 // today we know z and w are in device space. We could use derivatives 328 segments->fFSCode.appendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName); 329 segments->fFSCode.append ("\t} else {\n"); 330 segments->fFSCode.appendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n" 331 "\t\t 2.0*%s.x*duvdy.x - duvdy.y);\n", 332 fsName, fsName); 333 segments->fFSCode.appendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName); 334 segments->fFSCode.append("\t\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n" 335 "\t}\n"); 336 if (kES2_GrGLBinding == gl.binding()) { 337 segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n"); 338 } 339 break; 340 case GrDrawState::kHairQuad_EdgeType: 341 segments->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName); 342 segments->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName); 343 segments->fFSCode.appendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n" 344 "\t 2.0*%s.x*duvdy.x - duvdy.y);\n", 345 fsName, fsName); 346 segments->fFSCode.appendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName); 347 segments->fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n"); 348 segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n"); 349 if (kES2_GrGLBinding == gl.binding()) { 350 segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n"); 351 } 352 break; 353 case GrDrawState::kCircle_EdgeType: 354 segments->fFSCode.append("\tfloat edgeAlpha;\n"); 355 segments->fFSCode.appendf("\tfloat d = distance(gl_FragCoord.xy, %s.xy);\n", fsName); 356 segments->fFSCode.appendf("\tfloat outerAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName); 357 segments->fFSCode.appendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName); 358 segments->fFSCode.append("\tedgeAlpha = outerAlpha * innerAlpha;\n"); 359 break; 360 default: 361 GrCrash("Unknown Edge Type!"); 362 break; 363 } 364 *coverageVar = "edgeAlpha"; 365 } else { 366 coverageVar->reset(); 367 } 368} 369 370namespace { 371 372void genInputColor(GrGLProgram::ProgramDesc::ColorInput colorInput, 373 GrGLProgram::CachedData* programData, 374 GrGLShaderBuilder* segments, 375 GrStringBuilder* inColor) { 376 switch (colorInput) { 377 case GrGLProgram::ProgramDesc::kAttribute_ColorInput: { 378 segments->fVSAttrs.push_back().set(kVec4f_GrSLType, 379 GrGLShaderVar::kAttribute_TypeModifier, 380 COL_ATTR_NAME); 381 const char *vsName, *fsName; 382 segments->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName); 383 segments->fVSCode.appendf("\t%s = " COL_ATTR_NAME ";\n", vsName); 384 *inColor = fsName; 385 } break; 386 case GrGLProgram::ProgramDesc::kUniform_ColorInput: 387 segments->addUniform(GrGLShaderBuilder::kFragment_VariableLifetime, 388 kVec4f_GrSLType, COL_UNI_NAME); 389 programData->fUniLocations.fColorUni = kUseUniform; 390 *inColor = COL_UNI_NAME; 391 break; 392 case GrGLProgram::ProgramDesc::kTransBlack_ColorInput: 393 GrAssert(!"needComputedColor should be false."); 394 break; 395 case GrGLProgram::ProgramDesc::kSolidWhite_ColorInput: 396 break; 397 default: 398 GrCrash("Unknown color type."); 399 break; 400 } 401} 402 403void genAttributeCoverage(GrGLShaderBuilder* segments, 404 GrStringBuilder* inOutCoverage) { 405 segments->fVSAttrs.push_back().set(kVec4f_GrSLType, 406 GrGLShaderVar::kAttribute_TypeModifier, 407 COV_ATTR_NAME); 408 const char *vsName, *fsName; 409 segments->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName); 410 segments->fVSCode.appendf("\t%s = " COV_ATTR_NAME ";\n", vsName); 411 if (inOutCoverage->size()) { 412 segments->fFSCode.appendf("\tvec4 attrCoverage = %s * %s;\n", 413 fsName, inOutCoverage->c_str()); 414 *inOutCoverage = "attrCoverage"; 415 } else { 416 *inOutCoverage = fsName; 417 } 418} 419 420void genUniformCoverage(GrGLShaderBuilder* segments, 421 GrGLProgram::CachedData* programData, 422 GrStringBuilder* inOutCoverage) { 423 segments->addUniform(GrGLShaderBuilder::kFragment_VariableLifetime, 424 kVec4f_GrSLType, COV_UNI_NAME); 425 programData->fUniLocations.fCoverageUni = kUseUniform; 426 if (inOutCoverage->size()) { 427 segments->fFSCode.appendf("\tvec4 uniCoverage = %s * %s;\n", 428 COV_UNI_NAME, inOutCoverage->c_str()); 429 *inOutCoverage = "uniCoverage"; 430 } else { 431 *inOutCoverage = COV_UNI_NAME; 432 } 433} 434 435} 436 437void GrGLProgram::genGeometryShader(const GrGLContextInfo& gl, 438 GrGLShaderBuilder* segments) const { 439#if GR_GL_EXPERIMENTAL_GS 440 if (fProgramDesc.fExperimentalGS) { 441 GrAssert(gl.glslGeneration() >= k150_GrGLSLGeneration); 442 segments->fGSHeader.append("layout(triangles) in;\n" 443 "layout(triangle_strip, max_vertices = 6) out;\n"); 444 segments->fGSCode.append("void main() {\n" 445 "\tfor (int i = 0; i < 3; ++i) {\n" 446 "\t\tgl_Position = gl_in[i].gl_Position;\n"); 447 if (this->fProgramDesc.fEmitsPointSize) { 448 segments->fGSCode.append("\t\tgl_PointSize = 1.0;\n"); 449 } 450 GrAssert(segments->fGSInputs.count() == segments->fGSOutputs.count()); 451 int count = segments->fGSInputs.count(); 452 for (int i = 0; i < count; ++i) { 453 segments->fGSCode.appendf("\t\t%s = %s[i];\n", 454 segments->fGSOutputs[i].getName().c_str(), 455 segments->fGSInputs[i].getName().c_str()); 456 } 457 segments->fGSCode.append("\t\tEmitVertex();\n" 458 "\t}\n" 459 "\tEndPrimitive();\n" 460 "}\n"); 461 } 462#endif 463} 464 465const char* GrGLProgram::adjustInColor(const GrStringBuilder& inColor) const { 466 if (inColor.size()) { 467 return inColor.c_str(); 468 } else { 469 if (ProgramDesc::kSolidWhite_ColorInput == fProgramDesc.fColorInput) { 470 return all_ones_vec(4); 471 } else { 472 return all_zeros_vec(4); 473 } 474 } 475} 476 477// If this destructor is in the header file, we must include GrGLProgramStage 478// instead of just forward-declaring it. 479GrGLProgram::CachedData::~CachedData() { 480 for (int i = 0; i < GrDrawState::kNumStages; ++i) { 481 delete fCustomStage[i]; 482 } 483} 484 485 486bool GrGLProgram::genProgram(const GrGLContextInfo& gl, 487 GrCustomStage** customStages, 488 GrGLProgram::CachedData* programData) const { 489 GrGLShaderBuilder segments; 490 const uint32_t& layout = fProgramDesc.fVertexLayout; 491 492 programData->fUniLocations.reset(); 493 494#if GR_GL_EXPERIMENTAL_GS 495 segments.fUsesGS = fProgramDesc.fExperimentalGS; 496#endif 497 498 SkXfermode::Coeff colorCoeff, uniformCoeff; 499 bool applyColorMatrix = SkToBool(fProgramDesc.fColorMatrixEnabled); 500 // The rest of transfer mode color filters have not been implemented 501 if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) { 502 GR_DEBUGCODE(bool success =) 503 SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode> 504 (fProgramDesc.fColorFilterXfermode), 505 &uniformCoeff, &colorCoeff); 506 GR_DEBUGASSERT(success); 507 } else { 508 colorCoeff = SkXfermode::kOne_Coeff; 509 uniformCoeff = SkXfermode::kZero_Coeff; 510 } 511 512 // no need to do the color filter / matrix at all if coverage is 0. The 513 // output color is scaled by the coverage. All the dual source outputs are 514 // scaled by the coverage as well. 515 if (ProgramDesc::kTransBlack_ColorInput == fProgramDesc.fCoverageInput) { 516 colorCoeff = SkXfermode::kZero_Coeff; 517 uniformCoeff = SkXfermode::kZero_Coeff; 518 applyColorMatrix = false; 519 } 520 521 // If we know the final color is going to be all zeros then we can 522 // simplify the color filter coeffecients. needComputedColor will then 523 // come out false below. 524 if (ProgramDesc::kTransBlack_ColorInput == fProgramDesc.fColorInput) { 525 colorCoeff = SkXfermode::kZero_Coeff; 526 if (SkXfermode::kDC_Coeff == uniformCoeff || 527 SkXfermode::kDA_Coeff == uniformCoeff) { 528 uniformCoeff = SkXfermode::kZero_Coeff; 529 } else if (SkXfermode::kIDC_Coeff == uniformCoeff || 530 SkXfermode::kIDA_Coeff == uniformCoeff) { 531 uniformCoeff = SkXfermode::kOne_Coeff; 532 } 533 } 534 535 bool needColorFilterUniform; 536 bool needComputedColor; 537 needBlendInputs(uniformCoeff, colorCoeff, 538 &needColorFilterUniform, &needComputedColor); 539 540 // the dual source output has no canonical var name, have to 541 // declare an output, which is incompatible with gl_FragColor/gl_FragData. 542 bool dualSourceOutputWritten = false; 543 segments.fHeader.printf(GrGetGLSLVersionDecl(gl.binding(), 544 gl.glslGeneration())); 545 546 GrGLShaderVar colorOutput; 547 bool isColorDeclared = GrGLSLSetupFSColorOuput(gl.glslGeneration(), 548 declared_color_output_name(), 549 &colorOutput); 550 if (isColorDeclared) { 551 segments.fFSOutputs.push_back(colorOutput); 552 } 553 554 segments.addUniform(GrGLShaderBuilder::kVertex_VariableLifetime, 555 kMat33f_GrSLType, VIEW_MATRIX_NAME); 556 programData->fUniLocations.fViewMatrixUni = kUseUniform; 557 558 segments.fVSAttrs.push_back().set(kVec2f_GrSLType, 559 GrGLShaderVar::kAttribute_TypeModifier, POS_ATTR_NAME); 560 561 segments.fVSCode.append( 562 "void main() {\n" 563 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n" 564 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n"); 565 566 // incoming color to current stage being processed. 567 GrStringBuilder inColor; 568 569 if (needComputedColor) { 570 genInputColor((ProgramDesc::ColorInput) fProgramDesc.fColorInput, 571 programData, &segments, &inColor); 572 } 573 574 // we output point size in the GS if present 575 if (fProgramDesc.fEmitsPointSize && !segments.fUsesGS){ 576 segments.fVSCode.append("\tgl_PointSize = 1.0;\n"); 577 } 578 579 segments.fFSCode.append("void main() {\n"); 580 581 // add texture coordinates that are used to the list of vertex attr decls 582 GrStringBuilder texCoordAttrs[GrDrawState::kMaxTexCoords]; 583 for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { 584 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) { 585 tex_attr_name(t, texCoordAttrs + t); 586 segments.fVSAttrs.push_back().set(kVec2f_GrSLType, 587 GrGLShaderVar::kAttribute_TypeModifier, 588 texCoordAttrs[t].c_str()); 589 } 590 } 591 592 /////////////////////////////////////////////////////////////////////////// 593 // We need to convert generic effect representations to GL-specific 594 // backends so they can be accesseed in genStageCode() and in subsequent, 595 // uses of programData, but it's safest to do so below when we're *sure* 596 // we need them. 597 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 598 programData->fCustomStage[s] = NULL; 599 } 600 601 /////////////////////////////////////////////////////////////////////////// 602 // compute the final color 603 604 // if we have color stages string them together, feeding the output color 605 // of each to the next and generating code for each stage. 606 if (needComputedColor) { 607 GrStringBuilder outColor; 608 for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) { 609 if (fProgramDesc.fStages[s].isEnabled()) { 610 // create var to hold stage result 611 outColor = "color"; 612 outColor.appendS32(s); 613 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str()); 614 615 const char* inCoords; 616 // figure out what our input coords are 617 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & 618 layout) { 619 inCoords = POS_ATTR_NAME; 620 } else { 621 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout); 622 // we better have input tex coordinates if stage is enabled. 623 GrAssert(tcIdx >= 0); 624 GrAssert(texCoordAttrs[tcIdx].size()); 625 inCoords = texCoordAttrs[tcIdx].c_str(); 626 } 627 628 if (NULL != customStages[s]) { 629 const GrProgramStageFactory& factory = 630 customStages[s]->getFactory(); 631 programData->fCustomStage[s] = 632 factory.createGLInstance(customStages[s]); 633 } 634 this->genStageCode(gl, 635 s, 636 fProgramDesc.fStages[s], 637 inColor.size() ? inColor.c_str() : NULL, 638 outColor.c_str(), 639 inCoords, 640 &segments, 641 &programData->fUniLocations.fStages[s], 642 programData->fCustomStage[s]); 643 inColor = outColor; 644 } 645 } 646 } 647 648 // if have all ones or zeros for the "dst" input to the color filter then we 649 // may be able to make additional optimizations. 650 if (needColorFilterUniform && needComputedColor && !inColor.size()) { 651 GrAssert(ProgramDesc::kSolidWhite_ColorInput == fProgramDesc.fColorInput); 652 bool uniformCoeffIsZero = SkXfermode::kIDC_Coeff == uniformCoeff || 653 SkXfermode::kIDA_Coeff == uniformCoeff; 654 if (uniformCoeffIsZero) { 655 uniformCoeff = SkXfermode::kZero_Coeff; 656 bool bogus; 657 needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff, 658 &needColorFilterUniform, &bogus); 659 } 660 } 661 if (needColorFilterUniform) { 662 segments.addUniform(GrGLShaderBuilder::kFragment_VariableLifetime, 663 kVec4f_GrSLType, COL_FILTER_UNI_NAME); 664 programData->fUniLocations.fColorFilterUni = kUseUniform; 665 } 666 bool wroteFragColorZero = false; 667 if (SkXfermode::kZero_Coeff == uniformCoeff && 668 SkXfermode::kZero_Coeff == colorCoeff && 669 !applyColorMatrix) { 670 segments.fFSCode.appendf("\t%s = %s;\n", 671 colorOutput.getName().c_str(), 672 all_zeros_vec(4)); 673 wroteFragColorZero = true; 674 } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) { 675 segments.fFSCode.append("\tvec4 filteredColor;\n"); 676 const char* color = adjustInColor(inColor); 677 addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff, 678 colorCoeff, color); 679 inColor = "filteredColor"; 680 } 681 if (applyColorMatrix) { 682 segments.addUniform(GrGLShaderBuilder::kFragment_VariableLifetime, 683 kMat44f_GrSLType, COL_MATRIX_UNI_NAME); 684 segments.addUniform(GrGLShaderBuilder::kFragment_VariableLifetime, 685 kVec4f_GrSLType, COL_MATRIX_VEC_UNI_NAME); 686 programData->fUniLocations.fColorMatrixUni = kUseUniform; 687 programData->fUniLocations.fColorMatrixVecUni = kUseUniform; 688 segments.fFSCode.append("\tvec4 matrixedColor;\n"); 689 const char* color = adjustInColor(inColor); 690 addColorMatrix(&segments.fFSCode, "matrixedColor", color); 691 inColor = "matrixedColor"; 692 } 693 694 /////////////////////////////////////////////////////////////////////////// 695 // compute the partial coverage (coverage stages and edge aa) 696 697 GrStringBuilder inCoverage; 698 bool coverageIsZero = ProgramDesc::kTransBlack_ColorInput == 699 fProgramDesc.fCoverageInput; 700 // we don't need to compute coverage at all if we know the final shader 701 // output will be zero and we don't have a dual src blend output. 702 if (!wroteFragColorZero || 703 ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) { 704 705 if (!coverageIsZero) { 706 this->genEdgeCoverage(gl, 707 layout, 708 programData, 709 &inCoverage, 710 &segments); 711 712 switch (fProgramDesc.fCoverageInput) { 713 case ProgramDesc::kSolidWhite_ColorInput: 714 // empty string implies solid white 715 break; 716 case ProgramDesc::kAttribute_ColorInput: 717 genAttributeCoverage(&segments, &inCoverage); 718 break; 719 case ProgramDesc::kUniform_ColorInput: 720 genUniformCoverage(&segments, programData, &inCoverage); 721 break; 722 default: 723 GrCrash("Unexpected input coverage."); 724 } 725 726 GrStringBuilder outCoverage; 727 const int& startStage = fProgramDesc.fFirstCoverageStage; 728 for (int s = startStage; s < GrDrawState::kNumStages; ++s) { 729 if (fProgramDesc.fStages[s].isEnabled()) { 730 // create var to hold stage output 731 outCoverage = "coverage"; 732 outCoverage.appendS32(s); 733 segments.fFSCode.appendf("\tvec4 %s;\n", 734 outCoverage.c_str()); 735 736 const char* inCoords; 737 // figure out what our input coords are 738 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & 739 layout) { 740 inCoords = POS_ATTR_NAME; 741 } else { 742 int tcIdx = 743 GrDrawTarget::VertexTexCoordsForStage(s, layout); 744 // we better have input tex coordinates if stage is 745 // enabled. 746 GrAssert(tcIdx >= 0); 747 GrAssert(texCoordAttrs[tcIdx].size()); 748 inCoords = texCoordAttrs[tcIdx].c_str(); 749 } 750 751 if (NULL != customStages[s]) { 752 const GrProgramStageFactory& factory = 753 customStages[s]->getFactory(); 754 programData->fCustomStage[s] = 755 factory.createGLInstance(customStages[s]); 756 } 757 this->genStageCode(gl, s, 758 fProgramDesc.fStages[s], 759 inCoverage.size() ? inCoverage.c_str() : NULL, 760 outCoverage.c_str(), 761 inCoords, 762 &segments, 763 &programData->fUniLocations.fStages[s], 764 programData->fCustomStage[s]); 765 inCoverage = outCoverage; 766 } 767 } 768 } 769 if (ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) { 770 segments.fFSOutputs.push_back().set(kVec4f_GrSLType, 771 GrGLShaderVar::kOut_TypeModifier, 772 dual_source_output_name()); 773 bool outputIsZero = coverageIsZero; 774 GrStringBuilder coeff; 775 if (!outputIsZero && 776 ProgramDesc::kCoverage_DualSrcOutput != 777 fProgramDesc.fDualSrcOutput && !wroteFragColorZero) { 778 if (!inColor.size()) { 779 outputIsZero = true; 780 } else { 781 if (fProgramDesc.fDualSrcOutput == 782 ProgramDesc::kCoverageISA_DualSrcOutput) { 783 coeff.printf("(1 - %s.a)", inColor.c_str()); 784 } else { 785 coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str()); 786 } 787 } 788 } 789 if (outputIsZero) { 790 segments.fFSCode.appendf("\t%s = %s;\n", 791 dual_source_output_name(), 792 all_zeros_vec(4)); 793 } else { 794 modulate_helper(dual_source_output_name(), 795 coeff.c_str(), 796 inCoverage.c_str(), 797 &segments.fFSCode); 798 } 799 dualSourceOutputWritten = true; 800 } 801 } 802 803 /////////////////////////////////////////////////////////////////////////// 804 // combine color and coverage as frag color 805 806 if (!wroteFragColorZero) { 807 if (coverageIsZero) { 808 segments.fFSCode.appendf("\t%s = %s;\n", 809 colorOutput.getName().c_str(), 810 all_zeros_vec(4)); 811 } else { 812 modulate_helper(colorOutput.getName().c_str(), 813 inColor.c_str(), 814 inCoverage.c_str(), 815 &segments.fFSCode); 816 } 817 if (ProgramDesc::kUnpremultiplied_RoundDown_OutputConfig == 818 fProgramDesc.fOutputConfig) { 819 segments.fFSCode.appendf("\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.rgb / %s.a * 255.0)/255.0, %s.a);\n", 820 colorOutput.getName().c_str(), 821 colorOutput.getName().c_str(), 822 colorOutput.getName().c_str(), 823 colorOutput.getName().c_str(), 824 colorOutput.getName().c_str()); 825 } else if (ProgramDesc::kUnpremultiplied_RoundUp_OutputConfig == 826 fProgramDesc.fOutputConfig) { 827 segments.fFSCode.appendf("\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.rgb / %s.a * 255.0)/255.0, %s.a);\n", 828 colorOutput.getName().c_str(), 829 colorOutput.getName().c_str(), 830 colorOutput.getName().c_str(), 831 colorOutput.getName().c_str(), 832 colorOutput.getName().c_str()); 833 } 834 } 835 836 segments.fVSCode.append("}\n"); 837 segments.fFSCode.append("}\n"); 838 839 /////////////////////////////////////////////////////////////////////////// 840 // insert GS 841#if GR_DEBUG 842 this->genGeometryShader(gl, &segments); 843#endif 844 845 /////////////////////////////////////////////////////////////////////////// 846 // compile and setup attribs and unis 847 848 if (!CompileShaders(gl, segments, programData)) { 849 return false; 850 } 851 852 if (!this->bindOutputsAttribsAndLinkProgram(gl, texCoordAttrs, 853 isColorDeclared, 854 dualSourceOutputWritten, 855 programData)) { 856 return false; 857 } 858 859 this->getUniformLocationsAndInitCache(gl, programData); 860 861 return true; 862} 863 864namespace { 865 866inline void expand_decls(const VarArray& vars, 867 const GrGLContextInfo& gl, 868 GrStringBuilder* string) { 869 const int count = vars.count(); 870 for (int i = 0; i < count; ++i) { 871 vars[i].appendDecl(gl, string); 872 } 873} 874 875inline void print_shader(int stringCnt, 876 const char** strings, 877 int* stringLengths) { 878 for (int i = 0; i < stringCnt; ++i) { 879 if (NULL == stringLengths || stringLengths[i] < 0) { 880 GrPrintf(strings[i]); 881 } else { 882 GrPrintf("%.*s", stringLengths[i], strings[i]); 883 } 884 } 885} 886 887typedef SkTArray<const char*, true> StrArray; 888#define PREALLOC_STR_ARRAY(N) SkSTArray<(N), const char*, true> 889 890typedef SkTArray<int, true> LengthArray; 891#define PREALLOC_LENGTH_ARRAY(N) SkSTArray<(N), int, true> 892 893// these shouldn't relocate 894typedef GrTAllocator<GrStringBuilder> TempArray; 895#define PREALLOC_TEMP_ARRAY(N) GrSTAllocator<(N), GrStringBuilder> 896 897inline void append_string(const GrStringBuilder& str, 898 StrArray* strings, 899 LengthArray* lengths) { 900 int length = (int) str.size(); 901 if (length) { 902 strings->push_back(str.c_str()); 903 lengths->push_back(length); 904 } 905 GrAssert(strings->count() == lengths->count()); 906} 907 908inline void append_decls(const VarArray& vars, 909 const GrGLContextInfo& gl, 910 StrArray* strings, 911 LengthArray* lengths, 912 TempArray* temp) { 913 expand_decls(vars, gl, &temp->push_back()); 914 append_string(temp->back(), strings, lengths); 915} 916 917} 918 919bool GrGLProgram::CompileShaders(const GrGLContextInfo& gl, 920 const GrGLShaderBuilder& segments, 921 CachedData* programData) { 922 enum { kPreAllocStringCnt = 8 }; 923 924 PREALLOC_STR_ARRAY(kPreAllocStringCnt) strs; 925 PREALLOC_LENGTH_ARRAY(kPreAllocStringCnt) lengths; 926 PREALLOC_TEMP_ARRAY(kPreAllocStringCnt) temps; 927 928 GrStringBuilder unis; 929 GrStringBuilder inputs; 930 GrStringBuilder outputs; 931 932 append_string(segments.fHeader, &strs, &lengths); 933 append_decls(segments.fVSUnis, gl, &strs, &lengths, &temps); 934 append_decls(segments.fVSAttrs, gl, &strs, &lengths, &temps); 935 append_decls(segments.fVSOutputs, gl, &strs, &lengths, &temps); 936 append_string(segments.fVSCode, &strs, &lengths); 937 938#if PRINT_SHADERS 939 print_shader(strs.count(), &strs[0], &lengths[0]); 940 GrPrintf("\n"); 941#endif 942 943 programData->fVShaderID = 944 CompileShader(gl, GR_GL_VERTEX_SHADER, strs.count(), 945 &strs[0], &lengths[0]); 946 947 if (!programData->fVShaderID) { 948 return false; 949 } 950 if (segments.fUsesGS) { 951 strs.reset(); 952 lengths.reset(); 953 temps.reset(); 954 append_string(segments.fHeader, &strs, &lengths); 955 append_string(segments.fGSHeader, &strs, &lengths); 956 append_decls(segments.fGSInputs, gl, &strs, &lengths, &temps); 957 append_decls(segments.fGSOutputs, gl, &strs, &lengths, &temps); 958 append_string(segments.fGSCode, &strs, &lengths); 959#if PRINT_SHADERS 960 print_shader(strs.count(), &strs[0], &lengths[0]); 961 GrPrintf("\n"); 962#endif 963 programData->fGShaderID = 964 CompileShader(gl, GR_GL_GEOMETRY_SHADER, strs.count(), 965 &strs[0], &lengths[0]); 966 } else { 967 programData->fGShaderID = 0; 968 } 969 970 strs.reset(); 971 lengths.reset(); 972 temps.reset(); 973 974 append_string(segments.fHeader, &strs, &lengths); 975 GrStringBuilder precisionStr(GrGetGLSLShaderPrecisionDecl(gl.binding())); 976 append_string(precisionStr, &strs, &lengths); 977 append_decls(segments.fFSUnis, gl, &strs, &lengths, &temps); 978 append_decls(segments.fFSInputs, gl, &strs, &lengths, &temps); 979 // We shouldn't have declared outputs on 1.10 980 GrAssert(k110_GrGLSLGeneration != gl.glslGeneration() || 981 segments.fFSOutputs.empty()); 982 append_decls(segments.fFSOutputs, gl, &strs, &lengths, &temps); 983 append_string(segments.fFSFunctions, &strs, &lengths); 984 append_string(segments.fFSCode, &strs, &lengths); 985 986#if PRINT_SHADERS 987 print_shader(strs.count(), &strs[0], &lengths[0]); 988 GrPrintf("\n"); 989#endif 990 991 programData->fFShaderID = 992 CompileShader(gl, GR_GL_FRAGMENT_SHADER, strs.count(), 993 &strs[0], &lengths[0]); 994 995 if (!programData->fFShaderID) { 996 return false; 997 } 998 999 return true; 1000} 1001 1002#define GL_CALL(X) GR_GL_CALL(gl.interface(), X) 1003#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gl.interface(), R, X) 1004 1005GrGLuint GrGLProgram::CompileShader(const GrGLContextInfo& gl, 1006 GrGLenum type, 1007 int stringCnt, 1008 const char** strings, 1009 int* stringLengths) { 1010 SK_TRACE_EVENT1("GrGLProgram::CompileShader", 1011 "stringCount", SkStringPrintf("%i", stringCnt).c_str()); 1012 1013 GrGLuint shader; 1014 GL_CALL_RET(shader, CreateShader(type)); 1015 if (0 == shader) { 1016 return 0; 1017 } 1018 1019 GrGLint compiled = GR_GL_INIT_ZERO; 1020 GL_CALL(ShaderSource(shader, stringCnt, strings, stringLengths)); 1021 GL_CALL(CompileShader(shader)); 1022 GL_CALL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled)); 1023 1024 if (!compiled) { 1025 GrGLint infoLen = GR_GL_INIT_ZERO; 1026 GL_CALL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen)); 1027 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger 1028 if (infoLen > 0) { 1029 // retrieve length even though we don't need it to workaround 1030 // bug in chrome cmd buffer param validation. 1031 GrGLsizei length = GR_GL_INIT_ZERO; 1032 GL_CALL(GetShaderInfoLog(shader, infoLen+1, 1033 &length, (char*)log.get())); 1034 print_shader(stringCnt, strings, stringLengths); 1035 GrPrintf("\n%s", log.get()); 1036 } 1037 GrAssert(!"Shader compilation failed!"); 1038 GL_CALL(DeleteShader(shader)); 1039 return 0; 1040 } 1041 return shader; 1042} 1043 1044bool GrGLProgram::bindOutputsAttribsAndLinkProgram( 1045 const GrGLContextInfo& gl, 1046 GrStringBuilder texCoordAttrNames[], 1047 bool bindColorOut, 1048 bool bindDualSrcOut, 1049 CachedData* programData) const { 1050 GL_CALL_RET(programData->fProgramID, CreateProgram()); 1051 if (!programData->fProgramID) { 1052 return false; 1053 } 1054 const GrGLint& progID = programData->fProgramID; 1055 1056 GL_CALL(AttachShader(progID, programData->fVShaderID)); 1057 if (programData->fGShaderID) { 1058 GL_CALL(AttachShader(progID, programData->fGShaderID)); 1059 } 1060 GL_CALL(AttachShader(progID, programData->fFShaderID)); 1061 1062 if (bindColorOut) { 1063 GL_CALL(BindFragDataLocation(programData->fProgramID, 1064 0, declared_color_output_name())); 1065 } 1066 if (bindDualSrcOut) { 1067 GL_CALL(BindFragDataLocationIndexed(programData->fProgramID, 1068 0, 1, dual_source_output_name())); 1069 } 1070 1071 // Bind the attrib locations to same values for all shaders 1072 GL_CALL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME)); 1073 for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { 1074 if (texCoordAttrNames[t].size()) { 1075 GL_CALL(BindAttribLocation(progID, 1076 TexCoordAttributeIdx(t), 1077 texCoordAttrNames[t].c_str())); 1078 } 1079 } 1080 1081 GL_CALL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME)); 1082 GL_CALL(BindAttribLocation(progID, CoverageAttributeIdx(), COV_ATTR_NAME)); 1083 GL_CALL(BindAttribLocation(progID, EdgeAttributeIdx(), EDGE_ATTR_NAME)); 1084 1085 GL_CALL(LinkProgram(progID)); 1086 1087 GrGLint linked = GR_GL_INIT_ZERO; 1088 GL_CALL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked)); 1089 if (!linked) { 1090 GrGLint infoLen = GR_GL_INIT_ZERO; 1091 GL_CALL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen)); 1092 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger 1093 if (infoLen > 0) { 1094 // retrieve length even though we don't need it to workaround 1095 // bug in chrome cmd buffer param validation. 1096 GrGLsizei length = GR_GL_INIT_ZERO; 1097 GL_CALL(GetProgramInfoLog(progID, 1098 infoLen+1, 1099 &length, 1100 (char*)log.get())); 1101 GrPrintf((char*)log.get()); 1102 } 1103 GrAssert(!"Error linking program"); 1104 GL_CALL(DeleteProgram(progID)); 1105 programData->fProgramID = 0; 1106 return false; 1107 } 1108 return true; 1109} 1110 1111void GrGLProgram::getUniformLocationsAndInitCache(const GrGLContextInfo& gl, 1112 CachedData* programData) const { 1113 const GrGLint& progID = programData->fProgramID; 1114 1115 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) { 1116 GL_CALL_RET(programData->fUniLocations.fViewMatrixUni, 1117 GetUniformLocation(progID, VIEW_MATRIX_NAME)); 1118 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni); 1119 } 1120 if (kUseUniform == programData->fUniLocations.fColorUni) { 1121 GL_CALL_RET(programData->fUniLocations.fColorUni, 1122 GetUniformLocation(progID, COL_UNI_NAME)); 1123 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni); 1124 } 1125 if (kUseUniform == programData->fUniLocations.fColorFilterUni) { 1126 GL_CALL_RET(programData->fUniLocations.fColorFilterUni, 1127 GetUniformLocation(progID, COL_FILTER_UNI_NAME)); 1128 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni); 1129 } 1130 1131 if (kUseUniform == programData->fUniLocations.fColorMatrixUni) { 1132 GL_CALL_RET(programData->fUniLocations.fColorMatrixUni, 1133 GetUniformLocation(progID, COL_MATRIX_UNI_NAME)); 1134 } 1135 1136 if (kUseUniform == programData->fUniLocations.fColorMatrixVecUni) { 1137 GL_CALL_RET(programData->fUniLocations.fColorMatrixVecUni, 1138 GetUniformLocation(progID, COL_MATRIX_VEC_UNI_NAME)); 1139 } 1140 if (kUseUniform == programData->fUniLocations.fCoverageUni) { 1141 GL_CALL_RET(programData->fUniLocations.fCoverageUni, 1142 GetUniformLocation(progID, COV_UNI_NAME)); 1143 GrAssert(kUnusedUniform != programData->fUniLocations.fCoverageUni); 1144 } 1145 1146 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 1147 StageUniLocations& locations = programData->fUniLocations.fStages[s]; 1148 if (fProgramDesc.fStages[s].isEnabled()) { 1149 if (kUseUniform == locations.fTextureMatrixUni) { 1150 GrStringBuilder texMName; 1151 tex_matrix_name(s, &texMName); 1152 GL_CALL_RET(locations.fTextureMatrixUni, 1153 GetUniformLocation(progID, texMName.c_str())); 1154 GrAssert(kUnusedUniform != locations.fTextureMatrixUni); 1155 } 1156 1157 if (kUseUniform == locations.fSamplerUni) { 1158 GrStringBuilder samplerName; 1159 sampler_name(s, &samplerName); 1160 GL_CALL_RET(locations.fSamplerUni, 1161 GetUniformLocation(progID,samplerName.c_str())); 1162 GrAssert(kUnusedUniform != locations.fSamplerUni); 1163 } 1164 1165 if (kUseUniform == locations.fNormalizedTexelSizeUni) { 1166 GrStringBuilder texelSizeName; 1167 normalized_texel_size_name(s, &texelSizeName); 1168 GL_CALL_RET(locations.fNormalizedTexelSizeUni, 1169 GetUniformLocation(progID, texelSizeName.c_str())); 1170 GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni); 1171 } 1172 1173 if (kUseUniform == locations.fRadial2Uni) { 1174 GrStringBuilder radial2ParamName; 1175 radial2_param_name(s, &radial2ParamName); 1176 GL_CALL_RET(locations.fRadial2Uni, 1177 GetUniformLocation(progID, radial2ParamName.c_str())); 1178 GrAssert(kUnusedUniform != locations.fRadial2Uni); 1179 } 1180 1181 if (kUseUniform == locations.fTexDomUni) { 1182 GrStringBuilder texDomName; 1183 tex_domain_name(s, &texDomName); 1184 GL_CALL_RET(locations.fTexDomUni, 1185 GetUniformLocation(progID, texDomName.c_str())); 1186 GrAssert(kUnusedUniform != locations.fTexDomUni); 1187 } 1188 1189 GrStringBuilder kernelName, imageIncrementName; 1190 convolve_param_names(s, &kernelName, &imageIncrementName); 1191 if (kUseUniform == locations.fKernelUni) { 1192 GL_CALL_RET(locations.fKernelUni, 1193 GetUniformLocation(progID, kernelName.c_str())); 1194 GrAssert(kUnusedUniform != locations.fKernelUni); 1195 } 1196 1197 if (kUseUniform == locations.fImageIncrementUni) { 1198 GL_CALL_RET(locations.fImageIncrementUni, 1199 GetUniformLocation(progID, 1200 imageIncrementName.c_str())); 1201 GrAssert(kUnusedUniform != locations.fImageIncrementUni); 1202 } 1203 1204 if (NULL != programData->fCustomStage[s]) { 1205 programData->fCustomStage[s]-> 1206 initUniforms(gl.interface(), progID); 1207 } 1208 } 1209 } 1210 GL_CALL(UseProgram(progID)); 1211 1212 // init sampler unis and set bogus values for state tracking 1213 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 1214 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) { 1215 GL_CALL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s)); 1216 } 1217 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix(); 1218 programData->fRadial2CenterX1[s] = GR_ScalarMax; 1219 programData->fRadial2Radius0[s] = -GR_ScalarMax; 1220 programData->fTextureWidth[s] = -1; 1221 programData->fTextureHeight[s] = -1; 1222 programData->fTextureDomain[s].setEmpty(); 1223 // Must not reset fStageOverride[] here. 1224 } 1225 programData->fViewMatrix = GrMatrix::InvalidMatrix(); 1226 programData->fColor = GrColor_ILLEGAL; 1227 programData->fColorFilterColor = GrColor_ILLEGAL; 1228} 1229 1230//============================================================================ 1231// Stage code generation 1232//============================================================================ 1233 1234namespace { 1235 1236bool isRadialMapping(GrGLProgram::StageDesc::CoordMapping mapping) { 1237 return 1238 (GrGLProgram::StageDesc::kRadial2Gradient_CoordMapping == mapping || 1239 GrGLProgram::StageDesc::kRadial2GradientDegenerate_CoordMapping == mapping); 1240} 1241 1242const GrGLShaderVar* genRadialVS(int stageNum, 1243 GrGLShaderBuilder* segments, 1244 GrGLProgram::StageUniLocations* locations, 1245 const char** radial2VaryingVSName, 1246 const char** radial2VaryingFSName, 1247 const char* varyingVSName) { 1248 GrStringBuilder r2ParamsName; 1249 radial2_param_name(stageNum, &r2ParamsName); 1250 const GrGLShaderVar* radial2FSParams = 1251 &segments->addUniform(GrGLShaderBuilder::kBoth_VariableLifetime, 1252 kFloat_GrSLType, r2ParamsName.c_str(), -1, 6); 1253 locations->fRadial2Uni = kUseUniform; 1254 1255 // for radial grads without perspective we can pass the linear 1256 // part of the quadratic as a varying. 1257 if (segments->fVaryingDims == segments->fCoordDims) { 1258 GrAssert(2 == segments->fCoordDims); 1259 segments->addVarying(kFloat_GrSLType, 1260 "Radial2BCoeff", 1261 stageNum, 1262 radial2VaryingVSName, 1263 radial2VaryingFSName); 1264 1265 GrStringBuilder radial2p2; 1266 GrStringBuilder radial2p3; 1267 radial2FSParams->appendArrayAccess(2, &radial2p2); 1268 radial2FSParams->appendArrayAccess(3, &radial2p3); 1269 1270 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3]) 1271 const char* r2ParamName = radial2FSParams->getName().c_str(); 1272 segments->fVSCode.appendf("\t%s = 2.0 *(%s * %s.x - %s);\n", 1273 *radial2VaryingVSName, radial2p2.c_str(), 1274 varyingVSName, radial2p3.c_str()); 1275 } 1276 1277 return radial2FSParams; 1278} 1279 1280void genRadial2GradientCoordMapping(int stageNum, 1281 GrGLShaderBuilder* segments, 1282 const char* radial2VaryingFSName, 1283 const GrGLShaderVar* radial2Params) { 1284 GrStringBuilder cName("c"); 1285 GrStringBuilder ac4Name("ac4"); 1286 GrStringBuilder rootName("root"); 1287 1288 cName.appendS32(stageNum); 1289 ac4Name.appendS32(stageNum); 1290 rootName.appendS32(stageNum); 1291 1292 GrStringBuilder radial2p0; 1293 GrStringBuilder radial2p1; 1294 GrStringBuilder radial2p2; 1295 GrStringBuilder radial2p3; 1296 GrStringBuilder radial2p4; 1297 GrStringBuilder radial2p5; 1298 radial2Params->appendArrayAccess(0, &radial2p0); 1299 radial2Params->appendArrayAccess(1, &radial2p1); 1300 radial2Params->appendArrayAccess(2, &radial2p2); 1301 radial2Params->appendArrayAccess(3, &radial2p3); 1302 radial2Params->appendArrayAccess(4, &radial2p4); 1303 radial2Params->appendArrayAccess(5, &radial2p5); 1304 1305 // if we were able to interpolate the linear component bVar is the varying 1306 // otherwise compute it 1307 GrStringBuilder bVar; 1308 if (segments->fCoordDims == segments->fVaryingDims) { 1309 bVar = radial2VaryingFSName; 1310 GrAssert(2 == segments->fVaryingDims); 1311 } else { 1312 GrAssert(3 == segments->fVaryingDims); 1313 bVar = "b"; 1314 bVar.appendS32(stageNum); 1315 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n", 1316 bVar.c_str(), radial2p2.c_str(), 1317 segments->fSampleCoords.c_str(), radial2p3.c_str()); 1318 } 1319 1320 // c = (x^2)+(y^2) - params[4] 1321 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s;\n", 1322 cName.c_str(), segments->fSampleCoords.c_str(), 1323 segments->fSampleCoords.c_str(), 1324 radial2p4.c_str()); 1325 // ac4 = 4.0 * params[0] * c 1326 segments->fFSCode.appendf("\tfloat %s = %s * 4.0 * %s;\n", 1327 ac4Name.c_str(), radial2p0.c_str(), 1328 cName.c_str()); 1329 1330 // root = sqrt(b^2-4ac) 1331 // (abs to avoid exception due to fp precision) 1332 segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n", 1333 rootName.c_str(), bVar.c_str(), bVar.c_str(), 1334 ac4Name.c_str()); 1335 1336 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1] 1337 // y coord is 0.5 (texture is effectively 1D) 1338 segments->fSampleCoords.printf("vec2((-%s + %s * %s) * %s, 0.5)", 1339 bVar.c_str(), radial2p5.c_str(), 1340 rootName.c_str(), radial2p1.c_str()); 1341 segments->fComplexCoord = true; 1342} 1343 1344void genRadial2GradientDegenerateCoordMapping(int stageNum, 1345 GrGLShaderBuilder* segments, 1346 const char* radial2VaryingFSName, 1347 const GrGLShaderVar* radial2Params) { 1348 GrStringBuilder cName("c"); 1349 1350 cName.appendS32(stageNum); 1351 1352 GrStringBuilder radial2p2; 1353 GrStringBuilder radial2p3; 1354 GrStringBuilder radial2p4; 1355 radial2Params->appendArrayAccess(2, &radial2p2); 1356 radial2Params->appendArrayAccess(3, &radial2p3); 1357 radial2Params->appendArrayAccess(4, &radial2p4); 1358 1359 // if we were able to interpolate the linear component bVar is the varying 1360 // otherwise compute it 1361 GrStringBuilder bVar; 1362 if (segments->fCoordDims == segments->fVaryingDims) { 1363 bVar = radial2VaryingFSName; 1364 GrAssert(2 == segments->fVaryingDims); 1365 } else { 1366 GrAssert(3 == segments->fVaryingDims); 1367 bVar = "b"; 1368 bVar.appendS32(stageNum); 1369 segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n", 1370 bVar.c_str(), radial2p2.c_str(), 1371 segments->fSampleCoords.c_str(), radial2p3.c_str()); 1372 } 1373 1374 // c = (x^2)+(y^2) - params[4] 1375 segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s;\n", 1376 cName.c_str(), segments->fSampleCoords.c_str(), 1377 segments->fSampleCoords.c_str(), 1378 radial2p4.c_str()); 1379 1380 // x coord is: -c/b 1381 // y coord is 0.5 (texture is effectively 1D) 1382 segments->fSampleCoords.printf("vec2((-%s / %s), 0.5)", cName.c_str(), bVar.c_str()); 1383 segments->fComplexCoord = true; 1384} 1385 1386void gen2x2FS(int stageNum, 1387 GrGLShaderBuilder* segments, 1388 GrGLProgram::StageUniLocations* locations, 1389 const char* samplerName, 1390 const char* texelSizeName, 1391 const char* fsOutColor, 1392 GrStringBuilder& texFunc) { 1393 locations->fNormalizedTexelSizeUni = kUseUniform; 1394 if (segments->fComplexCoord) { 1395 // assign the coord to a var rather than compute 4x. 1396 GrStringBuilder coordVar("tCoord"); 1397 coordVar.appendS32(stageNum); 1398 segments->fFSCode.appendf("\t%s %s = %s;\n", 1399 float_vector_type_str(segments->fCoordDims), 1400 coordVar.c_str(), segments->fSampleCoords.c_str()); 1401 segments->fSampleCoords = coordVar; 1402 } 1403 GrAssert(2 == segments->fCoordDims); 1404 GrStringBuilder accumVar("accum"); 1405 accumVar.appendS32(stageNum); 1406 segments->fFSCode.appendf("\tvec4 %s = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str()); 1407 segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str()); 1408 segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str()); 1409 segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str()); 1410 segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), segments->fModulate.c_str()); 1411 1412} 1413 1414void genMorphologyVS(int stageNum, 1415 const StageDesc& desc, 1416 GrGLShaderBuilder* segments, 1417 GrGLProgram::StageUniLocations* locations, 1418 const char** imageIncrementName, 1419 const char* varyingVSName) { 1420 1421 GrStringBuilder iiName; 1422 image_increment_param_name(stageNum, &iiName); 1423 const GrGLShaderVar* imgInc = 1424 &segments->addUniform( 1425 GrGLShaderBuilder::kBoth_VariableLifetime, kVec2f_GrSLType, 1426 iiName.c_str()); 1427 *imageIncrementName = imgInc->getName().c_str(); 1428 1429 locations->fImageIncrementUni = kUseUniform; 1430 segments->fVSCode.appendf("\t%s -= vec2(%d, %d) * %s;\n", 1431 varyingVSName, desc.fKernelWidth, 1432 desc.fKernelWidth, *imageIncrementName); 1433} 1434 1435void genMorphologyFS(int stageNum, 1436 const StageDesc& desc, 1437 GrGLShaderBuilder* segments, 1438 const char* samplerName, 1439 const char* imageIncrementName, 1440 const char* fsOutColor, 1441 GrStringBuilder& texFunc) { 1442 GrStringBuilder valueVar("value"); 1443 valueVar.appendS32(stageNum); 1444 GrStringBuilder coordVar("coord"); 1445 coordVar.appendS32(stageNum); 1446 bool isDilate = StageDesc::kDilate_FetchMode == desc.fFetchMode; 1447 1448 if (isDilate) { 1449 segments->fFSCode.appendf("\tvec4 %s = vec4(0, 0, 0, 0);\n", 1450 valueVar.c_str()); 1451 } else { 1452 segments->fFSCode.appendf("\tvec4 %s = vec4(1, 1, 1, 1);\n", 1453 valueVar.c_str()); 1454 } 1455 segments->fFSCode.appendf("\tvec2 %s = %s;\n", 1456 coordVar.c_str(), 1457 segments->fSampleCoords.c_str()); 1458 segments->fFSCode.appendf("\tfor (int i = 0; i < %d; i++) {\n", 1459 desc.fKernelWidth * 2 + 1); 1460 segments->fFSCode.appendf("\t\t%s = %s(%s, %s(%s, %s)%s);\n", 1461 valueVar.c_str(), isDilate ? "max" : "min", 1462 valueVar.c_str(), texFunc.c_str(), 1463 samplerName, coordVar.c_str(), 1464 segments->fSwizzle.c_str()); 1465 segments->fFSCode.appendf("\t\t%s += %s;\n", 1466 coordVar.c_str(), 1467 imageIncrementName); 1468 segments->fFSCode.appendf("\t}\n"); 1469 segments->fFSCode.appendf("\t%s = %s%s;\n", fsOutColor, 1470 valueVar.c_str(), segments->fModulate.c_str()); 1471} 1472 1473} 1474 1475void GrGLProgram::genStageCode(const GrGLContextInfo& gl, 1476 int stageNum, 1477 const GrGLProgram::StageDesc& desc, 1478 const char* fsInColor, // NULL means no incoming color 1479 const char* fsOutColor, 1480 const char* vsInCoord, 1481 GrGLShaderBuilder* segments, 1482 StageUniLocations* locations, 1483 GrGLProgramStage* customStage) const { 1484 1485 GrAssert(stageNum >= 0 && stageNum <= GrDrawState::kNumStages); 1486 GrAssert((desc.fInConfigFlags & StageDesc::kInConfigBitMask) == 1487 desc.fInConfigFlags); 1488 1489 if (NULL != customStage) { 1490 customStage->setupVariables(segments, stageNum); 1491 } 1492 1493 /// Vertex Shader Stuff 1494 1495 // decide whether we need a matrix to transform texture coords 1496 // and whether the varying needs a perspective coord. 1497 const char* matName = NULL; 1498 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) { 1499 segments->fVaryingDims = segments->fCoordDims; 1500 } else { 1501 GrStringBuilder texMatName; 1502 tex_matrix_name(stageNum, &texMatName); 1503 const GrGLShaderVar* mat = &segments->addUniform( 1504 GrGLShaderBuilder::kVertex_VariableLifetime, kMat33f_GrSLType, 1505 texMatName.c_str()); 1506 // Can't use texMatName.c_str() because it's on the stack! 1507 matName = mat->getName().c_str(); 1508 locations->fTextureMatrixUni = kUseUniform; 1509 1510 if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) { 1511 segments->fVaryingDims = segments->fCoordDims; 1512 } else { 1513 segments->fVaryingDims = segments->fCoordDims + 1; 1514 } 1515 } 1516 GrAssert(segments->fVaryingDims > 0); 1517 1518 GrStringBuilder samplerName; 1519 sampler_name(stageNum, &samplerName); 1520 const GrGLShaderVar* sampler = &segments->addUniform( 1521 GrGLShaderBuilder::kFragment_VariableLifetime, kSampler2D_GrSLType, 1522 samplerName.c_str()); 1523 locations->fSamplerUni = kUseUniform; 1524 1525 const char* texelSizeName = NULL; 1526 if (StageDesc::k2x2_FetchMode == desc.fFetchMode) { 1527 GrStringBuilder ntsName; 1528 normalized_texel_size_name(stageNum, &ntsName); 1529 texelSizeName = segments->addUniform( 1530 GrGLShaderBuilder::kFragment_VariableLifetime, 1531 kVec2f_GrSLType, ntsName.c_str()).getName().c_str(); 1532 } 1533 1534 const char *varyingVSName, *varyingFSName; 1535 segments->addVarying(GrSLFloatVectorType(segments->fVaryingDims), 1536 "Stage", 1537 stageNum, 1538 &varyingVSName, 1539 &varyingFSName); 1540 1541 if (!matName) { 1542 GrAssert(segments->fVaryingDims == segments->fCoordDims); 1543 segments->fVSCode.appendf("\t%s = %s;\n", varyingVSName, vsInCoord); 1544 } else { 1545 // varying = texMatrix * texCoord 1546 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n", 1547 varyingVSName, matName, vsInCoord, 1548 vector_all_coords(segments->fVaryingDims)); 1549 } 1550 1551 const GrGLShaderVar* radial2Params = NULL; 1552 const char* radial2VaryingVSName = NULL; 1553 const char* radial2VaryingFSName = NULL; 1554 1555 if (isRadialMapping((StageDesc::CoordMapping) desc.fCoordMapping)) { 1556 radial2Params = genRadialVS(stageNum, segments, 1557 locations, 1558 &radial2VaryingVSName, 1559 &radial2VaryingFSName, 1560 varyingVSName); 1561 } 1562 1563 GrGLShaderVar* kernel = NULL; 1564 const char* imageIncrementName = NULL; 1565 if (StageDesc::kDilate_FetchMode == desc.fFetchMode || 1566 StageDesc::kErode_FetchMode == desc.fFetchMode) { 1567 genMorphologyVS(stageNum, desc, segments, locations, 1568 &imageIncrementName, varyingVSName); 1569 } 1570 1571 if (NULL != customStage) { 1572 segments->fVSCode.appendf("\t{ // stage %d %s\n", 1573 stageNum, customStage->name()); 1574 customStage->emitVS(segments, varyingVSName); 1575 segments->fVSCode.appendf("\t}\n"); 1576 } 1577 1578 /// Fragment Shader Stuff 1579 1580 // Function used to access the shader, may be made projective. 1581 GrStringBuilder texFunc("texture2D"); 1582 if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit | 1583 StageDesc::kNoPerspective_OptFlagBit)) { 1584 GrAssert(segments->fVaryingDims == segments->fCoordDims); 1585 segments->fSampleCoords = varyingFSName; 1586 } else { 1587 // If we have to do some special op on the varyings to get 1588 // our final tex coords then when in perspective we have to 1589 // do an explicit divide. Otherwise, we can use a Proj func. 1590 if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping && 1591 StageDesc::kSingle_FetchMode == desc.fFetchMode) { 1592 texFunc.append("Proj"); 1593 segments->fSampleCoords = varyingFSName; 1594 } else { 1595 // This block is replicated in GrGLProgramStage::emitTextureLookup() 1596 segments->fSampleCoords = "inCoord"; 1597 segments->fSampleCoords.appendS32(stageNum); 1598 segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n", 1599 GrGLShaderVar::TypeString(GrSLFloatVectorType(segments->fCoordDims)), 1600 segments->fSampleCoords.c_str(), 1601 varyingFSName, 1602 GrGLSLVectorNonhomogCoords(segments->fVaryingDims), 1603 varyingFSName, 1604 GrGLSLVectorHomogCoord(segments->fVaryingDims)); 1605 } 1606 } 1607 1608 segments->fComplexCoord = false; 1609 // NOTE: GrGLProgramStages will soon responsible for mapping 1610 //if (NULL == customStage) { 1611 switch (desc.fCoordMapping) { 1612 case StageDesc::kIdentity_CoordMapping: 1613 // Do nothing 1614 break; 1615 case StageDesc::kSweepGradient_CoordMapping: 1616 segments->fSampleCoords.printf("vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)", segments->fSampleCoords.c_str(), segments->fSampleCoords.c_str()); 1617 segments->fComplexCoord = true; 1618 break; 1619 case StageDesc::kRadialGradient_CoordMapping: 1620 segments->fSampleCoords.printf("vec2(length(%s.xy), 0.5)", segments->fSampleCoords.c_str()); 1621 segments->fComplexCoord = true; 1622 break; 1623 case StageDesc::kRadial2Gradient_CoordMapping: 1624 genRadial2GradientCoordMapping( 1625 stageNum, segments, 1626 radial2VaryingFSName, radial2Params); 1627 break; 1628 case StageDesc::kRadial2GradientDegenerate_CoordMapping: 1629 genRadial2GradientDegenerateCoordMapping( 1630 stageNum, segments, 1631 radial2VaryingFSName, radial2Params); 1632 break; 1633 } 1634 //} 1635 1636 static const uint32_t kMulByAlphaMask = 1637 (StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag | 1638 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag); 1639 1640 segments->computeSwizzle(desc.fInConfigFlags); 1641 segments->computeModulate(fsInColor); 1642 1643 if (desc.fOptFlags & StageDesc::kCustomTextureDomain_OptFlagBit) { 1644 GrStringBuilder texDomainName; 1645 tex_domain_name(stageNum, &texDomainName); 1646 const GrGLShaderVar* texDomain = 1647 &segments->addUniform( 1648 GrGLShaderBuilder::kFragment_VariableLifetime, 1649 kVec4f_GrSLType, texDomainName.c_str()); 1650 GrStringBuilder coordVar("clampCoord"); 1651 segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n", 1652 float_vector_type_str(segments->fCoordDims), 1653 coordVar.c_str(), 1654 segments->fSampleCoords.c_str(), 1655 texDomainName.c_str(), 1656 texDomainName.c_str()); 1657 segments->fSampleCoords = coordVar; 1658 locations->fTexDomUni = kUseUniform; 1659 } 1660 1661 if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit | 1662 StageDesc::kNoPerspective_OptFlagBit)) { 1663 segments->setSamplerMode(GrGLShaderBuilder::kDefault_SamplerMode); 1664 } else if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping && 1665 StageDesc::kSingle_FetchMode == desc.fFetchMode) { 1666 segments->setSamplerMode(GrGLShaderBuilder::kProj_SamplerMode); 1667 } else { 1668 segments->setSamplerMode( 1669 GrGLShaderBuilder::kExplicitDivide_SamplerMode); 1670 } 1671 1672 // NOTE: GrGLProgramStages are now responsible for fetching 1673 if (NULL == customStage) { 1674 switch (desc.fFetchMode) { 1675 case StageDesc::k2x2_FetchMode: 1676 GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask)); 1677 gen2x2FS(stageNum, segments, locations, 1678 samplerName.c_str(), texelSizeName, fsOutColor, texFunc); 1679 break; 1680 case StageDesc::kConvolution_FetchMode: 1681 GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask)); 1682 break; 1683 case StageDesc::kDilate_FetchMode: 1684 case StageDesc::kErode_FetchMode: 1685 GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask)); 1686 genMorphologyFS(stageNum, desc, segments, 1687 samplerName.c_str(), imageIncrementName, fsOutColor, texFunc); 1688 break; 1689 default: 1690 if (desc.fInConfigFlags & kMulByAlphaMask) { 1691 // only one of the mul by alpha flags should be set 1692 GrAssert(GrIsPow2(kMulByAlphaMask & desc.fInConfigFlags)); 1693 GrAssert(!(desc.fInConfigFlags & 1694 StageDesc::kSmearAlpha_InConfigFlag)); 1695 GrAssert(!(desc.fInConfigFlags & 1696 StageDesc::kSmearRed_InConfigFlag)); 1697 segments->fFSCode.appendf("\t%s = %s(%s, %s)%s;\n", 1698 fsOutColor, texFunc.c_str(), 1699 samplerName.c_str(), 1700 segments->fSampleCoords.c_str(), 1701 segments->fSwizzle.c_str()); 1702 if (desc.fInConfigFlags & 1703 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag) { 1704 segments->fFSCode.appendf("\t%s = vec4(ceil(%s.rgb*%s.a*255.0)/255.0,%s.a)%s;\n", 1705 fsOutColor, fsOutColor, fsOutColor, 1706 fsOutColor, segments->fModulate.c_str()); 1707 } else { 1708 segments->fFSCode.appendf("\t%s = vec4(floor(%s.rgb*%s.a*255.0)/255.0,%s.a)%s;\n", 1709 fsOutColor, fsOutColor, fsOutColor, 1710 fsOutColor, segments->fModulate.c_str()); 1711 } 1712 } else { 1713 segments->emitDefaultFetch(fsOutColor, samplerName.c_str()); 1714 } 1715 } 1716 } 1717 1718 if (NULL != customStage) { 1719 // Enclose custom code in a block to avoid namespace conflicts 1720 segments->fFSCode.appendf("\t{ // stage %d %s \n", 1721 stageNum, customStage->name()); 1722 segments->emitTextureSetup(); 1723 customStage->emitFS(segments, fsOutColor, fsInColor, 1724 samplerName.c_str()); 1725 segments->fFSCode.appendf("\t}\n"); 1726 } 1727} 1728 1729 1730