Add support for vk image sharing mode and handle queues xfers correctly.

Change-Id: I9dbe6020d67cc452c9cbbdeace68f1d01275b419
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/293559
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/GrAHardwareBufferUtils.cpp b/src/gpu/GrAHardwareBufferUtils.cpp
index b701daf..badb8ee 100644
--- a/src/gpu/GrAHardwareBufferUtils.cpp
+++ b/src/gpu/GrAHardwareBufferUtils.cpp
@@ -486,6 +486,7 @@
     // "foreign" device we can leave them as external.
     imageInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
     imageInfo.fYcbcrConversionInfo = *ycbcrConversion;
+    imageInfo.fSharingMode = imageCreateInfo.sharingMode;
 
     *deleteProc = delete_vk_image;
     *updateProc = update_vk_image;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 97d819f..c8ee2c7 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1198,7 +1198,8 @@
 
 static bool check_image_info(const GrVkCaps& caps,
                              const GrVkImageInfo& info,
-                             bool needsAllocation) {
+                             bool needsAllocation,
+                             uint32_t graphicsQueueIndex) {
     if (VK_NULL_HANDLE == info.fImage) {
         return false;
     }
@@ -1211,6 +1212,18 @@
         return false;
     }
 
+    if (info.fCurrentQueueFamily != VK_QUEUE_FAMILY_IGNORED &&
+        info.fCurrentQueueFamily != VK_QUEUE_FAMILY_EXTERNAL &&
+        info.fCurrentQueueFamily != VK_QUEUE_FAMILY_FOREIGN_EXT) {
+        if (info.fSharingMode == VK_SHARING_MODE_EXCLUSIVE) {
+            if (info.fCurrentQueueFamily != graphicsQueueIndex) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
     if (info.fYcbcrConversionInfo.isValid()) {
         if (!caps.supportsYcbcrConversion()) {
             return false;
@@ -1256,7 +1269,8 @@
         return nullptr;
     }
 
-    if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership)) {
+    if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership,
+                          this->queueIndex())) {
         return nullptr;
     }
 
@@ -1282,7 +1296,8 @@
         return nullptr;
     }
 
-    if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership)) {
+    if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership,
+                          this->queueIndex())) {
         return nullptr;
     }
 
@@ -1309,7 +1324,8 @@
         return nullptr;
     }
 
-    if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership)) {
+    if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership,
+                          this->queueIndex())) {
         return nullptr;
     }
 
@@ -1349,7 +1365,7 @@
         return nullptr;
     }
 
