1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CC_PAINT_PAINT_CACHE_H_
6 #define CC_PAINT_PAINT_CACHE_H_
7 
8 #include <map>
9 #include <set>
10 
11 #include "base/containers/mru_cache.h"
12 #include "base/containers/stack_container.h"
13 #include "cc/paint/paint_export.h"
14 #include "third_party/skia/include/core/SkPath.h"
15 #include "third_party/skia/include/core/SkTextBlob.h"
16 
17 namespace cc {
18 
19 // PaintCache is used to cache high frequency small paint data types, like
20 // SkTextBlob and SkPath in the GPU service. The ClientPaintCache budgets and
21 // controls the cache state in the ServicePaintCache, regularly purging old
22 // entries returned in ClientPaintCache::Purge from the service side cache. In
23 // addition to this, the complete cache is cleared during the raster context
24 // idle cleanup. This effectively means that the cache budget is used as working
25 // memory that is only kept while we are actively rasterizing.
26 //
27 // The entries are serialized by the caller during paint op serialization, and
28 // the cache assumes the deserialization and purging to be done in order for
29 // accurately tracking the service side state in ServicePaintCache.
30 //
31 // Note that while TransferCache should be used for large data types that would
32 // benefit from a shared cache budgeted across all clients, using a client
33 // controlled PaintCache with a tighter budget is better for these data types
34 // since it avoids the need for cross-process ref-counting required by the
35 // TransferCache.
36 
37 using PaintCacheId = uint32_t;
38 using PaintCacheIds = std::vector<PaintCacheId>;
39 enum class PaintCacheDataType : uint32_t { kTextBlob, kPath, kLast = kPath };
40 enum class PaintCacheEntryState : uint32_t {
41   kEmpty,
42   kCached,
43   kInlined,
44   kLast = kInlined
45 };
46 
47 constexpr size_t PaintCacheDataTypeCount =
48     static_cast<uint32_t>(PaintCacheDataType::kLast) + 1u;
49 
50 class CC_PAINT_EXPORT ClientPaintCache {
51  public:
52   // If ClientPaintCache is constructed with a max_budget_bytes of
53   // kNoCachingBudget, its Put() method becomes a no-op, rendering the instance
54   // a no-op instance.
55   static constexpr size_t kNoCachingBudget = 0u;
56 
57   explicit ClientPaintCache(size_t max_budget_bytes);
58   ClientPaintCache(const ClientPaintCache&) = delete;
59   ~ClientPaintCache();
60 
61   ClientPaintCache& operator=(const ClientPaintCache&) = delete;
62 
63   bool Get(PaintCacheDataType type, PaintCacheId id);
64   void Put(PaintCacheDataType type, PaintCacheId id, size_t size);
65 
66   // Populates |purged_data| with the list of ids which should be purged from
67   // the ServicePaintCache.
68   using PurgedData = PaintCacheIds[PaintCacheDataTypeCount];
69   void Purge(PurgedData* purged_data);
70 
71   // Finalize the state of pending entries, which were sent to the service-side
72   // cache.
73   void FinalizePendingEntries();
74 
75   // Notifies that the pending entries were not sent to the service-side cache
76   // and should be discarded.
77   void AbortPendingEntries();
78 
79   // Notifies that all entries should be purged from the ServicePaintCache.
80   // Returns true if any entries were evicted from this call.
81   bool PurgeAll();
82 
bytes_used()83   size_t bytes_used() const { return bytes_used_; }
84 
85  private:
86   using CacheKey = std::pair<PaintCacheDataType, PaintCacheId>;
87   using CacheMap = base::MRUCache<CacheKey, size_t>;
88 
89   template <typename Iterator>
90   void EraseFromMap(Iterator it);
91 
92   CacheMap cache_map_;
93   const size_t max_budget_;
94   size_t bytes_used_ = 0u;
95 
96   // List of entries added to the map but not committed since we might fail to
97   // send them to the service-side cache. This is necessary to ensure we
98   // maintain an accurate mirror of the service-side state.
99   base::StackVector<CacheKey, 1> pending_entries_;
100 };
101 
102 class CC_PAINT_EXPORT ServicePaintCache {
103  public:
104   ServicePaintCache();
105   ~ServicePaintCache();
106 
107   // Stores the |blob| received from the client in the cache.
108   void PutTextBlob(PaintCacheId id, sk_sp<SkTextBlob> blob);
109 
110   // Retrieves an entry for |id| stored in the cache. Or nullptr if the entry
111   // is not found.
112   sk_sp<SkTextBlob> GetTextBlob(PaintCacheId id) const;
113 
114   // Stores |path| received from the client in the cache.
115   void PutPath(PaintCacheId, SkPath path);
116 
117   // Retrieves an entry for |id| stored in the cache. The path data is stored in
118   // |path| pointed memory. Returns false, if the entry is not found.
119   bool GetPath(PaintCacheId id, SkPath* path) const;
120 
121   void Purge(PaintCacheDataType type,
122              size_t n,
123              const volatile PaintCacheId* ids);
124   void PurgeAll();
empty()125   bool empty() const { return cached_blobs_.empty() && cached_paths_.empty(); }
126 
127  private:
128   using BlobMap = std::map<PaintCacheId, sk_sp<SkTextBlob>>;
129   BlobMap cached_blobs_;
130   using PathMap = std::map<PaintCacheId, SkPath>;
131   PathMap cached_paths_;
132 };
133 
134 }  // namespace cc
135 
136 #endif  // CC_PAINT_PAINT_CACHE_H_
137