Add drawDrawable support to GrRenderTargetContext.

This also includes adding drawable Op and plumbing it through to the GPU.

BUG=skia:

Change-Id: I0b2464c5a458c2fbf05b9528e47b9e6e3ac27d57
Reviewed-on: https://skia-review.googlesource.com/c/9645
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/tests/VkDrawableTest.cpp b/tests/VkDrawableTest.cpp
new file mode 100644
index 0000000..ff24708
--- /dev/null
+++ b/tests/VkDrawableTest.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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 "GrBackendDrawableInfo.h"
+#include "GrContextFactory.h"
+#include "GrContextPriv.h"
+#include "SkDrawable.h"
+#include "SkSurface.h"
+#include "Test.h"
+#include "vk/GrVkGpu.h"
+#include "vk/GrVkInterface.h"
+#include "vk/GrVkMemory.h"
+#include "vk/GrVkUtil.h"
+
+using sk_gpu_test::GrContextFactory;
+
+static const int DEV_W = 16, DEV_H = 16;
+
+class TestDrawable : public SkDrawable {
+public:
+    TestDrawable(const GrVkInterface* interface, int32_t width, int32_t height)
+            : INHERITED()
+            , fInterface(interface)
+            , fWidth(width)
+            , fHeight(height) {}
+
+    ~TestDrawable() override {}
+
+    class DrawHandler : public GpuDrawHandler {
+    public:
+        DrawHandler(const GrVkInterface* interface, int32_t width, int32_t height)
+            : INHERITED()
+            , fInterface(interface)
+            , fWidth(width)
+            , fHeight(height) {}
+        ~DrawHandler() override {}
+
+        void draw(const GrBackendDrawableInfo& info) override {
+            GrVkDrawableInfo vkInfo;
+            SkAssertResult(info.getVkDrawableInfo(&vkInfo));
+
+            // Clear to Red
+            VkClearColorValue vkColor;
+            vkColor.float32[0] = 1.0f; // r
+            vkColor.float32[1] = 0.0f; // g
+            vkColor.float32[2] = 0.0f; // b
+            vkColor.float32[3] = 1.0f; // a
+
+            // Clear right half of render target
+            VkClearRect clearRect;
+            clearRect.rect.offset = { fWidth / 2, 0 };
+            clearRect.rect.extent = { (uint32_t)fWidth / 2, (uint32_t)fHeight };
+            clearRect.baseArrayLayer = 0;
+            clearRect.layerCount = 1;
+
+            VkClearAttachment attachment;
+            attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+            attachment.colorAttachment = vkInfo.fImageAttachmentIndex;
+            attachment.clearValue.color = vkColor;
+
+            GR_VK_CALL(fInterface, CmdClearAttachments(vkInfo.fSecondaryCommandBuffer,
+                                                       1,
+                                                       &attachment,
+                                                       1,
+                                                       &clearRect));
+            vkInfo.fDrawBounds->offset = { fWidth / 2, 0 };
+            vkInfo.fDrawBounds->extent = { (uint32_t)fWidth / 2, (uint32_t)fHeight };
+        }
+    private:
+        const GrVkInterface* fInterface;
+        int32_t              fWidth;
+        int32_t              fHeight;
+
+        typedef GpuDrawHandler INHERITED;
+    };
+
+    std::unique_ptr<GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi backendApi,
+                                                         const SkMatrix& matrix) override {
+        if (backendApi != GrBackendApi::kVulkan) {
+            return nullptr;
+        }
+        std::unique_ptr<DrawHandler> draw(new DrawHandler(fInterface, fWidth, fHeight));
+        return std::move(draw);
+    }
+
+    SkRect onGetBounds() override {
+        return SkRect::MakeLTRB(fWidth / 2, 0, fWidth, fHeight);
+    }
+
+    void onDraw(SkCanvas*) override {
+        SkASSERT(false);
+    }
+
+private:
+    const GrVkInterface* fInterface;
+    int32_t fWidth;
+    int32_t fHeight;
+
+    typedef SkDrawable INHERITED;
+};
+
+void draw_drawable_test(skiatest::Reporter* reporter, GrContext* context) {
+    GrVkGpu* gpu = static_cast<GrVkGpu*>(context->contextPriv().getGpu());
+
+    const SkImageInfo ii = SkImageInfo::Make(DEV_W, DEV_H, kRGBA_8888_SkColorType,
+                                             kPremul_SkAlphaType);
+    sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo,
+                                                         ii, 0, kTopLeft_GrSurfaceOrigin, nullptr));
+    SkCanvas* canvas = surface->getCanvas();
+    canvas->clear(SK_ColorBLUE);
+
+    sk_sp<TestDrawable> drawable(new TestDrawable(gpu->vkInterface(), DEV_W, DEV_H));
+    canvas->drawDrawable(drawable.get());
+
+    SkPaint paint;
+    paint.setColor(SK_ColorGREEN);
+    SkIRect rect = SkIRect::MakeLTRB(0, DEV_H/2, DEV_W, DEV_H);
+    canvas->drawIRect(rect, paint);
+
+    // read pixels
+    SkBitmap bitmap;
+    bitmap.allocPixels(ii);
+    canvas->readPixels(bitmap, 0, 0);
+
+    const uint32_t* canvasPixels = static_cast<const uint32_t*>(bitmap.getPixels());
+    bool failureFound = false;
+    SkPMColor expectedPixel;
+    for (int cy = 0; cy < DEV_H || failureFound; ++cy) {
+        for (int cx = 0; cx < DEV_W || failureFound; ++cx) {
+            SkPMColor canvasPixel = canvasPixels[cy * DEV_W + cx];
+            if (cy < DEV_H / 2) {
+                if (cx < DEV_W / 2) {
+                    expectedPixel = 0xFFFF0000; // Blue
+                } else {
+                    expectedPixel = 0xFF0000FF; // Red
+                }
+            } else {
+                expectedPixel = 0xFF00FF00; // Green
+            }
+            if (expectedPixel != canvasPixel) {
+                failureFound = true;
+                ERRORF(reporter, "Wrong color at %d, %d. Got 0x%08x when we expected 0x%08x",
+                       cx, cy, canvasPixel, expectedPixel);
+            }
+        }
+    }
+}
+
+
+DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkDrawableTest, reporter, ctxInfo) {
+    draw_drawable_test(reporter, ctxInfo.grContext());
+}
+
+#endif