#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "cc/tiles/gpu_image_decode_cache.h"
#include <inttypes.h>
#include <algorithm>
#include <limits>
#include <string>
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/containers/span.h"
#include "base/debug/alias.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/hash/hash.h"
#include "base/logging.h"
#include "base/memory/discardable_memory_allocator.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/not_fatal_until.h"
#include "base/notreached.h"
#include "base/numerics/safe_math.h"
#include "base/ranges/algorithm.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "base/trace_event/memory_dump_manager.h"
#include "cc/base/devtools_instrumentation.h"
#include "cc/base/features.h"
#include "cc/base/histograms.h"
#include "cc/base/switches.h"
#include "cc/paint/paint_flags.h"
#include "cc/raster/scoped_grcontext_access.h"
#include "cc/raster/tile_task.h"
#include "cc/tiles/mipmap_util.h"
#include "cc/tiles/raster_dark_mode_filter.h"
#include "components/viz/common/gpu/raster_context_provider.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_info.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkPixmap.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkSamplingOptions.h"
#include "third_party/skia/include/core/SkSize.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkYUVAPixmaps.h"
#include "third_party/skia/include/gpu/GpuTypes.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/gpu/GrYUVABackendTextures.h"
#include "third_party/skia/include/gpu/ganesh/SkImageGanesh.h"
#include "third_party/skia/include/gpu/ganesh/gl/GrGLBackendSurface.h"
#include "third_party/skia/include/gpu/gl/GrGLTypes.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gl/trace_util.h"
namespace cc {
namespace {
static const int kNormalMaxItemsInCacheForGpu = …;
static const int kSuspendedMaxItemsInCacheForGpu = …;
static const int kMaxItemsInWorkingSet = …;
enum ImageUsageState : int { … };
bool SkipImage(const DrawImage& draw_image) { … }
PaintFlags::FilterQuality CalculateDesiredFilterQuality(
const DrawImage& draw_image) { … }
SkSize CalculateScaleFactorForMipLevel(const DrawImage& draw_image,
AuxImage aux_image,
int upload_scale_mip_level) { … }
gfx::Size CalculateSizeForMipLevel(const DrawImage& draw_image,
AuxImage aux_image,
int upload_scale_mip_level) { … }
bool ShouldGenerateMips(const DrawImage& draw_image,
AuxImage aux_image,
int upload_scale_mip_level) { … }
size_t EstimateHardwareDecodedDataSize(
const ImageHeaderMetadata* image_metadata) { … }
bool DrawAndScaleImageRGB(const DrawImage& draw_image,
AuxImage aux_image,
SkPixmap& target_pixmap,
PaintImage::GeneratorClientId client_id) { … }
bool DrawAndScaleImageYUV(
const DrawImage& draw_image,
AuxImage aux_image,
PaintImage::GeneratorClientId client_id,
const SkYUVAPixmapInfo::SupportedDataTypes& yuva_supported_data_types,
SkYUVAPixmaps& yuva_pixmaps) { … }
sk_sp<SkImage> TakeOwnershipOfSkImageBacking(GrDirectContext* context,
sk_sp<SkImage> image) { … }
void DeleteSkImageAndPreventCaching(viz::RasterContextProvider* context,
sk_sp<SkImage>&& image) { … }
sk_sp<SkImage> MakeTextureImage(viz::RasterContextProvider* context,
sk_sp<SkImage> source_image,
sk_sp<SkColorSpace> target_color_space,
skgpu::Mipmapped mip_mapped) { … }
class HeapDiscardableMemory : public base::DiscardableMemory { … };
std::optional<SkYUVAPixmapInfo> GetYUVADecodeInfo(
const DrawImage& draw_image,
AuxImage aux_image,
const SkISize target_size,
const SkYUVAPixmapInfo::SupportedDataTypes& yuva_supported_data_types) { … }
bool NeedsToneMapping(sk_sp<SkColorSpace> image_color_space, bool has_gainmap) { … }
}
GpuImageDecodeCache::InUseCacheKey::InUseCacheKey(const DrawImage& draw_image,
int mip_level)
: … { … }
bool GpuImageDecodeCache::InUseCacheKey::operator==(
const InUseCacheKey& other) const { … }
size_t GpuImageDecodeCache::InUseCacheKeyHash::operator()(
const InUseCacheKey& cache_key) const { … }
GpuImageDecodeCache::InUseCacheEntry::InUseCacheEntry(
scoped_refptr<ImageData> image_data)
: … { … }
GpuImageDecodeCache::InUseCacheEntry::InUseCacheEntry(const InUseCacheEntry&) =
default;
GpuImageDecodeCache::InUseCacheEntry::InUseCacheEntry(InUseCacheEntry&&) =
default;
GpuImageDecodeCache::InUseCacheEntry::~InUseCacheEntry() = default;
class GpuImageDecodeTaskImpl : public TileTask { … };
class ImageUploadTaskImpl : public TileTask { … };
GpuImageDecodeCache::ImageDataBase::ImageDataBase() = default;
GpuImageDecodeCache::ImageDataBase::~ImageDataBase() = default;
void GpuImageDecodeCache::ImageDataBase::OnSetLockedData(bool out_of_raster) { … }
void GpuImageDecodeCache::ImageDataBase::OnResetData() { … }
void GpuImageDecodeCache::ImageDataBase::OnLock() { … }
void GpuImageDecodeCache::ImageDataBase::OnUnlock() { … }
int GpuImageDecodeCache::ImageDataBase::UsageState() const { … }
GpuImageDecodeCache::DecodedAuxImageData::DecodedAuxImageData() = default;
GpuImageDecodeCache::DecodedAuxImageData::DecodedAuxImageData(
const SkPixmap& rgba_pixmap,
std::unique_ptr<base::DiscardableMemory> in_data) { … }
GpuImageDecodeCache::DecodedAuxImageData::DecodedAuxImageData(
const SkYUVAPixmaps& yuva_pixmaps,
std::unique_ptr<base::DiscardableMemory> in_data) { … }
GpuImageDecodeCache::DecodedAuxImageData::DecodedAuxImageData(
DecodedAuxImageData&& other)
: … { … }
GpuImageDecodeCache::DecodedAuxImageData&
GpuImageDecodeCache::DecodedAuxImageData::operator=(
DecodedAuxImageData&& other) { … }
GpuImageDecodeCache::DecodedAuxImageData::~DecodedAuxImageData() = default;
bool GpuImageDecodeCache::DecodedAuxImageData::IsEmpty() const { … }
void GpuImageDecodeCache::DecodedAuxImageData::ResetData() { … }
GpuImageDecodeCache::DecodedImageData::DecodedImageData(
bool is_bitmap_backed,
bool can_do_hardware_accelerated_decode,
bool do_hardware_accelerated_decode)
: … { … }
GpuImageDecodeCache::DecodedImageData::~DecodedImageData() { … }
bool GpuImageDecodeCache::DecodedImageData::Lock() { … }
void GpuImageDecodeCache::DecodedImageData::Unlock() { … }
void GpuImageDecodeCache::DecodedImageData::SetLockedData(
DecodedAuxImageData aux_image_data[kAuxImageCount],
bool out_of_raster) { … }
void GpuImageDecodeCache::DecodedImageData::SetBitmapImage(
sk_sp<SkImage> image) { … }
void GpuImageDecodeCache::DecodedImageData::ResetBitmapImage() { … }
void GpuImageDecodeCache::DecodedImageData::ResetData() { … }
void GpuImageDecodeCache::DecodedImageData::ReportUsageStats() const { … }
GpuImageDecodeCache::UploadedImageData::UploadedImageData() = default;
GpuImageDecodeCache::UploadedImageData::~UploadedImageData() { … }
void GpuImageDecodeCache::UploadedImageData::SetImage(
sk_sp<SkImage> image,
bool represents_yuv_image) { … }
void GpuImageDecodeCache::UploadedImageData::SetYuvImage(
sk_sp<SkImage> y_image_input,
sk_sp<SkImage> u_image_input,
sk_sp<SkImage> v_image_input) { … }
void GpuImageDecodeCache::UploadedImageData::SetTransferCacheId(uint32_t id) { … }
void GpuImageDecodeCache::UploadedImageData::Reset() { … }
void GpuImageDecodeCache::UploadedImageData::ReportUsageStats() const { … }
GpuImageDecodeCache::ImageInfo::ImageInfo() = default;
GpuImageDecodeCache::ImageInfo::ImageInfo(const SkImageInfo& rgba)
: … { … }
GpuImageDecodeCache::ImageInfo::ImageInfo(const SkYUVAPixmapInfo& yuva)
: … { … }
GpuImageDecodeCache::ImageInfo::ImageInfo(const ImageInfo&) = default;
GpuImageDecodeCache::ImageInfo& GpuImageDecodeCache::ImageInfo::operator=(
const ImageInfo&) = default;
GpuImageDecodeCache::ImageInfo::~ImageInfo() = default;
GpuImageDecodeCache::ImageData::ImageData(
PaintImage::Id paint_image_id,
DecodedDataMode mode,
const gfx::ColorSpace& target_color_space,
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])
: … { … }
GpuImageDecodeCache::ImageData::~ImageData() { … }
bool GpuImageDecodeCache::ImageData::IsGpuOrTransferCache() const { … }
bool GpuImageDecodeCache::ImageData::HasUploadedData() const { … }
void GpuImageDecodeCache::ImageData::ValidateBudgeted() const { … }
size_t GpuImageDecodeCache::ImageData::GetTotalSize() const { … }
GrGLuint GpuImageDecodeCache::GlIdFromSkImage(const SkImage* image) { … }
GpuImageDecodeCache::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::~GpuImageDecodeCache() { … }
ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRef(
ClientId client_id,
const DrawImage& draw_image,
const TracingInfo& tracing_info) { … }
ImageDecodeCache::TaskResult
GpuImageDecodeCache::GetOutOfRasterDecodeTaskForImageAndRef(
ClientId client_id,
const DrawImage& draw_image) { … }
ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
ClientId client_id,
const DrawImage& draw_image,
const TracingInfo& tracing_info,
DecodeTaskType task_type) { … }
void GpuImageDecodeCache::UnrefImage(const DrawImage& draw_image) { … }
bool GpuImageDecodeCache::UseCacheForDrawImage(
const DrawImage& draw_image) const { … }
DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
const DrawImage& draw_image) { … }
void GpuImageDecodeCache::DrawWithImageFinished(
const DrawImage& draw_image,
const DecodedDrawImage& decoded_draw_image) { … }
void GpuImageDecodeCache::ReduceCacheUsage() { … }
void GpuImageDecodeCache::ReduceCacheUsageLocked() NO_THREAD_SAFETY_ANALYSIS { … }
void GpuImageDecodeCache::SetShouldAggressivelyFreeResources(
bool aggressively_free_resources,
bool context_lock_acquired) { … }
void GpuImageDecodeCache::ClearCache() { … }
void GpuImageDecodeCache::RecordStats() { … }
void GpuImageDecodeCache::AddToPersistentCache(const DrawImage& draw_image,
scoped_refptr<ImageData> data) { … }
template <typename Iterator>
Iterator GpuImageDecodeCache::RemoveFromPersistentCache(Iterator it) { … }
bool GpuImageDecodeCache::TryFlushPendingWork() { … }
bool GpuImageDecodeCache::DoPurgeOldCacheEntries(base::TimeDelta max_age) { … }
void GpuImageDecodeCache::PurgeOldCacheEntriesCallback() { … }
void GpuImageDecodeCache::PostPurgeOldCacheEntriesTask() { … }
size_t GpuImageDecodeCache::GetMaximumMemoryLimitBytes() const { … }
void GpuImageDecodeCache::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 { … }
void GpuImageDecodeCache::MemoryDumpYUVImage(
base::trace_event::ProcessMemoryDump* pmd,
const ImageData* image_data,
const std::string& dump_base_name,
size_t locked_size) const { … }
bool GpuImageDecodeCache::OnMemoryDump(
const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) { … }
void GpuImageDecodeCache::DecodeImageInTask(const DrawImage& draw_image,
TaskType task_type) { … }
void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image) { … }
void GpuImageDecodeCache::OnImageDecodeTaskCompleted(
const DrawImage& draw_image,
DecodeTaskType task_type) { … }
void GpuImageDecodeCache::OnImageUploadTaskCompleted(
const DrawImage& draw_image) { … }
int GpuImageDecodeCache::CalculateUploadScaleMipLevel(
const DrawImage& draw_image,
AuxImage aux_image) const { … }
GpuImageDecodeCache::InUseCacheKey
GpuImageDecodeCache::InUseCacheKeyFromDrawImage(
const DrawImage& draw_image) const { … }
scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef(
ClientId client_id,
const DrawImage& draw_image,
const TracingInfo& tracing_info,
DecodeTaskType task_type) { … }
void GpuImageDecodeCache::RefImageDecode(const DrawImage& draw_image,
const InUseCacheKey& cache_key) { … }
void GpuImageDecodeCache::UnrefImageDecode(const DrawImage& draw_image,
const InUseCacheKey& cache_key) { … }
void GpuImageDecodeCache::RefImage(const DrawImage& draw_image,
const InUseCacheKey& cache_key) { … }
void GpuImageDecodeCache::UnrefImageInternal(const DrawImage& draw_image,
const InUseCacheKey& cache_key) { … }
void GpuImageDecodeCache::OwnershipChanged(const DrawImage& draw_image,
ImageData* image_data) { … }
bool GpuImageDecodeCache::EnsureCapacity(size_t required_size) { … }
bool GpuImageDecodeCache::CanFitInWorkingSet(size_t size) const { … }
bool GpuImageDecodeCache::ExceedsCacheLimits() const { … }
void GpuImageDecodeCache::InsertTransferCacheEntry(
const ClientImageTransferCacheEntry& image_entry,
ImageData* image_data) { … }
bool GpuImageDecodeCache::NeedsDarkModeFilter(const DrawImage& draw_image,
ImageData* image_data) { … }
void GpuImageDecodeCache::DecodeImageAndGenerateDarkModeFilterIfNecessary(
const DrawImage& draw_image,
ImageData* image_data,
TaskType task_type) { … }
void GpuImageDecodeCache::DecodeImageIfNecessary(
const DrawImage& draw_image,
ImageData* image_data,
TaskType task_type,
bool needs_decode_for_dark_mode) { … }
void GpuImageDecodeCache::GenerateDarkModeFilter(const DrawImage& draw_image,
ImageData* image_data) { … }
void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
ImageData* image_data) { … }
void GpuImageDecodeCache::UploadImageIfNecessary_TransferCache_HardwareDecode(
const DrawImage& draw_image,
ImageData* image_data,
sk_sp<SkColorSpace> color_space) { … }
void GpuImageDecodeCache::UploadImageIfNecessary_TransferCache_SoftwareDecode(
const DrawImage& draw_image,
ImageData* image_data,
sk_sp<SkColorSpace> decoded_color_space,
const std::optional<gfx::HDRMetadata>& hdr_metadata,
sk_sp<SkColorSpace> target_color_space) { … }
void GpuImageDecodeCache::UploadImageIfNecessary_GpuCpu_YUVA(
const DrawImage& draw_image,
ImageData* image_data,
sk_sp<SkImage> uploaded_image,
skgpu::Mipmapped image_needs_mips,
sk_sp<SkColorSpace> decoded_color_space,
sk_sp<SkColorSpace> color_space) { … }
void GpuImageDecodeCache::UploadImageIfNecessary_GpuCpu_RGBA(
const DrawImage& draw_image,
ImageData* image_data,
sk_sp<SkImage> uploaded_image,
skgpu::Mipmapped image_needs_mips,
sk_sp<SkColorSpace> color_space) { … }
scoped_refptr<GpuImageDecodeCache::ImageData>
GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image,
bool allow_hardware_decode) { … }
void GpuImageDecodeCache::WillAddCacheEntry(const DrawImage& draw_image) { … }
void GpuImageDecodeCache::DeleteImage(ImageData* image_data) { … }
void GpuImageDecodeCache::UnlockImage(ImageData* image_data) { … }
void GpuImageDecodeCache::FlushYUVImages(
std::vector<sk_sp<SkImage>>* yuv_images) { … }
void GpuImageDecodeCache::RunPendingContextThreadOperations() { … }
std::tuple<SkImageInfo, int> GpuImageDecodeCache::CreateImageInfoForDrawImage(
const DrawImage& draw_image,
AuxImage aux_image) const { … }
bool GpuImageDecodeCache::TryLockImage(HaveContextLock have_context_lock,
const DrawImage& draw_image,
ImageData* data) { … }
GpuImageDecodeCache::ImageData* GpuImageDecodeCache::GetImageDataForDrawImage(
const DrawImage& draw_image,
const InUseCacheKey& key) { … }
bool GpuImageDecodeCache::IsCompatible(const ImageData* image_data,
const DrawImage& draw_image) const { … }
size_t GpuImageDecodeCache::GetDrawImageSizeForTesting(const DrawImage& image) { … }
void GpuImageDecodeCache::SetImageDecodingFailedForTesting(
const DrawImage& image) { … }
bool GpuImageDecodeCache::DiscardableIsLockedForTesting(
const DrawImage& image) { … }
bool GpuImageDecodeCache::IsInInUseCacheForTesting(
const DrawImage& image) const { … }
bool GpuImageDecodeCache::IsInPersistentCacheForTesting(
const DrawImage& image) const { … }
sk_sp<SkImage> GpuImageDecodeCache::GetSWImageDecodeForTesting(
const DrawImage& image) { … }
sk_sp<SkImage> GpuImageDecodeCache::GetUploadedPlaneForTesting(
const DrawImage& draw_image,
YUVIndex index) { … }
size_t GpuImageDecodeCache::GetDarkModeImageCacheSizeForTesting(
const DrawImage& draw_image) { … }
bool GpuImageDecodeCache::NeedsDarkModeFilterForTesting(
const DrawImage& draw_image) { … }
void GpuImageDecodeCache::TouchCacheEntryForTesting(
const DrawImage& draw_image) { … }
void GpuImageDecodeCache::OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level) { … }
bool GpuImageDecodeCache::AcquireContextLockForTesting() { … }
void GpuImageDecodeCache::ReleaseContextLockForTesting()
NO_THREAD_SAFETY_ANALYSIS { … }
bool GpuImageDecodeCache::SupportsColorSpaceConversion() const { … }
sk_sp<SkColorSpace> GpuImageDecodeCache::ColorSpaceForImageDecode(
const DrawImage& image,
DecodedDataMode mode) const { … }
void GpuImageDecodeCache::CheckContextLockAcquiredIfNecessary() { … }
sk_sp<SkImage> GpuImageDecodeCache::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 yuv_color_space,
sk_sp<SkColorSpace> target_color_space,
sk_sp<SkColorSpace> decoded_color_space) const { … }
void GpuImageDecodeCache::UpdateMipsIfNeeded(const DrawImage& draw_image,
ImageData* image_data) { … }
scoped_refptr<TileTask> GpuImageDecodeCache::GetTaskFromMapForClientId(
const ClientId client_id,
const ImageTaskMap& task_map) { … }
base::TimeDelta GpuImageDecodeCache::get_purge_interval() { … }
base::TimeDelta GpuImageDecodeCache::get_max_purge_age() { … }
}