-    if (!check_image_info(this->vkCaps(), info, false)) {
+    if (!check_image_info(this->vkCaps(), info, false, this->queueIndex())) {
         return nullptr;
     }
 
@@ -1382,7 +1398,7 @@
     if (!tex.getVkImageInfo(&imageInfo)) {
         return nullptr;
     }
-    if (!check_image_info(this->vkCaps(), imageInfo, false)) {
+    if (!check_image_info(this->vkCaps(), imageInfo, false, this->queueIndex())) {
         return nullptr;
     }
 
diff --git a/src/gpu/vk/GrVkImage.cpp b/src/gpu/vk/GrVkImage.cpp
index 9b50ca7..1270743 100644
--- a/src/gpu/vk/GrVkImage.cpp
+++ b/src/gpu/vk/GrVkImage.cpp
@@ -13,6 +13,43 @@
 
 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
 
+GrVkImage::GrVkImage(const GrVkGpu* gpu,
+                     const GrVkImageInfo& info,
+                     sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
+                     GrBackendObjectOwnership ownership,
+                     bool forSecondaryCB)
+        : fInfo(info)
+        , fInitialQueueFamily(info.fCurrentQueueFamily)
+        , fMutableState(std::move(mutableState))
+        , fIsBorrowed(GrBackendObjectOwnership::kBorrowed == ownership) {
+    SkASSERT(fMutableState->getImageLayout() == fInfo.fImageLayout);
+    SkASSERT(fMutableState->getQueueFamilyIndex() == fInfo.fCurrentQueueFamily);
+#ifdef SK_DEBUG
+    // We can't transfer from the non graphics queue to the graphics queue since we can't
+    // release the image from the original queue without having that queue. This limits us in terms
+    // of the types of queue indices we can handle.
+    if (info.fCurrentQueueFamily != VK_QUEUE_FAMILY_IGNORED &&
+        info.fCurrentQueueFamily != VK_QUEUE_FAMILY_EXTERNAL &&
+        info.fCurrentQueueFamily != VK_QUEUE_FAMILY_FOREIGN_EXT) {
+        if (info.fSharingMode == VK_SHARING_MODE_EXCLUSIVE) {
+            if (info.fCurrentQueueFamily != gpu->queueIndex()) {
+                SkASSERT(false);
+            }
+        } else {
+            SkASSERT(false);
+        }
+    }
+#endif
+    if (forSecondaryCB) {
+        fResource = nullptr;
+    } else if (fIsBorrowed) {
+        fResource = new BorrowedResource(gpu, info.fImage, info.fAlloc, info.fImageTiling);
+    } else {
+        SkASSERT(VK_NULL_HANDLE != info.fAlloc.fMemory);
+        fResource = new Resource(gpu, info.fImage, info.fAlloc, info.fImageTiling);
+    }
+}
+
 VkPipelineStageFlags GrVkImage::LayoutToPipelineSrcStageFlags(const VkImageLayout layout) {
     if (VK_IMAGE_LAYOUT_GENERAL == layout) {
         return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
@@ -116,15 +153,22 @@
     uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
     uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
     if (this->currentQueueFamilyIndex() != VK_QUEUE_FAMILY_IGNORED &&
-        gpu->queueIndex() != this->currentQueueFamilyIndex()) {
+        this->currentQueueFamilyIndex() != gpu->queueIndex()) {
         // The image still is owned by its original queue family and we need to transfer it into
         // ours.
         SkASSERT(!releaseFamilyQueue);
         SkASSERT(this->currentQueueFamilyIndex() == fInitialQueueFamily);
-
+        // We only support transferring from external or foreign queues here and not arbitrary
+        // ones.
+        SkASSERT(this->currentQueueFamilyIndex() == VK_QUEUE_FAMILY_EXTERNAL ||
+                 this->currentQueueFamilyIndex() == VK_QUEUE_FAMILY_FOREIGN_EXT);
         srcQueueFamilyIndex = this->currentQueueFamilyIndex();
-        dstQueueFamilyIndex = gpu->queueIndex();
-        this->setQueueFamilyIndex(gpu->queueIndex());
+        if (fInfo.fSharingMode == VK_SHARING_MODE_EXCLUSIVE) {
+            dstQueueFamilyIndex = gpu->queueIndex();
+        } else {
+            dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        }
+        this->setQueueFamilyIndex(dstQueueFamilyIndex);
     } else if (releaseFamilyQueue) {
         // We are releasing the image so we must transfer the image back to its original queue
         // family.
@@ -217,6 +261,7 @@
     info->fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED;
     info->fProtected =
             (createflags & VK_IMAGE_CREATE_PROTECTED_BIT) ? GrProtected::kYes : GrProtected::kNo;
+    info->fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
     return true;
 }
 
diff --git a/src/gpu/vk/GrVkImage.h b/src/gpu/vk/GrVkImage.h
index 4ff3e7e..d7657dc 100644
--- a/src/gpu/vk/GrVkImage.h
+++ b/src/gpu/vk/GrVkImage.h
@@ -29,22 +29,8 @@
               const GrVkImageInfo& info,
               sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
               GrBackendObjectOwnership ownership,
-              bool forSecondaryCB = false)
-            : fInfo(info)
-            , fInitialQueueFamily(info.fCurrentQueueFamily)
-            , fMutableState(std::move(mutableState))
-            , fIsBorrowed(GrBackendObjectOwnership::kBorrowed == ownership) {
-        SkASSERT(fMutableState->getImageLayout() == fInfo.fImageLayout);
-        SkASSERT(fMutableState->getQueueFamilyIndex() == fInfo.fCurrentQueueFamily);
-        if (forSecondaryCB) {
-            fResource = nullptr;
-        } else if (fIsBorrowed) {
-            fResource = new BorrowedResource(gpu, info.fImage, info.fAlloc, info.fImageTiling);
-        } else {
-            SkASSERT(VK_NULL_HANDLE != info.fAlloc.fMemory);
-            fResource = new Resource(gpu, info.fImage, info.fAlloc, info.fImageTiling);
-        }
-    }
+              bool forSecondaryCB = false);
+
     virtual ~GrVkImage();
 
     VkImage image() const {