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

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

Powered by Google App Engine
This is Rietveld 408576698