[Impeller] tear down swapchain when backgrounding. (#165259)
When we return to the foreground the swapchain is reconstructed anyway.
Eagerly tearing the old one down releases memory faster. Highlighted by
a regression in a customer: money benchmark.
diff --git a/engine/src/flutter/ci/licenses_golden/excluded_files b/engine/src/flutter/ci/licenses_golden/excluded_files
index d632d10..4227a1f 100644
--- a/engine/src/flutter/ci/licenses_golden/excluded_files
+++ b/engine/src/flutter/ci/licenses_golden/excluded_files
@@ -206,6 +206,7 @@
../../../flutter/impeller/renderer/backend/vulkan/render_pass_cache_unittests.cc
../../../flutter/impeller/renderer/backend/vulkan/render_pass_vk_unittests.cc
../../../flutter/impeller/renderer/backend/vulkan/resource_manager_vk_unittests.cc
+../../../flutter/impeller/renderer/backend/vulkan/surface_context_vk_unittests.cc
../../../flutter/impeller/renderer/backend/vulkan/swapchain/README.md
../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/README.md
../../../flutter/impeller/renderer/backend/vulkan/test
diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn b/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn
index cc800da..2f31d4f 100644
--- a/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn
+++ b/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn
@@ -22,6 +22,7 @@
"render_pass_cache_unittests.cc",
"render_pass_vk_unittests.cc",
"resource_manager_vk_unittests.cc",
+ "surface_context_vk_unittests.cc",
"test/gpu_tracer_unittests.cc",
"test/mock_vulkan.cc",
"test/mock_vulkan.h",
diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc
index a96e5fa..33cbc58 100644
--- a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc
+++ b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc
@@ -72,6 +72,13 @@
return SetSwapchain(SwapchainVK::Create(parent_, std::move(surface), size));
}
+void SurfaceContextVK::TeardownSwapchain() {
+ // When background the application, tear down the swapchain to release memory
+ // from the images. When returning to the foreground, SetWindowSurface will be
+ // called which will re-create the swapchain.
+ swapchain_.reset();
+}
+
bool SurfaceContextVK::SetSwapchain(std::shared_ptr<SwapchainVK> swapchain) {
if (!swapchain || !swapchain->IsValid()) {
VALIDATION_LOG << "Invalid swapchain.";
diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h
index c629e65..9f0b088 100644
--- a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h
+++ b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h
@@ -96,6 +96,9 @@
/// recreated on the next frame.
void UpdateSurfaceSize(const ISize& size) const;
+ /// @brief Can be called when the surface is destroyed to reduce memory usage.
+ void TeardownSwapchain();
+
// |Context|
void InitializeCommonlyUsedShadersIfNeeded() const override;
diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk_unittests.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk_unittests.cc
new file mode 100644
index 0000000..5cb2c7e
--- /dev/null
+++ b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk_unittests.cc
@@ -0,0 +1,47 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sys/types.h>
+#include <memory>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "impeller/renderer/backend/vulkan/surface_context_vk.h"
+#include "impeller/renderer/backend/vulkan/test/mock_vulkan.h"
+#include "impeller/renderer/surface.h"
+
+namespace impeller {
+namespace testing {
+
+namespace {
+vk::UniqueSurfaceKHR CreateSurface(const ContextVK& context) {
+#if FML_OS_DARWIN
+ impeller::vk::MetalSurfaceCreateInfoEXT createInfo = {};
+ auto [result, surface] =
+ context.GetInstance().createMetalSurfaceEXTUnique(createInfo);
+ FML_DCHECK(result == vk::Result::eSuccess);
+ return std::move(surface);
+#else
+ return {};
+#endif // FML_OS_DARWIN
+}
+} // namespace
+
+TEST(SurfaceContextVK, TearsDownSwapchain) {
+ SetSwapchainImageSize({100, 100});
+ std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
+
+ vk::UniqueSurfaceKHR surface = CreateSurface(*context);
+ SurfaceContextVK surface_context(context);
+
+ EXPECT_TRUE(surface_context.SetWindowSurface(std::move(surface), {100, 100}));
+ EXPECT_NE(surface_context.AcquireNextSurface(), nullptr);
+
+ surface_context.TeardownSwapchain();
+
+ EXPECT_EQ(surface_context.AcquireNextSurface(), nullptr);
+}
+
+} // namespace testing
+} // namespace impeller
diff --git a/engine/src/flutter/shell/platform/android/android_surface_vk_impeller.cc b/engine/src/flutter/shell/platform/android/android_surface_vk_impeller.cc
index 2ecea59..008724c 100644
--- a/engine/src/flutter/shell/platform/android/android_surface_vk_impeller.cc
+++ b/engine/src/flutter/shell/platform/android/android_surface_vk_impeller.cc
@@ -37,7 +37,7 @@
}
void AndroidSurfaceVKImpeller::TeardownOnScreenContext() {
- // Nothing to do.
+ surface_context_vk_->TeardownSwapchain();
}
std::unique_ptr<Surface> AndroidSurfaceVKImpeller::CreateGPUSurface(