Remove GrProgramDesc's need for the GrGpu

Although not strictly necessary, being able to compute the program key w/o needing access to the Gpu will give us more flexibility.

Bug: skia:9455
Change-Id: I0cd76d79a3008b69be18636be370e7aaa531bc65
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/247686
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/GrCaps.h b/src/gpu/GrCaps.h
index 27f0ec4..4ab32b9 100644
--- a/src/gpu/GrCaps.h
+++ b/src/gpu/GrCaps.h
@@ -21,7 +21,9 @@
 class GrBackendRenderTarget;
 class GrBackendTexture;
 struct GrContextOptions;
+class GrProcessorKeyBuilder;
 class GrRenderTargetProxy;
+class GrSamplerState;
 class GrSurface;
 class SkJSONWriter;
 
@@ -430,6 +432,15 @@
         return result;
     }
 
+    /**
+     * Adds fields to the key to represent the sampler that will be created for the passed
+     * in parameters. Currently this extra keying is only needed when building a vulkan pipeline
+     * with immutable samplers.
+     */
+    virtual void addExtraSamplerKey(GrProcessorKeyBuilder*,
+                                    const GrSamplerState&,
+                                    const GrBackendFormat&) const {}
+
 #ifdef SK_DEBUG
     // This is just a debugging entry point until we're weaned off of GrPixelConfig. It
     // should be used to verify that the pixel config from user-level code (the genericConfig)
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 79d2d57..58f6db7 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -569,18 +569,6 @@
         }
     }
 
-    /**
-     * Returns a key that represents the sampler that will be created for the passed in parameters.
-     * Currently this key is only used when we are building a vulkan pipeline with immutable
-     * samplers. In that case, we need our cache key to also contain this key.
-     *
-     * A return value of 0 indicates that the program/pipeline we are creating is not affected by
-     * the sampler.
-     */
-    virtual uint32_t getExtraSamplerKeyForProgram(const GrSamplerState&, const GrBackendFormat&) {
-        return 0;
-    }
-
     virtual void storeVkPipelineCacheData() {}
 
 protected:
diff --git a/src/gpu/GrPrimitiveProcessor.cpp b/src/gpu/GrPrimitiveProcessor.cpp
index 5ca399a..87b6f3f 100644
--- a/src/gpu/GrPrimitiveProcessor.cpp
+++ b/src/gpu/GrPrimitiveProcessor.cpp
@@ -55,20 +55,17 @@
 
 GrPrimitiveProcessor::TextureSampler::TextureSampler(const GrSamplerState& samplerState,
                                                      const GrBackendFormat& backendFormat,
-                                                     const GrSwizzle& swizzle,
-                                                     uint32_t extraSamplerKey) {
-    this->reset(samplerState, backendFormat, swizzle, extraSamplerKey);
+                                                     const GrSwizzle& swizzle) {
+    this->reset(samplerState, backendFormat, swizzle);
 }
 
 void GrPrimitiveProcessor::TextureSampler::reset(const GrSamplerState& samplerState,
                                                  const GrBackendFormat& backendFormat,
-                                                 const GrSwizzle& swizzle,
-                                                 uint32_t extraSamplerKey) {
+                                                 const GrSwizzle& swizzle) {
     fSamplerState = samplerState;
     fSamplerState.setFilterMode(clamp_filter(backendFormat.textureType(), samplerState.filter()));
     fBackendFormat = backendFormat;
     fSwizzle = swizzle;
-    fExtraSamplerKey = extraSamplerKey;
     fIsInitialized = true;
 }
 
diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h
index e0baf65..ba9d581 100644
--- a/src/gpu/GrPrimitiveProcessor.h
+++ b/src/gpu/GrPrimitiveProcessor.h
@@ -255,14 +255,12 @@
 public:
     TextureSampler() = default;
 
