Add a cache of GrVkSamplers in GrVkResourceProvider.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1765523002

Review URL: https://codereview.chromium.org/1765523002
diff --git a/src/gpu/vk/GrVkProgram.cpp b/src/gpu/vk/GrVkProgram.cpp
index 0e1e201..92adde8 100644
--- a/src/gpu/vk/GrVkProgram.cpp
+++ b/src/gpu/vk/GrVkProgram.cpp
@@ -163,7 +163,7 @@
     }
 }
 
-void GrVkProgram::setData(const GrVkGpu* gpu,
+void GrVkProgram::setData(GrVkGpu* gpu,
                           const GrPrimitiveProcessor& primProc,
                           const GrPipeline& pipeline) {
     // This is here to protect against someone calling setData multiple times in a row without
@@ -255,12 +255,13 @@
     }
 }
 
-void GrVkProgram::writeSamplers(const GrVkGpu* gpu,
+void GrVkProgram::writeSamplers(GrVkGpu* gpu,
                                 const SkTArray<const GrTextureAccess*>& textureBindings) {
     SkASSERT(fNumSamplers == textureBindings.count());
 
     for (int i = 0; i < textureBindings.count(); ++i) {
-        fSamplers.push(GrVkSampler::Create(gpu, *textureBindings[i]));
+        const GrTextureParams& params = textureBindings[i]->getParams();
+        fSamplers.push(gpu->resourceProvider().findOrCreateCompatibleSampler(params));
 
         GrVkTexture* texture = static_cast<GrVkTexture*>(textureBindings[i]->getTexture());
 
diff --git a/src/gpu/vk/GrVkProgram.h b/src/gpu/vk/GrVkProgram.h
index e047726..9b4eeb1 100644
--- a/src/gpu/vk/GrVkProgram.h
+++ b/src/gpu/vk/GrVkProgram.h
@@ -33,7 +33,7 @@
 
     GrVkPipeline* vkPipeline() const { return fPipeline; }
 
-    void setData(const GrVkGpu*, const GrPrimitiveProcessor&, const GrPipeline&);
+    void setData(GrVkGpu*, const GrPrimitiveProcessor&, const GrPipeline&);
 
     void bind(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer);
 
@@ -68,7 +68,7 @@
 
     void writeUniformBuffers(const GrVkGpu* gpu);
 
-    void writeSamplers(const GrVkGpu* gpu, const SkTArray<const GrTextureAccess*>& textureBindings);
+    void writeSamplers(GrVkGpu* gpu, const SkTArray<const GrTextureAccess*>& textureBindings);
 
 
     /**
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index 19bda41..b273e3b 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -7,9 +7,11 @@
 
 #include "GrVkResourceProvider.h"
 
+#include "GrTextureParams.h"
 #include "GrVkCommandBuffer.h"
 #include "GrVkPipeline.h"
 #include "GrVkRenderPass.h"
+#include "GrVkSampler.h"
 #include "GrVkUtil.h"
 
 #ifdef SK_TRACE_VK_RESOURCES
@@ -81,6 +83,17 @@
     return new GrVkDescriptorPool(fGpu, typeCounts);
 }
 
+GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrTextureParams& params) {
+    GrVkSampler* sampler = fSamplers.find(GrVkSampler::GenerateKey(params));
+    if (!sampler) {
+        sampler = GrVkSampler::Create(fGpu, params);
+        fSamplers.add(sampler);
+    }
+    SkASSERT(sampler);
+    sampler->ref();
+    return sampler;
+}
+
 GrVkCommandBuffer* GrVkResourceProvider::createCommandBuffer() {
     GrVkCommandBuffer* cmdBuffer = GrVkCommandBuffer::Create(fGpu, fGpu->cmdPool());
     fActiveCommandBuffers.push_back(cmdBuffer);
@@ -112,6 +125,13 @@
     }
     fSimpleRenderPasses.reset();
 
+    // Iterate through all store GrVkSamplers and unref them before resetting the hash.
+    SkTDynamicHash<GrVkSampler, uint8_t>::Iter iter(&fSamplers);
+    for (; !iter.done(); ++iter) {
+        (*iter).unref(fGpu);
+    }
+    fSamplers.reset();
+
 #ifdef SK_TRACE_VK_RESOURCES
     SkASSERT(0 == GrVkResource::fTrace.count());
 #endif
@@ -133,6 +153,13 @@
     }
     fSimpleRenderPasses.reset();
 
+    // Iterate through all store GrVkSamplers and unrefAndAbandon them before resetting the hash.
+    SkTDynamicHash<GrVkSampler, uint8_t>::Iter iter(&fSamplers);
+    for (; !iter.done(); ++iter) {
+        (*iter).unrefAndAbandon();
+    }
+    fSamplers.reset();
+
 #ifdef SK_TRACE_VK_RESOURCES
     SkASSERT(0 == GrVkResource::fTrace.count());
 #endif
diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h
index 38d6c40..a769a65 100644
--- a/src/gpu/vk/GrVkResourceProvider.h
+++ b/src/gpu/vk/GrVkResourceProvider.h
@@ -12,16 +12,19 @@
 #include "GrVkResource.h"
 #include "GrVkUtil.h"
 #include "SkTArray.h"
+#include "SkTDynamicHash.h"
 
 #include "vulkan/vulkan.h"
 
 class GrPipeline;
 class GrPrimitiveProcessor;
+class GrTextureParams;
 class GrVkCommandBuffer;
 class GrVkGpu;
 class GrVkPipeline;
 class GrVkRenderPass;
 class GrVkRenderTarget;
+class GrVkSampler;
 
 class GrVkResourceProvider {
 public:
@@ -55,6 +58,10 @@
     GrVkDescriptorPool* findOrCreateCompatibleDescriptorPool(
                                         const GrVkDescriptorPool::DescriptorTypeCounts& typeCounts);
 
+    // Finds or creates a compatible GrVkSampler based on the GrTextureParams.
+    // The refcount is incremented and a pointer returned.
+    GrVkSampler* findOrCreateCompatibleSampler(const GrTextureParams&);
+
     // Destroy any cached resources. To be called before destroying the VkDevice.
     // The assumption is that all queues are idle and all command buffers are finished.
     // For resource tracing to work properly, this should be called after unrefing all other
@@ -78,6 +85,10 @@
 
     // Array of CommandBuffers that are currently in flight
     SkSTArray<4, GrVkCommandBuffer*> fActiveCommandBuffers;
+
+    // Stores GrVkSampler objects that we've already created so we can reuse them across multiple
+    // programs
+    SkTDynamicHash<GrVkSampler, uint8_t> fSamplers;
 };
 
 #endif
diff --git a/src/gpu/vk/GrVkSampler.cpp b/src/gpu/vk/GrVkSampler.cpp
index 4bba662..9938340 100644
--- a/src/gpu/vk/GrVkSampler.cpp
+++ b/src/gpu/vk/GrVkSampler.cpp
@@ -23,7 +23,7 @@
     return gWrapModes[tm];
 }
 
-GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrTextureAccess& textureAccess) {
+GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrTextureParams& params) {
 
     static VkFilter vkMinFilterModes[] = {
         VK_FILTER_NEAREST,
@@ -36,8 +36,6 @@
         VK_FILTER_LINEAR
     };
 
-    const GrTextureParams& params = textureAccess.getParams();
-
     VkSamplerCreateInfo createInfo;
     memset(&createInfo, 0, sizeof(VkSamplerCreateInfo));
     createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
@@ -65,10 +63,24 @@
                                                           nullptr,
                                                           &sampler));
 
-    return new GrVkSampler(sampler);
+    return new GrVkSampler(sampler, GenerateKey(params));
 }
 
 void GrVkSampler::freeGPUData(const GrVkGpu* gpu) const {
     SkASSERT(fSampler);
     GR_VK_CALL(gpu->vkInterface(), DestroySampler(gpu->device(), fSampler, nullptr));
 }
+
+uint8_t GrVkSampler::GenerateKey(const GrTextureParams& params) {
+
+    uint8_t key = params.filterMode();
+    
+    SkASSERT(params.filterMode() <= 3);
+    key |= (params.getTileModeX() << 2);
+
+    GR_STATIC_ASSERT(SkShader::kTileModeCount <= 4);
+    key |= (params.getTileModeY() << 4);
+
+    return key;
+}
+
diff --git a/src/gpu/vk/GrVkSampler.h b/src/gpu/vk/GrVkSampler.h
index d3212cb..7218135 100644
--- a/src/gpu/vk/GrVkSampler.h
+++ b/src/gpu/vk/GrVkSampler.h
@@ -13,23 +13,31 @@
 #include "vulkan/vulkan.h"
 
 class GrTextureAccess;
+class GrTextureParams;
 class GrVkGpu;
 
 
 class GrVkSampler : public GrVkResource {
 public:
-    static GrVkSampler* Create(const GrVkGpu* gpu, const GrTextureAccess& textureAccess);
+    static GrVkSampler* Create(const GrVkGpu* gpu, const GrTextureParams&);
 
     VkSampler sampler() const { return fSampler; }
 
+    // Helpers for hashing GrVkSampler
+    static uint8_t GenerateKey(const GrTextureParams&);
+
+    static const uint8_t& GetKey(const GrVkSampler& sampler) { return sampler.fKey; }
+    static uint32_t Hash(const uint8_t& key) { return key; }
 private:
-    GrVkSampler(VkSampler sampler) : INHERITED(), fSampler(sampler) {}
+    GrVkSampler(VkSampler sampler, uint8_t key) : INHERITED(), fSampler(sampler), fKey(key) {}
 
     void freeGPUData(const GrVkGpu* gpu) const override;
 
     VkSampler  fSampler;
+    uint8_t   fKey;
 
     typedef GrVkResource INHERITED;
 };
 
-#endif
\ No newline at end of file
+#endif
+