Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Side by Side Diff: cc/tiles/checker_image_tracker.cc

Issue 2928433003: cc: Add scaling for checkered images. (Closed)
Patch Set: comments Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698