1 /*
2  * Copyright 2010 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkStrikeCache_DEFINED
9 #define SkStrikeCache_DEFINED
10 
11 #include <unordered_map>
12 #include <unordered_set>
13 
14 #include "include/private/SkSpinlock.h"
15 #include "include/private/SkTemplates.h"
16 #include "src/core/SkDescriptor.h"
17 #include "src/core/SkScalerCache.h"
18 
19 class SkTraceMemoryDump;
20 
21 #ifndef SK_DEFAULT_FONT_CACHE_COUNT_LIMIT
22     #define SK_DEFAULT_FONT_CACHE_COUNT_LIMIT   2048
23 #endif
24 
25 #ifndef SK_DEFAULT_FONT_CACHE_LIMIT
26     #define SK_DEFAULT_FONT_CACHE_LIMIT     (2 * 1024 * 1024)
27 #endif
28 
29 ///////////////////////////////////////////////////////////////////////////////
30 
31 class SkStrikePinner {
32 public:
33     virtual ~SkStrikePinner() = default;
34     virtual bool canDelete() = 0;
35 };
36 
37 class SkStrikeCache final : public SkStrikeForGPUCacheInterface {
38 public:
39     SkStrikeCache() = default;
40 
41     class Strike final : public SkRefCnt, public SkStrikeForGPU {
42     public:
Strike(SkStrikeCache * strikeCache,const SkDescriptor & desc,std::unique_ptr<SkScalerContext> scaler,const SkFontMetrics * metrics,std::unique_ptr<SkStrikePinner> pinner)43         Strike(SkStrikeCache* strikeCache,
44                const SkDescriptor& desc,
45                std::unique_ptr<SkScalerContext> scaler,
46                const SkFontMetrics* metrics,
47                std::unique_ptr<SkStrikePinner> pinner)
48                 : fStrikeCache{strikeCache}
49                 , fScalerCache{desc, std::move(scaler), metrics}
50                 , fPinner{std::move(pinner)} {}
51 
mergeGlyphAndImage(SkPackedGlyphID toID,const SkGlyph & from)52         SkGlyph* mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& from) {
53             auto [glyph, increase] = fScalerCache.mergeGlyphAndImage(toID, from);
54             this->updateDelta(increase);
55             return glyph;
56         }
57 
mergePath(SkGlyph * glyph,const SkPath * path)58         const SkPath* mergePath(SkGlyph* glyph, const SkPath* path) {
59             auto [glyphPath, increase] = fScalerCache.mergePath(glyph, path);
60             this->updateDelta(increase);
61             return glyphPath;
62         }
63 
getScalerContext()64         SkScalerContext* getScalerContext() const {
65             return fScalerCache.getScalerContext();
66         }
67 
findIntercepts(const SkScalar bounds[2],SkScalar scale,SkScalar xPos,SkGlyph * glyph,SkScalar * array,int * count)68         void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
69                             SkGlyph* glyph, SkScalar* array, int* count) {
70             fScalerCache.findIntercepts(bounds, scale, xPos, glyph, array, count);
71         }
72 
getFontMetrics()73         const SkFontMetrics& getFontMetrics() const {
74             return fScalerCache.getFontMetrics();
75         }
76 
metrics(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])77         SkSpan<const SkGlyph*> metrics(SkSpan<const SkGlyphID> glyphIDs,
78                                        const SkGlyph* results[]) {
79             auto [glyphs, increase] = fScalerCache.metrics(glyphIDs, results);
80             this->updateDelta(increase);
81             return glyphs;
82         }
83 
preparePaths(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])84         SkSpan<const SkGlyph*> preparePaths(SkSpan<const SkGlyphID> glyphIDs,
85                                             const SkGlyph* results[]) {
86             auto [glyphs, increase] = fScalerCache.preparePaths(glyphIDs, results);
87             this->updateDelta(increase);
88             return glyphs;
89         }
90 
prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,const SkGlyph * results[])91         SkSpan<const SkGlyph*> prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,
92                                              const SkGlyph* results[]) {
93             auto [glyphs, increase] = fScalerCache.prepareImages(glyphIDs, results);
94             this->updateDelta(increase);
95             return glyphs;
96         }
97 
prepareForDrawingMasksCPU(SkDrawableGlyphBuffer * drawables)98         void prepareForDrawingMasksCPU(SkDrawableGlyphBuffer* drawables) {
99             size_t increase = fScalerCache.prepareForDrawingMasksCPU(drawables);
100             this->updateDelta(increase);
101         }
102 
roundingSpec()103         const SkGlyphPositionRoundingSpec& roundingSpec() const override {
104             return fScalerCache.roundingSpec();
105         }
106 
getDescriptor()107         const SkDescriptor& getDescriptor() const override {
108             return fScalerCache.getDescriptor();
109         }
110 
prepareForMaskDrawing(SkDrawableGlyphBuffer * drawbles,SkSourceGlyphBuffer * rejects)111         void prepareForMaskDrawing(
112                 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override {
113             size_t increase = fScalerCache.prepareForMaskDrawing(drawbles, rejects);
114             this->updateDelta(increase);
115         }
116 
prepareForSDFTDrawing(SkDrawableGlyphBuffer * drawbles,SkSourceGlyphBuffer * rejects)117         void prepareForSDFTDrawing(
118                 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override {
119             size_t increase = fScalerCache.prepareForSDFTDrawing(drawbles, rejects);
120             this->updateDelta(increase);
121         }
122 
prepareForPathDrawing(SkDrawableGlyphBuffer * drawbles,SkSourceGlyphBuffer * rejects)123         void prepareForPathDrawing(
124                 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override {
125             size_t increase = fScalerCache.prepareForPathDrawing(drawbles, rejects);
126             this->updateDelta(increase);
127         }
128 
onAboutToExitScope()129         void onAboutToExitScope() override {
130             this->unref();
131         }
132 
133         void updateDelta(size_t increase);
134 
135         SkStrikeCache* const            fStrikeCache;
136         Strike*                         fNext{nullptr};
137         Strike*                         fPrev{nullptr};
138         SkScalerCache                   fScalerCache;
139         std::unique_ptr<SkStrikePinner> fPinner;
140         size_t                          fMemoryUsed{sizeof(SkScalerCache)};
141         bool                            fRemoved{false};
142     };  // Strike
143 
144     static SkStrikeCache* GlobalStrikeCache();
145 
146     sk_sp<Strike> findStrike(const SkDescriptor& desc) SK_EXCLUDES(fLock);
147 
148     sk_sp<Strike> createStrike(
149             const SkDescriptor& desc,
150             std::unique_ptr<SkScalerContext> scaler,
151             SkFontMetrics* maybeMetrics = nullptr,
152             std::unique_ptr<SkStrikePinner> = nullptr) SK_EXCLUDES(fLock);
153 
154     sk_sp<Strike> findOrCreateStrike(
155             const SkDescriptor& desc,
156             const SkScalerContextEffects& effects,
157             const SkTypeface& typeface) SK_EXCLUDES(fLock);
158 
159     SkScopedStrikeForGPU findOrCreateScopedStrike(
160             const SkDescriptor& desc,
161             const SkScalerContextEffects& effects,
162             const SkTypeface& typeface) override SK_EXCLUDES(fLock);
163 
164     static void PurgeAll();
165     static void Dump();
166 
167     // Dump memory usage statistics of all the attaches caches in the process using the
168     // SkTraceMemoryDump interface.
169     static void DumpMemoryStatistics(SkTraceMemoryDump* dump);
170 
171     void purgeAll() SK_EXCLUDES(fLock); // does not change budget
172 
173     int getCacheCountLimit() const SK_EXCLUDES(fLock);
174     int setCacheCountLimit(int limit) SK_EXCLUDES(fLock);
175     int getCacheCountUsed() const SK_EXCLUDES(fLock);
176 
177     size_t getCacheSizeLimit() const SK_EXCLUDES(fLock);
178     size_t setCacheSizeLimit(size_t limit) SK_EXCLUDES(fLock);
179     size_t getTotalMemoryUsed() const SK_EXCLUDES(fLock);
180 
181 private:
182     sk_sp<Strike> internalFindStrikeOrNull(const SkDescriptor& desc) SK_REQUIRES(fLock);
183     sk_sp<Strike> internalCreateStrike(
184             const SkDescriptor& desc,
185             std::unique_ptr<SkScalerContext> scaler,
186             SkFontMetrics* maybeMetrics = nullptr,
187             std::unique_ptr<SkStrikePinner> = nullptr) SK_REQUIRES(fLock);
188 
189     // The following methods can only be called when mutex is already held.
190     void internalRemoveStrike(Strike* strike) SK_REQUIRES(fLock);
191     void internalAttachToHead(sk_sp<Strike> strike) SK_REQUIRES(fLock);
192 
193     // Checkout budgets, modulated by the specified min-bytes-needed-to-purge,
194     // and attempt to purge caches to match.
195     // Returns number of bytes freed.
196     size_t internalPurge(size_t minBytesNeeded = 0) SK_REQUIRES(fLock);
197 
198     // A simple accounting of what each glyph cache reports and the strike cache total.
199     void validate() const SK_REQUIRES(fLock);
200 
201     void forEachStrike(std::function<void(const Strike&)> visitor) const SK_EXCLUDES(fLock);
202 
203     mutable SkMutex fLock;
SK_GUARDED_BY(fLock)204     Strike* fHead SK_GUARDED_BY(fLock) {nullptr};
SK_GUARDED_BY(fLock)205     Strike* fTail SK_GUARDED_BY(fLock) {nullptr};
206     struct StrikeTraits {
GetKeyStrikeTraits207         static const SkDescriptor& GetKey(const sk_sp<Strike>& strike) {
208             return strike->getDescriptor();
209         }
HashStrikeTraits210         static uint32_t Hash(const SkDescriptor& descriptor) {
211             return descriptor.getChecksum();
212         }
213     };
214     SkTHashTable<sk_sp<Strike>, SkDescriptor, StrikeTraits> fStrikeLookup SK_GUARDED_BY(fLock);
215 
216     size_t  fCacheSizeLimit{SK_DEFAULT_FONT_CACHE_LIMIT};
SK_GUARDED_BY(fLock)217     size_t  fTotalMemoryUsed SK_GUARDED_BY(fLock) {0};
218     int32_t fCacheCountLimit{SK_DEFAULT_FONT_CACHE_COUNT_LIMIT};
SK_GUARDED_BY(fLock)219     int32_t fCacheCount SK_GUARDED_BY(fLock) {0};
220 };
221 
222 using SkStrike = SkStrikeCache::Strike;
223 
224 #endif  // SkStrikeCache_DEFINED
225