summaryrefslogtreecommitdiff
path: root/chromium/cc/tiles/checker_image_tracker.cc
blob: c8113d4d56052edb486948d64999a2680ce952d8 (plain)
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
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/tiles/checker_image_tracker.h"

#include "base/bind.h"
#include "base/trace_event/trace_event.h"

namespace cc {
namespace {
// The minimum size of an image that we should consider checkering.
size_t kMinImageSizeToCheckerBytes = 512 * 1024;

size_t SafeSizeOfImage(const SkImage* image) {
  base::CheckedNumeric<size_t> checked_size = 4;
  checked_size *= image->width();
  checked_size *= image->height();
  return checked_size.ValueOrDefault(std::numeric_limits<size_t>::max());
}

}  // namespace

CheckerImageTracker::CheckerImageTracker(ImageController* image_controller,
                                         CheckerImageTrackerClient* client,
                                         bool enable_checker_imaging)
    : image_controller_(image_controller),
      client_(client),
      enable_checker_imaging_(enable_checker_imaging),
      weak_factory_(this) {}

CheckerImageTracker::~CheckerImageTracker() {
  // Unlock all images pending decode requests.
  for (auto it : image_id_to_decode_request_id_)
    image_controller_->UnlockImageDecode(it.second);
}

void CheckerImageTracker::FilterImagesForCheckeringForTile(
    std::vector<DrawImage>* images,
    ImageIdFlatSet* checkered_images,
    WhichTree tree) {
  DCHECK(checkered_images->empty());

  auto images_to_checker = std::remove_if(
      images->begin(), images->end(),
      [this, tree, &checkered_images](const DrawImage& draw_image) {
        const sk_sp<const SkImage>& image = draw_image.image();
        DCHECK(image->isLazyGenerated());
        if (ShouldCheckerImage(image, tree)) {
          ScheduleImageDecodeIfNecessary(image);
          checkered_images->insert(image->uniqueID());
          return true;
        }
        return false;
      });
  images->erase(images_to_checker, images->end());
}

const ImageIdFlatSet& CheckerImageTracker::TakeImagesToInvalidateOnSyncTree() {
  DCHECK_EQ(invalidated_images_on_current_sync_tree_.size(), 0u)
      << "Sync tree can not be invalidated more than once";

  invalidated_images_on_current_sync_tree_.swap(images_pending_invalidation_);
  images_pending_invalidation_.clear();
  return invalidated_images_on_current_sync_tree_;
}

void CheckerImageTracker::DidActivateSyncTree() {
  for (auto image_id : invalidated_images_on_current_sync_tree_) {
    auto it = image_id_to_decode_request_id_.find(image_id);
    image_controller_->UnlockImageDecode(it->second);
    image_id_to_decode_request_id_.erase(it);
  }

  invalidated_images_on_current_sync_tree_.clear();
}

void CheckerImageTracker::DidFinishImageDecode(
    ImageId image_id,
    ImageController::ImageDecodeRequestId request_id,
    ImageController::ImageDecodeResult result) {
  TRACE_EVENT_ASYNC_END0("cc", "CheckerImageTracker::DeferImageDecode",
                         image_id);

  DCHECK_NE(result, ImageController::ImageDecodeResult::DECODE_NOT_REQUIRED);
  DCHECK_NE(pending_image_decodes_.count(image_id), 0u);
  pending_image_decodes_.erase(image_id);

  images_decoded_once_.insert(image_id);
  images_pending_invalidation_.insert(image_id);
  client_->NeedsInvalidationForCheckerImagedTiles();
}

bool CheckerImageTracker::ShouldCheckerImage(const sk_sp<const SkImage>& image,
                                             WhichTree tree) const {
  TRACE_EVENT1("cc", "CheckerImageTracker::ShouldCheckerImage", "image_id",
               image->uniqueID());

  if (!enable_checker_imaging_)
    return false;

  // If the image was invalidated on the current sync tree and the tile is
  // for the active tree, continue checkering it on the active tree to ensure
  // the image update is atomic for the frame.
  if (invalidated_images_on_current_sync_tree_.count(image->uniqueID()) != 0 &&
      tree == WhichTree::ACTIVE_TREE) {
    return true;
  }

  // If a decode request is pending for this image, continue checkering it.
  if (pending_image_decodes_.find(image->uniqueID()) !=
      pending_image_decodes_.end()) {
    return true;
  }

  // If the image is pending invalidation, continue checkering it. All tiles
  // for these images will be invalidated on the next pending tree.
  if (images_pending_invalidation_.find(image->uniqueID()) !=
      images_pending_invalidation_.end()) {
    return true;
  }

  // If the image has been decoded once before, don't checker it again.
  if (images_decoded_once_.find(image->uniqueID()) !=
      images_decoded_once_.end()) {
    return false;
  }

  return SafeSizeOfImage(image.get()) >= kMinImageSizeToCheckerBytes;
}

void CheckerImageTracker::ScheduleImageDecodeIfNecessary(
    const sk_sp<const SkImage>& image) {
  ImageId image_id = image->uniqueID();

  // If the image has already been decoded, or a decode request is pending, we
  // don't need to schedule another decode.
  if (images_decoded_once_.count(image_id) != 0 ||
      pending_image_decodes_.count(image_id) != 0) {
    return;
  }

  TRACE_EVENT_ASYNC_BEGIN0("cc", "CheckerImageTracker::DeferImageDecode",
                           image_id);
  DCHECK_EQ(image_id_to_decode_request_id_.count(image_id), 0U);

  image_id_to_decode_request_id_[image_id] =
      image_controller_->QueueImageDecode(
          image, base::Bind(&CheckerImageTracker::DidFinishImageDecode,
                            weak_factory_.GetWeakPtr(), image_id));
  pending_image_decodes_.insert(image_id);
}

}  // namespace cc