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