/src/skia/src/core/SkStrikeCache.h
Line | Count | Source (jump to first uncovered line) |
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 | 0 | virtual ~SkStrikePinner() = default; |
34 | | virtual bool canDelete() = 0; |
35 | | }; |
36 | | |
37 | | class SkStrikeCache final : public SkStrikeForGPUCacheInterface { |
38 | | public: |
39 | 18 | SkStrikeCache() = default; |
40 | | |
41 | | class Strike final : public SkRefCnt, public SkStrikeForGPU { |
42 | | public: |
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 | 16.0k | , fPinner{std::move(pinner)} {} |
51 | | |
52 | 0 | SkGlyph* mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& from) { |
53 | 0 | auto [glyph, increase] = fScalerCache.mergeGlyphAndImage(toID, from); |
54 | 0 | this->updateDelta(increase); |
55 | 0 | return glyph; |
56 | 0 | } |
57 | | |
58 | 0 | const SkPath* mergePath(SkGlyph* glyph, const SkPath* path) { |
59 | 0 | auto [glyphPath, increase] = fScalerCache.mergePath(glyph, path); |
60 | 0 | this->updateDelta(increase); |
61 | 0 | return glyphPath; |
62 | 0 | } |
63 | | |
64 | 0 | SkScalerContext* getScalerContext() const { |
65 | 0 | return fScalerCache.getScalerContext(); |
66 | 0 | } |
67 | | |
68 | | void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos, |
69 | 0 | SkGlyph* glyph, SkScalar* array, int* count) { |
70 | 0 | fScalerCache.findIntercepts(bounds, scale, xPos, glyph, array, count); |
71 | 0 | } |
72 | | |
73 | 4.02k | const SkFontMetrics& getFontMetrics() const { |
74 | 4.02k | return fScalerCache.getFontMetrics(); |
75 | 4.02k | } |
76 | | |
77 | | SkSpan<const SkGlyph*> metrics(SkSpan<const SkGlyphID> glyphIDs, |
78 | 9.62M | const SkGlyph* results[]) { |
79 | 9.62M | auto [glyphs, increase] = fScalerCache.metrics(glyphIDs, results); |
80 | 9.62M | this->updateDelta(increase); |
81 | 9.62M | return glyphs; |
82 | 9.62M | } |
83 | | |
84 | | SkSpan<const SkGlyph*> preparePaths(SkSpan<const SkGlyphID> glyphIDs, |
85 | 53.6k | const SkGlyph* results[]) { |
86 | 53.6k | auto [glyphs, increase] = fScalerCache.preparePaths(glyphIDs, results); |
87 | 53.6k | this->updateDelta(increase); |
88 | 53.6k | return glyphs; |
89 | 53.6k | } |
90 | | |
91 | | SkSpan<const SkGlyph*> prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs, |
92 | 715 | const SkGlyph* results[]) { |
93 | 715 | auto [glyphs, increase] = fScalerCache.prepareImages(glyphIDs, results); |
94 | 715 | this->updateDelta(increase); |
95 | 715 | return glyphs; |
96 | 715 | } |
97 | | |
98 | 155k | void prepareForDrawingMasksCPU(SkDrawableGlyphBuffer* drawables) { |
99 | 155k | size_t increase = fScalerCache.prepareForDrawingMasksCPU(drawables); |
100 | 155k | this->updateDelta(increase); |
101 | 155k | } |
102 | | |
103 | 157k | const SkGlyphPositionRoundingSpec& roundingSpec() const override { |
104 | 157k | return fScalerCache.roundingSpec(); |
105 | 157k | } |
106 | | |
107 | 10.3M | const SkDescriptor& getDescriptor() const override { |
108 | 10.3M | return fScalerCache.getDescriptor(); |
109 | 10.3M | } |
110 | | |
111 | | void prepareForMaskDrawing( |
112 | 1.26k | SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override { |
113 | 1.26k | size_t increase = fScalerCache.prepareForMaskDrawing(drawbles, rejects); |
114 | 1.26k | this->updateDelta(increase); |
115 | 1.26k | } |
116 | | |
117 | | void prepareForSDFTDrawing( |
118 | 132 | SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override { |
119 | 132 | size_t increase = fScalerCache.prepareForSDFTDrawing(drawbles, rejects); |
120 | 132 | this->updateDelta(increase); |
121 | 132 | } |
122 | | |
123 | | void prepareForPathDrawing( |
124 | 56.7k | SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override { |
125 | 56.7k | size_t increase = fScalerCache.prepareForPathDrawing(drawbles, rejects); |
126 | 56.7k | this->updateDelta(increase); |
127 | 56.7k | } |
128 | | |
129 | 5.31k | void onAboutToExitScope() override { |
130 | 5.31k | this->unref(); |
131 | 5.31k | } |
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; |
204 | | Strike* fHead SK_GUARDED_BY(fLock) {nullptr}; |
205 | | Strike* fTail SK_GUARDED_BY(fLock) {nullptr}; |
206 | | struct StrikeTraits { |
207 | 402k | static const SkDescriptor& GetKey(const sk_sp<Strike>& strike) { |
208 | 402k | return strike->getDescriptor(); |
209 | 402k | } |
210 | 418k | static uint32_t Hash(const SkDescriptor& descriptor) { |
211 | 418k | return descriptor.getChecksum(); |
212 | 418k | } |
213 | | }; |
214 | | SkTHashTable<sk_sp<Strike>, SkDescriptor, StrikeTraits> fStrikeLookup SK_GUARDED_BY(fLock); |
215 | | |
216 | | size_t fCacheSizeLimit{SK_DEFAULT_FONT_CACHE_LIMIT}; |
217 | | size_t fTotalMemoryUsed SK_GUARDED_BY(fLock) {0}; |
218 | | int32_t fCacheCountLimit{SK_DEFAULT_FONT_CACHE_COUNT_LIMIT}; |
219 | | int32_t fCacheCount SK_GUARDED_BY(fLock) {0}; |
220 | | }; |
221 | | |
222 | | using SkStrike = SkStrikeCache::Strike; |
223 | | |
224 | | #endif // SkStrikeCache_DEFINED |