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/gn/gpu.gni b/gn/gpu.gni
index 66868a1..4a3b703 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -11,6 +11,7 @@
   "$_include/gpu/GrBackendDrawableInfo.h",
   "$_include/gpu/GrBackendSemaphore.h",
   "$_include/gpu/GrBackendSurface.h",
+  "$_include/gpu/GrBackendSurfaceMutableState.h",
   "$_include/gpu/GrConfig.h",
   "$_include/gpu/GrContext.h",
   "$_include/gpu/GrContextOptions.h",
@@ -35,6 +36,7 @@
   "$_src/gpu/GrAuditTrail.h",
   "$_src/gpu/GrAutoLocaleSetter.h",
   "$_src/gpu/GrBackendSurface.cpp",
+  "$_src/gpu/GrBackendSurfaceMutableStateImpl.h",
   "$_src/gpu/GrBackendTextureImageGenerator.cpp",
   "$_src/gpu/GrBackendTextureImageGenerator.h",
   "$_src/gpu/GrBaseContextPriv.h",
diff --git a/gn/tests.gni b/gn/tests.gni
index 3b9b2d8..aadfae7 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -17,6 +17,7 @@
   "$_tests/AsADashTest.cpp",
   "$_tests/BRDTest.cpp",
   "$_tests/BackendAllocationTest.cpp",
+  "$_tests/BackendSurfaceMutableStateTest.cpp",
   "$_tests/BadIcoTest.cpp",
   "$_tests/BitSetTest.cpp",
   "$_tests/BitmapCopyTest.cpp",
diff --git a/include/gpu/GrBackendSurface.h b/include/gpu/GrBackendSurface.h
index 373d23f..c7c1780 100644
--- a/include/gpu/GrBackendSurface.h
+++ b/include/gpu/GrBackendSurface.h
@@ -8,6 +8,7 @@
 #ifndef GrBackendSurface_DEFINED
 #define GrBackendSurface_DEFINED
 
+#include "include/gpu/GrBackendSurfaceMutableState.h"
 #include "include/gpu/GrTypes.h"
 #include "include/gpu/gl/GrGLTypes.h"
 #include "include/gpu/mock/GrMockTypes.h"
@@ -19,6 +20,7 @@
 #include "include/gpu/dawn/GrDawnTypes.h"
 #endif
 
+class GrBackendSurfaceMutableStateImpl;
 class GrVkImageLayout;
 class GrGLTextureParameters;
 
