blob: 42d7b0205ceef792948d289abedee7ef6c48aa9f [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#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/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/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
namespace cc {
class SoftwareImageDecodeCacheUtils {
// 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 {
// 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);
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. Note we don't
// compare |nearest_neighbor_| because we would only use kOriginal type in
// that case (dchecked below), which implies no scale. The returned scale
// to Skia would respect the nearest neighbor value of the requested
// image.
DCHECK(!is_nearest_neighbor_ || type_ == kOriginal);
return frame_key_ == other.frame_key_ && type_ == other.type_ &&
(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_; }
gfx::Rect src_rect() const { return src_rect_; }
gfx::Size target_size() const { return target_size_; }
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;
CacheKey(PaintImage::FrameKey frame_key,
PaintImage::Id stable_id,
ProcessingType type,
bool is_nearest_neighbor,
const gfx::Rect& src_rect,
const gfx::Size& size);
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_;
gfx::Rect src_rect_;
gfx::Size target_size_;
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 {
CacheEntry(const SkImageInfo& info,
std::unique_ptr<base::DiscardableMemory> memory,
const SkSize& src_rect_offset);
void MoveImageMemoryTo(CacheEntry* entry);
sk_sp<SkImage> image() const {
if (!memory)
return nullptr;
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;
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;
static std::unique_ptr<CacheEntry> DoDecodeImage(
const CacheKey& key,
const PaintImage& image,
SkColorType color_type,
sk_sp<SkColorSpace> color_space,
PaintImage::GeneratorClientId client_id);
static std::unique_ptr<CacheEntry> GenerateCacheEntryFromCandidate(
const CacheKey& key,
const DecodedDrawImage& candidate,
bool needs_extract_subset,
SkColorType color_type);
} // namespace cc