GrGLProgram.cpp revision d2ae1fad78bbd37d77bd437ea14fb7df22c672d8
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 sampler_name(int stage, GrStringBuilder* s) { 84 *s = "uSampler"; 85 s->appendS32(stage); 86} 87 88inline void radial2_param_name(int stage, GrStringBuilder* s) { 89 *s = "uRadial2Params"; 90 s->appendS32(stage); 91} 92 93inline void tex_domain_name(int stage, GrStringBuilder* s) { 94 *s = "uTexDom"; 95 s->appendS32(stage); 96} 97} 98 99GrGLProgram::GrGLProgram() { 100} 101 102GrGLProgram::~GrGLProgram() { 103} 104 105void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff, 106 GrBlendCoeff* dstCoeff) const { 107 switch (fProgramDesc.fDualSrcOutput) { 108 case ProgramDesc::kNone_DualSrcOutput: 109 break; 110 // the prog will write a coverage value to the secondary 111 // output and the dst is blended by one minus that value. 112 case ProgramDesc::kCoverage_DualSrcOutput: 113 case ProgramDesc::kCoverageISA_DualSrcOutput: 114 case ProgramDesc::kCoverageISC_DualSrcOutput: 115 *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_BlendCoeff; 116 break; 117 default: 118 GrCrash("Unexpected dual source blend output"); 119 break; 120 } 121} 122 123// assigns modulation of two vars to an output var 124// vars can be vec4s or floats (or one of each) 125// result is always vec4 126// if either var is "" then assign to the other var 127// if both are "" then assign all ones 128static inline void modulate_helper(const char* outputVar, 129 const char* var0, 130 const char* var1, 131 GrStringBuilder* code) { 132 GrAssert(NULL != outputVar); 133 GrAssert(NULL != var0); 134 GrAssert(NULL != var1); 135 GrAssert(NULL != code); 136 137 bool has0 = '\0' != *var0; 138 bool has1 = '\0' != *var1; 139 140 if (!has0 && !has1) { 141 code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4)); 142 } else if (!has0) { 143 code->appendf("\t%s = vec4(%s);\n", outputVar, var1); 144 } else if (!has1) { 145 code->appendf("\t%s = vec4(%s);\n", outputVar, var0); 146 } else { 147 code->appendf("\t%s = vec4(%s * %s);\n", outputVar, var0, var1); 148 } 149} 150 151// assigns addition of two vars to an output var 152// vars can be vec4s or floats (or one of each) 153// result is always vec4 154// if either var is "" then assign to the other var 155// if both are "" then assign all zeros 156static inline void add_helper(const char* outputVar, 157 const char* var0, 158 const char* var1, 159 GrStringBuilder* code) { 160 GrAssert(NULL != outputVar); 161 GrAssert(NULL != var0); 162 GrAssert(NULL != var1); 163 GrAssert(NULL != code); 164 165 bool has0 = '\0' != *var0; 166 bool has1 = '\0' != *var1; 167 168 if (!has0 && !has1) { 169 code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4)); 170 } else if (!has0) { 171 code->appendf("\t%s = vec4(%s);\n", outputVar, var1); 172 } else if (!has1) { 173 code->appendf("\t%s = vec4(%s);\n", outputVar, var0); 174 } else { 175 code->appendf("\t%s = vec4(%s + %s);\n", outputVar, var0, var1); 176 } 177} 178 179// given two blend coeffecients determine whether the src 180// and/or dst computation can be omitted. 181static inline void needBlendInputs(SkXfermode::Coeff srcCoeff, 182 SkXfermode::Coeff dstCoeff, 183 bool* needSrcValue, 184 bool* needDstValue) { 185 if (SkXfermode::kZero_Coeff == srcCoeff) { 186 switch (dstCoeff) { 187 // these all read the src 188 case SkXfermode::kSC_Coeff: 189 case SkXfermode::kISC_Coeff: 190 case SkXfermode::kSA_Coeff: 191 case SkXfermode::kISA_Coeff: 192 *needSrcValue = true; 193 break; 194 default: 195 *needSrcValue = false; 196 break; 197 } 198 } else { 199 *needSrcValue = true; 200 } 201 if (SkXfermode::kZero_Coeff == dstCoeff) { 202 switch (srcCoeff) { 203 // these all read the dst 204 case SkXfermode::kDC_Coeff: 205 case SkXfermode::kIDC_Coeff: 206 case SkXfermode::kDA_Coeff: 207 case SkXfermode::kIDA_Coeff: 208 *needDstValue = true; 209 break; 210 default: 211 *needDstValue = false; 212 break; 213 } 214 } else { 215 *needDstValue = true; 216 } 217} 218 219/** 220 * Create a blend_coeff * value string to be used in shader code. Sets empty 221 * string if result is trivially zero. 222 */ 223static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff, 224 const char* src, const char* dst, 225 const char* value) { 226 switch (coeff) { 227 case SkXfermode::kZero_Coeff: /** 0 */ 228 *str = ""; 229 break; 230 case SkXfermode::kOne_Coeff: /** 1 */ 231 *str = value; 232 break; 233 case SkXfermode::kSC_Coeff: 234 str->printf("(%s * %s)", src, value); 235 break; 236 case SkXfermode::kISC_Coeff: 237 str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value); 238 break; 239 case SkXfermode::kDC_Coeff: 240 str->printf("(%s * %s)", dst, value); 241 break; 242 case SkXfermode::kIDC_Coeff: 243 str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value); 244 break; 245 case SkXfermode::kSA_Coeff: /** src alpha */ 246 str->printf("(%s.a * %s)", src, value); 247 break; 248 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */ 249 str->printf("((1.0 - %s.a) * %s)", src, value); 250 break; 251 case SkXfermode::kDA_Coeff: /** dst alpha */ 252 str->printf("(%s.a * %s)", dst, value); 253 break; 254 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */ 255 str->printf("((1.0 - %s.a) * %s)", dst, value); 256 break; 257 default: 258 GrCrash("Unexpected xfer coeff."); 259 break; 260 } 261} 262/** 263 * Adds a line to the fragment shader code which modifies the color by 264 * the specified color filter. 265 */ 266static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar, 267 SkXfermode::Coeff uniformCoeff, 268 SkXfermode::Coeff colorCoeff, 269 const char* inColor) { 270 GrStringBuilder colorStr, constStr; 271 blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME, 272 inColor, inColor); 273 blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME, 274 inColor, COL_FILTER_UNI_NAME); 275 276 add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode); 277} 278/** 279 * Adds code to the fragment shader code which modifies the color by 280 * the specified color matrix. 281 */ 282static void addColorMatrix(GrStringBuilder* fsCode, const char * outputVar, 283 const char* inColor) { 284 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); 285 fsCode->appendf("\t%s.rgb *= %s.a;\n", outputVar, outputVar); 286} 287 288void GrGLProgram::genEdgeCoverage(const GrGLContextInfo& gl, 289 GrVertexLayout layout, 290 CachedData* programData, 291 GrStringBuilder* coverageVar, 292 GrGLShaderBuilder* segments) const { 293 if (layout & GrDrawTarget::kEdge_VertexLayoutBit) { 294 const char *vsName, *fsName; 295 segments->addVarying(kVec4f_GrSLType, "Edge", &vsName, &fsName); 296 segments->fVSAttrs.push_back().set(kVec4f_GrSLType, 297 GrGLShaderVar::kAttribute_TypeModifier, EDGE_ATTR_NAME); 298 segments->fVSCode.appendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName); 299 switch (fProgramDesc.fVertexEdgeType) { 300 case GrDrawState::kHairLine_EdgeType: 301 segments->fFSCode.appendf("\tfloat edgeAlpha = abs(dot(vec3(gl_FragCoord.xy,1), %s.xyz));\n", fsName); 302 segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n"); 303 break; 304 case GrDrawState::kQuad_EdgeType: 305 segments->fFSCode.append("\tfloat edgeAlpha;\n"); 306 // keep the derivative instructions outside the conditional 307 segments->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName); 308 segments->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName); 309 segments->fFSCode.appendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName); 310 // today we know z and w are in device space. We could use derivatives 311 segments->fFSCode.appendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName); 312 segments->fFSCode.append ("\t} else {\n"); 313 segments->fFSCode.appendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n" 314 "\t\t 2.0*%s.x*duvdy.x - duvdy.y);\n", 315 fsName, fsName); 316 segments->fFSCode.appendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName); 317 segments->fFSCode.append("\t\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n" 318 "\t}\n"); 319 if (kES2_GrGLBinding == gl.binding()) { 320 segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n"); 321 } 322 break; 323 case GrDrawState::kHairQuad_EdgeType: 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("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n" 327 "\t 2.0*%s.x*duvdy.x - duvdy.y);\n", 328 fsName, fsName); 329 segments->fFSCode.appendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName); 330 segments->fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n"); 331 segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n"); 332 if (kES2_GrGLBinding == gl.binding()) { 333 segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n"); 334 } 335 break; 336 case GrDrawState::kCircle_EdgeType: 337 segments->fFSCode.append("\tfloat edgeAlpha;\n"); 338 segments->fFSCode.appendf("\tfloat d = distance(gl_FragCoord.xy, %s.xy);\n", fsName); 339 segments->fFSCode.appendf("\tfloat outerAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName); 340 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); 341 segments->fFSCode.append("\tedgeAlpha = outerAlpha * innerAlpha;\n"); 342 break; 343 default: 344 GrCrash("Unknown Edge Type!"); 345 break; 346 } 347 *coverageVar = "edgeAlpha"; 348 } else { 349 coverageVar->reset(); 350 } 351} 352 353namespace { 354 355void genInputColor(GrGLProgram::ProgramDesc::ColorInput colorInput, 356 GrGLProgram::CachedData* programData, 357 GrGLShaderBuilder* segments, 358 GrStringBuilder* inColor) { 359 switch (colorInput) { 360 case GrGLProgram::ProgramDesc::kAttribute_ColorInput: { 361 segments->fVSAttrs.push_back().set(kVec4f_GrSLType, 362 GrGLShaderVar::kAttribute_TypeModifier, 363 COL_ATTR_NAME); 364 const char *vsName, *fsName; 365 segments->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName); 366 segments->fVSCode.appendf("\t%s = " COL_ATTR_NAME ";\n", vsName); 367 *inColor = fsName; 368 } break; 369 case GrGLProgram::ProgramDesc::kUniform_ColorInput: 370 segments->addUniform(GrGLShaderBuilder::kFragment_VariableLifetime, 371 kVec4f_GrSLType, COL_UNI_NAME); 372 programData->fUniLocations.fColorUni = kUseUniform; 373 *inColor = COL_UNI_NAME; 374 break; 375 case GrGLProgram::ProgramDesc::kTransBlack_ColorInput: 376 GrAssert(!"needComputedColor should be false."); 377 break; 378 case GrGLProgram::ProgramDesc::kSolidWhite_ColorInput: 379 break; 380 default: 381 GrCrash("Unknown color type."); 382 break; 383 } 384} 385 386void genAttributeCoverage(GrGLShaderBuilder* segments, 387 GrStringBuilder* inOutCoverage) { 388 segments->fVSAttrs.push_back().set(kVec4f_GrSLType, 389 GrGLShaderVar::kAttribute_TypeModifier, 390 COV_ATTR_NAME); 391 const char *vsName, *fsName; 392 segments->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName); 393 segments->fVSCode.appendf("\t%s = " COV_ATTR_NAME ";\n", vsName); 394 if (inOutCoverage->size()) { 395 segments->fFSCode.appendf("\tvec4 attrCoverage = %s * %s;\n", 396 fsName, inOutCoverage->c_str()); 397 *inOutCoverage = "attrCoverage"; 398 } else { 399 *inOutCoverage = fsName; 400 } 401} 402 403void genUniformCoverage(GrGLShaderBuilder* segments, 404 GrGLProgram::CachedData* programData, 405 GrStringBuilder* inOutCoverage) { 406 segments->addUniform(GrGLShaderBuilder::kFragment_VariableLifetime, 407 kVec4f_GrSLType, COV_UNI_NAME); 408 programData->fUniLocations.fCoverageUni = kUseUniform; 409 if (inOutCoverage->size()) { 410 segments->fFSCode.appendf("\tvec4 uniCoverage = %s * %s;\n", 411 COV_UNI_NAME, inOutCoverage->c_str()); 412 *inOutCoverage = "uniCoverage"; 413 } else { 414 *inOutCoverage = COV_UNI_NAME; 415 } 416} 417 418} 419 420void GrGLProgram::genGeometryShader(const GrGLContextInfo& gl, 421 GrGLShaderBuilder* segments) const { 422#if GR_GL_EXPERIMENTAL_GS 423 if (fProgramDesc.fExperimentalGS) { 424 GrAssert(gl.glslGeneration() >= k150_GrGLSLGeneration); 425 segments->fGSHeader.append("layout(triangles) in;\n" 426 "layout(triangle_strip, max_vertices = 6) out;\n"); 427 segments->fGSCode.append("void main() {\n" 428 "\tfor (int i = 0; i < 3; ++i) {\n" 429 "\t\tgl_Position = gl_in[i].gl_Position;\n"); 430 if (this->fProgramDesc.fEmitsPointSize) { 431 segments->fGSCode.append("\t\tgl_PointSize = 1.0;\n"); 432 } 433 GrAssert(segments->fGSInputs.count() == segments->fGSOutputs.count()); 434 int count = segments->fGSInputs.count(); 435 for (int i = 0; i < count; ++i) { 436 segments->fGSCode.appendf("\t\t%s = %s[i];\n", 437 segments->fGSOutputs[i].getName().c_str(), 438 segments->fGSInputs[i].getName().c_str()); 439 } 440 segments->fGSCode.append("\t\tEmitVertex();\n" 441 "\t}\n" 442 "\tEndPrimitive();\n" 443 "}\n"); 444 } 445#endif 446} 447 448const char* GrGLProgram::adjustInColor(const GrStringBuilder& inColor) const { 449 if (inColor.size()) { 450 return inColor.c_str(); 451 } else { 452 if (ProgramDesc::kSolidWhite_ColorInput == fProgramDesc.fColorInput) { 453 return all_ones_vec(4); 454 } else { 455 return all_zeros_vec(4); 456 } 457 } 458} 459 460// If this destructor is in the header file, we must include GrGLProgramStage 461// instead of just forward-declaring it. 462GrGLProgram::CachedData::~CachedData() { 463 for (int i = 0; i < GrDrawState::kNumStages; ++i) { 464 delete fCustomStage[i]; 465 } 466} 467 468 469bool GrGLProgram::genProgram(const GrGLContextInfo& gl, 470 GrCustomStage** customStages, 471 GrGLProgram::CachedData* programData) const { 472 GrGLShaderBuilder segments; 473 const uint32_t& layout = fProgramDesc.fVertexLayout; 474 475 programData->fUniLocations.reset(); 476 477#if GR_GL_EXPERIMENTAL_GS 478 segments.fUsesGS = fProgramDesc.fExperimentalGS; 479#endif 480 481 SkXfermode::Coeff colorCoeff, uniformCoeff; 482 bool applyColorMatrix = SkToBool(fProgramDesc.fColorMatrixEnabled); 483 // The rest of transfer mode color filters have not been implemented 484 if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) { 485 GR_DEBUGCODE(bool success =) 486 SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode> 487 (fProgramDesc.fColorFilterXfermode), 488 &uniformCoeff, &colorCoeff); 489 GR_DEBUGASSERT(success); 490 } else { 491 colorCoeff = SkXfermode::kOne_Coeff; 492 uniformCoeff = SkXfermode::kZero_Coeff; 493 } 494 495 // no need to do the color filter / matrix at all if coverage is 0. The 496 // output color is scaled by the coverage. All the dual source outputs are 497 // scaled by the coverage as well. 498 if (ProgramDesc::kTransBlack_ColorInput == fProgramDesc.fCoverageInput) { 499 colorCoeff = SkXfermode::kZero_Coeff; 500 uniformCoeff = SkXfermode::kZero_Coeff; 501 applyColorMatrix = false; 502 } 503 504 // If we know the final color is going to be all zeros then we can 505 // simplify the color filter coeffecients. needComputedColor will then 506 // come out false below. 507 if (ProgramDesc::kTransBlack_ColorInput == fProgramDesc.fColorInput) { 508 colorCoeff = SkXfermode::kZero_Coeff; 509 if (SkXfermode::kDC_Coeff == uniformCoeff || 510 SkXfermode::kDA_Coeff == uniformCoeff) { 511 uniformCoeff = SkXfermode::kZero_Coeff; 512 } else if (SkXfermode::kIDC_Coeff == uniformCoeff || 513 SkXfermode::kIDA_Coeff == uniformCoeff) { 514 uniformCoeff = SkXfermode::kOne_Coeff; 515 } 516 } 517 518 bool needColorFilterUniform; 519 bool needComputedColor; 520 needBlendInputs(uniformCoeff, colorCoeff, 521 &needColorFilterUniform, &needComputedColor); 522 523 // the dual source output has no canonical var name, have to 524 // declare an output, which is incompatible with gl_FragColor/gl_FragData. 525 bool dualSourceOutputWritten = false; 526 segments.fHeader.printf(GrGetGLSLVersionDecl(gl.binding(), 527 gl.glslGeneration())); 528 529 GrGLShaderVar colorOutput; 530 bool isColorDeclared = GrGLSLSetupFSColorOuput(gl.glslGeneration(), 531 declared_color_output_name(), 532 &colorOutput); 533 if (isColorDeclared) { 534 segments.fFSOutputs.push_back(colorOutput); 535 } 536 537 segments.addUniform(GrGLShaderBuilder::kVertex_VariableLifetime, 538 kMat33f_GrSLType, VIEW_MATRIX_NAME); 539 programData->fUniLocations.fViewMatrixUni = kUseUniform; 540 541 segments.fVSAttrs.push_back().set(kVec2f_GrSLType, 542 GrGLShaderVar::kAttribute_TypeModifier, POS_ATTR_NAME); 543 544 segments.fVSCode.append( 545 "void main() {\n" 546 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n" 547 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n"); 548 549 // incoming color to current stage being processed. 550 GrStringBuilder inColor; 551 552 if (needComputedColor) { 553 genInputColor((ProgramDesc::ColorInput) fProgramDesc.fColorInput, 554 programData, &segments, &inColor); 555 } 556 557 // we output point size in the GS if present 558 if (fProgramDesc.fEmitsPointSize && !segments.fUsesGS){ 559 segments.fVSCode.append("\tgl_PointSize = 1.0;\n"); 560 } 561 562 segments.fFSCode.append("void main() {\n"); 563 564 // add texture coordinates that are used to the list of vertex attr decls 565 GrStringBuilder texCoordAttrs[GrDrawState::kMaxTexCoords]; 566 for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { 567 if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) { 568 tex_attr_name(t, texCoordAttrs + t); 569 segments.fVSAttrs.push_back().set(kVec2f_GrSLType, 570 GrGLShaderVar::kAttribute_TypeModifier, 571 texCoordAttrs[t].c_str()); 572 } 573 } 574 575 /////////////////////////////////////////////////////////////////////////// 576 // We need to convert generic effect representations to GL-specific 577 // backends so they can be accesseed in genStageCode() and in subsequent, 578 // uses of programData, but it's safest to do so below when we're *sure* 579 // we need them. 580 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 581 programData->fCustomStage[s] = NULL; 582 } 583 584 /////////////////////////////////////////////////////////////////////////// 585 // compute the final color 586 587 // if we have color stages string them together, feeding the output color 588 // of each to the next and generating code for each stage. 589 if (needComputedColor) { 590 GrStringBuilder outColor; 591 for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) { 592 if (fProgramDesc.fStages[s].isEnabled()) { 593 // create var to hold stage result 594 outColor = "color"; 595 outColor.appendS32(s); 596 segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str()); 597 598 const char* inCoords; 599 // figure out what our input coords are 600 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & 601 layout) { 602 inCoords = POS_ATTR_NAME; 603 } else { 604 int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout); 605 // we better have input tex coordinates if stage is enabled. 606 GrAssert(tcIdx >= 0); 607 GrAssert(texCoordAttrs[tcIdx].size()); 608 inCoords = texCoordAttrs[tcIdx].c_str(); 609 } 610 611 if (NULL != customStages[s]) { 612 const GrProgramStageFactory& factory = 613 customStages[s]->getFactory(); 614 programData->fCustomStage[s] = 615 factory.createGLInstance(*customStages[s]); 616 } 617 this->genStageCode(gl, 618 s, 619 fProgramDesc.fStages[s], 620 inColor.size() ? inColor.c_str() : NULL, 621 outColor.c_str(), 622 inCoords, 623 &segments, 624 &programData->fUniLocations.fStages[s], 625 programData->fCustomStage[s]); 626 inColor = outColor; 627 } 628 } 629 } 630 631 // if have all ones or zeros for the "dst" input to the color filter then we 632 // may be able to make additional optimizations. 633 if (needColorFilterUniform && needComputedColor && !inColor.size()) { 634 GrAssert(ProgramDesc::kSolidWhite_ColorInput == fProgramDesc.fColorInput); 635 bool uniformCoeffIsZero = SkXfermode::kIDC_Coeff == uniformCoeff || 636 SkXfermode::kIDA_Coeff == uniformCoeff; 637 if (uniformCoeffIsZero) { 638 uniformCoeff = SkXfermode::kZero_Coeff; 639 bool bogus; 640 needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff, 641 &needColorFilterUniform, &bogus); 642 } 643 } 644 if (needColorFilterUniform) { 645 segments.addUniform(GrGLShaderBuilder::kFragment_VariableLifetime, 646 kVec4f_GrSLType, COL_FILTER_UNI_NAME); 647 programData->fUniLocations.fColorFilterUni = kUseUniform; 648 } 649 bool wroteFragColorZero = false; 650 if (SkXfermode::kZero_Coeff == uniformCoeff && 651 SkXfermode::kZero_Coeff == colorCoeff && 652 !applyColorMatrix) { 653 segments.fFSCode.appendf("\t%s = %s;\n", 654 colorOutput.getName().c_str(), 655 all_zeros_vec(4)); 656 wroteFragColorZero = true; 657 } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) { 658 segments.fFSCode.append("\tvec4 filteredColor;\n"); 659 const char* color = adjustInColor(inColor); 660 addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff, 661 colorCoeff, color); 662 inColor = "filteredColor"; 663 } 664 if (applyColorMatrix) { 665 segments.addUniform(GrGLShaderBuilder::kFragment_VariableLifetime, 666 kMat44f_GrSLType, COL_MATRIX_UNI_NAME); 667 segments.addUniform(GrGLShaderBuilder::kFragment_VariableLifetime, 668 kVec4f_GrSLType, COL_MATRIX_VEC_UNI_NAME); 669 programData->fUniLocations.fColorMatrixUni = kUseUniform; 670 programData->fUniLocations.fColorMatrixVecUni = kUseUniform; 671 segments.fFSCode.append("\tvec4 matrixedColor;\n"); 672 const char* color = adjustInColor(inColor); 673 addColorMatrix(&segments.fFSCode, "matrixedColor", color); 674 inColor = "matrixedColor"; 675 } 676 677 /////////////////////////////////////////////////////////////////////////// 678 // compute the partial coverage (coverage stages and edge aa) 679 680 GrStringBuilder inCoverage; 681 bool coverageIsZero = ProgramDesc::kTransBlack_ColorInput == 682 fProgramDesc.fCoverageInput; 683 // we don't need to compute coverage at all if we know the final shader 684 // output will be zero and we don't have a dual src blend output. 685 if (!wroteFragColorZero || 686 ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) { 687 688 if (!coverageIsZero) { 689 this->genEdgeCoverage(gl, 690 layout, 691 programData, 692 &inCoverage, 693 &segments); 694 695 switch (fProgramDesc.fCoverageInput) { 696 case ProgramDesc::kSolidWhite_ColorInput: 697 // empty string implies solid white 698 break; 699 case ProgramDesc::kAttribute_ColorInput: 700 genAttributeCoverage(&segments, &inCoverage); 701 break; 702 case ProgramDesc::kUniform_ColorInput: 703 genUniformCoverage(&segments, programData, &inCoverage); 704 break; 705 default: 706 GrCrash("Unexpected input coverage."); 707 } 708 709 GrStringBuilder outCoverage; 710 const int& startStage = fProgramDesc.fFirstCoverageStage; 711 for (int s = startStage; s < GrDrawState::kNumStages; ++s) { 712 if (fProgramDesc.fStages[s].isEnabled()) { 713 // create var to hold stage output 714 outCoverage = "coverage"; 715 outCoverage.appendS32(s); 716 segments.fFSCode.appendf("\tvec4 %s;\n", 717 outCoverage.c_str()); 718 719 const char* inCoords; 720 // figure out what our input coords are 721 if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & 722 layout) { 723 inCoords = POS_ATTR_NAME; 724 } else { 725 int tcIdx = 726 GrDrawTarget::VertexTexCoordsForStage(s, layout); 727 // we better have input tex coordinates if stage is 728 // enabled. 729 GrAssert(tcIdx >= 0); 730 GrAssert(texCoordAttrs[tcIdx].size()); 731 inCoords = texCoordAttrs[tcIdx].c_str(); 732 } 733 734 if (NULL != customStages[s]) { 735 const GrProgramStageFactory& factory = 736 customStages[s]->getFactory(); 737 programData->fCustomStage[s] = 738 factory.createGLInstance(*customStages[s]); 739 } 740 this->genStageCode(gl, s, 741 fProgramDesc.fStages[s], 742 inCoverage.size() ? inCoverage.c_str() : NULL, 743 outCoverage.c_str(), 744 inCoords, 745 &segments, 746 &programData->fUniLocations.fStages[s], 747 programData->fCustomStage[s]); 748 inCoverage = outCoverage; 749 } 750 } 751 } 752 if (ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) { 753 segments.fFSOutputs.push_back().set(kVec4f_GrSLType, 754 GrGLShaderVar::kOut_TypeModifier, 755 dual_source_output_name()); 756 bool outputIsZero = coverageIsZero; 757 GrStringBuilder coeff; 758 if (!outputIsZero && 759 ProgramDesc::kCoverage_DualSrcOutput != 760 fProgramDesc.fDualSrcOutput && !wroteFragColorZero) { 761 if (!inColor.size()) { 762 outputIsZero = true; 763 } else { 764 if (fProgramDesc.fDualSrcOutput == 765 ProgramDesc::kCoverageISA_DualSrcOutput) { 766 coeff.printf("(1 - %s.a)", inColor.c_str()); 767 } else { 768 coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str()); 769 } 770 } 771 } 772 if (outputIsZero) { 773 segments.fFSCode.appendf("\t%s = %s;\n", 774 dual_source_output_name(), 775 all_zeros_vec(4)); 776 } else { 777 modulate_helper(dual_source_output_name(), 778 coeff.c_str(), 779 inCoverage.c_str(), 780 &segments.fFSCode); 781 } 782 dualSourceOutputWritten = true; 783 } 784 } 785 786 /////////////////////////////////////////////////////////////////////////// 787 // combine color and coverage as frag color 788 789 if (!wroteFragColorZero) { 790 if (coverageIsZero) { 791 segments.fFSCode.appendf("\t%s = %s;\n", 792 colorOutput.getName().c_str(), 793 all_zeros_vec(4)); 794 } else { 795 modulate_helper(colorOutput.getName().c_str(), 796 inColor.c_str(), 797 inCoverage.c_str(), 798 &segments.fFSCode); 799 } 800 if (ProgramDesc::kUnpremultiplied_RoundDown_OutputConfig == 801 fProgramDesc.fOutputConfig) { 802 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", 803 colorOutput.getName().c_str(), 804 colorOutput.getName().c_str(), 805 colorOutput.getName().c_str(), 806 colorOutput.getName().c_str(), 807 colorOutput.getName().c_str()); 808 } else if (ProgramDesc::kUnpremultiplied_RoundUp_OutputConfig == 809 fProgramDesc.fOutputConfig) { 810 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", 811 colorOutput.getName().c_str(), 812 colorOutput.getName().c_str(), 813 colorOutput.getName().c_str(), 814 colorOutput.getName().c_str(), 815 colorOutput.getName().c_str()); 816 } 817 } 818 819 segments.fVSCode.append("}\n"); 820 segments.fFSCode.append("}\n"); 821 822 /////////////////////////////////////////////////////////////////////////// 823 // insert GS 824#if GR_DEBUG 825 this->genGeometryShader(gl, &segments); 826#endif 827 828 /////////////////////////////////////////////////////////////////////////// 829 // compile and setup attribs and unis 830 831 if (!CompileShaders(gl, segments, programData)) { 832 return false; 833 } 834 835 if (!this->bindOutputsAttribsAndLinkProgram(gl, texCoordAttrs, 836 isColorDeclared, 837 dualSourceOutputWritten, 838 programData)) { 839 return false; 840 } 841 842 this->getUniformLocationsAndInitCache(gl, programData); 843 844 return true; 845} 846 847namespace { 848 849inline void expand_decls(const VarArray& vars, 850 const GrGLContextInfo& gl, 851 GrStringBuilder* string) { 852 const int count = vars.count(); 853 for (int i = 0; i < count; ++i) { 854 vars[i].appendDecl(gl, string); 855 } 856} 857 858inline void print_shader(int stringCnt, 859 const char** strings, 860 int* stringLengths) { 861 for (int i = 0; i < stringCnt; ++i) { 862 if (NULL == stringLengths || stringLengths[i] < 0) { 863 GrPrintf(strings[i]); 864 } else { 865 GrPrintf("%.*s", stringLengths[i], strings[i]); 866 } 867 } 868} 869 870typedef SkTArray<const char*, true> StrArray; 871#define PREALLOC_STR_ARRAY(N) SkSTArray<(N), const char*, true> 872 873typedef SkTArray<int, true> LengthArray; 874#define PREALLOC_LENGTH_ARRAY(N) SkSTArray<(N), int, true> 875 876// these shouldn't relocate 877typedef GrTAllocator<GrStringBuilder> TempArray; 878#define PREALLOC_TEMP_ARRAY(N) GrSTAllocator<(N), GrStringBuilder> 879 880inline void append_string(const GrStringBuilder& str, 881 StrArray* strings, 882 LengthArray* lengths) { 883 int length = (int) str.size(); 884 if (length) { 885 strings->push_back(str.c_str()); 886 lengths->push_back(length); 887 } 888 GrAssert(strings->count() == lengths->count()); 889} 890 891inline void append_decls(const VarArray& vars, 892 const GrGLContextInfo& gl, 893 StrArray* strings, 894 LengthArray* lengths, 895 TempArray* temp) { 896 expand_decls(vars, gl, &temp->push_back()); 897 append_string(temp->back(), strings, lengths); 898} 899 900} 901 902bool GrGLProgram::CompileShaders(const GrGLContextInfo& gl, 903 const GrGLShaderBuilder& segments, 904 CachedData* programData) { 905 enum { kPreAllocStringCnt = 8 }; 906 907 PREALLOC_STR_ARRAY(kPreAllocStringCnt) strs; 908 PREALLOC_LENGTH_ARRAY(kPreAllocStringCnt) lengths; 909 PREALLOC_TEMP_ARRAY(kPreAllocStringCnt) temps; 910 911 GrStringBuilder unis; 912 GrStringBuilder inputs; 913 GrStringBuilder outputs; 914 915 append_string(segments.fHeader, &strs, &lengths); 916 append_decls(segments.fVSUnis, gl, &strs, &lengths, &temps); 917 append_decls(segments.fVSAttrs, gl, &strs, &lengths, &temps); 918 append_decls(segments.fVSOutputs, gl, &strs, &lengths, &temps); 919 append_string(segments.fVSCode, &strs, &lengths); 920 921#if PRINT_SHADERS 922 print_shader(strs.count(), &strs[0], &lengths[0]); 923 GrPrintf("\n"); 924#endif 925 926 programData->fVShaderID = 927 CompileShader(gl, GR_GL_VERTEX_SHADER, strs.count(), 928 &strs[0], &lengths[0]); 929 930 if (!programData->fVShaderID) { 931 return false; 932 } 933 if (segments.fUsesGS) { 934 strs.reset(); 935 lengths.reset(); 936 temps.reset(); 937 append_string(segments.fHeader, &strs, &lengths); 938 append_string(segments.fGSHeader, &strs, &lengths); 939 append_decls(segments.fGSInputs, gl, &strs, &lengths, &temps); 940 append_decls(segments.fGSOutputs, gl, &strs, &lengths, &temps); 941 append_string(segments.fGSCode, &strs, &lengths); 942#if PRINT_SHADERS 943 print_shader(strs.count(), &strs[0], &lengths[0]); 944 GrPrintf("\n"); 945#endif 946 programData->fGShaderID = 947 CompileShader(gl, GR_GL_GEOMETRY_SHADER, strs.count(), 948 &strs[0], &lengths[0]); 949 } else { 950 programData->fGShaderID = 0; 951 } 952 953 strs.reset(); 954 lengths.reset(); 955 temps.reset(); 956 957 append_string(segments.fHeader, &strs, &lengths); 958 GrStringBuilder precisionStr(GrGetGLSLShaderPrecisionDecl(gl.binding())); 959 append_string(precisionStr, &strs, &lengths); 960 append_decls(segments.fFSUnis, gl, &strs, &lengths, &temps); 961 append_decls(segments.fFSInputs, gl, &strs, &lengths, &temps); 962 // We shouldn't have declared outputs on 1.10 963 GrAssert(k110_GrGLSLGeneration != gl.glslGeneration() || 964 segments.fFSOutputs.empty()); 965 append_decls(segments.fFSOutputs, gl, &strs, &lengths, &temps); 966 append_string(segments.fFSFunctions, &strs, &lengths); 967 append_string(segments.fFSCode, &strs, &lengths); 968 969#if PRINT_SHADERS 970 print_shader(strs.count(), &strs[0], &lengths[0]); 971 GrPrintf("\n"); 972#endif 973 974 programData->fFShaderID = 975 CompileShader(gl, GR_GL_FRAGMENT_SHADER, strs.count(), 976 &strs[0], &lengths[0]); 977 978 if (!programData->fFShaderID) { 979 return false; 980 } 981 982 return true; 983} 984 985#define GL_CALL(X) GR_GL_CALL(gl.interface(), X) 986#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gl.interface(), R, X) 987 988GrGLuint GrGLProgram::CompileShader(const GrGLContextInfo& gl, 989 GrGLenum type, 990 int stringCnt, 991 const char** strings, 992 int* stringLengths) { 993 SK_TRACE_EVENT1("GrGLProgram::CompileShader", 994 "stringCount", SkStringPrintf("%i", stringCnt).c_str()); 995 996 GrGLuint shader; 997 GL_CALL_RET(shader, CreateShader(type)); 998 if (0 == shader) { 999 return 0; 1000 } 1001 1002 GrGLint compiled = GR_GL_INIT_ZERO; 1003 GL_CALL(ShaderSource(shader, stringCnt, strings, stringLengths)); 1004 GL_CALL(CompileShader(shader)); 1005 GL_CALL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled)); 1006 1007 if (!compiled) { 1008 GrGLint infoLen = GR_GL_INIT_ZERO; 1009 GL_CALL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen)); 1010 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger 1011 if (infoLen > 0) { 1012 // retrieve length even though we don't need it to workaround 1013 // bug in chrome cmd buffer param validation. 1014 GrGLsizei length = GR_GL_INIT_ZERO; 1015 GL_CALL(GetShaderInfoLog(shader, infoLen+1, 1016 &length, (char*)log.get())); 1017 print_shader(stringCnt, strings, stringLengths); 1018 GrPrintf("\n%s", log.get()); 1019 } 1020 GrAssert(!"Shader compilation failed!"); 1021 GL_CALL(DeleteShader(shader)); 1022 return 0; 1023 } 1024 return shader; 1025} 1026 1027bool GrGLProgram::bindOutputsAttribsAndLinkProgram( 1028 const GrGLContextInfo& gl, 1029 GrStringBuilder texCoordAttrNames[], 1030 bool bindColorOut, 1031 bool bindDualSrcOut, 1032 CachedData* programData) const { 1033 GL_CALL_RET(programData->fProgramID, CreateProgram()); 1034 if (!programData->fProgramID) { 1035 return false; 1036 } 1037 const GrGLint& progID = programData->fProgramID; 1038 1039 GL_CALL(AttachShader(progID, programData->fVShaderID)); 1040 if (programData->fGShaderID) { 1041 GL_CALL(AttachShader(progID, programData->fGShaderID)); 1042 } 1043 GL_CALL(AttachShader(progID, programData->fFShaderID)); 1044 1045 if (bindColorOut) { 1046 GL_CALL(BindFragDataLocation(programData->fProgramID, 1047 0, declared_color_output_name())); 1048 } 1049 if (bindDualSrcOut) { 1050 GL_CALL(BindFragDataLocationIndexed(programData->fProgramID, 1051 0, 1, dual_source_output_name())); 1052 } 1053 1054 // Bind the attrib locations to same values for all shaders 1055 GL_CALL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME)); 1056 for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { 1057 if (texCoordAttrNames[t].size()) { 1058 GL_CALL(BindAttribLocation(progID, 1059 TexCoordAttributeIdx(t), 1060 texCoordAttrNames[t].c_str())); 1061 } 1062 } 1063 1064 GL_CALL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME)); 1065 GL_CALL(BindAttribLocation(progID, CoverageAttributeIdx(), COV_ATTR_NAME)); 1066 GL_CALL(BindAttribLocation(progID, EdgeAttributeIdx(), EDGE_ATTR_NAME)); 1067 1068 GL_CALL(LinkProgram(progID)); 1069 1070 GrGLint linked = GR_GL_INIT_ZERO; 1071 GL_CALL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked)); 1072 if (!linked) { 1073 GrGLint infoLen = GR_GL_INIT_ZERO; 1074 GL_CALL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen)); 1075 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger 1076 if (infoLen > 0) { 1077 // retrieve length even though we don't need it to workaround 1078 // bug in chrome cmd buffer param validation. 1079 GrGLsizei length = GR_GL_INIT_ZERO; 1080 GL_CALL(GetProgramInfoLog(progID, 1081 infoLen+1, 1082 &length, 1083 (char*)log.get())); 1084 GrPrintf((char*)log.get()); 1085 } 1086 GrAssert(!"Error linking program"); 1087 GL_CALL(DeleteProgram(progID)); 1088 programData->fProgramID = 0; 1089 return false; 1090 } 1091 return true; 1092} 1093 1094void GrGLProgram::getUniformLocationsAndInitCache(const GrGLContextInfo& gl, 1095 CachedData* programData) const { 1096 const GrGLint& progID = programData->fProgramID; 1097 1098 if (kUseUniform == programData->fUniLocations.fViewMatrixUni) { 1099 GL_CALL_RET(programData->fUniLocations.fViewMatrixUni, 1100 GetUniformLocation(progID, VIEW_MATRIX_NAME)); 1101 GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni); 1102 } 1103 if (kUseUniform == programData->fUniLocations.fColorUni) { 1104 GL_CALL_RET(programData->fUniLocations.fColorUni, 1105 GetUniformLocation(progID, COL_UNI_NAME)); 1106 GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni); 1107 } 1108 if (kUseUniform == programData->fUniLocations.fColorFilterUni) { 1109 GL_CALL_RET(programData->fUniLocations.fColorFilterUni, 1110 GetUniformLocation(progID, COL_FILTER_UNI_NAME)); 1111 GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni); 1112 } 1113 1114 if (kUseUniform == programData->fUniLocations.fColorMatrixUni) { 1115 GL_CALL_RET(programData->fUniLocations.fColorMatrixUni, 1116 GetUniformLocation(progID, COL_MATRIX_UNI_NAME)); 1117 } 1118 1119 if (kUseUniform == programData->fUniLocations.fColorMatrixVecUni) { 1120 GL_CALL_RET(programData->fUniLocations.fColorMatrixVecUni, 1121 GetUniformLocation(progID, COL_MATRIX_VEC_UNI_NAME)); 1122 } 1123 if (kUseUniform == programData->fUniLocations.fCoverageUni) { 1124 GL_CALL_RET(programData->fUniLocations.fCoverageUni, 1125 GetUniformLocation(progID, COV_UNI_NAME)); 1126 GrAssert(kUnusedUniform != programData->fUniLocations.fCoverageUni); 1127 } 1128 1129 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 1130 StageUniLocations& locations = programData->fUniLocations.fStages[s]; 1131 if (fProgramDesc.fStages[s].isEnabled()) { 1132 if (kUseUniform == locations.fTextureMatrixUni) { 1133 GrStringBuilder texMName; 1134 tex_matrix_name(s, &texMName); 1135 GL_CALL_RET(locations.fTextureMatrixUni, 1136 GetUniformLocation(progID, texMName.c_str())); 1137 GrAssert(kUnusedUniform != locations.fTextureMatrixUni); 1138 } 1139 1140 if (kUseUniform == locations.fSamplerUni) { 1141 GrStringBuilder samplerName; 1142 sampler_name(s, &samplerName); 1143 GL_CALL_RET(locations.fSamplerUni, 1144 GetUniformLocation(progID,samplerName.c_str())); 1145 GrAssert(kUnusedUniform != locations.fSamplerUni); 1146 } 1147 1148 if (kUseUniform == locations.fTexDomUni) { 1149 GrStringBuilder texDomName; 1150 tex_domain_name(s, &texDomName); 1151 GL_CALL_RET(locations.fTexDomUni, 1152 GetUniformLocation(progID, texDomName.c_str())); 1153 GrAssert(kUnusedUniform != locations.fTexDomUni); 1154 } 1155 1156 if (NULL != programData->fCustomStage[s]) { 1157 programData->fCustomStage[s]-> 1158 initUniforms(gl.interface(), progID); 1159 } 1160 } 1161 } 1162 GL_CALL(UseProgram(progID)); 1163 1164 // init sampler unis and set bogus values for state tracking 1165 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 1166 if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) { 1167 GL_CALL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s)); 1168 } 1169 programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix(); 1170 programData->fTextureWidth[s] = -1; 1171 programData->fTextureHeight[s] = -1; 1172 programData->fTextureDomain[s].setEmpty(); 1173 // this is arbitrary, just initialize to something 1174 programData->fTextureOrientation[s] = 1175 GrGLTexture::kBottomUp_Orientation; 1176 // Must not reset fStageOverride[] here. 1177 } 1178 programData->fViewMatrix = GrMatrix::InvalidMatrix(); 1179 programData->fViewportSize.set(-1, -1); 1180 programData->fColor = GrColor_ILLEGAL; 1181 programData->fColorFilterColor = GrColor_ILLEGAL; 1182} 1183 1184//============================================================================ 1185// Stage code generation 1186//============================================================================ 1187 1188void GrGLProgram::genStageCode(const GrGLContextInfo& gl, 1189 int stageNum, 1190 const GrGLProgram::StageDesc& desc, 1191 const char* fsInColor, // NULL means no incoming color 1192 const char* fsOutColor, 1193 const char* vsInCoord, 1194 GrGLShaderBuilder* segments, 1195 StageUniLocations* locations, 1196 GrGLProgramStage* customStage) const { 1197 1198 GrAssert(stageNum >= 0 && stageNum <= GrDrawState::kNumStages); 1199 GrAssert((desc.fInConfigFlags & StageDesc::kInConfigBitMask) == 1200 desc.fInConfigFlags); 1201 1202 /// Vertex Shader Stuff 1203 1204 // decide whether we need a matrix to transform texture coords 1205 // and whether the varying needs a perspective coord. 1206 const char* matName = NULL; 1207 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) { 1208 segments->fVaryingDims = segments->fCoordDims; 1209 } else { 1210 GrStringBuilder texMatName; 1211 tex_matrix_name(stageNum, &texMatName); 1212 const GrGLShaderVar* mat = &segments->addUniform( 1213 GrGLShaderBuilder::kVertex_VariableLifetime, kMat33f_GrSLType, 1214 texMatName.c_str()); 1215 // Can't use texMatName.c_str() because it's on the stack! 1216 matName = mat->getName().c_str(); 1217 locations->fTextureMatrixUni = kUseUniform; 1218 1219 if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) { 1220 segments->fVaryingDims = segments->fCoordDims; 1221 } else { 1222 segments->fVaryingDims = segments->fCoordDims + 1; 1223 } 1224 } 1225 GrAssert(segments->fVaryingDims > 0); 1226 1227 // Must setup variables after computing segments->fVaryingDims 1228 if (NULL != customStage) { 1229 customStage->setupVariables(segments, stageNum); 1230 } 1231 1232 GrStringBuilder samplerName; 1233 sampler_name(stageNum, &samplerName); 1234 const GrGLShaderVar* sampler = &segments->addUniform( 1235 GrGLShaderBuilder::kFragment_VariableLifetime, kSampler2D_GrSLType, 1236 samplerName.c_str()); 1237 locations->fSamplerUni = kUseUniform; 1238 1239 const char *varyingVSName, *varyingFSName; 1240 segments->addVarying(GrSLFloatVectorType(segments->fVaryingDims), 1241 "Stage", 1242 stageNum, 1243 &varyingVSName, 1244 &varyingFSName); 1245 1246 if (!matName) { 1247 GrAssert(segments->fVaryingDims == segments->fCoordDims); 1248 segments->fVSCode.appendf("\t%s = %s;\n", varyingVSName, vsInCoord); 1249 } else { 1250 // varying = texMatrix * texCoord 1251 segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n", 1252 varyingVSName, matName, vsInCoord, 1253 vector_all_coords(segments->fVaryingDims)); 1254 } 1255 1256 GrGLShaderVar* kernel = NULL; 1257 const char* imageIncrementName = NULL; 1258 if (NULL != customStage) { 1259 segments->fVSCode.appendf("\t{ // stage %d %s\n", 1260 stageNum, customStage->name()); 1261 customStage->emitVS(segments, varyingVSName); 1262 segments->fVSCode.appendf("\t}\n"); 1263 } 1264 1265 /// Fragment Shader Stuff 1266 1267 segments->fSampleCoords = varyingFSName; 1268 1269 GrGLShaderBuilder::SamplerMode sampleMode = 1270 GrGLShaderBuilder::kExplicitDivide_SamplerMode; 1271 if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit | 1272 StageDesc::kNoPerspective_OptFlagBit)) { 1273 sampleMode = GrGLShaderBuilder::kDefault_SamplerMode; 1274 } else if (NULL == customStage) { 1275 sampleMode = GrGLShaderBuilder::kProj_SamplerMode; 1276 } 1277 segments->setupTextureAccess(sampleMode, stageNum); 1278 1279 segments->computeSwizzle(desc.fInConfigFlags); 1280 segments->computeModulate(fsInColor); 1281 1282 static const uint32_t kMulByAlphaMask = 1283 (StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag | 1284 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag); 1285 1286 if (desc.fOptFlags & StageDesc::kCustomTextureDomain_OptFlagBit) { 1287 GrStringBuilder texDomainName; 1288 tex_domain_name(stageNum, &texDomainName); 1289 const GrGLShaderVar* texDomain = 1290 &segments->addUniform( 1291 GrGLShaderBuilder::kFragment_VariableLifetime, 1292 kVec4f_GrSLType, texDomainName.c_str()); 1293 GrStringBuilder coordVar("clampCoord"); 1294 segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n", 1295 float_vector_type_str(segments->fCoordDims), 1296 coordVar.c_str(), 1297 segments->fSampleCoords.c_str(), 1298 texDomainName.c_str(), 1299 texDomainName.c_str()); 1300 segments->fSampleCoords = coordVar; 1301 locations->fTexDomUni = kUseUniform; 1302 } 1303 1304 // NOTE: GrGLProgramStages are now responsible for fetching 1305 if (NULL == customStage) { 1306 if (desc.fInConfigFlags & kMulByAlphaMask) { 1307 // only one of the mul by alpha flags should be set 1308 GrAssert(GrIsPow2(kMulByAlphaMask & desc.fInConfigFlags)); 1309 GrAssert(!(desc.fInConfigFlags & 1310 StageDesc::kSmearAlpha_InConfigFlag)); 1311 GrAssert(!(desc.fInConfigFlags & 1312 StageDesc::kSmearRed_InConfigFlag)); 1313 segments->fFSCode.appendf("\t%s = %s(%s, %s)%s;\n", 1314 fsOutColor, 1315 segments->fTexFunc.c_str(), 1316 samplerName.c_str(), 1317 segments->fSampleCoords.c_str(), 1318 segments->fSwizzle.c_str()); 1319 if (desc.fInConfigFlags & 1320 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag) { 1321 segments->fFSCode.appendf("\t%s = vec4(ceil(%s.rgb*%s.a*255.0)/255.0,%s.a)%s;\n", 1322 fsOutColor, fsOutColor, fsOutColor, 1323 fsOutColor, segments->fModulate.c_str()); 1324 } else { 1325 segments->fFSCode.appendf("\t%s = vec4(floor(%s.rgb*%s.a*255.0)/255.0,%s.a)%s;\n", 1326 fsOutColor, fsOutColor, fsOutColor, 1327 fsOutColor, segments->fModulate.c_str()); 1328 } 1329 } else { 1330 segments->emitDefaultFetch(fsOutColor, samplerName.c_str()); 1331 } 1332 } 1333 1334 if (NULL != customStage) { 1335 // Enclose custom code in a block to avoid namespace conflicts 1336 segments->fFSCode.appendf("\t{ // stage %d %s \n", 1337 stageNum, customStage->name()); 1338 customStage->emitFS(segments, fsOutColor, fsInColor, 1339 samplerName.c_str()); 1340 segments->fFSCode.appendf("\t}\n"); 1341 } 1342} 1343 1344 1345