OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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) { } |
OLD | NEW |