Add unit test the explicit tests create a GrVkCopyPipeline

Bug: skia:7663
Change-Id: I9883d903302fbbcd42f73601f49af96b6cc875ba
Reviewed-on: https://skia-review.googlesource.com/111361
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Hal Canary <halcanary@google.com>
(cherry picked from commit f3a4ef91d8d0b0ade21d2f86320f1a988816ba31)
Reviewed-on: https://skia-review.googlesource.com/111303
diff --git a/gn/tests.gni b/gn/tests.gni
index e4519d9..b218c5c 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -275,6 +275,7 @@
   "$_tests/VerticesTest.cpp",
   "$_tests/VkClearTests.cpp",
   "$_tests/VkHeapTests.cpp",
+  "$_tests/VkMakeCopyPipelineTest.cpp",
   "$_tests/VkUploadPixelsTests.cpp",
   "$_tests/VkWrapTests.cpp",
   "$_tests/VptrTest.cpp",
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index 765e838..9a219c8 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -88,6 +88,9 @@
                                             dst->numColorSamples(),
                                             *dst->simpleRenderPass(),
                                             fPipelineCache);
+        if (!pipeline) {
+            return nullptr;
+        }
         fCopyPipelines.push_back(pipeline);
     }
     SkASSERT(pipeline);
diff --git a/tests/VkMakeCopyPipelineTest.cpp b/tests/VkMakeCopyPipelineTest.cpp
new file mode 100644
index 0000000..f9a0ec6
--- /dev/null
+++ b/tests/VkMakeCopyPipelineTest.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// This is a GPU-backend specific test. It relies on static intializers to work
+
+#include "SkTypes.h"
+
+#if SK_SUPPORT_GPU && defined(SK_VULKAN)
+
+#include "GrContextFactory.h"
+#include "GrContextPriv.h"
+#include "GrTest.h"
+#include "GrTexture.h"
+#include "Test.h"
+#include "vk/GrVkCopyPipeline.h"
+#include "vk/GrVkGpu.h"
+#include "vk/GrVkRenderTarget.h"
+#include "vk/GrVkUtil.h"
+
+using sk_gpu_test::GrContextFactory;
+
+class TestVkCopyProgram {
+public:
+    TestVkCopyProgram()
+            : fVertShaderModule(VK_NULL_HANDLE)
+            , fFragShaderModule(VK_NULL_HANDLE)
+            , fPipelineLayout(VK_NULL_HANDLE) {}
+
+    void test(GrVkGpu* gpu, skiatest::Reporter* reporter) {
+        const char vertShaderText[] =
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+
+            "layout(set = 0, binding = 0) uniform vertexUniformBuffer {"
+            "half4 uPosXform;"
+            "half4 uTexCoordXform;"
+            "};"
+            "layout(location = 0) in float2 inPosition;"
+            "layout(location = 1) out half2 vTexCoord;"
+
+            "// Copy Program VS\n"
+            "void main() {"
+            "vTexCoord = inPosition * uTexCoordXform.xy + uTexCoordXform.zw;"
+            "sk_Position.xy = inPosition * uPosXform.xy + uPosXform.zw;"
+            "sk_Position.zw = half2(0, 1);"
+            "}";
+
+        const char fragShaderText[] =
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+
+            "layout(set = 1, binding = 0) uniform sampler2D uTextureSampler;"
+            "layout(location = 1) in half2 vTexCoord;"
+            "layout(location = 0, index = 0) out half4 fsColorOut;"
+
+            "// Copy Program FS\n"
+            "void main() {"
+            "fsColorOut = texture(uTextureSampler, vTexCoord);"
+            "}";
+
+        SkSL::Program::Settings settings;
+        SkSL::Program::Inputs inputs;
+        if (!GrCompileVkShaderModule(gpu, vertShaderText, VK_SHADER_STAGE_VERTEX_BIT,
+                                     &fVertShaderModule, &fShaderStageInfo[0], settings, &inputs)) {
+            this->destroyResources(gpu);
+            REPORTER_ASSERT(reporter, false);
+            return;
+        }
+        SkASSERT(inputs.isEmpty());
+
+        if (!GrCompileVkShaderModule(gpu, fragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT,
+                                     &fFragShaderModule, &fShaderStageInfo[1], settings, &inputs)) {
+            this->destroyResources(gpu);
+            REPORTER_ASSERT(reporter, false);
+            return;
+        }
+
+        VkDescriptorSetLayout dsLayout[2];
+
+        GrVkResourceProvider& resourceProvider = gpu->resourceProvider();
+
+        dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout();
+
+        uint32_t samplerVisibility = kFragment_GrShaderFlag;
+        SkTArray<uint32_t> visibilityArray(&samplerVisibility, 1);
+
+        resourceProvider.getSamplerDescriptorSetHandle(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                                                       visibilityArray, &fSamplerDSHandle);
+        dsLayout[GrVkUniformHandler::kSamplerDescSet] =
+                resourceProvider.getSamplerDSLayout(fSamplerDSHandle);
+
+        // Create the VkPipelineLayout
+        VkPipelineLayoutCreateInfo layoutCreateInfo;
+        memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags));
+        layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+        layoutCreateInfo.pNext = 0;
+        layoutCreateInfo.flags = 0;
+        layoutCreateInfo.setLayoutCount = 2;
+        layoutCreateInfo.pSetLayouts = dsLayout;
+        layoutCreateInfo.pushConstantRangeCount = 0;
+        layoutCreateInfo.pPushConstantRanges = nullptr;
+
+        VkResult err = GR_VK_CALL(gpu->vkInterface(), CreatePipelineLayout(gpu->device(),
+                                                                           &layoutCreateInfo,
+                                                                           nullptr,
+                                                                           &fPipelineLayout));
+        if (err) {
+            this->destroyResources(gpu);
+            REPORTER_ASSERT(reporter, false);
+            return;
+        }
+
+        GrSurfaceDesc surfDesc;
+        surfDesc.fFlags = kRenderTarget_GrSurfaceFlag;
+        surfDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
+        surfDesc.fWidth = 16;
+        surfDesc.fHeight = 16;
+        surfDesc.fConfig = kRGBA_8888_GrPixelConfig;
+        surfDesc.fSampleCnt = 1;
+        sk_sp<GrTexture> tex = gpu->createTexture(surfDesc, SkBudgeted::kNo);
+        if (!tex) {
+            this->destroyResources(gpu);
+            REPORTER_ASSERT(reporter, tex.get());
+            return;
+
+        }
+        GrRenderTarget* rt = tex->asRenderTarget();
+        REPORTER_ASSERT(reporter, rt);
+        GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt);
+
+        GrVkCopyPipeline* copyPipeline = GrVkCopyPipeline::Create(gpu,
+                                                                  fShaderStageInfo,
+                                                                  fPipelineLayout,
+                                                                  1,
+                                                                  *vkRT->simpleRenderPass(),
+                                                                  VK_NULL_HANDLE);
+
+        REPORTER_ASSERT(reporter, copyPipeline);
+        if (copyPipeline) {
+            copyPipeline->unref(gpu);
+        }
+
+        this->destroyResources(gpu);
+    }
+
+    void destroyResources(GrVkGpu* gpu) {
+        if (VK_NULL_HANDLE != fVertShaderModule) {
+            GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fVertShaderModule,
+                                                               nullptr));
+            fVertShaderModule = VK_NULL_HANDLE;
+        }
+
+        if (VK_NULL_HANDLE != fFragShaderModule) {
+            GR_VK_CALL(gpu->vkInterface(), DestroyShaderModule(gpu->device(), fFragShaderModule,
+                                                               nullptr));
+            fFragShaderModule = VK_NULL_HANDLE;
+        }
+
+        if (VK_NULL_HANDLE != fPipelineLayout) {
+            GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(), fPipelineLayout,
+                                                                 nullptr));
+            fPipelineLayout = VK_NULL_HANDLE;
+        }
+    }
+
+    VkShaderModule fVertShaderModule;
+    VkShaderModule fFragShaderModule;
+    VkPipelineShaderStageCreateInfo fShaderStageInfo[2];
+
+    GrVkDescriptorSetManager::Handle fSamplerDSHandle;
+    VkPipelineLayout fPipelineLayout;
+
+};
+
+DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkMakeCopyPipelineTest, reporter, ctxInfo) {
+    GrContext* context = ctxInfo.grContext();
+    GrVkGpu* gpu = static_cast<GrVkGpu*>(context->contextPriv().getGpu());
+
+    if (!gpu->vkCaps().supportsCopiesAsDraws()) {
+        return;
+    }
+
+    TestVkCopyProgram copyProgram;
+    copyProgram.test(gpu, reporter);
+}
+
+#endif