1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212

cc / tiles / software_image_decode_cache_utils.h [blame]

// 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_