Add GrBackendMutableState object to handle shared texture state.

This is will be the main struct used to synchronize changes of certain
texture/image between clients and Skia. With this change we
implement support for the Vulkan shared state as POC.

Bug: skia:10254
Change-Id: I10543357635c347838b193874e4da4496a0dcf06
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/292311
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrBackendSurface.cpp b/src/gpu/GrBackendSurface.cpp
index 72b9270..c107893 100644
--- a/src/gpu/GrBackendSurface.cpp
+++ b/src/gpu/GrBackendSurface.cpp
@@ -7,6 +7,7 @@
 
 #include "include/gpu/GrBackendSurface.h"
 
+#include "src/gpu/GrBackendSurfaceMutableStateImpl.h"
 #include "src/gpu/gl/GrGLUtil.h"
 
 #ifdef SK_DAWN
@@ -386,6 +387,8 @@
 #endif
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+GrBackendTexture::GrBackendTexture() : fIsValid(false) {}
+
 #ifdef SK_DAWN
 GrBackendTexture::GrBackendTexture(int width,
                                    int height,
@@ -398,12 +401,24 @@
         , fDawnInfo(dawnInfo) {}
 #endif
 
-GrBackendTexture::GrBackendTexture(int width, int height, const GrVkImageInfo& vkInfo)
 #ifdef SK_VULKAN
+GrBackendTexture::GrBackendTexture(int width, int height, const GrVkImageInfo& vkInfo)
         : GrBackendTexture(width, height, vkInfo,
-                           sk_sp<GrVkImageLayout>(new GrVkImageLayout(vkInfo.fImageLayout))) {}
-#else
-        : fIsValid(false) {}
+                           sk_sp<GrBackendSurfaceMutableStateImpl>(
+                                   new GrBackendSurfaceMutableStateImpl(
+                                        vkInfo.fImageLayout, vkInfo.fCurrentQueueFamily))) {}
+
+GrBackendTexture::GrBackendTexture(int width,
+                                   int height,
+                                   const GrVkImageInfo& vkInfo,
+                                   sk_sp<GrBackendSurfaceMutableStateImpl> mutableState)
+        : fIsValid(true)
+        , fWidth(width)
+        , fHeight(height)
+        , fMipMapped(GrMipMapped(vkInfo.fLevelCount > 1))
+        , fBackend(GrBackendApi::kVulkan)
+        , fVkInfo(vkInfo)
+        , fMutableState(std::move(mutableState)) {}
 #endif
 
 #ifdef SK_GL
@@ -427,19 +442,6 @@
 }
 #endif
 
-#ifdef SK_VULKAN
-GrBackendTexture::GrBackendTexture(int width,
-                                   int height,
-                                   const GrVkImageInfo& vkInfo,
-                                   sk_sp<GrVkImageLayout> layout)
-        : fIsValid(true)
-        , fWidth(width)
-        , fHeight(height)
-        , fMipMapped(GrMipMapped(vkInfo.fLevelCount > 1))
-        , fBackend(GrBackendApi::kVulkan)
-        , fVkInfo(vkInfo, layout.release()) {}
-#endif
-
 #ifdef SK_METAL
 GrBackendTexture::GrBackendTexture(int width,
                                    int height,
@@ -566,10 +568,15 @@
         default:
             SK_ABORT("Unknown GrBackend");
     }
+    fMutableState = that.fMutableState;
     fIsValid = true;
     return *this;
 }
 
