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

gpu / command_buffer / service / service_transfer_cache.h [blame]

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef GPU_COMMAND_BUFFER_SERVICE_SERVICE_TRANSFER_CACHE_H_
#define GPU_COMMAND_BUFFER_SERVICE_SERVICE_TRANSFER_CACHE_H_

#include <stddef.h>
#include <stdint.h>

#include <memory>
#include <vector>

#include "base/containers/lru_cache.h"
#include "base/containers/span.h"
#include "base/functional/callback.h"
#include "base/functional/function_ref.h"
#include "base/gtest_prod_util.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/trace_event/memory_dump_provider.h"
#include "cc/paint/image_transfer_cache_entry.h"
#include "cc/paint/transfer_cache_entry.h"
#include "gpu/command_buffer/common/discardable_handle.h"
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/gpu_gles2_export.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkYUVAInfo.h"

class GrDirectContext;
class SkImage;

namespace gpu {

// ServiceTransferCache is a GPU process interface for retrieving cached entries
// from the transfer cache. These entries are populated by client calls to the
// ClientTransferCache or by an image decode accelerator task in the GPU
// process.
//
// In addition to access, the ServiceTransferCache is also responsible for
// unlocking and deleting entries when no longer needed, as well as enforcing
// cache limits. If the cache exceeds its specified limits, unlocked transfer
// cache entries may be deleted.
class GPU_GLES2_EXPORT ServiceTransferCache
    : public base::trace_event::MemoryDumpProvider {
 public:
  struct GPU_GLES2_EXPORT EntryKey {
    EntryKey(int decoder_id,
             cc::TransferCacheEntryType entry_type,
             uint32_t entry_id);
    int decoder_id;
    cc::TransferCacheEntryType entry_type;
    uint32_t entry_id;
  };

  ServiceTransferCache(const GpuPreferences& preferences,
                       base::RepeatingClosure flush_callback);

  ServiceTransferCache(const ServiceTransferCache&) = delete;
  ServiceTransferCache& operator=(const ServiceTransferCache&) = delete;

  ~ServiceTransferCache() override;

  bool CreateLockedEntry(const EntryKey& key,
                         ServiceDiscardableHandle handle,
                         GrDirectContext* context,
                         skgpu::graphite::Recorder* graphite_recorder,
                         base::span<uint8_t> data);
  void CreateLocalEntry(const EntryKey& key,
                        std::unique_ptr<cc::ServiceTransferCacheEntry> entry);
  bool UnlockEntry(const EntryKey& key);
  bool DeleteEntry(const EntryKey& key);
  cc::ServiceTransferCacheEntry* GetEntry(const EntryKey& key);
  void DeleteAllEntriesForDecoder(int decoder_id);

  // Creates an image transfer cache entry using |plane_images| (refer to
  // ServiceImageTransferCacheEntry::BuildFromHardwareDecodedImage() for
  // details). |decoder_id| and |entry_id| are used for creating the
  // ServiceTransferCache::EntryKey (assuming cc::TransferCacheEntryType:kImage
  // for the type). Returns true if the entry could be created and inserted;
  // false otherwise.
  bool CreateLockedHardwareDecodedImageEntry(
      int decoder_id,
      uint32_t entry_id,
      ServiceDiscardableHandle handle,
      GrDirectContext* context,
      std::vector<sk_sp<SkImage>> plane_images,
      SkYUVAInfo::PlaneConfig plane_config,
      SkYUVAInfo::Subsampling subsampling,
      SkYUVColorSpace yuv_color_space,
      size_t buffer_byte_size,
      bool needs_mips);

  void PurgeMemory(
      base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);

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

  // Test-only functions:
  void SetCacheSizeLimitForTesting(size_t cache_size_limit) {
    cache_size_limit_ = cache_size_limit;
    EnforceLimits();
  }
  void SetMaxCacheEntriesForTesting(size_t max_cache_entries) {
    max_cache_entries_ = max_cache_entries;
    EnforceLimits();
  }
  size_t cache_size_for_testing() const { return total_size_; }
  size_t entries_count_for_testing() const { return entries_.size(); }

 private:
  FRIEND_TEST_ALL_PREFIXES(ServiceTransferCacheTest, PurgeEntryOnTimer);

  struct CacheEntryInternal {
    CacheEntryInternal(std::optional<ServiceDiscardableHandle> handle,
                       std::unique_ptr<cc::ServiceTransferCacheEntry> entry);
    CacheEntryInternal(CacheEntryInternal&& other);
    CacheEntryInternal& operator=(CacheEntryInternal&& other);
    ~CacheEntryInternal();
    std::optional<ServiceDiscardableHandle> handle;
    std::unique_ptr<cc::ServiceTransferCacheEntry> entry;
    base::TimeTicks last_use = base::TimeTicks::Now();

    // For metrics.
    uint32_t num_reuse = 0u;
    base::TimeDelta max_last_use_delta;
  };

  struct EntryKeyComp {
    bool operator()(const EntryKey& lhs, const EntryKey& rhs) const {
      if (lhs.decoder_id != rhs.decoder_id)
        return lhs.decoder_id < rhs.decoder_id;
      if (lhs.entry_type != rhs.entry_type)
        return lhs.entry_type < rhs.entry_type;
      return lhs.entry_id < rhs.entry_id;
    }
  };

  using EntryCache = base::LRUCache<EntryKey, CacheEntryInternal, EntryKeyComp>;

  void EnforceLimits();
  void MaybePostPruneOldEntries();
  void PruneOldEntries();
  // Helper to iterate through entries from least recently used to most
  // recently used and erase them until `should_stop` returns true. Returns
  // number of entries removed.
  int RemoveOldEntriesUntil(
      base::FunctionRef<bool(EntryCache::reverse_iterator)> should_stop);

  template <typename Iterator>
  Iterator ForceDeleteEntry(Iterator it);

  const base::RepeatingClosure flush_callback_;

  EntryCache entries_;

  // Total size of all |entries_|. The same as summing
  // GpuDiscardableEntry::size for each entry.
  size_t total_size_ = 0;
  // Total size of all |entries_| of TransferCacheEntryType::kImage.
  size_t total_image_size_ = 0;
  // Number of |entries_| of TransferCacheEntryType::kImage.
  int total_image_count_ = 0;

  // The limit above which the cache will start evicting resources.
  size_t cache_size_limit_;

  // The max number of entries we will hold in the cache.
  size_t max_cache_entries_;

  bool request_post_prune_old_entries_while_pending_ = false;
  base::OneShotTimer prune_old_entries_timer_;
};

}  // namespace gpu

#endif  // GPU_COMMAND_BUFFER_SERVICE_SERVICE_TRANSFER_CACHE_H_