Index: cc/tiles/checker_image_tracker.cc |
diff --git a/cc/tiles/checker_image_tracker.cc b/cc/tiles/checker_image_tracker.cc |
index 2f04b9f478e85f76ddb9e5ff5f8e54ac116f0c62..e076983ad7e9f3452a042accf35c69efd2895b57 100644 |
--- a/cc/tiles/checker_image_tracker.cc |
+++ b/cc/tiles/checker_image_tracker.cc |
@@ -21,6 +21,20 @@ size_t SafeSizeOfImage(const SkImage* image) { |
return checked_size.ValueOrDefault(std::numeric_limits<size_t>::max()); |
} |
+std::string ToString(PaintImage::Id paint_image_id, |
+ SkImageId sk_image_id, |
+ bool complete, |
+ bool static_image, |
+ bool fits_size_constraints, |
+ size_t size) { |
+ std::ostringstream str; |
+ str << "paint_image_id[" << paint_image_id << "] sk_image_id[" << sk_image_id |
+ << "] complete[" << complete << "] static[" << static_image |
+ << "], fits_size_constraints[" << fits_size_constraints << "], size[" |
+ << size << "]"; |
+ return str.str(); |
+} |
+ |
} // namespace |
CheckerImageTracker::CheckerImageTracker(ImageController* image_controller, |
@@ -89,8 +103,8 @@ void CheckerImageTracker::ClearTracker(bool can_clear_decode_policy_tracking) { |
for (auto image_id : images_pending_invalidation_) { |
auto it = image_async_decode_state_.find(image_id); |
DCHECK(it != image_async_decode_state_.end()); |
- DCHECK_EQ(it->second, DecodePolicy::SYNC); |
- it->second = DecodePolicy::ASYNC; |
+ DCHECK_EQ(it->second.policy, DecodePolicy::SYNC); |
+ it->second.policy = DecodePolicy::ASYNC; |
} |
} |
images_pending_invalidation_.clear(); |
@@ -98,7 +112,7 @@ void CheckerImageTracker::ClearTracker(bool can_clear_decode_policy_tracking) { |
void CheckerImageTracker::DisallowCheckeringForImage(const PaintImage& image) { |
image_async_decode_state_.insert( |
- std::make_pair(image.stable_id(), DecodePolicy::SYNC)); |
+ std::make_pair(image.stable_id(), DecodeState())); |
} |
void CheckerImageTracker::DidFinishImageDecode( |
@@ -122,22 +136,22 @@ void CheckerImageTracker::DidFinishImageDecode( |
return; |
} |
- it->second = DecodePolicy::SYNC; |
+ it->second.policy = DecodePolicy::SYNC; |
images_pending_invalidation_.insert(image_id); |
ScheduleNextImageDecode(); |
client_->NeedsInvalidationForCheckerImagedTiles(); |
} |
-bool CheckerImageTracker::ShouldCheckerImage(const PaintImage& image, |
+bool CheckerImageTracker::ShouldCheckerImage(const DrawImage& draw_image, |
WhichTree tree) { |
+ const PaintImage& image = draw_image.paint_image(); |
+ PaintImage::Id image_id = image.stable_id(); |
TRACE_EVENT1("cc", "CheckerImageTracker::ShouldCheckerImage", "image_id", |
- image.stable_id()); |
+ image_id); |
if (!enable_checker_imaging_) |
return false; |
- PaintImage::Id image_id = image.stable_id(); |
- |
// 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. |
@@ -154,32 +168,74 @@ bool CheckerImageTracker::ShouldCheckerImage(const PaintImage& image, |
} |
auto insert_result = image_async_decode_state_.insert( |
- std::pair<PaintImage::Id, DecodePolicy>(image_id, DecodePolicy::SYNC)); |
+ std::pair<PaintImage::Id, DecodeState>(image_id, DecodeState())); |
auto it = insert_result.first; |
if (insert_result.second) { |
- bool can_checker_image = |
- image.animation_type() == PaintImage::AnimationType::STATIC && |
+ bool complete = |
image.completion_state() == PaintImage::CompletionState::DONE; |
- if (can_checker_image) { |
- size_t size = SafeSizeOfImage(image.sk_image().get()); |
- it->second = (size >= kMinImageSizeToCheckerBytes && |
- size <= image_controller_->image_cache_max_limit_bytes()) |
- ? DecodePolicy::ASYNC |
- : DecodePolicy::SYNC; |
- } |
+ bool static_image = |
+ image.animation_type() == PaintImage::AnimationType::STATIC; |
+ size_t size = SafeSizeOfImage(image.sk_image().get()); |
+ bool fits_size_constraints = |
+ size >= kMinImageSizeToCheckerBytes && |
+ size <= image_controller_->image_cache_max_limit_bytes(); |
+ |
+ // Only checker images that are static and completely loaded and fit within |
+ // the size constraints. |
+ bool can_checker_image = complete && static_image && fits_size_constraints; |
+ if (can_checker_image) |
+ it->second.policy = DecodePolicy::ASYNC; |
+ |
+ TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
+ "CheckerImageTracker::CheckerImagingDecision", |
+ "can_checker_image", can_checker_image, "image_params", |
+ ToString(image_id, image.sk_image()->uniqueID(), complete, |
+ static_image, fits_size_constraints, size)); |
+ } |
+ |
+ // Update the decode state from the latest image we have seen. Note that it |
+ // is not necessary to perform this in the early out cases above since in |
+ // each of those cases the image has already been decoded. |
+ UpdateDecodeState(draw_image, image_id, &it->second); |
+ |
+ return it->second.policy == DecodePolicy::ASYNC; |
+} |
+ |
+void CheckerImageTracker::UpdateDecodeState(const DrawImage& draw_image, |
+ PaintImage::Id paint_image_id, |
+ DecodeState* decode_state) { |
+ // If the policy is not async then either we decoded this image already or |
+ // we decided not to ever checker it. |
+ if (decode_state->policy != DecodePolicy::ASYNC) |
+ return; |
+ |
+ // If the decode is already in flight, then we will have to live with what we |
+ // have now. |
+ if (outstanding_image_decode_.has_value() && |
+ outstanding_image_decode_.value().stable_id() == paint_image_id) { |
+ return; |
} |
- return it->second == DecodePolicy::ASYNC; |
+ // Choose the max scale and filter quality. This keeps the memory usage to the |
+ // minimum possible while still increasing the possibility of getting a cache |
+ // hit. |
+ decode_state->scale = SkSize::Make( |
+ std::max(decode_state->scale.fWidth, draw_image.scale().fWidth), |
+ std::max(decode_state->scale.fHeight, draw_image.scale().fHeight)); |
+ decode_state->filter_quality = |
+ std::max(decode_state->filter_quality, draw_image.filter_quality()); |
+ decode_state->color_space = draw_image.target_color_space(); |
} |
void CheckerImageTracker::ScheduleNextImageDecode() { |
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
"CheckerImageTracker::ScheduleNextImageDecode"); |
- // We can have only one outsanding decode pending completion with the decode |
+ // We can have only one outstanding decode pending completion with the decode |
// service. We'll come back here when it is completed. |
if (outstanding_image_decode_.has_value()) |
return; |
+ DrawImage draw_image; |
while (!image_decode_queue_.empty()) { |
auto candidate = std::move(image_decode_queue_.front()); |
image_decode_queue_.erase(image_decode_queue_.begin()); |
@@ -191,9 +247,14 @@ void CheckerImageTracker::ScheduleNextImageDecode() { |
PaintImage::Id image_id = candidate.stable_id(); |
auto it = image_async_decode_state_.find(image_id); |
DCHECK(it != image_async_decode_state_.end()); |
- if (it->second != DecodePolicy::ASYNC) |
+ if (it->second.policy != DecodePolicy::ASYNC) |
continue; |
+ draw_image = DrawImage(candidate, candidate.sk_image()->bounds(), |
+ it->second.filter_quality, |
+ SkMatrix::MakeScale(it->second.scale.width(), |
+ it->second.scale.height()), |
+ it->second.color_space); |
outstanding_image_decode_.emplace(candidate); |
break; |
} |
@@ -211,9 +272,8 @@ void CheckerImageTracker::ScheduleNextImageDecode() { |
image_id); |
ImageController::ImageDecodeRequestId request_id = |
image_controller_->QueueImageDecode( |
- outstanding_image_decode_.value().sk_image(), |
- base::Bind(&CheckerImageTracker::DidFinishImageDecode, |
- weak_factory_.GetWeakPtr(), image_id)); |
+ draw_image, base::Bind(&CheckerImageTracker::DidFinishImageDecode, |
+ weak_factory_.GetWeakPtr(), image_id)); |
image_id_to_decode_.emplace(image_id, base::MakeUnique<ScopedDecodeHolder>( |
image_controller_, request_id)); |