GrVkPipelineStateCache.cpp revision 1edc5b92fecefb79f01cf0e302646eacf32b06c7
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
21static const bool c_DisplayVkPipelineCache{false};
22#endif
23
24struct GrVkResourceProvider::PipelineStateCache::Entry {
25
26    Entry() : fPipelineState(nullptr) {}
27
28    static const GrVkPipelineState::Desc& GetKey(const Entry* entry) {
29        return entry->fPipelineState->getDesc();
30    }
31
32    static uint32_t Hash(const GrVkPipelineState::Desc& key) {
33        return key.getChecksum();
34    }
35
36    sk_sp<GrVkPipelineState> fPipelineState;
37
38private:
39    SK_DECLARE_INTERNAL_LLIST_INTERFACE(Entry);
40};
41
42GrVkResourceProvider::PipelineStateCache::PipelineStateCache(GrVkGpu* gpu)
43    : fCount(0)
44    , fGpu(gpu)
45#ifdef GR_PIPELINE_STATE_CACHE_STATS
46    , fTotalRequests(0)
47    , fCacheMisses(0)
48#endif
49{}
50
51GrVkResourceProvider::PipelineStateCache::~PipelineStateCache() {
52    SkASSERT(0 == fCount);
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
67void GrVkResourceProvider::PipelineStateCache::reset() {
68    fHashTable.foreach([](Entry** entry) {
69        delete *entry;
70    });
71    fHashTable.reset();
72    fCount = 0;
73}
74
75void GrVkResourceProvider::PipelineStateCache::abandon() {
76    fHashTable.foreach([](Entry** entry) {
77        SkASSERT((*entry)->fPipelineState.get());
78        (*entry)->fPipelineState->abandonGPUResources();
79    });
80
81    this->reset();
82}
83
84void GrVkResourceProvider::PipelineStateCache::release() {
85    fHashTable.foreach([this](Entry** entry) {
86        SkASSERT((*entry)->fPipelineState.get());
87        (*entry)->fPipelineState->freeGPUResources(fGpu);
88    });
89
90    this->reset();
91}
92
93sk_sp<GrVkPipelineState> GrVkResourceProvider::PipelineStateCache::refPipelineState(
94                                                               const GrPipeline& pipeline,
95                                                               const GrPrimitiveProcessor& primProc,
96                                                               GrPrimitiveType primitiveType,
97                                                               const GrVkRenderPass& renderPass) {
98#ifdef GR_PIPELINE_STATE_CACHE_STATS
99    ++fTotalRequests;
100#endif
101    GrStencilSettings stencil;
102    if (pipeline.isStencilEnabled()) {
103        GrRenderTarget* rt = pipeline.getRenderTarget();
104        // TODO: attach stencil and create settings during render target flush.
105        SkASSERT(rt->renderTargetPriv().getStencilAttachment());
106        stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(),
107                      rt->renderTargetPriv().numStencilBits());
108    }
109
110    // Get GrVkProgramDesc
111    GrVkPipelineState::Desc desc;
112    if (!GrVkPipelineState::Desc::Build(&desc, primProc, pipeline, stencil,
113                                        primitiveType, *fGpu->caps()->shaderCaps())) {
114        GrCapsDebugf(fGpu->caps(), "Failed to build vk program descriptor!\n");
115        return nullptr;
116    }
117    desc.finalize();
118
119    Entry* entry = nullptr;
120    if (Entry** entryptr = fHashTable.find(desc)) {
121        SkASSERT(*entryptr);
122        entry = *entryptr;
123    }
124    if (!entry) {
125#ifdef GR_PIPELINE_STATE_CACHE_STATS
126        ++fCacheMisses;
127#endif
128        sk_sp<GrVkPipelineState> pipelineState(
129            GrVkPipelineStateBuilder::CreatePipelineState(fGpu,
130                                                          pipeline,
131                                                          stencil,
132                                                          primProc,
133                                                          primitiveType,
134                                                          desc,
135                                                          renderPass));
136        if (nullptr == pipelineState) {
137            return nullptr;
138        }
139        if (fCount < kMaxEntries) {
140            entry = new Entry;
141            fCount++;
142        } else {
143            SkASSERT(fCount == kMaxEntries);
144            entry = fLRUList.head();
145            fLRUList.remove(entry);
146            entry->fPipelineState->freeGPUResources(fGpu);
147            fHashTable.remove(entry->fPipelineState->getDesc());
148        }
149        entry->fPipelineState = std::move(pipelineState);
150        fHashTable.set(entry);
151        fLRUList.addToTail(entry);
152        return entry->fPipelineState;
153    } else {
154        fLRUList.remove(entry);
155        fLRUList.addToTail(entry);
156    }
157    return entry->fPipelineState;
158}
159