Add program pre-compilation to Vulkan backend

This CL fills out the GrVkGpu::compile method and updates GrVkCaps::makeDesc to both reconstruct the GrVkRenderPass AttachmentsDescriptor and AttachmentFlags from the GrProgramDesc.

In the 'compile' case, the renderPass info is used to get a renderpass and then a pipeline state.

In the 'makeDesc' case, the renderPass info is used to create the ProgramDesc.

Bug: skia:9455
Change-Id: I3810651232c95c3d837d96655853ea54056c70cb
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/288462
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrDDLContext.cpp b/src/gpu/GrDDLContext.cpp
index ee77eaf..72e893a 100644
--- a/src/gpu/GrDDLContext.cpp
+++ b/src/gpu/GrDDLContext.cpp
@@ -71,11 +71,10 @@
 
         const GrCaps* caps = this->caps();
 
-        if (this->backend() == GrBackendApi::kVulkan ||
-            this->backend() == GrBackendApi::kMetal ||
+        if (this->backend() == GrBackendApi::kMetal ||
             this->backend() == GrBackendApi::kDirect3D ||
             this->backend() == GrBackendApi::kDawn) {
-            // Currently Vulkan, Metal, Direct3D, and Dawn require a live renderTarget to
+            // Currently Metal, Direct3D, and Dawn require a live renderTarget to
             // compute the key
             return;
         }
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 144b685..6201245 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -975,8 +975,7 @@
             *fRenderTargetContext->caps());
 }
 