-    TextureSampler(const GrSamplerState&, const GrBackendFormat&, const GrSwizzle&,
-                   uint32_t extraSamplerKey = 0);
+    TextureSampler(const GrSamplerState&, const GrBackendFormat&, const GrSwizzle&);
 
     TextureSampler(const TextureSampler&) = delete;
     TextureSampler& operator=(const TextureSampler&) = delete;
 
-    void reset(const GrSamplerState&, const GrBackendFormat&, const GrSwizzle&,
-               uint32_t extraSamplerKey = 0);
+    void reset(const GrSamplerState&, const GrBackendFormat&, const GrSwizzle&);
 
     const GrBackendFormat& backendFormat() const { return fBackendFormat; }
     GrTextureType textureType() const { return fBackendFormat.textureType(); }
@@ -270,15 +268,12 @@
     const GrSamplerState& samplerState() const { return fSamplerState; }
     const GrSwizzle& swizzle() const { return fSwizzle; }
 
-    uint32_t extraSamplerKey() const { return fExtraSamplerKey; }
-
     bool isInitialized() const { return fIsInitialized; }
 
 private:
     GrSamplerState  fSamplerState;
     GrBackendFormat fBackendFormat;
     GrSwizzle       fSwizzle;
-    uint32_t        fExtraSamplerKey = 0;
     bool            fIsInitialized = false;
 };
 
diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp
index 8d995a3..d0b4f23 100644
--- a/src/gpu/GrProgramDesc.cpp
+++ b/src/gpu/GrProgramDesc.cpp
@@ -45,62 +45,48 @@
 }
 
 static uint32_t sampler_key(GrTextureType textureType, const GrSwizzle& swizzle,
-                            const GrShaderCaps& caps) {
+                            const GrCaps& caps) {
     int samplerTypeKey = texture_type_key(textureType);
 
     GR_STATIC_ASSERT(2 == sizeof(swizzle.asKey()));
     uint16_t swizzleKey = 0;
-    if (caps.textureSwizzleAppliedInShader()) {
+    if (caps.shaderCaps()->textureSwizzleAppliedInShader()) {
         swizzleKey = swizzle.asKey();
     }
     return SkToU32(samplerTypeKey | swizzleKey << kSamplerOrImageTypeKeyBits);
 }
 
 static void add_fp_sampler_keys(GrProcessorKeyBuilder* b, const GrFragmentProcessor& fp,
-                                GrGpu* gpu, const GrShaderCaps& caps) {
+                                const GrCaps& caps) {
     int numTextureSamplers = fp.numTextureSamplers();
     if (!numTextureSamplers) {
         return;
     }
     for (int i = 0; i < numTextureSamplers; ++i) {
         const GrFragmentProcessor::TextureSampler& sampler = fp.textureSampler(i);
-        const GrTexture* tex = sampler.peekTexture();
-        uint32_t samplerKey = sampler_key(
-                tex->texturePriv().textureType(), sampler.swizzle(), caps);
-        uint32_t extraSamplerKey = gpu->getExtraSamplerKeyForProgram(
-                sampler.samplerState(), sampler.proxy()->backendFormat());
-        if (extraSamplerKey) {
-            // We first mark the normal sampler key with last bit to flag that it has an extra
-            // sampler key. We then add both keys.
-            SkASSERT((samplerKey & (1 << 31)) == 0);
-            b->add32(samplerKey | (1 << 31));
-            b->add32(extraSamplerKey);
-        } else {
-            b->add32(samplerKey);
-        }
+        const GrBackendFormat& backendFormat = sampler.proxy()->backendFormat();
+
+        uint32_t samplerKey = sampler_key(backendFormat.textureType(), sampler.swizzle(), caps);
+        b->add32(samplerKey);
+
+        caps.addExtraSamplerKey(b, sampler.samplerState(), backendFormat);
     }
 }
 
 static void add_pp_sampler_keys(GrProcessorKeyBuilder* b, const GrPrimitiveProcessor& pp,
-                                const GrShaderCaps& caps) {
+                                const GrCaps& caps) {
     int numTextureSamplers = pp.numTextureSamplers();
     if (!numTextureSamplers) {
         return;
     }
     for (int i = 0; i < numTextureSamplers; ++i) {
         const GrPrimitiveProcessor::TextureSampler& sampler = pp.textureSampler(i);
-        uint32_t samplerKey = sampler_key(
-                sampler.textureType(), sampler.swizzle(), caps);
-        uint32_t extraSamplerKey = sampler.extraSamplerKey();
-        if (extraSamplerKey) {
-            // We first mark the normal sampler key with last bit to flag that it has an extra
-            // sampler key. We then add both keys.
-            SkASSERT((samplerKey & (1 << 31)) == 0);
-            b->add32(samplerKey | (1 << 31));
-            b->add32(extraSamplerKey);
-        } else {
-            b->add32(samplerKey);
-        }
+        const GrBackendFormat& backendFormat = sampler.backendFormat();
+
+        uint32_t samplerKey = sampler_key(backendFormat.textureType(), sampler.swizzle(), caps);
+        b->add32(samplerKey);
+
+        caps.addExtraSamplerKey(b, sampler.samplerState(), backendFormat);
     }
 }
 
@@ -114,8 +100,7 @@
  * function because it is hairy, though FPs do not have attribs, and GPs do not have transforms
  */
 static bool gen_fp_meta_key(const GrFragmentProcessor& fp,
-                            GrGpu* gpu,
-                            const GrShaderCaps& shaderCaps,
+                            const GrCaps& caps,
                             uint32_t transformKey,
                             GrProcessorKeyBuilder* b) {
     size_t processorKeySize = b->size();
@@ -127,7 +112,7 @@
         return false;
     }
 
-    add_fp_sampler_keys(b, fp, gpu, shaderCaps);
+    add_fp_sampler_keys(b, fp, caps);
 
     uint32_t* key = b->add32n(2);
     key[0] = (classID << 16) | SkToU32(processorKeySize);
@@ -136,7 +121,7 @@
 }
 
 static bool gen_pp_meta_key(const GrPrimitiveProcessor& pp,
-                            const GrShaderCaps& shaderCaps,
+                            const GrCaps& caps,
                             uint32_t transformKey,
                             GrProcessorKeyBuilder* b) {
     size_t processorKeySize = b->size();
@@ -148,7 +133,7 @@
         return false;
     }
 
