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

cc / paint / paint_cache.cc [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.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "cc/paint/paint_cache.h"

#include "base/check_op.h"
#include "base/containers/flat_set.h"
#include "base/not_fatal_until.h"
#include "base/notreached.h"
#include "base/synchronization/lock.h"

namespace cc {
namespace {

template <typename T>
void EraseFromMap(T* map, size_t n, const volatile PaintCacheId* ids) {
  for (size_t i = 0; i < n; ++i) {
    auto id = ids[i];
    map->erase(id);
  }
}

}  // namespace

constexpr size_t ClientPaintCache::kNoCachingBudget;

ClientPaintCache::ClientPaintCache(size_t max_budget_bytes)
    : cache_map_(CacheMap::NO_AUTO_EVICT), max_budget_(max_budget_bytes) {}
ClientPaintCache::~ClientPaintCache() = default;

bool ClientPaintCache::Get(PaintCacheDataType type, PaintCacheId id) {
  return cache_map_.Get(std::make_pair(type, id)) != cache_map_.end();
}

void ClientPaintCache::Put(PaintCacheDataType type,
                           PaintCacheId id,
                           size_t size) {
  if (max_budget_ == kNoCachingBudget)
    return;
  auto key = std::make_pair(type, id);
  DCHECK(cache_map_.Peek(key) == cache_map_.end());

  pending_entries_.push_back(key);
  cache_map_.Put(key, size);
  bytes_used_ += size;
}

template <typename Iterator>
void ClientPaintCache::EraseFromMap(Iterator it) {
  DCHECK_GE(bytes_used_, it->second);
  bytes_used_ -= it->second;
  cache_map_.Erase(it);
}

void ClientPaintCache::FinalizePendingEntries() {
  pending_entries_.clear();
}

void ClientPaintCache::AbortPendingEntries() {
  for (const auto& entry : pending_entries_) {
    auto it = cache_map_.Peek(entry);
    CHECK(it != cache_map_.end(), base::NotFatalUntil::M130);
    EraseFromMap(it);
  }
  pending_entries_.clear();
}

void ClientPaintCache::Purge(PurgedData* purged_data) {
  DCHECK(pending_entries_.empty());

  while (bytes_used_ > max_budget_) {
    auto it = cache_map_.rbegin();
    PaintCacheDataType type = it->first.first;
    PaintCacheId id = it->first.second;

    EraseFromMap(it);
    (*purged_data)[static_cast<uint32_t>(type)].push_back(id);
  }
}

bool ClientPaintCache::PurgeAll() {
  DCHECK(pending_entries_.empty());

  bool has_data = !cache_map_.empty();
  cache_map_.Clear();
  bytes_used_ = 0u;
  return has_data;
}

ServicePaintCache::ServicePaintCache() = default;
ServicePaintCache::~ServicePaintCache() = default;

void ServicePaintCache::PutPath(PaintCacheId id, SkPath path) {
  cached_paths_.emplace(id, std::move(path));
}

bool ServicePaintCache::GetPath(PaintCacheId id, SkPath* path) const {
  auto it = cached_paths_.find(id);
  if (it == cached_paths_.end())
    return false;
  *path = it->second;
  return true;
}

void ServicePaintCache::Purge(PaintCacheDataType type,
                              size_t n,
                              const volatile PaintCacheId* ids) {
  switch (type) {
    case PaintCacheDataType::kPath:
      EraseFromMap(&cached_paths_, n, ids);
      return;
  }

  NOTREACHED();
}

void ServicePaintCache::PurgeAll() {
  cached_paths_.clear();
}

}  // namespace cc