-GrOpsTask::CanDiscardPreviousOps GrRenderTargetContext::canDiscardPreviousOpsOnFullClear(
-        ) const {
+GrOpsTask::CanDiscardPreviousOps GrRenderTargetContext::canDiscardPreviousOpsOnFullClear() const {
 #if GR_TEST_UTILS
     if (fPreserveOpsOnFullClear_TestingOnly) {
         return GrOpsTask::CanDiscardPreviousOps::kNo;
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 5dc79fb..6826cdb 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -1701,13 +1701,39 @@
     // GrVkPipelineStateBuilder.cpp).
     b.add32(GrVkGpu::kShader_PersistentCacheKeyType);
 
-    GrVkRenderTarget* vkRT = (GrVkRenderTarget*) rt;
+    if (rt) {
+        GrVkRenderTarget* vkRT = (GrVkRenderTarget*) rt;
 
-    bool needsStencil = programInfo.numStencilSamples() || programInfo.isStencilEnabled();
-    // TODO: support failure in getSimpleRenderPass
-    const GrVkRenderPass* rp = vkRT->getSimpleRenderPass(needsStencil);
-    SkASSERT(rp);
-    rp->genKey(&b);
+        bool needsStencil = programInfo.numStencilSamples() || programInfo.isStencilEnabled();
+        // TODO: support failure in getSimpleRenderPass
+        const GrVkRenderPass* rp = vkRT->getSimpleRenderPass(needsStencil);
+        SkASSERT(rp);
+        rp->genKey(&b);
+
+#ifdef SK_DEBUG
+        if (!rp->isExternal()) {
+            // This is to ensure ReconstructAttachmentsDescriptor keeps matching
+            // getSimpleRenderPass' result
+            GrVkRenderPass::AttachmentsDescriptor attachmentsDescriptor;
+            GrVkRenderPass::AttachmentFlags attachmentFlags;
+            GrVkRenderTarget::ReconstructAttachmentsDescriptor(*this, programInfo,
+                                                               &attachmentsDescriptor,
+                                                               &attachmentFlags);
+            SkASSERT(rp->isCompatible(attachmentsDescriptor, attachmentFlags));
+        }
+#endif
+    } else {
+        GrVkRenderPass::AttachmentsDescriptor attachmentsDescriptor;
+        GrVkRenderPass::AttachmentFlags attachmentFlags;
+        GrVkRenderTarget::ReconstructAttachmentsDescriptor(*this, programInfo,
+                                                           &attachmentsDescriptor,
+                                                           &attachmentFlags);
+
+        // kExternal_AttachmentFlag is only set for wrapped secondary command buffers - which
+        // will always go through the above 'rt' path (i.e., we can always pass 0 as the final
+        // parameter to GenKey).
+        GrVkRenderPass::GenKey(&b, attachmentFlags, attachmentsDescriptor, 0);
+    }
 
     GrStencilSettings stencil = programInfo.nonGLStencilSettings();
     stencil.genKey(&b, true);
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index b075f43..8bfdafd 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1896,8 +1896,33 @@
     }
 }
 
-bool GrVkGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
-    return false;
+bool GrVkGpu::compile(const GrProgramDesc& desc, const GrProgramInfo& programInfo) {
+    SkASSERT(!(GrProcessor::CustomFeatures::kSampleLocations & programInfo.requestedFeatures()));
+
+    GrVkRenderPass::AttachmentsDescriptor attachmentsDescriptor;
+    GrVkRenderPass::AttachmentFlags attachmentFlags;
+    GrVkRenderTarget::ReconstructAttachmentsDescriptor(this->vkCaps(), programInfo,
+                                                       &attachmentsDescriptor, &attachmentFlags);
+
+    sk_sp<const GrVkRenderPass> renderPass(this->resourceProvider().findCompatibleRenderPass(
+                                                                         &attachmentsDescriptor,
+                                                                         attachmentFlags));
+    if (!renderPass) {
+        return false;
+    }
+
+    Stats::ProgramCacheResult stat;
+
+    auto pipelineState = this->resourceProvider().findOrCreateCompatiblePipelineState(
+                                    desc,
+                                    programInfo,
+                                    renderPass->vkRenderPass(),
+                                    &stat);
+    if (!pipelineState) {
+        return false;
+    }
+
+    return stat != Stats::ProgramCacheResult::kHit;
 }
 
 #if GR_TEST_UTILS
diff --git a/src/gpu/vk/GrVkRenderPass.cpp b/src/gpu/vk/GrVkRenderPass.cpp
index 281983f..bb4f145 100644
--- a/src/gpu/vk/GrVkRenderPass.cpp
+++ b/src/gpu/vk/GrVkRenderPass.cpp
@@ -266,19 +266,25 @@
 }
 
 void GrVkRenderPass::genKey(GrProcessorKeyBuilder* b) const {
-    b->add32(fAttachmentFlags);
-    if (fAttachmentFlags & kColor_AttachmentFlag) {
-        b->add32(fAttachmentsDescriptor.fColor.fFormat);
-        b->add32(fAttachmentsDescriptor.fColor.fSamples);
+    GenKey(b, fAttachmentFlags, fAttachmentsDescriptor, (uint64_t)fRenderPass);
+}
+
+void GrVkRenderPass::GenKey(GrProcessorKeyBuilder* b,
+                            AttachmentFlags attachmentFlags,
+                            const AttachmentsDescriptor& attachmentsDescriptor,
+                            uint64_t externalRenderPass) {
+    b->add32(attachmentFlags);
+    if (attachmentFlags & kColor_AttachmentFlag) {
+        b->add32(attachmentsDescriptor.fColor.fFormat);
+        b->add32(attachmentsDescriptor.fColor.fSamples);
     }
-    if (fAttachmentFlags & kStencil_AttachmentFlag) {
-        b->add32(fAttachmentsDescriptor.fStencil.fFormat);
-        b->add32(fAttachmentsDescriptor.fStencil.fSamples);
+    if (attachmentFlags & kStencil_AttachmentFlag) {
+        b->add32(attachmentsDescriptor.fStencil.fFormat);
+        b->add32(attachmentsDescriptor.fStencil.fSamples);
     }
-    if (fAttachmentFlags & kExternal_AttachmentFlag) {
-        SkASSERT(!(fAttachmentFlags & ~kExternal_AttachmentFlag));
-        uint64_t handle = (uint64_t)fRenderPass;
-        b->add32((uint32_t)(handle & 0xFFFFFFFF));
-        b->add32((uint32_t)(handle>>32));
+    if (attachmentFlags & kExternal_AttachmentFlag) {
+        SkASSERT(!(attachmentFlags & ~kExternal_AttachmentFlag));
+        b->add32((uint32_t)(externalRenderPass & 0xFFFFFFFF));
+        b->add32((uint32_t)(externalRenderPass>>32));
     }
 }
diff --git a/src/gpu/vk/GrVkRenderPass.h b/src/gpu/vk/GrVkRenderPass.h
index 5009e1e..9a0170d 100644
--- a/src/gpu/vk/GrVkRenderPass.h
+++ b/src/gpu/vk/GrVkRenderPass.h
@@ -108,6 +108,8 @@
 
     bool isCompatibleExternalRP(VkRenderPass) const;
 
+    SkDEBUGCODE(bool isExternal() const { return fAttachmentFlags & kExternal_AttachmentFlag; })
+
     bool equalLoadStoreOps(const LoadStoreOps& colorOps,
                            const LoadStoreOps& stencilOps) const;
 
@@ -120,7 +122,12 @@
     uint32_t clearValueCount() const { return fClearValueCount; }
 
 
-    void genKey(GrProcessorKeyBuilder* b) const;
+    void genKey(GrProcessorKeyBuilder*) const;
+
+    static void GenKey(GrProcessorKeyBuilder*,
+                       AttachmentFlags,
+                       const AttachmentsDescriptor&,
+                       uint64_t externalRenderPass);
 
 #ifdef SK_TRACE_MANAGED_RESOURCES
     void dumpInfo() const override {
diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp
index c2afefc..74f0f4d 100644
--- a/src/gpu/vk/GrVkRenderTarget.cpp
+++ b/src/gpu/vk/GrVkRenderTarget.cpp
@@ -343,6 +343,36 @@
     desc->fAttachmentCount = attachmentCount;
 }
 
+void GrVkRenderTarget::ReconstructAttachmentsDescriptor(const GrVkCaps& vkCaps,
+                                                        const GrProgramInfo& programInfo,
+                                                        GrVkRenderPass::AttachmentsDescriptor* desc,
+                                                        GrVkRenderPass::AttachmentFlags* flags) {
+    VkFormat format;
+    SkAssertResult(programInfo.backendFormat().asVkFormat(&format));
+
+    desc->fColor.fFormat = format;
+    desc->fColor.fSamples = programInfo.numSamples();
+    *flags = GrVkRenderPass::kColor_AttachmentFlag;
+    uint32_t attachmentCount = 1;
+
+    SkASSERT(!programInfo.isStencilEnabled() || programInfo.numStencilSamples());
+    if (programInfo.numStencilSamples()) {
+        const GrVkCaps::StencilFormat& stencilFormat = vkCaps.preferredStencilFormat();
+        desc->fStencil.fFormat = stencilFormat.fInternalFormat;
+        desc->fStencil.fSamples = programInfo.numStencilSamples();
+#ifdef SK_DEBUG
+        if (vkCaps.mixedSamplesSupport()) {
+            SkASSERT(desc->fStencil.fSamples >= desc->fColor.fSamples);
+        } else {
+            SkASSERT(desc->fStencil.fSamples == desc->fColor.fSamples);
+        }
+#endif
+        *flags |= GrVkRenderPass::kStencil_AttachmentFlag;
+        ++attachmentCount;
+    }
+    desc->fAttachmentCount = attachmentCount;
+}
+
 GrVkRenderTarget::~GrVkRenderTarget() {
     // either release or abandon should have been called by the owner of this object.
     SkASSERT(!fMSAAImage);
diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h
index 94ad40f..32149d1 100644
--- a/src/gpu/vk/GrVkRenderTarget.h
+++ b/src/gpu/vk/GrVkRenderTarget.h
@@ -100,6 +100,14 @@
                                   GrVkRenderPass::AttachmentFlags* flags,
                                   bool withStencil) const;
 
+    // Reconstruct the render target attachment information from the programInfo. This includes
+    // which attachments the render target will have (color, stencil) and the attachments' formats
+    // and sample counts - cf. getAttachmentsDescriptor.
+    static void ReconstructAttachmentsDescriptor(const GrVkCaps& vkCaps,
+                                                 const GrProgramInfo& programInfo,
+                                                 GrVkRenderPass::AttachmentsDescriptor* desc,
+                                                 GrVkRenderPass::AttachmentFlags* flags);
+
     void addResources(GrVkCommandBuffer& commandBuffer, bool withStencil);
 
     void addWrappedGrSecondaryCommandBuffer(std::unique_ptr<GrVkSecondaryCommandBuffer> cmdBuffer) {