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/SkStrike.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     class Node;
43 
44 public:
45     SkStrikeCache() = default;
46     ~SkStrikeCache() override;
47 
48     class ExclusiveStrikePtr {
49     public:
50         explicit ExclusiveStrikePtr(Node*);
51         ExclusiveStrikePtr();
52         ExclusiveStrikePtr(const ExclusiveStrikePtr&) = delete;
53         ExclusiveStrikePtr& operator = (const ExclusiveStrikePtr&) = delete;
54         ExclusiveStrikePtr(ExclusiveStrikePtr&&);
55         ExclusiveStrikePtr& operator = (ExclusiveStrikePtr&&);
56         ~ExclusiveStrikePtr();
57 
58         SkStrike* get() const;
59         SkStrike* operator -> () const;
60         SkStrike& operator *  () const;
61         explicit operator bool () const { return fNode != nullptr; }
62         friend bool operator == (const ExclusiveStrikePtr&, const ExclusiveStrikePtr&);
63         friend bool operator == (const ExclusiveStrikePtr&, decltype(nullptr));
64         friend bool operator == (decltype(nullptr), const ExclusiveStrikePtr&);
65 
66     private:
67         Node* fNode;
68     };
69 
70     static SkStrikeCache* GlobalStrikeCache();
71 
72     ExclusiveStrikePtr findStrikeExclusive(const SkDescriptor&);
73 
74     ExclusiveStrikePtr createStrikeExclusive(
75             const SkDescriptor& desc,
76             std::unique_ptr<SkScalerContext> scaler,
77             SkFontMetrics* maybeMetrics = nullptr,
78             std::unique_ptr<SkStrikePinner> = nullptr);
79 
80     ExclusiveStrikePtr findOrCreateStrikeExclusive(
81             const SkDescriptor& desc,
82             const SkScalerContextEffects& effects,
83             const SkTypeface& typeface);
84 
85     // Routines to find suitable data when working in a remote cache situation. These are
86     // suitable as substitutes for similar calls in SkScalerContext.
87     bool desperationSearchForImage(const SkDescriptor& desc,
88                                    SkGlyph* glyph,
89                                    SkStrike* targetCache);
90     bool desperationSearchForPath(const SkDescriptor& desc, SkGlyphID glyphID, SkPath* path);
91 
92     SkScopedStrikeForGPU findOrCreateScopedStrike(const SkDescriptor& desc,
93                                                   const SkScalerContextEffects& effects,
94                                                   const SkTypeface& typeface) override;
95 
96     static std::unique_ptr<SkScalerContext> CreateScalerContext(
97             const SkDescriptor&, const SkScalerContextEffects&, const SkTypeface&);
98 
99     static void PurgeAll();
100     static void ValidateGlyphCacheDataSize();
101     static void Dump();
102 
103     // Dump memory usage statistics of all the attaches caches in the process using the
104     // SkTraceMemoryDump interface.
105     static void DumpMemoryStatistics(SkTraceMemoryDump* dump);
106 
107     void purgeAll(); // does not change budget
108 
109     int getCacheCountLimit() const;
110     int setCacheCountLimit(int limit);
111     int getCacheCountUsed() const;
112 
113     size_t getCacheSizeLimit() const;
114     size_t setCacheSizeLimit(size_t limit);
115     size_t getTotalMemoryUsed() const;
116 
117     int  getCachePointSizeLimit() const;
118     int  setCachePointSizeLimit(int limit);
119 
120 #ifdef SK_DEBUG
121     // A simple accounting of what each glyph cache reports and the strike cache total.
122     void validate() const SK_REQUIRES(fLock);
123     // Make sure that each glyph cache's memory tracking and actual memory used are in sync.
124     void validateGlyphCacheDataSize() const;
125 #else
validate()126     void validate() const {}
validateGlyphCacheDataSize()127     void validateGlyphCacheDataSize() const {}
128 #endif
129 
130 private:
131     Node* findAndDetachStrike(const SkDescriptor&);
132     Node* createStrike(
133             const SkDescriptor& desc,
134             std::unique_ptr<SkScalerContext> scaler,
135             SkFontMetrics* maybeMetrics = nullptr,
136             std::unique_ptr<SkStrikePinner> = nullptr);
137     Node* findOrCreateStrike(
138             const SkDescriptor& desc,
139             const SkScalerContextEffects& effects,
140             const SkTypeface& typeface);
141     void attachNode(Node* node);
142 
143     // The following methods can only be called when mutex is already held.
internalGetHead()144     Node* internalGetHead() const SK_REQUIRES(fLock) { return fHead; }
internalGetTail()145     Node* internalGetTail() const SK_REQUIRES(fLock) { return fTail; }
146     void internalDetachCache(Node*) SK_REQUIRES(fLock);
147     void internalAttachToHead(Node*) SK_REQUIRES(fLock);
148 
149     // Checkout budgets, modulated by the specified min-bytes-needed-to-purge,
150     // and attempt to purge caches to match.
151     // Returns number of bytes freed.
152     size_t internalPurge(size_t minBytesNeeded = 0) SK_REQUIRES(fLock);
153 
154     void forEachStrike(std::function<void(const SkStrike&)> visitor) const;
155 
156     mutable SkSpinlock fLock;
SK_GUARDED_BY(fLock)157     Node*              fHead SK_GUARDED_BY(fLock) {nullptr};
SK_GUARDED_BY(fLock)158     Node*              fTail SK_GUARDED_BY(fLock) {nullptr};
159     size_t             fTotalMemoryUsed{0};
160     size_t             fCacheSizeLimit{SK_DEFAULT_FONT_CACHE_LIMIT};
161     int32_t            fCacheCountLimit{SK_DEFAULT_FONT_CACHE_COUNT_LIMIT};
162     int32_t            fCacheCount{0};
163     int32_t            fPointSizeLimit{SK_DEFAULT_FONT_CACHE_POINT_SIZE_LIMIT};
164 };
165 
166 using SkExclusiveStrikePtr = SkStrikeCache::ExclusiveStrikePtr;
167 
168 #endif  // SkStrikeCache_DEFINED
169