1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2022 Google LLC 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef skgpu_graphite_GlobalCache_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define skgpu_graphite_GlobalCache_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkSpinlock.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkLRUCache.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h" 16*c8dee2aaSAndroid Build Coastguard Worker 17*c8dee2aaSAndroid Build Coastguard Worker #include <functional> 18*c8dee2aaSAndroid Build Coastguard Worker 19*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite { 20*c8dee2aaSAndroid Build Coastguard Worker 21*c8dee2aaSAndroid Build Coastguard Worker class ComputePipeline; 22*c8dee2aaSAndroid Build Coastguard Worker class GraphicsPipeline; 23*c8dee2aaSAndroid Build Coastguard Worker class Resource; 24*c8dee2aaSAndroid Build Coastguard Worker class ShaderCodeDictionary; 25*c8dee2aaSAndroid Build Coastguard Worker 26*c8dee2aaSAndroid Build Coastguard Worker /** 27*c8dee2aaSAndroid Build Coastguard Worker * GlobalCache holds GPU resources that should be shared by every Recorder. The common requirement 28*c8dee2aaSAndroid Build Coastguard Worker * of these resources are they are static/read-only, have long lifetimes, and are likely to be used 29*c8dee2aaSAndroid Build Coastguard Worker * by multiple Recorders. The canonical example of this are pipelines. 30*c8dee2aaSAndroid Build Coastguard Worker * 31*c8dee2aaSAndroid Build Coastguard Worker * GlobalCache is thread safe, but intentionally splits queries and storing operations so that they 32*c8dee2aaSAndroid Build Coastguard Worker * are not atomic. The pattern is to query for a resource, which has a high likelihood of a cache 33*c8dee2aaSAndroid Build Coastguard Worker * hit. If it's not found, the Recorder creates the resource on its own, without locking the 34*c8dee2aaSAndroid Build Coastguard Worker * GlobalCache. After the resource is created, it is added to the GlobalCache, atomically returning 35*c8dee2aaSAndroid Build Coastguard Worker * the winning Resource in the event of a race between Recorders for the same UniqueKey. 36*c8dee2aaSAndroid Build Coastguard Worker */ 37*c8dee2aaSAndroid Build Coastguard Worker class GlobalCache { 38*c8dee2aaSAndroid Build Coastguard Worker public: 39*c8dee2aaSAndroid Build Coastguard Worker GlobalCache(); 40*c8dee2aaSAndroid Build Coastguard Worker ~GlobalCache(); 41*c8dee2aaSAndroid Build Coastguard Worker 42*c8dee2aaSAndroid Build Coastguard Worker void deleteResources(); 43*c8dee2aaSAndroid Build Coastguard Worker 44*c8dee2aaSAndroid Build Coastguard Worker // Find a cached GraphicsPipeline that matches the associated key. 45*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GraphicsPipeline> findGraphicsPipeline(const UniqueKey&) SK_EXCLUDES(fSpinLock); 46*c8dee2aaSAndroid Build Coastguard Worker 47*c8dee2aaSAndroid Build Coastguard Worker // Associate the given pipeline with the key. If the key has already had a separate pipeline 48*c8dee2aaSAndroid Build Coastguard Worker // associated with the key, that pipeline is returned and the passed-in pipeline is discarded. 49*c8dee2aaSAndroid Build Coastguard Worker // Otherwise, the passed-in pipeline is held by the GlobalCache and also returned back. 50*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GraphicsPipeline> addGraphicsPipeline(const UniqueKey&, 51*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GraphicsPipeline>) SK_EXCLUDES(fSpinLock); 52*c8dee2aaSAndroid Build Coastguard Worker 53*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS) 54*c8dee2aaSAndroid Build Coastguard Worker int numGraphicsPipelines() const SK_EXCLUDES(fSpinLock); 55*c8dee2aaSAndroid Build Coastguard Worker void resetGraphicsPipelines() SK_EXCLUDES(fSpinLock); 56*c8dee2aaSAndroid Build Coastguard Worker void forEachGraphicsPipeline( 57*c8dee2aaSAndroid Build Coastguard Worker const std::function<void(const UniqueKey&, const GraphicsPipeline*)>& fn) 58*c8dee2aaSAndroid Build Coastguard Worker SK_EXCLUDES(fSpinLock); 59*c8dee2aaSAndroid Build Coastguard Worker 60*c8dee2aaSAndroid Build Coastguard Worker struct PipelineStats { 61*c8dee2aaSAndroid Build Coastguard Worker int fGraphicsCacheHits = 0; 62*c8dee2aaSAndroid Build Coastguard Worker int fGraphicsCacheMisses = 0; 63*c8dee2aaSAndroid Build Coastguard Worker int fGraphicsCacheAdditions = 0; 64*c8dee2aaSAndroid Build Coastguard Worker int fGraphicsRaces = 0; 65*c8dee2aaSAndroid Build Coastguard Worker }; 66*c8dee2aaSAndroid Build Coastguard Worker 67*c8dee2aaSAndroid Build Coastguard Worker PipelineStats getStats() const SK_EXCLUDES(fSpinLock); 68*c8dee2aaSAndroid Build Coastguard Worker #endif 69*c8dee2aaSAndroid Build Coastguard Worker 70*c8dee2aaSAndroid Build Coastguard Worker // Find and add operations for ComputePipelines, with the same pattern as GraphicsPipelines. 71*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ComputePipeline> findComputePipeline(const UniqueKey&) SK_EXCLUDES(fSpinLock); 72*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ComputePipeline> addComputePipeline(const UniqueKey&, 73*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ComputePipeline>) SK_EXCLUDES(fSpinLock); 74*c8dee2aaSAndroid Build Coastguard Worker 75*c8dee2aaSAndroid Build Coastguard Worker // The GlobalCache holds a ref on the given Resource until the cache is destroyed, keeping it 76*c8dee2aaSAndroid Build Coastguard Worker // alive for the lifetime of the SharedContext. This should be used only for Resources that are 77*c8dee2aaSAndroid Build Coastguard Worker // immutable after initialization so that anyone can use the resource without synchronization 78*c8dee2aaSAndroid Build Coastguard Worker // or reference tracking. 79*c8dee2aaSAndroid Build Coastguard Worker void addStaticResource(sk_sp<Resource>) SK_EXCLUDES(fSpinLock); 80*c8dee2aaSAndroid Build Coastguard Worker 81*c8dee2aaSAndroid Build Coastguard Worker private: 82*c8dee2aaSAndroid Build Coastguard Worker struct KeyHash { operatorKeyHash83*c8dee2aaSAndroid Build Coastguard Worker uint32_t operator()(const UniqueKey& key) const { return key.hash(); } 84*c8dee2aaSAndroid Build Coastguard Worker }; 85*c8dee2aaSAndroid Build Coastguard Worker 86*c8dee2aaSAndroid Build Coastguard Worker using GraphicsPipelineCache = SkLRUCache<UniqueKey, sk_sp<GraphicsPipeline>, KeyHash>; 87*c8dee2aaSAndroid Build Coastguard Worker using ComputePipelineCache = SkLRUCache<UniqueKey, sk_sp<ComputePipeline>, KeyHash>; 88*c8dee2aaSAndroid Build Coastguard Worker 89*c8dee2aaSAndroid Build Coastguard Worker // TODO: can we do something better given this should have write-seldom/read-often behavior? 90*c8dee2aaSAndroid Build Coastguard Worker mutable SkSpinlock fSpinLock; 91*c8dee2aaSAndroid Build Coastguard Worker 92*c8dee2aaSAndroid Build Coastguard Worker // GraphicsPipelines and ComputePipelines are expensive to create, likely to be used by multiple 93*c8dee2aaSAndroid Build Coastguard Worker // Recorders, and are ideally pre-compiled on process startup so thread write-contention is 94*c8dee2aaSAndroid Build Coastguard Worker // expected to be low. For these reasons we store pipelines globally instead of per-Recorder. 95*c8dee2aaSAndroid Build Coastguard Worker GraphicsPipelineCache fGraphicsPipelineCache SK_GUARDED_BY(fSpinLock); 96*c8dee2aaSAndroid Build Coastguard Worker ComputePipelineCache fComputePipelineCache SK_GUARDED_BY(fSpinLock); 97*c8dee2aaSAndroid Build Coastguard Worker 98*c8dee2aaSAndroid Build Coastguard Worker skia_private::TArray<sk_sp<Resource>> fStaticResource SK_GUARDED_BY(fSpinLock); 99*c8dee2aaSAndroid Build Coastguard Worker 100*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS) 101*c8dee2aaSAndroid Build Coastguard Worker PipelineStats fStats SK_GUARDED_BY(fSpinLock); 102*c8dee2aaSAndroid Build Coastguard Worker #endif 103*c8dee2aaSAndroid Build Coastguard Worker }; 104*c8dee2aaSAndroid Build Coastguard Worker 105*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite 106*c8dee2aaSAndroid Build Coastguard Worker 107*c8dee2aaSAndroid Build Coastguard Worker #endif // skgpu_graphite_GlobalCache_DEFINED 108