| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrGpuGL.h" | 8 #include "GrGpuGL.h" |
| 9 | 9 |
| 10 #include "GrEffect.h" | 10 #include "GrEffect.h" |
| 11 #include "GrGLEffect.h" | 11 #include "GrGLEffect.h" |
| 12 #include "SkTSearch.h" |
| 12 | 13 |
| 13 typedef GrGLUniformManager::UniformHandle UniformHandle; | 14 typedef GrGLUniformManager::UniformHandle UniformHandle; |
| 14 static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidU
niformHandle; | 15 static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidU
niformHandle; |
| 15 | 16 |
| 16 #define SKIP_CACHE_CHECK true | 17 struct GrGpuGL::ProgramCache::Entry { |
| 17 #define GR_UINT32_MAX static_cast<uint32_t>(-1) | 18 SK_DECLARE_INST_COUNT_ROOT(Entry); |
| 19 Entry() : fProgram(NULL), fLRUStamp(0) {} |
| 20 |
| 21 SkAutoTUnref<GrGLProgram> fProgram; |
| 22 unsigned int fLRUStamp; |
| 23 }; |
| 24 |
| 25 SK_DEFINE_INST_COUNT(GrGpuGL::ProgramCache::Entry); |
| 26 |
| 27 struct GrGpuGL::ProgramCache::ProgDescLess { |
| 28 bool operator() (const GrGLProgramDesc& desc, const Entry* entry) { |
| 29 GrAssert(NULL != entry->fProgram.get()); |
| 30 return GrGLProgramDesc::Less(desc, entry->fProgram->getDesc()); |
| 31 } |
| 32 |
| 33 bool operator() (const Entry* entry, const GrGLProgramDesc& desc) { |
| 34 GrAssert(NULL != entry->fProgram.get()); |
| 35 return GrGLProgramDesc::Less(entry->fProgram->getDesc(), desc); |
| 36 } |
| 37 }; |
| 18 | 38 |
| 19 GrGpuGL::ProgramCache::ProgramCache(const GrGLContext& gl) | 39 GrGpuGL::ProgramCache::ProgramCache(const GrGLContext& gl) |
| 20 : fCount(0) | 40 : fCount(0) |
| 21 , fCurrLRUStamp(0) | 41 , fCurrLRUStamp(0) |
| 22 , fGL(gl) | 42 , fGL(gl) |
| 23 #ifdef PROGRAM_CACHE_STATS | 43 #ifdef PROGRAM_CACHE_STATS |
| 24 , fTotalRequests(0) | 44 , fTotalRequests(0) |
| 25 , fCacheMisses(0) | 45 , fCacheMisses(0) |
| 46 , fHashMisses(0) |
| 26 #endif | 47 #endif |
| 27 { | 48 { |
| 49 for (int i = 0; i < 1 << kHashBits; ++i) { |
| 50 fHashTable[i] = NULL; |
| 51 } |
| 28 } | 52 } |
| 29 | 53 |
| 30 GrGpuGL::ProgramCache::~ProgramCache() { | 54 GrGpuGL::ProgramCache::~ProgramCache() { |
| 55 for (int i = 0; i < fCount; ++i){ |
| 56 SkDELETE(fEntries[i]); |
| 57 } |
| 31 // dump stats | 58 // dump stats |
| 32 #ifdef PROGRAM_CACHE_STATS | 59 #ifdef PROGRAM_CACHE_STATS |
| 33 SkDebugf("--- Program Cache ---\n"); | 60 SkDebugf("--- Program Cache ---\n"); |
| 34 SkDebugf("Total requests: %d\n", fTotalRequests); | 61 SkDebugf("Total requests: %d\n", fTotalRequests); |
| 35 SkDebugf("Cache misses: %d\n", fCacheMisses); | 62 SkDebugf("Cache misses: %d\n", fCacheMisses); |
| 36 SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) | 63 SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ? |
| 37 ? (float)fCacheMisses/(float)fTotalRequests
: 0.0f); | 64 100.f * fCacheMisses / fTotalRequests : |
| 65 0.f); |
| 66 int cacheHits = fTotalRequests - fCacheMisses; |
| 67 SkDebugf("Hash miss %%: %f\n", (cacheHits > 0) ? 100.f * fHashMisses / cache
Hits : 0.f); |
| 38 SkDebugf("---------------------\n"); | 68 SkDebugf("---------------------\n"); |
| 39 #endif | 69 #endif |
| 40 } | 70 } |
| 41 | 71 |
| 42 void GrGpuGL::ProgramCache::abandon() { | 72 void GrGpuGL::ProgramCache::abandon() { |
| 43 for (int i = 0; i < fCount; ++i) { | 73 for (int i = 0; i < fCount; ++i) { |
| 44 GrAssert(NULL != fEntries[i].fProgram.get()); | 74 GrAssert(NULL != fEntries[i]->fProgram.get()); |
| 45 fEntries[i].fProgram->abandon(); | 75 fEntries[i]->fProgram->abandon(); |
| 46 fEntries[i].fProgram.reset(NULL); | 76 fEntries[i]->fProgram.reset(NULL); |
| 47 } | 77 } |
| 48 fCount = 0; | 78 fCount = 0; |
| 49 } | 79 } |
| 50 | 80 |
| 81 int GrGpuGL::ProgramCache::search(const GrGLProgramDesc& desc) const { |
| 82 ProgDescLess less; |
| 83 return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less); |
| 84 } |
| 85 |
| 51 GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc, | 86 GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc, |
| 52 const GrEffectStage* stages[]) { | 87 const GrEffectStage* stages[]) { |
| 53 Entry newEntry; | |
| 54 newEntry.fKey.setKeyData(desc.asKey()); | |
| 55 #ifdef PROGRAM_CACHE_STATS | 88 #ifdef PROGRAM_CACHE_STATS |
| 56 ++fTotalRequests; | 89 ++fTotalRequests; |
| 57 #endif | 90 #endif |
| 58 | 91 |
| 59 Entry* entry = fHashCache.find(newEntry.fKey); | 92 Entry* entry = NULL; |
| 93 |
| 94 uint32_t hashIdx = desc.getChecksum(); |
| 95 hashIdx ^= hashIdx >> 16; |
| 96 if (kHashBits <= 8) { |
| 97 hashIdx ^= hashIdx >> 8; |
| 98 } |
| 99 hashIdx &=((1 << kHashBits) - 1); |
| 100 Entry* hashedEntry = fHashTable[hashIdx]; |
| 101 if (NULL != hashedEntry && hashedEntry->fProgram->getDesc() == desc) { |
| 102 GrAssert(NULL != hashedEntry->fProgram); |
| 103 entry = hashedEntry; |
| 104 } |
| 105 |
| 106 int entryIdx; |
| 60 if (NULL == entry) { | 107 if (NULL == entry) { |
| 108 entryIdx = this->search(desc); |
| 109 if (entryIdx >= 0) { |
| 110 entry = fEntries[entryIdx]; |
| 111 #ifdef PROGRAM_CACHE_STATS |
| 112 ++fHashMisses; |
| 113 #endif |
| 114 } |
| 115 } |
| 116 |
| 117 if (NULL == entry) { |
| 118 // We have a cache miss |
| 61 #ifdef PROGRAM_CACHE_STATS | 119 #ifdef PROGRAM_CACHE_STATS |
| 62 ++fCacheMisses; | 120 ++fCacheMisses; |
| 63 #endif | 121 #endif |
| 64 newEntry.fProgram.reset(GrGLProgram::Create(fGL, desc, stages)); | 122 GrGLProgram* program = GrGLProgram::Create(fGL, desc, stages); |
| 65 if (NULL == newEntry.fProgram.get()) { | 123 if (NULL == program) { |
| 66 return NULL; | 124 return NULL; |
| 67 } | 125 } |
| 126 int purgeIdx = 0; |
| 68 if (fCount < kMaxEntries) { | 127 if (fCount < kMaxEntries) { |
| 69 entry = fEntries + fCount; | 128 entry = SkNEW(Entry); |
| 70 ++fCount; | 129 purgeIdx = fCount++; |
| 130 fEntries[purgeIdx] = entry; |
| 71 } else { | 131 } else { |
| 72 GrAssert(kMaxEntries == fCount); | 132 GrAssert(fCount == kMaxEntries); |
| 73 entry = fEntries; | 133 purgeIdx = 0; |
| 74 for (int i = 1; i < kMaxEntries; ++i) { | 134 for (int i = 1; i < kMaxEntries; ++i) { |
| 75 if (fEntries[i].fLRUStamp < entry->fLRUStamp) { | 135 if (fEntries[i]->fLRUStamp < fEntries[purgeIdx]->fLRUStamp) { |
| 76 entry = fEntries + i; | 136 purgeIdx = i; |
| 77 } | 137 } |
| 78 } | 138 } |
| 79 fHashCache.remove(entry->fKey, entry); | 139 entry = fEntries[purgeIdx]; |
| 140 int purgedHashIdx = entry->fProgram->getDesc().getChecksum() & ((1 <
< kHashBits) - 1); |
| 141 if (fHashTable[purgedHashIdx] == entry) { |
| 142 fHashTable[purgedHashIdx] = NULL; |
| 143 } |
| 80 } | 144 } |
| 81 *entry = newEntry; | 145 GrAssert(fEntries[purgeIdx] == entry); |
| 82 fHashCache.insert(entry->fKey, entry); | 146 entry->fProgram.reset(program); |
| 147 // We need to shift fEntries around so that the entry currently at purge
Idx is placed |
| 148 // just before the entry at ~entryIdx (in order to keep fEntries sorted
by descriptor). |
| 149 entryIdx = ~entryIdx; |
| 150 if (entryIdx < purgeIdx) { |
| 151 // Let E and P be the entries at index entryIdx and purgeIdx, respe
ctively. |
| 152 // If the entries array looks like this: |
| 153 // aaaaEbbbbbPccccc |
| 154 // we rearrange it to look like this: |
| 155 // aaaaPEbbbbbccccc |
| 156 size_t copySize = (purgeIdx - entryIdx) * sizeof(Entry*); |
| 157 memmove(fEntries + entryIdx + 1, fEntries + entryIdx, copySize); |
| 158 fEntries[entryIdx] = entry; |
| 159 } else if (purgeIdx < entryIdx) { |
| 160 // If the entries array looks like this: |
| 161 // aaaaPbbbbbEccccc |
| 162 // we rearrange it to look like this: |
| 163 // aaaabbbbbPEccccc |
| 164 size_t copySize = (entryIdx - purgeIdx - 1) * sizeof(Entry*); |
| 165 memmove(fEntries + purgeIdx, fEntries + purgeIdx + 1, copySize); |
| 166 fEntries[entryIdx - 1] = entry; |
| 167 } |
| 168 #if GR_DEBUG |
| 169 GrAssert(NULL != fEntries[0]->fProgram.get()); |
| 170 for (int i = 0; i < fCount - 1; ++i) { |
| 171 GrAssert(NULL != fEntries[i + 1]->fProgram.get()); |
| 172 const GrGLProgramDesc& a = fEntries[i]->fProgram->getDesc(); |
| 173 const GrGLProgramDesc& b = fEntries[i + 1]->fProgram->getDesc(); |
| 174 GrAssert(GrGLProgramDesc::Less(a, b)); |
| 175 GrAssert(!GrGLProgramDesc::Less(b, a)); |
| 176 } |
| 177 #endif |
| 83 } | 178 } |
| 84 | 179 |
| 180 fHashTable[hashIdx] = entry; |
| 85 entry->fLRUStamp = fCurrLRUStamp; | 181 entry->fLRUStamp = fCurrLRUStamp; |
| 86 if (GR_UINT32_MAX == fCurrLRUStamp) { | 182 |
| 183 if (SK_MaxU32 == fCurrLRUStamp) { |
| 87 // wrap around! just trash our LRU, one time hit. | 184 // wrap around! just trash our LRU, one time hit. |
| 88 for (int i = 0; i < fCount; ++i) { | 185 for (int i = 0; i < fCount; ++i) { |
| 89 fEntries[i].fLRUStamp = 0; | 186 fEntries[i]->fLRUStamp = 0; |
| 90 } | 187 } |
| 91 } | 188 } |
| 92 ++fCurrLRUStamp; | 189 ++fCurrLRUStamp; |
| 93 return entry->fProgram; | 190 return entry->fProgram; |
| 94 } | 191 } |
| 95 | 192 |
| 96 //////////////////////////////////////////////////////////////////////////////// | 193 //////////////////////////////////////////////////////////////////////////////// |
| 97 | 194 |
| 98 void GrGpuGL::abandonResources(){ | 195 void GrGpuGL::abandonResources(){ |
| 99 INHERITED::abandonResources(); | 196 INHERITED::abandonResources(); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 this->flushMiscFixedFunctionState(); | 267 this->flushMiscFixedFunctionState(); |
| 171 | 268 |
| 172 GrBlendCoeff srcCoeff; | 269 GrBlendCoeff srcCoeff; |
| 173 GrBlendCoeff dstCoeff; | 270 GrBlendCoeff dstCoeff; |
| 174 GrDrawState::BlendOptFlags blendOpts = drawState.getBlendOpts(false, &sr
cCoeff, &dstCoeff); | 271 GrDrawState::BlendOptFlags blendOpts = drawState.getBlendOpts(false, &sr
cCoeff, &dstCoeff); |
| 175 if (GrDrawState::kSkipDraw_BlendOptFlag & blendOpts) { | 272 if (GrDrawState::kSkipDraw_BlendOptFlag & blendOpts) { |
| 176 return false; | 273 return false; |
| 177 } | 274 } |
| 178 | 275 |
| 179 const GrEffectStage* stages[GrDrawState::kNumStages]; | 276 const GrEffectStage* stages[GrDrawState::kNumStages]; |
| 180 for (int i = 0; i < GrDrawState::kNumStages; ++i) { | |
| 181 stages[i] = drawState.isStageEnabled(i) ? &drawState.getStage(i) : N
ULL; | |
| 182 } | |
| 183 GrGLProgramDesc desc; | 277 GrGLProgramDesc desc; |
| 184 GrGLProgramDesc::Build(this->getDrawState(), | 278 GrGLProgramDesc::Build(this->getDrawState(), |
| 185 kDrawPoints_DrawType == type, | 279 kDrawPoints_DrawType == type, |
| 186 blendOpts, | 280 blendOpts, |
| 187 srcCoeff, | 281 srcCoeff, |
| 188 dstCoeff, | 282 dstCoeff, |
| 189 this, | 283 this, |
| 190 dstCopy, | 284 dstCopy, |
| 285 stages, |
| 191 &desc); | 286 &desc); |
| 192 | 287 |
| 193 fCurrentProgram.reset(fProgramCache->getProgram(desc, stages)); | 288 fCurrentProgram.reset(fProgramCache->getProgram(desc, stages)); |
| 194 if (NULL == fCurrentProgram.get()) { | 289 if (NULL == fCurrentProgram.get()) { |
| 195 GrAssert(!"Failed to create program!"); | 290 GrAssert(!"Failed to create program!"); |
| 196 return false; | 291 return false; |
| 197 } | 292 } |
| 198 fCurrentProgram.get()->ref(); | 293 fCurrentProgram.get()->ref(); |
| 199 | 294 |
| 200 GrGLuint programID = fCurrentProgram->programID(); | 295 GrGLuint programID = fCurrentProgram->programID(); |
| 201 if (fHWProgramID != programID) { | 296 if (fHWProgramID != programID) { |
| 202 GL_CALL(UseProgram(programID)); | 297 GL_CALL(UseProgram(programID)); |
| 203 fHWProgramID = programID; | 298 fHWProgramID = programID; |
| 204 } | 299 } |
| 205 | 300 |
| 206 fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff); | 301 fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff); |
| 207 this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff); | 302 this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff); |
| 208 | 303 |
| 209 GrColor color; | 304 fCurrentProgram->setData(this, blendOpts, stages, dstCopy, &fSharedGLPro
gramState); |
| 210 GrColor coverage; | |
| 211 if (blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag) { | |
| 212 color = 0; | |
| 213 coverage = 0; | |
| 214 } else if (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) { | |
| 215 color = 0xffffffff; | |
| 216 coverage = drawState.getCoverage(); | |
| 217 } else { | |
| 218 color = drawState.getColor(); | |
| 219 coverage = drawState.getCoverage(); | |
| 220 } | |
| 221 fCurrentProgram->setData(this, color, coverage, dstCopy, &fSharedGLProgr
amState); | |
| 222 } | 305 } |
| 223 this->flushStencil(type); | 306 this->flushStencil(type); |
| 224 this->flushScissor(); | 307 this->flushScissor(); |
| 225 this->flushAAState(type); | 308 this->flushAAState(type); |
| 226 | 309 |
| 227 GrIRect* devRect = NULL; | 310 GrIRect* devRect = NULL; |
| 228 GrIRect devClipBounds; | 311 GrIRect devClipBounds; |
| 229 if (drawState.isClipState()) { | 312 if (drawState.isClipState()) { |
| 230 this->getClip()->getConservativeBounds(drawState.getRenderTarget(), &dev
ClipBounds); | 313 this->getClip()->getConservativeBounds(drawState.getRenderTarget(), &dev
ClipBounds); |
| 231 devRect = &devClipBounds; | 314 devRect = &devClipBounds; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 GrGLAttribTypeToLayout(attribType).fCount, | 389 GrGLAttribTypeToLayout(attribType).fCount, |
| 307 GrGLAttribTypeToLayout(attribType).fType, | 390 GrGLAttribTypeToLayout(attribType).fType, |
| 308 GrGLAttribTypeToLayout(attribType).fNormalized, | 391 GrGLAttribTypeToLayout(attribType).fNormalized, |
| 309 stride, | 392 stride, |
| 310 reinterpret_cast<GrGLvoid*>( | 393 reinterpret_cast<GrGLvoid*>( |
| 311 vertexOffsetInBytes + vertexAttrib->fOffset)); | 394 vertexOffsetInBytes + vertexAttrib->fOffset)); |
| 312 } | 395 } |
| 313 | 396 |
| 314 attribState->disableUnusedAttribArrays(this, usedAttribArraysMask); | 397 attribState->disableUnusedAttribArrays(this, usedAttribArraysMask); |
| 315 } | 398 } |
| OLD | NEW |