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