/* * 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/ganesh/GrContextOptions.h" #include "include/gpu/ganesh/GrDirectContext.h" #include "include/private/base/SkAssert.h" #include "include/private/base/SkDebug.h" #include "include/private/gpu/ganesh/GrTypesPriv.h" #include "include/private/gpu/vk/SkiaVulkan.h" #include "src/core/SkLRUCache.h" #include "src/gpu/ganesh/GrAttachment.h" #include "src/gpu/ganesh/GrCaps.h" #include "src/gpu/ganesh/GrDirectContextPriv.h" #include "src/gpu/ganesh/GrProgramDesc.h" #include "src/gpu/ganesh/GrProgramInfo.h" #include "src/gpu/ganesh/GrRenderTarget.h" #include "src/gpu/ganesh/vk/GrVkGpu.h" #include "src/gpu/ganesh/vk/GrVkPipelineState.h" #include "src/gpu/ganesh/vk/GrVkPipelineStateBuilder.h" #include "src/gpu/ganesh/vk/GrVkResourceProvider.h" #include #ifdef SK_DEBUG // 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 fPipelineState; }; GrVkResourceProvider::PipelineStateCache::PipelineStateCache(GrVkGpu* gpu) : fMap(gpu->getContext()->priv().options().fRuntimeProgramCacheSize) , fGpu(gpu) { } GrVkResourceProvider::PipelineStateCache::~PipelineStateCache() { SkASSERT(0 == fMap.count()); // dump stats #ifdef SK_DEBUG if (c_DisplayVkPipelineCache) { using CacheResult = Stats::ProgramCacheResult; int misses = fStats.numInlineProgramCacheResult(CacheResult::kMiss) + fStats.numPreProgramCacheResult(CacheResult::kMiss); int total = misses + fStats.numInlineProgramCacheResult(CacheResult::kHit) + fStats.numPreProgramCacheResult(CacheResult::kHit); SkDebugf("--- Pipeline State Cache ---\n"); SkDebugf("Total requests: %d\n", total); SkDebugf("Cache misses: %d\n", misses); SkDebugf("Cache miss %%: %f\n", (total > 0) ? 100.f * misses / total : 0.0f); } #endif } void GrVkResourceProvider::PipelineStateCache::release() { fMap.reset(); } GrVkPipelineState* GrVkResourceProvider::PipelineStateCache::findOrCreatePipelineState( GrRenderTarget* renderTarget, const GrProgramInfo& programInfo, VkRenderPass compatibleRenderPass, bool overrideSubpassForResolveLoad) { #ifdef SK_DEBUG if (programInfo.isStencilEnabled()) { SkASSERT(renderTarget->getStencilAttachment(programInfo.numSamples() > 1)); SkASSERT(renderTarget->numStencilBits(programInfo.numSamples() > 1) == 8); SkASSERT(renderTarget->getStencilAttachment(programInfo.numSamples() > 1)->numSamples() == programInfo.numSamples()); } #endif auto flags = overrideSubpassForResolveLoad ? GrCaps::ProgramDescOverrideFlags::kVulkanHasResolveLoadSubpass : GrCaps::ProgramDescOverrideFlags::kNone; GrProgramDesc desc = fGpu->caps()->makeDesc(renderTarget, programInfo, flags); if (!desc.isValid()) { GrCapsDebugf(fGpu->caps(), "Failed to build vk program descriptor!\n"); return nullptr; } Stats::ProgramCacheResult stat; auto tmp = this->findOrCreatePipelineStateImpl(desc, programInfo, compatibleRenderPass, overrideSubpassForResolveLoad, &stat); if (!tmp) { fStats.incNumInlineCompilationFailures(); } else { fStats.incNumInlineProgramCacheResult(stat); } return tmp; } GrVkPipelineState* GrVkResourceProvider::PipelineStateCache::findOrCreatePipelineStateImpl( const GrProgramDesc& desc, const GrProgramInfo& programInfo, VkRenderPass compatibleRenderPass, bool overrideSubpassForResolveLoad, Stats::ProgramCacheResult* stat) { if (stat) { *stat = Stats::ProgramCacheResult::kHit; } std::unique_ptr* entry = fMap.find(desc); if (!entry) { if (stat) { *stat = Stats::ProgramCacheResult::kMiss; } GrVkPipelineState* pipelineState(GrVkPipelineStateBuilder::CreatePipelineState( fGpu, desc, programInfo, compatibleRenderPass, overrideSubpassForResolveLoad)); if (!pipelineState) { return nullptr; } entry = fMap.insert(desc, std::make_unique(fGpu, pipelineState)); return (*entry)->fPipelineState.get(); } return (*entry)->fPipelineState.get(); }