+sk_sp<GrBackendSurfaceMutableStateImpl> GrBackendTexture::getMutableState() const {
+    return fMutableState;
+}
+
 #ifdef SK_DAWN
 bool GrBackendTexture::getDawnTextureInfo(GrDawnTextureInfo* outInfo) const {
     if (this->isValid() && GrBackendApi::kDawn == fBackend) {
@@ -580,30 +587,19 @@
 }
 #endif
 
-bool GrBackendTexture::getVkImageInfo(GrVkImageInfo* outInfo) const {
 #ifdef SK_VULKAN
+bool GrBackendTexture::getVkImageInfo(GrVkImageInfo* outInfo) const {
     if (this->isValid() && GrBackendApi::kVulkan == fBackend) {
-        *outInfo = fVkInfo.snapImageInfo();
+        *outInfo = fVkInfo.snapImageInfo(fMutableState.get());
         return true;
     }
-#endif
     return false;
 }
 
 void GrBackendTexture::setVkImageLayout(VkImageLayout layout) {
-#ifdef SK_VULKAN
     if (this->isValid() && GrBackendApi::kVulkan == fBackend) {
-        fVkInfo.setImageLayout(layout);
+        fMutableState->setImageLayout(layout);
     }
-#endif
-}
-
-#ifdef SK_VULKAN
-sk_sp<GrVkImageLayout> GrBackendTexture::getGrVkImageLayout() const {
-    if (this->isValid() && GrBackendApi::kVulkan == fBackend) {
-        return fVkInfo.getGrVkImageLayout();
-    }
-    return nullptr;
 }
 #endif
 
@@ -674,6 +670,10 @@
     return false;
 }
 
+void GrBackendTexture::setMutableState(const GrBackendSurfaceMutableState& state) {
+    fMutableState->set(state);
+}
+
 bool GrBackendTexture::isProtected() const {
     if (!this->isValid() || this->backend() != GrBackendApi::kVulkan) {
         return false;
@@ -695,7 +695,8 @@
 #endif
 #ifdef SK_VULKAN
         case GrBackendApi::kVulkan:
-            return fVkInfo.snapImageInfo().fImage == that.fVkInfo.snapImageInfo().fImage;
+            return fVkInfo.snapImageInfo(fMutableState.get()).fImage ==
+                   that.fVkInfo.snapImageInfo(that.fMutableState.get()).fImage;
 #endif
 #ifdef SK_METAL
         case GrBackendApi::kMetal:
@@ -723,7 +724,7 @@
 #endif
 #ifdef SK_VULKAN
         case GrBackendApi::kVulkan: {
-            auto info = fVkInfo.snapImageInfo();
+            auto info = fVkInfo.snapImageInfo(fMutableState.get());
             if (info.fYcbcrConversionInfo.isValid()) {
                 SkASSERT(info.fFormat == info.fYcbcrConversionInfo.fFormat);
                 return GrBackendFormat::MakeVk(info.fYcbcrConversionInfo);
@@ -800,6 +801,9 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
+GrBackendRenderTarget::GrBackendRenderTarget() : fIsValid(false) {}
+
+
 #ifdef SK_DAWN
 GrBackendRenderTarget::GrBackendRenderTarget(int width,
                                              int height,
@@ -816,6 +820,7 @@
         , fDawnInfo(dawnInfo) {}
 #endif
 
+#ifdef SK_VULKAN
 GrBackendRenderTarget::GrBackendRenderTarget(int width,
                                              int height,
                                              int sampleCnt,
@@ -830,26 +835,24 @@
                                              int height,
                                              int sampleCnt,
                                              const GrVkImageInfo& vkInfo)
-#ifdef SK_VULKAN
         : GrBackendRenderTarget(width, height, sampleCnt, vkInfo,
-                                sk_sp<GrVkImageLayout>(new GrVkImageLayout(vkInfo.fImageLayout))) {}
-#else
-        : fIsValid(false) {}
-#endif
+                                sk_sp<GrBackendSurfaceMutableStateImpl>(
+                                        new GrBackendSurfaceMutableStateImpl(
+                                               vkInfo.fImageLayout, vkInfo.fCurrentQueueFamily))) {}
 
-#ifdef SK_VULKAN
 GrBackendRenderTarget::GrBackendRenderTarget(int width,
                                              int height,
                                              int sampleCnt,
                                              const GrVkImageInfo& vkInfo,
-                                             sk_sp<GrVkImageLayout> layout)
+                                             sk_sp<GrBackendSurfaceMutableStateImpl> mutableState)
         : fIsValid(true)
         , fWidth(width)
         , fHeight(height)
         , fSampleCnt(std::max(1, sampleCnt))
         , fStencilBits(0)  // We always create stencil buffers internally for vulkan
         , fBackend(GrBackendApi::kVulkan)
-        , fVkInfo(vkInfo, layout.release()) {}
+        , fVkInfo(vkInfo)
+        , fMutableState(mutableState) {}
 #endif
 
 #ifdef SK_METAL
@@ -984,10 +987,15 @@
         default:
             SK_ABORT("Unknown GrBackend");
     }
+    fMutableState = that.fMutableState;
     fIsValid = that.fIsValid;
     return *this;
 }
 
+sk_sp<GrBackendSurfaceMutableStateImpl> GrBackendRenderTarget::getMutableState() const {
+    return fMutableState;
+}
+
 #ifdef SK_DAWN
 bool GrBackendRenderTarget::getDawnRenderTargetInfo(GrDawnRenderTargetInfo* outInfo) const {
     if (this->isValid() && GrBackendApi::kDawn == fBackend) {
@@ -998,30 +1006,19 @@
 }
 #endif
 
-bool GrBackendRenderTarget::getVkImageInfo(GrVkImageInfo* outInfo) const {
 #ifdef SK_VULKAN
+bool GrBackendRenderTarget::getVkImageInfo(GrVkImageInfo* outInfo) const {
     if (this->isValid() && GrBackendApi::kVulkan == fBackend) {
-        *outInfo = fVkInfo.snapImageInfo();
+        *outInfo = fVkInfo.snapImageInfo(fMutableState.get());
         return true;
     }
-#endif
     return false;
 }
 
 void GrBackendRenderTarget::setVkImageLayout(VkImageLayout layout) {
-#ifdef SK_VULKAN
     if (this->isValid() && GrBackendApi::kVulkan == fBackend) {
-        fVkInfo.setImageLayout(layout);
+        fMutableState->setImageLayout(layout);
     }
-#endif
-}
-
-#ifdef SK_VULKAN
-sk_sp<GrVkImageLayout> GrBackendRenderTarget::getGrVkImageLayout() const {
-    if (this->isValid() && GrBackendApi::kVulkan == fBackend) {
-        return fVkInfo.getGrVkImageLayout();
-    }
-    return nullptr;
 }
 #endif
 
@@ -1079,7 +1076,7 @@
 #endif
 #ifdef SK_VULKAN
         case GrBackendApi::kVulkan: {
-            auto info = fVkInfo.snapImageInfo();
+            auto info = fVkInfo.snapImageInfo(fMutableState.get());
             if (info.fYcbcrConversionInfo.isValid()) {
                 SkASSERT(info.fFormat == info.fYcbcrConversionInfo.fFormat);
                 return GrBackendFormat::MakeVk(info.fYcbcrConversionInfo);
@@ -1122,6 +1119,10 @@
     return false;
 }
 
+void GrBackendRenderTarget::setMutableState(const GrBackendSurfaceMutableState& state) {
+    fMutableState->set(state);
+}
+
 bool GrBackendRenderTarget::isProtected() const {
     if (!this->isValid() || this->backend() != GrBackendApi::kVulkan) {
         return false;
diff --git a/src/gpu/GrBackendSurfaceMutableStateImpl.h b/src/gpu/GrBackendSurfaceMutableStateImpl.h
new file mode 100644
index 0000000..3e3bc92
--- /dev/null
+++ b/src/gpu/GrBackendSurfaceMutableStateImpl.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrBackendSurfaceMutableStateImpl_DEFINED
+#define GrBackendSurfaceMutableStateImpl_DEFINED
+
+#include "include/core/SkRefCnt.h"
+#include "include/gpu/GrBackendSurfaceMutableState.h"
+
+class GrBackendSurfaceMutableStateImpl : public SkRefCnt {
+public:
+#ifdef SK_VULKAN
+    GrBackendSurfaceMutableStateImpl(VkImageLayout layout, uint32_t queueFamilyIndex)
+            : fState(layout, queueFamilyIndex) {}
+
+    GrBackendSurfaceMutableStateImpl(GrVkSharedImageInfo sharedInfo)
+            : fState(sharedInfo.getImageLayout(), sharedInfo.getQueueFamilyIndex()) {}
+#endif
+
+    void set(const GrBackendSurfaceMutableState& state) { fState = state; }
+
+#ifdef SK_VULKAN
+    VkImageLayout getImageLayout() const {
+        SkASSERT(fState.fBackend == GrBackend::kVulkan);
+        return fState.fVkState.getImageLayout();
+    }
+
+    void setImageLayout(VkImageLayout layout) {
+        SkASSERT(fState.fBackend == GrBackend::kVulkan);
+        fState.fVkState.setImageLayout(layout);
+    }
+
+    uint32_t getQueueFamilyIndex() const {
+        SkASSERT(fState.fBackend == GrBackend::kVulkan);
+        return fState.fVkState.getQueueFamilyIndex();
+    }
+
+    void setQueueFamilyIndex(uint32_t queueFamilyIndex) {
+        SkASSERT(fState.fBackend == GrBackend::kVulkan);
+        fState.fVkState.setQueueFamilyIndex(queueFamilyIndex);
+    }
+
+    const GrVkSharedImageInfo& getVkSharedImageInfo() {
+        SkASSERT(fState.fBackend == GrBackend::kVulkan);
+        return fState.fVkState;
+    }
+#endif
+
+
+private:
+    GrBackendSurfaceMutableState fState;
+};
+
+#endif
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index e4f4fa0..97d819f 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1268,10 +1268,10 @@
         return nullptr;
     }
 
-    sk_sp<GrVkImageLayout> layout = backendTex.getGrVkImageLayout();
-    SkASSERT(layout);
+    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = backendTex.getMutableState();
+    SkASSERT(mutableState);
     return GrVkTexture::MakeWrappedTexture(this, backendTex.dimensions(), ownership, cacheable,
-                                           ioType, imageInfo, std::move(layout));
+                                           ioType, imageInfo, std::move(mutableState));
 }
 
 sk_sp<GrTexture> GrVkGpu::onWrapCompressedBackendTexture(const GrBackendTexture& beTex,
@@ -1294,10 +1294,10 @@
         return nullptr;
     }
 
-    sk_sp<GrVkImageLayout> layout = beTex.getGrVkImageLayout();
-    SkASSERT(layout);
+    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = beTex.getMutableState();
+    SkASSERT(mutableState);
     return GrVkTexture::MakeWrappedTexture(this, beTex.dimensions(), ownership, cacheable,
-                                           kRead_GrIOType, imageInfo, std::move(layout));
+                                           kRead_GrIOType, imageInfo, std::move(mutableState));
 }
 
 sk_sp<GrTexture> GrVkGpu::onWrapRenderableBackendTexture(const GrBackendTexture& backendTex,
@@ -1326,12 +1326,13 @@
 
     sampleCnt = this->vkCaps().getRenderTargetSampleCount(sampleCnt, imageInfo.fFormat);
 
-    sk_sp<GrVkImageLayout> layout = backendTex.getGrVkImageLayout();
-    SkASSERT(layout);
+    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = backendTex.getMutableState();
+    SkASSERT(mutableState);
 
     return GrVkTextureRenderTarget::MakeWrappedTextureRenderTarget(this, backendTex.dimensions(),
                                                                    sampleCnt, ownership, cacheable,
-                                                                   imageInfo, std::move(layout));
+                                                                   imageInfo,
+                                                                   std::move(mutableState));
 }
 
 sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) {
@@ -1360,10 +1361,11 @@
         return nullptr;
     }
 
