blob: 9708978be495b09a46427e3fb5c6e18e23edf516 [file] [log] [blame]
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrMtlResourceProvider.h"
#include "GrMtlCopyManager.h"
#include "GrMtlGpu.h"
#include "GrMtlPipelineState.h"
#include "GrMtlUtil.h"
#include "SkSLCompiler.h"
GrMtlResourceProvider::GrMtlResourceProvider(GrMtlGpu* gpu)
: fGpu(gpu) {
fPipelineStateCache.reset(new PipelineStateCache(gpu));
}
GrMtlCopyPipelineState* GrMtlResourceProvider::findOrCreateCopyPipelineState(
MTLPixelFormat dstPixelFormat,
id<MTLFunction> vertexFunction,
id<MTLFunction> fragmentFunction,
MTLVertexDescriptor* vertexDescriptor) {
for (const auto& copyPipelineState: fCopyPipelineStateCache) {
if (GrMtlCopyManager::IsCompatible(copyPipelineState.get(), dstPixelFormat)) {
return copyPipelineState.get();
}
}
fCopyPipelineStateCache.emplace_back(GrMtlCopyPipelineState::CreateCopyPipelineState(
fGpu, dstPixelFormat, vertexFunction, fragmentFunction, vertexDescriptor));
return fCopyPipelineStateCache.back().get();
}
GrMtlPipelineState* GrMtlResourceProvider::findOrCreateCompatiblePipelineState(
GrRenderTarget* renderTarget, GrSurfaceOrigin origin,
const GrPipeline& pipeline, const GrPrimitiveProcessor& proc,
const GrTextureProxy* const primProcProxies[], GrPrimitiveType primType) {
return fPipelineStateCache->refPipelineState(renderTarget, origin, proc, primProcProxies,
pipeline, primType);
}
////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef GR_PIPELINE_STATE_CACHE_STATS
// Display pipeline state cache usage
static const bool c_DisplayMtlPipelineCache{false};
#endif
struct GrMtlResourceProvider::PipelineStateCache::Entry {
Entry(GrMtlGpu* gpu, GrMtlPipelineState* pipelineState)
: fGpu(gpu)
, fPipelineState(pipelineState) {}
GrMtlGpu* fGpu;
std::unique_ptr<GrMtlPipelineState> fPipelineState;
};
GrMtlResourceProvider::PipelineStateCache::PipelineStateCache(GrMtlGpu* gpu)
: fMap(kMaxEntries)
, fGpu(gpu)
#ifdef GR_PIPELINE_STATE_CACHE_STATS
, fTotalRequests(0)
, fCacheMisses(0)
#endif
{}
GrMtlResourceProvider::PipelineStateCache::~PipelineStateCache() {
// TODO: determine if we need abandon/release methods
fMap.reset();
// dump stats
#ifdef GR_PIPELINE_STATE_CACHE_STATS
if (c_DisplayMtlPipelineCache) {
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
}
GrMtlPipelineState* GrMtlResourceProvider::PipelineStateCache::refPipelineState(
GrRenderTarget* renderTarget,
GrSurfaceOrigin origin,
const GrPrimitiveProcessor& primProc,
const GrTextureProxy* const primProcProxies[],
const GrPipeline& pipeline,
GrPrimitiveType primType) {
#ifdef GR_PIPELINE_STATE_CACHE_STATS
++fTotalRequests;
#endif
// Get GrMtlProgramDesc
GrMtlPipelineStateBuilder::Desc desc;
if (!GrMtlPipelineStateBuilder::Desc::Build(&desc, renderTarget, primProc, pipeline, primType,
fGpu)) {
GrCapsDebugf(fGpu->caps(), "Failed to build mtl program descriptor!\n");
return nullptr;
}
std::unique_ptr<Entry>* entry = fMap.find(desc);
if (!entry) {
// Didn't find an origin-independent version, check with the specific origin
desc.setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(origin));
entry = fMap.find(desc);
}
if (!entry) {
#ifdef GR_PIPELINE_STATE_CACHE_STATS
++fCacheMisses;
#endif
GrMtlPipelineState* pipelineState(GrMtlPipelineStateBuilder::CreatePipelineState(
fGpu, renderTarget, origin, primProc, primProcProxies, pipeline, &desc));
if (nullptr == pipelineState) {
return nullptr;
}
entry = fMap.insert(desc, std::unique_ptr<Entry>(new Entry(fGpu, pipelineState)));
return (*entry)->fPipelineState.get();
}
return (*entry)->fPipelineState.get();
}