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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
cc / tiles / software_image_decode_cache_utils.h [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.
#ifndef CC_TILES_SOFTWARE_IMAGE_DECODE_CACHE_UTILS_H_
#define CC_TILES_SOFTWARE_IMAGE_DECODE_CACHE_UTILS_H_
#include <limits>
#include <memory>
#include <string>
#include "base/functional/callback.h"
#include "base/memory/discardable_memory.h"
#include "base/memory/scoped_refptr.h"
#include "cc/cc_export.h"
#include "cc/paint/decoded_draw_image.h"
#include "cc/paint/draw_image.h"
#include "cc/paint/paint_image.h"
#include "cc/paint/target_color_params.h"
#include "cc/raster/tile_task.h"
#include "cc/tiles/image_decode_cache_utils.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkSize.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
namespace cc {
class SoftwareImageDecodeCacheUtils {
private:
// The following should only be accessed by the software image cache.
friend class SoftwareImageDecodeCache;
// CacheKey is a class that gets a cache key out of a given draw
// image. That is, this key uniquely identifies an image in the cache. Note
// that it's insufficient to use SkImage's unique id, since the same image can
// appear in the cache multiple times at different scales and filter
// qualities.
class CC_EXPORT CacheKey {
public:
// Enum indicating the type of processing to do for this key:
// kOriginal - use the original decode without any subrecting or scaling.
// kSubrectOriginal - extract a subrect from the original decode but do not
// scale it.
// kSubrectAndScale - extract a subrect (if needed) from the original decode
// and scale it.
enum ProcessingType { kOriginal, kSubrectOriginal, kSubrectAndScale };
static CacheKey FromDrawImage(const DrawImage& image,
SkColorType color_type);
CacheKey(const CacheKey& other);
CacheKey& operator=(const CacheKey& other);
bool operator==(const CacheKey& other) const {
// The frame_key always has to be the same. However, after that all
// original decodes are the same, so if we can use the original decode,
// return true. If not, then we have to compare every field.
// |nearest_neighbor_| is not compared below since it is not used for
// scaled decodes and does not affect the contents of the cache entry
// (just passed to skia for the filtering to be done at raster time).
DCHECK(!is_nearest_neighbor_ || type_ != kSubrectAndScale);
return frame_key_ == other.frame_key_ && type_ == other.type_ &&
target_color_params_ == other.target_color_params_ &&
(type_ == kOriginal || (src_rect_ == other.src_rect_ &&
target_size_ == other.target_size_));
}
bool operator!=(const CacheKey& other) const { return !(*this == other); }
const PaintImage::FrameKey& frame_key() const { return frame_key_; }
PaintImage::Id stable_id() const { return stable_id_; }
ProcessingType type() const { return type_; }
bool is_nearest_neighbor() const { return is_nearest_neighbor_; }
bool may_be_lcp_candidate() const { return may_be_lcp_candidate_; }
gfx::Rect src_rect() const { return src_rect_; }
gfx::Size target_size() const { return target_size_; }
const TargetColorParams& target_color_params() const {
return target_color_params_;
}
size_t get_hash() const { return hash_; }
// Helper to figure out how much memory the locked image represented by this
// key would take.
size_t locked_bytes() const {
// TODO(vmpstr): Handle formats other than RGBA.
base::CheckedNumeric<size_t> result = 4;
result *= target_size_.width();
result *= target_size_.height();
return result.ValueOrDefault(std::numeric_limits<size_t>::max());
}
std::string ToString() const;
private:
CacheKey(PaintImage::FrameKey frame_key,
PaintImage::Id stable_id,
ProcessingType type,
bool is_nearest_neighbor,
bool may_be_lcp_candidate,
const gfx::Rect& src_rect,
const gfx::Size& size,
const TargetColorParams& target_color_params);
PaintImage::FrameKey frame_key_;
// The stable id is does not factor into the cache key's value for hashing
// and comparison (as it is redundant). It is only used to look up other
// cache entries of the same stable id.
PaintImage::Id stable_id_;
ProcessingType type_;
bool is_nearest_neighbor_;
bool may_be_lcp_candidate_;
gfx::Rect src_rect_;
gfx::Size target_size_;
TargetColorParams target_color_params_;
size_t hash_;
};
struct CacheKeyHash {
size_t operator()(const CacheKey& key) const { return key.get_hash(); }
};
// CacheEntry is a convenience storage for discardable memory. It can also
// construct an image out of SkImageInfo and stored discardable memory.
class CC_EXPORT CacheEntry {
public:
CacheEntry();
CacheEntry(const SkImageInfo& info,
std::unique_ptr<base::DiscardableMemory> memory,
const SkSize& src_rect_offset);
~CacheEntry();
void MoveImageMemoryTo(CacheEntry* entry);
sk_sp<SkImage> image() const {
if (!memory)
return nullptr;
DCHECK(is_locked);
return image_;
}
const SkSize& src_rect_offset() const { return src_rect_offset_; }
bool Lock();
void Unlock();
// An ID which uniquely identifies this CacheEntry within the image decode
// cache. Used in memory tracing.
uint64_t tracing_id() const { return tracing_id_; }
// Mark this image as being used in either a draw or as a source for a
// scaled image. Either case represents this decode as being valuable and
// not wasted.
void mark_used() { usage_stats_.used = true; }
void mark_cached() { cached_ = true; }
void mark_out_of_raster() { usage_stats_.first_lock_out_of_raster = true; }
// Since this is an inner class, we expose these variables publicly for
// simplicity.
// TODO(vmpstr): A good simple clean-up would be to rethink this class
// and its interactions to instead expose a few functions which would also
// facilitate easier DCHECKs.
int ref_count = 0;
bool decode_failed = false;
bool is_locked = false;
bool is_budgeted = false;
scoped_refptr<TileTask> in_raster_task;
scoped_refptr<TileTask> out_of_raster_task;
std::unique_ptr<base::DiscardableMemory> memory;
private:
struct UsageStats {
// We can only create a decoded image in a locked state, so the initial
// lock count is 1.
int lock_count = 1;
bool used = false;
bool last_lock_failed = false;
bool first_lock_wasted = false;
bool first_lock_out_of_raster = false;
};
SkImageInfo image_info_;
sk_sp<SkImage> image_;
SkSize src_rect_offset_;
uint64_t tracing_id_;
UsageStats usage_stats_;
// Indicates whether this entry was ever in the cache.
bool cached_ = false;
};
// |on_no_memory| is called when memory allocation fails in this function,
// before retrying it once. As a consequence, this should free memory, and
// importantly, address space as well.
static std::unique_ptr<CacheEntry> DoDecodeImage(
const CacheKey& key,
const PaintImage& image,
SkColorType color_type,
PaintImage::GeneratorClientId client_id,
base::OnceClosure on_no_memory);
static std::unique_ptr<CacheEntry> GenerateCacheEntryFromCandidate(
const CacheKey& key,
const DecodedDrawImage& candidate,
bool needs_extract_subset,
SkColorType color_type);
};
} // namespace cc
#endif // CC_TILES_SOFTWARE_IMAGE_DECODE_CACHE_UTILS_H_