[Impeller] cache MSAA texture in swapchain for devices that do not support memoryless. (#43349)

For devices that don't support memoryless textures, the fullscreen MSAA texture adds a substantial amount of memory thrashing when it is allocated and deallocated. For these devices, lets cache the MSAA texture in the swapchain image.

https://github.com/flutter/flutter/issues/129737
diff --git a/impeller/renderer/backend/vulkan/surface_vk.cc b/impeller/renderer/backend/vulkan/surface_vk.cc
index 3f1006e..ab11006 100644
--- a/impeller/renderer/backend/vulkan/surface_vk.cc
+++ b/impeller/renderer/backend/vulkan/surface_vk.cc
@@ -12,12 +12,18 @@
 
 std::unique_ptr<SurfaceVK> SurfaceVK::WrapSwapchainImage(
     const std::shared_ptr<Context>& context,
-    const std::shared_ptr<SwapchainImageVK>& swapchain_image,
+    std::shared_ptr<SwapchainImageVK>& swapchain_image,
     SwapCallback swap_callback) {
   if (!context || !swapchain_image || !swap_callback) {
     return nullptr;
   }
 
+  // Some Vulkan devices may not support memoryless (lazily allocated) textures.
+  // In this case we will cache the MSAA texture on the swapchain image to avoid
+  // thrasing the VMA heap.
+  bool supports_memoryless =
+      context->GetCapabilities()->SupportsMemorylessTextures();
+
   TextureDescriptor msaa_tex_desc;
   msaa_tex_desc.storage_mode = StorageMode::kDeviceTransient;
   msaa_tex_desc.type = TextureType::kTexture2DMultisample;
@@ -26,12 +32,20 @@
   msaa_tex_desc.size = swapchain_image->GetSize();
   msaa_tex_desc.usage = static_cast<uint64_t>(TextureUsage::kRenderTarget);
 
-  auto msaa_tex = context->GetResourceAllocator()->CreateTexture(msaa_tex_desc);
-  if (!msaa_tex) {
-    VALIDATION_LOG << "Could not allocate MSAA color texture.";
-    return nullptr;
+  std::shared_ptr<Texture> msaa_tex;
+  if (supports_memoryless || !swapchain_image->HasMSAATexture()) {
+    msaa_tex = context->GetResourceAllocator()->CreateTexture(msaa_tex_desc);
+    msaa_tex->SetLabel("ImpellerOnscreenColorMSAA");
+    if (!msaa_tex) {
+      VALIDATION_LOG << "Could not allocate MSAA color texture.";
+      return nullptr;
+    }
+    if (!supports_memoryless) {
+      swapchain_image->SetMSAATexture(msaa_tex);
+    }
+  } else {
+    msaa_tex = swapchain_image->GetMSAATexture();
   }
-  msaa_tex->SetLabel("ImpellerOnscreenColorMSAA");
 
   TextureDescriptor resolve_tex_desc;
   resolve_tex_desc.type = TextureType::kTexture2D;
diff --git a/impeller/renderer/backend/vulkan/surface_vk.h b/impeller/renderer/backend/vulkan/surface_vk.h
index b6824f5..6138a8e 100644
--- a/impeller/renderer/backend/vulkan/surface_vk.h
+++ b/impeller/renderer/backend/vulkan/surface_vk.h
@@ -19,7 +19,7 @@
 
   static std::unique_ptr<SurfaceVK> WrapSwapchainImage(
       const std::shared_ptr<Context>& context,
-      const std::shared_ptr<SwapchainImageVK>& swapchain_image,
+      std::shared_ptr<SwapchainImageVK>& swapchain_image,
       SwapCallback swap_callback);
 
   // |Surface|
diff --git a/impeller/renderer/backend/vulkan/swapchain_image_vk.cc b/impeller/renderer/backend/vulkan/swapchain_image_vk.cc
index 392c76b..dee06c7 100644
--- a/impeller/renderer/backend/vulkan/swapchain_image_vk.cc
+++ b/impeller/renderer/backend/vulkan/swapchain_image_vk.cc
@@ -35,6 +35,18 @@
   return is_valid_;
 }
 
+std::shared_ptr<Texture> SwapchainImageVK::GetMSAATexture() const {
+  return msaa_tex_;
+}
+
+bool SwapchainImageVK::HasMSAATexture() const {
+  return msaa_tex_ != nullptr;
+}
+
+void SwapchainImageVK::SetMSAATexture(std::shared_ptr<Texture> msaa_tex) {
+  msaa_tex_ = std::move(msaa_tex);
+}
+
 PixelFormat SwapchainImageVK::GetPixelFormat() const {
   return desc_.format;
 }
diff --git a/impeller/renderer/backend/vulkan/swapchain_image_vk.h b/impeller/renderer/backend/vulkan/swapchain_image_vk.h
index 6cf1943..115cfa1 100644
--- a/impeller/renderer/backend/vulkan/swapchain_image_vk.h
+++ b/impeller/renderer/backend/vulkan/swapchain_image_vk.h
@@ -30,12 +30,19 @@
   // |TextureSourceVK|
   vk::Image GetImage() const override;
 
+  std::shared_ptr<Texture> GetMSAATexture() const;
+
+  bool HasMSAATexture() const;
+
   // |TextureSourceVK|
   vk::ImageView GetImageView() const override;
 
+  void SetMSAATexture(std::shared_ptr<Texture> msaa_tex);
+
  private:
   vk::Image image_ = VK_NULL_HANDLE;
   vk::UniqueImageView image_view_ = {};
+  std::shared_ptr<Texture> msaa_tex_;
   bool is_valid_ = false;
 
   FML_DISALLOW_COPY_AND_ASSIGN(SwapchainImageVK);