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