@@ -224,7 +226,7 @@
 class SK_API GrBackendTexture {
 public:
     // Creates an invalid backend texture.
-    GrBackendTexture() : fIsValid(false) {}
+    GrBackendTexture();
 
     // The GrGLTextureInfo must have a valid fFormat.
     GrBackendTexture(int width,
@@ -232,9 +234,11 @@
                      GrMipMapped,
                      const GrGLTextureInfo& glInfo);
 
+#ifdef SK_VULKAN
     GrBackendTexture(int width,
                      int height,
                      const GrVkImageInfo& vkInfo);
+#endif
 
 #ifdef SK_METAL
     GrBackendTexture(int width,
@@ -286,6 +290,7 @@
     bool getDawnTextureInfo(GrDawnTextureInfo*) const;
 #endif
 
+#ifdef SK_VULKAN
     // If the backend API is Vulkan, copies a snapshot of the GrVkImageInfo struct into the passed
     // in pointer and returns true. This snapshot will set the fImageLayout to the current layout
     // state. Otherwise returns false if the backend API is not Vulkan.
@@ -294,6 +299,7 @@
     // Anytime the client changes the VkImageLayout of the VkImage captured by this
     // GrBackendTexture, they must call this function to notify Skia of the changed layout.
     void setVkImageLayout(VkImageLayout);
+#endif
 
 #ifdef SK_METAL
     // If the backend API is Metal, copies a snapshot of the GrMtlTextureInfo struct into the passed
@@ -319,6 +325,13 @@
     // in pointer and returns true. Otherwise returns false if the backend API is not Mock.
     bool getMockTextureInfo(GrMockTextureInfo*) const;
 
+    // If the client changes any of the mutable backend of the GrBackendTexture they should call
+    // this function to inform Skia that those values have changed. The backend API specific state
+    // that can be set from this function are:
+    //
+    // Vulkan: VkImageLayout and QueueFamilyIndex
+    void setMutableState(const GrBackendSurfaceMutableState&);
+
     // Returns true if we are working with protected content.
     bool isProtected() const;
 
@@ -333,6 +346,8 @@
 #endif
 
 private:
+    friend class GrVkGpu;  // for getMutableState
+    sk_sp<GrBackendSurfaceMutableStateImpl> getMutableState() const;
 
 #ifdef SK_GL
     friend class GrGLTexture;
@@ -347,12 +362,10 @@
 
 #ifdef SK_VULKAN
     friend class GrVkTexture;
-    friend class GrVkGpu;    // for getGrVkImageLayout
     GrBackendTexture(int width,
                      int height,
                      const GrVkImageInfo& vkInfo,
-                     sk_sp<GrVkImageLayout> layout);
-    sk_sp<GrVkImageLayout> getGrVkImageLayout() const;
+                     sk_sp<GrBackendSurfaceMutableStateImpl> mutableState);
 #endif
 
 #ifdef SK_DIRECT3D
@@ -390,12 +403,14 @@
 #ifdef SK_DAWN
     GrDawnTextureInfo fDawnInfo;
 #endif
+
+    sk_sp<GrBackendSurfaceMutableStateImpl> fMutableState;
 };
 
 class SK_API GrBackendRenderTarget {
 public:
     // Creates an invalid backend texture.
-    GrBackendRenderTarget() : fIsValid(false) {}
+    GrBackendRenderTarget();
 
     // The GrGLTextureInfo must have a valid fFormat.
     GrBackendRenderTarget(int width,
@@ -412,6 +427,7 @@
                           const GrDawnRenderTargetInfo& dawnInfo);
 #endif
 
+#ifdef SK_VULKAN
     /** Deprecated, use version that does not take stencil bits. */
     GrBackendRenderTarget(int width,
                           int height,
@@ -419,6 +435,7 @@
                           int stencilBits,
                           const GrVkImageInfo& vkInfo);
     GrBackendRenderTarget(int width, int height, int sampleCnt, const GrVkImageInfo& vkInfo);
+#endif
 
 #ifdef SK_METAL
     GrBackendRenderTarget(int width,
@@ -463,6 +480,7 @@
     bool getDawnRenderTargetInfo(GrDawnRenderTargetInfo*) const;
 #endif
 
+#ifdef SK_VULKAN
     // If the backend API is Vulkan, copies a snapshot of the GrVkImageInfo struct into the passed
     // in pointer and returns true. This snapshot will set the fImageLayout to the current layout
     // state. Otherwise returns false if the backend API is not Vulkan.
@@ -471,6 +489,7 @@
     // Anytime the client changes the VkImageLayout of the VkImage captured by this
     // GrBackendRenderTarget, they must call this function to notify Skia of the changed layout.
     void setVkImageLayout(VkImageLayout);
+#endif
 
 #ifdef SK_METAL
     // If the backend API is Metal, copies a snapshot of the GrMtlTextureInfo struct into the passed
@@ -495,6 +514,13 @@
     // in pointer and returns true. Otherwise returns false if the backend API is not Mock.
     bool getMockRenderTargetInfo(GrMockRenderTargetInfo*) const;
 
+    // If the client changes any of the mutable backend of the GrBackendTexture they should call
+    // this function to inform Skia that those values have changed. The backend API specific state
+    // that can be set from this function are:
+    //
+    // Vulkan: VkImageLayout and QueueFamilyIndex
+    void setMutableState(const GrBackendSurfaceMutableState&);
+
     // Returns true if we are working with protected content.
     bool isProtected() const;
 
@@ -507,12 +533,15 @@
 #endif
 
 private:
-    friend class GrVkGpu; // for getGrVkImageLayout
-    sk_sp<GrVkImageLayout> getGrVkImageLayout() const;
+    friend class GrVkGpu; // for getMutableState
+    sk_sp<GrBackendSurfaceMutableStateImpl> getMutableState() const;
 
+#ifdef SK_VULKAN
     friend class GrVkRenderTarget;
     GrBackendRenderTarget(int width, int height, int sampleCnt, const GrVkImageInfo& vkInfo,
-                          sk_sp<GrVkImageLayout> layout);
+                          sk_sp<GrBackendSurfaceMutableStateImpl> mutableState);
+#endif
+
 #ifdef SK_DIRECT3D
     friend class GrD3DGpu;
     friend class GrD3DRenderTarget;
@@ -550,6 +579,7 @@
 #ifdef SK_DAWN
     GrDawnRenderTargetInfo  fDawnInfo;
 #endif
+    sk_sp<GrBackendSurfaceMutableStateImpl> fMutableState;
 };
 
 #endif
