// 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. #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/351564777): Remove this and convert code to safer constructs. #pragma allow_unsafe_buffers #endif #ifndef CC_TILES_GPU_IMAGE_DECODE_CACHE_H_ #define CC_TILES_GPU_IMAGE_DECODE_CACHE_H_ #include <memory> #include <optional> #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/memory/weak_ptr.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/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 { class ColorFilter; class RasterDarkModeFilter; // OVERVIEW: // // GpuImageDecodeCache handles the decode and upload of images that will // be used by Skia's GPU raster path. It also maintains a cache of these // decoded/uploaded images for later re-use. // // Generally, when an image is required for raster, GpuImageDecodeCache // creates two tasks, one to decode the image, and one to upload the image to // the GPU. These tasks are completed before the raster task which depends on // the image. We need to separate decode and upload tasks, as decode can occur // simultaneously on multiple threads, while upload requires the GL context // lock so it must happen on our non-concurrent raster thread. // // Decoded and Uploaded image data share a single cache entry. Depending on how // far we've progressed, this cache entry may contain CPU-side decoded data, // GPU-side uploaded data, or both. CPU-side decoded data is stored in software // discardable memory and is only locked for short periods of time (until the // upload completes). Uploaded GPU data is stored in GPU discardable memory and // remains locked for the duration of the raster tasks which depend on it. // // In cases where the size of locked GPU images exceeds our working set limits, // we operate in an "at-raster" mode. In this mode, there are no decode/upload // tasks, and images are decoded/uploaded as needed, immediately before being // used in raster. Cache entries for at-raster tasks are marked as such, which // prevents future tasks from taking a dependency on them and extending their // lifetime longer than is necessary. // // RASTER-SCALE CACHING: // // In order to save memory, images which are going to be scaled may be uploaded // at lower than original resolution. In these cases, we may later need to // re-upload the image at a higher resolution. To handle multiple images of // different scales being in use at the same time, we have a two-part caching // system. // // The first cache, |persistent_cache_|, stores one ImageData per image id. // These ImageDatas are not necessarily associated with a given DrawImage, and // are saved (persisted) even when their ref-count reaches zero (assuming they // fit in the current memory budget). This allows for future re-use of image // resources. // // The second cache, |in_use_cache_|, stores one image data per DrawImage - // this may be the same ImageData that is in the persistent_cache_. These // cache entries are more transient and are deleted as soon as all refs to the // given DrawImage are released (the image is no longer in-use). // // For examples of raster-scale caching, see https://goo.gl/0zCd9Z // // REF COUNTING: // // In dealing with the two caches in GpuImageDecodeCache, there are three // ref-counting concepts in use: // 1) ImageData upload/decode ref-counts. // These ref-counts represent the overall number of references to the // upload or decode portion of an ImageData. These ref-counts control // both whether the upload/decode data can be freed, as well as whether an // ImageData can be removed from the |persistent_cache_|. ImageDatas are // only removed from the |persistent_cache_| if their upload/decode // ref-counts are zero or if they are orphaned and replaced by a new entry. // 2) InUseCacheEntry ref-counts. // These ref-counts represent the number of references to an // InUseCacheEntry from a specific DrawImage. When the InUseCacheEntry's // ref-count reaches 0 it will be deleted. // 3) scoped_refptr ref-counts. // Because both the persistent_cache_ and the in_use_cache_ point at the // same ImageDatas (and may need to keep these ImageDatas alive independent // of each other), they hold ImageDatas by scoped_refptr. The scoped_refptr // keeps an ImageData alive while it is present in either the // |persistent_cache_| or |in_use_cache_|. // // HARDWARE ACCELERATED DECODES: // // In Chrome OS, we have the ability to use specialized hardware to decode // certain images. Because this requires interacting with drivers, it must be // done in the GPU process. Therefore, we follow a different path than the usual // decode -> upload tasks: // 1) We decide whether to do hardware decode acceleration for an image before // we create the decode/upload tasks. Under the hood, this involves parsing // the image and checking if it's supported by the hardware decoder // according to information advertised by the GPU process. Also, we only // allow hardware decoding in OOP-R mode. // 2) If we do decide to do hardware decoding, we don't create a decode task. // Instead, we create only an upload task and store enough state to // indicate that the image will go through this hardware accelerated path. // The reason that we use the upload task is that we need to hold the // context lock in order to schedule the image decode. // 3) When the upload task runs, we send a request to the GPU process to start // the image decode. This is an IPC message that does not require us to // wait for the response. Instead, we get a sync token that is signalled // when the decode completes. We insert a wait for this sync token right // after sending the decode request. // // We also handle the more unusual case where images are decoded at raster time. // The process is similar: we skip the software decode and then request the // hardware decode in the same way as step (3) above. // // Note that the decoded data never makes it back to the renderer. It stays in // the GPU process. The sync token ensures that any raster work that needs the // image happens after the decode completes. class CC_EXPORT GpuImageDecodeCache : public ImageDecodeCache, public base::trace_event::MemoryDumpProvider { … }; } // namespace cc #endif // CC_TILES_GPU_IMAGE_DECODE_CACHE_H_