-// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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/time/default_tick_clock.h"
#include "base/trace_event/trace_event.h"
namespace cc {
namespace {
-const int kNumFramesToLock = 2;
+// Timeout images after 250ms, whether or not they've been used. This prevents
+// unbounded cache usage.
+const int64_t kTimeoutDurationMs = 250;
} // namespace
-DecodedImageTracker::DecodedImageTracker(ImageController* controller)
- : image_controller_(controller) {
+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() {
- for (auto& pair : locked_images_)
- image_controller_->UnlockImageDecode(pair.first);
+ UnlockAllImages();
}
void DecodedImageTracker::QueueImageDecode(
const PaintImage& image,
- const gfx::ColorSpace& target_color_space,
- const base::Callback<void(bool)>& callback) {
+ 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(image.frame_index()).ToString());
+ 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, image_bounds, kNone_SkFilterQuality,
- SkMatrix::I(), image.frame_index(), target_color_space);
+ DrawImage draw_image(image, false, image_bounds,
+ PaintFlags::FilterQuality::kNone, SkM44(), frame_index,
+ target_color_params);
image_controller_->QueueImageDecode(
- draw_image, base::Bind(&DecodedImageTracker::ImageDecodeFinished,
- base::Unretained(this), callback));
+ draw_image, base::BindOnce(&DecodedImageTracker::ImageDecodeFinished,
+ base::Unretained(this), std::move(callback),
+ image.stable_id()));
}
-void DecodedImageTracker::NotifyFrameFinished() {
- // Go through the images and if the frame ref count goes to 0, unlock the
- // image in the controller.
- for (auto it = locked_images_.begin(); it != locked_images_.end();) {
- auto id = it->first;
- int& ref_count = it->second;
- if (--ref_count != 0) {
- ++it;
- continue;
- }
- image_controller_->UnlockImageDecode(id);
- it = locked_images_.erase(it);
- }
+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(
- const base::Callback<void(bool)>& callback,
- ImageController::ImageDecodeRequestId id,
+ 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)
- locked_images_.push_back(std::make_pair(id, kNumFramesToLock));
+ 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;
- callback.Run(decode_succeeded);
+ 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