Use the new GrMSAAAttachment class in vulkan.

Instead of creating internal msaa VkImages for vulkan render targets we
now get a GrMSAAAttachment from the resource provider to use instead.
As of now only one GrVkRenderTarget can hold a ref to an msaa attachment
at a time.

Bug: skia:10830
Change-Id: I361a1687f10e047a5b61228f861326f2b1418f06
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/320272
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 2fd4dbb..dc1abb1 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -2300,7 +2300,7 @@
         if (vkRT->wrapsSecondaryCommandBuffer()) {
             return false;
         }
-        dstImage = vkRT->numSamples() > 1 ? vkRT->msaaImage() : vkRT;
+        dstImage = vkRT->colorAttachmentImage();
     } else {
         SkASSERT(dst->asTexture());
         dstImage = static_cast<GrVkTexture*>(dst->asTexture());
@@ -2308,7 +2308,7 @@
     GrRenderTarget* srcRT = src->asRenderTarget();
     if (srcRT) {
         GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(srcRT);
-        srcImage = vkRT->numSamples() > 1 ? vkRT->msaaImage() : vkRT;
+        srcImage = vkRT->colorAttachmentImage();
     } else {
         SkASSERT(src->asTexture());
         srcImage = static_cast<GrVkTexture*>(src->asTexture());
diff --git a/src/gpu/vk/GrVkOpsRenderPass.cpp b/src/gpu/vk/GrVkOpsRenderPass.cpp
index 63367cc..de2f092 100644
--- a/src/gpu/vk/GrVkOpsRenderPass.cpp
+++ b/src/gpu/vk/GrVkOpsRenderPass.cpp
@@ -16,6 +16,7 @@
 #include "src/gpu/GrOpFlushState.h"
 #include "src/gpu/GrPipeline.h"
 #include "src/gpu/GrRenderTarget.h"
+#include "src/gpu/vk/GrVkAttachment.h"
 #include "src/gpu/vk/GrVkCommandBuffer.h"
 #include "src/gpu/vk/GrVkCommandPool.h"
 #include "src/gpu/vk/GrVkGpu.h"
@@ -76,7 +77,7 @@
     GrVkRenderPass::LoadStoreOps vkStencilOps(loadOp, storeOp);
 
     GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
-    GrVkImage* targetImage = vkRT->msaaImage() ? vkRT->msaaImage() : vkRT;
+    GrVkImage* targetImage = vkRT->colorAttachmentImage();
 
     if (fSelfDependencyFlags == SelfDependencyFlags::kForInputAttachment) {
         // We need to use the GENERAL layout in this case since we'll be using texture barriers
@@ -677,7 +678,7 @@
     }
     GrVkRenderTarget* target = static_cast<GrVkRenderTarget*>(fRenderTarget);
 
-    GrVkImage* targetImage = target->msaaImage() ? target->msaaImage() : target;
+    GrVkImage* targetImage = target->colorAttachmentImage();
 
     VkRect2D bounds;
     bounds.offset = { 0, 0 };
diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp
index 2357ebe..3f3f2f5 100644
--- a/src/gpu/vk/GrVkRenderTarget.cpp
+++ b/src/gpu/vk/GrVkRenderTarget.cpp
@@ -8,6 +8,11 @@
 #include "src/gpu/vk/GrVkRenderTarget.h"
 
 #include "include/gpu/GrBackendSurface.h"
+#include "include/gpu/GrDirectContext.h"
+#include "src/gpu/GrBackendSurfaceMutableStateImpl.h"
+#include "src/gpu/GrContextPriv.h"
+#include "src/gpu/GrResourceProvider.h"
+#include "src/gpu/vk/GrVkAttachment.h"
 #include "src/gpu/vk/GrVkCommandBuffer.h"
 #include "src/gpu/vk/GrVkDescriptorSet.h"
 #include "src/gpu/vk/GrVkFramebuffer.h"
@@ -20,8 +25,8 @@
 
 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
 
-static int renderpass_features_to_index(
-        bool hasStencil, GrVkRenderPass::SelfDependencyFlags selfDepFlags) {
+static int renderpass_features_to_index(bool hasStencil,
+                                        GrVkRenderPass::SelfDependencyFlags selfDepFlags) {
     int index = hasStencil ? 1 : 0;
     if (selfDepFlags & GrVkRenderPass::SelfDependencyFlags::kForInputAttachment) {
         index += 2;
@@ -39,8 +44,7 @@
                                    int sampleCnt,
                                    const GrVkImageInfo& info,
                                    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
-                                   const GrVkImageInfo& msaaInfo,
-                                   sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
+                                   sk_sp<GrVkAttachment> msaaAttachment,
                                    sk_sp<const GrVkImageView> colorAttachmentView,
                                    sk_sp<const GrVkImageView> resolveAttachmentView)
         : GrSurface(gpu, dimensions, info.fProtected)
@@ -48,13 +52,12 @@
         // for the moment we only support 1:1 color to stencil
         , GrRenderTarget(gpu, dimensions, sampleCnt, info.fProtected)
         , fColorAttachmentView(std::move(colorAttachmentView))
-        , fMSAAImage(new GrVkImage(gpu, msaaInfo, std::move(msaaMutableState),
-                                   GrBackendObjectOwnership::kOwned))
+        , fMSAAAttachment(std::move(msaaAttachment))
         , fResolveAttachmentView(std::move(resolveAttachmentView))
         , fCachedFramebuffers()
         , fCachedRenderPasses() {
-    SkASSERT(info.fProtected == msaaInfo.fProtected);
-    SkASSERT(sampleCnt > 1);
+    SkASSERT((info.fProtected == GrProtected::kYes) == fMSAAAttachment->isProtected());
+    SkASSERT(sampleCnt > 1 && sampleCnt == fMSAAAttachment->numSamples());
     SkASSERT(SkToBool(info.fImageUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
     this->setFlags(info);
     this->registerWithCacheWrapped(GrWrapCacheable::kNo);
@@ -67,8 +70,7 @@
                                    int sampleCnt,
                                    const GrVkImageInfo& info,
                                    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
-                                   const GrVkImageInfo& msaaInfo,
-                                   sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
+                                   sk_sp<GrVkAttachment> msaaAttachment,
                                    sk_sp<const GrVkImageView> colorAttachmentView,
                                    sk_sp<const GrVkImageView> resolveAttachmentView,
                                    GrBackendObjectOwnership ownership)
@@ -77,13 +79,12 @@
         // for the moment we only support 1:1 color to stencil
         , GrRenderTarget(gpu, dimensions, sampleCnt, info.fProtected)
         , fColorAttachmentView(std::move(colorAttachmentView))
-        , fMSAAImage(new GrVkImage(gpu, msaaInfo, std::move(msaaMutableState),
-                                   GrBackendObjectOwnership::kOwned))
+        , fMSAAAttachment(std::move(msaaAttachment))
         , fResolveAttachmentView(std::move(resolveAttachmentView))
         , fCachedFramebuffers()
         , fCachedRenderPasses() {
-    SkASSERT(info.fProtected == msaaInfo.fProtected);
-    SkASSERT(sampleCnt > 1);
+    SkASSERT((info.fProtected == GrProtected::kYes) == fMSAAAttachment->isProtected());
+    SkASSERT(sampleCnt > 1 && sampleCnt == fMSAAAttachment->numSamples());
     SkASSERT(SkToBool(info.fImageUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
     this->setFlags(info);
 }
@@ -99,7 +100,6 @@
         , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kBorrowed)
         , GrRenderTarget(gpu, dimensions, info.fSampleCount, info.fProtected)
         , fColorAttachmentView(std::move(colorAttachmentView))
-        , fMSAAImage(nullptr)
         , fCachedFramebuffers()
         , fCachedRenderPasses() {
     SkASSERT(SkToBool(info.fImageUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
@@ -119,7 +119,6 @@
         , GrVkImage(gpu, info, std::move(mutableState), ownership)
         , GrRenderTarget(gpu, dimensions, info.fSampleCount, info.fProtected)
         , fColorAttachmentView(std::move(colorAttachmentView))
-        , fMSAAImage(nullptr)
         , fCachedFramebuffers()
         , fCachedRenderPasses() {
     SkASSERT(SkToBool(info.fImageUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
@@ -135,7 +134,6 @@
         : GrSurface(gpu, dimensions, info.fProtected)
         , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kBorrowed, true)
         , GrRenderTarget(gpu, dimensions, 1, info.fProtected)
-        , fMSAAImage(nullptr)
         , fCachedFramebuffers()
         , fCachedRenderPasses()
         , fSecondaryCommandBuffer(secondaryCommandBuffer) {
@@ -157,7 +155,10 @@
 }
 
 sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(
-        GrVkGpu* gpu, SkISize dimensions, int sampleCnt, const GrVkImageInfo& info,
+        GrVkGpu* gpu,
+        SkISize dimensions,
+        int sampleCnt,
+        const GrVkImageInfo& info,
         sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) {
     SkASSERT(VK_NULL_HANDLE != info.fImage);
     SkASSERT(1 == info.fLevelCount);
@@ -170,65 +171,44 @@
 
     VkFormat pixelFormat = info.fFormat;
 
-    VkImage colorImage;
-
     // create msaa surface if necessary
-    GrVkImageInfo msInfo;
-    sk_sp<GrBackendSurfaceMutableStateImpl> msMutableState;
+    sk_sp<GrVkAttachment> vkMSAAAttachment;
+    sk_sp<const GrVkImageView> colorAttachmentView;
     sk_sp<const GrVkImageView> resolveAttachmentView;
     if (sampleCnt != wrappedImageSampleCnt) {
-        GrVkImage::ImageDesc msImageDesc;
-        msImageDesc.fImageType = VK_IMAGE_TYPE_2D;
-        msImageDesc.fFormat = pixelFormat;
-        msImageDesc.fWidth = dimensions.fWidth;
-        msImageDesc.fHeight = dimensions.fHeight;
-        msImageDesc.fLevels = 1;
-        msImageDesc.fSamples = sampleCnt;
-        msImageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
-        msImageDesc.fUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
-                                  VK_IMAGE_USAGE_TRANSFER_DST_BIT |
-                                  VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
-        msImageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
-        msImageDesc.fIsProtected = info.fProtected;
-
-        if (!GrVkImage::InitImageInfo(gpu, msImageDesc, &msInfo)) {
+        auto rp = gpu->getContext()->priv().resourceProvider();
+        sk_sp<GrAttachment> msaaAttachment =
+                rp->makeMSAAAttachment(dimensions, GrBackendFormat::MakeVk(info.fFormat),
+                                         sampleCnt, info.fProtected);
+        if (!msaaAttachment) {
             return nullptr;
         }
+        vkMSAAAttachment = sk_sp<GrVkAttachment>(
+                static_cast<GrVkAttachment*>(msaaAttachment.release()));
 
-        // Set color attachment image
-        colorImage = msInfo.fImage;
+        colorAttachmentView = sk_ref_sp<const GrVkImageView>(vkMSAAAttachment->view());
 
         // Create Resolve attachment view
-        resolveAttachmentView = GrVkImageView::Make(gpu, info.fImage, pixelFormat,
-                                                      GrVkImageView::kColor_Type, 1,
-                                                      GrVkYcbcrConversionInfo());
+        resolveAttachmentView =
+                GrVkImageView::Make(gpu, info.fImage, pixelFormat, GrVkImageView::kColor_Type, 1,
+                                    GrVkYcbcrConversionInfo());
         if (!resolveAttachmentView) {
-            GrVkImage::DestroyImageInfo(gpu, &msInfo);
             return nullptr;
         }
-        msMutableState.reset(new GrBackendSurfaceMutableStateImpl(msInfo.fImageLayout,
-                                                           msInfo.fCurrentQueueFamily));
     } else {
-        // Set color attachment image
-        colorImage = info.fImage;
+        colorAttachmentView = GrVkImageView::Make(gpu, info.fImage, pixelFormat,
+                                                  GrVkImageView::kColor_Type, 1,
+                                                  GrVkYcbcrConversionInfo());
     }
 
-    // Get color attachment view
-    sk_sp<const GrVkImageView> colorAttachmentView = GrVkImageView::Make(
-            gpu, colorImage, pixelFormat, GrVkImageView::kColor_Type, 1, GrVkYcbcrConversionInfo());
     if (!colorAttachmentView) {
-        if (resolveAttachmentView) {
-            resolveAttachmentView.reset();
-            GrVkImage::DestroyImageInfo(gpu, &msInfo);
-        }
         return nullptr;
     }
 
     GrVkRenderTarget* vkRT;
     if (resolveAttachmentView) {
         vkRT = new GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState),
-                                    msInfo, std::move(msMutableState),
-                                    std::move(colorAttachmentView),
+                                    std::move(vkMSAAAttachment), std::move(colorAttachmentView),
                                     std::move(resolveAttachmentView));
     } else {
         vkRT = new GrVkRenderTarget(gpu, dimensions, info, std::move(mutableState),
@@ -240,9 +220,8 @@
 
 sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeSecondaryCBRenderTarget(
         GrVkGpu* gpu, SkISize dimensions, const GrVkDrawableInfo& vkInfo) {
-    const GrVkRenderPass* rp =
-            gpu->resourceProvider().findCompatibleExternalRenderPass(vkInfo.fCompatibleRenderPass,
-                                                                     vkInfo.fColorAttachmentIndex);
+    const GrVkRenderPass* rp = gpu->resourceProvider().findCompatibleExternalRenderPass(
+            vkInfo.fCompatibleRenderPass, vkInfo.fColorAttachmentIndex);
     if (!rp) {
         return nullptr;
     }
@@ -356,10 +335,9 @@
 
     // Stencil attachment view is stored in the base RT stencil attachment
     const GrVkImageView* stencilView = withStencil ? this->stencilAttachmentView() : nullptr;
-    fCachedFramebuffers[cacheIndex] = GrVkFramebuffer::Create(gpu, this->width(), this->height(),
-                                                              renderPass,
-                                                              fColorAttachmentView.get(),
-                                                              stencilView);
+    fCachedFramebuffers[cacheIndex] =
+            GrVkFramebuffer::Create(gpu, this->width(), this->height(), renderPass,
+                                    fColorAttachmentView.get(), stencilView);
 
     return fCachedFramebuffers[cacheIndex];
 }
@@ -458,10 +436,8 @@
     return fCachedInputDescriptorSet;
 }
 
-
 GrVkRenderTarget::~GrVkRenderTarget() {
     // either release or abandon should have been called by the owner of this object.
-    SkASSERT(!fMSAAImage);
     SkASSERT(!fResolveAttachmentView);
     SkASSERT(!fColorAttachmentView);
 
@@ -473,12 +449,12 @@
     SkASSERT(!fCachedInputDescriptorSet);
 }
 
-void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer, bool withStencil,
+void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer,
+                                    bool withStencil,
                                     SelfDependencyFlags selfDepFlags) {
     commandBuffer.addResource(this->getFramebuffer(withStencil, selfDepFlags));
     commandBuffer.addResource(this->colorAttachmentView());
-    commandBuffer.addResource(this->msaaImageResource() ? this->msaaImageResource()
-                                                        : this->resource());
+    commandBuffer.addResource(fMSAAAttachment ? fMSAAAttachment->resource() : this->resource());
     if (this->stencilImageResource()) {
         commandBuffer.addResource(this->stencilImageResource());
         commandBuffer.addResource(this->stencilAttachmentView());
@@ -486,9 +462,8 @@
 }
 
 void GrVkRenderTarget::releaseInternalObjects() {
-    if (fMSAAImage) {
-        fMSAAImage->releaseImage();
-        fMSAAImage.reset();
+    if (fMSAAAttachment) {
+        fMSAAAttachment.reset();
     }
 
     if (fResolveAttachmentView) {
@@ -540,16 +515,16 @@
 
 GrVkImage* GrVkRenderTarget::msaaImage() {
     if (this->numSamples() == 1) {
-        SkASSERT(fColorAttachmentView && !fResolveAttachmentView);
+        SkASSERT(fColorAttachmentView && !fMSAAAttachment && !fResolveAttachmentView);
         return nullptr;
     }
-    if (!this->fResolveAttachmentView) {
+    if (!fMSAAAttachment) {
         // In this case *this* object is MSAA (there is not a separate color and resolve buffer)
-        SkASSERT(!fMSAAImage);
+        SkASSERT(!fResolveAttachmentView);
         return this;
     }
-    SkASSERT(fMSAAImage);
-    return fMSAAImage.get();
+    SkASSERT(fMSAAAttachment);
+    return fMSAAAttachment.get();
 }
 
 const GrManagedResource* GrVkRenderTarget::stencilImageResource() const {
@@ -574,6 +549,13 @@
     return nullptr;
 }
 
+GrVkImage* GrVkRenderTarget::colorAttachmentImage() {
+    if (fMSAAAttachment) {
+        return fMSAAAttachment.get();
+    }
+    return this;
+}
+
 GrVkGpu* GrVkRenderTarget::getVkGpu() const {
     SkASSERT(!this->wasDestroyed());
     return static_cast<GrVkGpu*>(this->getGpu());
diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h
index db52d51..730606b 100644
--- a/src/gpu/vk/GrVkRenderTarget.h
+++ b/src/gpu/vk/GrVkRenderTarget.h
@@ -40,23 +40,24 @@
     using SelfDependencyFlags = GrVkRenderPass::SelfDependencyFlags;
 
     const GrVkFramebuffer* getFramebuffer(bool withStencil, SelfDependencyFlags);
+
     const GrVkImageView* colorAttachmentView() const { return fColorAttachmentView.get(); }
-    const GrManagedResource* msaaImageResource() const {
-        if (fMSAAImage) {
-            return fMSAAImage->fResource;
-        }
-        return nullptr;
-    }
+
     /**
      * If this render target is multisampled, this returns the MSAA image for rendering. This
      * will be different than *this* when we have separate render/resolve images. If not
      * multisampled returns nullptr.
      */
     GrVkImage* msaaImage();
+
     const GrVkImageView* resolveAttachmentView() const { return fResolveAttachmentView.get(); }
     const GrManagedResource* stencilImageResource() const;
     const GrVkImageView* stencilAttachmentView() const;
 
+    // Returns the main target for draws. If using MSAA and we have a resolve target, it will be the
+    // msaa attachment. Otherwise it will be this object.
+    GrVkImage* colorAttachmentImage();
+
     const GrVkRenderPass* getSimpleRenderPass(bool withStencil, SelfDependencyFlags);
     GrVkResourceProvider::CompatibleRPHandle compatibleRenderPassHandle(bool withStencil,
                                                                         SelfDependencyFlags);
@@ -105,8 +106,7 @@
                      int sampleCnt,
                      const GrVkImageInfo& info,
                      sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
-                     const GrVkImageInfo& msaaInfo,
-                     sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
+                     sk_sp<GrVkAttachment> msaaAttachment,
                      sk_sp<const GrVkImageView> colorAttachmentView,
                      sk_sp<const GrVkImageView> resolveAttachmentView,
                      GrBackendObjectOwnership);
@@ -138,8 +138,7 @@
                      int sampleCnt,
                      const GrVkImageInfo& info,
                      sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
-                     const GrVkImageInfo& msaaInfo,
-                     sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
+                     sk_sp<GrVkAttachment> msaaAttachment,
                      sk_sp<const GrVkImageView> colorAttachmentView,
                      sk_sp<const GrVkImageView> resolveAttachmentView);
 
@@ -175,7 +174,7 @@
     void releaseInternalObjects();
 
     sk_sp<const GrVkImageView> fColorAttachmentView;
-    std::unique_ptr<GrVkImage> fMSAAImage;
+    sk_sp<GrVkAttachment>      fMSAAAttachment;
     sk_sp<const GrVkImageView> fResolveAttachmentView;
 
     // We can have a renderpass with and without stencil, input attachment dependency, and advanced
diff --git a/src/gpu/vk/GrVkTextureRenderTarget.cpp b/src/gpu/vk/GrVkTextureRenderTarget.cpp
index 7cfd759..2af87b9 100644
--- a/src/gpu/vk/GrVkTextureRenderTarget.cpp
+++ b/src/gpu/vk/GrVkTextureRenderTarget.cpp
@@ -7,7 +7,10 @@
 
 #include "src/gpu/vk/GrVkTextureRenderTarget.h"
 
+#include "src/gpu/GrContextPriv.h"
+#include "src/gpu/GrResourceProvider.h"
 #include "src/gpu/GrTexture.h"
+#include "src/gpu/vk/GrVkAttachment.h"
 #include "src/gpu/vk/GrVkGpu.h"
 #include "src/gpu/vk/GrVkImageView.h"
 #include "src/gpu/vk/GrVkUtil.h"
@@ -26,8 +29,7 @@
         const GrVkImageInfo& info,
         sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
         sk_sp<const GrVkImageView> texView,
-        const GrVkImageInfo& msaaInfo,
-        sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
+        sk_sp<GrVkAttachment> msaaAttachment,
         sk_sp<const GrVkImageView> colorAttachmentView,
         sk_sp<const GrVkImageView> resolveAttachmentView,
         GrMipmapStatus mipmapStatus)
@@ -35,10 +37,9 @@
         , GrVkImage(gpu, info, mutableState, GrBackendObjectOwnership::kOwned)
         , GrVkTexture(gpu, dimensions, info, mutableState, std::move(texView), mipmapStatus,
                       GrBackendObjectOwnership::kOwned)
-        , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState), msaaInfo,
-                           std::move(msaaMutableState), std::move(colorAttachmentView),
+        , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState),
+                           std::move(msaaAttachment), std::move(colorAttachmentView),
                            std::move(resolveAttachmentView), GrBackendObjectOwnership::kOwned) {
-    SkASSERT(info.fProtected == msaaInfo.fProtected);
     this->registerWithCache(budgeted);
 }
 
@@ -67,8 +68,7 @@
         const GrVkImageInfo& info,
         sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
         sk_sp<const GrVkImageView> texView,
-        const GrVkImageInfo& msaaInfo,
-        sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
+        sk_sp<GrVkAttachment> msaaAttachment,
         sk_sp<const GrVkImageView> colorAttachmentView,
         sk_sp<const GrVkImageView> resolveAttachmentView,
         GrMipmapStatus mipmapStatus,
@@ -78,10 +78,9 @@
         , GrVkImage(gpu, info, mutableState, ownership)
         , GrVkTexture(gpu, dimensions, info, mutableState, std::move(texView), mipmapStatus,
                       ownership)
-        , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState), msaaInfo,
-                           std::move(msaaMutableState), std::move(colorAttachmentView),
+        , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState),
+                           std::move(msaaAttachment), std::move(colorAttachmentView),
                            std::move(resolveAttachmentView), ownership) {
-    SkASSERT(info.fProtected == msaaInfo.fProtected);
     this->registerWithCacheWrapped(cacheable);
 }
 
@@ -109,8 +108,7 @@
     sk_sp<const GrVkImageView> imageView;
     sk_sp<const GrVkImageView> colorAttachmentView;
     sk_sp<const GrVkImageView> resolveAttachmentView;
-    GrVkImageInfo msInfo;
-    sk_sp<GrBackendSurfaceMutableStateImpl> msMutableState;
+    sk_sp<GrVkAttachment> msaaAttachment;
 };
 }  // anonymous namespace
 
@@ -127,51 +125,35 @@
 
     VkFormat pixelFormat = info.fFormat;
 
-    VkImage colorImage;
-
     // create msaa surface if necessary
     if (sampleCnt > 1) {
-        GrVkImage::ImageDesc msImageDesc;
-        msImageDesc.fImageType = VK_IMAGE_TYPE_2D;
-        msImageDesc.fFormat = pixelFormat;
-        msImageDesc.fWidth = dimensions.fWidth;
-        msImageDesc.fHeight = dimensions.fHeight;
-        msImageDesc.fLevels = 1;
-        msImageDesc.fSamples = sampleCnt;
-        msImageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
-        msImageDesc.fUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
-                                  VK_IMAGE_USAGE_TRANSFER_DST_BIT |
-                                  VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
-        msImageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
-
-        if (!GrVkImage::InitImageInfo(gpu, msImageDesc, &views.msInfo)) {
+        auto rp = gpu->getContext()->priv().resourceProvider();
+        sk_sp<GrAttachment> msaaAttachment =
+                rp->makeMSAAAttachment(dimensions, GrBackendFormat::MakeVk(info.fFormat),
+                                         sampleCnt, info.fProtected);
+        if (!msaaAttachment) {
             return {};
         }
 
-        // Set color attachment image
-        colorImage = views.msInfo.fImage;
+        views.msaaAttachment = sk_sp<GrVkAttachment>(
+                static_cast<GrVkAttachment*>(msaaAttachment.release()));
+
+        views.colorAttachmentView = sk_ref_sp<const GrVkImageView>(views.msaaAttachment->view());
 
         // Create resolve attachment view.
         views.resolveAttachmentView =
                 GrVkImageView::Make(gpu, image, pixelFormat, GrVkImageView::kColor_Type,
                                     info.fLevelCount, GrVkYcbcrConversionInfo());
         if (!views.resolveAttachmentView) {
-            GrVkImage::DestroyImageInfo(gpu, &views.msInfo);
             return {};
         }
-        views.msMutableState.reset(new GrBackendSurfaceMutableStateImpl(
-                views.msInfo.fImageLayout, views.msInfo.fCurrentQueueFamily));
     } else {
-        // Set color attachment image
-        colorImage = info.fImage;
+        views.colorAttachmentView = GrVkImageView::Make(
+                gpu, info.fImage, pixelFormat, GrVkImageView::kColor_Type, 1,
+                GrVkYcbcrConversionInfo());
     }
 
-    views.colorAttachmentView = GrVkImageView::Make(
-            gpu, colorImage, pixelFormat, GrVkImageView::kColor_Type, 1, GrVkYcbcrConversionInfo());
     if (!views.colorAttachmentView) {
-        if (sampleCnt > 1) {
-            GrVkImage::DestroyImageInfo(gpu, &views.msInfo);
-        }
         return {};
     }
     return views;
@@ -202,7 +184,7 @@
     if (sampleCnt > 1) {
         return sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget(
                 gpu, budgeted, dimensions, sampleCnt, info, std::move(mutableState),
-                std::move(views.imageView), views.msInfo, std::move(views.msMutableState),
+                std::move(views.imageView), std::move(views.msaaAttachment),
                 std::move(views.colorAttachmentView), std::move(views.resolveAttachmentView),
                 mipmapStatus));
     } else {
@@ -236,7 +218,7 @@
     if (sampleCnt > 1) {
         return sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget(
                 gpu, dimensions, sampleCnt, info, std::move(mutableState),
-                std::move(views.imageView), views.msInfo, std::move(views.msMutableState),
+                std::move(views.imageView), std::move(views.msaaAttachment),
                 std::move(views.colorAttachmentView), std::move(views.resolveAttachmentView),
                 mipmapStatus, ownership, cacheable));
     } else {
diff --git a/src/gpu/vk/GrVkTextureRenderTarget.h b/src/gpu/vk/GrVkTextureRenderTarget.h
index a653f1b..39f6a40 100644
--- a/src/gpu/vk/GrVkTextureRenderTarget.h
+++ b/src/gpu/vk/GrVkTextureRenderTarget.h
@@ -65,8 +65,7 @@
                             const GrVkImageInfo& info,
                             sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                             sk_sp<const GrVkImageView> texView,
-                            const GrVkImageInfo& msaaInfo,
-                            sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
+                            sk_sp<GrVkAttachment> msaaAttachment,
                             sk_sp<const GrVkImageView> colorAttachmentView,
                             sk_sp<const GrVkImageView> resolveAttachmentView,
                             GrMipmapStatus);
@@ -88,8 +87,7 @@
                             const GrVkImageInfo& info,
                             sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
                             sk_sp<const GrVkImageView> texView,
-                            const GrVkImageInfo& msaaInfo,
-                            sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState,
+                            sk_sp<GrVkAttachment> msaaAttachment,
                             sk_sp<const GrVkImageView> colorAttachmentView,
                             sk_sp<const GrVkImageView> resolveAttachmentView,
                             GrMipmapStatus,