Add GrMtlPipelineStateCache.
Allows us to cache MTLRenderPipelines rather than regenerating them for every use. Bug: skia: Change-Id: I3357d3bc6d644074bd9d544a8d5205af56d918e5 Reviewed-on: https://skia-review.googlesource.com/c/195127 Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
a8c728f080
commit
1223e7fc0a
@ -106,3 +106,20 @@ GrPipeline::GrPipeline(GrScissorTest scissorTest, SkBlendMode blendmode)
|
||||
fFlags |= kScissorEnabled_Flag;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GrPipeline::getBlendInfoKey() const {
|
||||
GrXferProcessor::BlendInfo blendInfo;
|
||||
this->getXferProcessor().getBlendInfo(&blendInfo);
|
||||
|
||||
static const uint32_t kBlendWriteShift = 1;
|
||||
static const uint32_t kBlendCoeffShift = 5;
|
||||
GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << kBlendCoeffShift));
|
||||
GR_STATIC_ASSERT(kFirstAdvancedGrBlendEquation - 1 < 4);
|
||||
|
||||
uint32_t key = blendInfo.fWriteColor;
|
||||
key |= (blendInfo.fSrcBlend << kBlendWriteShift);
|
||||
key |= (blendInfo.fDstBlend << (kBlendWriteShift + kBlendCoeffShift));
|
||||
key |= (blendInfo.fEquation << (kBlendWriteShift + 2 * kBlendCoeffShift));
|
||||
|
||||
return key;
|
||||
}
|
||||
|
@ -195,6 +195,9 @@ public:
|
||||
return SkString("No pipeline flags\n");
|
||||
}
|
||||
|
||||
// Used by Vulkan and Metal to cache their respective pipeline objects
|
||||
uint32_t getBlendInfoKey() const;
|
||||
|
||||
private:
|
||||
void markAsBad() { fFlags |= kIsBad_Flag; }
|
||||
|
||||
|
@ -73,8 +73,7 @@ private:
|
||||
const GrPrimitiveProcessor& primProc,
|
||||
const GrPipeline& pipeline,
|
||||
const GrPipeline::FixedDynamicState* fixedDynamicState,
|
||||
const GrMesh meshes[],
|
||||
int meshCount);
|
||||
GrPrimitiveType primType);
|
||||
|
||||
void onDraw(const GrPrimitiveProcessor& primProc,
|
||||
const GrPipeline& pipeline,
|
||||
|
@ -108,21 +108,8 @@ GrMtlPipelineState* GrMtlGpuRTCommandBuffer::prepareDrawState(
|
||||
const GrPrimitiveProcessor& primProc,
|
||||
const GrPipeline& pipeline,
|
||||
const GrPipeline::FixedDynamicState* fixedDynamicState,
|
||||
const GrMesh meshes[],
|
||||
int meshCount) {
|
||||
GrPrimitiveType primType) {
|
||||
// TODO: resolve textures and regenerate mipmaps as needed
|
||||
bool hasPoints = false;
|
||||
for (int i = 0; i < meshCount; ++i) {
|
||||
if (meshes[i].primitiveType() == GrPrimitiveType::kPoints) {
|
||||
hasPoints = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
GrProgramDesc desc;
|
||||
if (!GrProgramDesc::Build(&desc, fRenderTarget->config(), primProc, hasPoints,
|
||||
pipeline, fGpu)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const GrTextureProxy* const* primProcProxies = nullptr;
|
||||
if (fixedDynamicState) {
|
||||
@ -130,17 +117,19 @@ GrMtlPipelineState* GrMtlGpuRTCommandBuffer::prepareDrawState(
|
||||
}
|
||||
SkASSERT(SkToBool(primProcProxies) == SkToBool(primProc.numTextureSamplers()));
|
||||
|
||||
// TODO: use resource provider for pipeline
|
||||
GrMtlPipelineState* pipelineState =
|
||||
GrMtlPipelineStateBuilder::CreatePipelineState(fRenderTarget, fOrigin, primProc,
|
||||
primProcProxies, pipeline,
|
||||
&desc, fGpu);
|
||||
fGpu->resourceProvider().findOrCreateCompatiblePipelineState(fRenderTarget, fOrigin,
|
||||
pipeline,
|
||||
primProc,
|
||||
primProcProxies,
|
||||
primType);
|
||||
if (!pipelineState) {
|
||||
return nullptr;
|
||||
}
|
||||
// We cannot have an active encoder when we set the pipeline data since it requires its own
|
||||
// command encoder.
|
||||
SkASSERT(fActiveRenderCmdEncoder == nil);
|
||||
// TODO: this doesn't appear to be true -- we only use a command encoder here
|
||||
// SkASSERT(fActiveRenderCmdEncoder == nil);
|
||||
pipelineState->setData(fRenderTarget, fOrigin, primProc, pipeline, primProcProxies);
|
||||
|
||||
return pipelineState;
|
||||
@ -160,15 +149,16 @@ void GrMtlGpuRTCommandBuffer::onDraw(const GrPrimitiveProcessor& primProc,
|
||||
return; // TODO: ScissorRects are not supported.
|
||||
}
|
||||
|
||||
std::unique_ptr<GrMtlPipelineState> pipelineState(
|
||||
this->prepareDrawState(primProc, pipeline, fixedDynamicState, meshes, meshCount));
|
||||
GrPrimitiveType primitiveType = meshes[0].primitiveType();
|
||||
GrMtlPipelineState* pipelineState = this->prepareDrawState(primProc, pipeline,
|
||||
fixedDynamicState, primitiveType);
|
||||
if (!pipelineState) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->internalBegin();
|
||||
[fActiveRenderCmdEncoder setRenderPipelineState: pipelineState->mtlPipelineState()];
|
||||
|
||||
[fActiveRenderCmdEncoder setRenderPipelineState: pipelineState->mtlPipelineState()];
|
||||
pipelineState->bind(fActiveRenderCmdEncoder);
|
||||
pipelineState->setBlendConstants(fActiveRenderCmdEncoder, fRenderTarget->config(),
|
||||
pipeline.getXferProcessor());
|
||||
@ -176,9 +166,26 @@ void GrMtlGpuRTCommandBuffer::onDraw(const GrPrimitiveProcessor& primProc,
|
||||
|
||||
for (int i = 0; i < meshCount; ++i) {
|
||||
const GrMesh& mesh = meshes[i];
|
||||
SkASSERT(fActiveRenderCmdEncoder);
|
||||
SkASSERT(nil != fActiveRenderCmdEncoder);
|
||||
if (mesh.primitiveType() != primitiveType) {
|
||||
SkDEBUGCODE(pipelineState = nullptr);
|
||||
primitiveType = mesh.primitiveType();
|
||||
pipelineState = this->prepareDrawState(primProc, pipeline, fixedDynamicState,
|
||||
primitiveType);
|
||||
if (!pipelineState) {
|
||||
return;
|
||||
}
|
||||
|
||||
[fActiveRenderCmdEncoder setRenderPipelineState: pipelineState->mtlPipelineState()];
|
||||
pipelineState->bind(fActiveRenderCmdEncoder);
|
||||
pipelineState->setBlendConstants(fActiveRenderCmdEncoder, fRenderTarget->config(),
|
||||
pipeline.getXferProcessor());
|
||||
pipelineState->setDepthStencilState(fActiveRenderCmdEncoder);
|
||||
}
|
||||
|
||||
mesh.sendToGpu(this);
|
||||
}
|
||||
|
||||
this->internalEnd();
|
||||
fCommandBufferInfo.fBounds.join(bounds);
|
||||
}
|
||||
|
@ -22,28 +22,62 @@ class GrMtlPipelineState;
|
||||
|
||||
class GrMtlPipelineStateBuilder : public GrGLSLProgramBuilder {
|
||||
public:
|
||||
static GrMtlPipelineState* CreatePipelineState(GrRenderTarget*, GrSurfaceOrigin,
|
||||
/**
|
||||
* For Metal we want to cache the entire pipeline for reuse of draws. The Desc here holds all
|
||||
* the information needed to differentiate one pipeline from another.
|
||||
*
|
||||
* The GrProgramDesc contains all the information need to create the actual shaders for the
|
||||
* pipeline.
|
||||
*
|
||||
* For Metal we need to add to the GrProgramDesc to include the rest of the state on the
|
||||
* pipeline. This includes blending information and primitive type. The pipeline is immutable
|
||||
* so any remaining dynamic state is set via the MtlRenderCmdEncoder.
|
||||
*/
|
||||
class Desc : public GrProgramDesc {
|
||||
public:
|
||||
static bool Build(Desc*,
|
||||
GrRenderTarget*,
|
||||
const GrPrimitiveProcessor&,
|
||||
const GrPipeline&,
|
||||
GrPrimitiveType,
|
||||
GrMtlGpu* gpu);
|
||||
|
||||
size_t shaderKeyLength() const { return fShaderKeyLength; }
|
||||
|
||||
private:
|
||||
size_t fShaderKeyLength;
|
||||
|
||||
typedef GrProgramDesc INHERITED;
|
||||
};
|
||||
|
||||
/** Generates a pipeline state.
|
||||
*
|
||||
* The GrMtlPipelineState implements what is specified in the GrPipeline and
|
||||
* GrPrimitiveProcessor as input. After successful generation, the builder result objects are
|
||||
* available to be used. This function may modify the program key by setting the surface origin
|
||||
* key to 0 (unspecified) if it turns out the program does not care about the surface origin.
|
||||
* @return true if generation was successful.
|
||||
*/
|
||||
static GrMtlPipelineState* CreatePipelineState(GrMtlGpu*,
|
||||
GrRenderTarget*, GrSurfaceOrigin,
|
||||
const GrPrimitiveProcessor&,
|
||||
const GrTextureProxy* const primProcProxies[],
|
||||
const GrPipeline&,
|
||||
GrProgramDesc*,
|
||||
GrMtlGpu*);
|
||||
Desc*);
|
||||
|
||||
private:
|
||||
GrMtlPipelineStateBuilder(GrRenderTarget*, GrSurfaceOrigin,
|
||||
GrMtlPipelineStateBuilder(GrMtlGpu*, GrRenderTarget*, GrSurfaceOrigin,
|
||||
const GrPipeline&,
|
||||
const GrPrimitiveProcessor&,
|
||||
const GrTextureProxy* const primProcProxies[],
|
||||
const GrPipeline&,
|
||||
GrProgramDesc*, GrMtlGpu*);
|
||||
GrProgramDesc*);
|
||||
|
||||
GrMtlPipelineState* finalize(const GrPrimitiveProcessor& primProc,
|
||||
const GrPipeline& pipeline,
|
||||
Desc*);
|
||||
|
||||
const GrCaps* caps() const override;
|
||||
|
||||
GrGLSLUniformHandler* uniformHandler() override { return &fUniformHandler; }
|
||||
|
||||
const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; }
|
||||
|
||||
GrGLSLVaryingHandler* varyingHandler() override { return &fVaryingHandler; }
|
||||
|
||||
void finalizeFragmentOutputColor(GrShaderVar& outputColor) override;
|
||||
|
||||
void finalizeFragmentSecondaryColor(GrShaderVar& outputColor) override;
|
||||
@ -53,7 +87,9 @@ private:
|
||||
const SkSL::Program::Settings& settings,
|
||||
GrProgramDesc* desc);
|
||||
|
||||
GrMtlPipelineState* finalize(const GrPrimitiveProcessor&, const GrPipeline&, GrProgramDesc*);
|
||||
GrGLSLUniformHandler* uniformHandler() override { return &fUniformHandler; }
|
||||
const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; }
|
||||
GrGLSLVaryingHandler* varyingHandler() override { return &fVaryingHandler; }
|
||||
|
||||
GrMtlGpu* fGpu;
|
||||
GrMtlUniformHandler fUniformHandler;
|
||||
|
@ -17,14 +17,14 @@
|
||||
#import <simd/simd.h>
|
||||
|
||||
GrMtlPipelineState* GrMtlPipelineStateBuilder::CreatePipelineState(
|
||||
GrMtlGpu* gpu,
|
||||
GrRenderTarget* renderTarget, GrSurfaceOrigin origin,
|
||||
const GrPrimitiveProcessor& primProc,
|
||||
const GrTextureProxy* const primProcProxies[],
|
||||
const GrPipeline& pipeline,
|
||||
GrProgramDesc* desc,
|
||||
GrMtlGpu* gpu) {
|
||||
GrMtlPipelineStateBuilder builder(renderTarget, origin, primProc, primProcProxies, pipeline,
|
||||
desc, gpu);
|
||||
Desc* desc) {
|
||||
GrMtlPipelineStateBuilder builder(gpu, renderTarget, origin, pipeline, primProc,
|
||||
primProcProxies, desc);
|
||||
|
||||
if (!builder.emitAndInstallProcs()) {
|
||||
return nullptr;
|
||||
@ -32,12 +32,13 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::CreatePipelineState(
|
||||
return builder.finalize(primProc, pipeline, desc);
|
||||
}
|
||||
|
||||
GrMtlPipelineStateBuilder::GrMtlPipelineStateBuilder(GrRenderTarget* renderTarget, GrSurfaceOrigin origin,
|
||||
GrMtlPipelineStateBuilder::GrMtlPipelineStateBuilder(GrMtlGpu* gpu,
|
||||
GrRenderTarget* renderTarget,
|
||||
GrSurfaceOrigin origin,
|
||||
const GrPipeline& pipeline,
|
||||
const GrPrimitiveProcessor& primProc,
|
||||
const GrTextureProxy* const primProcProxies[],
|
||||
const GrPipeline& pipeline,
|
||||
GrProgramDesc* desc,
|
||||
GrMtlGpu* gpu)
|
||||
GrProgramDesc* desc)
|
||||
: INHERITED(renderTarget, origin, primProc, primProcProxies, pipeline, desc)
|
||||
, fGpu(gpu)
|
||||
, fUniformHandler(this)
|
||||
@ -316,7 +317,7 @@ uint32_t buffer_size(uint32_t offset, uint32_t maxAlignment) {
|
||||
|
||||
GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(const GrPrimitiveProcessor& primProc,
|
||||
const GrPipeline& pipeline,
|
||||
GrProgramDesc* desc) {
|
||||
Desc* desc) {
|
||||
auto pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||
|
||||
fVS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
|
||||
@ -332,6 +333,7 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(const GrPrimitiveProcess
|
||||
settings.fSharpenTextures = fGpu->getContext()->priv().options().fSharpenMipmappedTextures;
|
||||
SkASSERT(!this->fragColorIsInOut());
|
||||
|
||||
// TODO: Store shaders in cache
|
||||
id<MTLLibrary> vertexLibrary = nil;
|
||||
id<MTLLibrary> fragmentLibrary = nil;
|
||||
vertexLibrary = this->createMtlShaderLibrary(fVS,
|
||||
@ -354,6 +356,10 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(const GrPrimitiveProcess
|
||||
pipelineDescriptor.fragmentFunction = fragmentFunction;
|
||||
pipelineDescriptor.vertexDescriptor = create_vertex_descriptor(primProc);
|
||||
pipelineDescriptor.colorAttachments[0] = create_color_attachment(this->config(), pipeline);
|
||||
GrMtlCaps* mtlCaps = (GrMtlCaps*)this->caps();
|
||||
pipelineDescriptor.stencilAttachmentPixelFormat =
|
||||
pipeline.isStencilEnabled() ? mtlCaps->preferredStencilFormat().fInternalFormat
|
||||
: MTLPixelFormatInvalid;
|
||||
|
||||
SkASSERT(pipelineDescriptor.vertexFunction);
|
||||
SkASSERT(pipelineDescriptor.fragmentFunction);
|
||||
@ -392,3 +398,35 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(const GrPrimitiveProcess
|
||||
std::move(fFragmentProcessors),
|
||||
fFragmentProcessorCnt);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool GrMtlPipelineStateBuilder::Desc::Build(Desc* desc,
|
||||
GrRenderTarget* renderTarget,
|
||||
const GrPrimitiveProcessor& primProc,
|
||||
const GrPipeline& pipeline,
|
||||
GrPrimitiveType primitiveType,
|
||||
GrMtlGpu* gpu) {
|
||||
if (!INHERITED::Build(desc, renderTarget->config(), primProc,
|
||||
GrPrimitiveType::kLines == primitiveType, pipeline, gpu)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GrProcessorKeyBuilder b(&desc->key());
|
||||
|
||||
int keyLength = desc->key().count();
|
||||
SkASSERT(0 == (keyLength % 4));
|
||||
desc->fShaderKeyLength = SkToU32(keyLength);
|
||||
|
||||
b.add32(renderTarget->config());
|
||||
b.add32(renderTarget->numColorSamples());
|
||||
b.add32(pipeline.isStencilEnabled() ? gpu->mtlCaps().preferredStencilFormat().fInternalFormat
|
||||
: MTLPixelFormatInvalid);
|
||||
// Stencil samples don't seem to be tracked in the MTLRenderPipeline
|
||||
|
||||
b.add32(pipeline.getBlendInfoKey());
|
||||
|
||||
b.add32((uint32_t)primitiveType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
#define GrMtlResourceProvider_DEFINED
|
||||
|
||||
#include "GrMtlCopyPipelineState.h"
|
||||
#include "GrMtlPipelineStateBuilder.h"
|
||||
#include "SkLRUCache.h"
|
||||
#include "SkTArray.h"
|
||||
|
||||
#import <metal/metal.h>
|
||||
@ -17,17 +19,67 @@ class GrMtlGpu;
|
||||
|
||||
class GrMtlResourceProvider {
|
||||
public:
|
||||
GrMtlResourceProvider(GrMtlGpu* gpu) : fGpu(gpu) {}
|
||||
GrMtlResourceProvider(GrMtlGpu* gpu);
|
||||
|
||||
GrMtlCopyPipelineState* findOrCreateCopyPipelineState(MTLPixelFormat dstPixelFormat,
|
||||
id<MTLFunction> vertexFunction,
|
||||
id<MTLFunction> fragmentFunction,
|
||||
MTLVertexDescriptor* vertexDescriptor);
|
||||
|
||||
GrMtlPipelineState* findOrCreateCompatiblePipelineState(
|
||||
GrRenderTarget*, GrSurfaceOrigin,
|
||||
const GrPipeline&,
|
||||
const GrPrimitiveProcessor&,
|
||||
const GrTextureProxy* const primProcProxies[],
|
||||
GrPrimitiveType);
|
||||
|
||||
private:
|
||||
#ifdef SK_DEBUG
|
||||
#define GR_PIPELINE_STATE_CACHE_STATS
|
||||
#endif
|
||||
|
||||
class PipelineStateCache : public ::SkNoncopyable {
|
||||
public:
|
||||
PipelineStateCache(GrMtlGpu* gpu);
|
||||
~PipelineStateCache();
|
||||
|
||||
GrMtlPipelineState* refPipelineState(GrRenderTarget*, GrSurfaceOrigin,
|
||||
const GrPrimitiveProcessor&,
|
||||
const GrTextureProxy* const primProcProxies[],
|
||||
const GrPipeline&,
|
||||
GrPrimitiveType);
|
||||
|
||||
private:
|
||||
enum {
|
||||
// We may actually have kMaxEntries+1 PipelineStates in context because we create a new
|
||||
// PipelineState before evicting from the cache.
|
||||
kMaxEntries = 128,
|
||||
};
|
||||
|
||||
struct Entry;
|
||||
|
||||
struct DescHash {
|
||||
uint32_t operator()(const GrProgramDesc& desc) const {
|
||||
return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
SkLRUCache<const GrMtlPipelineStateBuilder::Desc, std::unique_ptr<Entry>, DescHash> fMap;
|
||||
|
||||
GrMtlGpu* fGpu;
|
||||
|
||||
#ifdef GR_PIPELINE_STATE_CACHE_STATS
|
||||
int fTotalRequests;
|
||||
int fCacheMisses;
|
||||
#endif
|
||||
};
|
||||
|
||||
SkTArray<std::unique_ptr<GrMtlCopyPipelineState>> fCopyPipelineStateCache;
|
||||
|
||||
GrMtlGpu* fGpu;
|
||||
|
||||
// Cache of GrMtlPipelineStates
|
||||
std::unique_ptr<PipelineStateCache> fPipelineStateCache;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -9,10 +9,17 @@
|
||||
|
||||
#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,
|
||||
@ -29,3 +36,92 @@ GrMtlCopyPipelineState* GrMtlResourceProvider::findOrCreateCopyPipelineState(
|
||||
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();
|
||||
}
|
||||
|
@ -374,23 +374,6 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32_t get_blend_info_key(const GrPipeline& pipeline) {
|
||||
GrXferProcessor::BlendInfo blendInfo;
|
||||
pipeline.getXferProcessor().getBlendInfo(&blendInfo);
|
||||
|
||||
static const uint32_t kBlendWriteShift = 1;
|
||||
static const uint32_t kBlendCoeffShift = 5;
|
||||
GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << kBlendCoeffShift));
|
||||
GR_STATIC_ASSERT(kFirstAdvancedGrBlendEquation - 1 < 4);
|
||||
|
||||
uint32_t key = blendInfo.fWriteColor;
|
||||
key |= (blendInfo.fSrcBlend << kBlendWriteShift);
|
||||
key |= (blendInfo.fDstBlend << (kBlendWriteShift + kBlendCoeffShift));
|
||||
key |= (blendInfo.fEquation << (kBlendWriteShift + 2 * kBlendCoeffShift));
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
bool GrVkPipelineStateBuilder::Desc::Build(Desc* desc,
|
||||
GrRenderTarget* renderTarget,
|
||||
const GrPrimitiveProcessor& primProc,
|
||||
@ -415,7 +398,7 @@ bool GrVkPipelineStateBuilder::Desc::Build(Desc* desc,
|
||||
|
||||
stencil.genKey(&b);
|
||||
|
||||
b.add32(get_blend_info_key(pipeline));
|
||||
b.add32(pipeline.getBlendInfoKey());
|
||||
|
||||
b.add32((uint32_t)primitiveType);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user