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