Add support for vkCmdCopyBuffer

This is then used when need to update GPU only buffers with data of size
greater than 65536. We create a temporary transfer buffer and then copy
that buffer into our GPU buffer.

Bug: skia:
Change-Id: I4bb9cb660f2ac1ccbbd1b508bb4ca6876342136f
Reviewed-on: https://skia-review.googlesource.com/38725
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/vk/GrVkBuffer.cpp b/src/gpu/vk/GrVkBuffer.cpp
index 9926ec4..b2af229 100644
--- a/src/gpu/vk/GrVkBuffer.cpp
+++ b/src/gpu/vk/GrVkBuffer.cpp
@@ -8,6 +8,7 @@
 #include "GrVkBuffer.h"
 #include "GrVkGpu.h"
 #include "GrVkMemory.h"
+#include "GrVkTransferBuffer.h"
 #include "GrVkUtil.h"
 
 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
@@ -192,7 +193,22 @@
         VK_CALL(gpu, UnmapMemory(gpu->device(), this->alloc().fMemory));
         fMapPtr = nullptr;
     } else {
-        gpu->updateBuffer(this, fMapPtr, this->offset(), size);
+        if (size <= 65536) {
+            gpu->updateBuffer(this, fMapPtr, this->offset(), size);
+        } else {
+            GrVkTransferBuffer* transferBuffer =
+                    GrVkTransferBuffer::Create(gpu, size, GrVkBuffer::kCopyRead_Type);
+            if(!transferBuffer) {
+                return;
+            }
+
+            char* buffer = (char*) transferBuffer->map();
+            memcpy (buffer, fMapPtr, size);
+            transferBuffer->unmap();
+
+            gpu->copyBuffer(transferBuffer, this, 0, this->offset(), size);
+            transferBuffer->unref();
+        }
         this->addMemoryBarrier(gpu,
                                VK_ACCESS_TRANSFER_WRITE_BIT,
                                buffer_type_to_access_flags(fDesc.fType),
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index 1f124a6..c44d121 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -637,6 +637,33 @@
                                                         copyRegions));
 }
 
+
+void GrVkPrimaryCommandBuffer::copyBuffer(GrVkGpu* gpu,
+                                          GrVkBuffer* srcBuffer,
+                                          GrVkBuffer* dstBuffer,
+                                          uint32_t regionCount,
+                                          const VkBufferCopy* regions) {
+    SkASSERT(fIsActive);
+    SkASSERT(!fActiveRenderPass);
+#ifdef SK_DEBUG
+    for (uint32_t i = 0; i < regionCount; ++i) {
+        const VkBufferCopy& region = regions[i];
+        SkASSERT(region.size > 0);
+        SkASSERT(region.srcOffset < srcBuffer->size());
+        SkASSERT(region.dstOffset < dstBuffer->size());
+        SkASSERT(region.srcOffset + region.size <= srcBuffer->size());
+        SkASSERT(region.dstOffset + region.size <= dstBuffer->size());
+    }
+#endif
+    this->addResource(srcBuffer->resource());
+    this->addResource(dstBuffer->resource());
+    GR_VK_CALL(gpu->vkInterface(), CmdCopyBuffer(fCmdBuffer,
+                                                 srcBuffer->buffer(),
+                                                 dstBuffer->buffer(),
+                                                 regionCount,
+                                                 regions));
+}
+
 void GrVkPrimaryCommandBuffer::updateBuffer(GrVkGpu* gpu,
                                             GrVkBuffer* dstBuffer,
                                             VkDeviceSize dstOffset,
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index 548efad..7d16242 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -250,6 +250,12 @@
                            uint32_t copyRegionCount,
                            const VkBufferImageCopy* copyRegions);
 
+    void copyBuffer(GrVkGpu* gpu,
+                    GrVkBuffer* srcBuffer,
+                    GrVkBuffer* dstBuffer,
+                    uint32_t regionCount,
+                    const VkBufferCopy* regions);
+
     void updateBuffer(GrVkGpu* gpu,
                       GrVkBuffer* dstBuffer,
                       VkDeviceSize dstOffset,
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index a36bbe5..83d28de 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -690,8 +690,9 @@
     // allocate buffer to hold our mip data
     GrVkTransferBuffer* transferBuffer =
                    GrVkTransferBuffer::Create(this, combinedBufferSize, GrVkBuffer::kCopyRead_Type);
-    if(!transferBuffer)
+    if(!transferBuffer) {
         return false;
+    }
 
     char* buffer = (char*) transferBuffer->map();
     SkTArray<VkBufferImageCopy> regions(mipLevelCount);
@@ -844,9 +845,17 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+void GrVkGpu::copyBuffer(GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, VkDeviceSize srcOffset,
+                         VkDeviceSize dstOffset, VkDeviceSize size) {
+    VkBufferCopy copyRegion;
+    copyRegion.srcOffset = srcOffset;
+    copyRegion.dstOffset = dstOffset;
+    copyRegion.size = size;
+    fCurrentCmdBuffer->copyBuffer(this, srcBuffer, dstBuffer, 1, &copyRegion);
+}
+
 bool GrVkGpu::updateBuffer(GrVkBuffer* buffer, const void* src,
                            VkDeviceSize offset, VkDeviceSize size) {
-
     // Update the buffer
     fCurrentCmdBuffer->updateBuffer(this, buffer, offset, size, src);
 
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index ad157ca..f36ec31 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -144,6 +144,8 @@
 
     void generateMipmap(GrVkTexture* tex);
 
+    void copyBuffer(GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, VkDeviceSize srcOffset,
+                    VkDeviceSize dstOffset, VkDeviceSize size);
     bool updateBuffer(GrVkBuffer* buffer, const void* src, VkDeviceSize offset, VkDeviceSize size);
 
     // Heaps
diff --git a/tests/TessellatingPathRendererTests.cpp b/tests/TessellatingPathRendererTests.cpp
index 78704d94..0ae5d55 100644
--- a/tests/TessellatingPathRendererTests.cpp
+++ b/tests/TessellatingPathRendererTests.cpp
@@ -454,9 +454,6 @@
     test_path(ctx, rtc.get(), create_path_21(), SkMatrix(), GrAAType::kCoverage);
     test_path(ctx, rtc.get(), create_path_22());
     test_path(ctx, rtc.get(), create_path_23());
-    // TODO: implement large buffer uploads in VK and remove this check.
-    if (ctx->contextPriv().getBackend() != kVulkan_GrBackend) {
-        test_path(ctx, rtc.get(), create_path_24());
-    }
+    test_path(ctx, rtc.get(), create_path_24());
 }
 #endif