-    sk_sp<GrVkImageLayout> layout = backendRT.getGrVkImageLayout();
+    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = backendRT.getMutableState();
+    SkASSERT(mutableState);
 
     sk_sp<GrVkRenderTarget> tgt = GrVkRenderTarget::MakeWrappedRenderTarget(
-            this, backendRT.dimensions(), 1, info, std::move(layout));
+            this, backendRT.dimensions(), 1, info, std::move(mutableState));
 
     // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
     SkASSERT(!backendRT.stencilBits());
@@ -1397,11 +1399,11 @@
         return nullptr;
     }
 
-    sk_sp<GrVkImageLayout> layout = tex.getGrVkImageLayout();
-    SkASSERT(layout);
+    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = tex.getMutableState();
+    SkASSERT(mutableState);
 
     return GrVkRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt, imageInfo,
-                                                     std::move(layout));
+                                                     std::move(mutableState));
 }
 
 sk_sp<GrRenderTarget> GrVkGpu::onWrapVulkanSecondaryCBAsRenderTarget(
@@ -1630,12 +1632,12 @@
     GrVkImageInfo info;
     SkAssertResult(backendTexture.getVkImageInfo(&info));
 
-    sk_sp<GrVkImageLayout> layout = backendTexture.getGrVkImageLayout();
-    SkASSERT(layout);
+    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = backendTexture.getMutableState();
+    SkASSERT(mutableState);
     sk_sp<GrVkTexture> texture =
                 GrVkTexture::MakeWrappedTexture(this, backendTexture.dimensions(),
                                                 kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
-                                                kRW_GrIOType, info, layout);
+                                                kRW_GrIOType, info, std::move(mutableState));
     if (!texture) {
         return false;
     }
diff --git a/src/gpu/vk/GrVkImage.cpp b/src/gpu/vk/GrVkImage.cpp
index 5022f1c..9b50ca7 100644
--- a/src/gpu/vk/GrVkImage.cpp
+++ b/src/gpu/vk/GrVkImage.cpp
@@ -91,7 +91,7 @@
              VK_IMAGE_LAYOUT_PREINITIALIZED != newLayout);
     VkImageLayout currentLayout = this->currentLayout();
 
