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