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