| // 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; | |
| 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, | |
| uint64_t entry_id); | |
| int decoder_id; | |
| cc::TransferCacheEntryType entry_type; | |
| uint64_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); | |
| // Memory coordinator interface: | |
| // Triggers immediate eviction of transfer cache entries down to | |
| // `memory_limit`. | |
| void OnReleaseMemory(int memory_limit); | |
| // Updates the target cache size limit non-destructively without forcing | |
| // immediate eviction. | |
| void OnUpdateMemoryLimit(int memory_limit); | |
| // 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) { | |
| max_cache_size_limit_ = 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 baseline limit above which the cache will start evicting resources. | |
| // Constant during normal execution, modified only by | |
| // SetCacheSizeLimitForTesting(). | |
| size_t max_cache_size_limit_; | |
| // 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_ |