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