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 "GrVkResourceProvider.h"
9 
10 #include "GrVkGpu.h"
11 #include "GrProcessor.h"
12 #include "GrRenderTargetPriv.h" // TODO: remove once refPipelineState gets passed stencil settings.
13 #include "GrVkPipelineState.h"
14 #include "GrVkPipelineStateBuilder.h"
15 #include "SkOpts.h"
16 #include "glsl/GrGLSLFragmentProcessor.h"
17 #include "glsl/GrGLSLProgramDataManager.h"
18 
19 #ifdef GR_PIPELINE_STATE_CACHE_STATS
20 // Display pipeline state cache usage
21 static const bool c_DisplayVkPipelineCache{false};
22 #endif
23 
24 struct GrVkResourceProvider::PipelineStateCache::Entry {
EntryGrVkResourceProvider::PipelineStateCache::Entry25     Entry(GrVkGpu* gpu, GrVkPipelineState* pipelineState)
26     : fGpu(gpu)
27     , fPipelineState(pipelineState) {}
28 
~EntryGrVkResourceProvider::PipelineStateCache::Entry29     ~Entry() {
30         if (fPipelineState) {
31             fPipelineState->freeGPUResources(fGpu);
32         }
33     }
34 
35     GrVkGpu* fGpu;
36     std::unique_ptr<GrVkPipelineState> fPipelineState;
37 };
38 
PipelineStateCache(GrVkGpu * gpu)39 GrVkResourceProvider::PipelineStateCache::PipelineStateCache(GrVkGpu* gpu)
40     : fMap(kMaxEntries)
41     , fGpu(gpu)
42 #ifdef GR_PIPELINE_STATE_CACHE_STATS
43     , fTotalRequests(0)
44     , fCacheMisses(0)
45 #endif
46 {}
47 
~PipelineStateCache()48 GrVkResourceProvider::PipelineStateCache::~PipelineStateCache() {
49     SkASSERT(0 == fMap.count());
50     // dump stats
51 #ifdef GR_PIPELINE_STATE_CACHE_STATS
52     if (c_DisplayVkPipelineCache) {
53         SkDebugf("--- Pipeline State Cache ---\n");
54         SkDebugf("Total requests: %d\n", fTotalRequests);
55         SkDebugf("Cache misses: %d\n", fCacheMisses);
56         SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ?
57                  100.f * fCacheMisses / fTotalRequests :
58                  0.f);
59         SkDebugf("---------------------\n");
60     }
61 #endif
62 }
63 
abandon()64 void GrVkResourceProvider::PipelineStateCache::abandon() {
65     fMap.foreach([](std::unique_ptr<Entry>* e) {
66         (*e)->fPipelineState->abandonGPUResources();
67         (*e)->fPipelineState = nullptr;
68     });
69     fMap.reset();
70 }
71 
release()72 void GrVkResourceProvider::PipelineStateCache::release() {
73     fMap.reset();
74 }
75 
refPipelineState(const GrPipeline & pipeline,const GrPrimitiveProcessor & primProc,GrPrimitiveType primitiveType,const GrVkRenderPass & renderPass)76 GrVkPipelineState* GrVkResourceProvider::PipelineStateCache::refPipelineState(
77                                                                const GrPipeline& pipeline,
78                                                                const GrPrimitiveProcessor& primProc,
79                                                                GrPrimitiveType primitiveType,
80                                                                const GrVkRenderPass& renderPass) {
81 #ifdef GR_PIPELINE_STATE_CACHE_STATS
82     ++fTotalRequests;
83 #endif
84     GrStencilSettings stencil;
85     if (pipeline.isStencilEnabled()) {
86         GrRenderTarget* rt = pipeline.renderTarget();
87         // TODO: attach stencil and create settings during render target flush.
88         SkASSERT(rt->renderTargetPriv().getStencilAttachment());
89         stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(),
90                       rt->renderTargetPriv().numStencilBits());
91     }
92 
93     // Get GrVkProgramDesc
94     GrVkPipelineState::Desc desc;
95     if (!GrVkPipelineState::Desc::Build(&desc, primProc, pipeline, stencil,
96                                         primitiveType, *fGpu->caps()->shaderCaps())) {
97         GrCapsDebugf(fGpu->caps(), "Failed to build vk program descriptor!\n");
98         return nullptr;
99     }
100     desc.finalize();
101 
102     std::unique_ptr<Entry>* entry = fMap.find(desc);
103     if (!entry) {
104         // Didn't find an origin-independent version, check with the specific origin
105         GrSurfaceOrigin origin = pipeline.proxy()->origin();
106         desc.setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(origin));
107         desc.finalize();
108         entry = fMap.find(desc);
109     }
110     if (!entry) {
111 #ifdef GR_PIPELINE_STATE_CACHE_STATS
112         ++fCacheMisses;
113 #endif
114         GrVkPipelineState* pipelineState(
115             GrVkPipelineStateBuilder::CreatePipelineState(fGpu,
116                                                           pipeline,
117                                                           stencil,
118                                                           primProc,
119                                                           primitiveType,
120                                                           &desc,
121                                                           renderPass));
122         if (nullptr == pipelineState) {
123             return nullptr;
124         }
125         entry = fMap.insert(desc, std::unique_ptr<Entry>(new Entry(fGpu, pipelineState)));
126         return (*entry)->fPipelineState.get();
127     }
128     return (*entry)->fPipelineState.get();
129 }
130