GrGpuGL_program.cpp revision cc78238f0b6aa1a7b3fc767758d9eeef4c1bffa9
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 "GrGpuGL.h" 9 10#include "GrEffect.h" 11#include "GrGLEffect.h" 12#include "GrGpuVertex.h" 13 14typedef GrGLUniformManager::UniformHandle UniformHandle; 15static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle; 16 17#define SKIP_CACHE_CHECK true 18#define GR_UINT32_MAX static_cast<uint32_t>(-1) 19 20GrGpuGL::ProgramCache::ProgramCache(const GrGLContextInfo& gl) 21 : fCount(0) 22 , fCurrLRUStamp(0) 23 , fGL(gl) { 24} 25 26void GrGpuGL::ProgramCache::abandon() { 27 for (int i = 0; i < fCount; ++i) { 28 GrAssert(NULL != fEntries[i].fProgram.get()); 29 fEntries[i].fProgram->abandon(); 30 fEntries[i].fProgram.reset(NULL); 31 } 32 fCount = 0; 33} 34 35GrGLProgram* GrGpuGL::ProgramCache::getProgram(const ProgramDesc& desc, 36 const GrEffectStage* stages[]) { 37 Entry newEntry; 38 newEntry.fKey.setKeyData(desc.asKey()); 39 40 Entry* entry = fHashCache.find(newEntry.fKey); 41 if (NULL == entry) { 42 newEntry.fProgram.reset(GrGLProgram::Create(fGL, desc, stages)); 43 if (NULL == newEntry.fProgram.get()) { 44 return NULL; 45 } 46 if (fCount < kMaxEntries) { 47 entry = fEntries + fCount; 48 ++fCount; 49 } else { 50 GrAssert(kMaxEntries == fCount); 51 entry = fEntries; 52 for (int i = 1; i < kMaxEntries; ++i) { 53 if (fEntries[i].fLRUStamp < entry->fLRUStamp) { 54 entry = fEntries + i; 55 } 56 } 57 fHashCache.remove(entry->fKey, entry); 58 } 59 *entry = newEntry; 60 fHashCache.insert(entry->fKey, entry); 61 } 62 63 entry->fLRUStamp = fCurrLRUStamp; 64 if (GR_UINT32_MAX == fCurrLRUStamp) { 65 // wrap around! just trash our LRU, one time hit. 66 for (int i = 0; i < fCount; ++i) { 67 fEntries[i].fLRUStamp = 0; 68 } 69 } 70 ++fCurrLRUStamp; 71 return entry->fProgram; 72} 73 74//////////////////////////////////////////////////////////////////////////////// 75 76void GrGpuGL::abandonResources(){ 77 INHERITED::abandonResources(); 78 fProgramCache->abandon(); 79 fHWProgramID = 0; 80} 81 82//////////////////////////////////////////////////////////////////////////////// 83 84#define GL_CALL(X) GR_GL_CALL(this->glInterface(), X) 85 86void GrGpuGL::flushViewMatrix(DrawType type) { 87 const GrGLRenderTarget* rt = static_cast<const GrGLRenderTarget*>(this->getDrawState().getRenderTarget()); 88 SkISize viewportSize; 89 const GrGLIRect& viewport = rt->getViewport(); 90 viewportSize.set(viewport.fWidth, viewport.fHeight); 91 92 const SkMatrix& vm = this->getDrawState().getViewMatrix(); 93 94 if (kStencilPath_DrawType == type) { 95 if (fHWPathMatrixState.fViewMatrix != vm || 96 fHWPathMatrixState.fRTSize != viewportSize) { 97 // rescale the coords from skia's "device" coords to GL's normalized coords, 98 // and perform a y-flip. 99 SkMatrix m; 100 m.setScale(SkIntToScalar(2) / rt->width(), SkIntToScalar(-2) / rt->height()); 101 m.postTranslate(-SK_Scalar1, SK_Scalar1); 102 m.preConcat(vm); 103 104 // GL wants a column-major 4x4. 105 GrGLfloat mv[] = { 106 // col 0 107 SkScalarToFloat(m[SkMatrix::kMScaleX]), 108 SkScalarToFloat(m[SkMatrix::kMSkewY]), 109 0, 110 SkScalarToFloat(m[SkMatrix::kMPersp0]), 111 112 // col 1 113 SkScalarToFloat(m[SkMatrix::kMSkewX]), 114 SkScalarToFloat(m[SkMatrix::kMScaleY]), 115 0, 116 SkScalarToFloat(m[SkMatrix::kMPersp1]), 117 118 // col 2 119 0, 0, 0, 0, 120 121 // col3 122 SkScalarToFloat(m[SkMatrix::kMTransX]), 123 SkScalarToFloat(m[SkMatrix::kMTransY]), 124 0.0f, 125 SkScalarToFloat(m[SkMatrix::kMPersp2]) 126 }; 127 GL_CALL(MatrixMode(GR_GL_PROJECTION)); 128 GL_CALL(LoadMatrixf(mv)); 129 fHWPathMatrixState.fViewMatrix = vm; 130 fHWPathMatrixState.fRTSize = viewportSize; 131 } 132 } else if (!fCurrentProgram->fViewMatrix.cheapEqualTo(vm) || 133 fCurrentProgram->fViewportSize != viewportSize) { 134 SkMatrix m; 135 m.setAll( 136 SkIntToScalar(2) / viewportSize.fWidth, 0, -SK_Scalar1, 137 0,-SkIntToScalar(2) / viewportSize.fHeight, SK_Scalar1, 138 0, 0, SkMatrix::I()[8]); 139 m.setConcat(m, vm); 140 141 // ES doesn't allow you to pass true to the transpose param, 142 // so do our own transpose 143 GrGLfloat mt[] = { 144 SkScalarToFloat(m[SkMatrix::kMScaleX]), 145 SkScalarToFloat(m[SkMatrix::kMSkewY]), 146 SkScalarToFloat(m[SkMatrix::kMPersp0]), 147 SkScalarToFloat(m[SkMatrix::kMSkewX]), 148 SkScalarToFloat(m[SkMatrix::kMScaleY]), 149 SkScalarToFloat(m[SkMatrix::kMPersp1]), 150 SkScalarToFloat(m[SkMatrix::kMTransX]), 151 SkScalarToFloat(m[SkMatrix::kMTransY]), 152 SkScalarToFloat(m[SkMatrix::kMPersp2]) 153 }; 154 fCurrentProgram->fUniformManager.setMatrix3f( 155 fCurrentProgram->fUniformHandles.fViewMatrixUni, 156 mt); 157 fCurrentProgram->fViewMatrix = vm; 158 fCurrentProgram->fViewportSize = viewportSize; 159 } 160} 161 162/////////////////////////////////////////////////////////////////////////////// 163 164void GrGpuGL::flushColor(GrColor color) { 165 const ProgramDesc& desc = fCurrentProgram->getDesc(); 166 const GrDrawState& drawState = this->getDrawState(); 167 168 if (this->getVertexLayout() & GrDrawState::kColor_VertexLayoutBit) { 169 // color will be specified per-vertex as an attribute 170 // invalidate the const vertex attrib color 171 fHWConstAttribColor = GrColor_ILLEGAL; 172 } else { 173 switch (desc.fColorInput) { 174 case ProgramDesc::kAttribute_ColorInput: 175 if (fHWConstAttribColor != color) { 176 // OpenGL ES only supports the float varieties of glVertexAttrib 177 GrGLfloat c[4]; 178 GrColorToRGBAFloat(color, c); 179 GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c)); 180 fHWConstAttribColor = color; 181 } 182 break; 183 case ProgramDesc::kUniform_ColorInput: 184 if (fCurrentProgram->fColor != color) { 185 // OpenGL ES doesn't support unsigned byte varieties of glUniform 186 GrGLfloat c[4]; 187 GrColorToRGBAFloat(color, c); 188 GrAssert(kInvalidUniformHandle != fCurrentProgram->fUniformHandles.fColorUni); 189 fCurrentProgram->fUniformManager.set4fv( 190 fCurrentProgram->fUniformHandles.fColorUni, 191 0, 1, c); 192 fCurrentProgram->fColor = color; 193 } 194 break; 195 case ProgramDesc::kSolidWhite_ColorInput: 196 case ProgramDesc::kTransBlack_ColorInput: 197 break; 198 default: 199 GrCrash("Unknown color type."); 200 } 201 } 202 UniformHandle filterColorUni = fCurrentProgram->fUniformHandles.fColorFilterUni; 203 if (kInvalidUniformHandle != filterColorUni && 204 fCurrentProgram->fColorFilterColor != drawState.getColorFilterColor()) { 205 GrGLfloat c[4]; 206 GrColorToRGBAFloat(drawState.getColorFilterColor(), c); 207 fCurrentProgram->fUniformManager.set4fv(filterColorUni, 0, 1, c); 208 fCurrentProgram->fColorFilterColor = drawState.getColorFilterColor(); 209 } 210} 211 212void GrGpuGL::flushCoverage(GrColor coverage) { 213 const ProgramDesc& desc = fCurrentProgram->getDesc(); 214 // const GrDrawState& drawState = this->getDrawState(); 215 216 217 if (this->getVertexLayout() & GrDrawState::kCoverage_VertexLayoutBit) { 218 // coverage will be specified per-vertex as an attribute 219 // invalidate the const vertex attrib coverage 220 fHWConstAttribCoverage = GrColor_ILLEGAL; 221 } else { 222 switch (desc.fCoverageInput) { 223 case ProgramDesc::kAttribute_ColorInput: 224 if (fHWConstAttribCoverage != coverage) { 225 // OpenGL ES only supports the float varieties of 226 // glVertexAttrib 227 GrGLfloat c[4]; 228 GrColorToRGBAFloat(coverage, c); 229 GL_CALL(VertexAttrib4fv(GrGLProgram::CoverageAttributeIdx(), 230 c)); 231 fHWConstAttribCoverage = coverage; 232 } 233 break; 234 case ProgramDesc::kUniform_ColorInput: 235 if (fCurrentProgram->fCoverage != coverage) { 236 // OpenGL ES doesn't support unsigned byte varieties of 237 // glUniform 238 GrGLfloat c[4]; 239 GrColorToRGBAFloat(coverage, c); 240 GrAssert(kInvalidUniformHandle != 241 fCurrentProgram->fUniformHandles.fCoverageUni); 242 fCurrentProgram->fUniformManager.set4fv( 243 fCurrentProgram->fUniformHandles.fCoverageUni, 244 0, 1, c); 245 fCurrentProgram->fCoverage = coverage; 246 } 247 break; 248 case ProgramDesc::kSolidWhite_ColorInput: 249 case ProgramDesc::kTransBlack_ColorInput: 250 break; 251 default: 252 GrCrash("Unknown coverage type."); 253 } 254 } 255} 256 257bool GrGpuGL::flushGraphicsState(DrawType type) { 258 const GrDrawState& drawState = this->getDrawState(); 259 260 // GrGpu::setupClipAndFlushState should have already checked this 261 // and bailed if not true. 262 GrAssert(NULL != drawState.getRenderTarget()); 263 264 if (kStencilPath_DrawType != type) { 265 this->flushMiscFixedFunctionState(); 266 267 GrBlendCoeff srcCoeff; 268 GrBlendCoeff dstCoeff; 269 BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff); 270 if (kSkipDraw_BlendOptFlag & blendOpts) { 271 return false; 272 } 273 274 const GrEffectStage* stages[GrDrawState::kNumStages]; 275 for (int i = 0; i < GrDrawState::kNumStages; ++i) { 276 stages[i] = drawState.isStageEnabled(i) ? &drawState.getStage(i) : NULL; 277 } 278 GrGLProgram::Desc desc; 279 this->buildProgram(kDrawPoints_DrawType == type, blendOpts, dstCoeff, &desc); 280 281 fCurrentProgram.reset(fProgramCache->getProgram(desc, stages)); 282 if (NULL == fCurrentProgram.get()) { 283 GrAssert(!"Failed to create program!"); 284 return false; 285 } 286 fCurrentProgram.get()->ref(); 287 288 if (fHWProgramID != fCurrentProgram->fProgramID) { 289 GL_CALL(UseProgram(fCurrentProgram->fProgramID)); 290 fHWProgramID = fCurrentProgram->fProgramID; 291 } 292 fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff); 293 this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff); 294 295 GrColor color; 296 GrColor coverage; 297 if (blendOpts & kEmitTransBlack_BlendOptFlag) { 298 color = 0; 299 coverage = 0; 300 } else if (blendOpts & kEmitCoverage_BlendOptFlag) { 301 color = 0xffffffff; 302 coverage = drawState.getCoverage(); 303 } else { 304 color = drawState.getColor(); 305 coverage = drawState.getCoverage(); 306 } 307 this->flushColor(color); 308 this->flushCoverage(coverage); 309 310 fCurrentProgram->setData(this); 311 } 312 this->flushStencil(type); 313 this->flushViewMatrix(type); 314 this->flushScissor(); 315 this->flushAAState(type); 316 317 GrIRect* devRect = NULL; 318 GrIRect devClipBounds; 319 if (drawState.isClipState()) { 320 this->getClip()->getConservativeBounds(drawState.getRenderTarget(), &devClipBounds); 321 devRect = &devClipBounds; 322 } 323 // This must come after textures are flushed because a texture may need 324 // to be msaa-resolved (which will modify bound FBO state). 325 this->flushRenderTarget(devRect); 326 327 return true; 328} 329 330#if GR_TEXT_SCALAR_IS_USHORT 331 #define TEXT_COORDS_GL_TYPE GR_GL_UNSIGNED_SHORT 332 #define TEXT_COORDS_ARE_NORMALIZED 1 333#elif GR_TEXT_SCALAR_IS_FLOAT 334 #define TEXT_COORDS_GL_TYPE GR_GL_FLOAT 335 #define TEXT_COORDS_ARE_NORMALIZED 0 336#elif GR_TEXT_SCALAR_IS_FIXED 337 #define TEXT_COORDS_GL_TYPE GR_GL_FIXED 338 #define TEXT_COORDS_ARE_NORMALIZED 0 339#else 340 #error "unknown GR_TEXT_SCALAR type" 341#endif 342 343void GrGpuGL::setupGeometry(int* startVertex, 344 int* startIndex, 345 int vertexCount, 346 int indexCount) { 347 348 int newColorOffset; 349 int newCoverageOffset; 350 int newTexCoordOffsets[GrDrawState::kMaxTexCoords]; 351 int newEdgeOffset; 352 353 GrVertexLayout currLayout = this->getVertexLayout(); 354 355 GrGLsizei newStride = GrDrawState::VertexSizeAndOffsetsByIdx( 356 currLayout, 357 newTexCoordOffsets, 358 &newColorOffset, 359 &newCoverageOffset, 360 &newEdgeOffset); 361 int oldColorOffset; 362 int oldCoverageOffset; 363 int oldTexCoordOffsets[GrDrawState::kMaxTexCoords]; 364 int oldEdgeOffset; 365 366 GrGLsizei oldStride = GrDrawState::VertexSizeAndOffsetsByIdx( 367 fHWGeometryState.fVertexLayout, 368 oldTexCoordOffsets, 369 &oldColorOffset, 370 &oldCoverageOffset, 371 &oldEdgeOffset); 372 bool indexed = NULL != startIndex; 373 374 int extraVertexOffset; 375 int extraIndexOffset; 376 this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset); 377 378 GrGLenum scalarType; 379 bool texCoordNorm; 380 if (currLayout & GrDrawState::kTextFormat_VertexLayoutBit) { 381 scalarType = TEXT_COORDS_GL_TYPE; 382 texCoordNorm = SkToBool(TEXT_COORDS_ARE_NORMALIZED); 383 } else { 384// GR_STATIC_ASSERT(SK_SCALAR_IS_FLOAT); 385 scalarType = GR_GL_FLOAT; 386 texCoordNorm = false; 387 } 388 389 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride; 390 *startVertex = 0; 391 if (indexed) { 392 *startIndex += extraIndexOffset; 393 } 394 395 // all the Pointers must be set if any of these are true 396 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty || 397 vertexOffset != fHWGeometryState.fVertexOffset || 398 newStride != oldStride; 399 400 // position and tex coord offsets change if above conditions are true 401 // or the type/normalization changed based on text vs nontext type coords. 402 bool posAndTexChange = allOffsetsChange || 403 (((TEXT_COORDS_GL_TYPE != GR_GL_FLOAT) || TEXT_COORDS_ARE_NORMALIZED) && 404 (GrDrawState::kTextFormat_VertexLayoutBit & 405 (fHWGeometryState.fVertexLayout ^ currLayout))); 406 407 if (posAndTexChange) { 408 int idx = GrGLProgram::PositionAttributeIdx(); 409 GL_CALL(VertexAttribPointer(idx, 2, scalarType, false, newStride, 410 (GrGLvoid*)vertexOffset)); 411 fHWGeometryState.fVertexOffset = vertexOffset; 412 } 413 414 for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { 415 if (newTexCoordOffsets[t] > 0) { 416 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]); 417 int idx = GrGLProgram::TexCoordAttributeIdx(t); 418 if (oldTexCoordOffsets[t] <= 0) { 419 GL_CALL(EnableVertexAttribArray(idx)); 420 GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm, 421 newStride, texCoordOffset)); 422 } else if (posAndTexChange || 423 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) { 424 GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm, 425 newStride, texCoordOffset)); 426 } 427 } else if (oldTexCoordOffsets[t] > 0) { 428 GL_CALL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t))); 429 } 430 } 431 432 if (newColorOffset > 0) { 433 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset); 434 int idx = GrGLProgram::ColorAttributeIdx(); 435 if (oldColorOffset <= 0) { 436 GL_CALL(EnableVertexAttribArray(idx)); 437 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, 438 true, newStride, colorOffset)); 439 } else if (allOffsetsChange || newColorOffset != oldColorOffset) { 440 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, 441 true, newStride, colorOffset)); 442 } 443 } else if (oldColorOffset > 0) { 444 GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx())); 445 } 446 447 if (newCoverageOffset > 0) { 448 GrGLvoid* coverageOffset = (int8_t*)(vertexOffset + newCoverageOffset); 449 int idx = GrGLProgram::CoverageAttributeIdx(); 450 if (oldCoverageOffset <= 0) { 451 GL_CALL(EnableVertexAttribArray(idx)); 452 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, 453 true, newStride, coverageOffset)); 454 } else if (allOffsetsChange || newCoverageOffset != oldCoverageOffset) { 455 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, 456 true, newStride, coverageOffset)); 457 } 458 } else if (oldCoverageOffset > 0) { 459 GL_CALL(DisableVertexAttribArray(GrGLProgram::CoverageAttributeIdx())); 460 } 461 462 if (newEdgeOffset > 0) { 463 GrGLvoid* edgeOffset = (int8_t*)(vertexOffset + newEdgeOffset); 464 int idx = GrGLProgram::EdgeAttributeIdx(); 465 if (oldEdgeOffset <= 0) { 466 GL_CALL(EnableVertexAttribArray(idx)); 467 GL_CALL(VertexAttribPointer(idx, 4, scalarType, 468 false, newStride, edgeOffset)); 469 } else if (allOffsetsChange || newEdgeOffset != oldEdgeOffset) { 470 GL_CALL(VertexAttribPointer(idx, 4, scalarType, 471 false, newStride, edgeOffset)); 472 } 473 } else if (oldEdgeOffset > 0) { 474 GL_CALL(DisableVertexAttribArray(GrGLProgram::EdgeAttributeIdx())); 475 } 476 477 fHWGeometryState.fVertexLayout = currLayout; 478 fHWGeometryState.fArrayPtrsDirty = false; 479} 480 481void GrGpuGL::buildProgram(bool isPoints, 482 BlendOptFlags blendOpts, 483 GrBlendCoeff dstCoeff, 484 ProgramDesc* desc) { 485 const GrDrawState& drawState = this->getDrawState(); 486 487 // This should already have been caught 488 GrAssert(!(kSkipDraw_BlendOptFlag & blendOpts)); 489 490 bool skipCoverage = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag); 491 492 bool skipColor = SkToBool(blendOpts & (kEmitTransBlack_BlendOptFlag | 493 kEmitCoverage_BlendOptFlag)); 494 495 // The descriptor is used as a cache key. Thus when a field of the 496 // descriptor will not affect program generation (because of the vertex 497 // layout in use or other descriptor field settings) it should be set 498 // to a canonical value to avoid duplicate programs with different keys. 499 500 // Must initialize all fields or cache will have false negatives! 501 desc->fVertexLayout = this->getVertexLayout(); 502 503 desc->fEmitsPointSize = isPoints; 504 505 bool requiresAttributeColors = !skipColor && 506 SkToBool(desc->fVertexLayout & GrDrawState::kColor_VertexLayoutBit); 507 bool requiresAttributeCoverage = !skipCoverage && 508 SkToBool(desc->fVertexLayout & GrDrawState::kCoverage_VertexLayoutBit); 509 510 // fColorInput/fCoverageInput records how colors are specified for the. 511 // program. So we strip the bits from the layout to avoid false negatives 512 // when searching for an existing program in the cache. 513 desc->fVertexLayout &= ~(GrDrawState::kColor_VertexLayoutBit | GrDrawState::kCoverage_VertexLayoutBit); 514 515 desc->fColorFilterXfermode = skipColor ? 516 SkXfermode::kDst_Mode : 517 drawState.getColorFilterMode(); 518 519 // no reason to do edge aa or look at per-vertex coverage if coverage is 520 // ignored 521 if (skipCoverage) { 522 desc->fVertexLayout &= ~(GrDrawState::kEdge_VertexLayoutBit | GrDrawState::kCoverage_VertexLayoutBit); 523 } 524 525 bool colorIsTransBlack = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag); 526 bool colorIsSolidWhite = (blendOpts & kEmitCoverage_BlendOptFlag) || 527 (!requiresAttributeColors && 0xffffffff == drawState.getColor()); 528 if (GR_AGGRESSIVE_SHADER_OPTS && colorIsTransBlack) { 529 desc->fColorInput = ProgramDesc::kTransBlack_ColorInput; 530 } else if (GR_AGGRESSIVE_SHADER_OPTS && colorIsSolidWhite) { 531 desc->fColorInput = ProgramDesc::kSolidWhite_ColorInput; 532 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) { 533 desc->fColorInput = ProgramDesc::kUniform_ColorInput; 534 } else { 535 desc->fColorInput = ProgramDesc::kAttribute_ColorInput; 536 } 537 538 bool covIsSolidWhite = !requiresAttributeCoverage && 0xffffffff == drawState.getCoverage(); 539 540 if (skipCoverage) { 541 desc->fCoverageInput = ProgramDesc::kTransBlack_ColorInput; 542 } else if (covIsSolidWhite) { 543 desc->fCoverageInput = ProgramDesc::kSolidWhite_ColorInput; 544 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) { 545 desc->fCoverageInput = ProgramDesc::kUniform_ColorInput; 546 } else { 547 desc->fCoverageInput = ProgramDesc::kAttribute_ColorInput; 548 } 549 550 int lastEnabledStage = -1; 551 552 if (!skipCoverage && (desc->fVertexLayout &GrDrawState::kEdge_VertexLayoutBit)) { 553 desc->fVertexEdgeType = drawState.getVertexEdgeType(); 554 desc->fDiscardIfOutsideEdge = drawState.getStencil().doesWrite(); 555 } else { 556 // Use canonical values when edge-aa is not enabled to avoid program cache misses. 557 desc->fVertexEdgeType = GrDrawState::kHairLine_EdgeType; 558 desc->fDiscardIfOutsideEdge = false; 559 } 560 561 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 562 563 bool skip = s < drawState.getFirstCoverageStage() ? skipColor : skipCoverage; 564 if (!skip && drawState.isStageEnabled(s)) { 565 lastEnabledStage = s; 566 const GrEffectRef& effect = *drawState.getStage(s).getEffect(); 567 const GrBackendEffectFactory& factory = effect->getFactory(); 568 desc->fEffectKeys[s] = factory.glEffectKey(drawState.getStage(s), this->glCaps()); 569 } else { 570 desc->fEffectKeys[s] = 0; 571 } 572 } 573 574 desc->fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput; 575 576 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything 577 // other than pass through values from the VS to the FS anyway). 578#if 0 && GR_GL_EXPERIMENTAL_GS 579 desc->fExperimentalGS = this->getCaps().fGeometryShaderSupport; 580#endif 581 582 // We want to avoid generating programs with different "first cov stage" values when they would 583 // compute the same result. We set field in the desc to kNumStages when either there are no 584 // coverage stages or the distinction between coverage and color is immaterial. 585 int firstCoverageStage = GrDrawState::kNumStages; 586 desc->fFirstCoverageStage = GrDrawState::kNumStages; 587 bool hasCoverage = drawState.getFirstCoverageStage() <= lastEnabledStage; 588 if (hasCoverage) { 589 firstCoverageStage = drawState.getFirstCoverageStage(); 590 } 591 592 // other coverage inputs 593 if (!hasCoverage) { 594 hasCoverage = requiresAttributeCoverage || 595 (desc->fVertexLayout & GrDrawState::kEdge_VertexLayoutBit); 596 } 597 598 if (hasCoverage) { 599 // color filter is applied between color/coverage computation 600 if (SkXfermode::kDst_Mode != desc->fColorFilterXfermode) { 601 desc->fFirstCoverageStage = firstCoverageStage; 602 } 603 604 if (this->getCaps().dualSourceBlendingSupport() && 605 !(blendOpts & (kEmitCoverage_BlendOptFlag | kCoverageAsAlpha_BlendOptFlag))) { 606 if (kZero_GrBlendCoeff == dstCoeff) { 607 // write the coverage value to second color 608 desc->fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput; 609 desc->fFirstCoverageStage = firstCoverageStage; 610 } else if (kSA_GrBlendCoeff == dstCoeff) { 611 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 612 desc->fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput; 613 desc->fFirstCoverageStage = firstCoverageStage; 614 } else if (kSC_GrBlendCoeff == dstCoeff) { 615 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 616 desc->fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput; 617 desc->fFirstCoverageStage = firstCoverageStage; 618 } 619 } 620 } 621} 622