1 /* 2 Copyright 2011 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #include "GrBinHashKey.h" 18 #include "GrGLProgram.h" 19 #include "GrGpuGLShaders.h" 20 #include "GrGpuVertex.h" 21 #include "GrMemory.h" 22 #include "GrNoncopyable.h" 23 #include "GrStringBuilder.h" 24 #include "GrRandom.h" 25 26 #define SKIP_CACHE_CHECK true 27 #define GR_UINT32_MAX static_cast<uint32_t>(-1) 28 29 #include "GrTHashCache.h" 30 31 class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable { 32 private: 33 class Entry; 34 35 #if GR_DEBUG 36 typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug 37 #else 38 typedef GrBinHashKey<Entry, 64> ProgramHashKey; 39 #endif 40 41 class Entry : public ::GrNoncopyable { 42 public: Entry()43 Entry() {} copyAndTakeOwnership(Entry & entry)44 void copyAndTakeOwnership(Entry& entry) { 45 fProgramData.copyAndTakeOwnership(entry.fProgramData); 46 fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer 47 fLRUStamp = entry.fLRUStamp; 48 } 49 50 public: compare(const ProgramHashKey & key) const51 int compare(const ProgramHashKey& key) const { return fKey.compare(key); } 52 53 public: 54 GrGLProgram::CachedData fProgramData; 55 ProgramHashKey fKey; 56 unsigned int fLRUStamp; 57 }; 58 59 GrTHashTable<Entry, ProgramHashKey, 8> fHashCache; 60 61 // We may have kMaxEntries+1 shaders in the GL context because 62 // we create a new shader before evicting from the cache. 63 enum { 64 kMaxEntries = 32 65 }; 66 Entry fEntries[kMaxEntries]; 67 int fCount; 68 unsigned int fCurrLRUStamp; 69 70 public: ProgramCache()71 ProgramCache() 72 : fCount(0) 73 , fCurrLRUStamp(0) { 74 } 75 ~ProgramCache()76 ~ProgramCache() { 77 for (int i = 0; i < fCount; ++i) { 78 GrGpuGLShaders::DeleteProgram(&fEntries[i].fProgramData); 79 } 80 } 81 abandon()82 void abandon() { 83 fCount = 0; 84 } 85 invalidateViewMatrices()86 void invalidateViewMatrices() { 87 for (int i = 0; i < fCount; ++i) { 88 // set to illegal matrix 89 fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix(); 90 } 91 } 92 getProgramData(const GrGLProgram & desc)93 GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) { 94 Entry newEntry; 95 while (newEntry.fKey.doPass()) { 96 desc.buildKey(newEntry.fKey); 97 } 98 Entry* entry = fHashCache.find(newEntry.fKey); 99 if (NULL == entry) { 100 if (!desc.genProgram(&newEntry.fProgramData)) { 101 return NULL; 102 } 103 if (fCount < kMaxEntries) { 104 entry = fEntries + fCount; 105 ++fCount; 106 } else { 107 GrAssert(kMaxEntries == fCount); 108 entry = fEntries; 109 for (int i = 1; i < kMaxEntries; ++i) { 110 if (fEntries[i].fLRUStamp < entry->fLRUStamp) { 111 entry = fEntries + i; 112 } 113 } 114 fHashCache.remove(entry->fKey, entry); 115 GrGpuGLShaders::DeleteProgram(&entry->fProgramData); 116 } 117 entry->copyAndTakeOwnership(newEntry); 118 fHashCache.insert(entry->fKey, entry); 119 } 120 121 entry->fLRUStamp = fCurrLRUStamp; 122 if (GR_UINT32_MAX == fCurrLRUStamp) { 123 // wrap around! just trash our LRU, one time hit. 124 for (int i = 0; i < fCount; ++i) { 125 fEntries[i].fLRUStamp = 0; 126 } 127 } 128 ++fCurrLRUStamp; 129 return &entry->fProgramData; 130 } 131 }; 132 abandonResources()133 void GrGpuGLShaders::abandonResources(){ 134 INHERITED::abandonResources(); 135 fProgramCache->abandon(); 136 } 137 DeleteProgram(GrGLProgram::CachedData * programData)138 void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) { 139 GR_GL(DeleteShader(programData->fVShaderID)); 140 GR_GL(DeleteShader(programData->fFShaderID)); 141 GR_GL(DeleteProgram(programData->fProgramID)); 142 GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));) 143 } 144 ProgramUnitTest()145 void GrGpuGLShaders::ProgramUnitTest() { 146 147 static const int STAGE_OPTS[] = { 148 0, 149 GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit, 150 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping 151 }; 152 static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = { 153 GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation, 154 GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation 155 }; 156 static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = { 157 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping, 158 GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping, 159 GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping, 160 GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping 161 }; 162 static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = { 163 GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode, 164 GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode, 165 }; 166 GrGLProgram program; 167 GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc; 168 169 static const int NUM_TESTS = 512; 170 171 // GrRandoms nextU() values have patterns in the low bits 172 // So using nextU() % array_count might never take some values. 173 GrRandom random; 174 for (int t = 0; t < NUM_TESTS; ++t) { 175 176 #if 0 177 GrPrintf("\nTest Program %d\n-------------\n", t); 178 static const int stop = -1; 179 if (t == stop) { 180 int breakpointhere = 9; 181 } 182 #endif 183 184 pdesc.fVertexLayout = 0; 185 pdesc.fEmitsPointSize = random.nextF() > .5f; 186 float colorType = random.nextF(); 187 if (colorType < 1.f / 3.f) { 188 pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType; 189 } else if (colorType < 2.f / 3.f) { 190 pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType; 191 } else { 192 pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType; 193 } 194 195 int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt)); 196 pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx; 197 198 idx = (int)(random.nextF() * (kNumStages+1)); 199 pdesc.fFirstCoverageStage = idx; 200 201 pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1)); 202 203 if (fDualSourceBlendingSupport) { 204 pdesc.fDualSrcOutput = 205 (GrGLProgram::ProgramDesc::DualSrcOutput) 206 (int)(random.nextF() * GrGLProgram::ProgramDesc::kDualSrcOutputCnt); 207 } else { 208 pdesc.fDualSrcOutput = 209 GrGLProgram::ProgramDesc::kNone_DualSrcOutput; 210 } 211 212 for (int s = 0; s < kNumStages; ++s) { 213 // enable the stage? 214 if (random.nextF() > .5f) { 215 // use separate tex coords? 216 if (random.nextF() > .5f) { 217 int t = (int)(random.nextF() * kMaxTexCoords); 218 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t); 219 } else { 220 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s); 221 } 222 } 223 // use text-formatted verts? 224 if (random.nextF() > .5f) { 225 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit; 226 } 227 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS)); 228 pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx]; 229 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES)); 230 pdesc.fStages[s].fModulation = STAGE_MODULATES[idx]; 231 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS)); 232 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx]; 233 idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES)); 234 pdesc.fStages[s].fFetchMode = FETCH_MODES[idx]; 235 pdesc.fStages[s].setEnabled(VertexUsesStage(s, pdesc.fVertexLayout)); 236 } 237 GrGLProgram::CachedData cachedData; 238 program.genProgram(&cachedData); 239 DeleteProgram(&cachedData); 240 bool again = false; 241 if (again) { 242 program.genProgram(&cachedData); 243 DeleteProgram(&cachedData); 244 } 245 } 246 } 247 GrGpuGLShaders()248 GrGpuGLShaders::GrGpuGLShaders() { 249 250 resetContext(); 251 int major, minor; 252 gl_version(&major, &minor); 253 254 f4X4DownsampleFilterSupport = true; 255 if (GR_GL_SUPPORT_DESKTOP) { 256 fDualSourceBlendingSupport = 257 major > 3 ||(3 == major && 3 <= minor) || 258 has_gl_extension("GL_ARB_blend_func_extended"); 259 } else { 260 fDualSourceBlendingSupport = false; 261 } 262 263 fProgramData = NULL; 264 fProgramCache = new ProgramCache(); 265 266 #if 0 267 ProgramUnitTest(); 268 #endif 269 } 270 ~GrGpuGLShaders()271 GrGpuGLShaders::~GrGpuGLShaders() { 272 delete fProgramCache; 273 } 274 getHWSamplerMatrix(int stage)275 const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) { 276 GrAssert(fProgramData); 277 278 if (GrGLProgram::kSetAsAttribute == 279 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) { 280 return fHWDrawState.fSamplerStates[stage].getMatrix(); 281 } else { 282 return fProgramData->fTextureMatrices[stage]; 283 } 284 } 285 recordHWSamplerMatrix(int stage,const GrMatrix & matrix)286 void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) { 287 GrAssert(fProgramData); 288 if (GrGLProgram::kSetAsAttribute == 289 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) { 290 fHWDrawState.fSamplerStates[stage].setMatrix(matrix); 291 } else { 292 fProgramData->fTextureMatrices[stage] = matrix; 293 } 294 } 295 resetContext()296 void GrGpuGLShaders::resetContext() { 297 INHERITED::resetContext(); 298 299 fHWGeometryState.fVertexLayout = 0; 300 fHWGeometryState.fVertexOffset = ~0; 301 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx())); 302 for (int t = 0; t < kMaxTexCoords; ++t) { 303 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t))); 304 } 305 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx())); 306 307 fHWProgramID = 0; 308 } 309 flushViewMatrix()310 void GrGpuGLShaders::flushViewMatrix() { 311 GrAssert(NULL != fCurrDrawState.fRenderTarget); 312 GrMatrix m; 313 m.setAll( 314 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1, 315 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1, 316 0, 0, GrMatrix::I()[8]); 317 m.setConcat(m, fCurrDrawState.fViewMatrix); 318 319 // ES doesn't allow you to pass true to the transpose param, 320 // so do our own transpose 321 GrGLfloat mt[] = { 322 GrScalarToFloat(m[GrMatrix::kMScaleX]), 323 GrScalarToFloat(m[GrMatrix::kMSkewY]), 324 GrScalarToFloat(m[GrMatrix::kMPersp0]), 325 GrScalarToFloat(m[GrMatrix::kMSkewX]), 326 GrScalarToFloat(m[GrMatrix::kMScaleY]), 327 GrScalarToFloat(m[GrMatrix::kMPersp1]), 328 GrScalarToFloat(m[GrMatrix::kMTransX]), 329 GrScalarToFloat(m[GrMatrix::kMTransY]), 330 GrScalarToFloat(m[GrMatrix::kMPersp2]) 331 }; 332 333 if (GrGLProgram::kSetAsAttribute == 334 fProgramData->fUniLocations.fViewMatrixUni) { 335 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx(); 336 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0)); 337 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3)); 338 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6)); 339 } else { 340 GrAssert(GrGLProgram::kUnusedUniform != 341 fProgramData->fUniLocations.fViewMatrixUni); 342 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni, 343 1, false, mt)); 344 } 345 } 346 flushTextureDomain(int s)347 void GrGpuGLShaders::flushTextureDomain(int s) { 348 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni; 349 if (GrGLProgram::kUnusedUniform != uni) { 350 const GrRect &texDom = 351 fCurrDrawState.fSamplerStates[s].getTextureDomain(); 352 353 if (((1 << s) & fDirtyFlags.fTextureChangedMask) || 354 fProgramData->fTextureDomain[s] != texDom) { 355 356 fProgramData->fTextureDomain[s] = texDom; 357 358 float values[4] = { 359 GrScalarToFloat(texDom.left()), 360 GrScalarToFloat(texDom.top()), 361 GrScalarToFloat(texDom.right()), 362 GrScalarToFloat(texDom.bottom()) 363 }; 364 365 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; 366 GrGLTexture::Orientation orientation = texture->orientation(); 367 368 // vertical flip if necessary 369 if (GrGLTexture::kBottomUp_Orientation == orientation) { 370 values[1] = 1.0f - values[1]; 371 values[3] = 1.0f - values[3]; 372 // The top and bottom were just flipped, so correct the ordering 373 // of elements so that values = (l, t, r, b). 374 SkTSwap(values[1], values[3]); 375 } 376 377 values[0] *= SkScalarToFloat(texture->contentScaleX()); 378 values[2] *= SkScalarToFloat(texture->contentScaleX()); 379 values[1] *= SkScalarToFloat(texture->contentScaleY()); 380 values[3] *= SkScalarToFloat(texture->contentScaleY()); 381 382 GR_GL(Uniform4fv(uni, 1, values)); 383 } 384 } 385 } 386 flushTextureMatrix(int s)387 void GrGpuGLShaders::flushTextureMatrix(int s) { 388 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni; 389 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; 390 if (NULL != texture) { 391 if (GrGLProgram::kUnusedUniform != uni && 392 (((1 << s) & fDirtyFlags.fTextureChangedMask) || 393 getHWSamplerMatrix(s) != getSamplerMatrix(s))) { 394 395 GrAssert(NULL != fCurrDrawState.fTextures[s]); 396 397 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; 398 399 GrMatrix m = getSamplerMatrix(s); 400 GrSamplerState::SampleMode mode = 401 fCurrDrawState.fSamplerStates[s].getSampleMode(); 402 AdjustTextureMatrix(texture, mode, &m); 403 404 // ES doesn't allow you to pass true to the transpose param, 405 // so do our own transpose 406 GrGLfloat mt[] = { 407 GrScalarToFloat(m[GrMatrix::kMScaleX]), 408 GrScalarToFloat(m[GrMatrix::kMSkewY]), 409 GrScalarToFloat(m[GrMatrix::kMPersp0]), 410 GrScalarToFloat(m[GrMatrix::kMSkewX]), 411 GrScalarToFloat(m[GrMatrix::kMScaleY]), 412 GrScalarToFloat(m[GrMatrix::kMPersp1]), 413 GrScalarToFloat(m[GrMatrix::kMTransX]), 414 GrScalarToFloat(m[GrMatrix::kMTransY]), 415 GrScalarToFloat(m[GrMatrix::kMPersp2]) 416 }; 417 418 if (GrGLProgram::kSetAsAttribute == 419 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) { 420 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s); 421 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0)); 422 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3)); 423 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6)); 424 } else { 425 GR_GL(UniformMatrix3fv(uni, 1, false, mt)); 426 } 427 recordHWSamplerMatrix(s, getSamplerMatrix(s)); 428 } 429 } 430 } 431 flushRadial2(int s)432 void GrGpuGLShaders::flushRadial2(int s) { 433 434 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni; 435 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; 436 if (GrGLProgram::kUnusedUniform != uni && 437 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() || 438 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() || 439 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) { 440 441 GrScalar centerX1 = sampler.getRadial2CenterX1(); 442 GrScalar radius0 = sampler.getRadial2Radius0(); 443 444 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1; 445 446 float values[6] = { 447 GrScalarToFloat(a), 448 1 / (2.f * values[0]), 449 GrScalarToFloat(centerX1), 450 GrScalarToFloat(radius0), 451 GrScalarToFloat(GrMul(radius0, radius0)), 452 sampler.isRadial2PosRoot() ? 1.f : -1.f 453 }; 454 GR_GL(Uniform1fv(uni, 6, values)); 455 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1(); 456 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0(); 457 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot(); 458 } 459 } 460 flushTexelSize(int s)461 void GrGpuGLShaders::flushTexelSize(int s) { 462 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni; 463 if (GrGLProgram::kUnusedUniform != uni) { 464 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; 465 if (texture->allocWidth() != fProgramData->fTextureWidth[s] || 466 texture->allocHeight() != fProgramData->fTextureWidth[s]) { 467 468 float texelSize[] = {1.f / texture->allocWidth(), 469 1.f / texture->allocHeight()}; 470 GR_GL(Uniform2fv(uni, 1, texelSize)); 471 } 472 } 473 } 474 flushEdgeAAData()475 void GrGpuGLShaders::flushEdgeAAData() { 476 const int& uni = fProgramData->fUniLocations.fEdgesUni; 477 if (GrGLProgram::kUnusedUniform != uni) { 478 int count = fCurrDrawState.fEdgeAANumEdges; 479 Edge edges[kMaxEdges]; 480 // Flip the edges in Y 481 float height = fCurrDrawState.fRenderTarget->height(); 482 for (int i = 0; i < count; ++i) { 483 edges[i] = fCurrDrawState.fEdgeAAEdges[i]; 484 float b = edges[i].fY; 485 edges[i].fY = -b; 486 edges[i].fZ += b * height; 487 } 488 GR_GL(Uniform3fv(uni, count, &edges[0].fX)); 489 } 490 } 491 492 static const float ONE_OVER_255 = 1.f / 255.f; 493 494 #define GR_COLOR_TO_VEC4(color) {\ 495 GrColorUnpackR(color) * ONE_OVER_255,\ 496 GrColorUnpackG(color) * ONE_OVER_255,\ 497 GrColorUnpackB(color) * ONE_OVER_255,\ 498 GrColorUnpackA(color) * ONE_OVER_255 \ 499 } 500 flushColor()501 void GrGpuGLShaders::flushColor() { 502 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc(); 503 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) { 504 // color will be specified per-vertex as an attribute 505 // invalidate the const vertex attrib color 506 fHWDrawState.fColor = GrColor_ILLEGAL; 507 } else { 508 switch (desc.fColorType) { 509 case GrGLProgram::ProgramDesc::kAttribute_ColorType: 510 if (fHWDrawState.fColor != fCurrDrawState.fColor) { 511 // OpenGL ES only supports the float varities of glVertexAttrib 512 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor); 513 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c)); 514 fHWDrawState.fColor = fCurrDrawState.fColor; 515 } 516 break; 517 case GrGLProgram::ProgramDesc::kUniform_ColorType: 518 if (fProgramData->fColor != fCurrDrawState.fColor) { 519 // OpenGL ES only supports the float varities of glVertexAttrib 520 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor); 521 GrAssert(GrGLProgram::kUnusedUniform != 522 fProgramData->fUniLocations.fColorUni); 523 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c)); 524 fProgramData->fColor = fCurrDrawState.fColor; 525 } 526 break; 527 case GrGLProgram::ProgramDesc::kNone_ColorType: 528 GrAssert(0xffffffff == fCurrDrawState.fColor); 529 break; 530 default: 531 GrCrash("Unknown color type."); 532 } 533 } 534 if (fProgramData->fUniLocations.fColorFilterUni 535 != GrGLProgram::kUnusedUniform 536 && fProgramData->fColorFilterColor 537 != fCurrDrawState.fColorFilterColor) { 538 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor); 539 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c)); 540 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor; 541 } 542 } 543 544 flushGraphicsState(GrPrimitiveType type)545 bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { 546 if (!flushGLStateCommon(type)) { 547 return false; 548 } 549 550 if (fDirtyFlags.fRenderTargetChanged) { 551 // our coords are in pixel space and the GL matrices map to NDC 552 // so if the viewport changed, our matrix is now wrong. 553 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix(); 554 // we assume all shader matrices may be wrong after viewport changes 555 fProgramCache->invalidateViewMatrices(); 556 } 557 558 buildProgram(type); 559 fProgramData = fProgramCache->getProgramData(fCurrentProgram); 560 if (NULL == fProgramData) { 561 GrAssert(!"Failed to create program!"); 562 return false; 563 } 564 565 if (fHWProgramID != fProgramData->fProgramID) { 566 GR_GL(UseProgram(fProgramData->fProgramID)); 567 fHWProgramID = fProgramData->fProgramID; 568 } 569 GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend; 570 GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend; 571 572 fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff); 573 this->flushBlend(type, srcCoeff, dstCoeff); 574 575 this->flushColor(); 576 577 GrMatrix* currViewMatrix; 578 if (GrGLProgram::kSetAsAttribute == 579 fProgramData->fUniLocations.fViewMatrixUni) { 580 currViewMatrix = &fHWDrawState.fViewMatrix; 581 } else { 582 currViewMatrix = &fProgramData->fViewMatrix; 583 } 584 585 if (*currViewMatrix != fCurrDrawState.fViewMatrix) { 586 flushViewMatrix(); 587 *currViewMatrix = fCurrDrawState.fViewMatrix; 588 } 589 590 for (int s = 0; s < kNumStages; ++s) { 591 this->flushTextureMatrix(s); 592 593 this->flushRadial2(s); 594 595 this->flushTexelSize(s); 596 597 this->flushTextureDomain(s); 598 } 599 this->flushEdgeAAData(); 600 resetDirtyFlags(); 601 return true; 602 } 603 postDraw()604 void GrGpuGLShaders::postDraw() { 605 } 606 setupGeometry(int * startVertex,int * startIndex,int vertexCount,int indexCount)607 void GrGpuGLShaders::setupGeometry(int* startVertex, 608 int* startIndex, 609 int vertexCount, 610 int indexCount) { 611 612 int newColorOffset; 613 int newTexCoordOffsets[kMaxTexCoords]; 614 615 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout, 616 newTexCoordOffsets, 617 &newColorOffset); 618 int oldColorOffset; 619 int oldTexCoordOffsets[kMaxTexCoords]; 620 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout, 621 oldTexCoordOffsets, 622 &oldColorOffset); 623 bool indexed = NULL != startIndex; 624 625 int extraVertexOffset; 626 int extraIndexOffset; 627 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset); 628 629 GrGLenum scalarType; 630 bool texCoordNorm; 631 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) { 632 scalarType = GrGLTextType; 633 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED; 634 } else { 635 scalarType = GrGLType; 636 texCoordNorm = false; 637 } 638 639 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride; 640 *startVertex = 0; 641 if (indexed) { 642 *startIndex += extraIndexOffset; 643 } 644 645 // all the Pointers must be set if any of these are true 646 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty || 647 vertexOffset != fHWGeometryState.fVertexOffset || 648 newStride != oldStride; 649 650 // position and tex coord offsets change if above conditions are true 651 // or the type/normalization changed based on text vs nontext type coords. 652 bool posAndTexChange = allOffsetsChange || 653 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) && 654 (kTextFormat_VertexLayoutBit & 655 (fHWGeometryState.fVertexLayout ^ 656 fGeometrySrc.fVertexLayout))); 657 658 if (posAndTexChange) { 659 int idx = GrGLProgram::PositionAttributeIdx(); 660 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride, 661 (GrGLvoid*)vertexOffset)); 662 fHWGeometryState.fVertexOffset = vertexOffset; 663 } 664 665 for (int t = 0; t < kMaxTexCoords; ++t) { 666 if (newTexCoordOffsets[t] > 0) { 667 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]); 668 int idx = GrGLProgram::TexCoordAttributeIdx(t); 669 if (oldTexCoordOffsets[t] <= 0) { 670 GR_GL(EnableVertexAttribArray(idx)); 671 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm, 672 newStride, texCoordOffset)); 673 } else if (posAndTexChange || 674 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) { 675 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm, 676 newStride, texCoordOffset)); 677 } 678 } else if (oldTexCoordOffsets[t] > 0) { 679 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t))); 680 } 681 } 682 683 if (newColorOffset > 0) { 684 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset); 685 int idx = GrGLProgram::ColorAttributeIdx(); 686 if (oldColorOffset <= 0) { 687 GR_GL(EnableVertexAttribArray(idx)); 688 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, 689 true, newStride, colorOffset)); 690 } else if (allOffsetsChange || newColorOffset != oldColorOffset) { 691 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, 692 true, newStride, colorOffset)); 693 } 694 } else if (oldColorOffset > 0) { 695 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx())); 696 } 697 698 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout; 699 fHWGeometryState.fArrayPtrsDirty = false; 700 } 701 buildProgram(GrPrimitiveType type)702 void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { 703 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc; 704 705 // Must initialize all fields or cache will have false negatives! 706 desc.fVertexLayout = fGeometrySrc.fVertexLayout; 707 708 desc.fEmitsPointSize = kPoints_PrimitiveType == type; 709 710 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit; 711 // fColorType records how colors are specified for the program. Strip 712 // the bit from the layout to avoid false negatives when searching for an 713 // existing program in the cache. 714 desc.fVertexLayout &= ~(kColor_VertexLayoutBit); 715 716 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode; 717 718 #if GR_AGGRESSIVE_SHADER_OPTS 719 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) { 720 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType; 721 } else 722 #endif 723 #if GR_GL_NO_CONSTANT_ATTRIBUTES 724 if (!requiresAttributeColors) { 725 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType; 726 } else 727 #endif 728 { 729 if (requiresAttributeColors) {} // suppress unused var warning 730 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType; 731 } 732 733 desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges; 734 735 int lastEnabledStage = -1; 736 737 for (int s = 0; s < kNumStages; ++s) { 738 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s]; 739 740 stage.fOptFlags = 0; 741 stage.setEnabled(this->isStageEnabled(s)); 742 743 if (stage.isEnabled()) { 744 lastEnabledStage = s; 745 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; 746 GrAssert(NULL != texture); 747 // we matrix to invert when orientation is TopDown, so make sure 748 // we aren't in that case before flagging as identity. 749 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) { 750 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit; 751 } else if (!getSamplerMatrix(s).hasPerspective()) { 752 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit; 753 } 754 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) { 755 case GrSamplerState::kNormal_SampleMode: 756 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping; 757 break; 758 case GrSamplerState::kRadial_SampleMode: 759 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping; 760 break; 761 case GrSamplerState::kRadial2_SampleMode: 762 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping; 763 break; 764 case GrSamplerState::kSweep_SampleMode: 765 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping; 766 break; 767 default: 768 GrCrash("Unexpected sample mode!"); 769 break; 770 } 771 772 switch (fCurrDrawState.fSamplerStates[s].getFilter()) { 773 // these both can use a regular texture2D() 774 case GrSamplerState::kNearest_Filter: 775 case GrSamplerState::kBilinear_Filter: 776 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode; 777 break; 778 // performs 4 texture2D()s 779 case GrSamplerState::k4x4Downsample_Filter: 780 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode; 781 break; 782 default: 783 GrCrash("Unexpected filter!"); 784 break; 785 } 786 787 if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) { 788 GrAssert(GrSamplerState::kClamp_WrapMode == 789 fCurrDrawState.fSamplerStates[s].getWrapX() && 790 GrSamplerState::kClamp_WrapMode == 791 fCurrDrawState.fSamplerStates[s].getWrapY()); 792 stage.fOptFlags |= 793 GrGLProgram::ProgramDesc::StageDesc:: 794 kCustomTextureDomain_OptFlagBit; 795 } 796 797 if (GrPixelConfigIsAlphaOnly(texture->config())) { 798 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation; 799 } else { 800 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation; 801 } 802 } else { 803 stage.fOptFlags = 0; 804 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0; 805 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0; 806 } 807 } 808 809 desc.fDualSrcOutput = GrGLProgram::ProgramDesc::kNone_DualSrcOutput; 810 // use canonical value when coverage/color distinction won't affect 811 // generated code to prevent duplicate programs. 812 desc.fFirstCoverageStage = kNumStages; 813 if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) { 814 // color filter is applied between color/coverage computation 815 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) { 816 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage; 817 } 818 819 // We could consider cases where the final color is solid (0xff alpha) 820 // and the dst coeff can correctly be set to a non-dualsrc gl value. 821 // (e.g. solid draw, and dst coeff is kZero. It's correct to make 822 // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be 823 // kOne). 824 if (fDualSourceBlendingSupport) { 825 if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) { 826 // write the coverage value to second color 827 desc.fDualSrcOutput = 828 GrGLProgram::ProgramDesc::kCoverage_DualSrcOutput; 829 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage; 830 } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) { 831 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially 832 // cover 833 desc.fDualSrcOutput = 834 GrGLProgram::ProgramDesc::kCoverageISA_DualSrcOutput; 835 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage; 836 } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) { 837 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially 838 // cover 839 desc.fDualSrcOutput = 840 GrGLProgram::ProgramDesc::kCoverageISC_DualSrcOutput; 841 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage; 842 } 843 } 844 } 845 } 846