diff --git a/include/gpu/GrBackendSurfaceMutableState.h b/include/gpu/GrBackendSurfaceMutableState.h
new file mode 100644
index 0000000..0e5a5db
--- /dev/null
+++ b/include/gpu/GrBackendSurfaceMutableState.h
@@ -0,0 +1,65 @@
+/*
+ * 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 GrBackendSurfaceMutableState_DEFINED
+#define GrBackendSurfaceMutableState_DEFINED
+
+#include "include/gpu/GrTypes.h"
+
+#ifdef SK_VULKAN
+#include "include/private/GrVkTypesPriv.h"
+#endif
+
+/**
+ * Since Skia and clients can both modify gpu textures and their connected state, Skia needs a way
+ * for clients to inform us if they have modifiend any of this state. In order to not need setters
+ * for every single API and state, we use this class to be a generic wrapper around all the mutable
+ * state. This class is used for calls that inform Skia of these texture/image state changes by the
+ * client as well as for requesting state changes to be done by Skia. The backend specific state
+ * that is wrapped by this class are:
+ *
+ * Vulkan: VkImageLayout and QueueFamilyIndex
+ */
+class GrBackendSurfaceMutableState {
+public:
+#ifdef SK_VULKAN
+    GrBackendSurfaceMutableState(VkImageLayout layout, uint32_t queueFamilyIndex)
+            : fVkState(layout, queueFamilyIndex)
+            , fBackend(GrBackend::kVulkan) {}
+#endif
+
+    GrBackendSurfaceMutableState& operator=(const GrBackendSurfaceMutableState& that) {
+        switch (fBackend) {
+            case GrBackend::kVulkan:
+#ifdef SK_VULKAN
+                SkASSERT(that.fBackend == GrBackend::kVulkan);
+                fVkState = that.fVkState;
+#endif
+                break;
+
+            default:
+                (void)that;
+                SkUNREACHABLE;
+        }
+        fBackend = that.fBackend;
+        return *this;
+    }
+
+private:
+    friend class GrBackendSurfaceMutableStateImpl;
+
+    union {
+        char fDummy;
+#ifdef SK_VULKAN
+        GrVkSharedImageInfo fVkState;
+#endif
+    };
+
+    GrBackend fBackend;
+};
+
+#endif
diff --git a/include/gpu/vk/GrVkTypes.h b/include/gpu/vk/GrVkTypes.h
index c735367..e5d91a4 100644
--- a/include/gpu/vk/GrVkTypes.h
+++ b/include/gpu/vk/GrVkTypes.h
@@ -190,14 +190,14 @@
             , fProtected(isProtected)
             , fYcbcrConversionInfo(ycbcrConversionInfo) {}
 
-    GrVkImageInfo(const GrVkImageInfo& info, VkImageLayout layout)
+    GrVkImageInfo(const GrVkImageInfo& info, VkImageLayout layout, uint32_t familyQueueIndex)
             : fImage(info.fImage)
             , fAlloc(info.fAlloc)
             , fImageTiling(info.fImageTiling)
             , fImageLayout(layout)
             , fFormat(info.fFormat)
             , fLevelCount(info.fLevelCount)
-            , fCurrentQueueFamily(info.fCurrentQueueFamily)
+            , fCurrentQueueFamily(familyQueueIndex)
             , fProtected(info.fProtected)
             , fYcbcrConversionInfo(info.fYcbcrConversionInfo) {}
 
