Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Side by Side Diff: src/core/SkGlyphCache.cpp

Issue 1264103003: Parallel cache - preliminary (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fully working Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2006 The Android Open Source Project 2 * Copyright 2006 The Android Open Source Project
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 <SkOnce.h>
8 #include "SkGlyphCache.h" 9 #include "SkGlyphCache.h"
9 #include "SkGlyphCache_Globals.h" 10 #include "SkGlyphCache_Globals.h"
10 #include "SkGraphics.h" 11 #include "SkGraphics.h"
11 #include "SkLazyPtr.h" 12 #include "SkLazyPtr.h"
12 #include "SkPath.h" 13 #include "SkPath.h"
13 #include "SkTemplates.h" 14 #include "SkTemplates.h"
14 #include "SkTypeface.h" 15 #include "SkTypeface.h"
15 16
16 //#define SPEW_PURGE_STATUS 17 //#define SPEW_PURGE_STATUS
17 18
(...skipping 13 matching lines...) Expand all
31 } 32 }
32 33
33 /////////////////////////////////////////////////////////////////////////////// 34 ///////////////////////////////////////////////////////////////////////////////
34 35
35 // so we don't grow our arrays a lot 36 // so we don't grow our arrays a lot
36 #define kMinGlyphCount 16 37 #define kMinGlyphCount 16
37 #define kMinGlyphImageSize (16*2) 38 #define kMinGlyphImageSize (16*2)
38 #define kMinAllocAmount ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphC ount) 39 #define kMinAllocAmount ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphC ount)
39 40
40 SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkSca lerContext* ctx) 41 SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkSca lerContext* ctx)
41 : fDesc(desc->copy()) 42 : fNext(NULL)
43 , fPrev(NULL)
44 , fDesc(desc->copy())
45 , refCount(0)
46 , fGlyphAlloc(kMinAllocAmount)
47 , fMemoryUsed(sizeof(*this))
42 , fScalerContext(ctx) 48 , fScalerContext(ctx)
43 , fGlyphAlloc(kMinAllocAmount) { 49 , fAuxProcList(NULL) {
44 SkASSERT(typeface); 50 SkASSERT(typeface);
45 SkASSERT(desc); 51 SkASSERT(desc);
46 SkASSERT(ctx); 52 SkASSERT(ctx);
47 53
48 fPrev = fNext = NULL;
49
50 fScalerContext->getFontMetrics(&fFontMetrics); 54 fScalerContext->getFontMetrics(&fFontMetrics);
51
52 fMemoryUsed = sizeof(*this);
53
54 fAuxProcList = NULL;
55 } 55 }
56 56
57 SkGlyphCache::~SkGlyphCache() { 57 SkGlyphCache::~SkGlyphCache() {
58 fGlyphMap.foreach( 58 fGlyphMap.foreach(
59 [](SkGlyph* g) { 59 [](SkGlyph* g) {
60 SkDELETE(g->fPath); 60 SkDELETE(g->fPath);
61 } 61 }
62 ); 62 );
63 SkDescriptor::Free(fDesc); 63 SkDescriptor::Free(fDesc);
64 SkDELETE(fScalerContext); 64 SkDELETE(fScalerContext);
65 this->invokeAndRemoveAuxProcs(); 65 this->invokeAndRemoveAuxProcs();
66 } 66 }
67 67
68 void SkGlyphCache::increaseMemoryUsed(size_t used) {
69 fMemoryUsed += used;
70 get_globals().increaseTotalMemoryUsed(used);
71 }
72
73 SkGlyphCache::CharGlyphRec SkGlyphCache::PackedUnicharIDtoCharGlyphRec(PackedUni charID packedUnicharID) {
74 SkFixed x = SkGlyph::SubToFixed(SkGlyph::ID2SubX(packedUnicharID));
75 SkFixed y = SkGlyph::SubToFixed(SkGlyph::ID2SubY(packedUnicharID));
76 SkUnichar unichar = SkGlyph::ID2Code(packedUnicharID);
77
78 SkAutoMutexAcquire lock(fScalerMutex);
79 PackedGlyphID packedGlyphID = SkGlyph::MakeID(fScalerContext->charToGlyphID( unichar), x, y);
80
81 return {packedUnicharID, packedGlyphID};
82 }
83
68 SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(PackedUnicharID packed UnicharID) { 84 SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(PackedUnicharID packed UnicharID) {
69 if (NULL == fPackedUnicharIDToPackedGlyphID.get()) { 85 if (NULL == fPackedUnicharIDToPackedGlyphID.get()) {
70 // Allocate the array. 86 fMu.releaseShared();
mtklein_C 2015/08/14 15:31:37 Let's add assertShared() / assertExclusive() metho
71 fPackedUnicharIDToPackedGlyphID.reset(kHashCount); 87
72 // Initialize array to map character and position with the impossible gl yph ID. This 88 // Add the map only if there is a call for char -> glyph mapping.
73 // represents no mapping. 89 {
74 for (int i = 0; i <kHashCount; ++i) { 90 SkAutoTAcquire<SkSharedMutex> lock(fMu);
75 fPackedUnicharIDToPackedGlyphID[i].fPackedUnicharID = SkGlyph::kImpo ssibleID; 91
76 fPackedUnicharIDToPackedGlyphID[i].fPackedGlyphID = 0; 92 // Now that the cache is locked exclusively, make sure no one added this array while unlocked.
93 if (NULL == fPackedUnicharIDToPackedGlyphID.get()) {
94 // Allocate the array.
95 fPackedUnicharIDToPackedGlyphID.reset(SkNEW(PackedUnicharIDToPac kedGlyphIDMap));
96 }
97
98 fPackedUnicharIDToPackedGlyphID->set(PackedUnicharIDtoCharGlyphRec(p ackedUnicharID));
77 } 99 }
100 fMu.acquireShared();
101
102 return fPackedUnicharIDToPackedGlyphID->find(packedUnicharID);
78 } 103 }
79 104
80 return &fPackedUnicharIDToPackedGlyphID[SkChecksum::CheapMix(packedUnicharID ) & kHashMask]; 105 CharGlyphRec* answer = fPackedUnicharIDToPackedGlyphID->find(packedUnicharID );
106 if (NULL == answer) {
107 fMu.releaseShared();
108 // Add a new char -> glyph mapping.
109 {
110 SkAutoTAcquire<SkSharedMutex> lock(fMu);
111 answer = fPackedUnicharIDToPackedGlyphID->find(packedUnicharID);
112 if (NULL == answer) {
113 fPackedUnicharIDToPackedGlyphID->set(PackedUnicharIDtoCharGlyphR ec(packedUnicharID));
114 }
115 }
116 fMu.acquireShared();
117 return fPackedUnicharIDToPackedGlyphID->find(packedUnicharID);
118 }
119
120 return answer;
81 } 121 }
82 122
83 /////////////////////////////////////////////////////////////////////////////// 123 ///////////////////////////////////////////////////////////////////////////////
84 124
85 #ifdef SK_DEBUG 125 #ifdef SK_DEBUG
86 #define VALIDATE() AutoValidate av(this) 126 #define VALIDATE() AutoValidate av(this)
87 #else 127 #else
88 #define VALIDATE() 128 #define VALIDATE()
89 #endif 129 #endif
90 130
91 uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) { 131 uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) {
92 VALIDATE(); 132 VALIDATE();
93 PackedUnicharID packedUnicharID = SkGlyph::MakeID(charCode); 133 PackedUnicharID packedUnicharID = SkGlyph::MakeID(charCode);
94 const CharGlyphRec& rec = *this->getCharGlyphRec(packedUnicharID); 134 const CharGlyphRec& rec = *this->getCharGlyphRec(packedUnicharID);
95 135 return SkGlyph::ID2Code(rec.fPackedGlyphID);
96 if (rec.fPackedUnicharID == packedUnicharID) {
97 return SkGlyph::ID2Code(rec.fPackedGlyphID);
98 } else {
99 return fScalerContext->charToGlyphID(charCode);
100 }
101 } 136 }
102 137
103 SkUnichar SkGlyphCache::glyphToUnichar(uint16_t glyphID) { 138 SkUnichar SkGlyphCache::glyphToUnichar(uint16_t glyphID) {
104 return fScalerContext->glyphIDToChar(glyphID); 139 SkUnichar answer;
140 SkAutoMutexAcquire lock(fScalerMutex);
mtklein_C 2015/08/14 15:31:37 Is this different from SkAutoMutexAcquire lock(f
141 answer = fScalerContext->glyphIDToChar(glyphID);
142 return answer;
105 } 143 }
106 144
107 unsigned SkGlyphCache::getGlyphCount() { 145 unsigned SkGlyphCache::getGlyphCount() {
108 return fScalerContext->getGlyphCount(); 146 return fScalerContext->getGlyphCount();
109 } 147 }
110 148
111 /////////////////////////////////////////////////////////////////////////////// 149 ///////////////////////////////////////////////////////////////////////////////
112 150
113 const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) { 151 const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) {
114 VALIDATE(); 152 VALIDATE();
(...skipping 24 matching lines...) Expand all
139 return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType); 177 return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType);
140 } 178 }
141 179
142 const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFi xed y) { 180 const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFi xed y) {
143 VALIDATE(); 181 VALIDATE();
144 PackedGlyphID packedGlyphID = SkGlyph::MakeID(glyphID, x, y); 182 PackedGlyphID packedGlyphID = SkGlyph::MakeID(glyphID, x, y);
145 return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType); 183 return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType);
146 } 184 }
147 185
148 SkGlyph* SkGlyphCache::lookupByChar(SkUnichar charCode, MetricsType type, SkFixe d x, SkFixed y) { 186 SkGlyph* SkGlyphCache::lookupByChar(SkUnichar charCode, MetricsType type, SkFixe d x, SkFixed y) {
149 PackedUnicharID id = SkGlyph::MakeID(charCode, x, y); 187 PackedUnicharID targetUnicharID = SkGlyph::MakeID(charCode, x, y);
150 CharGlyphRec* rec = this->getCharGlyphRec(id); 188 CharGlyphRec* rec = this->getCharGlyphRec(targetUnicharID);
151 if (rec->fPackedUnicharID != id) { 189 PackedGlyphID packedGlyphID = rec->fPackedGlyphID;
152 // this ID is based on the UniChar 190
153 rec->fPackedUnicharID = id; 191 return this->lookupByPackedGlyphID(packedGlyphID, type);
154 // this ID is based on the glyph index
155 PackedGlyphID combinedID = SkGlyph::MakeID(fScalerContext->charToGlyphID (charCode), x, y);
156 rec->fPackedGlyphID = combinedID;
157 return this->lookupByPackedGlyphID(combinedID, type);
158 } else {
159 return this->lookupByPackedGlyphID(rec->fPackedGlyphID, type);
160 }
161 } 192 }
162 193
163 SkGlyph* SkGlyphCache::lookupByPackedGlyphID(PackedGlyphID packedGlyphID, Metric sType type) { 194 SkGlyph* SkGlyphCache::lookupByPackedGlyphID(PackedGlyphID packedGlyphID, Metric sType type) {
164 SkGlyph* glyph = fGlyphMap.find(packedGlyphID); 195 SkGlyph* glyph = fGlyphMap.find(packedGlyphID);
165 196
166 if (NULL == glyph) { 197 if (NULL == glyph) {
167 glyph = this->allocateNewGlyph(packedGlyphID, type); 198 glyph = this->allocateNewGlyph(packedGlyphID, type);
168 } else { 199 } else {
169 if (type == kFull_MetricsType && glyph->isJustAdvance()) { 200 if (type == kFull_MetricsType && glyph->isJustAdvance()) {
170 fScalerContext->getMetrics(glyph); 201 addFullMetrics(glyph);
mtklein_C 2015/08/14 15:31:37 this->
171 } 202 }
172 } 203 }
173 return glyph; 204 return glyph;
174 } 205 }
175 206
176 SkGlyph* SkGlyphCache::allocateNewGlyph(PackedGlyphID packedGlyphID, MetricsType mtype) { 207 SkGlyph* SkGlyphCache::allocateNewGlyph(PackedGlyphID packedGlyphID, MetricsType mtype) {
177 fMemoryUsed += sizeof(SkGlyph);
178 208
179 SkGlyph* glyphPtr; 209 SkGlyph* glyphPtr;
180 { 210 {
181 SkGlyph glyph; 211 fMu.releaseShared();
182 glyph.initGlyphFromCombinedID(packedGlyphID); 212 {
183 glyphPtr = fGlyphMap.set(glyph); 213 SkAutoTAcquire<SkSharedMutex> mapLock(fMu);
mtklein_C 2015/08/14 15:31:37 Let's find some common naming scheme between fMu a
184 } 214 glyphPtr = fGlyphMap.find(packedGlyphID);
215 if (NULL == glyphPtr) {
216 SkGlyph glyph;
217 glyph.initGlyphFromCombinedID(packedGlyphID);
218 {
219 SkAutoMutexAcquire lock(fScalerMutex);
220 if (kJustAdvance_MetricsType == mtype) {
221 fScalerContext->getAdvance(&glyph);
222 } else {
223 SkASSERT(kFull_MetricsType == mtype);
224 fScalerContext->getMetrics(&glyph);
225 }
226 increaseMemoryUsed(sizeof(SkGlyph));
mtklein_C 2015/08/14 15:31:37 this->
227 } // drop scaler lock
228 glyphPtr = fGlyphMap.set(glyph);
185 229
186 if (kJustAdvance_MetricsType == mtype) { 230 } else if (kFull_MetricsType == mtype && glyphPtr->isJustAdvance()) {
187 fScalerContext->getAdvance(glyphPtr); 231 // Some other thread added the glyph, but only calculated just-a dvance metrics.
188 } else { 232 SkAutoMutexAcquire lock(fScalerMutex);
189 SkASSERT(kFull_MetricsType == mtype); 233 fScalerContext->getMetrics(glyphPtr);
190 fScalerContext->getMetrics(glyphPtr); 234 }
235 } // drop map lock
236 fMu.acquireShared();
237 glyphPtr = fGlyphMap.find(packedGlyphID);
191 } 238 }
192 239
193 SkASSERT(glyphPtr->fID != SkGlyph::kImpossibleID); 240 SkASSERT(glyphPtr->fID != SkGlyph::kImpossibleID);
194 return glyphPtr; 241 return glyphPtr;
195 } 242 }
196 243
197 const void* SkGlyphCache::findImage(const SkGlyph& glyph) { 244 void SkGlyphCache::addFullMetrics(SkGlyph* glyph) {
198 if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) { 245 // Now that the cache is exclusively owned, check again.
199 if (NULL == glyph.fImage) { 246 SkAutoMutexAcquire lock(fScalerMutex);
200 size_t size = glyph.computeImageSize(); 247 if (glyph->isJustAdvance()) {
201 const_cast<SkGlyph&>(glyph).fImage = fGlyphAlloc.alloc(size, 248 fScalerContext->getMetrics(glyph);
202 SkChunkAlloc::kReturnNil_AllocFailType); 249 }
203 // check that alloc() actually succeeded 250 }
204 if (glyph.fImage) { 251
205 fScalerContext->getImage(glyph); 252 void SkGlyphCache::onceFillInImage(GlyphAndCache gc) {
mtklein_C 2015/08/14 15:31:37 It'd be nice to remind ourselves we're holding the
206 // TODO: the scaler may have changed the maskformat during 253 SkGlyphCache* cache = gc.cache;
207 // getImage (e.g. from AA or LCD to BW) which means we may have 254 const SkGlyph* glyph = gc.glyph;
208 // overallocated the buffer. Check if the new computedImageSize 255 if (glyph->fWidth > 0 && glyph->fWidth < kMaxGlyphWidth) {
209 // is smaller, and if so, strink the alloc size in fImageAlloc. 256 size_t size = glyph->computeImageSize();
210 fMemoryUsed += size; 257 sk_atomic_store(&const_cast<SkGlyph*>(glyph)->fImage,
mtklein_C 2015/08/14 15:31:37 This shouldn't need to be atomic under this scheme
211 } 258 cache->fGlyphAlloc.alloc(size, SkChunkAlloc::kReturnNil_AllocFai lType),
259 sk_memory_order_relaxed);
260 if (glyph->fImage != NULL) {
261 cache->fScalerContext->getImage(*glyph);
262 cache->increaseMemoryUsed(size);
212 } 263 }
213 } 264 }
214 return glyph.fImage; 265 }
266
267 const void* SkGlyphCache::findImage(const SkGlyph& glyph) {
268 SkOnce(&glyph.fImageIsSet, &fScalerMutex, &SkGlyphCache::onceFillInImage, {t his, &glyph});
269 return sk_atomic_load(&glyph.fImage, sk_memory_order_relaxed);
mtklein_C 2015/08/14 15:31:37 Again, I think these do not need to be atomic.
herb_g 2015/08/21 19:16:50 I don't think this is correct. I think that making
270 }
271
272 void SkGlyphCache::onceFillInPath(GlyphAndCache gc) {
273 SkGlyphCache* cache = gc.cache;
274 const SkGlyph* glyph = gc.glyph;
275 if (glyph->fWidth > 0) {
276 sk_atomic_store(&const_cast<SkGlyph*>(glyph)->fPath, SkNEW(SkPath), sk_m emory_order_relaxed);
mtklein_C 2015/08/14 15:31:37 ditto
277 cache->fScalerContext->getPath(*glyph, glyph->fPath);
278 size_t size = sizeof(SkPath) + glyph->fPath->countPoints() * sizeof(SkPo int);
279 cache->increaseMemoryUsed(size);
280 }
215 } 281 }
216 282
217 const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) { 283 const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) {
218 if (glyph.fWidth) { 284 SkOnce(&glyph.fPathIsSet, &fScalerMutex, &SkGlyphCache::onceFillInPath, {thi s, &glyph});
219 if (glyph.fPath == NULL) { 285 return sk_atomic_load(&glyph.fPath, sk_memory_order_relaxed);
mtklein_C 2015/08/14 15:31:37 ditto
220 const_cast<SkGlyph&>(glyph).fPath = SkNEW(SkPath);
221 fScalerContext->getPath(glyph, glyph.fPath);
222 fMemoryUsed += sizeof(SkPath) +
223 glyph.fPath->countPoints() * sizeof(SkPoint);
224 }
225 }
226 return glyph.fPath;
227 } 286 }
228 287
229 void SkGlyphCache::dump() const { 288 void SkGlyphCache::dump() const {
230 const SkTypeface* face = fScalerContext->getTypeface(); 289 const SkTypeface* face = fScalerContext->getTypeface();
231 const SkScalerContextRec& rec = fScalerContext->getRec(); 290 const SkScalerContextRec& rec = fScalerContext->getRec();
232 SkMatrix matrix; 291 SkMatrix matrix;
233 rec.getSingleMatrix(&matrix); 292 rec.getSingleMatrix(&matrix);
234 matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize) ); 293 matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize) );
235 SkString name; 294 SkString name;
236 face->getFamilyName(&name); 295 face->getFamilyName(&name);
237 296
238 SkString msg; 297 SkString msg;
239 msg.printf("cache typeface:%x %25s:%d size:%2g [%g %g %g %g] lum:%02X devG:% d pntG:%d cntr:%d glyphs:%3d", 298 msg.printf("cache typeface:%x %25s:%d size:%2g [%g %g %g %g] lum:%02X devG:% d pntG:%d cntr:%d glyphs:%3d",
240 face->uniqueID(), name.c_str(), face->style(), rec.fTextSize, 299 face->uniqueID(), name.c_str(), face->style(), rec.fTextSize,
241 matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewX], 300 matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewX],
242 matrix[SkMatrix::kMSkewY], matrix[SkMatrix::kMScaleY], 301 matrix[SkMatrix::kMSkewY], matrix[SkMatrix::kMScaleY],
243 rec.fLumBits & 0xFF, rec.fDeviceGamma, rec.fPaintGamma, rec.fCont rast, 302 rec.fLumBits & 0xFF, rec.fDeviceGamma, rec.fPaintGamma, rec.fCont rast,
244 fGlyphMap.count()); 303 fGlyphMap.count());
245 SkDebugf("%s\n", msg.c_str()); 304 SkDebugf("%s\n", msg.c_str());
246 } 305 }
247 306
248 /////////////////////////////////////////////////////////////////////////////// 307 ///////////////////////////////////////////////////////////////////////////////
249 308
250 bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const { 309 bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const {
310 SkAutoMutexAcquire lock(fScalerMutex);
mtklein_C 2015/08/14 15:31:37 It's not obvious why these hold fScalerMutex?
251 const AuxProcRec* rec = fAuxProcList; 311 const AuxProcRec* rec = fAuxProcList;
252 while (rec) { 312 while (rec) {
253 if (rec->fProc == proc) { 313 if (rec->fProc == proc) {
254 if (dataPtr) { 314 if (dataPtr) {
255 *dataPtr = rec->fData; 315 *dataPtr = rec->fData;
256 } 316 }
257 return true; 317 return true;
258 } 318 }
259 rec = rec->fNext; 319 rec = rec->fNext;
260 } 320 }
261 return false; 321 return false;
262 } 322 }
263 323
264 void SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) { 324 void SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) {
265 if (proc == NULL) { 325 if (proc == NULL) {
266 return; 326 return;
267 } 327 }
268 328
329 SkAutoMutexAcquire lock(fScalerMutex);
269 AuxProcRec* rec = fAuxProcList; 330 AuxProcRec* rec = fAuxProcList;
270 while (rec) { 331 while (rec) {
271 if (rec->fProc == proc) { 332 if (rec->fProc == proc) {
272 rec->fData = data; 333 rec->fData = data;
273 return; 334 return;
274 } 335 }
275 rec = rec->fNext; 336 rec = rec->fNext;
276 } 337 }
277 // not found, create a new rec 338 // not found, create a new rec
278 rec = SkNEW(AuxProcRec); 339 rec = SkNEW(AuxProcRec);
279 rec->fProc = proc; 340 rec->fProc = proc;
280 rec->fData = data; 341 rec->fData = data;
281 rec->fNext = fAuxProcList; 342 rec->fNext = fAuxProcList;
282 fAuxProcList = rec; 343 fAuxProcList = rec;
283 } 344 }
284 345
285 void SkGlyphCache::invokeAndRemoveAuxProcs() { 346 void SkGlyphCache::invokeAndRemoveAuxProcs() {
286 AuxProcRec* rec = fAuxProcList; 347 AuxProcRec* rec = fAuxProcList;
287 while (rec) { 348 while (rec) {
288 rec->fProc(rec->fData); 349 rec->fProc(rec->fData);
289 AuxProcRec* next = rec->fNext; 350 AuxProcRec* next = rec->fNext;
290 SkDELETE(rec); 351 SkDELETE(rec);
291 rec = next; 352 rec = next;
292 } 353 }
293 } 354 }
294 355
295 /////////////////////////////////////////////////////////////////////////////// 356 ///////////////////////////////////////////////////////////////////////////////
296 /////////////////////////////////////////////////////////////////////////////// 357 ///////////////////////////////////////////////////////////////////////////////
297 358
298 359 typedef SkAutoTAcquire<SkSpinlock> AutoAcquire;
299 class AutoAcquire {
300 public:
301 AutoAcquire(SkSpinlock& lock) : fLock(lock) { fLock.acquire(); }
302 ~AutoAcquire() { fLock.release(); }
303 private:
304 SkSpinlock& fLock;
305 };
306 360
307 size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) { 361 size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) {
308 static const size_t minLimit = 256 * 1024; 362 static const size_t minLimit = 256 * 1024;
309 if (newLimit < minLimit) { 363 if (newLimit < minLimit) {
310 newLimit = minLimit; 364 newLimit = minLimit;
311 } 365 }
312 366
313 AutoAcquire ac(fLock); 367 AutoAcquire ac(fLock);
314 368
315 size_t prevLimit = fCacheSizeLimit; 369 size_t prevLimit = fCacheSizeLimit;
(...skipping 10 matching lines...) Expand all
326 AutoAcquire ac(fLock); 380 AutoAcquire ac(fLock);
327 381
328 int prevCount = fCacheCountLimit; 382 int prevCount = fCacheCountLimit;
329 fCacheCountLimit = newCount; 383 fCacheCountLimit = newCount;
330 this->internalPurge(); 384 this->internalPurge();
331 return prevCount; 385 return prevCount;
332 } 386 }
333 387
334 void SkGlyphCache_Globals::purgeAll() { 388 void SkGlyphCache_Globals::purgeAll() {
335 AutoAcquire ac(fLock); 389 AutoAcquire ac(fLock);
336 this->internalPurge(fTotalMemoryUsed); 390 this->internalPurge(fTotalMemoryUsed.load());
337 } 391 }
338 392
339 /* This guy calls the visitor from within the mutext lock, so the visitor 393 /* This guy calls the visitor from within the mutext lock, so the visitor
340 cannot: 394 cannot:
341 - take too much time 395 - take too much time
342 - try to acquire the mutext again 396 - try to acquire the mutext again
343 - call a fontscaler (which might call into the cache) 397 - call a fontscaler (which might call into the cache)
344 */ 398 */
345 SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface, 399 SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface, const SkDescriptor* desc, VisitProc proc, void* context) {
346 const SkDescriptor* desc,
347 bool (*proc)(const SkGlyphCache*, void*),
348 void* context) {
349 if (!typeface) { 400 if (!typeface) {
350 typeface = SkTypeface::GetDefaultTypeface(); 401 typeface = SkTypeface::GetDefaultTypeface();
351 } 402 }
352 SkASSERT(desc); 403 SkASSERT(desc);
353 404
354 SkGlyphCache_Globals& globals = get_globals(); 405 SkGlyphCache_Globals& globals = get_globals();
355 SkGlyphCache* cache; 406 SkGlyphCache* cache;
356 407
357 { 408 {
358 AutoAcquire ac(globals.fLock); 409 AutoAcquire ac(globals.fLock);
359 410
360 globals.validate(); 411 globals.validate();
361 412
362 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fN ext) { 413 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fN ext) {
363 if (cache->fDesc->equals(*desc)) { 414 if (cache->fDesc->equals(*desc)) {
364 globals.internalDetachCache(cache); 415 globals.internalMoveToHead(cache);
416 cache->fMu.acquireShared();
365 if (!proc(cache, context)) { 417 if (!proc(cache, context)) {
366 globals.internalAttachCacheToHead(cache); 418 cache->fMu.releaseShared();
367 cache = NULL; 419 return NULL;
368 } 420 }
421 cache->refCount += 1;
mtklein_C 2015/08/14 15:31:37 This seems odd. Are all these cache->refCounts al
369 return cache; 422 return cache;
370 } 423 }
371 } 424 }
372 } 425 }
373 426
374 // Check if we can create a scaler-context before creating the glyphcache. 427 // Check if we can create a scaler-context before creating the glyphcache.
375 // If not, we may have exhausted OS/font resources, so try purging the 428 // If not, we may have exhausted OS/font resources, so try purging the
376 // cache once and try again. 429 // cache once and try again.
377 { 430 {
378 // pass true the first time, to notice if the scalercontext failed, 431 // pass true the first time, to notice if the scalercontext failed,
379 // so we can try the purge. 432 // so we can try the purge.
380 SkScalerContext* ctx = typeface->createScalerContext(desc, true); 433 SkScalerContext* ctx = typeface->createScalerContext(desc, true);
381 if (!ctx) { 434 if (NULL == ctx) {
382 get_globals().purgeAll(); 435 get_globals().purgeAll();
383 ctx = typeface->createScalerContext(desc, false); 436 ctx = typeface->createScalerContext(desc, false);
384 SkASSERT(ctx); 437 SkASSERT(ctx);
385 } 438 }
386 cache = SkNEW_ARGS(SkGlyphCache, (typeface, desc, ctx)); 439 cache = SkNEW_ARGS(SkGlyphCache, (typeface, desc, ctx));
440
441 globals.attachCacheToHead(cache);
387 } 442 }
388 443
389 AutoValidate av(cache); 444 AutoValidate av(cache);
445 AutoAcquire ac(globals.fLock);
390 446
447 cache->fMu.acquireShared();
391 if (!proc(cache, context)) { // need to reattach 448 if (!proc(cache, context)) { // need to reattach
392 globals.attachCacheToHead(cache); 449 cache->fMu.releaseShared();
393 cache = NULL; 450 return NULL;
394 } 451 }
452 cache->refCount += 1;
395 return cache; 453 return cache;
396 } 454 }
397 455
398 void SkGlyphCache::AttachCache(SkGlyphCache* cache) { 456 void SkGlyphCache::AttachCache(SkGlyphCache* cache) {
399 SkASSERT(cache); 457 SkASSERT(cache);
400 SkASSERT(cache->fNext == NULL); 458 cache->fMu.releaseShared();
401 459 SkGlyphCache_Globals& globals = get_globals();
402 get_globals().attachCacheToHead(cache); 460 AutoAcquire ac(globals.fLock);
461 globals.validate();
462 cache->validate();
463 if (cache->refCount == 0) {
464 delete cache;
465 }
466 globals.internalPurge();
403 } 467 }
404 468
405 void SkGlyphCache::Dump() { 469 void SkGlyphCache::Dump() {
406 SkGlyphCache_Globals& globals = get_globals(); 470 SkGlyphCache_Globals& globals = get_globals();
407 AutoAcquire ac(globals.fLock); 471 AutoAcquire ac(globals.fLock);
408 SkGlyphCache* cache; 472 SkGlyphCache* cache;
409 473
410 globals.validate(); 474 globals.validate();
411 475
412 SkDebugf("SkGlyphCache strikes:%d memory:%d\n", 476 SkDebugf("SkGlyphCache strikes:%d memory:%d\n",
413 globals.getCacheCountUsed(), (int)globals.getTotalMemoryUsed()); 477 globals.getCacheCountUsed(), (int)globals.getTotalMemoryUsed());
414 478
415 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) { 479 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) {
416 cache->dump(); 480 cache->dump();
417 } 481 }
418 } 482 }
419 483
420 /////////////////////////////////////////////////////////////////////////////// 484 ///////////////////////////////////////////////////////////////////////////////
421 485
422 void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) { 486 void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) {
423 AutoAcquire ac(fLock); 487 AutoAcquire ac(fLock);
424 488
489 fCacheCount += 1;
490 cache->refCount += 1;
491 // Access to cache->fMemoryUsed is single threaded until internalMoveToHead.
492 fTotalMemoryUsed.fetch_add(cache->fMemoryUsed);
493
494 this->internalMoveToHead(cache);
495
425 this->validate(); 496 this->validate();
426 cache->validate(); 497 cache->validate();
427 498
428 this->internalAttachCacheToHead(cache);
429 this->internalPurge(); 499 this->internalPurge();
430 } 500 }
431 501
432 SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const { 502 SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const {
433 SkGlyphCache* cache = fHead; 503 SkGlyphCache* cache = fHead;
434 if (cache) { 504 if (cache) {
435 while (cache->fNext) { 505 while (cache->fNext) {
436 cache = cache->fNext; 506 cache = cache->fNext;
437 } 507 }
438 } 508 }
439 return cache; 509 return cache;
440 } 510 }
441 511
442 size_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) { 512 size_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) {
443 this->validate(); 513 this->validate();
444 514
445 size_t bytesNeeded = 0; 515 size_t bytesNeeded = 0;
446 if (fTotalMemoryUsed > fCacheSizeLimit) { 516 if (fTotalMemoryUsed.load() > fCacheSizeLimit) {
447 bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit; 517 bytesNeeded = fTotalMemoryUsed.load() - fCacheSizeLimit;
448 } 518 }
449 bytesNeeded = SkTMax(bytesNeeded, minBytesNeeded); 519 bytesNeeded = SkTMax(bytesNeeded, minBytesNeeded);
450 if (bytesNeeded) { 520 if (bytesNeeded) {
451 // no small purges! 521 // no small purges!
452 bytesNeeded = SkTMax(bytesNeeded, fTotalMemoryUsed >> 2); 522 bytesNeeded = SkTMax(bytesNeeded, fTotalMemoryUsed.load() >> 2);
453 } 523 }
454 524
455 int countNeeded = 0; 525 int countNeeded = 0;
456 if (fCacheCount > fCacheCountLimit) { 526 if (fCacheCount > fCacheCountLimit) {
457 countNeeded = fCacheCount - fCacheCountLimit; 527 countNeeded = fCacheCount - fCacheCountLimit;
458 // no small purges! 528 // no small purges!
459 countNeeded = SkMax32(countNeeded, fCacheCount >> 2); 529 countNeeded = SkMax32(countNeeded, fCacheCount >> 2);
460 } 530 }
461 531
462 // early exit 532 // early exit
463 if (!countNeeded && !bytesNeeded) { 533 if (!countNeeded && !bytesNeeded) {
464 return 0; 534 return 0;
465 } 535 }
466 536
467 size_t bytesFreed = 0; 537 size_t bytesFreed = 0;
468 int countFreed = 0; 538 int countFreed = 0;
469 539
470 // we start at the tail and proceed backwards, as the linklist is in LRU 540 // we start at the tail and proceed backwards, as the linklist is in LRU
471 // order, with unimportant entries at the tail. 541 // order, with unimportant entries at the tail.
472 SkGlyphCache* cache = this->internalGetTail(); 542 SkGlyphCache* cache = this->internalGetTail();
473 while (cache != NULL && 543 while (cache != NULL &&
474 (bytesFreed < bytesNeeded || countFreed < countNeeded)) { 544 (bytesFreed < bytesNeeded || countFreed < countNeeded)) {
475 SkGlyphCache* prev = cache->fPrev; 545 SkGlyphCache* prev = cache->fPrev;
476 bytesFreed += cache->fMemoryUsed; 546 bytesFreed += cache->fMemoryUsed;
477 countFreed += 1; 547 countFreed += 1;
478 548
479 this->internalDetachCache(cache); 549 this->internalDetachCache(cache);
480 SkDELETE(cache); 550 if (0 == cache->refCount) {
551 SkDELETE(cache);
552 }
481 cache = prev; 553 cache = prev;
482 } 554 }
483 555
484 this->validate(); 556 this->validate();
485 557
486 #ifdef SPEW_PURGE_STATUS 558 #ifdef SPEW_PURGE_STATUS
487 if (countFreed) { 559 if (countFreed) {
488 SkDebugf("purging %dK from font cache [%d entries]\n", 560 SkDebugf("purging %dK from font cache [%d entries]\n",
489 (int)(bytesFreed >> 10), countFreed); 561 (int)(bytesFreed >> 10), countFreed);
490 } 562 }
491 #endif 563 #endif
492 564
493 return bytesFreed; 565 return bytesFreed;
494 } 566 }
495 567
496 void SkGlyphCache_Globals::internalAttachCacheToHead(SkGlyphCache* cache) { 568 void SkGlyphCache_Globals::internalMoveToHead(SkGlyphCache *cache) {
497 SkASSERT(NULL == cache->fPrev && NULL == cache->fNext); 569 if (cache != fHead) {
498 if (fHead) { 570 if (cache->fPrev) {
499 fHead->fPrev = cache; 571 cache->fPrev->fNext = cache->fNext;
500 cache->fNext = fHead; 572 }
573 if (cache->fNext) {
574 cache->fNext->fPrev = cache->fPrev;
575 }
576 cache->fNext = NULL;
577 cache->fPrev = NULL;
578 if (fHead) {
579 fHead->fPrev = cache;
580 cache->fNext = fHead;
581 }
582 fHead = cache;
501 } 583 }
502 fHead = cache;
503
504 fCacheCount += 1;
505 fTotalMemoryUsed += cache->fMemoryUsed;
506 } 584 }
507 585
508 void SkGlyphCache_Globals::internalDetachCache(SkGlyphCache* cache) { 586 void SkGlyphCache_Globals::internalDetachCache(SkGlyphCache* cache) {
509 SkASSERT(fCacheCount > 0);
510 fCacheCount -= 1; 587 fCacheCount -= 1;
511 fTotalMemoryUsed -= cache->fMemoryUsed; 588 fTotalMemoryUsed.fetch_add(-cache->fMemoryUsed);
512 589
513 if (cache->fPrev) { 590 if (cache->fPrev) {
514 cache->fPrev->fNext = cache->fNext; 591 cache->fPrev->fNext = cache->fNext;
515 } else { 592 } else {
516 fHead = cache->fNext; 593 fHead = cache->fNext;
517 } 594 }
518 if (cache->fNext) { 595 if (cache->fNext) {
519 cache->fNext->fPrev = cache->fPrev; 596 cache->fNext->fPrev = cache->fPrev;
520 } 597 }
521 cache->fPrev = cache->fNext = NULL; 598 cache->fPrev = cache->fNext = NULL;
599 cache->refCount -= 1;
600
522 } 601 }
523 602
603
524 /////////////////////////////////////////////////////////////////////////////// 604 ///////////////////////////////////////////////////////////////////////////////
525 605
526 #ifdef SK_DEBUG 606 #ifdef SK_DEBUG
527 607
528 void SkGlyphCache::validate() const { 608 void SkGlyphCache::validate() const {
529 #ifdef SK_DEBUG_GLYPH_CACHE 609 #ifdef SK_DEBUG_GLYPH_CACHE
530 int count = fGlyphArray.count(); 610 int count = fGlyphArray.count();
531 for (int i = 0; i < count; i++) { 611 for (int i = 0; i < count; i++) {
532 const SkGlyph* glyph = &fGlyphArray[i]; 612 const SkGlyph* glyph = &fGlyphArray[i];
533 SkASSERT(glyph); 613 SkASSERT(glyph);
534 if (glyph->fImage) { 614 if (glyph->fImage) {
535 SkASSERT(fGlyphAlloc.contains(glyph->fImage)); 615 SkASSERT(fGlyphAlloc.contains(glyph->fImage));
536 } 616 }
537 } 617 }
538 #endif 618 #endif
539 } 619 }
540 620
541 void SkGlyphCache_Globals::validate() const { 621 void SkGlyphCache_Globals::validate() const {
542 size_t computedBytes = 0;
543 int computedCount = 0; 622 int computedCount = 0;
544 623
545 const SkGlyphCache* head = fHead; 624 SkGlyphCache* head = fHead;
546 while (head != NULL) { 625 while (head != NULL) {
547 computedBytes += head->fMemoryUsed;
548 computedCount += 1; 626 computedCount += 1;
549 head = head->fNext; 627 head = head->fNext;
550 } 628 }
551 629
552 SkASSERTF(fCacheCount == computedCount, "fCacheCount: %d, computedCount: %d" , fCacheCount, 630 SkASSERTF(fCacheCount == computedCount, "fCacheCount: %d, computedCount: %d" , fCacheCount,
553 computedCount); 631 computedCount);
554 SkASSERTF(fTotalMemoryUsed == computedBytes, "fTotalMemoryUsed: %d, computed Bytes: %d",
555 fTotalMemoryUsed, computedBytes);
556 } 632 }
557 633
558 #endif 634 #endif
559 635
560 /////////////////////////////////////////////////////////////////////////////// 636 ///////////////////////////////////////////////////////////////////////////////
561 /////////////////////////////////////////////////////////////////////////////// 637 ///////////////////////////////////////////////////////////////////////////////
562 638
563 #include "SkTypefaceCache.h" 639 #include "SkTypefaceCache.h"
564 640
565 size_t SkGraphics::GetFontCacheLimit() { 641 size_t SkGraphics::GetFontCacheLimit() {
(...skipping 21 matching lines...) Expand all
587 } 663 }
588 664
589 void SkGraphics::PurgeFontCache() { 665 void SkGraphics::PurgeFontCache() {
590 get_globals().purgeAll(); 666 get_globals().purgeAll();
591 SkTypefaceCache::PurgeAll(); 667 SkTypefaceCache::PurgeAll();
592 } 668 }
593 669
594 // TODO(herb): clean up TLS apis. 670 // TODO(herb): clean up TLS apis.
595 size_t SkGraphics::GetTLSFontCacheLimit() { return 0; } 671 size_t SkGraphics::GetTLSFontCacheLimit() { return 0; }
596 void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { } 672 void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698