-    add_pp_sampler_keys(b, pp, shaderCaps);
+    add_pp_sampler_keys(b, pp, caps);
 
     uint32_t* key = b->add32n(2);
     key[0] = (classID << 16) | SkToU32(processorKeySize);
@@ -156,9 +141,7 @@
     return true;
 }
 
-static bool gen_xp_meta_key(const GrXferProcessor& xp,
-                            const GrShaderCaps& shaderCaps,
-                            GrProcessorKeyBuilder* b) {
+static bool gen_xp_meta_key(const GrXferProcessor& xp, GrProcessorKeyBuilder* b) {
     size_t processorKeySize = b->size();
     uint32_t classID = xp.classID();
 
@@ -174,31 +157,28 @@
 
 static bool gen_frag_proc_and_meta_keys(const GrPrimitiveProcessor& primProc,
                                         const GrFragmentProcessor& fp,
-                                        GrGpu* gpu,
-                                        const GrShaderCaps& shaderCaps,
+                                        const GrCaps& caps,
                                         GrProcessorKeyBuilder* b) {
     for (int i = 0; i < fp.numChildProcessors(); ++i) {
-        if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), gpu, shaderCaps, b)) {
+        if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), caps, b)) {
             return false;
         }
     }
 
-    fp.getGLSLProcessorKey(shaderCaps, b);
+    fp.getGLSLProcessorKey(*caps.shaderCaps(), b);
 
