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 |