| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/tiles/checker_image_tracker.h" | 5 #include "cc/tiles/checker_image_tracker.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
| 9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 #include "base/trace_event/trace_event.h" | 10 #include "base/trace_event/trace_event.h" |
| 11 | 11 |
| 12 namespace cc { | 12 namespace cc { |
| 13 namespace { | 13 namespace { |
| 14 // The minimum size of an image that we should consider checkering. | 14 // The minimum size of an image that we should consider checkering. |
| 15 size_t kMinImageSizeToCheckerBytes = 512 * 1024; | 15 size_t kMinImageSizeToCheckerBytes = 512 * 1024; |
| 16 | 16 |
| 17 size_t SafeSizeOfImage(const SkImage* image) { | 17 size_t SafeSizeOfImage(const SkImage* image) { |
| 18 base::CheckedNumeric<size_t> checked_size = 4; | 18 base::CheckedNumeric<size_t> checked_size = 4; |
| 19 checked_size *= image->width(); | 19 checked_size *= image->width(); |
| 20 checked_size *= image->height(); | 20 checked_size *= image->height(); |
| 21 return checked_size.ValueOrDefault(std::numeric_limits<size_t>::max()); | 21 return checked_size.ValueOrDefault(std::numeric_limits<size_t>::max()); |
| 22 } | 22 } |
| 23 | 23 |
| 24 std::string ToString(PaintImage::Id paint_image_id, |
| 25 SkImageId sk_image_id, |
| 26 bool complete, |
| 27 bool static_image, |
| 28 bool fits_size_constraints, |
| 29 size_t size) { |
| 30 std::ostringstream str; |
| 31 str << "paint_image_id[" << paint_image_id << "] sk_image_id[" << sk_image_id |
| 32 << "] complete[" << complete << "] static[" << static_image |
| 33 << "], fits_size_constraints[" << fits_size_constraints << "], size[" |
| 34 << size << "]"; |
| 35 return str.str(); |
| 36 } |
| 37 |
| 24 } // namespace | 38 } // namespace |
| 25 | 39 |
| 26 CheckerImageTracker::CheckerImageTracker(ImageController* image_controller, | 40 CheckerImageTracker::CheckerImageTracker(ImageController* image_controller, |
| 27 CheckerImageTrackerClient* client, | 41 CheckerImageTrackerClient* client, |
| 28 bool enable_checker_imaging) | 42 bool enable_checker_imaging) |
| 29 : image_controller_(image_controller), | 43 : image_controller_(image_controller), |
| 30 client_(client), | 44 client_(client), |
| 31 enable_checker_imaging_(enable_checker_imaging), | 45 enable_checker_imaging_(enable_checker_imaging), |
| 32 weak_factory_(this) {} | 46 weak_factory_(this) {} |
| 33 | 47 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 image_id_to_decode_.clear(); | 96 image_id_to_decode_.clear(); |
| 83 | 97 |
| 84 if (can_clear_decode_policy_tracking) { | 98 if (can_clear_decode_policy_tracking) { |
| 85 image_async_decode_state_.clear(); | 99 image_async_decode_state_.clear(); |
| 86 } else { | 100 } else { |
| 87 // If we can't clear the decode policy, we need to make sure we still | 101 // If we can't clear the decode policy, we need to make sure we still |
| 88 // re-decode and checker images that were pending invalidation. | 102 // re-decode and checker images that were pending invalidation. |
| 89 for (auto image_id : images_pending_invalidation_) { | 103 for (auto image_id : images_pending_invalidation_) { |
| 90 auto it = image_async_decode_state_.find(image_id); | 104 auto it = image_async_decode_state_.find(image_id); |
| 91 DCHECK(it != image_async_decode_state_.end()); | 105 DCHECK(it != image_async_decode_state_.end()); |
| 92 DCHECK_EQ(it->second, DecodePolicy::SYNC); | 106 DCHECK_EQ(it->second.policy, DecodePolicy::SYNC); |
| 93 it->second = DecodePolicy::ASYNC; | 107 it->second.policy = DecodePolicy::ASYNC; |
| 94 } | 108 } |
| 95 } | 109 } |
| 96 images_pending_invalidation_.clear(); | 110 images_pending_invalidation_.clear(); |
| 97 } | 111 } |
| 98 | 112 |
| 99 void CheckerImageTracker::DisallowCheckeringForImage(const PaintImage& image) { | 113 void CheckerImageTracker::DisallowCheckeringForImage(const PaintImage& image) { |
| 100 image_async_decode_state_.insert( | 114 image_async_decode_state_.insert( |
| 101 std::make_pair(image.stable_id(), DecodePolicy::SYNC)); | 115 std::make_pair(image.stable_id(), DecodeState())); |
| 102 } | 116 } |
| 103 | 117 |
| 104 void CheckerImageTracker::DidFinishImageDecode( | 118 void CheckerImageTracker::DidFinishImageDecode( |
| 105 PaintImage::Id image_id, | 119 PaintImage::Id image_id, |
| 106 ImageController::ImageDecodeRequestId request_id, | 120 ImageController::ImageDecodeRequestId request_id, |
| 107 ImageController::ImageDecodeResult result) { | 121 ImageController::ImageDecodeResult result) { |
| 108 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | 122 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
| 109 "CheckerImageTracker::DidFinishImageDecode"); | 123 "CheckerImageTracker::DidFinishImageDecode"); |
| 110 TRACE_EVENT_ASYNC_END0("cc", "CheckerImageTracker::DeferImageDecode", | 124 TRACE_EVENT_ASYNC_END0("cc", "CheckerImageTracker::DeferImageDecode", |
| 111 image_id); | 125 image_id); |
| 112 | 126 |
| 113 DCHECK_NE(ImageController::ImageDecodeResult::DECODE_NOT_REQUIRED, result); | 127 DCHECK_NE(ImageController::ImageDecodeResult::DECODE_NOT_REQUIRED, result); |
| 114 DCHECK_EQ(outstanding_image_decode_.value().stable_id(), image_id); | 128 DCHECK_EQ(outstanding_image_decode_.value().stable_id(), image_id); |
| 115 outstanding_image_decode_.reset(); | 129 outstanding_image_decode_.reset(); |
| 116 | 130 |
| 117 // The async decode state may have been cleared if the tracker was cleared | 131 // The async decode state may have been cleared if the tracker was cleared |
| 118 // before this decode could be finished. | 132 // before this decode could be finished. |
| 119 auto it = image_async_decode_state_.find(image_id); | 133 auto it = image_async_decode_state_.find(image_id); |
| 120 if (it == image_async_decode_state_.end()) { | 134 if (it == image_async_decode_state_.end()) { |
| 121 DCHECK_EQ(image_id_to_decode_.count(image_id), 0u); | 135 DCHECK_EQ(image_id_to_decode_.count(image_id), 0u); |
| 122 return; | 136 return; |
| 123 } | 137 } |
| 124 | 138 |
| 125 it->second = DecodePolicy::SYNC; | 139 it->second.policy = DecodePolicy::SYNC; |
| 126 images_pending_invalidation_.insert(image_id); | 140 images_pending_invalidation_.insert(image_id); |
| 127 ScheduleNextImageDecode(); | 141 ScheduleNextImageDecode(); |
| 128 client_->NeedsInvalidationForCheckerImagedTiles(); | 142 client_->NeedsInvalidationForCheckerImagedTiles(); |
| 129 } | 143 } |
| 130 | 144 |
| 131 bool CheckerImageTracker::ShouldCheckerImage(const PaintImage& image, | 145 bool CheckerImageTracker::ShouldCheckerImage(const DrawImage& draw_image, |
| 132 WhichTree tree) { | 146 WhichTree tree) { |
| 147 const PaintImage& image = draw_image.paint_image(); |
| 148 PaintImage::Id image_id = image.stable_id(); |
| 133 TRACE_EVENT1("cc", "CheckerImageTracker::ShouldCheckerImage", "image_id", | 149 TRACE_EVENT1("cc", "CheckerImageTracker::ShouldCheckerImage", "image_id", |
| 134 image.stable_id()); | 150 image_id); |
| 135 | 151 |
| 136 if (!enable_checker_imaging_) | 152 if (!enable_checker_imaging_) |
| 137 return false; | 153 return false; |
| 138 | 154 |
| 139 PaintImage::Id image_id = image.stable_id(); | |
| 140 | |
| 141 // If the image was invalidated on the current sync tree and the tile is | 155 // If the image was invalidated on the current sync tree and the tile is |
| 142 // for the active tree, continue checkering it on the active tree to ensure | 156 // for the active tree, continue checkering it on the active tree to ensure |
| 143 // the image update is atomic for the frame. | 157 // the image update is atomic for the frame. |
| 144 if (invalidated_images_on_current_sync_tree_.count(image_id) != 0 && | 158 if (invalidated_images_on_current_sync_tree_.count(image_id) != 0 && |
| 145 tree == WhichTree::ACTIVE_TREE) { | 159 tree == WhichTree::ACTIVE_TREE) { |
| 146 return true; | 160 return true; |
| 147 } | 161 } |
| 148 | 162 |
| 149 // If the image is pending invalidation, continue checkering it. All tiles | 163 // If the image is pending invalidation, continue checkering it. All tiles |
| 150 // for these images will be invalidated on the next pending tree. | 164 // for these images will be invalidated on the next pending tree. |
| 151 if (images_pending_invalidation_.find(image_id) != | 165 if (images_pending_invalidation_.find(image_id) != |
| 152 images_pending_invalidation_.end()) { | 166 images_pending_invalidation_.end()) { |
| 153 return true; | 167 return true; |
| 154 } | 168 } |
| 155 | 169 |
| 156 auto insert_result = image_async_decode_state_.insert( | 170 auto insert_result = image_async_decode_state_.insert( |
| 157 std::pair<PaintImage::Id, DecodePolicy>(image_id, DecodePolicy::SYNC)); | 171 std::pair<PaintImage::Id, DecodeState>(image_id, DecodeState())); |
| 158 auto it = insert_result.first; | 172 auto it = insert_result.first; |
| 159 if (insert_result.second) { | 173 if (insert_result.second) { |
| 160 bool can_checker_image = | 174 bool complete = |
| 161 image.animation_type() == PaintImage::AnimationType::STATIC && | |
| 162 image.completion_state() == PaintImage::CompletionState::DONE; | 175 image.completion_state() == PaintImage::CompletionState::DONE; |
| 163 if (can_checker_image) { | 176 bool static_image = |
| 164 size_t size = SafeSizeOfImage(image.sk_image().get()); | 177 image.animation_type() == PaintImage::AnimationType::STATIC; |
| 165 it->second = (size >= kMinImageSizeToCheckerBytes && | 178 size_t size = SafeSizeOfImage(image.sk_image().get()); |
| 166 size <= image_controller_->image_cache_max_limit_bytes()) | 179 bool fits_size_constraints = |
| 167 ? DecodePolicy::ASYNC | 180 size >= kMinImageSizeToCheckerBytes && |
| 168 : DecodePolicy::SYNC; | 181 size <= image_controller_->image_cache_max_limit_bytes(); |
| 169 } | 182 |
| 183 // Only checker images that are static and completely loaded and fit within |
| 184 // the size constraints. |
| 185 bool can_checker_image = complete && static_image && fits_size_constraints; |
| 186 if (can_checker_image) |
| 187 it->second.policy = DecodePolicy::ASYNC; |
| 188 |
| 189 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
| 190 "CheckerImageTracker::CheckerImagingDecision", |
| 191 "can_checker_image", can_checker_image, "image_params", |
| 192 ToString(image_id, image.sk_image()->uniqueID(), complete, |
| 193 static_image, fits_size_constraints, size)); |
| 170 } | 194 } |
| 171 | 195 |
| 172 return it->second == DecodePolicy::ASYNC; | 196 // Update the decode state from the latest image we have seen. Note that it |
| 197 // is not necessary to perform this in the early out cases above since in |
| 198 // each of those cases the image has already been decoded. |
| 199 UpdateDecodeState(draw_image, image_id, &it->second); |
| 200 |
| 201 return it->second.policy == DecodePolicy::ASYNC; |
| 202 } |
| 203 |
| 204 void CheckerImageTracker::UpdateDecodeState(const DrawImage& draw_image, |
| 205 PaintImage::Id paint_image_id, |
| 206 DecodeState* decode_state) { |
| 207 // If the policy is not async then either we decoded this image already or |
| 208 // we decided not to ever checker it. |
| 209 if (decode_state->policy != DecodePolicy::ASYNC) |
| 210 return; |
| 211 |
| 212 // If the decode is already in flight, then we will have to live with what we |
| 213 // have now. |
| 214 if (outstanding_image_decode_.has_value() && |
| 215 outstanding_image_decode_.value().stable_id() == paint_image_id) { |
| 216 return; |
| 217 } |
| 218 |
| 219 // Choose the max scale and filter quality. This keeps the memory usage to the |
| 220 // minimum possible while still increasing the possibility of getting a cache |
| 221 // hit. |
| 222 decode_state->scale = SkSize::Make( |
| 223 std::max(decode_state->scale.fWidth, draw_image.scale().fWidth), |
| 224 std::max(decode_state->scale.fHeight, draw_image.scale().fHeight)); |
| 225 decode_state->filter_quality = |
| 226 std::max(decode_state->filter_quality, draw_image.filter_quality()); |
| 227 decode_state->color_space = draw_image.target_color_space(); |
| 173 } | 228 } |
| 174 | 229 |
| 175 void CheckerImageTracker::ScheduleNextImageDecode() { | 230 void CheckerImageTracker::ScheduleNextImageDecode() { |
| 176 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | 231 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
| 177 "CheckerImageTracker::ScheduleNextImageDecode"); | 232 "CheckerImageTracker::ScheduleNextImageDecode"); |
| 178 // We can have only one outsanding decode pending completion with the decode | 233 // We can have only one outstanding decode pending completion with the decode |
| 179 // service. We'll come back here when it is completed. | 234 // service. We'll come back here when it is completed. |
| 180 if (outstanding_image_decode_.has_value()) | 235 if (outstanding_image_decode_.has_value()) |
| 181 return; | 236 return; |
| 182 | 237 |
| 238 DrawImage draw_image; |
| 183 while (!image_decode_queue_.empty()) { | 239 while (!image_decode_queue_.empty()) { |
| 184 auto candidate = std::move(image_decode_queue_.front()); | 240 auto candidate = std::move(image_decode_queue_.front()); |
| 185 image_decode_queue_.erase(image_decode_queue_.begin()); | 241 image_decode_queue_.erase(image_decode_queue_.begin()); |
| 186 | 242 |
| 187 // Once an image has been decoded, it can still be present in the decode | 243 // Once an image has been decoded, it can still be present in the decode |
| 188 // queue (duplicate entries), or while an image is still being skipped on | 244 // queue (duplicate entries), or while an image is still being skipped on |
| 189 // the active tree. Check if the image is still ASYNC to see if a decode is | 245 // the active tree. Check if the image is still ASYNC to see if a decode is |
| 190 // needed. | 246 // needed. |
| 191 PaintImage::Id image_id = candidate.stable_id(); | 247 PaintImage::Id image_id = candidate.stable_id(); |
| 192 auto it = image_async_decode_state_.find(image_id); | 248 auto it = image_async_decode_state_.find(image_id); |
| 193 DCHECK(it != image_async_decode_state_.end()); | 249 DCHECK(it != image_async_decode_state_.end()); |
| 194 if (it->second != DecodePolicy::ASYNC) | 250 if (it->second.policy != DecodePolicy::ASYNC) |
| 195 continue; | 251 continue; |
| 196 | 252 |
| 253 draw_image = DrawImage(candidate, candidate.sk_image()->bounds(), |
| 254 it->second.filter_quality, |
| 255 SkMatrix::MakeScale(it->second.scale.width(), |
| 256 it->second.scale.height()), |
| 257 it->second.color_space); |
| 197 outstanding_image_decode_.emplace(candidate); | 258 outstanding_image_decode_.emplace(candidate); |
| 198 break; | 259 break; |
| 199 } | 260 } |
| 200 | 261 |
| 201 // We either found an image to decode or we reached the end of the queue. If | 262 // We either found an image to decode or we reached the end of the queue. If |
| 202 // we couldn't find an image, we're done. | 263 // we couldn't find an image, we're done. |
| 203 if (!outstanding_image_decode_.has_value()) { | 264 if (!outstanding_image_decode_.has_value()) { |
| 204 DCHECK(image_decode_queue_.empty()); | 265 DCHECK(image_decode_queue_.empty()); |
| 205 return; | 266 return; |
| 206 } | 267 } |
| 207 | 268 |
| 208 PaintImage::Id image_id = outstanding_image_decode_.value().stable_id(); | 269 PaintImage::Id image_id = outstanding_image_decode_.value().stable_id(); |
| 209 DCHECK_EQ(image_id_to_decode_.count(image_id), 0u); | 270 DCHECK_EQ(image_id_to_decode_.count(image_id), 0u); |
| 210 TRACE_EVENT_ASYNC_BEGIN0("cc", "CheckerImageTracker::DeferImageDecode", | 271 TRACE_EVENT_ASYNC_BEGIN0("cc", "CheckerImageTracker::DeferImageDecode", |
| 211 image_id); | 272 image_id); |
| 212 ImageController::ImageDecodeRequestId request_id = | 273 ImageController::ImageDecodeRequestId request_id = |
| 213 image_controller_->QueueImageDecode( | 274 image_controller_->QueueImageDecode( |
| 214 outstanding_image_decode_.value().sk_image(), | 275 draw_image, base::Bind(&CheckerImageTracker::DidFinishImageDecode, |
| 215 base::Bind(&CheckerImageTracker::DidFinishImageDecode, | 276 weak_factory_.GetWeakPtr(), image_id)); |
| 216 weak_factory_.GetWeakPtr(), image_id)); | |
| 217 | 277 |
| 218 image_id_to_decode_.emplace(image_id, base::MakeUnique<ScopedDecodeHolder>( | 278 image_id_to_decode_.emplace(image_id, base::MakeUnique<ScopedDecodeHolder>( |
| 219 image_controller_, request_id)); | 279 image_controller_, request_id)); |
| 220 } | 280 } |
| 221 | 281 |
| 222 } // namespace cc | 282 } // namespace cc |
| OLD | NEW |