Add support for immuatable samplers in vulkan.

For ycbcr conversions we need add immutable samplers to the creation of
the VkPipeline via the descriptor set layout.

Bug: skia:
Change-Id: I5eea6037191fd34d26d49f58533035316158cacd
Reviewed-on: https://skia-review.googlesource.com/c/171642
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp
index 5c10b9f..aa84c98 100644
--- a/src/gpu/GrProgramDesc.cpp
+++ b/src/gpu/GrProgramDesc.cpp
@@ -50,7 +50,7 @@
 }
 
 static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrFragmentProcessor& fp,
-                             const GrShaderCaps& caps) {
+                             GrGpu* gpu, const GrShaderCaps& caps) {
     int numTextureSamplers = fp.numTextureSamplers();
     // Need two bytes per key.
     int word32Count = (numTextureSamplers + 1) / 2;
@@ -62,6 +62,16 @@
         const GrFragmentProcessor::TextureSampler& sampler = fp.textureSampler(i);
         const GrTexture* tex = sampler.peekTexture();
         k16[i] = sampler_key(tex->texturePriv().textureType(), tex->config(), caps);
+        uint32_t extraSamplerKey = gpu->getExtraSamplerKeyForProgram(
+                sampler.samplerState(), sampler.proxy()->backendFormat());
+        if (extraSamplerKey) {
+            SkASSERT(sampler.proxy()->textureType() == GrTextureType::kExternal);
+            // We first mark the normal sampler key with last bit to flag that it has an extra
+            // sampler key. We then add all the extraSamplerKeys to the end of the normal ones.
+            SkASSERT((k16[i] & (1 << 15)) == 0);
+            k16[i] = k16[i] | (1 << 15);
+            b->add32(extraSamplerKey);
+        }
     }
     // zero the last 16 bits if the number of uniforms for samplers is odd.
     if (numTextureSamplers & 0x1) {
@@ -70,7 +80,7 @@
 }
 
 static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrPrimitiveProcessor& pp,
-                              const GrShaderCaps& caps) {
+                             const GrShaderCaps& caps) {
     int numTextureSamplers = pp.numTextureSamplers();
     // Need two bytes per key.
     int word32Count = (numTextureSamplers + 1) / 2;
@@ -81,6 +91,15 @@
     for (int i = 0; i < numTextureSamplers; ++i) {
         const GrPrimitiveProcessor::TextureSampler& sampler = pp.textureSampler(i);
         k16[i] = sampler_key(sampler.textureType(), sampler.config(), caps);
+        uint32_t extraSamplerKey = sampler.extraSamplerKey();
+        if (extraSamplerKey) {
+            SkASSERT(sampler.textureType() == GrTextureType::kExternal);
+            // We first mark the normal sampler key with last bit to flag that it has an extra
+            // sampler key. We then add all the extraSamplerKeys to the end of the normal ones.
+            SkASSERT((k16[i] & (1 << 15)) == 0);
+            k16[i] = k16[i] | (1 << 15);
+            b->add32(extraSamplerKey);
+        }
     }
     // zero the last 16 bits if the number of uniforms for samplers is odd.
     if (numTextureSamplers & 0x1) {
@@ -98,6 +117,7 @@
  * function because it is hairy, though FPs do not have attribs, and GPs do not have transforms
  */
 static bool gen_meta_key(const GrFragmentProcessor& fp,
+                         GrGpu* gpu,
                          const GrShaderCaps& shaderCaps,
                          uint32_t transformKey,
                          GrProcessorKeyBuilder* b) {
@@ -110,7 +130,7 @@
         return false;
     }
 
-    add_sampler_keys(b, fp, shaderCaps);
+    add_sampler_keys(b, fp, gpu, shaderCaps);
 
     uint32_t* key = b->add32n(2);
     key[0] = (classID << 16) | SkToU32(processorKeySize);
@@ -157,30 +177,33 @@
 
 static bool gen_frag_proc_and_meta_keys(const GrPrimitiveProcessor& primProc,
                                         const GrFragmentProcessor& fp,
+                                        GrGpu* gpu,
                                         const GrShaderCaps& shaderCaps,
                                         GrProcessorKeyBuilder* b) {
     for (int i = 0; i < fp.numChildProcessors(); ++i) {
-        if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), shaderCaps, b)) {
+        if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), gpu, shaderCaps, b)) {
             return false;
         }
     }
 
     fp.getGLSLProcessorKey(shaderCaps, b);
 
-    return gen_meta_key(fp, shaderCaps, primProc.getTransformKey(fp.coordTransforms(),
-                                                                 fp.numCoordTransforms()), b);
+    return gen_meta_key(fp, gpu, shaderCaps, primProc.getTransformKey(fp.coordTransforms(),
+                                                                      fp.numCoordTransforms()), b);
 }
 
 bool GrProgramDesc::Build(GrProgramDesc* desc,
                           const GrPrimitiveProcessor& primProc,
                           bool hasPointSize,
                           const GrPipeline& pipeline,
-                          const GrShaderCaps& shaderCaps) {
+                          GrGpu* gpu) {
     // 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();
@@ -196,7 +219,7 @@
 
     for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
         const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i);
-        if (!gen_frag_proc_and_meta_keys(primProc, fp, shaderCaps, &b)) {
+        if (!gen_frag_proc_and_meta_keys(primProc, fp, gpu, shaderCaps, &b)) {
             desc->key().reset();
             return false;
         }