-    if (releaseFamilyQueue && fInfo.fCurrentQueueFamily == fInitialQueueFamily &&
+    if (releaseFamilyQueue && this->currentQueueFamilyIndex() == fInitialQueueFamily &&
         newLayout == currentLayout) {
         // We never transfered the image to this queue and we are releasing it so don't do anything.
         return;
@@ -100,8 +100,8 @@
     // If the old and new layout are the same and the layout is a read only layout, there is no need
     // to put in a barrier unless we also need to switch queues.
     if (newLayout == currentLayout && !releaseFamilyQueue &&
-        (fInfo.fCurrentQueueFamily == VK_QUEUE_FAMILY_IGNORED ||
-         fInfo.fCurrentQueueFamily == gpu->queueIndex()) &&
+        (this->currentQueueFamilyIndex() == VK_QUEUE_FAMILY_IGNORED ||
+         this->currentQueueFamilyIndex() == gpu->queueIndex()) &&
         (VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == currentLayout ||
          VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == currentLayout ||
          VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == currentLayout)) {
@@ -115,22 +115,22 @@
 
     uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
     uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-    if (fInfo.fCurrentQueueFamily != VK_QUEUE_FAMILY_IGNORED &&
-        gpu->queueIndex() != fInfo.fCurrentQueueFamily) {
+    if (this->currentQueueFamilyIndex() != VK_QUEUE_FAMILY_IGNORED &&
+        gpu->queueIndex() != this->currentQueueFamilyIndex()) {
         // The image still is owned by its original queue family and we need to transfer it into
         // ours.
         SkASSERT(!releaseFamilyQueue);
-        SkASSERT(fInfo.fCurrentQueueFamily == fInitialQueueFamily);
+        SkASSERT(this->currentQueueFamilyIndex() == fInitialQueueFamily);
 
-        srcQueueFamilyIndex = fInfo.fCurrentQueueFamily;
+        srcQueueFamilyIndex = this->currentQueueFamilyIndex();
         dstQueueFamilyIndex = gpu->queueIndex();
-        fInfo.fCurrentQueueFamily = gpu->queueIndex();
+        this->setQueueFamilyIndex(gpu->queueIndex());
     } else if (releaseFamilyQueue) {
         // We are releasing the image so we must transfer the image back to its original queue
         // family.
-        srcQueueFamilyIndex = fInfo.fCurrentQueueFamily;
+        srcQueueFamilyIndex = this->currentQueueFamilyIndex();
         dstQueueFamilyIndex = fInitialQueueFamily;
-        fInfo.fCurrentQueueFamily = fInitialQueueFamily;
+        this->setQueueFamilyIndex(fInitialQueueFamily);
     }
 
     VkImageMemoryBarrier imageMemoryBarrier = {
@@ -248,7 +248,7 @@
 }
 
 void GrVkImage::releaseImage(GrVkGpu* gpu) {
-    if (!gpu->isDeviceLost() && fInfo.fCurrentQueueFamily != fInitialQueueFamily) {
+    if (!gpu->isDeviceLost() && this->currentQueueFamilyIndex() != fInitialQueueFamily) {
         // The Vulkan spec is vague on what to put for the dstStageMask here. The spec for image
         // memory barrier says the dstStageMask must not be zero. However, in the spec when it talks
         // about family queue transfers it says the dstStageMask is ignored and should be set to
@@ -283,7 +283,7 @@
 
 #if GR_TEST_UTILS
 void GrVkImage::setCurrentQueueFamilyToGraphicsQueue(GrVkGpu* gpu) {
-    fInfo.fCurrentQueueFamily = gpu->queueIndex();
+    fMutableState->setQueueFamilyIndex(gpu->queueIndex());
 }
 #endif
 
diff --git a/src/gpu/vk/GrVkImage.h b/src/gpu/vk/GrVkImage.h
index fbd1576..4ff3e7e 100644
--- a/src/gpu/vk/GrVkImage.h
+++ b/src/gpu/vk/GrVkImage.h
@@ -12,9 +12,10 @@
 #include "include/gpu/GrBackendSurface.h"
 #include "include/gpu/vk/GrVkTypes.h"
 #include "include/private/GrTypesPriv.h"
+#include "include/private/GrVkTypesPriv.h"
+#include "src/gpu/GrBackendSurfaceMutableStateImpl.h"
 #include "src/gpu/GrManagedResource.h"
 #include "src/gpu/GrTexture.h"
-#include "src/gpu/vk/GrVkImageLayout.h"
 
 class GrVkGpu;
 class GrVkTexture;
@@ -24,13 +25,17 @@
     class Resource;
 
 public:
-    GrVkImage(const GrVkGpu* gpu, const GrVkImageInfo& info, sk_sp<GrVkImageLayout> layout,
-              GrBackendObjectOwnership ownership, bool forSecondaryCB = false)
+    GrVkImage(const GrVkGpu* gpu,
+              const GrVkImageInfo& info,
+              sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
+              GrBackendObjectOwnership ownership,
+              bool forSecondaryCB = false)
             : fInfo(info)
             , fInitialQueueFamily(info.fCurrentQueueFamily)
-            , fLayout(std::move(layout))
+            , fMutableState(std::move(mutableState))
             , fIsBorrowed(GrBackendObjectOwnership::kBorrowed == ownership) {
-        SkASSERT(fLayout->getImageLayout() == fInfo.fImageLayout);
+        SkASSERT(fMutableState->getImageLayout() == fInfo.fImageLayout);
+        SkASSERT(fMutableState->getQueueFamilyIndex() == fInfo.fCurrentQueueFamily);
         if (forSecondaryCB) {
             fResource = nullptr;
         } else if (fIsBorrowed) {
@@ -82,11 +87,9 @@
     }
     bool isBorrowed() const { return fIsBorrowed; }
 
-    sk_sp<GrVkImageLayout> grVkImageLayout() const { return fLayout; }
+    sk_sp<GrBackendSurfaceMutableStateImpl> getMutableState() const { return fMutableState; }
 
-    VkImageLayout currentLayout() const {
-        return fLayout->getImageLayout();
-    }
+    VkImageLayout currentLayout() const { return fMutableState->getImageLayout(); }
 
     void setImageLayout(const GrVkGpu* gpu,
                         VkImageLayout newLayout,
@@ -95,6 +98,12 @@
                         bool byRegion,
                         bool releaseFamilyQueue = false);
 
+    uint32_t currentQueueFamilyIndex() const { return fMutableState->getQueueFamilyIndex(); }
+
+    void setQueueFamilyIndex(uint32_t queueFamilyIndex) {
+        fMutableState->setQueueFamilyIndex(queueFamilyIndex);
+    }
+
     // Returns the image to its original queue family and changes the layout to present if the queue
     // family is not external or foreign.
     void prepareForPresent(GrVkGpu* gpu);
@@ -109,7 +118,7 @@
         // Should only be called when we have a real fResource object, i.e. never when being used as
         // a RT in an external secondary command buffer.
         SkASSERT(fResource);
-        fLayout->setImageLayout(newLayout);
+        fMutableState->setImageLayout(newLayout);
     }
 
     struct ImageDesc {
@@ -159,10 +168,10 @@
     void releaseImage(GrVkGpu* gpu);
     bool hasResource() const { return fResource; }
 
-    GrVkImageInfo          fInfo;
-    uint32_t               fInitialQueueFamily;
-    sk_sp<GrVkImageLayout> fLayout;
-    bool                   fIsBorrowed;
+    GrVkImageInfo                    fInfo;
+    uint32_t                         fInitialQueueFamily;
+    sk_sp<GrBackendSurfaceMutableStateImpl> fMutableState;
+    bool                             fIsBorrowed;
 
 private:
     class Resource : public GrTextureResource {
diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp
index 761dd97..f7249cd 100644
--- a/src/gpu/vk/GrVkRenderTarget.cpp
+++ b/src/gpu/vk/GrVkRenderTarget.cpp
@@ -26,17 +26,17 @@
                                    SkISize dimensions,
                                    int sampleCnt,
                                    const GrVkImageInfo& info,
-                                   sk_sp<GrVkImageLayout> layout,
+                                   sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                                    const GrVkImageInfo& msaaInfo,
-                                   sk_sp<GrVkImageLayout> msaaLayout,
+                                   sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
                                    const GrVkImageView* colorAttachmentView,
                                    const GrVkImageView* resolveAttachmentView)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, std::move(layout), GrBackendObjectOwnership::kBorrowed)
+        , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kBorrowed)
         // for the moment we only support 1:1 color to stencil
         , GrRenderTarget(gpu, dimensions, sampleCnt, info.fProtected)
         , fColorAttachmentView(colorAttachmentView)
-        , fMSAAImage(new GrVkImage(gpu, msaaInfo, std::move(msaaLayout),
+        , fMSAAImage(new GrVkImage(gpu, msaaInfo, std::move(msaaMutableState),
                                    GrBackendObjectOwnership::kOwned))
         , fResolveAttachmentView(resolveAttachmentView)
         , fCachedFramebuffer(nullptr)
@@ -54,18 +54,18 @@
                                    SkISize dimensions,
                                    int sampleCnt,
                                    const GrVkImageInfo& info,
-                                   sk_sp<GrVkImageLayout> layout,
+                                   sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                                    const GrVkImageInfo& msaaInfo,
-                                   sk_sp<GrVkImageLayout> msaaLayout,
+                                   sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
                                    const GrVkImageView* colorAttachmentView,
                                    const GrVkImageView* resolveAttachmentView,
                                    GrBackendObjectOwnership ownership)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, std::move(layout), ownership)
+        , GrVkImage(gpu, info, std::move(mutableState), ownership)
         // for the moment we only support 1:1 color to stencil
         , GrRenderTarget(gpu, dimensions, sampleCnt, info.fProtected)
         , fColorAttachmentView(colorAttachmentView)
-        , fMSAAImage(new GrVkImage(gpu, msaaInfo, std::move(msaaLayout),
+        , fMSAAImage(new GrVkImage(gpu, msaaInfo, std::move(msaaMutableState),
                                    GrBackendObjectOwnership::kOwned))
         , fResolveAttachmentView(resolveAttachmentView)
         , fCachedFramebuffer(nullptr)
@@ -81,10 +81,10 @@
 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
                                    SkISize dimensions,
                                    const GrVkImageInfo& info,
-                                   sk_sp<GrVkImageLayout> layout,
+                                   sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                                    const GrVkImageView* colorAttachmentView)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, std::move(layout), GrBackendObjectOwnership::kBorrowed)
+        , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kBorrowed)
         , GrRenderTarget(gpu, dimensions, 1, info.fProtected)
         , fColorAttachmentView(colorAttachmentView)
         , fMSAAImage(nullptr)
@@ -101,11 +101,11 @@
 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
                                    SkISize dimensions,
                                    const GrVkImageInfo& info,
-                                   sk_sp<GrVkImageLayout> layout,
+                                   sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                                    const GrVkImageView* colorAttachmentView,
                                    GrBackendObjectOwnership ownership)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, std::move(layout), ownership)
+        , GrVkImage(gpu, info, std::move(mutableState), ownership)
         , GrRenderTarget(gpu, dimensions, 1, info.fProtected)
         , fColorAttachmentView(colorAttachmentView)
         , fMSAAImage(nullptr)
@@ -118,11 +118,11 @@
 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
                                    SkISize dimensions,
                                    const GrVkImageInfo& info,
-                                   sk_sp<GrVkImageLayout> layout,
+                                   sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                                    const GrVkRenderPass* renderPass,
                                    VkCommandBuffer secondaryCommandBuffer)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, std::move(layout), GrBackendObjectOwnership::kBorrowed, true)
+        , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kBorrowed, true)
         , GrRenderTarget(gpu, dimensions, 1, info.fProtected)
         , fColorAttachmentView(nullptr)
         , fMSAAImage(nullptr)
@@ -136,11 +136,9 @@
     this->registerWithCacheWrapped(GrWrapCacheable::kNo);
 }
 
-sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu,
-                                                                  SkISize dimensions,
-                                                                  int sampleCnt,
-                                                                  const GrVkImageInfo& info,
-                                                                  sk_sp<GrVkImageLayout> layout) {
+sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(
+        GrVkGpu* gpu, SkISize dimensions, int sampleCnt, const GrVkImageInfo& info,
+        sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) {
     SkASSERT(VK_NULL_HANDLE != info.fImage);
 
     SkASSERT(1 == info.fLevelCount);
@@ -150,7 +148,7 @@
 
     // create msaa surface if necessary
     GrVkImageInfo msInfo;
-    sk_sp<GrVkImageLayout> msLayout;
+    sk_sp<GrBackendSurfaceMutableStateImpl> msMutableState;
     const GrVkImageView* resolveAttachmentView = nullptr;
     if (sampleCnt > 1) {
         GrVkImage::ImageDesc msImageDesc;
@@ -182,7 +180,8 @@
             GrVkImage::DestroyImageInfo(gpu, &msInfo);
             return nullptr;
         }
-        msLayout.reset(new GrVkImageLayout(msInfo.fImageLayout));
+        msMutableState.reset(new GrBackendSurfaceMutableStateImpl(msInfo.fImageLayout,
+                                                           msInfo.fCurrentQueueFamily));
     } else {
         // Set color attachment image
         colorImage = info.fImage;
@@ -202,11 +201,12 @@
 
     GrVkRenderTarget* vkRT;
     if (sampleCnt > 1) {
-        vkRT = new GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(layout), msInfo,
-                                    std::move(msLayout), colorAttachmentView,
+        vkRT = new GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState),
+                                    msInfo, std::move(msMutableState), colorAttachmentView,
                                     resolveAttachmentView);
     } else {
-        vkRT = new GrVkRenderTarget(gpu, dimensions, info, std::move(layout), colorAttachmentView);
+        vkRT = new GrVkRenderTarget(gpu, dimensions, info, std::move(mutableState),
+                                    colorAttachmentView);
     }
 
     return sk_sp<GrVkRenderTarget>(vkRT);
@@ -220,7 +220,8 @@
     info.fImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
     info.fFormat = vkInfo.fFormat;
 
-    sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
+    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState(new GrBackendSurfaceMutableStateImpl(
+            VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_QUEUE_FAMILY_IGNORED));
 
     const GrVkRenderPass* rp =
             gpu->resourceProvider().findCompatibleExternalRenderPass(vkInfo.fCompatibleRenderPass,
@@ -233,8 +234,8 @@
         return nullptr;
     }
 
-    GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu, dimensions, info, std::move(layout), rp,
-                                                  vkInfo.fSecondaryCommandBuffer);
+    GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu, dimensions, info, std::move(mutableState),
+                                                  rp, vkInfo.fSecondaryCommandBuffer);
 
     return sk_sp<GrVkRenderTarget>(vkRT);
 }
@@ -418,7 +419,7 @@
 GrBackendRenderTarget GrVkRenderTarget::getBackendRenderTarget() const {
     SkASSERT(!this->wrapsSecondaryCommandBuffer());
     return GrBackendRenderTarget(this->width(), this->height(), this->numSamples(), fInfo,
-                                 this->grVkImageLayout());
+                                 this->getMutableState());
 }
 
 const GrManagedResource* GrVkRenderTarget::stencilImageResource() const {
diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h
index da6f084..94ad40f 100644
--- a/src/gpu/vk/GrVkRenderTarget.h
+++ b/src/gpu/vk/GrVkRenderTarget.h
@@ -34,7 +34,7 @@
 public:
     static sk_sp<GrVkRenderTarget> MakeWrappedRenderTarget(GrVkGpu*, SkISize, int sampleCnt,
                                                            const GrVkImageInfo&,
-                                                           sk_sp<GrVkImageLayout>);
+                                                           sk_sp<GrBackendSurfaceMutableStateImpl>);
 
     static sk_sp<GrVkRenderTarget> MakeSecondaryCBRenderTarget(GrVkGpu*, SkISize,
                                                                const GrVkDrawableInfo& vkInfo);
@@ -111,9 +111,9 @@
                      SkISize dimensions,
                      int sampleCnt,
                      const GrVkImageInfo& info,
-                     sk_sp<GrVkImageLayout> layout,
+                     sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                      const GrVkImageInfo& msaaInfo,
-                     sk_sp<GrVkImageLayout> msaaLayout,
+                     sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
                      const GrVkImageView* colorAttachmentView,
                      const GrVkImageView* resolveAttachmentView,
                      GrBackendObjectOwnership);
@@ -121,7 +121,7 @@
     GrVkRenderTarget(GrVkGpu* gpu,
                      SkISize dimensions,
                      const GrVkImageInfo& info,
-                     sk_sp<GrVkImageLayout> layout,
+                     sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                      const GrVkImageView* colorAttachmentView,
                      GrBackendObjectOwnership);
 
@@ -145,22 +145,22 @@
                      SkISize dimensions,
                      int sampleCnt,
                      const GrVkImageInfo& info,
-                     sk_sp<GrVkImageLayout> layout,
+                     sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                      const GrVkImageInfo& msaaInfo,
-                     sk_sp<GrVkImageLayout> msaaLayout,
+                     sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
                      const GrVkImageView* colorAttachmentView,
                      const GrVkImageView* resolveAttachmentView);
 
     GrVkRenderTarget(GrVkGpu* gpu,
                      SkISize dimensions,
                      const GrVkImageInfo& info,
-                     sk_sp<GrVkImageLayout> layout,
+                     sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                      const GrVkImageView* colorAttachmentView);
 
     GrVkRenderTarget(GrVkGpu* gpu,
                      SkISize dimensions,
                      const GrVkImageInfo& info,
-                     sk_sp<GrVkImageLayout> layout,
+                     sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                      const GrVkRenderPass* renderPass,
                      VkCommandBuffer secondaryCommandBuffer);
 
diff --git a/src/gpu/vk/GrVkStencilAttachment.cpp b/src/gpu/vk/GrVkStencilAttachment.cpp
index 3236ac2..3d43a28 100644
--- a/src/gpu/vk/GrVkStencilAttachment.cpp
+++ b/src/gpu/vk/GrVkStencilAttachment.cpp
@@ -17,10 +17,10 @@
                                              const Format& format,
                                              const GrVkImage::ImageDesc& desc,
                                              const GrVkImageInfo& info,
-                                             sk_sp<GrVkImageLayout> layout,
+                                             sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                                              const GrVkImageView* stencilView)
     : GrStencilAttachment(gpu, desc.fWidth, desc.fHeight, format.fStencilBits, desc.fSamples)
-    , GrVkImage(gpu, info, std::move(layout), GrBackendObjectOwnership::kOwned)
+    , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kOwned)
     , fStencilView(stencilView) {
     this->registerWithCache(SkBudgeted::kYes);
     stencilView->ref();
@@ -57,9 +57,11 @@
         return nullptr;
     }
 
-    sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout));
+    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState(new GrBackendSurfaceMutableStateImpl(
+        info.fImageLayout, info.fCurrentQueueFamily));
     GrVkStencilAttachment* stencil = new GrVkStencilAttachment(gpu, format, imageDesc,
-                                                               info, std::move(layout), imageView);
+                                                               info, std::move(mutableState),
+                                                               imageView);
     imageView->unref();
 
     return stencil;
diff --git a/src/gpu/vk/GrVkStencilAttachment.h b/src/gpu/vk/GrVkStencilAttachment.h
index 8accd28..ad96fae 100644
--- a/src/gpu/vk/GrVkStencilAttachment.h
+++ b/src/gpu/vk/GrVkStencilAttachment.h
@@ -41,7 +41,7 @@
                           const Format& format,
                           const GrVkImage::ImageDesc&,
                           const GrVkImageInfo&,
-                          sk_sp<GrVkImageLayout> layout,
+                          sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                           const GrVkImageView* stencilView);
 
     GrVkGpu* getVkGpu() const;
