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