| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CC_TILES_SOFTWARE_IMAGE_DECODE_CACHE_UTILS_H_ |
| #define CC_TILES_SOFTWARE_IMAGE_DECODE_CACHE_UTILS_H_ |
| |
| #include <limits> |
| #include <memory> |
| #include <string> |
| |
| #include "base/functional/callback.h" |
| #include "base/memory/discardable_memory.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "cc/cc_export.h" |
| #include "cc/paint/decoded_draw_image.h" |
| #include "cc/paint/draw_image.h" |
| #include "cc/paint/paint_image.h" |
| #include "cc/paint/target_color_params.h" |
| #include "cc/raster/tile_task.h" |
| #include "cc/tiles/image_decode_cache_utils.h" |
| #include "third_party/skia/include/core/SkImage.h" |
| #include "third_party/skia/include/core/SkImageInfo.h" |
| #include "third_party/skia/include/core/SkSize.h" |
| #include "ui/gfx/color_space.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace cc { |
| |
| class SoftwareImageDecodeCacheUtils { |
| private: |
| // The following should only be accessed by the software image cache. |
| friend class SoftwareImageDecodeCache; |
| |
| // CacheKey is a class that gets a cache key out of a given draw |
| // image. That is, this key uniquely identifies an image in the cache. Note |
| // that it's insufficient to use SkImage's unique id, since the same image can |
| // appear in the cache multiple times at different scales and filter |
| // qualities. |
| class CC_EXPORT CacheKey { |
| public: |
| // Enum indicating the type of processing to do for this key: |
| // kOriginal - use the original decode without any subrecting or scaling. |
| // kSubrectOriginal - extract a subrect from the original decode but do not |
| // scale it. |
| // kSubrectAndScale - extract a subrect (if needed) from the original decode |
| // and scale it. |
| enum ProcessingType { kOriginal, kSubrectOriginal, kSubrectAndScale }; |
| |
| static CacheKey FromDrawImage(const DrawImage& image, |
| SkColorType color_type); |
| |
| CacheKey(const CacheKey& other); |
| CacheKey& operator=(const CacheKey& other); |
| |
| bool operator==(const CacheKey& other) const { |
| // The frame_key always has to be the same. However, after that all |
| // original decodes are the same, so if we can use the original decode, |
| // return true. If not, then we have to compare every field. |
| // |nearest_neighbor_| is not compared below since it is not used for |
| // scaled decodes and does not affect the contents of the cache entry |
| // (just passed to skia for the filtering to be done at raster time). |
| DCHECK(!is_nearest_neighbor_ || type_ != kSubrectAndScale); |
| return frame_key_ == other.frame_key_ && type_ == other.type_ && |
| target_color_params_ == other.target_color_params_ && |
| (type_ == kOriginal || (src_rect_ == other.src_rect_ && |
| target_size_ == other.target_size_)); |
| } |
| |
| bool operator!=(const CacheKey& other) const { return !(*this == other); } |
| |
| const PaintImage::FrameKey& frame_key() const { return frame_key_; } |
| PaintImage::Id stable_id() const { return stable_id_; } |
| ProcessingType type() const { return type_; } |
| bool is_nearest_neighbor() const { return is_nearest_neighbor_; } |
| bool may_be_lcp_candidate() const { return may_be_lcp_candidate_; } |
| gfx::Rect src_rect() const { return src_rect_; } |
| gfx::Size target_size() const { return target_size_; } |
| const TargetColorParams& target_color_params() const { |
| return target_color_params_; |
| } |
| |
| size_t get_hash() const { return hash_; } |
| |
| // Helper to figure out how much memory the locked image represented by this |
| // key would take. |
| size_t locked_bytes() const { |
| // TODO(vmpstr): Handle formats other than RGBA. |
| base::CheckedNumeric<size_t> result = 4; |
| result *= target_size_.width(); |
| result *= target_size_.height(); |
| return result.ValueOrDefault(std::numeric_limits<size_t>::max()); |
| } |
| |
| std::string ToString() const; |
| |
| private: |
| CacheKey(PaintImage::FrameKey frame_key, |
| PaintImage::Id stable_id, |
| ProcessingType type, |
| bool is_nearest_neighbor, |
| bool may_be_lcp_candidate, |
| const gfx::Rect& src_rect, |
| const gfx::Size& size, |
| const TargetColorParams& target_color_params); |
| |
| PaintImage::FrameKey frame_key_; |
| // The stable id is does not factor into the cache key's value for hashing |
| // and comparison (as it is redundant). It is only used to look up other |
| // cache entries of the same stable id. |
| PaintImage::Id stable_id_; |
| ProcessingType type_; |
| bool is_nearest_neighbor_; |
| bool may_be_lcp_candidate_; |
| gfx::Rect src_rect_; |
| gfx::Size target_size_; |
| TargetColorParams target_color_params_; |
| size_t hash_; |
| }; |
| |
| struct CacheKeyHash { |
| size_t operator()(const CacheKey& key) const { return key.get_hash(); } |
| }; |
| |
| // CacheEntry is a convenience storage for discardable memory. It can also |
| // construct an image out of SkImageInfo and stored discardable memory. |
| class CC_EXPORT CacheEntry { |
| public: |
| CacheEntry(); |
| CacheEntry(const SkImageInfo& info, |
| std::unique_ptr<base::DiscardableMemory> memory, |
| const SkSize& src_rect_offset); |
| ~CacheEntry(); |
| |
| void MoveImageMemoryTo(CacheEntry* entry); |
| |
| sk_sp<SkImage> image() const { |
| if (!memory) |
| return nullptr; |
| DCHECK(is_locked); |
| return image_; |
| } |
| const SkSize& src_rect_offset() const { return src_rect_offset_; } |
| |
| bool Lock(); |
| void Unlock(); |
| |
| // An ID which uniquely identifies this CacheEntry within the image decode |
| // cache. Used in memory tracing. |
| uint64_t tracing_id() const { return tracing_id_; } |
| // Mark this image as being used in either a draw or as a source for a |
| // scaled image. Either case represents this decode as being valuable and |
| // not wasted. |
| void mark_used() { usage_stats_.used = true; } |
| void mark_cached() { cached_ = true; } |
| void mark_out_of_raster() { usage_stats_.first_lock_out_of_raster = true; } |
| |
| // Since this is an inner class, we expose these variables publicly for |
| // simplicity. |
| // TODO(vmpstr): A good simple clean-up would be to rethink this class |
| // and its interactions to instead expose a few functions which would also |
| // facilitate easier DCHECKs. |
| int ref_count = 0; |
| bool decode_failed = false; |
| bool is_locked = false; |
| bool is_budgeted = false; |
| |
| scoped_refptr<TileTask> in_raster_task; |
| scoped_refptr<TileTask> out_of_raster_task; |
| |
| std::unique_ptr<base::DiscardableMemory> memory; |
| |
| private: |
| struct UsageStats { |
| // We can only create a decoded image in a locked state, so the initial |
| // lock count is 1. |
| int lock_count = 1; |
| bool used = false; |
| bool last_lock_failed = false; |
| bool first_lock_wasted = false; |
| bool first_lock_out_of_raster = false; |
| }; |
| |
| SkImageInfo image_info_; |
| sk_sp<SkImage> image_; |
| SkSize src_rect_offset_; |
| uint64_t tracing_id_; |
| UsageStats usage_stats_; |
| // Indicates whether this entry was ever in the cache. |
| bool cached_ = false; |
| }; |
| |
| // |on_no_memory| is called when memory allocation fails in this function, |
| // before retrying it once. As a consequence, this should free memory, and |
| // importantly, address space as well. |
| static std::unique_ptr<CacheEntry> DoDecodeImage( |
| const CacheKey& key, |
| const PaintImage& image, |
| SkColorType color_type, |
| PaintImage::GeneratorClientId client_id, |
| base::OnceClosure on_no_memory); |
| static std::unique_ptr<CacheEntry> GenerateCacheEntryFromCandidate( |
| const CacheKey& key, |
| const DecodedDrawImage& candidate, |
| bool needs_extract_subset, |
| SkColorType color_type); |
| }; |
| |
| } // namespace cc |
| |
| #endif // CC_TILES_SOFTWARE_IMAGE_DECODE_CACHE_UTILS_H_ |