xref: /aosp_15_r20/external/skia/src/gpu/graphite/GlobalCache.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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