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 "src/core/SkOpts.h"
11 #include "src/gpu/GrContextPriv.h"
12 #include "src/gpu/GrProcessor.h"
13 #include "src/gpu/GrRenderTargetPriv.h"
14 #include "src/gpu/GrStencilSettings.h"
15 #include "src/gpu/glsl/GrGLSLFragmentProcessor.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 GR_PIPELINE_STATE_CACHE_STATS
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 GR_PIPELINE_STATE_CACHE_STATS
46     , fTotalRequests(0)
47     , fCacheMisses(0)
48 #endif
49 {}
50 
~PipelineStateCache()51 GrVkResourceProvider::PipelineStateCache::~PipelineStateCache() {
52     SkASSERT(0 == fMap.count());
53     // dump stats
54 #ifdef GR_PIPELINE_STATE_CACHE_STATS
55     if (c_DisplayVkPipelineCache) {
56         SkDebugf("--- Pipeline State Cache ---\n");
57         SkDebugf("Total requests: %d\n", fTotalRequests);
58         SkDebugf("Cache misses: %d\n", fCacheMisses);
59         SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ?
60                  100.f * fCacheMisses / fTotalRequests :
61                  0.f);
62         SkDebugf("---------------------\n");
63     }
64 #endif
65 }
66 
abandon()67 void GrVkResourceProvider::PipelineStateCache::abandon() {
68     fMap.foreach([](std::unique_ptr<Entry>* e) {
69         (*e)->fPipelineState->abandonGPUResources();
70         (*e)->fPipelineState = nullptr;
71     });
72     fMap.reset();
73 }
74 
release()75 void GrVkResourceProvider::PipelineStateCache::release() {
76     fMap.reset();
77 }
78 
refPipelineState(GrRenderTarget * renderTarget,const GrProgramInfo & programInfo,GrPrimitiveType primitiveType,VkRenderPass compatibleRenderPass)79 GrVkPipelineState* GrVkResourceProvider::PipelineStateCache::refPipelineState(
80         GrRenderTarget* renderTarget,
81         const GrProgramInfo& programInfo,
82         GrPrimitiveType primitiveType,
83         VkRenderPass compatibleRenderPass) {
84 #ifdef GR_PIPELINE_STATE_CACHE_STATS
85     ++fTotalRequests;
86 #endif
87     GrStencilSettings stencil;
88     if (programInfo.pipeline().isStencilEnabled()) {
89         // TODO: attach stencil and create settings during render target flush.
90         SkASSERT(renderTarget->renderTargetPriv().getStencilAttachment());
91         stencil.reset(*programInfo.pipeline().getUserStencil(),
92                       programInfo.pipeline().hasStencilClip(),
93                       renderTarget->renderTargetPriv().numStencilBits());
94     }
95 
96     // TODO: can this be unified between GL, Vk and Mtl?
97     // Get GrVkProgramDesc
98     GrVkPipelineStateBuilder::Desc desc;
99     if (!GrVkPipelineStateBuilder::Desc::Build(&desc, renderTarget, programInfo, stencil,
100                                                primitiveType, fGpu)) {
101         GrCapsDebugf(fGpu->caps(), "Failed to build vk program descriptor!\n");
102         return nullptr;
103     }
104 
105     std::unique_ptr<Entry>* entry = fMap.find(desc);
106     if (!entry) {
107 #ifdef GR_PIPELINE_STATE_CACHE_STATS
108         ++fCacheMisses;
109 #endif
110         GrVkPipelineState* pipelineState(GrVkPipelineStateBuilder::CreatePipelineState(
111                 fGpu, renderTarget, programInfo,
112                 stencil, primitiveType, &desc, compatibleRenderPass));
113         if (!pipelineState) {
114             return nullptr;
115         }
116         entry = fMap.insert(desc, std::unique_ptr<Entry>(new Entry(fGpu, pipelineState)));
117         return (*entry)->fPipelineState.get();
118     }
119     return (*entry)->fPipelineState.get();
120 }
121