| OLD | NEW |
| (Empty) |
| 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 "builders/GrGLProgramBuilder.h" | |
| 11 #include "GrProcessor.h" | |
| 12 #include "GrGLProcessor.h" | |
| 13 #include "GrGLPathRendering.h" | |
| 14 #include "GrOptDrawState.h" | |
| 15 #include "SkRTConf.h" | |
| 16 #include "SkTSearch.h" | |
| 17 | |
| 18 #ifdef PROGRAM_CACHE_STATS | |
| 19 SK_CONF_DECLARE(bool, c_DisplayCache, "gpu.displayCache", false, | |
| 20 "Display program cache usage."); | |
| 21 #endif | |
| 22 | |
| 23 typedef GrGLProgramDataManager::UniformHandle UniformHandle; | |
| 24 | |
| 25 struct GrGLGpu::ProgramCache::Entry { | |
| 26 SK_DECLARE_INST_COUNT_ROOT(Entry); | |
| 27 Entry() : fProgram(NULL), fLRUStamp(0) {} | |
| 28 | |
| 29 SkAutoTUnref<GrGLProgram> fProgram; | |
| 30 unsigned int fLRUStamp; | |
| 31 }; | |
| 32 | |
| 33 struct GrGLGpu::ProgramCache::ProgDescLess { | |
| 34 bool operator() (const GrProgramDesc& desc, const Entry* entry) { | |
| 35 SkASSERT(entry->fProgram.get()); | |
| 36 return GrProgramDesc::Less(desc, entry->fProgram->getDesc()); | |
| 37 } | |
| 38 | |
| 39 bool operator() (const Entry* entry, const GrProgramDesc& desc) { | |
| 40 SkASSERT(entry->fProgram.get()); | |
| 41 return GrProgramDesc::Less(entry->fProgram->getDesc(), desc); | |
| 42 } | |
| 43 }; | |
| 44 | |
| 45 GrGLGpu::ProgramCache::ProgramCache(GrGLGpu* gpu) | |
| 46 : fCount(0) | |
| 47 , fCurrLRUStamp(0) | |
| 48 , fGpu(gpu) | |
| 49 #ifdef PROGRAM_CACHE_STATS | |
| 50 , fTotalRequests(0) | |
| 51 , fCacheMisses(0) | |
| 52 , fHashMisses(0) | |
| 53 #endif | |
| 54 { | |
| 55 for (int i = 0; i < 1 << kHashBits; ++i) { | |
| 56 fHashTable[i] = NULL; | |
| 57 } | |
| 58 } | |
| 59 | |
| 60 GrGLGpu::ProgramCache::~ProgramCache() { | |
| 61 for (int i = 0; i < fCount; ++i){ | |
| 62 SkDELETE(fEntries[i]); | |
| 63 } | |
| 64 // dump stats | |
| 65 #ifdef PROGRAM_CACHE_STATS | |
| 66 if (c_DisplayCache) { | |
| 67 SkDebugf("--- Program Cache ---\n"); | |
| 68 SkDebugf("Total requests: %d\n", fTotalRequests); | |
| 69 SkDebugf("Cache misses: %d\n", fCacheMisses); | |
| 70 SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ? | |
| 71 100.f * fCacheMisses / fTotalRequest
s : | |
| 72 0.f); | |
| 73 int cacheHits = fTotalRequests - fCacheMisses; | |
| 74 SkDebugf("Hash miss %%: %f\n", (cacheHits > 0) ? 100.f * fHashMisses / c
acheHits : 0.f); | |
| 75 SkDebugf("---------------------\n"); | |
| 76 } | |
| 77 #endif | |
| 78 } | |
| 79 | |
| 80 void GrGLGpu::ProgramCache::abandon() { | |
| 81 for (int i = 0; i < fCount; ++i) { | |
| 82 SkASSERT(fEntries[i]->fProgram.get()); | |
| 83 fEntries[i]->fProgram->abandon(); | |
| 84 SkDELETE(fEntries[i]); | |
| 85 } | |
| 86 fCount = 0; | |
| 87 } | |
| 88 | |
| 89 int GrGLGpu::ProgramCache::search(const GrProgramDesc& desc) const { | |
| 90 ProgDescLess less; | |
| 91 return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less); | |
| 92 } | |
| 93 | |
| 94 GrGLProgram* GrGLGpu::ProgramCache::getProgram(const GrOptDrawState& optState) { | |
| 95 #ifdef PROGRAM_CACHE_STATS | |
| 96 ++fTotalRequests; | |
| 97 #endif | |
| 98 | |
| 99 Entry* entry = NULL; | |
| 100 | |
| 101 uint32_t hashIdx = optState.programDesc().getChecksum(); | |
| 102 hashIdx ^= hashIdx >> 16; | |
| 103 if (kHashBits <= 8) { | |
| 104 hashIdx ^= hashIdx >> 8; | |
| 105 } | |
| 106 hashIdx &=((1 << kHashBits) - 1); | |
| 107 Entry* hashedEntry = fHashTable[hashIdx]; | |
| 108 if (hashedEntry && hashedEntry->fProgram->getDesc() == optState.programDesc(
)) { | |
| 109 SkASSERT(hashedEntry->fProgram); | |
| 110 entry = hashedEntry; | |
| 111 } | |
| 112 | |
| 113 int entryIdx; | |
| 114 if (NULL == entry) { | |
| 115 entryIdx = this->search(optState.programDesc()); | |
| 116 if (entryIdx >= 0) { | |
| 117 entry = fEntries[entryIdx]; | |
| 118 #ifdef PROGRAM_CACHE_STATS | |
| 119 ++fHashMisses; | |
| 120 #endif | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 if (NULL == entry) { | |
| 125 // We have a cache miss | |
| 126 #ifdef PROGRAM_CACHE_STATS | |
| 127 ++fCacheMisses; | |
| 128 #endif | |
| 129 GrGLProgram* program = GrGLProgramBuilder::CreateProgram(optState, fGpu)
; | |
| 130 if (NULL == program) { | |
| 131 return NULL; | |
| 132 } | |
| 133 int purgeIdx = 0; | |
| 134 if (fCount < kMaxEntries) { | |
| 135 entry = SkNEW(Entry); | |
| 136 purgeIdx = fCount++; | |
| 137 fEntries[purgeIdx] = entry; | |
| 138 } else { | |
| 139 SkASSERT(fCount == kMaxEntries); | |
| 140 purgeIdx = 0; | |
| 141 for (int i = 1; i < kMaxEntries; ++i) { | |
| 142 if (fEntries[i]->fLRUStamp < fEntries[purgeIdx]->fLRUStamp) { | |
| 143 purgeIdx = i; | |
| 144 } | |
| 145 } | |
| 146 entry = fEntries[purgeIdx]; | |
| 147 int purgedHashIdx = entry->fProgram->getDesc().getChecksum() & ((1 <
< kHashBits) - 1); | |
| 148 if (fHashTable[purgedHashIdx] == entry) { | |
| 149 fHashTable[purgedHashIdx] = NULL; | |
| 150 } | |
| 151 } | |
| 152 SkASSERT(fEntries[purgeIdx] == entry); | |
| 153 entry->fProgram.reset(program); | |
| 154 // We need to shift fEntries around so that the entry currently at purge
Idx is placed | |
| 155 // just before the entry at ~entryIdx (in order to keep fEntries sorted
by descriptor). | |
| 156 entryIdx = ~entryIdx; | |
| 157 if (entryIdx < purgeIdx) { | |
| 158 // Let E and P be the entries at index entryIdx and purgeIdx, respe
ctively. | |
| 159 // If the entries array looks like this: | |
| 160 // aaaaEbbbbbPccccc | |
| 161 // we rearrange it to look like this: | |
| 162 // aaaaPEbbbbbccccc | |
| 163 size_t copySize = (purgeIdx - entryIdx) * sizeof(Entry*); | |
| 164 memmove(fEntries + entryIdx + 1, fEntries + entryIdx, copySize); | |
| 165 fEntries[entryIdx] = entry; | |
| 166 } else if (purgeIdx < entryIdx) { | |
| 167 // If the entries array looks like this: | |
| 168 // aaaaPbbbbbEccccc | |
| 169 // we rearrange it to look like this: | |
| 170 // aaaabbbbbPEccccc | |
| 171 size_t copySize = (entryIdx - purgeIdx - 1) * sizeof(Entry*); | |
| 172 memmove(fEntries + purgeIdx, fEntries + purgeIdx + 1, copySize); | |
| 173 fEntries[entryIdx - 1] = entry; | |
| 174 } | |
| 175 #ifdef SK_DEBUG | |
| 176 SkASSERT(fEntries[0]->fProgram.get()); | |
| 177 for (int i = 0; i < fCount - 1; ++i) { | |
| 178 SkASSERT(fEntries[i + 1]->fProgram.get()); | |
| 179 const GrProgramDesc& a = fEntries[i]->fProgram->getDesc(); | |
| 180 const GrProgramDesc& b = fEntries[i + 1]->fProgram->getDesc(); | |
| 181 SkASSERT(GrProgramDesc::Less(a, b)); | |
| 182 SkASSERT(!GrProgramDesc::Less(b, a)); | |
| 183 } | |
| 184 #endif | |
| 185 } | |
| 186 | |
| 187 fHashTable[hashIdx] = entry; | |
| 188 entry->fLRUStamp = fCurrLRUStamp; | |
| 189 | |
| 190 if (SK_MaxU32 == fCurrLRUStamp) { | |
| 191 // wrap around! just trash our LRU, one time hit. | |
| 192 for (int i = 0; i < fCount; ++i) { | |
| 193 fEntries[i]->fLRUStamp = 0; | |
| 194 } | |
| 195 } | |
| 196 ++fCurrLRUStamp; | |
| 197 return entry->fProgram; | |
| 198 } | |
| OLD | NEW |