1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/gpu/GrContextOptions.h"
9 #include "include/gpu/GrDirectContext.h"
10 #include "src/core/SkOpts.h"
11 #include "src/gpu/GrDirectContextPriv.h"
12 #include "src/gpu/GrFragmentProcessor.h"
13 #include "src/gpu/GrProcessor.h"
14 #include "src/gpu/GrRenderTarget.h"
15 #include "src/gpu/GrStencilSettings.h"
16 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
17 #include "src/gpu/vk/GrVkGpu.h"
18 #include "src/gpu/vk/GrVkPipelineState.h"
19 #include "src/gpu/vk/GrVkPipelineStateBuilder.h"
20 #include "src/gpu/vk/GrVkResourceProvider.h"
21
22 #ifdef SK_DEBUG
23 // Display pipeline state cache usage
24 static const bool c_DisplayVkPipelineCache{false};
25 #endif
26
27 struct GrVkResourceProvider::PipelineStateCache::Entry {
EntryGrVkResourceProvider::PipelineStateCache::Entry28 Entry(GrVkGpu* gpu, GrVkPipelineState* pipelineState)
29 : fGpu(gpu)
30 , fPipelineState(pipelineState) {}
31
~EntryGrVkResourceProvider::PipelineStateCache::Entry32 ~Entry() {
33 if (fPipelineState) {
34 fPipelineState->freeGPUResources(fGpu);
35 }
36 }
37
38 GrVkGpu* fGpu;
39 std::unique_ptr<GrVkPipelineState> fPipelineState;
40 };
41
PipelineStateCache(GrVkGpu * gpu)42 GrVkResourceProvider::PipelineStateCache::PipelineStateCache(GrVkGpu* gpu)
43 : fMap(gpu->getContext()->priv().options().fRuntimeProgramCacheSize)
44 , fGpu(gpu) {
45 #ifdef SKIA_DFX_FOR_OHOS
46 fStats.setPipelineCountMax(gpu->getContext()->priv().options().fRuntimeProgramCacheSize);
47 #endif
48 }
49
~PipelineStateCache()50 GrVkResourceProvider::PipelineStateCache::~PipelineStateCache() {
51 SkASSERT(0 == fMap.count());
52 // dump stats
53 #ifdef SK_DEBUG
54 if (c_DisplayVkPipelineCache) {
55 using CacheResult = Stats::ProgramCacheResult;
56
57 int misses = fStats.numInlineProgramCacheResult(CacheResult::kMiss) +
58 fStats.numPreProgramCacheResult(CacheResult::kMiss);
59
60 int total = misses + fStats.numInlineProgramCacheResult(CacheResult::kHit) +
61 fStats.numPreProgramCacheResult(CacheResult::kHit);
62
63 SkDebugf("--- Pipeline State Cache ---\n");
64 SkDebugf("Total requests: %d\n", total);
65 SkDebugf("Cache misses: %d\n", misses);
66 SkDebugf("Cache miss %%: %f\n", (total > 0) ? 100.f * misses / total : 0.0f);
67 }
68 #endif
69 }
70
release()71 void GrVkResourceProvider::PipelineStateCache::release() {
72 fMap.reset();
73 }
74
findOrCreatePipelineState(GrRenderTarget * renderTarget,const GrProgramInfo & programInfo,VkRenderPass compatibleRenderPass,bool overrideSubpassForResolveLoad)75 GrVkPipelineState* GrVkResourceProvider::PipelineStateCache::findOrCreatePipelineState(
76 GrRenderTarget* renderTarget,
77 const GrProgramInfo& programInfo,
78 VkRenderPass compatibleRenderPass,
79 bool overrideSubpassForResolveLoad) {
80 #ifdef SK_DEBUG
81 if (programInfo.isStencilEnabled()) {
82 SkASSERT(renderTarget->getStencilAttachment(programInfo.numSamples() > 1));
83 SkASSERT(renderTarget->numStencilBits(programInfo.numSamples() > 1) == 8);
84 SkASSERT(renderTarget->getStencilAttachment(programInfo.numSamples() > 1)->numSamples() ==
85 programInfo.numSamples());
86 }
87 #endif
88
89 auto flags = overrideSubpassForResolveLoad
90 ? GrCaps::ProgramDescOverrideFlags::kVulkanHasResolveLoadSubpass
91 : GrCaps::ProgramDescOverrideFlags::kNone;
92
93 GrProgramDesc desc = fGpu->caps()->makeDesc(renderTarget, programInfo, flags);
94 if (!desc.isValid()) {
95 GrCapsDebugf(fGpu->caps(), "Failed to build vk program descriptor!\n");
96 return nullptr;
97 }
98
99 Stats::ProgramCacheResult stat;
100 auto tmp = this->findOrCreatePipelineStateImpl(desc, programInfo, compatibleRenderPass,
101 overrideSubpassForResolveLoad, &stat);
102 if (!tmp) {
103 fStats.incNumInlineCompilationFailures();
104 } else {
105 fStats.incNumInlineProgramCacheResult(stat);
106 }
107 #ifdef SKIA_DFX_FOR_OHOS
108 fStats.updatePipelineCount(fMap.count());
109 #endif
110 return tmp;
111 }
112
findOrCreatePipelineStateImpl(const GrProgramDesc & desc,const GrProgramInfo & programInfo,VkRenderPass compatibleRenderPass,bool overrideSubpassForResolveLoad,Stats::ProgramCacheResult * stat)113 GrVkPipelineState* GrVkResourceProvider::PipelineStateCache::findOrCreatePipelineStateImpl(
114 const GrProgramDesc& desc,
115 const GrProgramInfo& programInfo,
116 VkRenderPass compatibleRenderPass,
117 bool overrideSubpassForResolveLoad,
118 Stats::ProgramCacheResult* stat) {
119 if (stat) {
120 *stat = Stats::ProgramCacheResult::kHit;
121 }
122
123 std::unique_ptr<Entry>* entry = fMap.find(desc);
124 if (!entry) {
125 if (stat) {
126 *stat = Stats::ProgramCacheResult::kMiss;
127 }
128 GrVkPipelineState* pipelineState(GrVkPipelineStateBuilder::CreatePipelineState(
129 fGpu, desc, programInfo, compatibleRenderPass, overrideSubpassForResolveLoad));
130 if (!pipelineState) {
131 return nullptr;
132 }
133 entry = fMap.insert(desc, std::make_unique<Entry>(fGpu, pipelineState));
134 return (*entry)->fPipelineState.get();
135 }
136 return (*entry)->fPipelineState.get();
137 }
138