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