| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/software_image_decode_controller.h" | 5 #include "cc/tiles/software_image_decode_controller.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <functional> | 9 #include <functional> |
| 10 | 10 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 const size_t kMaxHighQualityImageSizeBytes = 64 * 1024 * 1024; | 29 const size_t kMaxHighQualityImageSizeBytes = 64 * 1024 * 1024; |
| 30 | 30 |
| 31 // The number of entries to keep around in the cache. This limit can be breached | 31 // The number of entries to keep around in the cache. This limit can be breached |
| 32 // if more items are locked. That is, locked items ignore this limit. | 32 // if more items are locked. That is, locked items ignore this limit. |
| 33 const size_t kMaxItemsInCache = 1000; | 33 const size_t kMaxItemsInCache = 1000; |
| 34 | 34 |
| 35 class AutoRemoveKeyFromTaskMap { | 35 class AutoRemoveKeyFromTaskMap { |
| 36 public: | 36 public: |
| 37 AutoRemoveKeyFromTaskMap( | 37 AutoRemoveKeyFromTaskMap( |
| 38 std::unordered_map<SoftwareImageDecodeController::ImageKey, | 38 std::unordered_map<SoftwareImageDecodeController::ImageKey, |
| 39 scoped_refptr<ImageDecodeTask>, | 39 scoped_refptr<Task>, |
| 40 SoftwareImageDecodeController::ImageKeyHash>* task_map, | 40 SoftwareImageDecodeController::ImageKeyHash>* task_map, |
| 41 const SoftwareImageDecodeController::ImageKey& key) | 41 const SoftwareImageDecodeController::ImageKey& key) |
| 42 : task_map_(task_map), key_(key) {} | 42 : task_map_(task_map), key_(key) {} |
| 43 ~AutoRemoveKeyFromTaskMap() { task_map_->erase(key_); } | 43 ~AutoRemoveKeyFromTaskMap() { task_map_->erase(key_); } |
| 44 | 44 |
| 45 private: | 45 private: |
| 46 std::unordered_map<SoftwareImageDecodeController::ImageKey, | 46 std::unordered_map<SoftwareImageDecodeController::ImageKey, |
| 47 scoped_refptr<ImageDecodeTask>, | 47 scoped_refptr<Task>, |
| 48 SoftwareImageDecodeController::ImageKeyHash>* task_map_; | 48 SoftwareImageDecodeController::ImageKeyHash>* task_map_; |
| 49 SoftwareImageDecodeController::ImageKey key_; | 49 SoftwareImageDecodeController::ImageKey key_; |
| 50 }; | 50 }; |
| 51 | 51 |
| 52 class ImageDecodeTaskImpl : public ImageDecodeTask { | 52 class ImageDecodeTaskImpl : public Task { |
| 53 public: | 53 public: |
| 54 ImageDecodeTaskImpl(SoftwareImageDecodeController* controller, | 54 ImageDecodeTaskImpl(SoftwareImageDecodeController* controller, |
| 55 const SoftwareImageDecodeController::ImageKey& image_key, | 55 const SoftwareImageDecodeController::ImageKey& image_key, |
| 56 const DrawImage& image, | 56 const DrawImage& image, |
| 57 uint64_t source_prepare_tiles_id) | 57 uint64_t source_prepare_tiles_id) |
| 58 : controller_(controller), | 58 : controller_(controller), |
| 59 image_key_(image_key), | 59 image_key_(image_key), |
| 60 image_(image), | 60 image_(image), |
| 61 image_ref_(skia::SharePtr(image.image())), | 61 image_ref_(skia::SharePtr(image.image())), |
| 62 source_prepare_tiles_id_(source_prepare_tiles_id) {} | 62 source_prepare_tiles_id_(source_prepare_tiles_id) {} |
| 63 | 63 |
| 64 // Overridden from Task: | 64 // Overridden from Task: |
| 65 void ScheduleOnOriginThread() override {} |
| 66 void CompleteOnOriginThread() override { |
| 67 controller_->RemovePendingTask(image_key_); |
| 68 } |
| 65 void RunOnWorkerThread() override { | 69 void RunOnWorkerThread() override { |
| 66 TRACE_EVENT2("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", "mode", | 70 TRACE_EVENT2("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", "mode", |
| 67 "software", "source_prepare_tiles_id", | 71 "software", "source_prepare_tiles_id", |
| 68 source_prepare_tiles_id_); | 72 source_prepare_tiles_id_); |
| 69 devtools_instrumentation::ScopedImageDecodeTask image_decode_task( | 73 devtools_instrumentation::ScopedImageDecodeTask image_decode_task( |
| 70 image_ref_.get()); | 74 image_ref_.get()); |
| 71 controller_->DecodeImage(image_key_, image_); | 75 controller_->DecodeImage(image_key_, image_); |
| 72 } | 76 } |
| 73 | 77 |
| 74 // Overridden from TileTask: | |
| 75 void ScheduleOnOriginThread(TileTaskClient* client) override {} | |
| 76 void CompleteOnOriginThread(TileTaskClient* client) override { | |
| 77 controller_->RemovePendingTask(image_key_); | |
| 78 } | |
| 79 | |
| 80 protected: | 78 protected: |
| 81 ~ImageDecodeTaskImpl() override {} | 79 ~ImageDecodeTaskImpl() override {} |
| 82 | 80 |
| 83 private: | 81 private: |
| 84 SoftwareImageDecodeController* controller_; | 82 SoftwareImageDecodeController* controller_; |
| 85 SoftwareImageDecodeController::ImageKey image_key_; | 83 SoftwareImageDecodeController::ImageKey image_key_; |
| 86 DrawImage image_; | 84 DrawImage image_; |
| 87 skia::RefPtr<const SkImage> image_ref_; | 85 skia::RefPtr<const SkImage> image_ref_; |
| 88 uint64_t source_prepare_tiles_id_; | 86 uint64_t source_prepare_tiles_id_; |
| 89 | 87 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 : SoftwareImageDecodeController(RGBA_8888) {} | 148 : SoftwareImageDecodeController(RGBA_8888) {} |
| 151 | 149 |
| 152 SoftwareImageDecodeController::~SoftwareImageDecodeController() { | 150 SoftwareImageDecodeController::~SoftwareImageDecodeController() { |
| 153 DCHECK_EQ(0u, decoded_images_ref_counts_.size()); | 151 DCHECK_EQ(0u, decoded_images_ref_counts_.size()); |
| 154 DCHECK_EQ(0u, at_raster_decoded_images_ref_counts_.size()); | 152 DCHECK_EQ(0u, at_raster_decoded_images_ref_counts_.size()); |
| 155 } | 153 } |
| 156 | 154 |
| 157 bool SoftwareImageDecodeController::GetTaskForImageAndRef( | 155 bool SoftwareImageDecodeController::GetTaskForImageAndRef( |
| 158 const DrawImage& image, | 156 const DrawImage& image, |
| 159 uint64_t prepare_tiles_id, | 157 uint64_t prepare_tiles_id, |
| 160 scoped_refptr<ImageDecodeTask>* task) { | 158 scoped_refptr<Task>* task) { |
| 161 // If the image already exists or if we're going to create a task for it, then | 159 // If the image already exists or if we're going to create a task for it, then |
| 162 // we'll likely need to ref this image (the exception is if we're prerolling | 160 // we'll likely need to ref this image (the exception is if we're prerolling |
| 163 // the image only). That means the image is or will be in the cache. When the | 161 // the image only). That means the image is or will be in the cache. When the |
| 164 // ref goes to 0, it will be unpinned but will remain in the cache. If the | 162 // ref goes to 0, it will be unpinned but will remain in the cache. If the |
| 165 // image does not fit into the budget, then we don't ref this image, since it | 163 // image does not fit into the budget, then we don't ref this image, since it |
| 166 // will be decoded at raster time which is when it will be temporarily put in | 164 // will be decoded at raster time which is when it will be temporarily put in |
| 167 // the cache. | 165 // the cache. |
| 168 ImageKey key = ImageKey::FromDrawImage(image); | 166 ImageKey key = ImageKey::FromDrawImage(image); |
| 169 TRACE_EVENT1("disabled-by-default-cc.debug", | 167 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 170 "SoftwareImageDecodeController::GetTaskForImageAndRef", "key", | 168 "SoftwareImageDecodeController::GetTaskForImageAndRef", "key", |
| 171 key.ToString()); | 169 key.ToString()); |
| 172 | 170 |
| 173 // If the target size is empty, we can skip this image during draw (and thus | 171 // If the target size is empty, we can skip this image during draw (and thus |
| 174 // we don't need to decode it or ref it). | 172 // we don't need to decode it or ref it). |
| 175 if (key.target_size().IsEmpty()) { | 173 if (key.target_size().IsEmpty()) { |
| 176 *task = nullptr; | 174 *task = nullptr; |
| 177 return false; | 175 return false; |
| 178 } | 176 } |
| 179 | 177 |
| 180 // If we're not going to do a scale, we will just create a task to preroll the | 178 // If we're not going to do a scale, we will just create a task to preroll the |
| 181 // image the first time we see it. This doesn't need to account for memory. | 179 // image the first time we see it. This doesn't need to account for memory. |
| 182 // TODO(vmpstr): We can also lock the original sized image, in which case it | 180 // TODO(vmpstr): We can also lock the original sized image, in which case it |
| 183 // does require memory bookkeeping. | 181 // does require memory bookkeeping. |
| 184 if (!CanHandleImage(key)) { | 182 if (!CanHandleImage(key)) { |
| 185 base::AutoLock lock(lock_); | 183 base::AutoLock lock(lock_); |
| 186 if (prerolled_images_.count(key.image_id()) == 0) { | 184 if (prerolled_images_.count(key.image_id()) == 0) { |
| 187 scoped_refptr<ImageDecodeTask>& existing_task = pending_image_tasks_[key]; | 185 scoped_refptr<Task>& existing_task = pending_image_tasks_[key]; |
| 188 if (!existing_task) { | 186 if (!existing_task) { |
| 189 existing_task = make_scoped_refptr( | 187 existing_task = make_scoped_refptr( |
| 190 new ImageDecodeTaskImpl(this, key, image, prepare_tiles_id)); | 188 new ImageDecodeTaskImpl(this, key, image, prepare_tiles_id)); |
| 191 } | 189 } |
| 192 *task = existing_task; | 190 *task = existing_task; |
| 193 } else { | 191 } else { |
| 194 *task = nullptr; | 192 *task = nullptr; |
| 195 } | 193 } |
| 196 return false; | 194 return false; |
| 197 } | 195 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 210 SanityCheckState(__LINE__, true); | 208 SanityCheckState(__LINE__, true); |
| 211 return true; | 209 return true; |
| 212 } | 210 } |
| 213 // If the image fits in memory, then we at least tried to lock it and | 211 // If the image fits in memory, then we at least tried to lock it and |
| 214 // failed. This means that it's not valid anymore. | 212 // failed. This means that it's not valid anymore. |
| 215 if (new_image_fits_in_memory) | 213 if (new_image_fits_in_memory) |
| 216 decoded_images_.Erase(decoded_it); | 214 decoded_images_.Erase(decoded_it); |
| 217 } | 215 } |
| 218 | 216 |
| 219 // If the task exists, return it. | 217 // If the task exists, return it. |
| 220 scoped_refptr<ImageDecodeTask>& existing_task = pending_image_tasks_[key]; | 218 scoped_refptr<Task>& existing_task = pending_image_tasks_[key]; |
| 221 if (existing_task) { | 219 if (existing_task) { |
| 222 RefImage(key); | 220 RefImage(key); |
| 223 *task = existing_task; | 221 *task = existing_task; |
| 224 SanityCheckState(__LINE__, true); | 222 SanityCheckState(__LINE__, true); |
| 225 return true; | 223 return true; |
| 226 } | 224 } |
| 227 | 225 |
| 228 // At this point, we have to create a new image/task, so we need to abort if | 226 // At this point, we have to create a new image/task, so we need to abort if |
| 229 // it doesn't fit into memory and there are currently no raster tasks that | 227 // it doesn't fit into memory and there are currently no raster tasks that |
| 230 // would have already accounted for memory. The latter part is possible if | 228 // would have already accounted for memory. The latter part is possible if |
| (...skipping 659 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 890 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { | 888 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { |
| 891 current_usage_bytes_ = 0; | 889 current_usage_bytes_ = 0; |
| 892 } | 890 } |
| 893 | 891 |
| 894 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() | 892 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() |
| 895 const { | 893 const { |
| 896 return current_usage_bytes_.ValueOrDie(); | 894 return current_usage_bytes_.ValueOrDie(); |
| 897 } | 895 } |
| 898 | 896 |
| 899 } // namespace cc | 897 } // namespace cc |
| OLD | NEW |