GrGpuGL_program.cpp revision 288d9549b42a4eb934e814790f2b7a81f017a9c5
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 "GrCustomStage.h" 11#include "GrGLProgramStage.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 GrCustomStage** 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 GrMatrix& 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 GrMatrix m; 100 m.setScale(GrIntToScalar(2) / rt->width(), GrIntToScalar(-2) / rt->height()); 101 m.postTranslate(-GR_Scalar1, GR_Scalar1); 102 m.preConcat(vm); 103 104 // GL wants a column-major 4x4. 105 GrGLfloat mv[] = { 106 // col 0 107 GrScalarToFloat(m[GrMatrix::kMScaleX]), 108 GrScalarToFloat(m[GrMatrix::kMSkewY]), 109 0, 110 GrScalarToFloat(m[GrMatrix::kMPersp0]), 111 112 // col 1 113 GrScalarToFloat(m[GrMatrix::kMSkewX]), 114 GrScalarToFloat(m[GrMatrix::kMScaleY]), 115 0, 116 GrScalarToFloat(m[GrMatrix::kMPersp1]), 117 118 // col 2 119 0, 0, 0, 0, 120 121 // col3 122 GrScalarToFloat(m[GrMatrix::kMTransX]), 123 GrScalarToFloat(m[GrMatrix::kMTransY]), 124 0.0f, 125 GrScalarToFloat(m[GrMatrix::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 GrMatrix m; 135 m.setAll( 136 GrIntToScalar(2) / viewportSize.fWidth, 0, -GR_Scalar1, 137 0,-GrIntToScalar(2) / viewportSize.fHeight, GR_Scalar1, 138 0, 0, GrMatrix::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 GrScalarToFloat(m[GrMatrix::kMScaleX]), 145 GrScalarToFloat(m[GrMatrix::kMSkewY]), 146 GrScalarToFloat(m[GrMatrix::kMPersp0]), 147 GrScalarToFloat(m[GrMatrix::kMSkewX]), 148 GrScalarToFloat(m[GrMatrix::kMScaleY]), 149 GrScalarToFloat(m[GrMatrix::kMPersp1]), 150 GrScalarToFloat(m[GrMatrix::kMTransX]), 151 GrScalarToFloat(m[GrMatrix::kMTransY]), 152 GrScalarToFloat(m[GrMatrix::kMPersp2]) 153 }; 154 fCurrentProgram->fUniformManager.setMatrix3f(fCurrentProgram->fUniforms.fViewMatrixUni, mt); 155 fCurrentProgram->fViewMatrix = vm; 156 fCurrentProgram->fViewportSize = viewportSize; 157 } 158} 159 160/////////////////////////////////////////////////////////////////////////////// 161 162// helpers for texture matrices 163 164void GrGpuGL::AdjustTextureMatrix(const GrGLTexture* texture, 165 GrMatrix* matrix) { 166 GrAssert(NULL != texture); 167 GrAssert(NULL != matrix); 168 GrGLTexture::Orientation orientation = texture->orientation(); 169 if (GrGLTexture::kBottomUp_Orientation == orientation) { 170 GrMatrix invY; 171 invY.setAll(GR_Scalar1, 0, 0, 172 0, -GR_Scalar1, GR_Scalar1, 173 0, 0, GrMatrix::I()[8]); 174 matrix->postConcat(invY); 175 } else { 176 GrAssert(GrGLTexture::kTopDown_Orientation == orientation); 177 } 178} 179 180int GrGpuGL::TextureMatrixOptFlags(const GrGLTexture* texture, 181 const GrSamplerState& sampler) { 182 GrAssert(NULL != texture); 183 GrMatrix matrix; 184 sampler.getTotalMatrix(&matrix); 185 186 bool canBeIndentity = GrGLTexture::kTopDown_Orientation == texture->orientation(); 187 188 if (canBeIndentity && matrix.isIdentity()) { 189 return GrGLProgram::StageDesc::kIdentityMatrix_OptFlagBit; 190 } else if (!matrix.hasPerspective()) { 191 return GrGLProgram::StageDesc::kNoPerspective_OptFlagBit; 192 } 193 return 0; 194} 195 196/////////////////////////////////////////////////////////////////////////////// 197 198void GrGpuGL::flushTextureMatrix(int s) { 199 const GrDrawState& drawState = this->getDrawState(); 200 201 // FIXME: Still assuming only a single texture per custom stage 202 const GrCustomStage* stage = drawState.getSampler(s).getCustomStage(); 203 const GrGLTexture* texture = static_cast<const GrGLTexture*>(stage->texture(0)); 204 if (NULL != texture) { 205 206 bool orientationChange = fCurrentProgram->fTextureOrientation[s] != 207 texture->orientation(); 208 209 UniformHandle matrixUni = fCurrentProgram->fUniforms.fStages[s].fTextureMatrixUni; 210 211 const GrMatrix& hwMatrix = fCurrentProgram->fTextureMatrices[s]; 212 GrMatrix samplerMatrix; 213 drawState.getSampler(s).getTotalMatrix(&samplerMatrix); 214 215 if (kInvalidUniformHandle != matrixUni && 216 (orientationChange || !hwMatrix.cheapEqualTo(samplerMatrix))) { 217 218 GrMatrix m = samplerMatrix; 219 AdjustTextureMatrix(texture, &m); 220 221 // ES doesn't allow you to pass true to the transpose param, 222 // so do our own transpose 223 GrGLfloat mt[] = { 224 GrScalarToFloat(m[GrMatrix::kMScaleX]), 225 GrScalarToFloat(m[GrMatrix::kMSkewY]), 226 GrScalarToFloat(m[GrMatrix::kMPersp0]), 227 GrScalarToFloat(m[GrMatrix::kMSkewX]), 228 GrScalarToFloat(m[GrMatrix::kMScaleY]), 229 GrScalarToFloat(m[GrMatrix::kMPersp1]), 230 GrScalarToFloat(m[GrMatrix::kMTransX]), 231 GrScalarToFloat(m[GrMatrix::kMTransY]), 232 GrScalarToFloat(m[GrMatrix::kMPersp2]) 233 }; 234 235 fCurrentProgram->fUniformManager.setMatrix3f(matrixUni, mt); 236 fCurrentProgram->fTextureMatrices[s] = samplerMatrix; 237 } 238 239 fCurrentProgram->fTextureOrientation[s] = texture->orientation(); 240 } 241} 242 243void GrGpuGL::flushColorMatrix() { 244 UniformHandle matrixUni = fCurrentProgram->fUniforms.fColorMatrixUni; 245 UniformHandle vecUni = fCurrentProgram->fUniforms.fColorMatrixVecUni; 246 if (kInvalidUniformHandle != matrixUni && kInvalidUniformHandle != vecUni) { 247 const float* m = this->getDrawState().getColorMatrix(); 248 GrGLfloat mt[] = { 249 m[0], m[5], m[10], m[15], 250 m[1], m[6], m[11], m[16], 251 m[2], m[7], m[12], m[17], 252 m[3], m[8], m[13], m[18], 253 }; 254 static float scale = 1.0f / 255.0f; 255 GrGLfloat vec[] = { 256 m[4] * scale, m[9] * scale, m[14] * scale, m[19] * scale, 257 }; 258 fCurrentProgram->fUniformManager.setMatrix4f(matrixUni, mt); 259 fCurrentProgram->fUniformManager.set4fv(vecUni, 0, 1, vec); 260 } 261} 262 263void GrGpuGL::flushColor(GrColor color) { 264 const ProgramDesc& desc = fCurrentProgram->getDesc(); 265 const GrDrawState& drawState = this->getDrawState(); 266 267 if (this->getVertexLayout() & kColor_VertexLayoutBit) { 268 // color will be specified per-vertex as an attribute 269 // invalidate the const vertex attrib color 270 fHWConstAttribColor = GrColor_ILLEGAL; 271 } else { 272 switch (desc.fColorInput) { 273 case ProgramDesc::kAttribute_ColorInput: 274 if (fHWConstAttribColor != color) { 275 // OpenGL ES only supports the float varieties of glVertexAttrib 276 GrGLfloat c[4]; 277 GrColorToRGBAFloat(color, c); 278 GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c)); 279 fHWConstAttribColor = color; 280 } 281 break; 282 case ProgramDesc::kUniform_ColorInput: 283 if (fCurrentProgram->fColor != color) { 284 // OpenGL ES doesn't support unsigned byte varieties of glUniform 285 GrGLfloat c[4]; 286 GrColorToRGBAFloat(color, c); 287 GrAssert(kInvalidUniformHandle != fCurrentProgram->fUniforms.fColorUni); 288 fCurrentProgram->fUniformManager.set4fv(fCurrentProgram->fUniforms.fColorUni, 289 0, 1, c); 290 fCurrentProgram->fColor = color; 291 } 292 break; 293 case ProgramDesc::kSolidWhite_ColorInput: 294 case ProgramDesc::kTransBlack_ColorInput: 295 break; 296 default: 297 GrCrash("Unknown color type."); 298 } 299 } 300 UniformHandle filterColorUni = fCurrentProgram->fUniforms.fColorFilterUni; 301 if (kInvalidUniformHandle != filterColorUni && 302 fCurrentProgram->fColorFilterColor != drawState.getColorFilterColor()) { 303 GrGLfloat c[4]; 304 GrColorToRGBAFloat(drawState.getColorFilterColor(), c); 305 fCurrentProgram->fUniformManager.set4fv(filterColorUni, 0, 1, c); 306 fCurrentProgram->fColorFilterColor = drawState.getColorFilterColor(); 307 } 308} 309 310void GrGpuGL::flushCoverage(GrColor coverage) { 311 const ProgramDesc& desc = fCurrentProgram->getDesc(); 312 // const GrDrawState& drawState = this->getDrawState(); 313 314 315 if (this->getVertexLayout() & kCoverage_VertexLayoutBit) { 316 // coverage will be specified per-vertex as an attribute 317 // invalidate the const vertex attrib coverage 318 fHWConstAttribCoverage = GrColor_ILLEGAL; 319 } else { 320 switch (desc.fCoverageInput) { 321 case ProgramDesc::kAttribute_ColorInput: 322 if (fHWConstAttribCoverage != coverage) { 323 // OpenGL ES only supports the float varieties of 324 // glVertexAttrib 325 GrGLfloat c[4]; 326 GrColorToRGBAFloat(coverage, c); 327 GL_CALL(VertexAttrib4fv(GrGLProgram::CoverageAttributeIdx(), 328 c)); 329 fHWConstAttribCoverage = coverage; 330 } 331 break; 332 case ProgramDesc::kUniform_ColorInput: 333 if (fCurrentProgram->fCoverage != coverage) { 334 // OpenGL ES doesn't support unsigned byte varieties of 335 // glUniform 336 GrGLfloat c[4]; 337 GrColorToRGBAFloat(coverage, c); 338 GrAssert(kInvalidUniformHandle != fCurrentProgram->fUniforms.fCoverageUni); 339 fCurrentProgram->fUniformManager.set4fv(fCurrentProgram->fUniforms.fCoverageUni, 340 0, 1, c); 341 fCurrentProgram->fCoverage = coverage; 342 } 343 break; 344 case ProgramDesc::kSolidWhite_ColorInput: 345 case ProgramDesc::kTransBlack_ColorInput: 346 break; 347 default: 348 GrCrash("Unknown coverage type."); 349 } 350 } 351} 352 353bool GrGpuGL::flushGraphicsState(DrawType type) { 354 const GrDrawState& drawState = this->getDrawState(); 355 356 // GrGpu::setupClipAndFlushState should have already checked this 357 // and bailed if not true. 358 GrAssert(NULL != drawState.getRenderTarget()); 359 360 if (kStencilPath_DrawType != type) { 361 this->flushMiscFixedFunctionState(); 362 363 GrBlendCoeff srcCoeff; 364 GrBlendCoeff dstCoeff; 365 BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff); 366 if (kSkipDraw_BlendOptFlag & blendOpts) { 367 return false; 368 } 369 370 const GrCustomStage* customStages [GrDrawState::kNumStages]; 371 GrGLProgram::Desc desc; 372 this->buildProgram(kDrawPoints_DrawType == type, blendOpts, dstCoeff, customStages, &desc); 373 374 fCurrentProgram.reset(fProgramCache->getProgram(desc, customStages)); 375 if (NULL == fCurrentProgram.get()) { 376 GrAssert(!"Failed to create program!"); 377 return false; 378 } 379 fCurrentProgram.get()->ref(); 380 381 if (fHWProgramID != fCurrentProgram->fProgramID) { 382 GL_CALL(UseProgram(fCurrentProgram->fProgramID)); 383 fHWProgramID = fCurrentProgram->fProgramID; 384 } 385 fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff); 386 this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff); 387 388 GrColor color; 389 GrColor coverage; 390 if (blendOpts & kEmitTransBlack_BlendOptFlag) { 391 color = 0; 392 coverage = 0; 393 } else if (blendOpts & kEmitCoverage_BlendOptFlag) { 394 color = 0xffffffff; 395 coverage = drawState.getCoverage(); 396 } else { 397 color = drawState.getColor(); 398 coverage = drawState.getCoverage(); 399 } 400 this->flushColor(color); 401 this->flushCoverage(coverage); 402 403 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 404 if (this->isStageEnabled(s)) { 405 this->flushBoundTextureAndParams(s); 406 407 this->flushTextureMatrix(s); 408 409 if (NULL != fCurrentProgram->fProgramStage[s]) { 410 const GrSamplerState& sampler = this->getDrawState().getSampler(s); 411 fCurrentProgram->fProgramStage[s]->setData(fCurrentProgram->fUniformManager, 412 *sampler.getCustomStage(), 413 drawState.getRenderTarget(), s); 414 } 415 } 416 } 417 this->flushColorMatrix(); 418 } 419 this->flushStencil(type); 420 this->flushViewMatrix(type); 421 this->flushScissor(); 422 this->flushAAState(type); 423 424 GrIRect* devRect = NULL; 425 GrIRect devClipBounds; 426 if (drawState.isClipState()) { 427 fClip->getConservativeBounds(drawState.getRenderTarget(), 428 &devClipBounds); 429 devRect = &devClipBounds; 430 } 431 // This must come after textures are flushed because a texture may need 432 // to be msaa-resolved (which will modify bound FBO state). 433 this->flushRenderTarget(devRect); 434 435 return true; 436} 437 438#if GR_TEXT_SCALAR_IS_USHORT 439 #define TEXT_COORDS_GL_TYPE GR_GL_UNSIGNED_SHORT 440 #define TEXT_COORDS_ARE_NORMALIZED 1 441#elif GR_TEXT_SCALAR_IS_FLOAT 442 #define TEXT_COORDS_GL_TYPE GR_GL_FLOAT 443 #define TEXT_COORDS_ARE_NORMALIZED 0 444#elif GR_TEXT_SCALAR_IS_FIXED 445 #define TEXT_COORDS_GL_TYPE GR_GL_FIXED 446 #define TEXT_COORDS_ARE_NORMALIZED 0 447#else 448 #error "unknown GR_TEXT_SCALAR type" 449#endif 450 451void GrGpuGL::setupGeometry(int* startVertex, 452 int* startIndex, 453 int vertexCount, 454 int indexCount) { 455 456 int newColorOffset; 457 int newCoverageOffset; 458 int newTexCoordOffsets[GrDrawState::kMaxTexCoords]; 459 int newEdgeOffset; 460 461 GrVertexLayout currLayout = this->getVertexLayout(); 462 463 GrGLsizei newStride = VertexSizeAndOffsetsByIdx( 464 currLayout, 465 newTexCoordOffsets, 466 &newColorOffset, 467 &newCoverageOffset, 468 &newEdgeOffset); 469 int oldColorOffset; 470 int oldCoverageOffset; 471 int oldTexCoordOffsets[GrDrawState::kMaxTexCoords]; 472 int oldEdgeOffset; 473 474 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx( 475 fHWGeometryState.fVertexLayout, 476 oldTexCoordOffsets, 477 &oldColorOffset, 478 &oldCoverageOffset, 479 &oldEdgeOffset); 480 bool indexed = NULL != startIndex; 481 482 int extraVertexOffset; 483 int extraIndexOffset; 484 this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset); 485 486 GrGLenum scalarType; 487 bool texCoordNorm; 488 if (currLayout & kTextFormat_VertexLayoutBit) { 489 scalarType = TEXT_COORDS_GL_TYPE; 490 texCoordNorm = SkToBool(TEXT_COORDS_ARE_NORMALIZED); 491 } else { 492 GR_STATIC_ASSERT(GR_SCALAR_IS_FLOAT); 493 scalarType = GR_GL_FLOAT; 494 texCoordNorm = false; 495 } 496 497 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride; 498 *startVertex = 0; 499 if (indexed) { 500 *startIndex += extraIndexOffset; 501 } 502 503 // all the Pointers must be set if any of these are true 504 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty || 505 vertexOffset != fHWGeometryState.fVertexOffset || 506 newStride != oldStride; 507 508 // position and tex coord offsets change if above conditions are true 509 // or the type/normalization changed based on text vs nontext type coords. 510 bool posAndTexChange = allOffsetsChange || 511 (((TEXT_COORDS_GL_TYPE != GR_GL_FLOAT) || TEXT_COORDS_ARE_NORMALIZED) && 512 (kTextFormat_VertexLayoutBit & 513 (fHWGeometryState.fVertexLayout ^ currLayout))); 514 515 if (posAndTexChange) { 516 int idx = GrGLProgram::PositionAttributeIdx(); 517 GL_CALL(VertexAttribPointer(idx, 2, scalarType, false, newStride, 518 (GrGLvoid*)vertexOffset)); 519 fHWGeometryState.fVertexOffset = vertexOffset; 520 } 521 522 for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { 523 if (newTexCoordOffsets[t] > 0) { 524 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]); 525 int idx = GrGLProgram::TexCoordAttributeIdx(t); 526 if (oldTexCoordOffsets[t] <= 0) { 527 GL_CALL(EnableVertexAttribArray(idx)); 528 GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm, 529 newStride, texCoordOffset)); 530 } else if (posAndTexChange || 531 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) { 532 GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm, 533 newStride, texCoordOffset)); 534 } 535 } else if (oldTexCoordOffsets[t] > 0) { 536 GL_CALL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t))); 537 } 538 } 539 540 if (newColorOffset > 0) { 541 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset); 542 int idx = GrGLProgram::ColorAttributeIdx(); 543 if (oldColorOffset <= 0) { 544 GL_CALL(EnableVertexAttribArray(idx)); 545 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, 546 true, newStride, colorOffset)); 547 } else if (allOffsetsChange || newColorOffset != oldColorOffset) { 548 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, 549 true, newStride, colorOffset)); 550 } 551 } else if (oldColorOffset > 0) { 552 GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx())); 553 } 554 555 if (newCoverageOffset > 0) { 556 GrGLvoid* coverageOffset = (int8_t*)(vertexOffset + newCoverageOffset); 557 int idx = GrGLProgram::CoverageAttributeIdx(); 558 if (oldCoverageOffset <= 0) { 559 GL_CALL(EnableVertexAttribArray(idx)); 560 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, 561 true, newStride, coverageOffset)); 562 } else if (allOffsetsChange || newCoverageOffset != oldCoverageOffset) { 563 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, 564 true, newStride, coverageOffset)); 565 } 566 } else if (oldCoverageOffset > 0) { 567 GL_CALL(DisableVertexAttribArray(GrGLProgram::CoverageAttributeIdx())); 568 } 569 570 if (newEdgeOffset > 0) { 571 GrGLvoid* edgeOffset = (int8_t*)(vertexOffset + newEdgeOffset); 572 int idx = GrGLProgram::EdgeAttributeIdx(); 573 if (oldEdgeOffset <= 0) { 574 GL_CALL(EnableVertexAttribArray(idx)); 575 GL_CALL(VertexAttribPointer(idx, 4, scalarType, 576 false, newStride, edgeOffset)); 577 } else if (allOffsetsChange || newEdgeOffset != oldEdgeOffset) { 578 GL_CALL(VertexAttribPointer(idx, 4, scalarType, 579 false, newStride, edgeOffset)); 580 } 581 } else if (oldEdgeOffset > 0) { 582 GL_CALL(DisableVertexAttribArray(GrGLProgram::EdgeAttributeIdx())); 583 } 584 585 fHWGeometryState.fVertexLayout = currLayout; 586 fHWGeometryState.fArrayPtrsDirty = false; 587} 588 589namespace { 590 591void setup_custom_stage(GrGLProgram::Desc::StageDesc* stage, 592 const GrSamplerState& sampler, 593 const GrGLCaps& caps, 594 const GrCustomStage** customStages, 595 GrGLProgram* program, int index) { 596 const GrCustomStage* customStage = sampler.getCustomStage(); 597 if (customStage) { 598 const GrProgramStageFactory& factory = customStage->getFactory(); 599 stage->fCustomStageKey = factory.glStageKey(*customStage, caps); 600 customStages[index] = customStage; 601 } else { 602 stage->fCustomStageKey = 0; 603 customStages[index] = NULL; 604 } 605} 606 607} 608 609void GrGpuGL::buildProgram(bool isPoints, 610 BlendOptFlags blendOpts, 611 GrBlendCoeff dstCoeff, 612 const GrCustomStage** customStages, 613 ProgramDesc* desc) { 614 const GrDrawState& drawState = this->getDrawState(); 615 616 // This should already have been caught 617 GrAssert(!(kSkipDraw_BlendOptFlag & blendOpts)); 618 619 bool skipCoverage = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag); 620 621 bool skipColor = SkToBool(blendOpts & (kEmitTransBlack_BlendOptFlag | 622 kEmitCoverage_BlendOptFlag)); 623 624 // The descriptor is used as a cache key. Thus when a field of the 625 // descriptor will not affect program generation (because of the vertex 626 // layout in use or other descriptor field settings) it should be set 627 // to a canonical value to avoid duplicate programs with different keys. 628 629 // Must initialize all fields or cache will have false negatives! 630 desc->fVertexLayout = this->getVertexLayout(); 631 632 desc->fEmitsPointSize = isPoints; 633 634 bool requiresAttributeColors = !skipColor && 635 SkToBool(desc->fVertexLayout & kColor_VertexLayoutBit); 636 bool requiresAttributeCoverage = !skipCoverage && 637 SkToBool(desc->fVertexLayout & kCoverage_VertexLayoutBit); 638 639 // fColorInput/fCoverageInput records how colors are specified for the. 640 // program. So we strip the bits from the layout to avoid false negatives 641 // when searching for an existing program in the cache. 642 desc->fVertexLayout &= ~(kColor_VertexLayoutBit | kCoverage_VertexLayoutBit); 643 644 desc->fColorFilterXfermode = skipColor ? 645 SkXfermode::kDst_Mode : 646 drawState.getColorFilterMode(); 647 648 desc->fColorMatrixEnabled = drawState.isStateFlagEnabled(GrDrawState::kColorMatrix_StateBit); 649 650 // no reason to do edge aa or look at per-vertex coverage if coverage is 651 // ignored 652 if (skipCoverage) { 653 desc->fVertexLayout &= ~(kEdge_VertexLayoutBit | kCoverage_VertexLayoutBit); 654 } 655 656 bool colorIsTransBlack = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag); 657 bool colorIsSolidWhite = (blendOpts & kEmitCoverage_BlendOptFlag) || 658 (!requiresAttributeColors && 0xffffffff == drawState.getColor()); 659 if (GR_AGGRESSIVE_SHADER_OPTS && colorIsTransBlack) { 660 desc->fColorInput = ProgramDesc::kTransBlack_ColorInput; 661 } else if (GR_AGGRESSIVE_SHADER_OPTS && colorIsSolidWhite) { 662 desc->fColorInput = ProgramDesc::kSolidWhite_ColorInput; 663 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) { 664 desc->fColorInput = ProgramDesc::kUniform_ColorInput; 665 } else { 666 desc->fColorInput = ProgramDesc::kAttribute_ColorInput; 667 } 668 669 bool covIsSolidWhite = !requiresAttributeCoverage && 0xffffffff == drawState.getCoverage(); 670 671 if (skipCoverage) { 672 desc->fCoverageInput = ProgramDesc::kTransBlack_ColorInput; 673 } else if (covIsSolidWhite) { 674 desc->fCoverageInput = ProgramDesc::kSolidWhite_ColorInput; 675 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) { 676 desc->fCoverageInput = ProgramDesc::kUniform_ColorInput; 677 } else { 678 desc->fCoverageInput = ProgramDesc::kAttribute_ColorInput; 679 } 680 681 int lastEnabledStage = -1; 682 683 if (!skipCoverage && (desc->fVertexLayout &GrDrawTarget::kEdge_VertexLayoutBit)) { 684 desc->fVertexEdgeType = drawState.getVertexEdgeType(); 685 } else { 686 // use canonical value when not set to avoid cache misses 687 desc->fVertexEdgeType = GrDrawState::kHairLine_EdgeType; 688 } 689 690 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 691 StageDesc& stage = desc->fStages[s]; 692 693 stage.fOptFlags = 0; 694 stage.setEnabled(this->isStageEnabled(s)); 695 696 bool skip = s < drawState.getFirstCoverageStage() ? skipColor : 697 skipCoverage; 698 699 if (!skip && stage.isEnabled()) { 700 lastEnabledStage = s; 701 const GrSamplerState& sampler = drawState.getSampler(s); 702 // FIXME: Still assuming one texture per custom stage 703 const GrCustomStage* customStage = drawState.getSampler(s).getCustomStage(); 704 const GrGLTexture* texture = static_cast<const GrGLTexture*>(customStage->texture(0)); 705 GrMatrix samplerMatrix; 706 sampler.getTotalMatrix(&samplerMatrix); 707 if (NULL != texture) { 708 // We call this helper function rather then simply checking the client-specified 709 // texture matrix. This is because we may have to concat a y-inversion to account 710 // for texture orientation. 711 stage.fOptFlags |= TextureMatrixOptFlags(texture, sampler); 712 } 713 714 setup_custom_stage(&stage, sampler, this->glCaps(), customStages, 715 fCurrentProgram.get(), s); 716 717 } else { 718 stage.fOptFlags = 0; 719 stage.fCustomStageKey = 0; 720 customStages[s] = NULL; 721 } 722 } 723 724 desc->fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput; 725 726 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything 727 // other than pass through values fromthe VS to the FS anyway). 728#if 0 && GR_GL_EXPERIMENTAL_GS 729 desc->fExperimentalGS = this->getCaps().fGeometryShaderSupport; 730#endif 731 732 // We want to avoid generating programs with different "first cov stage" values when they would 733 // compute the same result. We set field in the desc to kNumStages when either there are no 734 // coverage stages or the distinction between coverage and color is immaterial. 735 int firstCoverageStage = GrDrawState::kNumStages; 736 desc->fFirstCoverageStage = GrDrawState::kNumStages; 737 bool hasCoverage = drawState.getFirstCoverageStage() <= lastEnabledStage; 738 if (hasCoverage) { 739 firstCoverageStage = drawState.getFirstCoverageStage(); 740 } 741 742 // other coverage inputs 743 if (!hasCoverage) { 744 hasCoverage = requiresAttributeCoverage || 745 (desc->fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit); 746 } 747 748 if (hasCoverage) { 749 // color filter is applied between color/coverage computation 750 if (SkXfermode::kDst_Mode != desc->fColorFilterXfermode) { 751 desc->fFirstCoverageStage = firstCoverageStage; 752 } 753 754 if (this->getCaps().dualSourceBlendingSupport() && 755 !(blendOpts & (kEmitCoverage_BlendOptFlag | kCoverageAsAlpha_BlendOptFlag))) { 756 if (kZero_GrBlendCoeff == dstCoeff) { 757 // write the coverage value to second color 758 desc->fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput; 759 desc->fFirstCoverageStage = firstCoverageStage; 760 } else if (kSA_GrBlendCoeff == dstCoeff) { 761 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 762 desc->fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput; 763 desc->fFirstCoverageStage = firstCoverageStage; 764 } else if (kSC_GrBlendCoeff == dstCoeff) { 765 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 766 desc->fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput; 767 desc->fFirstCoverageStage = firstCoverageStage; 768 } 769 } 770 } 771} 772