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 / tiles / decoded_image_tracker.cc [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/tiles/decoded_image_tracker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/default_tick_clock.h"
#include "base/trace_event/trace_event.h"
namespace cc {
namespace {
// Timeout images after 250ms, whether or not they've been used. This prevents
// unbounded cache usage.
const int64_t kTimeoutDurationMs = 250;
} // namespace
DecodedImageTracker::ImageLock::ImageLock(
DecodedImageTracker* tracker,
ImageController::ImageDecodeRequestId request_id,
base::TimeTicks lock_time)
: tracker_(tracker), request_id_(request_id), lock_time_(lock_time) {}
DecodedImageTracker::ImageLock::~ImageLock() {
tracker_->image_controller_->UnlockImageDecode(request_id_);
}
DecodedImageTracker::DecodedImageTracker(
ImageController* controller,
scoped_refptr<base::SequencedTaskRunner> task_runner)
: image_controller_(controller),
task_runner_(std::move(task_runner)),
tick_clock_(base::DefaultTickClock::GetInstance()) {
DCHECK(image_controller_);
}
DecodedImageTracker::~DecodedImageTracker() {
UnlockAllImages();
}
void DecodedImageTracker::QueueImageDecode(
const PaintImage& image,
const TargetColorParams& target_color_params,
base::OnceCallback<void(bool)> callback) {
size_t frame_index = PaintImage::kDefaultFrameIndex;
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"DecodedImageTracker::QueueImageDecode", "frame_key",
image.GetKeyForFrame(frame_index).ToString());
DCHECK(image_controller_);
// Queue the decode in the image controller, but switch out the callback for
// our own.
auto image_bounds = SkIRect::MakeWH(image.width(), image.height());
DrawImage draw_image(image, false, image_bounds,
PaintFlags::FilterQuality::kNone, SkM44(), frame_index,
target_color_params);
image_controller_->QueueImageDecode(
draw_image, base::BindOnce(&DecodedImageTracker::ImageDecodeFinished,
base::Unretained(this), std::move(callback),
image.stable_id()));
}
void DecodedImageTracker::UnlockAllImages() {
locked_images_.clear();
}
void DecodedImageTracker::OnImagesUsedInDraw(
const std::vector<DrawImage>& draw_images) {
for (const DrawImage& draw_image : draw_images)
locked_images_.erase(draw_image.paint_image().stable_id());
}
void DecodedImageTracker::ImageDecodeFinished(
base::OnceCallback<void(bool)> callback,
PaintImage::Id image_id,
ImageController::ImageDecodeRequestId request_id,
ImageController::ImageDecodeResult result) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"DecodedImageTracker::ImageDecodeFinished");
if (result == ImageController::ImageDecodeResult::SUCCESS) {
// If this image already exists, just replace it with the new (latest)
// decode.
locked_images_.erase(image_id);
locked_images_.emplace(
image_id,
std::make_unique<ImageLock>(this, request_id, tick_clock_->NowTicks()));
EnqueueTimeout();
}
bool decode_succeeded =
result == ImageController::ImageDecodeResult::SUCCESS ||
result == ImageController::ImageDecodeResult::DECODE_NOT_REQUIRED;
std::move(callback).Run(decode_succeeded);
}
void DecodedImageTracker::OnTimeoutImages() {
timeout_pending_ = false;
if (locked_images_.size() == 0)
return;
auto now = tick_clock_->NowTicks();
auto timeout = base::Milliseconds(kTimeoutDurationMs);
for (auto it = locked_images_.begin(); it != locked_images_.end();) {
auto& image = it->second;
if (now - image->lock_time() < timeout) {
++it;
continue;
}
it = locked_images_.erase(it);
}
EnqueueTimeout();
}
void DecodedImageTracker::EnqueueTimeout() {
if (timeout_pending_)
return;
if (locked_images_.size() == 0)
return;
timeout_pending_ = true;
task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&DecodedImageTracker::OnTimeoutImages,
weak_ptr_factory_.GetWeakPtr()),
base::Milliseconds(kTimeoutDurationMs));
}
} // namespace cc