Add static buffer support

Put resource tracking check in the right place

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2112653002

Review-Url: https://codereview.chromium.org/2112653002
diff --git a/src/gpu/vk/GrVkBuffer.cpp b/src/gpu/vk/GrVkBuffer.cpp
index 1c7c4d0..d28a8cc 100644
--- a/src/gpu/vk/GrVkBuffer.cpp
+++ b/src/gpu/vk/GrVkBuffer.cpp
@@ -29,23 +29,26 @@
     bufInfo.flags = 0;
     bufInfo.size = desc.fSizeInBytes;
     switch (desc.fType) {
-    case kVertex_Type:
-        bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
-        break;
-    case kIndex_Type:
-        bufInfo.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
-        break;
-    case kUniform_Type:
-        bufInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
-        break;
-    case kCopyRead_Type:
-        bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
-        break;
-    case kCopyWrite_Type:
-        bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
-        break;
-
+        case kVertex_Type:
+            bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+            break;
+        case kIndex_Type:
+            bufInfo.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+            break;
+        case kUniform_Type:
+            bufInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+            break;
+        case kCopyRead_Type:
+            bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+            break;
+        case kCopyWrite_Type:
+            bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+            break;
     }
+    if (!desc.fDynamic) {
+        bufInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+    }
+
     bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
     bufInfo.queueFamilyIndexCount = 0;
     bufInfo.pQueueFamilyIndices = nullptr;
@@ -59,6 +62,7 @@
     if (!GrVkMemory::AllocAndBindBufferMemory(gpu,
                                               buffer,
                                               desc.fType,
+                                              desc.fDynamic,
                                               &alloc)) {
         return nullptr;
     }
@@ -120,6 +124,9 @@
 void* GrVkBuffer::vkMap(const GrVkGpu* gpu) {
     VALIDATE();
     SkASSERT(!this->vkIsMapped());
+    if (!fDesc.fDynamic) {
+        return nullptr;
+    }
 
     if (!fResource->unique()) {
         // in use by the command buffer, so we need to create a new one
@@ -141,6 +148,7 @@
 void GrVkBuffer::vkUnmap(const GrVkGpu* gpu) {
     VALIDATE();
     SkASSERT(this->vkIsMapped());
+    SkASSERT(fDesc.fDynamic);
 
     VK_CALL(gpu, UnmapMemory(gpu->device(), this->alloc().fMemory));
 
@@ -152,7 +160,7 @@
     return SkToBool(fMapPtr);
 }
 
-bool GrVkBuffer::vkUpdateData(const GrVkGpu* gpu, const void* src, size_t srcSizeInBytes,
+bool GrVkBuffer::vkUpdateData(GrVkGpu* gpu, const void* src, size_t srcSizeInBytes,
                               bool* createdNewBuffer) {
     SkASSERT(!this->vkIsMapped());
     VALIDATE();
@@ -160,6 +168,10 @@
         return false;
     }
 
+    if (!fDesc.fDynamic) {
+        return gpu->updateBuffer(this, src, srcSizeInBytes);
+    }
+
     if (!fResource->unique()) {
         // in use by the command buffer, so we need to create a new one
         fResource->unref(gpu);
diff --git a/src/gpu/vk/GrVkBuffer.h b/src/gpu/vk/GrVkBuffer.h
index 0bfbeca..985b586 100644
--- a/src/gpu/vk/GrVkBuffer.h
+++ b/src/gpu/vk/GrVkBuffer.h
@@ -79,7 +79,7 @@
     void vkUnmap(const GrVkGpu* gpu);
     // If the caller passes in a non null createdNewBuffer, this function will set the bool to true
     // if it creates a new VkBuffer to upload the data to.
-    bool vkUpdateData(const GrVkGpu* gpu, const void* src, size_t srcSizeInBytes,
+    bool vkUpdateData(GrVkGpu* gpu, const void* src, size_t srcSizeInBytes,
                       bool* createdNewBuffer = nullptr);
 
     void vkAbandon();
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index 4a469fe..f076c0b 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -475,6 +475,25 @@
                                                         copyRegions));
 }
 
+void GrVkPrimaryCommandBuffer::updateBuffer(GrVkGpu* gpu,
+                                            GrVkBuffer* dstBuffer,
+                                            VkDeviceSize dstOffset,
+                                            VkDeviceSize dataSize,
+                                            const void* data) {
+    SkASSERT(fIsActive);
+    SkASSERT(!fActiveRenderPass);
+    SkASSERT(0 == (dstOffset & 0x03));   // four byte aligned
+    // TODO: handle larger transfer sizes
+    SkASSERT(dataSize <= 65536);
+    SkASSERT(0 == (dataSize & 0x03));    // four byte aligned
+    this->addResource(dstBuffer->resource());
+    GR_VK_CALL(gpu->vkInterface(), CmdUpdateBuffer(fCmdBuffer,
+                                                   dstBuffer->buffer(),
+                                                   dstOffset,
+                                                   dataSize,
+                                                   (const uint32_t*) data));
+}
+
 void GrVkPrimaryCommandBuffer::clearColorImage(const GrVkGpu* gpu,
                                                GrVkImage* image,
                                                const VkClearColorValue* color,
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index 87c33c0..95935f0 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -251,6 +251,12 @@
                            uint32_t copyRegionCount,
                            const VkBufferImageCopy* copyRegions);
 
+    void updateBuffer(GrVkGpu* gpu,
+                      GrVkBuffer* dstBuffer,
+                      VkDeviceSize dstOffset,
+                      VkDeviceSize dataSize,
+                      const void* data);
+
     void submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync);
     bool finished(const GrVkGpu* gpu) const;
 
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index e5d24fc..ab6761c 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -425,9 +425,9 @@
 }
 
 bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex,
