From 0f13702a3e89512432fbb59917880b0859359176 Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Fri, 28 Jul 2023 15:05:07 -0700 Subject: [PATCH] [Impeller] Create a wrapper Impeller context for each Vulkan surface and its swapchain In https://github.com/flutter/engine/pull/41059 the Android context and surface were changed to share one impeller::ContextVK across all instances of AndroidSurfaceVulkanImpeller. However, the ContextVK holds a reference to the current swapchain. If an app uses multiple AndroidSurfaceVulkanImpeller instances (e.g. for platform views), then one surface may overwrite the ContextVK's swapchain while another surface is trying to render. This patch allows each surface to get its own impeller::Context instance holding a swapchain tied to that surface. The per-surface contexts will delegate most operations to the shared parent ContextVK. --- ci/licenses_golden/licenses_flutter | 4 + .../backend/vulkan/playground_impl_vk.cc | 26 +++-- impeller/renderer/backend/vulkan/BUILD.gn | 2 + .../renderer/backend/vulkan/context_vk.cc | 46 +------- impeller/renderer/backend/vulkan/context_vk.h | 10 +- .../backend/vulkan/surface_context_vk.cc | 107 ++++++++++++++++++ .../backend/vulkan/surface_context_vk.h | 70 ++++++++++++ shell/gpu/gpu_surface_vulkan_impeller.cc | 5 +- .../android_surface_vulkan_impeller.cc | 21 ++-- .../android/android_surface_vulkan_impeller.h | 4 +- 10 files changed, 218 insertions(+), 77 deletions(-) create mode 100644 impeller/renderer/backend/vulkan/surface_context_vk.cc create mode 100644 impeller/renderer/backend/vulkan/surface_context_vk.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 6bbe76b177f91..36cc37fc4d535 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1549,6 +1549,8 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/shader_library_vk.cc + ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/shader_library_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/shared_object_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/shared_object_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/surface_context_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/surface_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/surface_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_image_vk.cc + ../../../flutter/LICENSE @@ -4240,6 +4242,8 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/shader_library_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/shader_library_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/shared_object_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/shared_object_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/surface_context_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/surface_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/surface_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_image_vk.cc diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.cc b/impeller/playground/backend/vulkan/playground_impl_vk.cc index 11bfead919442..26ba03bbd2a32 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.cc +++ b/impeller/playground/backend/vulkan/playground_impl_vk.cc @@ -18,6 +18,7 @@ #include "impeller/playground/imgui/vk/imgui_shaders_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" +#include "impeller/renderer/backend/vulkan/surface_context_vk.h" #include "impeller/renderer/backend/vulkan/surface_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" #include "impeller/renderer/vk/compute_shaders_vk.h" @@ -86,27 +87,27 @@ PlaygroundImplVK::PlaygroundImplVK(PlaygroundSwitches switches) context_settings.cache_directory = fml::paths::GetCachesDirectory(); context_settings.enable_validation = switches_.enable_vulkan_validation; - auto context = ContextVK::Create(std::move(context_settings)); - - if (!context || !context->IsValid()) { + auto context_vk = ContextVK::Create(std::move(context_settings)); + if (!context_vk || !context_vk->IsValid()) { VALIDATION_LOG << "Could not create Vulkan context in the playground."; return; } VkSurfaceKHR vk_surface; - auto res = - vk::Result{::glfwCreateWindowSurface(context->GetInstance(), // instance - window, // window - nullptr, // allocator - &vk_surface // surface - )}; + auto res = vk::Result{::glfwCreateWindowSurface( + context_vk->GetInstance(), // instance + window, // window + nullptr, // allocator + &vk_surface // surface + )}; if (res != vk::Result::eSuccess) { VALIDATION_LOG << "Could not create surface for GLFW window: " << vk::to_string(res); return; } - vk::UniqueSurfaceKHR surface{vk_surface, context->GetInstance()}; + vk::UniqueSurfaceKHR surface{vk_surface, context_vk->GetInstance()}; + auto context = context_vk->CreateSurfaceContext(); if (!context->SetWindowSurface(std::move(surface))) { VALIDATION_LOG << "Could not set up surface for context."; return; @@ -130,8 +131,9 @@ PlaygroundImpl::WindowHandle PlaygroundImplVK::GetWindowHandle() const { // |PlaygroundImpl| std::unique_ptr PlaygroundImplVK::AcquireSurfaceFrame( std::shared_ptr context) { - ContextVK* context_vk = reinterpret_cast(context_.get()); - return context_vk->AcquireNextSurface(); + SurfaceContextVK* surface_context_vk = + reinterpret_cast(context_.get()); + return surface_context_vk->AcquireNextSurface(); } } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/BUILD.gn b/impeller/renderer/backend/vulkan/BUILD.gn index 4515720b412e9..c54170f97d530 100644 --- a/impeller/renderer/backend/vulkan/BUILD.gn +++ b/impeller/renderer/backend/vulkan/BUILD.gn @@ -79,6 +79,8 @@ impeller_component("vulkan") { "shader_library_vk.h", "shared_object_vk.cc", "shared_object_vk.h", + "surface_context_vk.cc", + "surface_context_vk.h", "surface_vk.cc", "surface_vk.h", "swapchain_image_vk.cc", diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 8b311333cbfd7..efebc01518aaa 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -30,6 +30,7 @@ #include "impeller/renderer/backend/vulkan/fence_waiter_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/resource_manager_vk.h" +#include "impeller/renderer/backend/vulkan/surface_context_vk.h" #include "impeller/renderer/backend/vulkan/surface_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/capabilities.h" @@ -489,49 +490,8 @@ void ContextVK::Shutdown() { raster_message_loop_->Terminate(); } -std::unique_ptr ContextVK::AcquireNextSurface() { - TRACE_EVENT0("impeller", __FUNCTION__); - auto surface = swapchain_ ? swapchain_->AcquireNextDrawable() : nullptr; - if (surface && pipeline_library_) { - pipeline_library_->DidAcquireSurfaceFrame(); - } - if (allocator_) { - allocator_->DidAcquireSurfaceFrame(); - } - return surface; -} - -#ifdef FML_OS_ANDROID - -vk::UniqueSurfaceKHR ContextVK::CreateAndroidSurface( - ANativeWindow* window) const { - if (!device_holder_->instance) { - return vk::UniqueSurfaceKHR{VK_NULL_HANDLE}; - } - - auto create_info = vk::AndroidSurfaceCreateInfoKHR().setWindow(window); - auto surface_res = - device_holder_->instance->createAndroidSurfaceKHRUnique(create_info); - - if (surface_res.result != vk::Result::eSuccess) { - VALIDATION_LOG << "Could not create Android surface, error: " - << vk::to_string(surface_res.result); - return vk::UniqueSurfaceKHR{VK_NULL_HANDLE}; - } - - return std::move(surface_res.value); -} - -#endif // FML_OS_ANDROID - -bool ContextVK::SetWindowSurface(vk::UniqueSurfaceKHR surface) { - auto swapchain = SwapchainVK::Create(shared_from_this(), std::move(surface)); - if (!swapchain) { - VALIDATION_LOG << "Could not create swapchain."; - return false; - } - swapchain_ = std::move(swapchain); - return true; +std::shared_ptr ContextVK::CreateSurfaceContext() { + return std::make_shared(shared_from_this()); } const std::shared_ptr& ContextVK::GetCapabilities() const { diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 292edd30b9ef6..0891cdf04324b 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -32,6 +32,7 @@ class CommandEncoderVK; class DebugReportVK; class FenceWaiterVK; class ResourceManagerVK; +class SurfaceContextVK; class ContextVK final : public Context, public BackendCast, @@ -127,13 +128,7 @@ class ContextVK final : public Context, const std::shared_ptr GetConcurrentWorkerTaskRunner() const; - [[nodiscard]] bool SetWindowSurface(vk::UniqueSurfaceKHR surface); - - std::unique_ptr AcquireNextSurface(); - -#ifdef FML_OS_ANDROID - vk::UniqueSurfaceKHR CreateAndroidSurface(ANativeWindow* window) const; -#endif // FML_OS_ANDROID + std::shared_ptr CreateSurfaceContext(); const std::shared_ptr& GetGraphicsQueue() const; @@ -164,7 +159,6 @@ class ContextVK final : public Context, std::shared_ptr sampler_library_; std::shared_ptr pipeline_library_; QueuesVK queues_; - std::shared_ptr swapchain_; std::shared_ptr device_capabilities_; std::shared_ptr fence_waiter_; std::shared_ptr resource_manager_; diff --git a/impeller/renderer/backend/vulkan/surface_context_vk.cc b/impeller/renderer/backend/vulkan/surface_context_vk.cc new file mode 100644 index 0000000000000..7f2fdf82003c6 --- /dev/null +++ b/impeller/renderer/backend/vulkan/surface_context_vk.cc @@ -0,0 +1,107 @@ +// 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 "impeller/renderer/backend/vulkan/surface_context_vk.h" + +#include "flutter/fml/trace_event.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain_vk.h" + +namespace impeller { + +SurfaceContextVK::SurfaceContextVK(const std::shared_ptr& parent) + : parent_(parent) {} + +SurfaceContextVK::~SurfaceContextVK() = default; + +Context::BackendType SurfaceContextVK::GetBackendType() const { + return parent_->GetBackendType(); +} + +std::string SurfaceContextVK::DescribeGpuModel() const { + return parent_->DescribeGpuModel(); +} + +bool SurfaceContextVK::IsValid() const { + return parent_->IsValid(); +} + +std::shared_ptr SurfaceContextVK::GetResourceAllocator() const { + return parent_->GetResourceAllocator(); +} + +std::shared_ptr SurfaceContextVK::GetShaderLibrary() const { + return parent_->GetShaderLibrary(); +} + +std::shared_ptr SurfaceContextVK::GetSamplerLibrary() const { + return parent_->GetSamplerLibrary(); +} + +std::shared_ptr SurfaceContextVK::GetPipelineLibrary() const { + return parent_->GetPipelineLibrary(); +} + +std::shared_ptr SurfaceContextVK::CreateCommandBuffer() const { + return parent_->CreateCommandBuffer(); +} + +const std::shared_ptr& SurfaceContextVK::GetCapabilities() + const { + return parent_->GetCapabilities(); +} + +void SurfaceContextVK::Shutdown() { + parent_->Shutdown(); +} + +bool SurfaceContextVK::SetWindowSurface(vk::UniqueSurfaceKHR surface) { + auto swapchain = SwapchainVK::Create(parent_, std::move(surface)); + if (!swapchain) { + VALIDATION_LOG << "Could not create swapchain."; + return false; + } + swapchain_ = std::move(swapchain); + return true; +} + +std::unique_ptr SurfaceContextVK::AcquireNextSurface() { + TRACE_EVENT0("impeller", __FUNCTION__); + auto surface = swapchain_ ? swapchain_->AcquireNextDrawable() : nullptr; + auto pipeline_library = parent_->GetPipelineLibrary(); + if (surface && pipeline_library) { + impeller::PipelineLibraryVK::Cast(*pipeline_library) + .DidAcquireSurfaceFrame(); + } + auto allocator = parent_->GetResourceAllocator(); + if (allocator) { + allocator->DidAcquireSurfaceFrame(); + } + return surface; +} + +#ifdef FML_OS_ANDROID + +vk::UniqueSurfaceKHR SurfaceContextVK::CreateAndroidSurface( + ANativeWindow* window) const { + if (!parent_->GetInstance()) { + return vk::UniqueSurfaceKHR{VK_NULL_HANDLE}; + } + + auto create_info = vk::AndroidSurfaceCreateInfoKHR().setWindow(window); + auto surface_res = + parent_->GetInstance().createAndroidSurfaceKHRUnique(create_info); + + if (surface_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Could not create Android surface, error: " + << vk::to_string(surface_res.result); + return vk::UniqueSurfaceKHR{VK_NULL_HANDLE}; + } + + return std::move(surface_res.value); +} + +#endif // FML_OS_ANDROID + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/surface_context_vk.h b/impeller/renderer/backend/vulkan/surface_context_vk.h new file mode 100644 index 0000000000000..5847d49aa0d47 --- /dev/null +++ b/impeller/renderer/backend/vulkan/surface_context_vk.h @@ -0,0 +1,70 @@ +// 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. + +#pragma once + +#include + +#include "impeller/base/backend_cast.h" +#include "impeller/renderer/backend/vulkan/vk.h" +#include "impeller/renderer/context.h" + +namespace impeller { + +class ContextVK; +class Surface; +class SwapchainVK; + +class SurfaceContextVK : public Context, + public BackendCast { + public: + SurfaceContextVK(const std::shared_ptr& parent); + + // |Context| + ~SurfaceContextVK() override; + + // |Context| + BackendType GetBackendType() const override; + + // |Context| + std::string DescribeGpuModel() const override; + + // |Context| + bool IsValid() const override; + + // |Context| + std::shared_ptr GetResourceAllocator() const override; + + // |Context| + std::shared_ptr GetShaderLibrary() const override; + + // |Context| + std::shared_ptr GetSamplerLibrary() const override; + + // |Context| + std::shared_ptr GetPipelineLibrary() const override; + + // |Context| + std::shared_ptr CreateCommandBuffer() const override; + + // |Context| + const std::shared_ptr& GetCapabilities() const override; + + // |Context| + void Shutdown() override; + + [[nodiscard]] bool SetWindowSurface(vk::UniqueSurfaceKHR surface); + + std::unique_ptr AcquireNextSurface(); + +#ifdef FML_OS_ANDROID + vk::UniqueSurfaceKHR CreateAndroidSurface(ANativeWindow* window) const; +#endif // FML_OS_ANDROID + + private: + std::shared_ptr parent_; + std::shared_ptr swapchain_; +}; + +} // namespace impeller diff --git a/shell/gpu/gpu_surface_vulkan_impeller.cc b/shell/gpu/gpu_surface_vulkan_impeller.cc index 0899131776549..42c5f1d53c61e 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -7,7 +7,8 @@ #include "flutter/fml/make_copyable.h" #include "flutter/impeller/display_list/dl_dispatcher.h" #include "flutter/impeller/renderer/renderer.h" -#include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/surface_context_vk.h" +#include "impeller/renderer/surface.h" namespace flutter { @@ -54,7 +55,7 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( return nullptr; } - auto& context_vk = impeller::ContextVK::Cast(*impeller_context_); + auto& context_vk = impeller::SurfaceContextVK::Cast(*impeller_context_); std::unique_ptr surface = context_vk.AcquireNextSurface(); SurfaceFrame::SubmitCallback submit_callback = diff --git a/shell/platform/android/android_surface_vulkan_impeller.cc b/shell/platform/android/android_surface_vulkan_impeller.cc index e5d2416af90bb..dff8ab73fde73 100644 --- a/shell/platform/android/android_surface_vulkan_impeller.cc +++ b/shell/platform/android/android_surface_vulkan_impeller.cc @@ -17,9 +17,12 @@ namespace flutter { AndroidSurfaceVulkanImpeller::AndroidSurfaceVulkanImpeller( - const std::shared_ptr& android_context) - : android_context_(android_context) { - is_valid_ = android_context_->IsValid(); + const std::shared_ptr& android_context) { + is_valid_ = android_context->IsValid(); + + auto& context_vk = + impeller::ContextVK::Cast(*android_context->GetImpellerContext()); + surface_context_vk_ = context_vk.CreateSurfaceContext(); } AndroidSurfaceVulkanImpeller::~AndroidSurfaceVulkanImpeller() = default; @@ -43,8 +46,7 @@ std::unique_ptr AndroidSurfaceVulkanImpeller::CreateGPUSurface( } std::unique_ptr gpu_surface = - std::make_unique( - android_context_->GetImpellerContext()); + std::make_unique(surface_context_vk_); if (!gpu_surface->IsValid()) { return nullptr; @@ -70,16 +72,15 @@ bool AndroidSurfaceVulkanImpeller::SetNativeWindow( native_window_ = std::move(window); bool success = native_window_ && native_window_->IsValid(); if (success) { - auto& context_vk = - impeller::ContextVK::Cast(*android_context_->GetImpellerContext()); - auto surface = context_vk.CreateAndroidSurface(native_window_->handle()); + auto surface = + surface_context_vk_->CreateAndroidSurface(native_window_->handle()); if (!surface) { FML_LOG(ERROR) << "Could not create a vulkan surface."; return false; } - return context_vk.SetWindowSurface(std::move(surface)); + return surface_context_vk_->SetWindowSurface(std::move(surface)); } native_window_ = nullptr; @@ -88,7 +89,7 @@ bool AndroidSurfaceVulkanImpeller::SetNativeWindow( std::shared_ptr AndroidSurfaceVulkanImpeller::GetImpellerContext() { - return android_context_->GetImpellerContext(); + return surface_context_vk_; } } // namespace flutter diff --git a/shell/platform/android/android_surface_vulkan_impeller.h b/shell/platform/android/android_surface_vulkan_impeller.h index 548a0a5a4cf69..b58f4942e9c48 100644 --- a/shell/platform/android/android_surface_vulkan_impeller.h +++ b/shell/platform/android/android_surface_vulkan_impeller.h @@ -6,7 +6,7 @@ #include "flutter/fml/concurrent_message_loop.h" #include "flutter/fml/macros.h" -#include "flutter/impeller/renderer/context.h" +#include "flutter/impeller/renderer/backend/vulkan/surface_context_vk.h" #include "flutter/shell/platform/android/android_context_vulkan_impeller.h" #include "flutter/shell/platform/android/surface/android_native_window.h" #include "flutter/shell/platform/android/surface/android_surface.h" @@ -46,7 +46,7 @@ class AndroidSurfaceVulkanImpeller : public AndroidSurface { bool SetNativeWindow(fml::RefPtr window) override; private: - std::shared_ptr android_context_; + std::shared_ptr surface_context_vk_; fml::RefPtr native_window_; bool is_valid_ = false;