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

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

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

Powered by Google App Engine
This is Rietveld 408576698