diff --git a/src/gpu/vk/GrVkTexture.cpp b/src/gpu/vk/GrVkTexture.cpp
index ce3f49a..ec98f29 100644
--- a/src/gpu/vk/GrVkTexture.cpp
+++ b/src/gpu/vk/GrVkTexture.cpp
@@ -23,11 +23,11 @@
                          SkBudgeted budgeted,
                          SkISize dimensions,
                          const GrVkImageInfo& info,
-                         sk_sp<GrVkImageLayout> layout,
+                         sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                          const GrVkImageView* view,
                          GrMipMapsStatus mipMapsStatus)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, std::move(layout), GrBackendObjectOwnership::kOwned)
+        , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kOwned)
         , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
         , fTextureView(view)
         , fDescSetCache(kMaxCachedDescSets) {
@@ -41,11 +41,12 @@
 }
 
 GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info,
-                         sk_sp<GrVkImageLayout> layout, const GrVkImageView* view,
+                         sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
+                         const GrVkImageView* view,
                          GrMipMapsStatus mipMapsStatus, GrBackendObjectOwnership ownership,
                          GrWrapCacheable cacheable, GrIOType ioType, bool isExternal)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, std::move(layout), ownership)
+        , GrVkImage(gpu, info, std::move(mutableState), ownership)
         , INHERITED(gpu, dimensions, info.fProtected,
                     isExternal ? GrTextureType::kExternal : GrTextureType::k2D, mipMapsStatus)
         , fTextureView(view)
@@ -61,12 +62,12 @@
 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
                          SkISize dimensions,
                          const GrVkImageInfo& info,
-                         sk_sp<GrVkImageLayout> layout,
+                         sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                          const GrVkImageView* view,
                          GrMipMapsStatus mipMapsStatus,
                          GrBackendObjectOwnership ownership)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, layout, ownership)
+        , GrVkImage(gpu, info, std::move(mutableState), ownership)
         , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
         , fTextureView(view)
         , fDescSetCache(kMaxCachedDescSets) {
@@ -94,19 +95,16 @@
         GrVkImage::DestroyImageInfo(gpu, &info);
         return nullptr;
     }
-    sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout));
-
-    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, dimensions, info, std::move(layout),
-                                              imageView, mipMapsStatus));
+    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState(
+            new GrBackendSurfaceMutableStateImpl(info.fImageLayout, info.fCurrentQueueFamily));
+    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, dimensions, info,
+                                              std::move(mutableState), imageView, mipMapsStatus));
 }
 
-sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu,
-                                                   SkISize dimensions,
-                                                   GrWrapOwnership wrapOwnership,
-                                                   GrWrapCacheable cacheable,
-                                                   GrIOType ioType,
-                                                   const GrVkImageInfo& info,
-                                                   sk_sp<GrVkImageLayout> layout) {
+sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(
+        GrVkGpu* gpu, SkISize dimensions, GrWrapOwnership wrapOwnership, GrWrapCacheable cacheable,
+        GrIOType ioType, const GrVkImageInfo& info,
+        sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) {
     // Adopted textures require both image and allocation because we're responsible for freeing
     SkASSERT(VK_NULL_HANDLE != info.fImage &&
              (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));
@@ -125,9 +123,9 @@
             ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
     bool isExternal = info.fYcbcrConversionInfo.isValid() &&
                       (info.fYcbcrConversionInfo.fExternalFormat != 0);
-    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, dimensions, info, std::move(layout), imageView,
-                                              mipMapsStatus, ownership, cacheable, ioType,
-                                              isExternal));
+    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, dimensions, info, std::move(mutableState),
+                                              imageView, mipMapsStatus, ownership, cacheable,
+                                              ioType, isExternal));
 }
 
 GrVkTexture::~GrVkTexture() {
@@ -190,7 +188,7 @@
 }
 
 GrBackendTexture GrVkTexture::getBackendTexture() const {
-    return GrBackendTexture(this->width(), this->height(), fInfo, this->grVkImageLayout());
+    return GrBackendTexture(this->width(), this->height(), fInfo, this->getMutableState());
 }
 
 GrVkGpu* GrVkTexture::getVkGpu() const {
diff --git a/src/gpu/vk/GrVkTexture.h b/src/gpu/vk/GrVkTexture.h
index 6a13f5a..d719ef1 100644
--- a/src/gpu/vk/GrVkTexture.h
+++ b/src/gpu/vk/GrVkTexture.h
@@ -33,7 +33,7 @@
                                                  GrWrapCacheable,
                                                  GrIOType,
                                                  const GrVkImageInfo&,
-                                                 sk_sp<GrVkImageLayout>);
+                                                 sk_sp<GrBackendSurfaceMutableStateImpl>);
 
     ~GrVkTexture() override;
 
@@ -61,7 +61,7 @@
     GrVkTexture(GrVkGpu*,
                 SkISize dimensions,
                 const GrVkImageInfo&,
-                sk_sp<GrVkImageLayout>,
+                sk_sp<GrBackendSurfaceMutableStateImpl>,
                 const GrVkImageView*,
                 GrMipMapsStatus,
                 GrBackendObjectOwnership);
@@ -78,9 +78,10 @@
     void willRemoveLastRef() override;
 
 private:
-    GrVkTexture(GrVkGpu*, SkBudgeted, SkISize, const GrVkImageInfo&, sk_sp<GrVkImageLayout> layout,
-                const GrVkImageView* imageView, GrMipMapsStatus);
-    GrVkTexture(GrVkGpu*, SkISize, const GrVkImageInfo&, sk_sp<GrVkImageLayout>,
+    GrVkTexture(GrVkGpu*, SkBudgeted, SkISize, const GrVkImageInfo&,
+                sk_sp<GrBackendSurfaceMutableStateImpl>, const GrVkImageView* imageView,
+                GrMipMapsStatus);
+    GrVkTexture(GrVkGpu*, SkISize, const GrVkImageInfo&, sk_sp<GrBackendSurfaceMutableStateImpl>,
                 const GrVkImageView*, GrMipMapsStatus, GrBackendObjectOwnership, GrWrapCacheable,
                 GrIOType, bool isExternal);
 
diff --git a/src/gpu/vk/GrVkTextureRenderTarget.cpp b/src/gpu/vk/GrVkTextureRenderTarget.cpp
index 0ce652a..39d87d3 100644
--- a/src/gpu/vk/GrVkTextureRenderTarget.cpp
+++ b/src/gpu/vk/GrVkTextureRenderTarget.cpp
@@ -18,82 +18,87 @@
 
 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
 
-GrVkTextureRenderTarget::GrVkTextureRenderTarget(GrVkGpu* gpu,
-                                                 SkBudgeted budgeted,
-                                                 SkISize dimensions,
-                                                 int sampleCnt,
-                                                 const GrVkImageInfo& info,
-                                                 sk_sp<GrVkImageLayout> layout,
-                                                 const GrVkImageView* texView,
-                                                 const GrVkImageInfo& msaaInfo,
-                                                 sk_sp<GrVkImageLayout> msaaLayout,
-                                                 const GrVkImageView* colorAttachmentView,
-                                                 const GrVkImageView* resolveAttachmentView,
-                                                 GrMipMapsStatus mipMapsStatus)
+GrVkTextureRenderTarget::GrVkTextureRenderTarget(
+        GrVkGpu* gpu,
+        SkBudgeted budgeted,
+        SkISize dimensions,
+        int sampleCnt,
+        const GrVkImageInfo& info,
+        sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
+        const GrVkImageView* texView,
+        const GrVkImageInfo& msaaInfo,
+        sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
+        const GrVkImageView* colorAttachmentView,
+        const GrVkImageView* resolveAttachmentView,
+        GrMipMapsStatus mipMapsStatus)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, layout, GrBackendObjectOwnership::kOwned)
-        , GrVkTexture(gpu, dimensions, info, layout, texView, mipMapsStatus,
+        , GrVkImage(gpu, info, mutableState, GrBackendObjectOwnership::kOwned)
+        , GrVkTexture(gpu, dimensions, info, mutableState, texView, mipMapsStatus,
                       GrBackendObjectOwnership::kOwned)
-        , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, layout, msaaInfo,
-                           std::move(msaaLayout), colorAttachmentView, resolveAttachmentView,
+        , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState), msaaInfo,
+                           std::move(msaaMutableState), colorAttachmentView, resolveAttachmentView,
                            GrBackendObjectOwnership::kOwned) {
     SkASSERT(info.fProtected == msaaInfo.fProtected);
     this->registerWithCache(budgeted);
 }
 
