| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef CC_TILES_SOFTWARE_IMAGE_DECODE_CONTROLLER_H_ | |
| 6 #define CC_TILES_SOFTWARE_IMAGE_DECODE_CONTROLLER_H_ | |
| 7 | |
| 8 #include <stdint.h> | |
| 9 | |
| 10 #include <memory> | |
| 11 #include <unordered_map> | |
| 12 #include <unordered_set> | |
| 13 | |
| 14 #include "base/atomic_sequence_num.h" | |
| 15 #include "base/containers/mru_cache.h" | |
| 16 #include "base/hash.h" | |
| 17 #include "base/memory/discardable_memory_allocator.h" | |
| 18 #include "base/memory/memory_coordinator_client.h" | |
| 19 #include "base/memory/ref_counted.h" | |
| 20 #include "base/numerics/safe_math.h" | |
| 21 #include "base/threading/thread_checker.h" | |
| 22 #include "base/trace_event/memory_dump_provider.h" | |
| 23 #include "cc/base/cc_export.h" | |
| 24 #include "cc/playback/decoded_draw_image.h" | |
| 25 #include "cc/playback/draw_image.h" | |
| 26 #include "cc/resources/resource_format.h" | |
| 27 #include "cc/tiles/image_decode_controller.h" | |
| 28 #include "third_party/skia/include/core/SkRefCnt.h" | |
| 29 #include "ui/gfx/geometry/rect.h" | |
| 30 | |
| 31 namespace cc { | |
| 32 | |
| 33 // ImageDecodeControllerKey is a class that gets a cache key out of a given draw | |
| 34 // image. That is, this key uniquely identifies an image in the cache. Note that | |
| 35 // it's insufficient to use SkImage's unique id, since the same image can appear | |
| 36 // in the cache multiple times at different scales and filter qualities. | |
| 37 class CC_EXPORT ImageDecodeControllerKey { | |
| 38 public: | |
| 39 static ImageDecodeControllerKey FromDrawImage(const DrawImage& image); | |
| 40 | |
| 41 ImageDecodeControllerKey(const ImageDecodeControllerKey& other); | |
| 42 | |
| 43 bool operator==(const ImageDecodeControllerKey& other) const { | |
| 44 // The image_id always has to be the same. However, after that all original | |
| 45 // decodes are the same, so if we can use the original decode, return true. | |
| 46 // If not, then we have to compare every field. | |
| 47 return image_id_ == other.image_id_ && | |
| 48 can_use_original_decode_ == other.can_use_original_decode_ && | |
| 49 (can_use_original_decode_ || | |
| 50 (src_rect_ == other.src_rect_ && | |
| 51 target_size_ == other.target_size_ && | |
| 52 filter_quality_ == other.filter_quality_)); | |
| 53 } | |
| 54 | |
| 55 bool operator!=(const ImageDecodeControllerKey& other) const { | |
| 56 return !(*this == other); | |
| 57 } | |
| 58 | |
| 59 uint32_t image_id() const { return image_id_; } | |
| 60 SkFilterQuality filter_quality() const { return filter_quality_; } | |
| 61 gfx::Rect src_rect() const { return src_rect_; } | |
| 62 gfx::Size target_size() const { return target_size_; } | |
| 63 | |
| 64 bool can_use_original_decode() const { return can_use_original_decode_; } | |
| 65 bool should_use_subrect() const { return should_use_subrect_; } | |
| 66 size_t get_hash() const { return hash_; } | |
| 67 | |
| 68 // Helper to figure out how much memory the locked image represented by this | |
| 69 // key would take. | |
| 70 size_t locked_bytes() const { | |
| 71 // TODO(vmpstr): Handle formats other than RGBA. | |
| 72 base::CheckedNumeric<size_t> result = 4; | |
| 73 result *= target_size_.width(); | |
| 74 result *= target_size_.height(); | |
| 75 return result.ValueOrDefault(std::numeric_limits<size_t>::max()); | |
| 76 } | |
| 77 | |
| 78 std::string ToString() const; | |
| 79 | |
| 80 private: | |
| 81 ImageDecodeControllerKey(uint32_t image_id, | |
| 82 const gfx::Rect& src_rect, | |
| 83 const gfx::Size& size, | |
| 84 SkFilterQuality filter_quality, | |
| 85 bool can_use_original_decode, | |
| 86 bool should_use_subrect); | |
| 87 | |
| 88 uint32_t image_id_; | |
| 89 gfx::Rect src_rect_; | |
| 90 gfx::Size target_size_; | |
| 91 SkFilterQuality filter_quality_; | |
| 92 bool can_use_original_decode_; | |
| 93 bool should_use_subrect_; | |
| 94 size_t hash_; | |
| 95 }; | |
| 96 | |
| 97 // Hash function for the above ImageDecodeControllerKey. | |
| 98 struct ImageDecodeControllerKeyHash { | |
| 99 size_t operator()(const ImageDecodeControllerKey& key) const { | |
| 100 return key.get_hash(); | |
| 101 } | |
| 102 }; | |
| 103 | |
| 104 class CC_EXPORT SoftwareImageDecodeController | |
| 105 : public ImageDecodeController, | |
| 106 public base::trace_event::MemoryDumpProvider, | |
| 107 public base::MemoryCoordinatorClient { | |
| 108 public: | |
| 109 using ImageKey = ImageDecodeControllerKey; | |
| 110 using ImageKeyHash = ImageDecodeControllerKeyHash; | |
| 111 | |
| 112 SoftwareImageDecodeController(ResourceFormat format, | |
| 113 size_t locked_memory_limit_bytes); | |
| 114 ~SoftwareImageDecodeController() override; | |
| 115 | |
| 116 // ImageDecodeController overrides. | |
| 117 bool GetTaskForImageAndRef(const DrawImage& image, | |
| 118 const TracingInfo& tracing_info, | |
| 119 scoped_refptr<TileTask>* task) override; | |
| 120 void UnrefImage(const DrawImage& image) override; | |
| 121 DecodedDrawImage GetDecodedImageForDraw(const DrawImage& image) override; | |
| 122 void DrawWithImageFinished(const DrawImage& image, | |
| 123 const DecodedDrawImage& decoded_image) override; | |
| 124 void ReduceCacheUsage() override; | |
| 125 // Software doesn't keep outstanding images pinned, so this is a no-op. | |
| 126 void SetShouldAggressivelyFreeResources( | |
| 127 bool aggressively_free_resources) override {} | |
| 128 | |
| 129 // Decode the given image and store it in the cache. This is only called by an | |
| 130 // image decode task from a worker thread. | |
| 131 void DecodeImage(const ImageKey& key, const DrawImage& image); | |
| 132 | |
| 133 void RemovePendingTask(const ImageKey& key); | |
| 134 | |
| 135 // MemoryDumpProvider overrides. | |
| 136 bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, | |
| 137 base::trace_event::ProcessMemoryDump* pmd) override; | |
| 138 | |
| 139 private: | |
| 140 // DecodedImage is a convenience storage for discardable memory. It can also | |
| 141 // construct an image out of SkImageInfo and stored discardable memory. | |
| 142 class DecodedImage { | |
| 143 public: | |
| 144 DecodedImage(const SkImageInfo& info, | |
| 145 std::unique_ptr<base::DiscardableMemory> memory, | |
| 146 const SkSize& src_rect_offset, | |
| 147 uint64_t tracing_id); | |
| 148 ~DecodedImage(); | |
| 149 | |
| 150 const sk_sp<SkImage>& image() const { | |
| 151 DCHECK(locked_); | |
| 152 return image_; | |
| 153 } | |
| 154 | |
| 155 const SkSize& src_rect_offset() const { return src_rect_offset_; } | |
| 156 | |
| 157 bool is_locked() const { return locked_; } | |
| 158 bool Lock(); | |
| 159 void Unlock(); | |
| 160 | |
| 161 const base::DiscardableMemory* memory() const { return memory_.get(); } | |
| 162 | |
| 163 // An ID which uniquely identifies this DecodedImage within the image decode | |
| 164 // controller. Used in memory tracing. | |
| 165 uint64_t tracing_id() const { return tracing_id_; } | |
| 166 // Mark this image as being used in either a draw or as a source for a | |
| 167 // scaled image. Either case represents this decode as being valuable and | |
| 168 // not wasted. | |
| 169 void mark_used() { usage_stats_.used = true; } | |
| 170 | |
| 171 private: | |
| 172 struct UsageStats { | |
| 173 // We can only create a decoded image in a locked state, so the initial | |
| 174 // lock count is 1. | |
| 175 int lock_count = 1; | |
| 176 bool used = false; | |
| 177 bool last_lock_failed = false; | |
| 178 bool first_lock_wasted = false; | |
| 179 }; | |
| 180 | |
| 181 bool locked_; | |
| 182 SkImageInfo image_info_; | |
| 183 std::unique_ptr<base::DiscardableMemory> memory_; | |
| 184 sk_sp<SkImage> image_; | |
| 185 SkSize src_rect_offset_; | |
| 186 uint64_t tracing_id_; | |
| 187 UsageStats usage_stats_; | |
| 188 }; | |
| 189 | |
| 190 // MemoryBudget is a convenience class for memory bookkeeping and ensuring | |
| 191 // that we don't go over the limit when pre-decoding. | |
| 192 class MemoryBudget { | |
| 193 public: | |
| 194 explicit MemoryBudget(size_t limit_bytes); | |
| 195 | |
| 196 size_t AvailableMemoryBytes() const; | |
| 197 void AddUsage(size_t usage); | |
| 198 void SubtractUsage(size_t usage); | |
| 199 void ResetUsage(); | |
| 200 size_t total_limit_bytes() const { return limit_bytes_; } | |
| 201 size_t GetCurrentUsageSafe() const; | |
| 202 | |
| 203 private: | |
| 204 size_t limit_bytes_; | |
| 205 base::CheckedNumeric<size_t> current_usage_bytes_; | |
| 206 }; | |
| 207 | |
| 208 using ImageMRUCache = base::HashingMRUCache<ImageKey, | |
| 209 std::unique_ptr<DecodedImage>, | |
| 210 ImageKeyHash>; | |
| 211 | |
| 212 // Looks for the key in the cache and returns true if it was found and was | |
| 213 // successfully locked (or if it was already locked). Note that if this | |
| 214 // function returns true, then a ref count is increased for the image. | |
| 215 bool LockDecodedImageIfPossibleAndRef(const ImageKey& key); | |
| 216 | |
| 217 // Actually decode the image. Note that this function can (and should) be | |
| 218 // called with no lock acquired, since it can do a lot of work. Note that it | |
| 219 // can also return nullptr to indicate the decode failed. | |
| 220 std::unique_ptr<DecodedImage> DecodeImageInternal( | |
| 221 const ImageKey& key, | |
| 222 const DrawImage& draw_image); | |
| 223 | |
| 224 // Get the decoded draw image for the given key and draw_image. Note that this | |
| 225 // function has to be called with no lock acquired, since it will acquire its | |
| 226 // own locks and might call DecodeImageInternal above. Also note that this | |
| 227 // function will use the provided key, even if | |
| 228 // ImageKey::FromDrawImage(draw_image) would return a different key. | |
| 229 // Note that when used internally, we still require that | |
| 230 // DrawWithImageFinished() is called afterwards. | |
| 231 DecodedDrawImage GetDecodedImageForDrawInternal(const ImageKey& key, | |
| 232 const DrawImage& draw_image); | |
| 233 | |
| 234 // GetOriginalImageDecode is called by DecodeImageInternal when the quality | |
| 235 // does not scale the image. Like DecodeImageInternal, it should be called | |
| 236 // with no lock acquired and it returns nullptr if the decoding failed. | |
| 237 std::unique_ptr<DecodedImage> GetOriginalImageDecode( | |
| 238 sk_sp<const SkImage> image); | |
| 239 | |
| 240 // GetSubrectImageDecode is similar to GetOriginalImageDecode in that no scale | |
| 241 // is performed on the image. However, we extract a subrect (copy it out) and | |
| 242 // only return this subrect in order to cache a smaller amount of memory. Note | |
| 243 // that this uses GetOriginalImageDecode to get the initial data, which | |
| 244 // ensures that we cache an unlocked version of the original image in case we | |
| 245 // need to extract multiple subrects (as would be the case in an atlas). | |
| 246 std::unique_ptr<DecodedImage> GetSubrectImageDecode( | |
| 247 const ImageKey& key, | |
| 248 sk_sp<const SkImage> image); | |
| 249 | |
| 250 // GetScaledImageDecode is called by DecodeImageInternal when the quality | |
| 251 // requires the image be scaled. Like DecodeImageInternal, it should be | |
| 252 // called with no lock acquired and it returns nullptr if the decoding or | |
| 253 // scaling failed. | |
| 254 std::unique_ptr<DecodedImage> GetScaledImageDecode( | |
| 255 const ImageKey& key, | |
| 256 sk_sp<const SkImage> image); | |
| 257 | |
| 258 void SanityCheckState(int line, bool lock_acquired); | |
| 259 void RefImage(const ImageKey& key); | |
| 260 void RefAtRasterImage(const ImageKey& key); | |
| 261 void UnrefAtRasterImage(const ImageKey& key); | |
| 262 | |
| 263 // Helper function which dumps all images in a specific ImageMRUCache. | |
| 264 void DumpImageMemoryForCache(const ImageMRUCache& cache, | |
| 265 const char* cache_name, | |
| 266 base::trace_event::ProcessMemoryDump* pmd) const; | |
| 267 | |
| 268 // Overriden from base::MemoryCoordinatorClient. | |
| 269 void OnMemoryStateChange(base::MemoryState state) override; | |
| 270 | |
| 271 std::unordered_map<ImageKey, scoped_refptr<TileTask>, ImageKeyHash> | |
| 272 pending_image_tasks_; | |
| 273 | |
| 274 // The members below this comment can only be accessed if the lock is held to | |
| 275 // ensure that they are safe to access on multiple threads. | |
| 276 base::Lock lock_; | |
| 277 | |
| 278 // Decoded images and ref counts (predecode path). | |
| 279 ImageMRUCache decoded_images_; | |
| 280 std::unordered_map<ImageKey, int, ImageKeyHash> decoded_images_ref_counts_; | |
| 281 | |
| 282 // Decoded image and ref counts (at-raster decode path). | |
| 283 ImageMRUCache at_raster_decoded_images_; | |
| 284 std::unordered_map<ImageKey, int, ImageKeyHash> | |
| 285 at_raster_decoded_images_ref_counts_; | |
| 286 | |
| 287 MemoryBudget locked_images_budget_; | |
| 288 | |
| 289 ResourceFormat format_; | |
| 290 size_t max_items_in_cache_; | |
| 291 | |
| 292 // Used to uniquely identify DecodedImages for memory traces. | |
| 293 base::AtomicSequenceNumber next_tracing_id_; | |
| 294 }; | |
| 295 | |
| 296 } // namespace cc | |
| 297 | |
| 298 #endif // CC_TILES_SOFTWARE_IMAGE_DECODE_CONTROLLER_H_ | |
| OLD | NEW |