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

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

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