-GrVkTextureRenderTarget::GrVkTextureRenderTarget(GrVkGpu* gpu,
-                                                 SkBudgeted budgeted,
-                                                 SkISize dimensions,
-                                                 const GrVkImageInfo& info,
-                                                 sk_sp<GrVkImageLayout> layout,
-                                                 const GrVkImageView* texView,
-                                                 const GrVkImageView* colorAttachmentView,
-                                                 GrMipMapsStatus mipMapsStatus)
+GrVkTextureRenderTarget::GrVkTextureRenderTarget(
+        GrVkGpu* gpu,
+        SkBudgeted budgeted,
+        SkISize dimensions,
+        const GrVkImageInfo& info,
+        sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
+        const GrVkImageView* texView,
+        const GrVkImageView* colorAttachmentView,
+        GrMipMapsStatus mipMapsStatus)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, layout, GrBackendObjectOwnership::kOwned)
-        , GrVkTexture(gpu, dimensions, info, layout, texView, mipMapsStatus,
+        , GrVkImage(gpu, info, mutableState, GrBackendObjectOwnership::kOwned)
+        , GrVkTexture(gpu, dimensions, info, mutableState, texView, mipMapsStatus,
                       GrBackendObjectOwnership::kOwned)
-        , GrVkRenderTarget(gpu, dimensions, info, layout, colorAttachmentView,
+        , GrVkRenderTarget(gpu, dimensions, info, std::move(mutableState), colorAttachmentView,
                            GrBackendObjectOwnership::kOwned) {
     this->registerWithCache(budgeted);
 }
 
-GrVkTextureRenderTarget::GrVkTextureRenderTarget(GrVkGpu* gpu,
-                                                 SkISize dimensions,
-                                                 int sampleCnt,
-                                                 const GrVkImageInfo& info,
-                                                 sk_sp<GrVkImageLayout> layout,
-                                                 const GrVkImageView* texView,
-                                                 const GrVkImageInfo& msaaInfo,
-                                                 sk_sp<GrVkImageLayout> msaaLayout,
-                                                 const GrVkImageView* colorAttachmentView,
-                                                 const GrVkImageView* resolveAttachmentView,
-                                                 GrMipMapsStatus mipMapsStatus,
-                                                 GrBackendObjectOwnership ownership,
-                                                 GrWrapCacheable cacheable)
+GrVkTextureRenderTarget::GrVkTextureRenderTarget(
+        GrVkGpu* gpu,
+        SkISize dimensions,
+        int sampleCnt,
+        const GrVkImageInfo& info,
+        sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
+        const GrVkImageView* texView,
+        const GrVkImageInfo& msaaInfo,
+        sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
+        const GrVkImageView* colorAttachmentView,
+        const GrVkImageView* resolveAttachmentView,
+        GrMipMapsStatus mipMapsStatus,
+        GrBackendObjectOwnership ownership,
+        GrWrapCacheable cacheable)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, layout, ownership)
-        , GrVkTexture(gpu, dimensions, info, layout, texView, mipMapsStatus, ownership)
-        , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, layout, msaaInfo,
-                           std::move(msaaLayout), colorAttachmentView, resolveAttachmentView,
+        , GrVkImage(gpu, info, mutableState, ownership)
+        , GrVkTexture(gpu, dimensions, info, mutableState, texView, mipMapsStatus, ownership)
+        , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState), msaaInfo,
+                           std::move(msaaMutableState), colorAttachmentView, resolveAttachmentView,
                            ownership) {
     SkASSERT(info.fProtected == msaaInfo.fProtected);
     this->registerWithCacheWrapped(cacheable);
 }
 
-GrVkTextureRenderTarget::GrVkTextureRenderTarget(GrVkGpu* gpu,
-                                                 SkISize dimensions,
-                                                 const GrVkImageInfo& info,
-                                                 sk_sp<GrVkImageLayout> layout,
-                                                 const GrVkImageView* texView,
-                                                 const GrVkImageView* colorAttachmentView,
-                                                 GrMipMapsStatus mipMapsStatus,
-                                                 GrBackendObjectOwnership ownership,
-                                                 GrWrapCacheable cacheable)
+GrVkTextureRenderTarget::GrVkTextureRenderTarget(
+        GrVkGpu* gpu,
+        SkISize dimensions,
+        const GrVkImageInfo& info,
+        sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
+        const GrVkImageView* texView,
+        const GrVkImageView* colorAttachmentView,
+        GrMipMapsStatus mipMapsStatus,
+        GrBackendObjectOwnership ownership,
+        GrWrapCacheable cacheable)
         : GrSurface(gpu, dimensions, info.fProtected)
-        , GrVkImage(gpu, info, layout, ownership)
-        , GrVkTexture(gpu, dimensions, info, layout, texView, mipMapsStatus, ownership)
-        , GrVkRenderTarget(gpu, dimensions, info, layout, colorAttachmentView, ownership) {
+        , GrVkImage(gpu, info, mutableState, ownership)
+        , GrVkTexture(gpu, dimensions, info, mutableState, texView, mipMapsStatus, ownership)
+        , GrVkRenderTarget(gpu, dimensions, info, std::move(mutableState), colorAttachmentView,
+                           ownership) {
     this->registerWithCacheWrapped(cacheable);
 }
 
@@ -103,7 +108,7 @@
     const GrVkImageView* colorAttachmentView = nullptr;
     const GrVkImageView* resolveAttachmentView = nullptr;
     GrVkImageInfo msInfo;
-    sk_sp<GrVkImageLayout> msLayout;
+    sk_sp<GrBackendSurfaceMutableStateImpl> msMutableState;
 };
 }  // anonymous namespace
 
@@ -154,7 +159,8 @@
             views.imageView->unref();
             return {};
         }
-        views.msLayout.reset(new GrVkImageLayout(views.msInfo.fImageLayout));
+        views.msMutableState.reset(new GrBackendSurfaceMutableStateImpl(
+                views.msInfo.fImageLayout, views.msInfo.fCurrentQueueFamily));
     } else {
         // Set color attachment image
         colorImage = info.fImage;
@@ -187,7 +193,8 @@
     if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) {
         return nullptr;
     }