diff --git a/include/private/GrVkTypesPriv.h b/include/private/GrVkTypesPriv.h
index 49b392c..07b6a2c 100644
--- a/include/private/GrVkTypesPriv.h
+++ b/include/private/GrVkTypesPriv.h
@@ -11,7 +11,7 @@
 #include "include/core/SkRefCnt.h"
 #include "include/gpu/vk/GrVkTypes.h"
 
-class GrVkImageLayout;
+class GrBackendSurfaceMutableStateImpl;
 
 // This struct is to used to store the the actual information about the vulkan backend image on the
 // GrBackendTexture and GrBackendRenderTarget. When a client calls getVkImageInfo on a
@@ -20,8 +20,7 @@
 // current VkImageLayout which can be shared with an internal GrVkImage so that layout updates can
 // be seen by all users of the image.
 struct GrVkBackendSurfaceInfo {
-    GrVkBackendSurfaceInfo(GrVkImageInfo info, GrVkImageLayout* layout)
-            : fImageInfo(info), fLayout(layout) {}
+    GrVkBackendSurfaceInfo(GrVkImageInfo info) : fImageInfo(info) {}
 
     void cleanup();
 
@@ -31,11 +30,7 @@
     // attempt to unref the old fLayout on this object.
     void assign(const GrVkBackendSurfaceInfo&, bool isValid);
 
-    void setImageLayout(VkImageLayout layout);
-
-    sk_sp<GrVkImageLayout> getGrVkImageLayout() const;
-
-    GrVkImageInfo snapImageInfo() const;
+    GrVkImageInfo snapImageInfo(const GrBackendSurfaceMutableStateImpl*) const;
 
     bool isProtected() const { return fImageInfo.fProtected == GrProtected::kYes; }
 #if GR_TEST_UTILS
@@ -44,7 +39,44 @@
 
 private:
     GrVkImageInfo    fImageInfo;
-    GrVkImageLayout* fLayout;
+};
+
+class GrVkSharedImageInfo {
+public:
+    GrVkSharedImageInfo(VkImageLayout layout, uint32_t queueFamilyIndex)
+            : fLayout(layout)
+            , fQueueFamilyIndex(queueFamilyIndex) {}
+
+    GrVkSharedImageInfo& operator=(const GrVkSharedImageInfo& that) {
+        fLayout = that.getImageLayout();
+        fQueueFamilyIndex = that.getQueueFamilyIndex();
+        return *this;
+    }
+
+
+     void setImageLayout(VkImageLayout layout) {
+        // Defaulting to use std::memory_order_seq_cst
+        fLayout.store(layout);
+    }
+
+    VkImageLayout getImageLayout() const {
+        // Defaulting to use std::memory_order_seq_cst
+        return fLayout.load();
+    }
+
+    void setQueueFamilyIndex(uint32_t queueFamilyIndex) {
+        // Defaulting to use std::memory_order_seq_cst
+        fQueueFamilyIndex.store(queueFamilyIndex);
+    }
+
+    uint32_t getQueueFamilyIndex() const {
+        // Defaulting to use std::memory_order_seq_cst
+        return fQueueFamilyIndex.load();
+    }
+
+private:
+    std::atomic<VkImageLayout> fLayout;
+    std::atomic<uint32_t> fQueueFamilyIndex;
 };
 
 #endif
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
diff --git a/tests/BackendSurfaceMutableStateTest.cpp b/tests/BackendSurfaceMutableStateTest.cpp
new file mode 100644
index 0000000..14907ab
--- /dev/null
+++ b/tests/BackendSurfaceMutableStateTest.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkImage.h"
+#include "include/gpu/GrBackendSurface.h"
+#include "include/gpu/GrContext.h"
+#include "include/gpu/vk/GrVkTypes.h"
+#include "src/gpu/GrTexture.h"
+#include "src/gpu/GrTextureProxy.h"
+#include "src/image/SkImage_Base.h"
+#include "tests/Test.h"
+
+#ifdef SK_VULKAN
+
+#include "src/gpu/vk/GrVkTexture.h"
+
+DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkBackendSurfaceMutableStateTest, reporter, ctxInfo) {
+    GrContext* context = ctxInfo.grContext();
+
+    GrBackendFormat format = GrBackendFormat::MakeVk(VK_FORMAT_R8G8B8A8_UNORM);
+    GrBackendTexture backendTex = context->createBackendTexture(
+            32, 32, format, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
+
+    REPORTER_ASSERT(reporter, backendTex.isValid());
+
+    GrVkImageInfo info;
+    REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
+    VkImageLayout initLayout = info.fImageLayout;
+    uint32_t initQueue = info.fCurrentQueueFamily;
+    GrBackendSurfaceMutableState initState(initLayout, initQueue);
+
+    // Verify that setting that state via a copy of a backendTexture is reflected in all the
+    // backendTextures.
+    GrBackendTexture backendTexCopy = backendTex;
+    REPORTER_ASSERT(reporter, backendTexCopy.getVkImageInfo(&info));
+    REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
+    REPORTER_ASSERT(reporter, initQueue == info.fCurrentQueueFamily);
+
+    GrBackendSurfaceMutableState newState(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+                                          VK_QUEUE_FAMILY_IGNORED);
+    backendTexCopy.setMutableState(newState);
+
+    REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
+    REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == info.fImageLayout);
+    REPORTER_ASSERT(reporter, VK_QUEUE_FAMILY_IGNORED == info.fCurrentQueueFamily);
+
+    REPORTER_ASSERT(reporter, backendTexCopy.getVkImageInfo(&info));
+    REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == info.fImageLayout);
+    REPORTER_ASSERT(reporter, VK_QUEUE_FAMILY_IGNORED == info.fCurrentQueueFamily);
+
+    // Setting back to the init state since we didn't actually change it
+    backendTex.setMutableState(initState);
+
+    sk_sp<SkImage> wrappedImage = SkImage::MakeFromTexture(context, backendTex,
+                                                           kTopLeft_GrSurfaceOrigin,
+                                                           kRGBA_8888_SkColorType,
+                                                           kPremul_SkAlphaType, nullptr);
+
+    const GrSurfaceProxyView* view = as_IB(wrappedImage)->view(context);
+    REPORTER_ASSERT(reporter, view);
+    REPORTER_ASSERT(reporter, view->proxy()->isInstantiated());
+    GrTexture* texture = view->proxy()->peekTexture();
+    REPORTER_ASSERT(reporter, texture);
+
+    // Verify that modifying the layout via the GrVkTexture is reflected in the GrBackendTexture
+    GrVkTexture* vkTexture = static_cast<GrVkTexture*>(texture);
+    REPORTER_ASSERT(reporter, initLayout == vkTexture->currentLayout());
+    REPORTER_ASSERT(reporter, initQueue == vkTexture->currentQueueFamilyIndex());
+    vkTexture->updateImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+
+    REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
+    REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == info.fImageLayout);
+    REPORTER_ASSERT(reporter, initQueue == info.fCurrentQueueFamily);
+
+    GrBackendTexture backendTexImage = wrappedImage->getBackendTexture(false);
+    REPORTER_ASSERT(reporter, backendTexImage.getVkImageInfo(&info));
+    REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == info.fImageLayout);
+    REPORTER_ASSERT(reporter, initQueue == info.fCurrentQueueFamily);
+
+    // Verify that modifying the layout via the GrBackendTexutre is reflected in the GrVkTexture
+    backendTexImage.setMutableState(newState);
+    REPORTER_ASSERT(reporter,
+                    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == vkTexture->currentLayout());
+    REPORTER_ASSERT(reporter, VK_QUEUE_FAMILY_IGNORED == info.fCurrentQueueFamily);
+
+    vkTexture->setQueueFamilyIndex(initQueue);
+    vkTexture->updateImageLayout(initLayout);
+
+    REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
+    REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
+    REPORTER_ASSERT(reporter, initQueue == info.fCurrentQueueFamily);
+
+    REPORTER_ASSERT(reporter, backendTexCopy.getVkImageInfo(&info));
+    REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
+    REPORTER_ASSERT(reporter, initQueue == info.fCurrentQueueFamily);
+
+    REPORTER_ASSERT(reporter, backendTexImage.getVkImageInfo(&info));
+    REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
+    REPORTER_ASSERT(reporter, initQueue == info.fCurrentQueueFamily);
+
+    context->deleteBackendTexture(backendTex);
+}
+
+#endif