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>
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index 537c543..b16f164 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -106,3 +106,20 @@
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;
+}
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index 91f619e..7efff26 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -195,6 +195,9 @@
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; }
diff --git a/src/gpu/mtl/GrMtlGpuCommandBuffer.h b/src/gpu/mtl/GrMtlGpuCommandBuffer.h
index 1505789..322a2e8 100644
--- a/src/gpu/mtl/GrMtlGpuCommandBuffer.h
+++ b/src/gpu/mtl/GrMtlGpuCommandBuffer.h
@@ -73,8 +73,7 @@
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,
diff --git a/src/gpu/mtl/GrMtlGpuCommandBuffer.mm b/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
index 914e9e3..77a1f5a 100644
--- a/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
+++ b/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
@@ -108,21 +108,8 @@
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 @@
}
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 @@
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 @@
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);
}
diff --git a/src/gpu/mtl/GrMtlPipelineStateBuilder.h b/src/gpu/mtl/GrMtlPipelineStateBuilder.h
index ce41618..fe4ef02 100644
--- a/src/gpu/mtl/GrMtlPipelineStateBuilder.h
+++ b/src/gpu/mtl/GrMtlPipelineStateBuilder.h
@@ -22,28 +22,62 @@
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 @@
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;
diff --git a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
index 93ba094..8f0003b 100644
--- a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
+++ b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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;
+}
diff --git a/src/gpu/mtl/GrMtlResourceProvider.h b/src/gpu/mtl/GrMtlResourceProvider.h
index d5b66ed..c0c0545 100644
--- a/src/gpu/mtl/GrMtlResourceProvider.h
+++ b/src/gpu/mtl/GrMtlResourceProvider.h
@@ -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 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
diff --git a/src/gpu/mtl/GrMtlResourceProvider.mm b/src/gpu/mtl/GrMtlResourceProvider.mm
index 2e1e40d..9708978 100644
--- a/src/gpu/mtl/GrMtlResourceProvider.mm
+++ b/src/gpu/mtl/GrMtlResourceProvider.mm
@@ -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 @@
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();
+}
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
index 400c1e9..b7485a6 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
@@ -374,23 +374,6 @@
//////////////////////////////////////////////////////////////////////////////
-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 @@
stencil.genKey(&b);
- b.add32(get_blend_info_key(pipeline));
+ b.add32(pipeline.getBlendInfoKey());
b.add32((uint32_t)primitiveType);