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 Entry(GrVkGpu* gpu, GrVkPipelineState* pipelineState) 26 : fGpu(gpu) 27 , fPipelineState(pipelineState) {} 28 29 ~Entry() { 30 if (fPipelineState) { 31 fPipelineState->freeGPUResources(fGpu); 32 } 33 } 34 35 GrVkGpu* fGpu; 36 std::unique_ptr<GrVkPipelineState> fPipelineState; 37}; 38 39GrVkResourceProvider::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 48GrVkResourceProvider::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 64void 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 72void GrVkResourceProvider::PipelineStateCache::release() { 73 fMap.reset(); 74} 75 76GrVkPipelineState* 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