#ifndef CC_TILES_GPU_IMAGE_DECODE_CACHE_H_
#define CC_TILES_GPU_IMAGE_DECODE_CACHE_H_
#include <memory>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/containers/lru_cache.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/memory/discardable_memory.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/trace_event/memory_dump_provider.h"
#include "cc/cc_export.h"
#include "cc/paint/image_transfer_cache_entry.h"
#include "cc/tiles/image_decode_cache.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkYUVAInfo.h"
#include "third_party/skia/include/gpu/gl/GrGLTypes.h"
namespace viz {
class RasterContextProvider;
}
namespace cc {
CC_EXPORT BASE_DECLARE_FEATURE(kPurgeOldCacheEntriesOnTimer);
class RasterDarkModeFilter;
class CC_EXPORT GpuImageDecodeCache
: public ImageDecodeCache,
public base::trace_event::MemoryDumpProvider {
public:
enum class DecodeTaskType { kPartOfUploadTask, kStandAloneDecodeTask };
explicit GpuImageDecodeCache(viz::RasterContextProvider* context,
bool use_transfer_cache,
SkColorType color_type,
size_t max_working_set_bytes,
int max_texture_size,
RasterDarkModeFilter* const dark_mode_filter);
~GpuImageDecodeCache() override;
static GrGLuint GlIdFromSkImage(const SkImage* image);
static constexpr base::TimeDelta kPurgeInterval = base::Seconds(30);
static constexpr base::TimeDelta kPurgeMaxAge = base::Seconds(30);
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& draw_image) override;
void DrawWithImageFinished(const DrawImage& image,
const DecodedDrawImage& decoded_image) override;
void ReduceCacheUsage() override;
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;
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override;
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level);
void DecodeImageInTask(const DrawImage& image, TaskType task_type);
void UploadImageInTask(const DrawImage& image);
void OnImageDecodeTaskCompleted(const DrawImage& image,
DecodeTaskType task_type);
void OnImageUploadTaskCompleted(const DrawImage& image);
bool SupportsColorSpaceConversion() const;
void SetWorkingSetLimitsForTesting(size_t bytes_limit, size_t items_limit) {
base::AutoLock locker(lock_);
max_working_set_bytes_ = bytes_limit;
max_working_set_items_ = items_limit;
}
size_t GetWorkingSetBytesForTesting() const {
base::AutoLock locker(lock_);
return working_set_bytes_;
}
size_t GetNumCacheEntriesForTesting() const {
base::AutoLock locker(lock_);
return persistent_cache_.size();
}
size_t GetInUseCacheEntriesForTesting() const {
base::AutoLock locker(lock_);
return in_use_cache_.size();
}
size_t GetDrawImageSizeForTesting(const DrawImage& image);
void SetImageDecodingFailedForTesting(const DrawImage& image);
bool DiscardableIsLockedForTesting(const DrawImage& image);
bool IsInInUseCacheForTesting(const DrawImage& image) const;
bool IsInPersistentCacheForTesting(const DrawImage& image) const;
sk_sp<SkImage> GetSWImageDecodeForTesting(const DrawImage& image);
sk_sp<SkImage> GetUploadedPlaneForTesting(const DrawImage& draw_image,
YUVIndex index);
size_t GetDarkModeImageCacheSizeForTesting(const DrawImage& draw_image);
size_t paint_image_entries_count_for_testing() const {
base::AutoLock locker(lock_);
return paint_image_entries_.size();
}
bool NeedsDarkModeFilterForTesting(const DrawImage& draw_image);
bool HasPendingPurgeTaskForTesting() const {
base::AutoLock locker(lock_);
return has_pending_purge_task();
}
void SetTimerTaskRunnerForTesting(
scoped_refptr<base::SequencedTaskRunner> task_runner)
LOCKS_EXCLUDED(lock_) {
base::AutoLock locker(lock_);
timer_.SetTaskRunner(task_runner);
}
void TouchCacheEntryForTesting(const DrawImage& draw_image)
LOCKS_EXCLUDED(lock_);
private:
enum class DecodedDataMode { kGpu, kCpu, kTransferCache };
using ImageTaskMap = base::flat_map<ClientId, scoped_refptr<TileTask>>;
struct ImageDataBase {
ImageDataBase();
~ImageDataBase();
bool is_locked() const { return is_locked_; }
void OnSetLockedData(bool out_of_raster);
void OnResetData();
void OnLock();
void OnUnlock();
void mark_used() {
DCHECK(is_locked_);
usage_stats_.used = true;
}
uint32_t ref_count = 0;
ImageTaskMap task_map;
protected:
using YUVSkImages = std::array<sk_sp<SkImage>, kNumYUVPlanes>;
struct UsageStats {
int lock_count = 1;
bool used = false;
bool first_lock_out_of_raster = false;
bool first_lock_wasted = false;
};
int UsageState() const;
bool is_locked_ = false;
UsageStats usage_stats_;
};
struct DecodedAuxImageData {
DecodedAuxImageData();
DecodedAuxImageData(const SkPixmap& rgba_pixmap,
std::unique_ptr<base::DiscardableMemory> data);
DecodedAuxImageData(const SkYUVAPixmaps& yuva_pixmaps,
std::unique_ptr<base::DiscardableMemory> data);
DecodedAuxImageData(const DecodedAuxImageData&) = delete;
DecodedAuxImageData(DecodedAuxImageData&&);
DecodedAuxImageData& operator=(const DecodedAuxImageData&) = delete;
DecodedAuxImageData& operator=(DecodedAuxImageData&&);
~DecodedAuxImageData();
bool IsEmpty() const;
void ResetData();
void ValidateImagesMatchPixmaps() const {
for (int i = 0; i < SkYUVAInfo::kMaxPlanes; ++i) {
DCHECK_EQ(images[i] == nullptr, pixmaps[i].dimensions().isEmpty());
}
}
std::unique_ptr<base::DiscardableMemory> data;
sk_sp<SkImage> images[SkYUVAInfo::kMaxPlanes];
SkPixmap pixmaps[SkYUVAInfo::kMaxPlanes];
};
struct DecodedImageData : public ImageDataBase {
explicit DecodedImageData(bool is_bitmap_backed,
bool can_do_hardware_accelerated_decode,
bool do_hardware_accelerated_decode);
~DecodedImageData();
bool Lock();
void Unlock();
void SetLockedData(DecodedAuxImageData aux_image_data[kAuxImageCount],
bool out_of_raster);
void ResetData();
bool HasData() const {
for (const auto& aux_image_data : aux_image_data_) {
if (aux_image_data.data) {
return true;
}
}
return false;
}
base::DiscardableMemory* data(AuxImage aux_image) const {
return aux_image_data_[AuxImageIndex(aux_image)].data.get();
}
void SetBitmapImage(sk_sp<SkImage> image);
void ResetBitmapImage();
sk_sp<SkImage> image(int plane, AuxImage aux_image) const {
DCHECK_LT(plane, SkYUVAInfo::kMaxPlanes);
if (is_bitmap_backed_) {
DCHECK_EQ(aux_image, AuxImage::kDefault);
} else {
DCHECK(is_locked());
}
return aux_image_data_[AuxImageIndex(aux_image)].images[plane];
}
const SkPixmap* pixmaps(AuxImage aux_image) const {
DCHECK(is_locked() || is_bitmap_backed_);
return aux_image_data_[AuxImageIndex(aux_image)].pixmaps;
}
bool can_do_hardware_accelerated_decode() const {
return can_do_hardware_accelerated_decode_;
}
bool do_hardware_accelerated_decode() const {
return do_hardware_accelerated_decode_;
}
sk_sp<SkImage> ImageForTesting() const {
return aux_image_data_[kAuxImageIndexDefault].images[0];
}
bool decode_failure = false;
ImageTaskMap stand_alone_task_map;
struct SkIRectCompare {
bool operator()(const SkIRect& a, const SkIRect& b) const {
return a.fLeft < b.fLeft || a.fTop < b.fTop || a.fRight < b.fRight ||
a.fBottom < b.fBottom;
}
};
base::flat_map<SkIRect, sk_sp<SkColorFilter>, SkIRectCompare>
dark_mode_color_filter_cache;
private:
void ReportUsageStats() const;
const bool is_bitmap_backed_;
DecodedAuxImageData aux_image_data_[kAuxImageCount];
bool can_do_hardware_accelerated_decode_;
bool do_hardware_accelerated_decode_;
};
struct UploadedImageData : public ImageDataBase {
UploadedImageData();
~UploadedImageData();
void SetImage(sk_sp<SkImage> image, bool represents_yuv_image = false);
void SetYuvImage(sk_sp<SkImage> y_image_input,
sk_sp<SkImage> u_image_input,
sk_sp<SkImage> v_image_input);
void SetTransferCacheId(uint32_t id);
void Reset();
const sk_sp<SkImage>& image() const {
DCHECK(mode_ == Mode::kSkImage || mode_ == Mode::kNone);
return image_;
}
const sk_sp<SkImage>& y_image() const {
return plane_image_internal(YUVIndex::kY);
}
const sk_sp<SkImage>& u_image() const {
return plane_image_internal(YUVIndex::kU);
}
const sk_sp<SkImage>& v_image() const {
return plane_image_internal(YUVIndex::kV);
}
GrGLuint gl_id() const {
DCHECK(mode_ == Mode::kSkImage || mode_ == Mode::kNone);
return gl_id_;
}
GrGLuint gl_y_id() const { return gl_plane_id_internal(YUVIndex::kY); }
GrGLuint gl_u_id() const { return gl_plane_id_internal(YUVIndex::kU); }
GrGLuint gl_v_id() const { return gl_plane_id_internal(YUVIndex::kV); }
bool has_yuv_planes() const {
if (!image_yuv_planes_) {
return false;
}
auto yuv_planes_rstart = image_yuv_planes_->crbegin() + !is_alpha_;
auto yuv_planes_rend = image_yuv_planes_->crend();
bool has_existing_planes = std::any_of(yuv_planes_rstart, yuv_planes_rend,
[](auto& it) { return it; });
bool has_null_planes = std::any_of(yuv_planes_rstart, yuv_planes_rend,
[](auto& it) { return !it; });
if (has_existing_planes && has_null_planes) {
DLOG(ERROR) << "Image has a mix of null and decoded planes";
}
return has_existing_planes && !has_null_planes;
}
absl::optional<uint32_t> transfer_cache_id() const {
DCHECK(mode_ == Mode::kTransferCache || mode_ == Mode::kNone);
return transfer_cache_id_;
}
void set_unmipped_image(sk_sp<SkImage> image) {
unmipped_image_ = std::move(image);
}
sk_sp<SkImage> take_unmipped_image() {
DCHECK(!is_locked_);
return std::move(unmipped_image_);
}
void set_unmipped_yuv_images(sk_sp<SkImage> y_image,
sk_sp<SkImage> u_image,
sk_sp<SkImage> v_image) {
if (!unmipped_yuv_images_) {
unmipped_yuv_images_ = YUVSkImages();
}
unmipped_yuv_images_->at(static_cast<size_t>(YUVIndex::kY)) =
std::move(y_image);
unmipped_yuv_images_->at(static_cast<size_t>(YUVIndex::kU)) =
std::move(u_image);
unmipped_yuv_images_->at(static_cast<size_t>(YUVIndex::kV)) =
std::move(v_image);
}
sk_sp<SkImage> take_unmipped_y_image() {
return take_unmipped_yuv_image_internal(YUVIndex::kY);
}
sk_sp<SkImage> take_unmipped_u_image() {
return take_unmipped_yuv_image_internal(YUVIndex::kU);
}
sk_sp<SkImage> take_unmipped_v_image() {
return take_unmipped_yuv_image_internal(YUVIndex::kV);
}
sk_sp<SkImage> take_unmipped_yuv_image_internal(const YUVIndex yuv_index) {
DCHECK(!is_locked_);
const size_t index = static_cast<size_t>(yuv_index);
if (unmipped_yuv_images_ && unmipped_yuv_images_->size() > index) {
return std::move(unmipped_yuv_images_->at(index));
}
return nullptr;
}
private:
enum class Mode {
kNone,
kSkImage,
kTransferCache,
};
void ReportUsageStats() const;
const sk_sp<SkImage>& plane_image_internal(const YUVIndex yuv_index) const {
DCHECK(mode_ == Mode::kSkImage || mode_ == Mode::kNone);
DCHECK(image_yuv_planes_);
const size_t index = static_cast<size_t>(yuv_index);
DCHECK_GT(image_yuv_planes_->size(), index)
<< "Requested reference to a plane_id that is not set";
return image_yuv_planes_->at(index);
}
GrGLuint gl_plane_id_internal(const YUVIndex yuv_index) const {
DCHECK(mode_ == Mode::kSkImage || mode_ == Mode::kNone);
DCHECK(gl_plane_ids_);
const size_t index = static_cast<size_t>(yuv_index);
DCHECK_GT(gl_plane_ids_->size(), index)
<< "Requested GL id for a plane texture that is not uploaded";
return gl_plane_ids_->at(index);
}
Mode mode_ = Mode::kNone;
sk_sp<SkImage> image_;
absl::optional<YUVSkImages> image_yuv_planes_;
bool is_alpha_ = false;
GrGLuint gl_id_ = 0;
absl::optional<std::array<GrGLuint, kNumYUVPlanes>> gl_plane_ids_;
absl::optional<uint32_t> transfer_cache_id_;
sk_sp<SkImage> unmipped_image_;
absl::optional<YUVSkImages> unmipped_yuv_images_;
};
struct ImageInfo {
ImageInfo();
explicit ImageInfo(const SkImageInfo& rgba);
explicit ImageInfo(const SkYUVAPixmapInfo& yuva);
ImageInfo(const ImageInfo&);
ImageInfo& operator=(const ImageInfo&);
~ImageInfo();
absl::optional<SkImageInfo> rgba;
absl::optional<SkYUVAPixmapInfo> yuva;
size_t size = 0;
};
struct ImageData : public base::RefCountedThreadSafe<ImageData> {
ImageData(PaintImage::Id paint_image_id,
DecodedDataMode mode,
const TargetColorParams& target_color_params,
PaintFlags::FilterQuality quality,
int upload_scale_mip_level,
bool needs_mips,
bool is_bitmap_backed,
bool can_do_hardware_accelerated_decode,
bool do_hardware_accelerated_decode,
ImageInfo image_info[kAuxImageCount]);
bool IsGpuOrTransferCache() const;
bool HasUploadedData() const;
void ValidateBudgeted() const;
const ImageInfo& GetImageInfo(AuxImage aux_image) const {
switch (aux_image) {
case AuxImage::kDefault:
return info;
case AuxImage::kGainmap:
return gainmap_info;
}
}
size_t GetTotalSize() const;
const PaintImage::Id paint_image_id;
const DecodedDataMode mode;
TargetColorParams target_color_params;
PaintFlags::FilterQuality quality;
int upload_scale_mip_level;
bool needs_mips = false;
bool is_bitmap_backed;
bool is_budgeted = false;
base::TimeTicks last_use;
const ImageInfo info;
const ImageInfo gainmap_info;
bool is_orphaned = false;
DecodedImageData decode;
UploadedImageData upload;
private:
friend class base::RefCountedThreadSafe<ImageData>;
~ImageData();
};
struct InUseCacheEntry {
explicit InUseCacheEntry(scoped_refptr<ImageData> image_data);
InUseCacheEntry(const InUseCacheEntry& other);
InUseCacheEntry(InUseCacheEntry&& other);
~InUseCacheEntry();
uint32_t ref_count = 0;
scoped_refptr<ImageData> image_data;
};
struct InUseCacheKeyHash;
struct InUseCacheKey {
InUseCacheKey(const DrawImage& draw_image, int mip_level);
bool operator==(const InUseCacheKey& other) const;
private:
friend struct GpuImageDecodeCache::InUseCacheKeyHash;
PaintImage::FrameKey frame_key;
int upload_scale_mip_level;
PaintFlags::FilterQuality filter_quality;
TargetColorParams target_color_params;
};
struct InUseCacheKeyHash {
size_t operator()(const InUseCacheKey&) const;
};
int CalculateUploadScaleMipLevel(const DrawImage& draw_image,
AuxImage aux_image) const;
InUseCacheKey InUseCacheKeyFromDrawImage(const DrawImage& draw_image) const;
scoped_refptr<TileTask> GetImageDecodeTaskAndRef(
ClientId client_id,
const DrawImage& image,
const TracingInfo& tracing_info,
DecodeTaskType task_type) EXCLUSIVE_LOCKS_REQUIRED(lock_);
TaskResult GetTaskForImageAndRefInternal(ClientId client_id,
const DrawImage& image,
const TracingInfo& tracing_info,
DecodeTaskType task_type);
void RefImageDecode(const DrawImage& draw_image,
const InUseCacheKey& cache_key)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void UnrefImageDecode(const DrawImage& draw_image,
const InUseCacheKey& cache_key)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void RefImage(const DrawImage& draw_image, const InUseCacheKey& cache_key)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void UnrefImageInternal(const DrawImage& draw_image,
const InUseCacheKey& cache_key)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void OwnershipChanged(const DrawImage& draw_image, ImageData* image_data)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
bool EnsureCapacity(size_t required_size) EXCLUSIVE_LOCKS_REQUIRED(lock_);
bool CanFitInWorkingSet(size_t size) const EXCLUSIVE_LOCKS_REQUIRED(lock_);
bool ExceedsCacheLimits() const EXCLUSIVE_LOCKS_REQUIRED(lock_);
void ReduceCacheUsageLocked() EXCLUSIVE_LOCKS_REQUIRED(lock_);
void InsertTransferCacheEntry(
const ClientImageTransferCacheEntry& image_entry,
ImageData* image_data) EXCLUSIVE_LOCKS_REQUIRED(lock_);
bool NeedsDarkModeFilter(const DrawImage& draw_image, ImageData* image_data);
void DecodeImageAndGenerateDarkModeFilterIfNecessary(
const DrawImage& draw_image,
ImageData* image_data,
TaskType task_type) EXCLUSIVE_LOCKS_REQUIRED(lock_);
void DecodeImageIfNecessary(const DrawImage& draw_image,
ImageData* image_data,
TaskType task_type,
bool needs_decode_for_dark_mode)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void GenerateDarkModeFilter(const DrawImage& draw_image,
ImageData* image_data)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
sk_sp<SkImage> CreateImageFromYUVATexturesInternal(
const SkImage* uploaded_y_image,
const SkImage* uploaded_u_image,
const SkImage* uploaded_v_image,
const int image_width,
const int image_height,
const SkYUVAInfo::PlaneConfig yuva_plane_config,
const SkYUVAInfo::Subsampling yuva_subsampling,
const SkYUVColorSpace yuva_color_space,
sk_sp<SkColorSpace> target_color_space,
sk_sp<SkColorSpace> decoded_color_space) const
EXCLUSIVE_LOCKS_REQUIRED(lock_);
scoped_refptr<GpuImageDecodeCache::ImageData> CreateImageData(
const DrawImage& image,
bool allow_hardware_decode);
void WillAddCacheEntry(const DrawImage& draw_image)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
std::tuple<SkImageInfo, int> CreateImageInfoForDrawImage(
const DrawImage& draw_image,
AuxImage aux_image) const;
ImageData* GetImageDataForDrawImage(const DrawImage& image,
const InUseCacheKey& key)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
bool IsCompatible(const ImageData* image_data,
const DrawImage& draw_image) const;
void DeleteImage(ImageData* image_data) EXCLUSIVE_LOCKS_REQUIRED(lock_);
void UnlockImage(ImageData* image_data) EXCLUSIVE_LOCKS_REQUIRED(lock_);
enum class HaveContextLock { kYes, kNo };
bool TryLockImage(HaveContextLock have_context_lock,
const DrawImage& draw_image,
ImageData* data) EXCLUSIVE_LOCKS_REQUIRED(lock_);
void UploadImageIfNecessary(const DrawImage& draw_image,
ImageData* image_data)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void UploadImageIfNecessary_TransferCache_HardwareDecode(
const DrawImage& draw_image,
ImageData* image_data,
sk_sp<SkColorSpace> color_space) EXCLUSIVE_LOCKS_REQUIRED(lock_);
void UploadImageIfNecessary_TransferCache_SoftwareDecode(
const DrawImage& draw_image,
ImageData* image_data,
sk_sp<SkColorSpace> decoded_target_colorspace,
absl::optional<TargetColorParams> target_color_params)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void UploadImageIfNecessary_GpuCpu_YUVA(
const DrawImage& draw_image,
ImageData* image_data,
sk_sp<SkImage> uploaded_image,
GrMipMapped image_needs_mips,
sk_sp<SkColorSpace> decoded_target_colorspace,
sk_sp<SkColorSpace> color_space) EXCLUSIVE_LOCKS_REQUIRED(lock_);
void UploadImageIfNecessary_GpuCpu_RGBA(const DrawImage& draw_image,
ImageData* image_data,
sk_sp<SkImage> uploaded_image,
GrMipMapped image_needs_mips,
sk_sp<SkColorSpace> color_space)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void FlushYUVImages(std::vector<sk_sp<SkImage>>* yuv_images)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void RunPendingContextThreadOperations() EXCLUSIVE_LOCKS_REQUIRED(lock_);
void CheckContextLockAcquiredIfNecessary();
sk_sp<SkColorSpace> ColorSpaceForImageDecode(const DrawImage& image,
DecodedDataMode mode) const;
void AddTextureDump(base::trace_event::ProcessMemoryDump* pmd,
const std::string& texture_dump_name,
const size_t bytes,
const GrGLuint gl_id,
const size_t locked_size) const
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void MemoryDumpYUVImage(base::trace_event::ProcessMemoryDump* pmd,
const ImageData* image_data,
const std::string& dump_base_name,
size_t locked_size) const
EXCLUSIVE_LOCKS_REQUIRED(lock_);
using PersistentCache = base::HashingLRUCache<PaintImage::FrameKey,
scoped_refptr<ImageData>,
PaintImage::FrameKeyHash>;
void AddToPersistentCache(const DrawImage& draw_image,
scoped_refptr<ImageData> data)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
template <typename Iterator>
Iterator RemoveFromPersistentCache(Iterator it)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void MaybePurgeOldCacheEntries() EXCLUSIVE_LOCKS_REQUIRED(lock_);
void PostPurgeOldCacheEntriesTask() EXCLUSIVE_LOCKS_REQUIRED(lock_);
void DoPurgeOldCacheEntries(base::TimeDelta max_age)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void PurgeOldCacheEntriesCallback() LOCKS_EXCLUDED(lock_);
void UpdateMipsIfNeeded(const DrawImage& draw_image, ImageData* image_data)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
static scoped_refptr<TileTask> GetTaskFromMapForClientId(
const ClientId client_id,
const ImageTaskMap& task_map);
bool has_pending_purge_task() const EXCLUSIVE_LOCKS_REQUIRED(lock_) {
return timer_.IsRunning();
}
const SkColorType color_type_;
const bool use_transfer_cache_ = false;
raw_ptr<viz::RasterContextProvider> context_;
int max_texture_size_ = 0;
const PaintImage::GeneratorClientId generator_client_id_;
bool allow_accelerated_jpeg_decodes_ = false;
bool allow_accelerated_webp_decodes_ = false;
SkYUVAPixmapInfo::SupportedDataTypes yuva_supported_data_types_;
const bool enable_clipped_image_scaling_;
mutable base::Lock lock_;
base::OneShotTimer timer_ GUARDED_BY(lock_);
PersistentCache persistent_cache_ GUARDED_BY(lock_);
size_t persistent_cache_memory_size_ GUARDED_BY(lock_) = 0;
struct CacheEntries {
PaintImage::ContentId content_ids[2] = {PaintImage::kInvalidContentId,
PaintImage::kInvalidContentId};
size_t count = 0u;
};
base::flat_map<PaintImage::Id, CacheEntries> paint_image_entries_
GUARDED_BY(lock_);
using InUseCache =
std::unordered_map<InUseCacheKey, InUseCacheEntry, InUseCacheKeyHash>;
InUseCache in_use_cache_ GUARDED_BY(lock_);
size_t max_working_set_bytes_ GUARDED_BY(lock_) = 0;
size_t max_working_set_items_ GUARDED_BY(lock_) = 0;
size_t working_set_bytes_ GUARDED_BY(lock_) = 0;
size_t working_set_items_ GUARDED_BY(lock_) = 0;
bool aggressively_freeing_resources_ GUARDED_BY(lock_) = false;
RAW_PTR_EXCLUSION RasterDarkModeFilter* const dark_mode_filter_;
std::vector<SkImage*> images_pending_complete_lock_;
std::vector<SkImage*> images_pending_unlock_;
std::vector<sk_sp<SkImage>> images_pending_deletion_;
std::vector<sk_sp<SkImage>> yuv_images_pending_deletion_;
std::vector<sk_sp<SkImage>> yuv_images_pending_unlock_;
const sk_sp<SkColorSpace> target_color_space_;
std::vector<uint32_t> ids_pending_unlock_;
std::vector<uint32_t> ids_pending_deletion_;
std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
};
}
#endif