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