diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.cc b/impeller/playground/backend/vulkan/playground_impl_vk.cc index 82d8d0e25ffbc..675558f6e53d8 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.cc +++ b/impeller/playground/backend/vulkan/playground_impl_vk.cc @@ -45,6 +45,8 @@ ShaderLibraryMappingsForPlayground() { }; } +vk::UniqueInstance PlaygroundImplVK::global_instance_; + void PlaygroundImplVK::DestroyWindowHandle(WindowHandle handle) { if (!handle) { return; @@ -67,6 +69,8 @@ PlaygroundImplVK::PlaygroundImplVK(PlaygroundSwitches switches) return; } + InitGlobalVulkanInstance(); + ::glfwDefaultWindowHints(); ::glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); ::glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); @@ -145,4 +149,33 @@ std::unique_ptr PlaygroundImplVK::AcquireSurfaceFrame( return surface_context_vk->AcquireNextSurface(); } +// Create a global instance of Vulkan in order to prevent unloading of the +// Vulkan library. +// A test suite may repeatedly create and destroy PlaygroundImplVK instances, +// and if the PlaygroundImplVK's Vulkan instance is the only one in the +// process then the Vulkan library will be unloaded when the instance is +// destroyed. Repeated loading and unloading of SwiftShader was leaking +// resources, so this will work around that leak. +// (see https://github.com/flutter/flutter/issues/138028) +void PlaygroundImplVK::InitGlobalVulkanInstance() { + if (global_instance_) { + return; + } + + VULKAN_HPP_DEFAULT_DISPATCHER.init(::glfwGetInstanceProcAddress); + + vk::ApplicationInfo application_info; + application_info.setApplicationVersion(VK_API_VERSION_1_0); + application_info.setApiVersion(VK_API_VERSION_1_1); + application_info.setEngineVersion(VK_API_VERSION_1_0); + application_info.setPEngineName("PlaygroundImplVK"); + application_info.setPApplicationName("PlaygroundImplVK"); + + auto instance_result = + vk::createInstanceUnique(vk::InstanceCreateInfo({}, &application_info)); + FML_CHECK(instance_result.result == vk::Result::eSuccess) + << "Unable to initialize global Vulkan instance"; + global_instance_ = std::move(instance_result.value); +} + } // namespace impeller diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.h b/impeller/playground/backend/vulkan/playground_impl_vk.h index 7c72326f82ea6..0fa614224a42e 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.h +++ b/impeller/playground/backend/vulkan/playground_impl_vk.h @@ -24,6 +24,10 @@ class PlaygroundImplVK final : public PlaygroundImpl { using UniqueHandle = std::unique_ptr; UniqueHandle handle_; + // A global Vulkan instance which ensures that the Vulkan library will remain + // loaded throughout the lifetime of the process. + static vk::UniqueInstance global_instance_; + // |PlaygroundImpl| std::shared_ptr GetContext() const override; @@ -37,6 +41,8 @@ class PlaygroundImplVK final : public PlaygroundImpl { PlaygroundImplVK(const PlaygroundImplVK&) = delete; PlaygroundImplVK& operator=(const PlaygroundImplVK&) = delete; + + static void InitGlobalVulkanInstance(); }; } // namespace impeller