-                                    int left, int top, int width, int height,
-                                    GrPixelConfig dataConfig,
-                                    const SkTArray<GrMipLevel>& texels) {
+                                   int left, int top, int width, int height,
+                                   GrPixelConfig dataConfig,
+                                   const SkTArray<GrMipLevel>& texels) {
     SkASSERT(!tex->isLinearTiled());
     // The assumption is either that we have no mipmaps, or that our rect is the entire texture
     SkASSERT(1 == texels.count() ||
@@ -555,10 +555,6 @@
                                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                                          regions.count(),
                                          regions.begin());
-
-    // Submit the current command buffer to the Queue
-    this->submitCommandBuffer(kSkip_SyncQueue);
-
     transferBuffer->unref();
 
     return true;
@@ -661,6 +657,16 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+bool GrVkGpu::updateBuffer(GrVkBuffer* buffer, const void* src, size_t srcSizeInBytes) {
+
+    // Update the buffer
+    fCurrentCmdBuffer->updateBuffer(this, buffer, 0, srcSizeInBytes, src);
+
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin) {
     // By default, all textures in Vk use TopLeft
     if (kDefault_GrSurfaceOrigin == origin) {
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 011189a..3373abd 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -125,6 +125,8 @@
 
     void generateMipmap(GrVkTexture* tex) const;
 
+    bool updateBuffer(GrVkBuffer* buffer, const void* src, size_t srcSizeInBytes);
+
     // Heaps
     enum Heap {
         kLinearImage_Heap = 0,
diff --git a/src/gpu/vk/GrVkMemory.cpp b/src/gpu/vk/GrVkMemory.cpp
index e411d2d..1983db5 100644
--- a/src/gpu/vk/GrVkMemory.cpp
+++ b/src/gpu/vk/GrVkMemory.cpp
@@ -49,6 +49,7 @@
 bool GrVkMemory::AllocAndBindBufferMemory(const GrVkGpu* gpu,
                                           VkBuffer buffer,
                                           GrVkBuffer::Type type,
+                                          bool dynamic,
                                           GrVkAlloc* alloc) {
     const GrVkInterface* iface = gpu->vkInterface();
     VkDevice device = gpu->device();
@@ -56,9 +57,10 @@
     VkMemoryRequirements memReqs;
     GR_VK_CALL(iface, GetBufferMemoryRequirements(device, buffer, &memReqs));
 
-    VkMemoryPropertyFlags desiredMemProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
-                                            VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
-                                            VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+    VkMemoryPropertyFlags desiredMemProps = dynamic ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+                                                      VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
+                                                      VK_MEMORY_PROPERTY_HOST_CACHED_BIT
+                                                    : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
     uint32_t typeIndex = 0;
     if (!get_valid_memory_type_index(gpu->physicalDeviceMemoryProperties(),
                                      memReqs.memoryTypeBits,
diff --git a/src/gpu/vk/GrVkMemory.h b/src/gpu/vk/GrVkMemory.h
index 44c8286..2b9feda 100644
--- a/src/gpu/vk/GrVkMemory.h
+++ b/src/gpu/vk/GrVkMemory.h
@@ -24,6 +24,7 @@
     bool AllocAndBindBufferMemory(const GrVkGpu* gpu,
                                   VkBuffer buffer,
                                   GrVkBuffer::Type type,
+                                  bool dynamic,
                                   GrVkAlloc* alloc);
     void FreeBufferMemory(const GrVkGpu* gpu, GrVkBuffer::Type type, const GrVkAlloc& alloc);
 
diff --git a/src/gpu/vk/GrVkPipelineStateDataManager.cpp b/src/gpu/vk/GrVkPipelineStateDataManager.cpp
index 13b363f..9fa6d6d 100644
--- a/src/gpu/vk/GrVkPipelineStateDataManager.cpp
+++ b/src/gpu/vk/GrVkPipelineStateDataManager.cpp
@@ -251,7 +251,7 @@
     }
 };
 
-bool GrVkPipelineStateDataManager::uploadUniformBuffers(const GrVkGpu* gpu,
+bool GrVkPipelineStateDataManager::uploadUniformBuffers(GrVkGpu* gpu,
                                                         GrVkUniformBuffer* vertexBuffer,
                                                         GrVkUniformBuffer* fragmentBuffer) const {
     bool updatedBuffer = false;
diff --git a/src/gpu/vk/GrVkPipelineStateDataManager.h b/src/gpu/vk/GrVkPipelineStateDataManager.h
index c22e779..eb7176c 100644
--- a/src/gpu/vk/GrVkPipelineStateDataManager.h
+++ b/src/gpu/vk/GrVkPipelineStateDataManager.h
@@ -50,7 +50,7 @@
     // Returns true if either the vertex or fragment buffer needed to generate a new underlying
     // VkBuffer object in order upload data. If true is returned, this is a signal to the caller
     // that they will need to update the descriptor set that is using these buffers.
-    bool uploadUniformBuffers(const GrVkGpu* gpu,
+    bool uploadUniformBuffers(GrVkGpu* gpu,
                               GrVkUniformBuffer* vertexBuffer,
                               GrVkUniformBuffer* fragmentBuffer) const;
 private:
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index 31d5568..4f6c792 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -261,10 +261,6 @@
 
     fPipelineStateCache->release();
 
-#ifdef SK_TRACE_VK_RESOURCES
-    SkASSERT(0 == GrVkResource::fTrace.count());
-#endif
-
     GR_VK_CALL(fGpu->vkInterface(), DestroyPipelineCache(fGpu->device(), fPipelineCache, nullptr));
     fPipelineCache = VK_NULL_HANDLE;
 
@@ -275,6 +271,10 @@
         fUniformDescLayout = VK_NULL_HANDLE;
     }
     fUniformDescPool->unref(fGpu);
+
+#ifdef SK_TRACE_VK_RESOURCES
+    SkASSERT(0 == GrVkResource::fTrace.count());
+#endif
 }
 
 void GrVkResourceProvider::abandonResources() {
@@ -300,13 +300,14 @@
 
     fPipelineStateCache->abandon();
 
-#ifdef SK_TRACE_VK_RESOURCES
-    SkASSERT(0 == GrVkResource::fTrace.count());
-#endif
     fPipelineCache = VK_NULL_HANDLE;
 
     fUniformDescLayout = VK_NULL_HANDLE;
     fUniformDescPool->unrefAndAbandon();
+
+#ifdef SK_TRACE_VK_RESOURCES
+    SkASSERT(0 == GrVkResource::fTrace.count());
+#endif
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/vk/GrVkTransferBuffer.cpp b/src/gpu/vk/GrVkTransferBuffer.cpp
index 4cf5c1b..f291dcd 100644
--- a/src/gpu/vk/GrVkTransferBuffer.cpp
+++ b/src/gpu/vk/GrVkTransferBuffer.cpp
@@ -12,7 +12,7 @@
 
 GrVkTransferBuffer* GrVkTransferBuffer::Create(GrVkGpu* gpu, size_t size, GrVkBuffer::Type type) {
     GrVkBuffer::Desc desc;
-    desc.fDynamic = false;
+    desc.fDynamic = true;
     SkASSERT(GrVkBuffer::kCopyRead_Type == type || GrVkBuffer::kCopyWrite_Type == type);
     desc.fType = type;
     desc.fSizeInBytes = size;
diff --git a/src/gpu/vk/GrVkUniformBuffer.h b/src/gpu/vk/GrVkUniformBuffer.h
index 37ede72..bfaf240 100644
--- a/src/gpu/vk/GrVkUniformBuffer.h
+++ b/src/gpu/vk/GrVkUniformBuffer.h
@@ -25,7 +25,7 @@
     }
     // The output variable createdNewBuffer must be set to true if a new VkBuffer is created in
     // order to upload the data
-    bool updateData(const GrVkGpu* gpu, const void* src, size_t srcSizeInBytes,
+    bool updateData(GrVkGpu* gpu, const void* src, size_t srcSizeInBytes,
                     bool* createdNewBuffer) {
         return this->vkUpdateData(gpu, src, srcSizeInBytes, createdNewBuffer);
     }