-    return gen_fp_meta_key(fp, gpu, shaderCaps, primProc.getTransformKey(fp.coordTransforms(),
-                                                                         fp.numCoordTransforms()),
-                                                                         b);
+    return gen_fp_meta_key(fp, caps, primProc.getTransformKey(fp.coordTransforms(),
+                                                              fp.numCoordTransforms()), b);
 }
 
 bool GrProgramDesc::Build(GrProgramDesc* desc, const GrRenderTarget* renderTarget,
-                          const GrProgramInfo& programInfo, GrGpu* gpu) {
+                          const GrProgramInfo& programInfo, const GrCaps& caps) {
+
     // The descriptor is used as a cache key. Thus when a field of the
     // descriptor will not affect program generation (because of the attribute
     // bindings in use or other descriptor field settings) it should be set
     // to a canonical value to avoid duplicate programs with different keys.
 
-    const GrShaderCaps& shaderCaps = *gpu->caps()->shaderCaps();
-
     GR_STATIC_ASSERT(0 == kProcessorKeysOffset % sizeof(uint32_t));
     // Make room for everything up to the effect keys.
     desc->key().reset();
@@ -206,16 +186,16 @@
 
     GrProcessorKeyBuilder b(&desc->key());
 
-    programInfo.primProc().getGLSLProcessorKey(shaderCaps, &b);
+    programInfo.primProc().getGLSLProcessorKey(*caps.shaderCaps(), &b);
     programInfo.primProc().getAttributeKey(&b);
-    if (!gen_pp_meta_key(programInfo.primProc(), shaderCaps, 0, &b)) {
+    if (!gen_pp_meta_key(programInfo.primProc(), caps, 0, &b)) {
         desc->key().reset();
         return false;
     }
 
     for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
         const GrFragmentProcessor& fp = programInfo.pipeline().getFragmentProcessor(i);
-        if (!gen_frag_proc_and_meta_keys(programInfo.primProc(), fp, gpu, shaderCaps, &b)) {
+        if (!gen_frag_proc_and_meta_keys(programInfo.primProc(), fp, caps, &b)) {
             desc->key().reset();
             return false;
         }
@@ -228,8 +208,8 @@
         origin = programInfo.pipeline().dstProxyView().origin();
         originIfDstTexture = &origin;
     }
-    xp.getGLSLProcessorKey(shaderCaps, &b, originIfDstTexture);
-    if (!gen_xp_meta_key(xp, shaderCaps, &b)) {
+    xp.getGLSLProcessorKey(*caps.shaderCaps(), &b, originIfDstTexture);
+    if (!gen_xp_meta_key(xp, &b)) {
         desc->key().reset();
         return false;
     }
diff --git a/src/gpu/GrProgramDesc.h b/src/gpu/GrProgramDesc.h
index dea6131..ce9b0e3 100644
--- a/src/gpu/GrProgramDesc.h
+++ b/src/gpu/GrProgramDesc.h
@@ -31,9 +31,9 @@
      * @param desc          The built and finalized descriptor
      * @param renderTarget  The target of the draw
      * @param programInfo   Program information need to build the key
-     * @param gpu           Pointer to the GrGpu object the program will be used with.
+     * @param caps          the caps
      **/
-    static bool Build(GrProgramDesc*, const GrRenderTarget*, const GrProgramInfo&, GrGpu*);
+    static bool Build(GrProgramDesc*, const GrRenderTarget*, const GrProgramInfo&, const GrCaps&);
 
     // This is strictly an OpenGL call since the other backends have additional data in their
     // keys
diff --git a/src/gpu/dawn/GrDawnGpu.cpp b/src/gpu/dawn/GrDawnGpu.cpp
index 6e24faa..ab859b2 100644
--- a/src/gpu/dawn/GrDawnGpu.cpp
+++ b/src/gpu/dawn/GrDawnGpu.cpp
@@ -89,8 +89,8 @@
                       GrRenderTarget* rt,
                       const GrProgramInfo& programInfo,
                       bool hasDepthStencil,
-                      GrGpu* gpu) {
-        if (!GrProgramDesc::Build(desc, rt, programInfo, gpu)) {
+                      const GrCaps& caps) {
+        if (!GrProgramDesc::Build(desc, rt, programInfo, caps)) {
             return false;
         }
         GrProcessorKeyBuilder b(&desc->key());
@@ -620,7 +620,7 @@
         const GrProgramInfo& programInfo) {
     bool hasDepthStencil = rt->renderTargetPriv().getStencilAttachment() != nullptr;
     Desc desc;
-    if (!Desc::Build(&desc, rt, programInfo, hasDepthStencil, this)) {
+    if (!Desc::Build(&desc, rt, programInfo, hasDepthStencil, *this->caps())) {
         return nullptr;
     }
 
diff --git a/src/gpu/gl/GrGLGpuProgramCache.cpp b/src/gpu/gl/GrGLGpuProgramCache.cpp
index 08260c0..9eff843 100644
--- a/src/gpu/gl/GrGLGpuProgramCache.cpp
+++ b/src/gpu/gl/GrGLGpuProgramCache.cpp
@@ -48,11 +48,11 @@
 GrGLProgram* GrGLGpu::ProgramCache::refProgram(GrGLGpu* gpu,
                                                GrRenderTarget* renderTarget,
                                                const GrProgramInfo& programInfo) {
-    // TODO: can this be unified between GL, Vk and Mtl?
-    // Get GrGLProgramDesc
-    GrProgramDesc desc;
+    const GrCaps& caps = *gpu->caps();
 
-    if (!GrProgramDesc::Build(&desc, renderTarget, programInfo, gpu)) {
+    GrProgramDesc desc;
+    if (!GrProgramDesc::Build(&desc, renderTarget, programInfo, caps)) {
+
         GrCapsDebugf(gpu->caps(), "Failed to gl program descriptor!\n");
         return nullptr;
     }
diff --git a/src/gpu/mtl/GrMtlPipelineStateBuilder.h b/src/gpu/mtl/GrMtlPipelineStateBuilder.h
index 0c360a1..569a06e 100644
--- a/src/gpu/mtl/GrMtlPipelineStateBuilder.h
+++ b/src/gpu/mtl/GrMtlPipelineStateBuilder.h
@@ -18,6 +18,7 @@
 #import <Metal/Metal.h>
 
 class GrProgramInfo;
+class GrMtlCaps;
 class GrMtlGpu;
 class GrMtlPipelineState;
 
@@ -36,7 +37,7 @@
      */
     class Desc : public GrProgramDesc {
     public:
-        static bool Build(Desc*, GrRenderTarget*, const GrProgramInfo&, GrMtlGpu*);
+        static bool Build(Desc*, GrRenderTarget*, const GrProgramInfo&, const GrMtlCaps&);
 
         size_t shaderKeyLength() const { return fShaderKeyLength; }
 
diff --git a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
index 63aad6c..7750da1 100644
--- a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
+++ b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
@@ -449,8 +449,8 @@
 bool GrMtlPipelineStateBuilder::Desc::Build(Desc* desc,
                                             GrRenderTarget* renderTarget,
                                             const GrProgramInfo& programInfo,
-                                            GrMtlGpu* gpu) {
-    if (!GrProgramDesc::Build(desc, renderTarget, programInfo, gpu)) {
+                                            const GrMtlCaps& caps) {
+    if (!GrProgramDesc::Build(desc, renderTarget, programInfo, caps)) {
         return false;
     }
 
@@ -462,13 +462,16 @@
 
     b.add32(renderTarget->config());
     b.add32(renderTarget->numSamples());
+
     bool hasStencilAttachment = SkToBool(renderTarget->renderTargetPriv().getStencilAttachment());
-    b.add32(hasStencilAttachment ? gpu->mtlCaps().preferredStencilFormat().fInternalFormat
+    SkASSERT(!programInfo.pipeline().isStencilEnabled() || hasStencilAttachment);
+
+    b.add32(hasStencilAttachment ? caps.preferredStencilFormat().fInternalFormat
                                  : MTLPixelFormatInvalid);
     b.add32((uint32_t)programInfo.pipeline().isStencilEnabled());
     // Stencil samples don't seem to be tracked in the MTLRenderPipeline
 
-    programInfo.pipeline().genKey(&b, *gpu->caps());
+    programInfo.pipeline().genKey(&b, caps);
 
     b.add32((uint32_t)programInfo.primitiveType());
 
diff --git a/src/gpu/mtl/GrMtlResourceProvider.mm b/src/gpu/mtl/GrMtlResourceProvider.mm
index 639a58f..2aecb4c 100644
--- a/src/gpu/mtl/GrMtlResourceProvider.mm
+++ b/src/gpu/mtl/GrMtlResourceProvider.mm
@@ -139,10 +139,12 @@
     ++fTotalRequests;
 #endif
 
+    const GrMtlCaps& caps = fGpu->mtlCaps();
+
     // TODO: unify GL, VK and Mtl
     // Get GrMtlProgramDesc
     GrMtlPipelineStateBuilder::Desc desc;
-    if (!GrMtlPipelineStateBuilder::Desc::Build(&desc, renderTarget, programInfo, fGpu)) {
+    if (!GrMtlPipelineStateBuilder::Desc::Build(&desc, renderTarget, programInfo, caps)) {
         GrCapsDebugf(fGpu->caps(), "Failed to build mtl program descriptor!\n");
         return nullptr;
     }
diff --git a/src/gpu/ops/GrLatticeOp.cpp b/src/gpu/ops/GrLatticeOp.cpp
index bb98f35..99e4477 100644
--- a/src/gpu/ops/GrLatticeOp.cpp
+++ b/src/gpu/ops/GrLatticeOp.cpp
@@ -96,12 +96,8 @@
               GrSamplerState::Filter filter, bool wideColor)
             : INHERITED(kLatticeGP_ClassID), fColorSpaceXform(std::move(csxf)) {
 
-        GrSamplerState samplerState = GrSamplerState(GrSamplerState::WrapMode::kClamp, filter);
-        uint32_t extraSamplerKey = gpu->getExtraSamplerKeyForProgram(samplerState,
-                                                                     proxy->backendFormat());
-
-        fSampler.reset(samplerState, proxy->backendFormat(), proxy->textureSwizzle(),
-                       extraSamplerKey);
+        fSampler.reset(GrSamplerState(GrSamplerState::WrapMode::kClamp, filter),
+                       proxy->backendFormat(), proxy->textureSwizzle());
         this->setTextureSamplerCnt(1);
         fInPosition = {"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
         fInTextureCoords = {"textureCoords", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index f979d6b..86fe00f 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -293,11 +293,11 @@
     static sk_sp<GrGeometryProcessor> Make(const VertexSpec& vertexSpec, const GrShaderCaps& caps,
                                            const GrBackendFormat& backendFormat,
                                            const GrSamplerState& samplerState,
-                                           const GrSwizzle& swizzle, uint32_t extraSamplerKey,
+                                           const GrSwizzle& swizzle,
                                            sk_sp<GrColorSpaceXform> textureColorSpaceXform,
                                            Saturate saturate) {
         return sk_sp<QuadPerEdgeAAGeometryProcessor>(new QuadPerEdgeAAGeometryProcessor(
-                vertexSpec, caps, backendFormat, samplerState, swizzle, extraSamplerKey,
+                vertexSpec, caps, backendFormat, samplerState, swizzle,
                 std::move(textureColorSpaceXform), saturate));
     }
 
@@ -501,13 +501,12 @@
                                    const GrBackendFormat& backendFormat,
                                    const GrSamplerState& samplerState,
                                    const GrSwizzle& swizzle,
-                                   uint32_t extraSamplerKey,
                                    sk_sp<GrColorSpaceXform> textureColorSpaceXform,
                                    Saturate saturate)
             : INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID)
             , fSaturate(saturate)
             , fTextureColorSpaceXform(std::move(textureColorSpaceXform))
-            , fSampler(samplerState, backendFormat, swizzle, extraSamplerKey) {
+            , fSampler(samplerState, backendFormat, swizzle) {
         SkASSERT(spec.hasLocalCoords());
         this->initializeAttrs(spec);
         this->setTextureSamplerCnt(1);
@@ -590,12 +589,11 @@
 sk_sp<GrGeometryProcessor> MakeTexturedProcessor(const VertexSpec& spec, const GrShaderCaps& caps,
                                                  const GrBackendFormat& backendFormat,
                                                  const GrSamplerState& samplerState,
-                                                 const GrSwizzle& swizzle, uint32_t extraSamplerKey,
+                                                 const GrSwizzle& swizzle,
                                                  sk_sp<GrColorSpaceXform> textureColorSpaceXform,
                                                  Saturate saturate) {
     return QuadPerEdgeAAGeometryProcessor::Make(spec, caps, backendFormat, samplerState, swizzle,
-                                                extraSamplerKey, std::move(textureColorSpaceXform),
-                                                saturate);
+                                                std::move(textureColorSpaceXform), saturate);
 }
 
 } // namespace GrQuadPerEdgeAA
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.h b/src/gpu/ops/GrQuadPerEdgeAA.h
index ae7fb28..ae245ea 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.h
+++ b/src/gpu/ops/GrQuadPerEdgeAA.h
@@ -131,7 +131,7 @@
 
     sk_sp<GrGeometryProcessor> MakeTexturedProcessor(
             const VertexSpec& spec, const GrShaderCaps& caps, const GrBackendFormat&,
-            const GrSamplerState& samplerState, const GrSwizzle& swizzle, uint32_t extraSamplerKey,
+            const GrSamplerState& samplerState, const GrSwizzle& swizzle,
             sk_sp<GrColorSpaceXform> textureColorSpaceXform, Saturate saturate);
 
     // Fill vertices with the vertex data needed to represent the given quad. The device position,
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 0ac1f10..7c19c4e 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -760,14 +760,9 @@
 
             auto saturate = static_cast<GrTextureOp::Saturate>(fSaturate);
 
-            GrGpu* gpu = target->resourceProvider()->priv().gpu();
-            uint32_t extraSamplerKey = gpu->getExtraSamplerKeyForProgram(samplerState,
-                                                                         backendFormat);
-
             gp = GrQuadPerEdgeAA::MakeTexturedProcessor(
                 desc.fVertexSpec, *target->caps().shaderCaps(), backendFormat,
-                samplerState, swizzle, extraSamplerKey, std::move(fTextureColorSpaceXform),
-                saturate);
+                samplerState, swizzle, std::move(fTextureColorSpaceXform), saturate);
 
             SkASSERT(vertexSize == gp->vertexStride());
         }
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 4089ed5..7dac87a 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -1700,6 +1700,24 @@
     return GrVkUniformHandler::kUniformBufferDescSet;
 }
 
+void GrVkCaps::addExtraSamplerKey(GrProcessorKeyBuilder* b,
+                                  const GrSamplerState& samplerState,
+                                  const GrBackendFormat& format) const {
+    const GrVkYcbcrConversionInfo* ycbcrInfo = format.getVkYcbcrConversionInfo();
+    if (!ycbcrInfo) {
+        return;
+    }
+
+    GrVkSampler::Key key = GrVkSampler::GenerateKey(samplerState, *ycbcrInfo);
+
+    size_t numInts = (sizeof(key) + 3) / 4;
+
+    uint32_t* tmp = b->add32n(numInts);
+
+    tmp[numInts - 1] = 0;
+    memcpy(tmp, &key, sizeof(key));
+}
+
 #if GR_TEST_UTILS
 std::vector<GrCaps::TestFormatColorTypeCombination> GrVkCaps::getTestingCombinations() const {
     std::vector<GrCaps::TestFormatColorTypeCombination> combos = {
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index 0b90035..b0ced01 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -184,6 +184,10 @@
     int getFragmentUniformBinding() const;
     int getFragmentUniformSet() const;
 
+    void addExtraSamplerKey(GrProcessorKeyBuilder*,
+                            const GrSamplerState&,
+                            const GrBackendFormat&) const override;
+
 #if GR_TEST_UTILS
     std::vector<TestFormatColorTypeCombination> getTestingCombinations() const override;
 #endif
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index cb48930..b52ebfb 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -2524,24 +2524,6 @@
     fDrawables.emplace_back(std::move(drawable));
 }
 
-uint32_t GrVkGpu::getExtraSamplerKeyForProgram(const GrSamplerState& samplerState,
-                                               const GrBackendFormat& format) {
-    const GrVkYcbcrConversionInfo* ycbcrInfo = format.getVkYcbcrConversionInfo();
-    SkASSERT(ycbcrInfo);
-    if (!ycbcrInfo->isValid()) {
-        return 0;
-    }
-
-    const GrVkSampler* sampler = this->resourceProvider().findOrCreateCompatibleSampler(
-            samplerState, *ycbcrInfo);
-
-    uint32_t result = sampler->uniqueID();
-
-    sampler->unref(this);
-
-    return result;
-}
-
 void GrVkGpu::storeVkPipelineCacheData() {
     if (this->getContext()->priv().getPersistentCache()) {
         this->resourceProvider().storePipelineCacheData();
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index d835521..d25fabe 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -156,9 +156,6 @@
                     VkDeviceSize dstOffset, VkDeviceSize size);
     bool updateBuffer(GrVkBuffer* buffer, const void* src, VkDeviceSize offset, VkDeviceSize size);
 
-    uint32_t getExtraSamplerKeyForProgram(const GrSamplerState&,
-                                          const GrBackendFormat& format) override;
-
     enum PersistentCacheKeyType : uint32_t {
         kShader_PersistentCacheKeyType = 0,
         kPipelineCache_PersistentCacheKeyType = 1,
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
index ca72313..e61c78e 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
@@ -327,8 +327,8 @@
                                            GrRenderTarget* renderTarget,
                                            const GrProgramInfo& programInfo,
                                            const GrStencilSettings& stencil,
-                                           GrVkGpu* gpu) {
-    if (!GrProgramDesc::Build(desc, renderTarget, programInfo, gpu)) {
+                                           const GrCaps& caps) {
+    if (!GrProgramDesc::Build(desc, renderTarget, programInfo, caps)) {
         return false;
     }
 
@@ -346,7 +346,7 @@
 
     stencil.genKey(&b);
 
-    programInfo.pipeline().genKey(&b, *gpu->caps());
+    programInfo.pipeline().genKey(&b, caps);
 
     // Vulkan requires the full primitive type as part of its key
     b.add32((uint32_t)programInfo.primitiveType());
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.h b/src/gpu/vk/GrVkPipelineStateBuilder.h
index 76d057b..58891a9 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.h
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.h
@@ -42,7 +42,7 @@
                           GrRenderTarget*,
                           const GrProgramInfo&,
                           const GrStencilSettings&,
-                          GrVkGpu* gpu);
+                          const GrCaps& caps);
 
         size_t shaderKeyLength() const { return fShaderKeyLength; }
 
diff --git a/src/gpu/vk/GrVkPipelineStateCache.cpp b/src/gpu/vk/GrVkPipelineStateCache.cpp
index 3bdf3fc..40882af 100644
--- a/src/gpu/vk/GrVkPipelineStateCache.cpp
+++ b/src/gpu/vk/GrVkPipelineStateCache.cpp
@@ -95,7 +95,8 @@
     // TODO: can this be unified between GL, Vk and Mtl?
     // Get GrVkProgramDesc
     GrVkPipelineStateBuilder::Desc desc;
-    if (!GrVkPipelineStateBuilder::Desc::Build(&desc, renderTarget, programInfo, stencil, fGpu)) {
+    if (!GrVkPipelineStateBuilder::Desc::Build(&desc, renderTarget, programInfo, stencil,
+                                               *fGpu->caps())) {
         GrCapsDebugf(fGpu->caps(), "Failed to build vk program descriptor!\n");
         return nullptr;
     }