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

cc / tiles / software_image_decode_cache.h [blame]

// Copyright 2016 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_H_
#define CC_TILES_SOFTWARE_IMAGE_DECODE_CACHE_H_

#include <stdint.h>

#include <memory>
#include <unordered_map>
#include <vector>

#include "base/containers/lru_cache.h"
#include "base/numerics/safe_math.h"
#include "base/thread_annotations.h"
#include "base/trace_event/memory_dump_provider.h"
#include "cc/cc_export.h"
#include "cc/paint/draw_image.h"
#include "cc/tiles/image_decode_cache.h"
#include "cc/tiles/software_image_decode_cache_utils.h"

namespace cc {

class CC_EXPORT SoftwareImageDecodeCache
    : public ImageDecodeCache,
      public base::trace_event::MemoryDumpProvider {
 public:
  using Utils = SoftwareImageDecodeCacheUtils;
  using CacheKey = Utils::CacheKey;
  using CacheKeyHash = Utils::CacheKeyHash;

  // Identifies whether a decode task performed decode work, or was fulfilled /
  // failed trivially.
  enum class TaskProcessingResult { kFullDecode, kLockOnly, kCancelled };

  SoftwareImageDecodeCache(SkColorType color_type,
                           size_t locked_memory_limit_bytes);
  ~SoftwareImageDecodeCache() override;

  // ImageDecodeCache overrides.
  // |client_id| is not used by the SoftwareImageDecodeCache for both of these
  // tasks.
  TaskResult GetTaskForImageAndRef(ClientId client_id,
                                   const DrawImage& image,
                                   const TracingInfo& tracing_info) override;
  TaskResult GetOutOfRasterDecodeTaskForImageAndRef(
      ClientId client_id,
      const DrawImage& image) override;
  void UnrefImage(const DrawImage& image) override;
  DecodedDrawImage GetDecodedImageForDraw(const DrawImage& image) override;
  void DrawWithImageFinished(const DrawImage& image,
                             const DecodedDrawImage& decoded_image) override;
  void ReduceCacheUsage() override;
  // Software doesn't keep outstanding images pinned, so this is a no-op.
  void SetShouldAggressivelyFreeResources(bool aggressively_free_resources,
                                          bool context_lock_acquired) override {
  }
  void ClearCache() override;
  size_t GetMaximumMemoryLimitBytes() const override;
  bool UseCacheForDrawImage(const DrawImage& image) const override;
  void RecordStats() override {}
  ClientId GenerateClientId() override;

  // Decode the given image and store it in the cache. This is only called by an
  // image decode task from a worker thread.
  TaskProcessingResult DecodeImageInTask(const CacheKey& key,
                                         const PaintImage& paint_image,
                                         TaskType task_type);

  void OnImageDecodeTaskCompleted(const CacheKey& key, TaskType task_type);

  // MemoryDumpProvider overrides.
  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                    base::trace_event::ProcessMemoryDump* pmd) override;

  size_t GetNumCacheEntriesForTesting();
  size_t GetMaxNumCacheEntriesForTesting();

 private:
  using CacheEntry = Utils::CacheEntry;

  // MemoryBudget is a convenience class for memory bookkeeping and ensuring
  // that we don't go over the limit when pre-decoding.
  class MemoryBudget {
   public:
    explicit MemoryBudget(size_t limit_bytes);

    size_t AvailableMemoryBytes() const;
    void AddUsage(size_t usage);
    void SubtractUsage(size_t usage);
    void ResetUsage();
    size_t total_limit_bytes() const { return limit_bytes_; }
    size_t GetCurrentUsageSafe() const;

   private:
    const size_t limit_bytes_;
    base::CheckedNumeric<size_t> current_usage_bytes_;
  };

  using ImageLRUCache = base::
      HashingLRUCache<CacheKey, std::unique_ptr<CacheEntry>, CacheKeyHash>;

  // Get the decoded draw image for the given key and paint_image. Note that
  // when used internally, we still require that DrawWithImageFinished() is
  // called afterwards.
  DecodedDrawImage GetDecodedImageForDrawInternal(const CacheKey& key,
                                                  const PaintImage& paint_image)
      EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // Removes unlocked decoded images until the number of decoded images is
  // reduced within the given limit.
  void ReduceCacheUsageUntilWithinLimit(size_t limit)
      EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // Helper method to get the different tasks. Note that this should be used as
  // if it was public (ie, all of the locks need to be properly acquired).
  TaskResult GetTaskForImageAndRefInternal(const DrawImage& image,
                                           const TracingInfo& tracing_info,
                                           TaskType type) LOCKS_EXCLUDED(lock_);

  CacheEntry* AddCacheEntry(const CacheKey& key)
      EXCLUSIVE_LOCKS_REQUIRED(lock_);

  TaskProcessingResult DecodeImageIfNecessary(const CacheKey& key,
                                              const PaintImage& paint_image,
                                              CacheEntry* cache_entry)
      EXCLUSIVE_LOCKS_REQUIRED(lock_);
  void AddBudgetForImage(const CacheKey& key, CacheEntry* entry)
      EXCLUSIVE_LOCKS_REQUIRED(lock_);
  void RemoveBudgetForImage(const CacheKey& key, CacheEntry* entry)
      EXCLUSIVE_LOCKS_REQUIRED(lock_);
  std::optional<CacheKey> FindCachedCandidate(const CacheKey& key)
      EXCLUSIVE_LOCKS_REQUIRED(lock_);

  void UnrefImage(const CacheKey& key) EXCLUSIVE_LOCKS_REQUIRED(lock_);

  SkColorType GetColorTypeForPaintImage(
      const TargetColorParams& target_color_params,
      const PaintImage& paint_image);

  base::Lock lock_;
  // Decoded images and ref counts (predecode path).
  ImageLRUCache decoded_images_ GUARDED_BY(lock_);

  // A map of PaintImage::FrameKey to the ImageKeys for cached decodes of this
  // PaintImage.
  std::unordered_map<PaintImage::FrameKey,
                     std::vector<CacheKey>,
                     PaintImage::FrameKeyHash>
      frame_key_to_image_keys_ GUARDED_BY(lock_);

  // Should be GUARDED_BY(lock_), except that accessing
  // |locked_images_budget_.total_limit_bytes()| is fine without the lock, as
  // it is const and thread safe.
  MemoryBudget locked_images_budget_;

  const SkColorType color_type_;
  const PaintImage::GeneratorClientId generator_client_id_;

  const size_t max_items_in_cache_;
};

}  // namespace cc

#endif  // CC_TILES_SOFTWARE_IMAGE_DECODE_CACHE_H_