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; | |
robertphillips
2013/05/21 19:22:37
fTotalRequests -> cacheHits?
bsalomon
2013/05/22 14:11:25
Done.
| |
67 SkDebugf("Hash miss %%: %f\n", (fTotalRequests > 0) ? 100.f * fHashMisses / cacheHits : 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 |