GrGLProgram.cpp revision 261dc569b6a53729bea6e4e7a0cf2afa980eb82d
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 "GrEffect.h" 12#include "GrCoordTransform.h" 13#include "GrDrawEffect.h" 14#include "GrGLEffect.h" 15#include "GrGpuGL.h" 16#include "GrGLShaderVar.h" 17#include "GrGLSL.h" 18#include "SkXfermode.h" 19 20SK_DEFINE_INST_COUNT(GrGLProgram) 21 22#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X) 23#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X) 24 25GrGLProgram* GrGLProgram::Create(GrGpuGL* gpu, 26 const GrGLProgramDesc& desc, 27 const GrEffectStage* colorStages[], 28 const GrEffectStage* coverageStages[]) { 29 GrGLProgram* program = SkNEW_ARGS(GrGLProgram, (gpu, desc, colorStages, coverageStages)); 30 if (!program->succeeded()) { 31 delete program; 32 program = NULL; 33 } 34 return program; 35} 36 37GrGLProgram::GrGLProgram(GrGpuGL* gpu, 38 const GrGLProgramDesc& desc, 39 const GrEffectStage* colorStages[], 40 const GrEffectStage* coverageStages[]) 41: fGpu(gpu) 42, fUniformManager(gpu) { 43 fDesc = desc; 44 fProgramID = 0; 45 46 fDstCopyTexUnit = -1; 47 48 fColor = GrColor_ILLEGAL; 49 fColorFilterColor = GrColor_ILLEGAL; 50 51 this->genProgram(colorStages, coverageStages); 52} 53 54GrGLProgram::~GrGLProgram() { 55 if (fProgramID) { 56 GL_CALL(DeleteProgram(fProgramID)); 57 } 58} 59 60void GrGLProgram::abandon() { 61 fProgramID = 0; 62} 63 64void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff, 65 GrBlendCoeff* dstCoeff) const { 66 switch (fDesc.getHeader().fCoverageOutput) { 67 case GrGLProgramDesc::kModulate_CoverageOutput: 68 break; 69 // The prog will write a coverage value to the secondary 70 // output and the dst is blended by one minus that value. 71 case GrGLProgramDesc::kSecondaryCoverage_CoverageOutput: 72 case GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput: 73 case GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput: 74 *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; 75 break; 76 case GrGLProgramDesc::kCombineWithDst_CoverageOutput: 77 // We should only have set this if the blend was specified as (1, 0) 78 SkASSERT(kOne_GrBlendCoeff == *srcCoeff && kZero_GrBlendCoeff == *dstCoeff); 79 break; 80 default: 81 GrCrash("Unexpected coverage output"); 82 break; 83 } 84} 85 86namespace { 87// given two blend coefficients determine whether the src 88// and/or dst computation can be omitted. 89inline void need_blend_inputs(SkXfermode::Coeff srcCoeff, 90 SkXfermode::Coeff dstCoeff, 91 bool* needSrcValue, 92 bool* needDstValue) { 93 if (SkXfermode::kZero_Coeff == srcCoeff) { 94 switch (dstCoeff) { 95 // these all read the src 96 case SkXfermode::kSC_Coeff: 97 case SkXfermode::kISC_Coeff: 98 case SkXfermode::kSA_Coeff: 99 case SkXfermode::kISA_Coeff: 100 *needSrcValue = true; 101 break; 102 default: 103 *needSrcValue = false; 104 break; 105 } 106 } else { 107 *needSrcValue = true; 108 } 109 if (SkXfermode::kZero_Coeff == dstCoeff) { 110 switch (srcCoeff) { 111 // these all read the dst 112 case SkXfermode::kDC_Coeff: 113 case SkXfermode::kIDC_Coeff: 114 case SkXfermode::kDA_Coeff: 115 case SkXfermode::kIDA_Coeff: 116 *needDstValue = true; 117 break; 118 default: 119 *needDstValue = false; 120 break; 121 } 122 } else { 123 *needDstValue = true; 124 } 125} 126 127/** 128 * Create a blend_coeff * value string to be used in shader code. Sets empty 129 * string if result is trivially zero. 130 */ 131inline void blend_term_string(SkString* str, SkXfermode::Coeff coeff, 132 const char* src, const char* dst, 133 const char* value) { 134 switch (coeff) { 135 case SkXfermode::kZero_Coeff: /** 0 */ 136 *str = ""; 137 break; 138 case SkXfermode::kOne_Coeff: /** 1 */ 139 *str = value; 140 break; 141 case SkXfermode::kSC_Coeff: 142 str->printf("(%s * %s)", src, value); 143 break; 144 case SkXfermode::kISC_Coeff: 145 str->printf("((%s - %s) * %s)", GrGLSLOnesVecf(4), src, value); 146 break; 147 case SkXfermode::kDC_Coeff: 148 str->printf("(%s * %s)", dst, value); 149 break; 150 case SkXfermode::kIDC_Coeff: 151 str->printf("((%s - %s) * %s)", GrGLSLOnesVecf(4), dst, value); 152 break; 153 case SkXfermode::kSA_Coeff: /** src alpha */ 154 str->printf("(%s.a * %s)", src, value); 155 break; 156 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */ 157 str->printf("((1.0 - %s.a) * %s)", src, value); 158 break; 159 case SkXfermode::kDA_Coeff: /** dst alpha */ 160 str->printf("(%s.a * %s)", dst, value); 161 break; 162 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */ 163 str->printf("((1.0 - %s.a) * %s)", dst, value); 164 break; 165 default: 166 GrCrash("Unexpected xfer coeff."); 167 break; 168 } 169} 170/** 171 * Adds a line to the fragment shader code which modifies the color by 172 * the specified color filter. 173 */ 174void add_color_filter(GrGLShaderBuilder* builder, 175 const char * outputVar, 176 SkXfermode::Coeff uniformCoeff, 177 SkXfermode::Coeff colorCoeff, 178 const char* filterColor, 179 const char* inColor) { 180 SkString colorStr, constStr; 181 blend_term_string(&colorStr, colorCoeff, filterColor, inColor, inColor); 182 blend_term_string(&constStr, uniformCoeff, filterColor, inColor, filterColor); 183 184 SkString sum; 185 GrGLSLAddf<4>(&sum, colorStr.c_str(), constStr.c_str()); 186 builder->fsCodeAppendf("\t%s = %s;\n", outputVar, sum.c_str()); 187} 188} 189 190namespace { 191 192void expand_known_value4f(SkString* string, GrSLConstantVec vec) { 193 SkASSERT(string->isEmpty() == (vec != kNone_GrSLConstantVec)); 194 switch (vec) { 195 case kNone_GrSLConstantVec: 196 break; 197 case kZeros_GrSLConstantVec: 198 *string = GrGLSLZerosVecf(4); 199 break; 200 case kOnes_GrSLConstantVec: 201 *string = GrGLSLOnesVecf(4); 202 break; 203 } 204} 205 206} 207 208bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], 209 const GrEffectStage* coverageStages[]) { 210 SkASSERT(0 == fProgramID); 211 212 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); 213 214 GrGLFullShaderBuilder builder(fGpu, fUniformManager, fDesc); 215 fUniformHandles.fViewMatrixUni = builder.getViewMatrixUniform(); 216 217 // incoming color to current stage being processed. 218 SkString inColor = builder.getInputColor(); 219 GrSLConstantVec knownColorValue = builder.getKnownColorValue(); 220 221 // Get the coeffs for the Mode-based color filter, determine if color is needed. 222 SkXfermode::Coeff colorCoeff; 223 SkXfermode::Coeff filterColorCoeff; 224 SkAssertResult( 225 SkXfermode::ModeAsCoeff(header.fColorFilterXfermode, 226 &filterColorCoeff, 227 &colorCoeff)); 228 bool needColor, needFilterColor; 229 need_blend_inputs(filterColorCoeff, colorCoeff, &needFilterColor, &needColor); 230 231 fColorEffects.reset( 232 builder.createAndEmitEffects(colorStages, 233 fDesc.effectKeys(), 234 needColor ? fDesc.numColorEffects() : 0, 235 &inColor, 236 &knownColorValue)); 237 238 // Insert the color filter. This will soon be replaced by a color effect. 239 if (SkXfermode::kDst_Mode != header.fColorFilterXfermode) { 240 const char* colorFilterColorUniName = NULL; 241 fUniformHandles.fColorFilterUni = builder.addUniform(GrGLShaderBuilder::kFragment_Visibility, 242 kVec4f_GrSLType, "FilterColor", 243 &colorFilterColorUniName); 244 245 builder.fsCodeAppend("\tvec4 filteredColor;\n"); 246 const char* color; 247 // add_color_filter requires a real input string. 248 if (knownColorValue == kOnes_GrSLConstantVec) { 249 color = GrGLSLOnesVecf(4); 250 } else if (knownColorValue == kZeros_GrSLConstantVec) { 251 color = GrGLSLZerosVecf(4); 252 } else { 253 color = inColor.c_str(); 254 } 255 add_color_filter(&builder, "filteredColor", filterColorCoeff, 256 colorCoeff, colorFilterColorUniName, color); 257 inColor = "filteredColor"; 258 } 259 260 /////////////////////////////////////////////////////////////////////////// 261 // compute the partial coverage 262 SkString inCoverage = builder.getInputCoverage(); 263 GrSLConstantVec knownCoverageValue = builder.getKnownCoverageValue(); 264 265 fCoverageEffects.reset( 266 builder.createAndEmitEffects(coverageStages, 267 fDesc.getEffectKeys() + fDesc.numColorEffects(), 268 fDesc.numCoverageEffects(), 269 &inCoverage, 270 &knownCoverageValue)); 271 272 // discard if coverage is zero 273 if (header.fDiscardIfZeroCoverage && kOnes_GrSLConstantVec != knownCoverageValue) { 274 if (kZeros_GrSLConstantVec == knownCoverageValue) { 275 // This is unfortunate. 276 builder.fsCodeAppend("\tdiscard;\n"); 277 } else { 278 builder.fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n", 279 inCoverage.c_str()); 280 } 281 } 282 283 if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) { 284 const char* secondaryOutputName = builder.enableSecondaryOutput(); 285 286 // default coeff to ones for kCoverage_DualSrcOutput 287 SkString coeff; 288 GrSLConstantVec knownCoeffValue = kOnes_GrSLConstantVec; 289 if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) { 290 // Get (1-A) into coeff 291 SkString inColorAlpha; 292 GrGLSLGetComponent4f(&inColorAlpha, 293 inColor.c_str(), 294 kA_GrColorComponentFlag, 295 knownColorValue, 296 true); 297 knownCoeffValue = GrGLSLSubtractf<1>(&coeff, 298 NULL, 299 inColorAlpha.c_str(), 300 kOnes_GrSLConstantVec, 301 knownColorValue, 302 true); 303 } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == header.fCoverageOutput) { 304 // Get (1-RGBA) into coeff 305 knownCoeffValue = GrGLSLSubtractf<4>(&coeff, 306 NULL, 307 inColor.c_str(), 308 kOnes_GrSLConstantVec, 309 knownColorValue, 310 true); 311 } 312 // Get coeff * coverage into modulate and then write that to the dual source output. 313 SkString modulate; 314 GrGLSLModulatef<4>(&modulate, 315 coeff.c_str(), 316 inCoverage.c_str(), 317 knownCoeffValue, 318 knownCoverageValue, 319 false); 320 builder.fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, modulate.c_str()); 321 } 322 323 /////////////////////////////////////////////////////////////////////////// 324 // combine color and coverage as frag color 325 326 // Get "color * coverage" into fragColor 327 SkString fragColor; 328 GrSLConstantVec knownFragColorValue = GrGLSLModulatef<4>(&fragColor, 329 inColor.c_str(), 330 inCoverage.c_str(), 331 knownColorValue, 332 knownCoverageValue, 333 true); 334 // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so. 335 if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) { 336 SkString dstCoeff; 337 GrSLConstantVec knownDstCoeffValue = GrGLSLSubtractf<4>(&dstCoeff, 338 NULL, 339 inCoverage.c_str(), 340 kOnes_GrSLConstantVec, 341 knownCoverageValue, 342 true); 343 SkString dstContribution; 344 GrSLConstantVec knownDstContributionValue = GrGLSLModulatef<4>(&dstContribution, 345 dstCoeff.c_str(), 346 builder.dstColor(), 347 knownDstCoeffValue, 348 kNone_GrSLConstantVec, 349 true); 350 SkString oldFragColor = fragColor; 351 fragColor.reset(); 352 GrGLSLAddf<4>(&fragColor, 353 oldFragColor.c_str(), 354 dstContribution.c_str(), 355 knownFragColorValue, 356 knownDstContributionValue, 357 false); 358 } else { 359 expand_known_value4f(&fragColor, knownFragColorValue); 360 } 361 builder.fsCodeAppendf("\t%s = %s;\n", builder.getColorOutputName(), fragColor.c_str()); 362 363 if (!builder.finish(&fProgramID)) { 364 return false; 365 } 366 367 fUniformHandles.fRTHeightUni = builder.getRTHeightUniform(); 368 fUniformHandles.fDstCopyTopLeftUni = builder.getDstCopyTopLeftUniform(); 369 fUniformHandles.fDstCopyScaleUni = builder.getDstCopyScaleUniform(); 370 fUniformHandles.fColorUni = builder.getColorUniform(); 371 fUniformHandles.fCoverageUni = builder.getCoverageUniform(); 372 fUniformHandles.fDstCopySamplerUni = builder.getDstCopySamplerUniform(); 373 // This must be called after we set fDstCopySamplerUni above. 374 this->initSamplerUniforms(); 375 376 return true; 377} 378 379void GrGLProgram::initSamplerUniforms() { 380 GL_CALL(UseProgram(fProgramID)); 381 GrGLint texUnitIdx = 0; 382 if (fUniformHandles.fDstCopySamplerUni.isValid()) { 383 fUniformManager.setSampler(fUniformHandles.fDstCopySamplerUni, texUnitIdx); 384 fDstCopyTexUnit = texUnitIdx++; 385 } 386 fColorEffects->initSamplers(fUniformManager, &texUnitIdx); 387 fCoverageEffects->initSamplers(fUniformManager, &texUnitIdx); 388} 389 390/////////////////////////////////////////////////////////////////////////////// 391 392void GrGLProgram::setData(GrDrawState::BlendOptFlags blendOpts, 393 const GrEffectStage* colorStages[], 394 const GrEffectStage* coverageStages[], 395 const GrDeviceCoordTexture* dstCopy, 396 SharedGLState* sharedState) { 397 const GrDrawState& drawState = fGpu->getDrawState(); 398 399 GrColor color; 400 GrColor coverage; 401 if (blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag) { 402 color = 0; 403 coverage = 0; 404 } else if (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) { 405 color = 0xffffffff; 406 coverage = drawState.getCoverage(); 407 } else { 408 color = drawState.getColor(); 409 coverage = drawState.getCoverage(); 410 } 411 412 this->setColor(drawState, color, sharedState); 413 this->setCoverage(drawState, coverage, sharedState); 414 this->setMatrixAndRenderTargetHeight(drawState); 415 416 // Setup the SkXfermode::Mode-based colorfilter uniform if necessary 417 if (fUniformHandles.fColorFilterUni.isValid() && 418 fColorFilterColor != drawState.getColorFilterColor()) { 419 GrGLfloat c[4]; 420 GrColorToRGBAFloat(drawState.getColorFilterColor(), c); 421 fUniformManager.set4fv(fUniformHandles.fColorFilterUni, 0, 1, c); 422 fColorFilterColor = drawState.getColorFilterColor(); 423 } 424 425 if (NULL != dstCopy) { 426 if (fUniformHandles.fDstCopyTopLeftUni.isValid()) { 427 fUniformManager.set2f(fUniformHandles.fDstCopyTopLeftUni, 428 static_cast<GrGLfloat>(dstCopy->offset().fX), 429 static_cast<GrGLfloat>(dstCopy->offset().fY)); 430 fUniformManager.set2f(fUniformHandles.fDstCopyScaleUni, 431 1.f / dstCopy->texture()->width(), 432 1.f / dstCopy->texture()->height()); 433 GrGLTexture* texture = static_cast<GrGLTexture*>(dstCopy->texture()); 434 static GrTextureParams kParams; // the default is clamp, nearest filtering. 435 fGpu->bindTexture(fDstCopyTexUnit, kParams, texture); 436 } else { 437 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid()); 438 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid()); 439 } 440 } else { 441 SkASSERT(!fUniformHandles.fDstCopyTopLeftUni.isValid()); 442 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid()); 443 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid()); 444 } 445 446 fColorEffects->setData(fGpu, fUniformManager, colorStages); 447 fCoverageEffects->setData(fGpu, fUniformManager, coverageStages); 448} 449 450void GrGLProgram::setColor(const GrDrawState& drawState, 451 GrColor color, 452 SharedGLState* sharedState) { 453 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); 454 if (!drawState.hasColorVertexAttribute()) { 455 switch (header.fColorInput) { 456 case GrGLProgramDesc::kAttribute_ColorInput: 457 SkASSERT(-1 != header.fColorAttributeIndex); 458 if (sharedState->fConstAttribColor != color || 459 sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) { 460 // OpenGL ES only supports the float varieties of glVertexAttrib 461 GrGLfloat c[4]; 462 GrColorToRGBAFloat(color, c); 463 GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c)); 464 sharedState->fConstAttribColor = color; 465 sharedState->fConstAttribColorIndex = header.fColorAttributeIndex; 466 } 467 break; 468 case GrGLProgramDesc::kUniform_ColorInput: 469 if (fColor != color) { 470 // OpenGL ES doesn't support unsigned byte varieties of glUniform 471 GrGLfloat c[4]; 472 GrColorToRGBAFloat(color, c); 473 fUniformManager.set4fv(fUniformHandles.fColorUni, 0, 1, c); 474 fColor = color; 475 } 476 sharedState->fConstAttribColorIndex = -1; 477 break; 478 case GrGLProgramDesc::kSolidWhite_ColorInput: 479 case GrGLProgramDesc::kTransBlack_ColorInput: 480 sharedState->fConstAttribColorIndex = -1; 481 break; 482 default: 483 GrCrash("Unknown color type."); 484 } 485 } else { 486 sharedState->fConstAttribColorIndex = -1; 487 } 488} 489 490void GrGLProgram::setCoverage(const GrDrawState& drawState, 491 GrColor coverage, 492 SharedGLState* sharedState) { 493 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); 494 if (!drawState.hasCoverageVertexAttribute()) { 495 switch (header.fCoverageInput) { 496 case GrGLProgramDesc::kAttribute_ColorInput: 497 if (sharedState->fConstAttribCoverage != coverage || 498 sharedState->fConstAttribCoverageIndex != header.fCoverageAttributeIndex) { 499 // OpenGL ES only supports the float varieties of glVertexAttrib 500 GrGLfloat c[4]; 501 GrColorToRGBAFloat(coverage, c); 502 GL_CALL(VertexAttrib4fv(header.fCoverageAttributeIndex, c)); 503 sharedState->fConstAttribCoverage = coverage; 504 sharedState->fConstAttribCoverageIndex = header.fCoverageAttributeIndex; 505 } 506 break; 507 case GrGLProgramDesc::kUniform_ColorInput: 508 if (fCoverage != coverage) { 509 // OpenGL ES doesn't support unsigned byte varieties of glUniform 510 GrGLfloat c[4]; 511 GrColorToRGBAFloat(coverage, c); 512 fUniformManager.set4fv(fUniformHandles.fCoverageUni, 0, 1, c); 513 fCoverage = coverage; 514 } 515 sharedState->fConstAttribCoverageIndex = -1; 516 break; 517 case GrGLProgramDesc::kSolidWhite_ColorInput: 518 case GrGLProgramDesc::kTransBlack_ColorInput: 519 sharedState->fConstAttribCoverageIndex = -1; 520 break; 521 default: 522 GrCrash("Unknown coverage type."); 523 } 524 } else { 525 sharedState->fConstAttribCoverageIndex = -1; 526 } 527} 528 529void GrGLProgram::setMatrixAndRenderTargetHeight(const GrDrawState& drawState) { 530 const GrRenderTarget* rt = drawState.getRenderTarget(); 531 SkISize size; 532 size.set(rt->width(), rt->height()); 533 534 // Load the RT height uniform if it is needed to y-flip gl_FragCoord. 535 if (fUniformHandles.fRTHeightUni.isValid() && 536 fMatrixState.fRenderTargetSize.fHeight != size.fHeight) { 537 fUniformManager.set1f(fUniformHandles.fRTHeightUni, SkIntToScalar(size.fHeight)); 538 } 539 540 if (fMatrixState.fRenderTargetOrigin != rt->origin() || 541 !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix()) || 542 fMatrixState.fRenderTargetSize != size) { 543 544 fMatrixState.fViewMatrix = drawState.getViewMatrix(); 545 fMatrixState.fRenderTargetSize = size; 546 fMatrixState.fRenderTargetOrigin = rt->origin(); 547 548 GrGLfloat viewMatrix[3 * 3]; 549 fMatrixState.getGLMatrix<3>(viewMatrix); 550 fUniformManager.setMatrix3f(fUniformHandles.fViewMatrixUni, viewMatrix); 551 } 552} 553