• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef SK_DEFAULT_FONT_CACHE_POINT_SIZE_LIMIT
30     #define SK_DEFAULT_FONT_CACHE_POINT_SIZE_LIMIT  256
31 #endif
32 
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 class SkStrikePinner {
36 public:
37     virtual ~SkStrikePinner() = default;
38     virtual bool canDelete() = 0;
39 };
40 
41 class SkStrikeCache final : public SkStrikeForGPUCacheInterface {
42 public:
43     SkStrikeCache() = default;
44     ~SkStrikeCache() override;
45 
46     class Strike final : public SkRefCnt, public SkStrikeForGPU {
47     public:
Strike(SkStrikeCache * strikeCache,const SkDescriptor & desc,std::unique_ptr<SkScalerContext> scaler,const SkFontMetrics * metrics,std::unique_ptr<SkStrikePinner> pinner)48         Strike(SkStrikeCache* strikeCache,
49                const SkDescriptor& desc,
50                std::unique_ptr<SkScalerContext> scaler,
51                const SkFontMetrics* metrics,
52                std::unique_ptr<SkStrikePinner> pinner)
53                 : fStrikeCache{strikeCache}
54                 , fScalerCache{desc, std::move(scaler), metrics}
55                 , fPinner{std::move(pinner)} {}
56 
mergeGlyphAndImage(SkPackedGlyphID toID,const SkGlyph & from)57         SkGlyph* mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& from) {
58             auto [glyph, increase] = fScalerCache.mergeGlyphAndImage(toID, from);
59             this->updateDelta(increase);
60             return glyph;
61         }
62 
mergePath(SkGlyph * glyph,const SkPath * path)63         const SkPath* mergePath(SkGlyph* glyph, const SkPath* path) {
64             auto [glyphPath, increase] = fScalerCache.mergePath(glyph, path);
65             this->updateDelta(increase);
66             return glyphPath;
67         }
68 
getScalerContext()69         SkScalerContext* getScalerContext() const {
70             return fScalerCache.getScalerContext();
71         }
72 
findIntercepts(const SkScalar bounds[2],SkScalar scale,SkScalar xPos,SkGlyph * glyph,SkScalar * array,int * count)73         void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
74                             SkGlyph* glyph, SkScalar* array, int* count) {
75             fScalerCache.findIntercepts(bounds, scale, xPos, glyph, array, count);
76         }
77 
getFontMetrics()78         const SkFontMetrics& getFontMetrics() const {
79             return fScalerCache.getFontMetrics();
80         }
81 
metrics(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])82         SkSpan<const SkGlyph*> metrics(SkSpan<const SkGlyphID> glyphIDs,
83                                        const SkGlyph* results[]) {
84             auto [glyphs, increase] = fScalerCache.metrics(glyphIDs, results);
85             this->updateDelta(increase);
86             return glyphs;
87         }
88 
preparePaths(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])89         SkSpan<const SkGlyph*> preparePaths(SkSpan<const SkGlyphID> glyphIDs,
90                                             const SkGlyph* results[]) {
91             auto [glyphs, increase] = fScalerCache.preparePaths(glyphIDs, results);
92             this->updateDelta(increase);
93             return glyphs;
94         }
95 
prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,const SkGlyph * results[])96         SkSpan<const SkGlyph*> prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,
97                                              const SkGlyph* results[]) {
98             auto [glyphs, increase] = fScalerCache.prepareImages(glyphIDs, results);
99             this->updateDelta(increase);
100             return glyphs;
101         }
102 
prepareForDrawingMasksCPU(SkDrawableGlyphBuffer * drawables)103         void prepareForDrawingMasksCPU(SkDrawableGlyphBuffer* drawables) {
104             size_t increase = fScalerCache.prepareForDrawingMasksCPU(drawables);
105             this->updateDelta(increase);
106         }
107 
roundingSpec()108         const SkGlyphPositionRoundingSpec& roundingSpec() const override {
109             return fScalerCache.roundingSpec();
110         }
111 
getDescriptor()112         const SkDescriptor& getDescriptor() const override {
113             return fScalerCache.getDescriptor();
114         }
115 
prepareForMaskDrawing(SkDrawableGlyphBuffer * drawbles,SkSourceGlyphBuffer * rejects)116         void prepareForMaskDrawing(
117                 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override {
118             size_t increase = fScalerCache.prepareForMaskDrawing(drawbles, rejects);
119             this->updateDelta(increase);
120         }
121 
prepareForSDFTDrawing(SkDrawableGlyphBuffer * drawbles,SkSourceGlyphBuffer * rejects)122         void prepareForSDFTDrawing(
123                 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override {
124             size_t increase = fScalerCache.prepareForSDFTDrawing(drawbles, rejects);
125             this->updateDelta(increase);
126         }
127 
prepareForPathDrawing(SkDrawableGlyphBuffer * drawbles,SkSourceGlyphBuffer * rejects)128         void prepareForPathDrawing(
129                 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override {
130             size_t increase = fScalerCache.prepareForPathDrawing(drawbles, rejects);
131             this->updateDelta(increase);
132         }
133 
onAboutToExitScope()134         void onAboutToExitScope() override {
135             this->unref();
136         }
137 
138         void updateDelta(size_t increase);
139 
140         SkStrikeCache* const            fStrikeCache;
141         Strike*                         fNext{nullptr};
142         Strike*                         fPrev{nullptr};
143         SkScalerCache                   fScalerCache;
144         std::unique_ptr<SkStrikePinner> fPinner;
145         size_t                          fMemoryUsed{sizeof(SkScalerCache)};
146         bool                            fRemoved{false};
147     };  // Strike
148 
149     class ExclusiveStrikePtr {
150     public:
151         explicit ExclusiveStrikePtr(sk_sp<Strike> strike);
152         ExclusiveStrikePtr();
153         ExclusiveStrikePtr(const ExclusiveStrikePtr&) = delete;
154         ExclusiveStrikePtr& operator = (const ExclusiveStrikePtr&) = delete;
155         ExclusiveStrikePtr(ExclusiveStrikePtr&&);
156         ExclusiveStrikePtr& operator = (ExclusiveStrikePtr&&);
157 
158         Strike* get() const;
159         Strike* operator -> () const;
160         Strike& operator *  () const;
161         explicit operator bool () const;
162         friend bool operator == (const ExclusiveStrikePtr&, const ExclusiveStrikePtr&);
163         friend bool operator == (const ExclusiveStrikePtr&, decltype(nullptr));
164         friend bool operator == (decltype(nullptr), const ExclusiveStrikePtr&);
165 
166     private:
167         sk_sp<Strike> fStrike;
168     };
169 
170     static SkStrikeCache* GlobalStrikeCache();
171 
172     ExclusiveStrikePtr findStrikeExclusive(const SkDescriptor&) SK_EXCLUDES(fLock);
173 
174     ExclusiveStrikePtr createStrikeExclusive(
175             const SkDescriptor& desc,
176             std::unique_ptr<SkScalerContext> scaler,
177             SkFontMetrics* maybeMetrics = nullptr,
178             std::unique_ptr<SkStrikePinner> = nullptr) SK_EXCLUDES(fLock);
179 
180     ExclusiveStrikePtr findOrCreateStrikeExclusive(
181             const SkDescriptor& desc,
182             const SkScalerContextEffects& effects,
183             const SkTypeface& typeface) SK_EXCLUDES(fLock);
184 
185     SkScopedStrikeForGPU findOrCreateScopedStrike(
186             const SkDescriptor& desc,
187             const SkScalerContextEffects& effects,
188             const SkTypeface& typeface) override SK_EXCLUDES(fLock);
189 
190     static void PurgeAll();
191     static void Dump();
192 
193     // Dump memory usage statistics of all the attaches caches in the process using the
194     // SkTraceMemoryDump interface.
195     static void DumpMemoryStatistics(SkTraceMemoryDump* dump);
196 
197     void purgeAll() SK_EXCLUDES(fLock); // does not change budget
198 
199     int getCacheCountLimit() const SK_EXCLUDES(fLock);
200     int setCacheCountLimit(int limit) SK_EXCLUDES(fLock);
201     int getCacheCountUsed() const SK_EXCLUDES(fLock);
202 
203     size_t getCacheSizeLimit() const SK_EXCLUDES(fLock);
204     size_t setCacheSizeLimit(size_t limit) SK_EXCLUDES(fLock);
205     size_t getTotalMemoryUsed() const SK_EXCLUDES(fLock);
206 
207     int  getCachePointSizeLimit() const SK_EXCLUDES(fLock);
208     int  setCachePointSizeLimit(int limit) SK_EXCLUDES(fLock);
209 
210 private:
211     sk_sp<Strike> internalFindStrikeOrNull(const SkDescriptor& desc) SK_REQUIRES(fLock);
212     sk_sp<Strike> internalCreateStrike(
213             const SkDescriptor& desc,
214             std::unique_ptr<SkScalerContext> scaler,
215             SkFontMetrics* maybeMetrics = nullptr,
216             std::unique_ptr<SkStrikePinner> = nullptr) SK_REQUIRES(fLock);
217     sk_sp<Strike> findOrCreateStrike(
218             const SkDescriptor& desc,
219             const SkScalerContextEffects& effects,
220             const SkTypeface& typeface) SK_EXCLUDES(fLock);
221 
222     // The following methods can only be called when mutex is already held.
223     void internalRemoveStrike(Strike* strike) SK_REQUIRES(fLock);
224     void internalAttachToHead(sk_sp<Strike> strike) SK_REQUIRES(fLock);
225 
226     // Checkout budgets, modulated by the specified min-bytes-needed-to-purge,
227     // and attempt to purge caches to match.
228     // Returns number of bytes freed.
229     size_t internalPurge(size_t minBytesNeeded = 0) SK_REQUIRES(fLock);
230 
231     // A simple accounting of what each glyph cache reports and the strike cache total.
232     void validate() const SK_REQUIRES(fLock);
233 
234     void forEachStrike(std::function<void(const Strike&)> visitor) const SK_EXCLUDES(fLock);
235 
236     mutable SkSpinlock fLock;
SK_GUARDED_BY(fLock)237     Strike* fHead SK_GUARDED_BY(fLock) {nullptr};
SK_GUARDED_BY(fLock)238     Strike* fTail SK_GUARDED_BY(fLock) {nullptr};
239     size_t  fCacheSizeLimit{SK_DEFAULT_FONT_CACHE_LIMIT};
SK_GUARDED_BY(fLock)240     size_t  fTotalMemoryUsed SK_GUARDED_BY(fLock) {0};
241     int32_t fCacheCountLimit{SK_DEFAULT_FONT_CACHE_COUNT_LIMIT};
SK_GUARDED_BY(fLock)242     int32_t fCacheCount SK_GUARDED_BY(fLock) {0};
243     int32_t fPointSizeLimit{SK_DEFAULT_FONT_CACHE_POINT_SIZE_LIMIT};
244 };
245 
246 using SkExclusiveStrikePtr = SkStrikeCache::ExclusiveStrikePtr;
247 using SkStrike = SkStrikeCache::Strike;
248 
249 #endif  // SkStrikeCache_DEFINED
250