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 virtual ~SkStrikePinner() = default; 34 virtual bool canDelete() = 0; 35 }; 36 37 class SkStrikeCache final : public SkStrikeForGPUCacheInterface { 38 public: 39 SkStrikeCache() = default; 40 41 class Strike final : public SkRefCnt, public SkStrikeForGPU { 42 public: Strike(SkStrikeCache * strikeCache,const SkDescriptor & desc,std::unique_ptr<SkScalerContext> scaler,const SkFontMetrics * metrics,std::unique_ptr<SkStrikePinner> pinner)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 , 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 getScalerContext()64 SkScalerContext* getScalerContext() const { 65 return fScalerCache.getScalerContext(); 66 } 67 findIntercepts(const SkScalar bounds[2],SkScalar scale,SkScalar xPos,SkGlyph * glyph,SkScalar * array,int * count)68 void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos, 69 SkGlyph* glyph, SkScalar* array, int* count) { 70 fScalerCache.findIntercepts(bounds, scale, xPos, glyph, array, count); 71 } 72 getFontMetrics()73 const SkFontMetrics& getFontMetrics() const { 74 return fScalerCache.getFontMetrics(); 75 } 76 metrics(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])77 SkSpan<const SkGlyph*> metrics(SkSpan<const SkGlyphID> glyphIDs, 78 const SkGlyph* results[]) { 79 auto [glyphs, increase] = fScalerCache.metrics(glyphIDs, results); 80 this->updateDelta(increase); 81 return glyphs; 82 } 83 preparePaths(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])84 SkSpan<const SkGlyph*> preparePaths(SkSpan<const SkGlyphID> glyphIDs, 85 const SkGlyph* results[]) { 86 auto [glyphs, increase] = fScalerCache.preparePaths(glyphIDs, results); 87 this->updateDelta(increase); 88 return glyphs; 89 } 90 prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,const SkGlyph * results[])91 SkSpan<const SkGlyph*> prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs, 92 const SkGlyph* results[]) { 93 auto [glyphs, increase] = fScalerCache.prepareImages(glyphIDs, results); 94 this->updateDelta(increase); 95 return glyphs; 96 } 97 prepareForDrawingMasksCPU(SkDrawableGlyphBuffer * drawables)98 void prepareForDrawingMasksCPU(SkDrawableGlyphBuffer* drawables) { 99 size_t increase = fScalerCache.prepareForDrawingMasksCPU(drawables); 100 this->updateDelta(increase); 101 } 102 roundingSpec()103 const SkGlyphPositionRoundingSpec& roundingSpec() const override { 104 return fScalerCache.roundingSpec(); 105 } 106 getDescriptor()107 const SkDescriptor& getDescriptor() const override { 108 return fScalerCache.getDescriptor(); 109 } 110 prepareForMaskDrawing(SkDrawableGlyphBuffer * drawbles,SkSourceGlyphBuffer * rejects)111 void prepareForMaskDrawing( 112 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override { 113 size_t increase = fScalerCache.prepareForMaskDrawing(drawbles, rejects); 114 this->updateDelta(increase); 115 } 116 prepareForSDFTDrawing(SkDrawableGlyphBuffer * drawbles,SkSourceGlyphBuffer * rejects)117 void prepareForSDFTDrawing( 118 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override { 119 size_t increase = fScalerCache.prepareForSDFTDrawing(drawbles, rejects); 120 this->updateDelta(increase); 121 } 122 prepareForPathDrawing(SkDrawableGlyphBuffer * drawbles,SkSourceGlyphBuffer * rejects)123 void prepareForPathDrawing( 124 SkDrawableGlyphBuffer* drawbles, SkSourceGlyphBuffer* rejects) override { 125 size_t increase = fScalerCache.prepareForPathDrawing(drawbles, rejects); 126 this->updateDelta(increase); 127 } 128 onAboutToExitScope()129 void onAboutToExitScope() override { 130 this->unref(); 131 } 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; SK_GUARDED_BY(fLock)204 Strike* fHead SK_GUARDED_BY(fLock) {nullptr}; SK_GUARDED_BY(fLock)205 Strike* fTail SK_GUARDED_BY(fLock) {nullptr}; 206 struct StrikeTraits { GetKeyStrikeTraits207 static const SkDescriptor& GetKey(const sk_sp<Strike>& strike) { 208 return strike->getDescriptor(); 209 } HashStrikeTraits210 static uint32_t Hash(const SkDescriptor& descriptor) { 211 return descriptor.getChecksum(); 212 } 213 }; 214 SkTHashTable<sk_sp<Strike>, SkDescriptor, StrikeTraits> fStrikeLookup SK_GUARDED_BY(fLock); 215 216 size_t fCacheSizeLimit{SK_DEFAULT_FONT_CACHE_LIMIT}; SK_GUARDED_BY(fLock)217 size_t fTotalMemoryUsed SK_GUARDED_BY(fLock) {0}; 218 int32_t fCacheCountLimit{SK_DEFAULT_FONT_CACHE_COUNT_LIMIT}; SK_GUARDED_BY(fLock)219 int32_t fCacheCount SK_GUARDED_BY(fLock) {0}; 220 }; 221 222 using SkStrike = SkStrikeCache::Strike; 223 224 #endif // SkStrikeCache_DEFINED 225