| 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 |
| 11 #include "base/format_macros.h" | 11 #include "base/format_macros.h" |
| 12 #include "base/macros.h" | 12 #include "base/macros.h" |
| 13 #include "base/memory/discardable_memory.h" | 13 #include "base/memory/discardable_memory.h" |
| 14 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 16 #include "base/thread_task_runner_handle.h" | 16 #include "base/thread_task_runner_handle.h" |
| 17 #include "base/trace_event/memory_dump_manager.h" | 17 #include "base/trace_event/memory_dump_manager.h" |
| 18 #include "cc/debug/devtools_instrumentation.h" | 18 #include "cc/debug/devtools_instrumentation.h" |
| 19 #include "cc/raster/tile_task_runner.h" | |
| 20 #include "third_party/skia/include/core/SkCanvas.h" | 19 #include "third_party/skia/include/core/SkCanvas.h" |
| 21 #include "third_party/skia/include/core/SkImage.h" | 20 #include "third_party/skia/include/core/SkImage.h" |
| 22 #include "ui/gfx/skia_util.h" | 21 #include "ui/gfx/skia_util.h" |
| 23 | 22 |
| 24 namespace cc { | 23 namespace cc { |
| 25 namespace { | 24 namespace { |
| 26 | 25 |
| 27 // The amount of memory we can lock ahead of time (128MB). This limit is only | 26 // The amount of memory we can lock ahead of time (128MB). This limit is only |
| 28 // used to inform the caller of the amount of space available in the cache. The | 27 // used to inform the caller of the amount of space available in the cache. The |
| 29 // caller can still request tasks which can cause this limit to be breached. | 28 // caller can still request tasks which can cause this limit to be breached. |
| 30 const size_t kLockedMemoryLimitBytes = 128 * 1024 * 1024; | 29 const size_t kLockedMemoryLimitBytes = 128 * 1024 * 1024; |
| 31 | 30 |
| 32 // The largest single high quality image to try and process. Images above this | 31 // The largest single high quality image to try and process. Images above this |
| 33 // size will drop down to medium quality. | 32 // size will drop down to medium quality. |
| 34 const size_t kMaxHighQualityImageSizeBytes = 64 * 1024 * 1024; | 33 const size_t kMaxHighQualityImageSizeBytes = 64 * 1024 * 1024; |
| 35 | 34 |
| 36 // The number of entries to keep around in the cache. This limit can be breached | 35 // The number of entries to keep around in the cache. This limit can be breached |
| 37 // if more items are locked. That is, locked items ignore this limit. | 36 // if more items are locked. That is, locked items ignore this limit. |
| 38 const size_t kMaxItemsInCache = 1000; | 37 const size_t kMaxItemsInCache = 1000; |
| 39 | 38 |
| 40 class AutoRemoveKeyFromTaskMap { | 39 class AutoRemoveKeyFromTaskMap { |
| 41 public: | 40 public: |
| 42 AutoRemoveKeyFromTaskMap( | 41 AutoRemoveKeyFromTaskMap( |
| 43 std::unordered_map<SoftwareImageDecodeController::ImageKey, | 42 std::unordered_map<SoftwareImageDecodeController::ImageKey, |
| 44 scoped_refptr<ImageDecodeTask>, | 43 scoped_refptr<Task>, |
| 45 SoftwareImageDecodeController::ImageKeyHash>* task_map, | 44 SoftwareImageDecodeController::ImageKeyHash>* task_map, |
| 46 const SoftwareImageDecodeController::ImageKey& key) | 45 const SoftwareImageDecodeController::ImageKey& key) |
| 47 : task_map_(task_map), key_(key) {} | 46 : task_map_(task_map), key_(key) {} |
| 48 ~AutoRemoveKeyFromTaskMap() { task_map_->erase(key_); } | 47 ~AutoRemoveKeyFromTaskMap() { task_map_->erase(key_); } |
| 49 | 48 |
| 50 private: | 49 private: |
| 51 std::unordered_map<SoftwareImageDecodeController::ImageKey, | 50 std::unordered_map<SoftwareImageDecodeController::ImageKey, |
| 52 scoped_refptr<ImageDecodeTask>, | 51 scoped_refptr<Task>, |
| 53 SoftwareImageDecodeController::ImageKeyHash>* task_map_; | 52 SoftwareImageDecodeController::ImageKeyHash>* task_map_; |
| 54 SoftwareImageDecodeController::ImageKey key_; | 53 SoftwareImageDecodeController::ImageKey key_; |
| 55 }; | 54 }; |
| 56 | 55 |
| 57 class ImageDecodeTaskImpl : public ImageDecodeTask { | 56 class ImageDecodeTaskImpl : public Task { |
| 58 public: | 57 public: |
| 59 ImageDecodeTaskImpl(SoftwareImageDecodeController* controller, | 58 ImageDecodeTaskImpl(SoftwareImageDecodeController* controller, |
| 60 const SoftwareImageDecodeController::ImageKey& image_key, | 59 const SoftwareImageDecodeController::ImageKey& image_key, |
| 61 const DrawImage& image, | 60 const DrawImage& image, |
| 62 uint64_t source_prepare_tiles_id) | 61 uint64_t source_prepare_tiles_id) |
| 63 : controller_(controller), | 62 : controller_(controller), |
| 64 image_key_(image_key), | 63 image_key_(image_key), |
| 65 image_(image), | 64 image_(image), |
| 66 image_ref_(skia::SharePtr(image.image())), | 65 image_ref_(skia::SharePtr(image.image())), |
| 67 source_prepare_tiles_id_(source_prepare_tiles_id) { | 66 source_prepare_tiles_id_(source_prepare_tiles_id) { |
| 68 SetTaskTypeId(TASK_TYPE_IMAGE_DECODE); | 67 SetTaskType(TASK_TYPE_IMAGE_DECODE); |
| 69 } | 68 } |
| 70 | 69 |
| 71 // Overridden from Task: | 70 // Overridden from Task: |
| 72 void RunOnWorkerThread() override { | 71 void RunOnWorkerThread() override { |
| 73 TRACE_EVENT2("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", "mode", | 72 TRACE_EVENT2("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", "mode", |
| 74 "software", "source_prepare_tiles_id", | 73 "software", "source_prepare_tiles_id", |
| 75 source_prepare_tiles_id_); | 74 source_prepare_tiles_id_); |
| 76 devtools_instrumentation::ScopedImageDecodeTask image_decode_task( | 75 devtools_instrumentation::ScopedImageDecodeTask image_decode_task( |
| 77 image_ref_.get()); | 76 image_ref_.get()); |
| 78 controller_->DecodeImage(image_key_, image_); | 77 controller_->DecodeImage(image_key_, image_); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 DCHECK_EQ(0u, at_raster_decoded_images_ref_counts_.size()); | 141 DCHECK_EQ(0u, at_raster_decoded_images_ref_counts_.size()); |
| 143 | 142 |
| 144 // It is safe to unregister, even if we didn't register in the constructor. | 143 // It is safe to unregister, even if we didn't register in the constructor. |
| 145 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( | 144 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( |
| 146 this); | 145 this); |
| 147 } | 146 } |
| 148 | 147 |
| 149 bool SoftwareImageDecodeController::GetTaskForImageAndRef( | 148 bool SoftwareImageDecodeController::GetTaskForImageAndRef( |
| 150 const DrawImage& image, | 149 const DrawImage& image, |
| 151 uint64_t prepare_tiles_id, | 150 uint64_t prepare_tiles_id, |
| 152 scoped_refptr<ImageDecodeTask>* task) { | 151 scoped_refptr<Task>* task) { |
| 153 // If the image already exists or if we're going to create a task for it, then | 152 // If the image already exists or if we're going to create a task for it, then |
| 154 // we'll likely need to ref this image (the exception is if we're prerolling | 153 // we'll likely need to ref this image (the exception is if we're prerolling |
| 155 // the image only). That means the image is or will be in the cache. When the | 154 // the image only). That means the image is or will be in the cache. When the |
| 156 // ref goes to 0, it will be unpinned but will remain in the cache. If the | 155 // ref goes to 0, it will be unpinned but will remain in the cache. If the |
| 157 // image does not fit into the budget, then we don't ref this image, since it | 156 // image does not fit into the budget, then we don't ref this image, since it |
| 158 // will be decoded at raster time which is when it will be temporarily put in | 157 // will be decoded at raster time which is when it will be temporarily put in |
| 159 // the cache. | 158 // the cache. |
| 160 ImageKey key = ImageKey::FromDrawImage(image); | 159 ImageKey key = ImageKey::FromDrawImage(image); |
| 161 TRACE_EVENT1("disabled-by-default-cc.debug", | 160 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 162 "SoftwareImageDecodeController::GetTaskForImageAndRef", "key", | 161 "SoftwareImageDecodeController::GetTaskForImageAndRef", "key", |
| 163 key.ToString()); | 162 key.ToString()); |
| 164 | 163 |
| 165 // If the target size is empty, we can skip this image during draw (and thus | 164 // If the target size is empty, we can skip this image during draw (and thus |
| 166 // we don't need to decode it or ref it). | 165 // we don't need to decode it or ref it). |
| 167 if (key.target_size().IsEmpty()) { | 166 if (key.target_size().IsEmpty()) { |
| 168 *task = nullptr; | 167 *task = nullptr; |
| 169 return false; | 168 return false; |
| 170 } | 169 } |
| 171 | 170 |
| 172 // If we're not going to do a scale, we will just create a task to preroll the | 171 // If we're not going to do a scale, we will just create a task to preroll the |
| 173 // image the first time we see it. This doesn't need to account for memory. | 172 // image the first time we see it. This doesn't need to account for memory. |
| 174 // TODO(vmpstr): We can also lock the original sized image, in which case it | 173 // TODO(vmpstr): We can also lock the original sized image, in which case it |
| 175 // does require memory bookkeeping. | 174 // does require memory bookkeeping. |
| 176 if (!CanHandleImage(key)) { | 175 if (!CanHandleImage(key)) { |
| 177 base::AutoLock lock(lock_); | 176 base::AutoLock lock(lock_); |
| 178 if (prerolled_images_.count(key.image_id()) == 0) { | 177 if (prerolled_images_.count(key.image_id()) == 0) { |
| 179 scoped_refptr<ImageDecodeTask>& existing_task = pending_image_tasks_[key]; | 178 scoped_refptr<Task>& existing_task = pending_image_tasks_[key]; |
| 180 if (!existing_task) { | 179 if (!existing_task) { |
| 181 existing_task = make_scoped_refptr( | 180 existing_task = make_scoped_refptr( |
| 182 new ImageDecodeTaskImpl(this, key, image, prepare_tiles_id)); | 181 new ImageDecodeTaskImpl(this, key, image, prepare_tiles_id)); |
| 183 } | 182 } |
| 184 *task = existing_task; | 183 *task = existing_task; |
| 185 } else { | 184 } else { |
| 186 *task = nullptr; | 185 *task = nullptr; |
| 187 } | 186 } |
| 188 return false; | 187 return false; |
| 189 } | 188 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 202 SanityCheckState(__LINE__, true); | 201 SanityCheckState(__LINE__, true); |
| 203 return true; | 202 return true; |
| 204 } | 203 } |
| 205 // If the image fits in memory, then we at least tried to lock it and | 204 // If the image fits in memory, then we at least tried to lock it and |
| 206 // failed. This means that it's not valid anymore. | 205 // failed. This means that it's not valid anymore. |
| 207 if (new_image_fits_in_memory) | 206 if (new_image_fits_in_memory) |
| 208 decoded_images_.Erase(decoded_it); | 207 decoded_images_.Erase(decoded_it); |
| 209 } | 208 } |
| 210 | 209 |
| 211 // If the task exists, return it. | 210 // If the task exists, return it. |
| 212 scoped_refptr<ImageDecodeTask>& existing_task = pending_image_tasks_[key]; | 211 scoped_refptr<Task>& existing_task = pending_image_tasks_[key]; |
| 213 if (existing_task) { | 212 if (existing_task) { |
| 214 RefImage(key); | 213 RefImage(key); |
| 215 *task = existing_task; | 214 *task = existing_task; |
| 216 SanityCheckState(__LINE__, true); | 215 SanityCheckState(__LINE__, true); |
| 217 return true; | 216 return true; |
| 218 } | 217 } |
| 219 | 218 |
| 220 // At this point, we have to create a new image/task, so we need to abort if | 219 // At this point, we have to create a new image/task, so we need to abort if |
| 221 // it doesn't fit into memory and there are currently no raster tasks that | 220 // it doesn't fit into memory and there are currently no raster tasks that |
| 222 // would have already accounted for memory. The latter part is possible if | 221 // would have already accounted for memory. The latter part is possible if |
| (...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 929 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { | 928 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { |
| 930 current_usage_bytes_ = 0; | 929 current_usage_bytes_ = 0; |
| 931 } | 930 } |
| 932 | 931 |
| 933 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() | 932 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() |
| 934 const { | 933 const { |
| 935 return current_usage_bytes_.ValueOrDie(); | 934 return current_usage_bytes_.ValueOrDie(); |
| 936 } | 935 } |
| 937 | 936 |
| 938 } // namespace cc | 937 } // namespace cc |
| OLD | NEW |