From 1223e7fc0a3c150d5f7b9d832af0368753cbbb9e Mon Sep 17 00:00:00 2001 From: Jim Van Verth Date: Thu, 28 Feb 2019 17:38:35 -0500 Subject: [PATCH] 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 Commit-Queue: Jim Van Verth --- src/gpu/GrPipeline.cpp | 17 +++++ src/gpu/GrPipeline.h | 3 + src/gpu/mtl/GrMtlGpuCommandBuffer.h | 3 +- src/gpu/mtl/GrMtlGpuCommandBuffer.mm | 53 +++++++------ src/gpu/mtl/GrMtlPipelineStateBuilder.h | 62 +++++++++++---- src/gpu/mtl/GrMtlPipelineStateBuilder.mm | 56 +++++++++++--- src/gpu/mtl/GrMtlResourceProvider.h | 54 ++++++++++++- src/gpu/mtl/GrMtlResourceProvider.mm | 96 ++++++++++++++++++++++++ src/gpu/vk/GrVkPipelineStateBuilder.cpp | 19 +---- 9 files changed, 297 insertions(+), 66 deletions(-) diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp index 537c5439dc..b16f164023 100644 --- a/src/gpu/GrPipeline.cpp +++ b/src/gpu/GrPipeline.cpp @@ -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; +} diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h index 91f619e885..7efff26ce5 100644 --- a/src/gpu/GrPipeline.h +++ b/src/gpu/GrPipeline.h @@ -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; } diff --git a/src/gpu/mtl/GrMtlGpuCommandBuffer.h b/src/gpu/mtl/GrMtlGpuCommandBuffer.h index 150578963e..322a2e858a 100644 --- a/src/gpu/mtl/GrMtlGpuCommandBuffer.h +++ b/src/gpu/mtl/GrMtlGpuCommandBuffer.h @@ -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, diff --git a/src/gpu/mtl/GrMtlGpuCommandBuffer.mm b/src/gpu/mtl/GrMtlGpuCommandBuffer.mm index 914e9e3437..77a1f5a47e 100644 --- a/src/gpu/mtl/GrMtlGpuCommandBuffer.mm +++ b/src/gpu/mtl/GrMtlGpuCommandBuffer.mm @@ -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 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); } diff --git a/src/gpu/mtl/GrMtlPipelineStateBuilder.h b/src/gpu/mtl/GrMtlPipelineStateBuilder.h index ce41618154..fe4ef02799 100644 --- a/src/gpu/mtl/GrMtlPipelineStateBuilder.h +++ b/src/gpu/mtl/GrMtlPipelineStateBuilder.h @@ -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; diff --git a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm index 93ba094024..8f0003b4d8 100644 --- a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm +++ b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm @@ -17,14 +17,14 @@ #import 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 vertexLibrary = nil; id 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; +} diff --git a/src/gpu/mtl/GrMtlResourceProvider.h b/src/gpu/mtl/GrMtlResourceProvider.h index d5b66ede66..c0c05452f8 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 @@ -17,17 +19,67 @@ class GrMtlGpu; class GrMtlResourceProvider { public: - GrMtlResourceProvider(GrMtlGpu* gpu) : fGpu(gpu) {} + GrMtlResourceProvider(GrMtlGpu* gpu); GrMtlCopyPipelineState* findOrCreateCopyPipelineState(MTLPixelFormat dstPixelFormat, id vertexFunction, id 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, DescHash> fMap; + + GrMtlGpu* fGpu; + +#ifdef GR_PIPELINE_STATE_CACHE_STATS + int fTotalRequests; + int fCacheMisses; +#endif + }; + SkTArray> fCopyPipelineStateCache; GrMtlGpu* fGpu; + + // Cache of GrMtlPipelineStates + std::unique_ptr fPipelineStateCache; }; #endif diff --git a/src/gpu/mtl/GrMtlResourceProvider.mm b/src/gpu/mtl/GrMtlResourceProvider.mm index 2e1e40dfe9..9708978be4 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 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 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 = 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(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 400c1e9908..b7485a6576 100644 --- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp +++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp @@ -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);