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 #include "src/gpu/graphite/GlobalCache.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ComputePipeline.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ContextUtils.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/GraphicsPipeline.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Resource.h"
14*c8dee2aaSAndroid Build Coastguard Worker
15*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
16*c8dee2aaSAndroid Build Coastguard Worker
GlobalCache()17*c8dee2aaSAndroid Build Coastguard Worker GlobalCache::GlobalCache()
18*c8dee2aaSAndroid Build Coastguard Worker : fGraphicsPipelineCache(256) // TODO: find a good value for these limits
19*c8dee2aaSAndroid Build Coastguard Worker , fComputePipelineCache(256) {}
20*c8dee2aaSAndroid Build Coastguard Worker
~GlobalCache()21*c8dee2aaSAndroid Build Coastguard Worker GlobalCache::~GlobalCache() {
22*c8dee2aaSAndroid Build Coastguard Worker // These should have been cleared out earlier by deleteResources().
23*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(SkAutoSpinlock lock{ fSpinLock });
24*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fGraphicsPipelineCache.count() == 0);
25*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fComputePipelineCache.count() == 0);
26*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fStaticResource.empty());
27*c8dee2aaSAndroid Build Coastguard Worker }
28*c8dee2aaSAndroid Build Coastguard Worker
deleteResources()29*c8dee2aaSAndroid Build Coastguard Worker void GlobalCache::deleteResources() {
30*c8dee2aaSAndroid Build Coastguard Worker SkAutoSpinlock lock{ fSpinLock };
31*c8dee2aaSAndroid Build Coastguard Worker
32*c8dee2aaSAndroid Build Coastguard Worker fGraphicsPipelineCache.reset();
33*c8dee2aaSAndroid Build Coastguard Worker fComputePipelineCache.reset();
34*c8dee2aaSAndroid Build Coastguard Worker fStaticResource.clear();
35*c8dee2aaSAndroid Build Coastguard Worker }
36*c8dee2aaSAndroid Build Coastguard Worker
findGraphicsPipeline(const UniqueKey & key)37*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GraphicsPipeline> GlobalCache::findGraphicsPipeline(const UniqueKey& key) {
38*c8dee2aaSAndroid Build Coastguard Worker SkAutoSpinlock lock{fSpinLock};
39*c8dee2aaSAndroid Build Coastguard Worker
40*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GraphicsPipeline>* entry = fGraphicsPipelineCache.find(key);
41*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
42*c8dee2aaSAndroid Build Coastguard Worker if (entry) { ++fStats.fGraphicsCacheHits; } else { ++fStats.fGraphicsCacheMisses; }
43*c8dee2aaSAndroid Build Coastguard Worker #endif
44*c8dee2aaSAndroid Build Coastguard Worker return entry ? *entry : nullptr;
45*c8dee2aaSAndroid Build Coastguard Worker }
46*c8dee2aaSAndroid Build Coastguard Worker
47*c8dee2aaSAndroid Build Coastguard Worker #if SK_HISTOGRAMS_ENABLED
48*c8dee2aaSAndroid Build Coastguard Worker // These values are persisted to logs. Entries should not be renumbered and
49*c8dee2aaSAndroid Build Coastguard Worker // numeric values should never be reused.
50*c8dee2aaSAndroid Build Coastguard Worker //
51*c8dee2aaSAndroid Build Coastguard Worker // LINT.IfChange(PipelineCreationRace)
52*c8dee2aaSAndroid Build Coastguard Worker enum class PipelineCreationRace {
53*c8dee2aaSAndroid Build Coastguard Worker // The <First>Over<Second> enum names mean the first type of compilation won a compilation race
54*c8dee2aaSAndroid Build Coastguard Worker // over the second type of compilation and ended up in the cache.
55*c8dee2aaSAndroid Build Coastguard Worker kNormalOverNormal = 0, // can happen w/ multiple Recorders on different threads
56*c8dee2aaSAndroid Build Coastguard Worker kNormalOverPrecompilation = 1,
57*c8dee2aaSAndroid Build Coastguard Worker kPrecompilationOverNormal = 2,
58*c8dee2aaSAndroid Build Coastguard Worker kPrecompilationOverPrecompilation = 3, // can happen with multiple threaded precompilation calls
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker kMaxValue = kPrecompilationOverPrecompilation,
61*c8dee2aaSAndroid Build Coastguard Worker };
62*c8dee2aaSAndroid Build Coastguard Worker // LINT.ThenChange(//tools/metrics/histograms/enums.xml:SkiaPipelineCreationRace)
63*c8dee2aaSAndroid Build Coastguard Worker
64*c8dee2aaSAndroid Build Coastguard Worker [[maybe_unused]] static constexpr int kPipelineCreationRaceCount =
65*c8dee2aaSAndroid Build Coastguard Worker static_cast<int>(PipelineCreationRace::kMaxValue) + 1;
66*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_HISTOGRAMS_ENABLED
67*c8dee2aaSAndroid Build Coastguard Worker
addGraphicsPipeline(const UniqueKey & key,sk_sp<GraphicsPipeline> pipeline)68*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GraphicsPipeline> GlobalCache::addGraphicsPipeline(const UniqueKey& key,
69*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GraphicsPipeline> pipeline) {
70*c8dee2aaSAndroid Build Coastguard Worker SkAutoSpinlock lock{fSpinLock};
71*c8dee2aaSAndroid Build Coastguard Worker
72*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GraphicsPipeline>* entry = fGraphicsPipelineCache.find(key);
73*c8dee2aaSAndroid Build Coastguard Worker if (!entry) {
74*c8dee2aaSAndroid Build Coastguard Worker // No equivalent pipeline was stored in the cache between a previous call to
75*c8dee2aaSAndroid Build Coastguard Worker // findGraphicsPipeline() that returned null (triggering the pipeline creation) and this
76*c8dee2aaSAndroid Build Coastguard Worker // later adding to the cache.
77*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
78*c8dee2aaSAndroid Build Coastguard Worker ++fStats.fGraphicsCacheAdditions;
79*c8dee2aaSAndroid Build Coastguard Worker #endif
80*c8dee2aaSAndroid Build Coastguard Worker entry = fGraphicsPipelineCache.insert(key, std::move(pipeline));
81*c8dee2aaSAndroid Build Coastguard Worker } else {
82*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
83*c8dee2aaSAndroid Build Coastguard Worker // else there was a race creating the same pipeline and this thread lost, so return
84*c8dee2aaSAndroid Build Coastguard Worker // the winner
85*c8dee2aaSAndroid Build Coastguard Worker ++fStats.fGraphicsRaces;
86*c8dee2aaSAndroid Build Coastguard Worker #endif
87*c8dee2aaSAndroid Build Coastguard Worker #if SK_HISTOGRAMS_ENABLED
88*c8dee2aaSAndroid Build Coastguard Worker [[maybe_unused]] int race = (*entry)->fromPrecompile() * 2 + pipeline->fromPrecompile();
89*c8dee2aaSAndroid Build Coastguard Worker SK_HISTOGRAM_ENUMERATION("Graphite.PipelineCreationRace",
90*c8dee2aaSAndroid Build Coastguard Worker race,
91*c8dee2aaSAndroid Build Coastguard Worker kPipelineCreationRaceCount);
92*c8dee2aaSAndroid Build Coastguard Worker #endif
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker return *entry;
95*c8dee2aaSAndroid Build Coastguard Worker }
96*c8dee2aaSAndroid Build Coastguard Worker
97*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
numGraphicsPipelines() const98*c8dee2aaSAndroid Build Coastguard Worker int GlobalCache::numGraphicsPipelines() const {
99*c8dee2aaSAndroid Build Coastguard Worker SkAutoSpinlock lock{fSpinLock};
100*c8dee2aaSAndroid Build Coastguard Worker
101*c8dee2aaSAndroid Build Coastguard Worker return fGraphicsPipelineCache.count();
102*c8dee2aaSAndroid Build Coastguard Worker }
103*c8dee2aaSAndroid Build Coastguard Worker
resetGraphicsPipelines()104*c8dee2aaSAndroid Build Coastguard Worker void GlobalCache::resetGraphicsPipelines() {
105*c8dee2aaSAndroid Build Coastguard Worker SkAutoSpinlock lock{fSpinLock};
106*c8dee2aaSAndroid Build Coastguard Worker
107*c8dee2aaSAndroid Build Coastguard Worker fGraphicsPipelineCache.reset();
108*c8dee2aaSAndroid Build Coastguard Worker }
109*c8dee2aaSAndroid Build Coastguard Worker
forEachGraphicsPipeline(const std::function<void (const UniqueKey &,const GraphicsPipeline *)> & fn)110*c8dee2aaSAndroid Build Coastguard Worker void GlobalCache::forEachGraphicsPipeline(
111*c8dee2aaSAndroid Build Coastguard Worker const std::function<void(const UniqueKey&, const GraphicsPipeline*)>& fn) {
112*c8dee2aaSAndroid Build Coastguard Worker SkAutoSpinlock lock{fSpinLock};
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker fGraphicsPipelineCache.foreach([&](const UniqueKey* k, const sk_sp<GraphicsPipeline>* v) {
115*c8dee2aaSAndroid Build Coastguard Worker fn(*k, v->get());
116*c8dee2aaSAndroid Build Coastguard Worker });
117*c8dee2aaSAndroid Build Coastguard Worker }
118*c8dee2aaSAndroid Build Coastguard Worker
getStats() const119*c8dee2aaSAndroid Build Coastguard Worker GlobalCache::PipelineStats GlobalCache::getStats() const {
120*c8dee2aaSAndroid Build Coastguard Worker SkAutoSpinlock lock{fSpinLock};
121*c8dee2aaSAndroid Build Coastguard Worker
122*c8dee2aaSAndroid Build Coastguard Worker return fStats;
123*c8dee2aaSAndroid Build Coastguard Worker }
124*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(GPU_TEST_UTILS)
125*c8dee2aaSAndroid Build Coastguard Worker
findComputePipeline(const UniqueKey & key)126*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ComputePipeline> GlobalCache::findComputePipeline(const UniqueKey& key) {
127*c8dee2aaSAndroid Build Coastguard Worker SkAutoSpinlock lock{fSpinLock};
128*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ComputePipeline>* entry = fComputePipelineCache.find(key);
129*c8dee2aaSAndroid Build Coastguard Worker return entry ? *entry : nullptr;
130*c8dee2aaSAndroid Build Coastguard Worker }
131*c8dee2aaSAndroid Build Coastguard Worker
addComputePipeline(const UniqueKey & key,sk_sp<ComputePipeline> pipeline)132*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ComputePipeline> GlobalCache::addComputePipeline(const UniqueKey& key,
133*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ComputePipeline> pipeline) {
134*c8dee2aaSAndroid Build Coastguard Worker SkAutoSpinlock lock{fSpinLock};
135*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ComputePipeline>* entry = fComputePipelineCache.find(key);
136*c8dee2aaSAndroid Build Coastguard Worker if (!entry) {
137*c8dee2aaSAndroid Build Coastguard Worker entry = fComputePipelineCache.insert(key, std::move(pipeline));
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker return *entry;
140*c8dee2aaSAndroid Build Coastguard Worker }
141*c8dee2aaSAndroid Build Coastguard Worker
addStaticResource(sk_sp<Resource> resource)142*c8dee2aaSAndroid Build Coastguard Worker void GlobalCache::addStaticResource(sk_sp<Resource> resource) {
143*c8dee2aaSAndroid Build Coastguard Worker SkAutoSpinlock lock{fSpinLock};
144*c8dee2aaSAndroid Build Coastguard Worker fStaticResource.push_back(std::move(resource));
145*c8dee2aaSAndroid Build Coastguard Worker }
146*c8dee2aaSAndroid Build Coastguard Worker
147*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
148