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