| /* |
| * Copyright 2016 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| |
| #include "include/gpu/GrContextOptions.h" |
| #include "src/core/SkOpts.h" |
| #include "src/gpu/GrContextPriv.h" |
| #include "src/gpu/GrProcessor.h" |
| #include "src/gpu/GrRenderTargetPriv.h" |
| #include "src/gpu/GrStencilSettings.h" |
| #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" |
| #include "src/gpu/glsl/GrGLSLProgramDataManager.h" |
| #include "src/gpu/vk/GrVkGpu.h" |
| #include "src/gpu/vk/GrVkPipelineState.h" |
| #include "src/gpu/vk/GrVkPipelineStateBuilder.h" |
| #include "src/gpu/vk/GrVkResourceProvider.h" |
| |
| #ifdef GR_PIPELINE_STATE_CACHE_STATS |
| // Display pipeline state cache usage |
| static const bool c_DisplayVkPipelineCache{false}; |
| #endif |
| |
| struct GrVkResourceProvider::PipelineStateCache::Entry { |
| Entry(GrVkGpu* gpu, GrVkPipelineState* pipelineState) |
| : fGpu(gpu) |
| , fPipelineState(pipelineState) {} |
| |
| ~Entry() { |
| if (fPipelineState) { |
| fPipelineState->freeGPUResources(fGpu); |
| } |
| } |
| |
| GrVkGpu* fGpu; |
| std::unique_ptr<GrVkPipelineState> fPipelineState; |
| }; |
| |
| GrVkResourceProvider::PipelineStateCache::PipelineStateCache(GrVkGpu* gpu) |
| : fMap(gpu->getContext()->priv().options().fRuntimeProgramCacheSize) |
| , fGpu(gpu) |
| #ifdef GR_PIPELINE_STATE_CACHE_STATS |
| , fTotalRequests(0) |
| , fCacheMisses(0) |
| #endif |
| {} |
| |
| GrVkResourceProvider::PipelineStateCache::~PipelineStateCache() { |
| SkASSERT(0 == fMap.count()); |
| // dump stats |
| #ifdef GR_PIPELINE_STATE_CACHE_STATS |
| if (c_DisplayVkPipelineCache) { |
| SkDebugf("--- Pipeline State Cache ---\n"); |
| SkDebugf("Total requests: %d\n", fTotalRequests); |
| SkDebugf("Cache misses: %d\n", fCacheMisses); |
| SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ? |
| 100.f * fCacheMisses / fTotalRequests : |
| 0.f); |
| SkDebugf("---------------------\n"); |
| } |
| #endif |
| } |
| |
| void GrVkResourceProvider::PipelineStateCache::abandon() { |
| fMap.foreach([](std::unique_ptr<Entry>* e) { |
| (*e)->fPipelineState->abandonGPUResources(); |
| (*e)->fPipelineState = nullptr; |
| }); |
| fMap.reset(); |
| } |
| |
| void GrVkResourceProvider::PipelineStateCache::release() { |
| fMap.reset(); |
| } |
| |
| GrVkPipelineState* GrVkResourceProvider::PipelineStateCache::refPipelineState( |
| GrRenderTarget* renderTarget, |
| const GrProgramInfo& programInfo, |
| GrPrimitiveType primitiveType, |
| VkRenderPass compatibleRenderPass) { |
| #ifdef GR_PIPELINE_STATE_CACHE_STATS |
| ++fTotalRequests; |
| #endif |
| GrStencilSettings stencil; |
| if (programInfo.pipeline().isStencilEnabled()) { |
| // TODO: attach stencil and create settings during render target flush. |
| SkASSERT(renderTarget->renderTargetPriv().getStencilAttachment()); |
| stencil.reset(*programInfo.pipeline().getUserStencil(), |
| programInfo.pipeline().hasStencilClip(), |
| renderTarget->renderTargetPriv().numStencilBits()); |
| } |
| |
| // TODO: can this be unified between GL, Vk and Mtl? |
| // Get GrVkProgramDesc |
| GrVkPipelineStateBuilder::Desc desc; |
| if (!GrVkPipelineStateBuilder::Desc::Build(&desc, renderTarget, programInfo, stencil, |
| primitiveType, fGpu)) { |
| GrCapsDebugf(fGpu->caps(), "Failed to build vk program descriptor!\n"); |
| return nullptr; |
| } |
| |
| std::unique_ptr<Entry>* entry = fMap.find(desc); |
| if (!entry) { |
| #ifdef GR_PIPELINE_STATE_CACHE_STATS |
| ++fCacheMisses; |
| #endif |
| GrVkPipelineState* pipelineState(GrVkPipelineStateBuilder::CreatePipelineState( |
| fGpu, renderTarget, programInfo, |
| stencil, primitiveType, &desc, compatibleRenderPass)); |
| if (!pipelineState) { |
| return nullptr; |
| } |
| entry = fMap.insert(desc, std::unique_ptr<Entry>(new Entry(fGpu, pipelineState))); |
| return (*entry)->fPipelineState.get(); |
| } |
| return (*entry)->fPipelineState.get(); |
| } |