-    sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout));
+    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState(
+            new GrBackendSurfaceMutableStateImpl(info.fImageLayout, info.fCurrentQueueFamily));
 
     Views views = create_views(gpu, dimensions, sampleCnt, info);
     if (!views.colorAttachmentView) {
@@ -196,12 +203,12 @@
     }
     if (sampleCnt > 1) {
         return sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget(
-                gpu, budgeted, dimensions, sampleCnt, info, std::move(layout), views.imageView,
-                views.msInfo, std::move(views.msLayout), views.colorAttachmentView,
-                views.resolveAttachmentView, mipMapsStatus));
+                gpu, budgeted, dimensions, sampleCnt, info, std::move(mutableState),
+                views.imageView, views.msInfo, std::move(views.msMutableState),
+                views.colorAttachmentView, views.resolveAttachmentView, mipMapsStatus));
     } else {
         return sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget(
-                gpu, budgeted, dimensions, info, std::move(layout), views.imageView,
+                gpu, budgeted, dimensions, info, std::move(mutableState), views.imageView,
                 views.colorAttachmentView, mipMapsStatus));
     }
 }
@@ -213,7 +220,7 @@
         GrWrapOwnership wrapOwnership,
         GrWrapCacheable cacheable,
         const GrVkImageInfo& info,
-        sk_sp<GrVkImageLayout> layout) {
+        sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) {
     // Adopted textures require both image and allocation because we're responsible for freeing
     SkASSERT(VK_NULL_HANDLE != info.fImage &&
              (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));
@@ -229,12 +236,12 @@
     }
     if (sampleCnt > 1) {
         return sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget(
-                gpu, dimensions, sampleCnt, info, std::move(layout), views.imageView, views.msInfo,
-                std::move(views.msLayout), views.colorAttachmentView, views.resolveAttachmentView,
-                mipMapsStatus, ownership, cacheable));
+                gpu, dimensions, sampleCnt, info, std::move(mutableState), views.imageView,
+                views.msInfo, std::move(views.msMutableState), views.colorAttachmentView,
+                views.resolveAttachmentView, mipMapsStatus, ownership, cacheable));
     } else {
         return sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget(
-                gpu, dimensions, info, std::move(layout), views.imageView,
+                gpu, dimensions, info, std::move(mutableState), views.imageView,
                 views.colorAttachmentView, mipMapsStatus, ownership, cacheable));
     }
 }
diff --git a/src/gpu/vk/GrVkTextureRenderTarget.h b/src/gpu/vk/GrVkTextureRenderTarget.h
index e319175..adc352d 100644
--- a/src/gpu/vk/GrVkTextureRenderTarget.h
+++ b/src/gpu/vk/GrVkTextureRenderTarget.h
@@ -32,13 +32,14 @@
                                                                      const GrVkImage::ImageDesc&,
                                                                      GrMipMapsStatus);
 
-    static sk_sp<GrVkTextureRenderTarget> MakeWrappedTextureRenderTarget(GrVkGpu*,
-                                                                         SkISize dimensions,
-                                                                         int sampleCnt,
-                                                                         GrWrapOwnership,
-                                                                         GrWrapCacheable,
-                                                                         const GrVkImageInfo&,
-                                                                         sk_sp<GrVkImageLayout>);
+    static sk_sp<GrVkTextureRenderTarget> MakeWrappedTextureRenderTarget(
+            GrVkGpu*,
+            SkISize dimensions,
+            int sampleCnt,
+            GrWrapOwnership,
+            GrWrapCacheable,
+            const GrVkImageInfo&,
+            sk_sp<GrBackendSurfaceMutableStateImpl>);
 
     GrBackendFormat backendFormat() const override { return this->getBackendFormat(); }
 
@@ -62,10 +63,10 @@
                             SkISize dimensions,
                             int sampleCnt,
                             const GrVkImageInfo& info,
-                            sk_sp<GrVkImageLayout> layout,
+                            sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                             const GrVkImageView* texView,
                             const GrVkImageInfo& msaaInfo,
-                            sk_sp<GrVkImageLayout> msaaLayout,
+                            sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
                             const GrVkImageView* colorAttachmentView,
                             const GrVkImageView* resolveAttachmentView,
                             GrMipMapsStatus);
@@ -75,7 +76,7 @@
                             SkBudgeted budgeted,
                             SkISize dimensions,
                             const GrVkImageInfo& info,
-                            sk_sp<GrVkImageLayout> layout,
+                            sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                             const GrVkImageView* texView,
                             const GrVkImageView* colorAttachmentView,
                             GrMipMapsStatus);
@@ -85,10 +86,10 @@
                             SkISize dimensions,
                             int sampleCnt,
                             const GrVkImageInfo& info,
-                            sk_sp<GrVkImageLayout> layout,
+                            sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                             const GrVkImageView* texView,
                             const GrVkImageInfo& msaaInfo,
-                            sk_sp<GrVkImageLayout> msaaLayout,
+                            sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
                             const GrVkImageView* colorAttachmentView,
                             const GrVkImageView* resolveAttachmentView,
                             GrMipMapsStatus,
@@ -99,7 +100,7 @@
     GrVkTextureRenderTarget(GrVkGpu* gpu,
                             SkISize dimensions,
                             const GrVkImageInfo& info,
-                            sk_sp<GrVkImageLayout> layout,
+                            sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                             const GrVkImageView* texView,
                             const GrVkImageView* colorAttachmentView,
                             GrMipMapsStatus,
diff --git a/src/gpu/vk/GrVkTypesPriv.cpp b/src/gpu/vk/GrVkTypesPriv.cpp
index 6f5d0b2..99d0cee 100644
--- a/src/gpu/vk/GrVkTypesPriv.cpp
+++ b/src/gpu/vk/GrVkTypesPriv.cpp
@@ -7,34 +7,20 @@
 
 #include "include/private/GrVkTypesPriv.h"
 
+#include "src/gpu/GrBackendSurfaceMutableStateImpl.h"
 #include "src/gpu/vk/GrVkImageLayout.h"
 
-void GrVkBackendSurfaceInfo::cleanup() {
-    SkSafeUnref(fLayout);
-    fLayout = nullptr;
-};
+void GrVkBackendSurfaceInfo::cleanup() {};
 
 void GrVkBackendSurfaceInfo::assign(const GrVkBackendSurfaceInfo& that, bool isThisValid) {
     fImageInfo = that.fImageInfo;
-    GrVkImageLayout* oldLayout = fLayout;
-    fLayout = SkSafeRef(that.fLayout);
-    if (isThisValid) {
-        SkSafeUnref(oldLayout);
-    }
 }
 
-void GrVkBackendSurfaceInfo::setImageLayout(VkImageLayout layout) {
-    SkASSERT(fLayout);
-    fLayout->setImageLayout(layout);
-}
-
-sk_sp<GrVkImageLayout> GrVkBackendSurfaceInfo::getGrVkImageLayout() const {
-    SkASSERT(fLayout);
-    return sk_ref_sp(fLayout);
-}
-
-GrVkImageInfo GrVkBackendSurfaceInfo::snapImageInfo() const {
-    return GrVkImageInfo(fImageInfo, fLayout->getImageLayout());
+GrVkImageInfo GrVkBackendSurfaceInfo::snapImageInfo(
+        const GrBackendSurfaceMutableStateImpl* mutableState) const {
+    SkASSERT(mutableState);
+    return GrVkImageInfo(fImageInfo, mutableState->getImageLayout(),
+                         mutableState->getQueueFamilyIndex());
 }
 
 #if GR_TEST_UTILS
@@ -45,6 +31,6 @@
     // GrVkImageLayout.
     cpyInfoThis.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
     cpyInfoThat.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-    return cpyInfoThis == cpyInfoThat && fLayout == that.fLayout;
+    return cpyInfoThis == cpyInfoThat;
 }
 #endif