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