blob: f051ff641bdcb29e3b5296a19eb15dfdfc5e7db9 [file] [log] [blame]
/*
* 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 "include/gpu/GrDirectContext.h"
#include "src/core/SkOpts.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/GrProcessor.h"
#include "src/gpu/GrRenderTarget.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 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<GrVkPipelineState> 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());
SkASSERT(renderTarget->numStencilBits(renderTarget->numSamples() > 1) == 8);
SkASSERT(renderTarget->getStencilAttachment()->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>* 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<Entry>(fGpu, pipelineState));
return (*entry)->fPipelineState.get();
}
return (*entry)->fPipelineState.get();
}