1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
cc / paint / paint_cache.cc [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif
#include "cc/paint/paint_cache.h"
#include "base/check_op.h"
#include "base/containers/flat_set.h"
#include "base/not_fatal_until.h"
#include "base/notreached.h"
#include "base/synchronization/lock.h"
namespace cc {
namespace {
template <typename T>
void EraseFromMap(T* map, size_t n, const volatile PaintCacheId* ids) {
for (size_t i = 0; i < n; ++i) {
auto id = ids[i];
map->erase(id);
}
}
} // namespace
constexpr size_t ClientPaintCache::kNoCachingBudget;
ClientPaintCache::ClientPaintCache(size_t max_budget_bytes)
: cache_map_(CacheMap::NO_AUTO_EVICT), max_budget_(max_budget_bytes) {}
ClientPaintCache::~ClientPaintCache() = default;
bool ClientPaintCache::Get(PaintCacheDataType type, PaintCacheId id) {
return cache_map_.Get(std::make_pair(type, id)) != cache_map_.end();
}
void ClientPaintCache::Put(PaintCacheDataType type,
PaintCacheId id,
size_t size) {
if (max_budget_ == kNoCachingBudget)
return;
auto key = std::make_pair(type, id);
DCHECK(cache_map_.Peek(key) == cache_map_.end());
pending_entries_.push_back(key);
cache_map_.Put(key, size);
bytes_used_ += size;
}
template <typename Iterator>
void ClientPaintCache::EraseFromMap(Iterator it) {
DCHECK_GE(bytes_used_, it->second);
bytes_used_ -= it->second;
cache_map_.Erase(it);
}
void ClientPaintCache::FinalizePendingEntries() {
pending_entries_.clear();
}
void ClientPaintCache::AbortPendingEntries() {
for (const auto& entry : pending_entries_) {
auto it = cache_map_.Peek(entry);
CHECK(it != cache_map_.end(), base::NotFatalUntil::M130);
EraseFromMap(it);
}
pending_entries_.clear();
}
void ClientPaintCache::Purge(PurgedData* purged_data) {
DCHECK(pending_entries_.empty());
while (bytes_used_ > max_budget_) {
auto it = cache_map_.rbegin();
PaintCacheDataType type = it->first.first;
PaintCacheId id = it->first.second;
EraseFromMap(it);
(*purged_data)[static_cast<uint32_t>(type)].push_back(id);
}
}
bool ClientPaintCache::PurgeAll() {
DCHECK(pending_entries_.empty());
bool has_data = !cache_map_.empty();
cache_map_.Clear();
bytes_used_ = 0u;
return has_data;
}
ServicePaintCache::ServicePaintCache() = default;
ServicePaintCache::~ServicePaintCache() = default;
void ServicePaintCache::PutPath(PaintCacheId id, SkPath path) {
cached_paths_.emplace(id, std::move(path));
}
bool ServicePaintCache::GetPath(PaintCacheId id, SkPath* path) const {
auto it = cached_paths_.find(id);
if (it == cached_paths_.end())
return false;
*path = it->second;
return true;
}
void ServicePaintCache::Purge(PaintCacheDataType type,
size_t n,
const volatile PaintCacheId* ids) {
switch (type) {
case PaintCacheDataType::kPath:
EraseFromMap(&cached_paths_, n, ids);
return;
}
NOTREACHED();
}
void ServicePaintCache::PurgeAll() {
cached_paths_.clear();
}
} // namespace cc