From d6504f50f5cc63f82944a4f904744aee6dd25357 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 19 Feb 2024 20:34:29 -0800 Subject: [PATCH] [Impeller] Wire up Android Hardware Buffer backed swapchains. * This avoids the use of `VK_KHR_swapchain` and `VK_KHR_surface` for swapchain on Android. * Instead, a pool of Android Hardware Buffers allocated by Impeller is used as swapchain images. * The hardware buffers are presented as contents on surface controls via surface transactions. * The total number of buffers either being used on the client side or in the compositor is capped. * The swapchain caches a certain (configurable) number of buffer on the client side but these can expire. * All swapchain images are lazily allocated. This is different from the KHR swapchains where all swapchain images are eagerly created when the swapchain size is updated. * The number of swapchain images used should generally be less than the KHR swapchain except in cases where there either compositor backpressure (where the client is able to wait on the semaphore till the internal count is reached), and when the backpressure subsides (where there are more recyclables generated but they haven't yet expired). To ameliorate the memory usage in case of the latter, the recyclables count will be less than the total number of allowable images in flight. * The format of the swapchain buffers is always RGBA8888. This may allow for earlier creation of the pipeline state objects since we no longer have to wait for surface acquisition to find the root surface format. * In terms of code organization, the old swapchains have been renamed to `KHRSwapchainVK` while the replacements are called `AHBSwapchainVK`. Corresponding utilities and dependencies have been renamed. * In order to make working with Android handles easier, a new toolkit has been introduced in `//impeller/toolkit/android`. This adds type-safe, reference-counted wrappers around the Android handles with lazy proc table setup. * These new swapchains may only be used on Android API 29 and above. This is the baseline for Impeller Vulkan on Android. So the KHR swapchains should never be used on Android. Instead, non-Android platforms will use this. * There is some recycling of device transient textures in the KHR swapchains that is being reproduced by caching the entire render target in the AHB swapchains. --- ci/licenses_golden/excluded_files | 2 + ci/licenses_golden/licenses_flutter | 64 +++-- impeller/BUILD.gn | 4 + .../backend/gles/playground_impl_gles.cc | 2 +- .../backend/gles/playground_impl_gles.h | 2 +- .../backend/metal/playground_impl_mtl.h | 2 +- .../backend/metal/playground_impl_mtl.mm | 2 +- .../backend/vulkan/playground_impl_vk.cc | 4 +- .../backend/vulkan/playground_impl_vk.h | 2 +- impeller/playground/playground_impl.h | 2 +- .../renderer/backend/gles/surface_gles.cc | 2 +- impeller/renderer/backend/gles/surface_gles.h | 2 +- impeller/renderer/backend/metal/surface_mtl.h | 2 +- .../renderer/backend/metal/surface_mtl.mm | 2 +- impeller/renderer/backend/vulkan/BUILD.gn | 28 ++- .../ahb_texture_source_vk.cc} | 60 +++-- .../ahb_texture_source_vk.h} | 42 ++-- .../backend/vulkan/surface_context_vk.cc | 53 ++-- .../backend/vulkan/surface_context_vk.h | 10 +- impeller/renderer/backend/vulkan/surface_vk.h | 45 ---- .../backend/vulkan/swapchain/ahb/README.md | 4 + .../vulkan/swapchain/ahb/ahb_surface_vk.cc | 87 +++++++ .../vulkan/swapchain/ahb/ahb_surface_vk.h | 46 ++++ .../vulkan/swapchain/ahb/ahb_swapchain_vk.cc | 231 ++++++++++++++++++ .../vulkan/swapchain/ahb/ahb_swapchain_vk.h | 91 +++++++ .../backend/vulkan/swapchain/khr/README.md | 4 + .../khr/khr_surface_vk.cc} | 19 +- .../vulkan/swapchain/khr/khr_surface_vk.h | 45 ++++ .../khr/khr_swapchain_image_vk.cc} | 28 +-- .../khr/khr_swapchain_image_vk.h} | 20 +- .../khr/khr_swapchain_impl_vk.cc} | 61 ++--- .../khr/khr_swapchain_impl_vk.h} | 35 +-- .../vulkan/swapchain/khr/khr_swapchain_vk.cc | 89 +++++++ .../vulkan/swapchain/khr/khr_swapchain_vk.h | 65 +++++ .../renderer/backend/vulkan/swapchain_vk.cc | 78 +----- .../renderer/backend/vulkan/swapchain_vk.h | 74 +++--- .../vulkan/test/swapchain_unittests.cc | 9 +- impeller/renderer/renderer.cc | 2 +- impeller/renderer/renderer.h | 2 +- impeller/renderer/surface.cc | 2 +- impeller/renderer/surface.h | 2 +- impeller/toolkit/android/BUILD.gn | 26 ++ impeller/toolkit/android/hardware_buffer.cc | 100 ++++++++ impeller/toolkit/android/hardware_buffer.h | 98 ++++++++ impeller/toolkit/android/native_window.cc | 34 +++ impeller/toolkit/android/native_window.h | 57 +++++ impeller/toolkit/android/proc_table.cc | 46 ++++ impeller/toolkit/android/proc_table.h | 79 ++++++ impeller/toolkit/android/surface_control.cc | 43 ++++ impeller/toolkit/android/surface_control.h | 80 ++++++ .../toolkit/android/surface_transaction.cc | 99 ++++++++ .../toolkit/android/surface_transaction.h | 125 ++++++++++ shell/gpu/gpu_surface_vulkan_impeller.cc | 18 +- .../android_surface_vulkan_impeller.cc | 19 +- .../android/image_external_texture_vk.cc | 7 +- .../android/image_external_texture_vk.h | 2 +- 56 files changed, 1770 insertions(+), 389 deletions(-) rename impeller/renderer/backend/vulkan/{android_hardware_buffer_texture_source_vk.cc => android/ahb_texture_source_vk.cc} (88%) rename impeller/renderer/backend/vulkan/{android_hardware_buffer_texture_source_vk.h => android/ahb_texture_source_vk.h} (67%) delete mode 100644 impeller/renderer/backend/vulkan/surface_vk.h create mode 100644 impeller/renderer/backend/vulkan/swapchain/ahb/README.md create mode 100644 impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.cc create mode 100644 impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.h create mode 100644 impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc create mode 100644 impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h create mode 100644 impeller/renderer/backend/vulkan/swapchain/khr/README.md rename impeller/renderer/backend/vulkan/{surface_vk.cc => swapchain/khr/khr_surface_vk.cc} (83%) create mode 100644 impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.h rename impeller/renderer/backend/vulkan/{swapchain_image_vk.cc => swapchain/khr/khr_swapchain_image_vk.cc} (59%) rename impeller/renderer/backend/vulkan/{swapchain_image_vk.h => swapchain/khr/khr_swapchain_image_vk.h} (64%) rename impeller/renderer/backend/vulkan/{swapchain_impl_vk.cc => swapchain/khr/khr_swapchain_impl_vk.cc} (89%) rename impeller/renderer/backend/vulkan/{swapchain_impl_vk.h => swapchain/khr/khr_swapchain_impl_vk.h} (67%) create mode 100644 impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.cc create mode 100644 impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h create mode 100644 impeller/toolkit/android/BUILD.gn create mode 100644 impeller/toolkit/android/hardware_buffer.cc create mode 100644 impeller/toolkit/android/hardware_buffer.h create mode 100644 impeller/toolkit/android/native_window.cc create mode 100644 impeller/toolkit/android/native_window.h create mode 100644 impeller/toolkit/android/proc_table.cc create mode 100644 impeller/toolkit/android/proc_table.h create mode 100644 impeller/toolkit/android/surface_control.cc create mode 100644 impeller/toolkit/android/surface_control.h create mode 100644 impeller/toolkit/android/surface_transaction.cc create mode 100644 impeller/toolkit/android/surface_transaction.h diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 9f3dafd9aca8c..5311da160f013 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -177,6 +177,8 @@ ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/render_pass_cache_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/resource_manager_vk_unittests.cc +../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/README.md +../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/README.md ../../../flutter/impeller/renderer/backend/vulkan/test ../../../flutter/impeller/renderer/blit_pass_unittests.cc ../../../flutter/impeller/renderer/capabilities_unittests.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 3d33f51e5d590..46c438f18bdcc 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -35234,8 +35234,8 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.h ORIGIN: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/barrier_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/barrier_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/blit_command_vk.cc + ../../../flutter/LICENSE @@ -35297,12 +35297,18 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/shared_object_vk.cc + 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 -ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_image_vk.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_impl_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/texture_source_vk.cc + ../../../flutter/LICENSE @@ -35445,6 +35451,16 @@ ORIGIN: ../../../flutter/impeller/tessellator/c/tessellator.h + ../../../flutter ORIGIN: ../../../flutter/impeller/tessellator/dart/lib/tessellator.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/tessellator/tessellator.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/tessellator/tessellator.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/toolkit/android/hardware_buffer.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/toolkit/android/hardware_buffer.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/toolkit/android/native_window.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/toolkit/android/native_window.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/toolkit/android/proc_table.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/toolkit/android/proc_table.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/toolkit/android/surface_control.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/toolkit/android/surface_control.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/toolkit/android/surface_transaction.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/toolkit/android/surface_transaction.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/toolkit/egl/config.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/toolkit/egl/config.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/toolkit/egl/context.cc + ../../../flutter/LICENSE @@ -38084,8 +38100,8 @@ FILE: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.h FILE: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.mm FILE: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.h -FILE: ../../../flutter/impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.cc -FILE: ../../../flutter/impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/barrier_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/barrier_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/blit_command_vk.cc @@ -38148,12 +38164,18 @@ 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 -FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_image_vk.h -FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc -FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_impl_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/texture_source_vk.cc @@ -38296,6 +38318,16 @@ FILE: ../../../flutter/impeller/tessellator/c/tessellator.h FILE: ../../../flutter/impeller/tessellator/dart/lib/tessellator.dart FILE: ../../../flutter/impeller/tessellator/tessellator.cc FILE: ../../../flutter/impeller/tessellator/tessellator.h +FILE: ../../../flutter/impeller/toolkit/android/hardware_buffer.cc +FILE: ../../../flutter/impeller/toolkit/android/hardware_buffer.h +FILE: ../../../flutter/impeller/toolkit/android/native_window.cc +FILE: ../../../flutter/impeller/toolkit/android/native_window.h +FILE: ../../../flutter/impeller/toolkit/android/proc_table.cc +FILE: ../../../flutter/impeller/toolkit/android/proc_table.h +FILE: ../../../flutter/impeller/toolkit/android/surface_control.cc +FILE: ../../../flutter/impeller/toolkit/android/surface_control.h +FILE: ../../../flutter/impeller/toolkit/android/surface_transaction.cc +FILE: ../../../flutter/impeller/toolkit/android/surface_transaction.h FILE: ../../../flutter/impeller/toolkit/egl/config.cc FILE: ../../../flutter/impeller/toolkit/egl/config.h FILE: ../../../flutter/impeller/toolkit/egl/context.cc diff --git a/impeller/BUILD.gn b/impeller/BUILD.gn index 79dbd862f1fa3..bd3277cb5ec95 100644 --- a/impeller/BUILD.gn +++ b/impeller/BUILD.gn @@ -42,6 +42,10 @@ config("impeller_public_config") { defines += [ "IMPELLER_TRACE_ALL_GL_CALLS" ] } + if (is_android) { + defines += [ "__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__" ] + } + if (is_win) { defines += [ # TODO(dnfield): https://github.com/flutter/flutter/issues/50053 diff --git a/impeller/playground/backend/gles/playground_impl_gles.cc b/impeller/playground/backend/gles/playground_impl_gles.cc index 4eb970a55a756..82945835a76b0 100644 --- a/impeller/playground/backend/gles/playground_impl_gles.cc +++ b/impeller/playground/backend/gles/playground_impl_gles.cc @@ -165,7 +165,7 @@ PlaygroundImpl::WindowHandle PlaygroundImplGLES::GetWindowHandle() const { } // |PlaygroundImpl| -std::unique_ptr PlaygroundImplGLES::AcquireSurfaceFrame( +std::shared_ptr PlaygroundImplGLES::AcquireSurfaceFrame( std::shared_ptr context) { auto window = reinterpret_cast(GetWindowHandle()); int width = 0; diff --git a/impeller/playground/backend/gles/playground_impl_gles.h b/impeller/playground/backend/gles/playground_impl_gles.h index 21a51fd9ab807..85b99e1a13cb5 100644 --- a/impeller/playground/backend/gles/playground_impl_gles.h +++ b/impeller/playground/backend/gles/playground_impl_gles.h @@ -36,7 +36,7 @@ class PlaygroundImplGLES final : public PlaygroundImpl { WindowHandle GetWindowHandle() const override; // |PlaygroundImpl| - std::unique_ptr AcquireSurfaceFrame( + std::shared_ptr AcquireSurfaceFrame( std::shared_ptr context) override; PlaygroundImplGLES(const PlaygroundImplGLES&) = delete; diff --git a/impeller/playground/backend/metal/playground_impl_mtl.h b/impeller/playground/backend/metal/playground_impl_mtl.h index 9d8698d2857d7..b018852b925c3 100644 --- a/impeller/playground/backend/metal/playground_impl_mtl.h +++ b/impeller/playground/backend/metal/playground_impl_mtl.h @@ -46,7 +46,7 @@ class PlaygroundImplMTL final : public PlaygroundImpl { WindowHandle GetWindowHandle() const override; // |PlaygroundImpl| - std::unique_ptr AcquireSurfaceFrame( + std::shared_ptr AcquireSurfaceFrame( std::shared_ptr context) override; PlaygroundImplMTL(const PlaygroundImplMTL&) = delete; diff --git a/impeller/playground/backend/metal/playground_impl_mtl.mm b/impeller/playground/backend/metal/playground_impl_mtl.mm index 421d6eba3c46b..f13b0f45f03e0 100644 --- a/impeller/playground/backend/metal/playground_impl_mtl.mm +++ b/impeller/playground/backend/metal/playground_impl_mtl.mm @@ -107,7 +107,7 @@ } // |PlaygroundImpl| -std::unique_ptr PlaygroundImplMTL::AcquireSurfaceFrame( +std::shared_ptr PlaygroundImplMTL::AcquireSurfaceFrame( std::shared_ptr context) { if (!data_->metal_layer) { return nullptr; diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.cc b/impeller/playground/backend/vulkan/playground_impl_vk.cc index f980674e2410b..9d3b4b89a7cb2 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.cc +++ b/impeller/playground/backend/vulkan/playground_impl_vk.cc @@ -20,7 +20,7 @@ #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/swapchain/khr/khr_surface_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" #include "impeller/renderer/vk/compute_shaders_vk.h" #include "impeller/scene/shaders/vk/scene_shaders_vk.h" @@ -142,7 +142,7 @@ PlaygroundImpl::WindowHandle PlaygroundImplVK::GetWindowHandle() const { } // |PlaygroundImpl| -std::unique_ptr PlaygroundImplVK::AcquireSurfaceFrame( +std::shared_ptr PlaygroundImplVK::AcquireSurfaceFrame( std::shared_ptr context) { SurfaceContextVK* surface_context_vk = reinterpret_cast(context_.get()); diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.h b/impeller/playground/backend/vulkan/playground_impl_vk.h index 83237b34da64a..e9de32d13d25b 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.h +++ b/impeller/playground/backend/vulkan/playground_impl_vk.h @@ -40,7 +40,7 @@ class PlaygroundImplVK final : public PlaygroundImpl { WindowHandle GetWindowHandle() const override; // |PlaygroundImpl| - std::unique_ptr AcquireSurfaceFrame( + std::shared_ptr AcquireSurfaceFrame( std::shared_ptr context) override; PlaygroundImplVK(const PlaygroundImplVK&) = delete; diff --git a/impeller/playground/playground_impl.h b/impeller/playground/playground_impl.h index 68598d398553d..4ff65751321ff 100644 --- a/impeller/playground/playground_impl.h +++ b/impeller/playground/playground_impl.h @@ -28,7 +28,7 @@ class PlaygroundImpl { virtual std::shared_ptr GetContext() const = 0; - virtual std::unique_ptr AcquireSurfaceFrame( + virtual std::shared_ptr AcquireSurfaceFrame( std::shared_ptr context) = 0; Vector2 GetContentScale() const; diff --git a/impeller/renderer/backend/gles/surface_gles.cc b/impeller/renderer/backend/gles/surface_gles.cc index f32c5131d1fa7..d5eb1e9ef6292 100644 --- a/impeller/renderer/backend/gles/surface_gles.cc +++ b/impeller/renderer/backend/gles/surface_gles.cc @@ -86,7 +86,7 @@ SurfaceGLES::SurfaceGLES(SwapCallback swap_callback, SurfaceGLES::~SurfaceGLES() = default; // |Surface| -bool SurfaceGLES::Present() const { +bool SurfaceGLES::Present() { return swap_callback_ ? swap_callback_() : false; } diff --git a/impeller/renderer/backend/gles/surface_gles.h b/impeller/renderer/backend/gles/surface_gles.h index 1b040598d3994..4af803db7de23 100644 --- a/impeller/renderer/backend/gles/surface_gles.h +++ b/impeller/renderer/backend/gles/surface_gles.h @@ -35,7 +35,7 @@ class SurfaceGLES final : public Surface { SurfaceGLES(SwapCallback swap_callback, const RenderTarget& target_desc); // |Surface| - bool Present() const override; + bool Present() override; SurfaceGLES(const SurfaceGLES&) = delete; diff --git a/impeller/renderer/backend/metal/surface_mtl.h b/impeller/renderer/backend/metal/surface_mtl.h index a933ecff87a36..f328e78db8f0e 100644 --- a/impeller/renderer/backend/metal/surface_mtl.h +++ b/impeller/renderer/backend/metal/surface_mtl.h @@ -60,7 +60,7 @@ class SurfaceMTL final : public Surface { IRect coverage() const; // |Surface| - bool Present() const override; + bool Present() override; private: std::weak_ptr context_; diff --git a/impeller/renderer/backend/metal/surface_mtl.mm b/impeller/renderer/backend/metal/surface_mtl.mm index f23cbfbe13895..0ea52aa1b30a2 100644 --- a/impeller/renderer/backend/metal/surface_mtl.mm +++ b/impeller/renderer/backend/metal/surface_mtl.mm @@ -223,7 +223,7 @@ - (void)flutterPrepareForPresent:(nonnull id)commandBuffer; } // |Surface| -bool SurfaceMTL::Present() const { +bool SurfaceMTL::Present() { auto context = context_.lock(); if (!context) { return false; diff --git a/impeller/renderer/backend/vulkan/BUILD.gn b/impeller/renderer/backend/vulkan/BUILD.gn index 20ee2f02dad44..447a533cf6a63 100644 --- a/impeller/renderer/backend/vulkan/BUILD.gn +++ b/impeller/renderer/backend/vulkan/BUILD.gn @@ -34,8 +34,6 @@ impeller_component("vulkan") { sources = [ "allocator_vk.cc", "allocator_vk.h", - "android_hardware_buffer_texture_source_vk.cc", - "android_hardware_buffer_texture_source_vk.h", "barrier_vk.cc", "barrier_vk.h", "blit_command_vk.cc", @@ -97,12 +95,14 @@ impeller_component("vulkan") { "shared_object_vk.h", "surface_context_vk.cc", "surface_context_vk.h", - "surface_vk.cc", - "surface_vk.h", - "swapchain_image_vk.cc", - "swapchain_image_vk.h", - "swapchain_impl_vk.cc", - "swapchain_impl_vk.h", + "swapchain/khr/khr_surface_vk.cc", + "swapchain/khr/khr_surface_vk.h", + "swapchain/khr/khr_swapchain_image_vk.cc", + "swapchain/khr/khr_swapchain_image_vk.h", + "swapchain/khr/khr_swapchain_impl_vk.cc", + "swapchain/khr/khr_swapchain_impl_vk.h", + "swapchain/khr/khr_swapchain_vk.cc", + "swapchain/khr/khr_swapchain_vk.h", "swapchain_vk.cc", "swapchain_vk.h", "texture_source_vk.cc", @@ -130,4 +130,16 @@ impeller_component("vulkan") { "//flutter/third_party/vulkan-deps/vulkan-headers/src:vulkan_headers", "//third_party/vulkan_memory_allocator", ] + + if (is_android) { + sources += [ + "android/ahb_texture_source_vk.cc", + "android/ahb_texture_source_vk.h", + "swapchain/ahb/ahb_surface_vk.cc", + "swapchain/ahb/ahb_surface_vk.h", + "swapchain/ahb/ahb_swapchain_vk.cc", + "swapchain/ahb/ahb_swapchain_vk.h", + ] + public_deps += [ "../../../toolkit/android" ] + } } diff --git a/impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.cc b/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.cc similarity index 88% rename from impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.cc rename to impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.cc index 0ec9e2725ff02..152db1583abc6 100644 --- a/impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.cc +++ b/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.cc @@ -2,7 +2,7 @@ // 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/android_hardware_buffer_texture_source_vk.h" +#include "impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h" #include @@ -10,8 +10,6 @@ #include "impeller/renderer/backend/vulkan/texture_source_vk.h" #include "impeller/renderer/backend/vulkan/yuv_conversion_library_vk.h" -#ifdef FML_OS_ANDROID - namespace impeller { using AHBProperties = vk::StructureChain< @@ -293,17 +291,18 @@ static TextureDescriptor ToTextureDescriptor( return desc; } -AndroidHardwareBufferTextureSourceVK::AndroidHardwareBufferTextureSourceVK( - const std::shared_ptr& context, - struct AHardwareBuffer* ahb, - const AHardwareBuffer_Desc& ahb_desc) +AHBTextureSourceVK::AHBTextureSourceVK(const std::shared_ptr& context, + struct AHardwareBuffer* ahb, + const AHardwareBuffer_Desc& ahb_desc) : TextureSourceVK(ToTextureDescriptor(ahb_desc)) { if (!context) { VALIDATION_LOG << "Invalid context."; return; } - const auto& device = context->GetDevice(); + const auto& context_vk = ContextVK::Cast(*context); + + const auto& device = context_vk.GetDevice(); AHBProperties ahb_props; @@ -340,7 +339,7 @@ AndroidHardwareBufferTextureSourceVK::AndroidHardwareBufferTextureSourceVK( } // Figure out how to perform YUV conversions. - auto yuv_conversion = CreateYUVConversion(*context, ahb_props); + auto yuv_conversion = CreateYUVConversion(context_vk, ahb_props); if (!yuv_conversion || !yuv_conversion->IsValid()) { return; } @@ -363,50 +362,61 @@ AndroidHardwareBufferTextureSourceVK::AndroidHardwareBufferTextureSourceVK( image_view_ = std::move(image_view); #ifdef IMPELLER_DEBUG - context->SetDebugName(device_memory_.get(), "AHB Device Memory"); - context->SetDebugName(image_.get(), "AHB Image"); - context->SetDebugName(yuv_conversion_->GetConversion(), "AHB YUV Conversion"); - context->SetDebugName(image_view_.get(), "AHB ImageView"); + context_vk.SetDebugName(device_memory_.get(), "AHB Device Memory"); + context_vk.SetDebugName(image_.get(), "AHB Image"); + context_vk.SetDebugName(yuv_conversion_->GetConversion(), + "AHB YUV Conversion"); + context_vk.SetDebugName(image_view_.get(), "AHB ImageView"); #endif // IMPELLER_DEBUG is_valid_ = true; } +AHBTextureSourceVK::AHBTextureSourceVK( + const std::shared_ptr& context, + std::shared_ptr hardware_buffer) + : AHBTextureSourceVK(context, + hardware_buffer->GetHandle(), + hardware_buffer->GetAndroidDescriptor()) { + hardware_buffer_ = std::move(hardware_buffer); + is_valid_ = is_valid_ && hardware_buffer_ && hardware_buffer_->IsValid(); +} + // |TextureSourceVK| -AndroidHardwareBufferTextureSourceVK::~AndroidHardwareBufferTextureSourceVK() = - default; +AHBTextureSourceVK::~AHBTextureSourceVK() = default; -bool AndroidHardwareBufferTextureSourceVK::IsValid() const { +const std::shared_ptr& +AHBTextureSourceVK::GetHardwareBuffer() const { + return hardware_buffer_; +} + +bool AHBTextureSourceVK::IsValid() const { return is_valid_; } // |TextureSourceVK| -vk::Image AndroidHardwareBufferTextureSourceVK::GetImage() const { +vk::Image AHBTextureSourceVK::GetImage() const { return image_.get(); } // |TextureSourceVK| -vk::ImageView AndroidHardwareBufferTextureSourceVK::GetImageView() const { +vk::ImageView AHBTextureSourceVK::GetImageView() const { return image_view_.get(); } // |TextureSourceVK| -vk::ImageView AndroidHardwareBufferTextureSourceVK::GetRenderTargetView() - const { +vk::ImageView AHBTextureSourceVK::GetRenderTargetView() const { return image_view_.get(); } // |TextureSourceVK| -bool AndroidHardwareBufferTextureSourceVK::IsSwapchainImage() const { +bool AHBTextureSourceVK::IsSwapchainImage() const { return false; } // |TextureSourceVK| -std::shared_ptr -AndroidHardwareBufferTextureSourceVK::GetYUVConversion() const { +std::shared_ptr AHBTextureSourceVK::GetYUVConversion() const { return needs_yuv_conversion_ ? yuv_conversion_ : nullptr; } } // namespace impeller - -#endif diff --git a/impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.h b/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h similarity index 67% rename from impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.h rename to impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h index 724308cb2b6fb..ef6176595faa0 100644 --- a/impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.h +++ b/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h @@ -2,23 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_ANDROID_HARDWARE_BUFFER_TEXTURE_SOURCE_VK_H_ -#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_ANDROID_HARDWARE_BUFFER_TEXTURE_SOURCE_VK_H_ +#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_ANDROID_AHB_TEXTURE_SOURCE_VK_H_ +#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_ANDROID_AHB_TEXTURE_SOURCE_VK_H_ -#include "flutter/fml/build_config.h" -#include "vulkan/vulkan_core.h" - -#ifdef FML_OS_ANDROID +#include +#include +#include "flutter/fml/build_config.h" #include "flutter/fml/macros.h" #include "impeller/geometry/size.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/texture_source_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/backend/vulkan/yuv_conversion_vk.h" - -#include -#include +#include "impeller/toolkit/android/hardware_buffer.h" namespace impeller { @@ -36,15 +33,19 @@ class ContextVK; /// descriptors. The objects are meant to be used directly (either /// as render targets or sources for sampling), not copied. /// -class AndroidHardwareBufferTextureSourceVK final : public TextureSourceVK { +class AHBTextureSourceVK final : public TextureSourceVK { public: - AndroidHardwareBufferTextureSourceVK( - const std::shared_ptr& context, - struct AHardwareBuffer* hardware_buffer, - const AHardwareBuffer_Desc& hardware_buffer_desc); + AHBTextureSourceVK(const std::shared_ptr& context, + struct AHardwareBuffer* hardware_buffer, + const AHardwareBuffer_Desc& hardware_buffer_desc); + + AHBTextureSourceVK(const std::shared_ptr& context, + std::shared_ptr buffer); // |TextureSourceVK| - ~AndroidHardwareBufferTextureSourceVK() override; + ~AHBTextureSourceVK() override; + + const std::shared_ptr& GetHardwareBuffer() const; // |TextureSourceVK| vk::Image GetImage() const override; @@ -64,6 +65,7 @@ class AndroidHardwareBufferTextureSourceVK final : public TextureSourceVK { std::shared_ptr GetYUVConversion() const override; private: + std::shared_ptr hardware_buffer_; vk::UniqueDeviceMemory device_memory_; vk::UniqueImage image_; vk::UniqueImageView image_view_; @@ -71,15 +73,11 @@ class AndroidHardwareBufferTextureSourceVK final : public TextureSourceVK { bool needs_yuv_conversion_ = false; bool is_valid_ = false; - AndroidHardwareBufferTextureSourceVK( - const AndroidHardwareBufferTextureSourceVK&) = delete; + AHBTextureSourceVK(const AHBTextureSourceVK&) = delete; - AndroidHardwareBufferTextureSourceVK& operator=( - const AndroidHardwareBufferTextureSourceVK&) = delete; + AHBTextureSourceVK& operator=(const AHBTextureSourceVK&) = delete; }; } // namespace impeller -#endif - -#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_ANDROID_HARDWARE_BUFFER_TEXTURE_SOURCE_VK_H_ +#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_ANDROID_AHB_TEXTURE_SOURCE_VK_H_ diff --git a/impeller/renderer/backend/vulkan/surface_context_vk.cc b/impeller/renderer/backend/vulkan/surface_context_vk.cc index f0a7912433d4b..44fc9d52d05f5 100644 --- a/impeller/renderer/backend/vulkan/surface_context_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_context_vk.cc @@ -4,12 +4,17 @@ #include "impeller/renderer/backend/vulkan/surface_context_vk.h" +#include "flutter/fml/build_config.h" #include "flutter/fml/trace_event.h" #include "impeller/renderer/backend/vulkan/command_pool_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" -#include "impeller/renderer/backend/vulkan/swapchain_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h" #include "impeller/renderer/surface.h" +#if FML_OS_ANDROID +#include "impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h" +#endif // #FML_OS_ANDROID + namespace impeller { SurfaceContextVK::SurfaceContextVK(const std::shared_ptr& parent) @@ -64,7 +69,7 @@ void SurfaceContextVK::Shutdown() { bool SurfaceContextVK::SetWindowSurface(vk::UniqueSurfaceKHR surface, const ISize& size) { - auto swapchain = SwapchainVK::Create(parent_, std::move(surface), size); + auto swapchain = KHRSwapchainVK::Create(parent_, std::move(surface), size); if (!swapchain) { VALIDATION_LOG << "Could not create swapchain."; return false; @@ -77,7 +82,23 @@ bool SurfaceContextVK::SetWindowSurface(vk::UniqueSurfaceKHR surface, return true; } -std::unique_ptr SurfaceContextVK::AcquireNextSurface() { +#ifdef FML_OS_ANDROID + +bool SurfaceContextVK::SetWindowSurface(ANativeWindow* window) { + if (!parent_->GetInstance()) { + return false; + } + auto swapchain = AHBSwapchainVK::Create(parent_, window); + if (!swapchain) { + return false; + } + swapchain_ = std::move(swapchain); + return true; +} + +#endif // FML_OS_ANDROID + +std::shared_ptr SurfaceContextVK::AcquireNextSurface() { TRACE_EVENT0("impeller", __FUNCTION__); auto surface = swapchain_ ? swapchain_->AcquireNextDrawable() : nullptr; if (!surface) { @@ -93,32 +114,12 @@ std::unique_ptr SurfaceContextVK::AcquireNextSurface() { } void SurfaceContextVK::UpdateSurfaceSize(const ISize& size) const { - swapchain_->UpdateSurfaceSize(size); -} - -#ifdef FML_OS_ANDROID - -vk::UniqueSurfaceKHR SurfaceContextVK::CreateAndroidSurface( - ANativeWindow* window) const { - if (!parent_->GetInstance()) { - return vk::UniqueSurfaceKHR{VK_NULL_HANDLE}; + if (!swapchain_) { + return; } - - 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); + swapchain_->UpdateSurfaceSize(size); } -#endif // FML_OS_ANDROID - const vk::Device& SurfaceContextVK::GetDevice() const { return parent_->GetDevice(); } diff --git a/impeller/renderer/backend/vulkan/surface_context_vk.h b/impeller/renderer/backend/vulkan/surface_context_vk.h index 76f691411c7e8..c47bc37e33ca7 100644 --- a/impeller/renderer/backend/vulkan/surface_context_vk.h +++ b/impeller/renderer/backend/vulkan/surface_context_vk.h @@ -72,7 +72,11 @@ class SurfaceContextVK : public Context, [[nodiscard]] bool SetWindowSurface(vk::UniqueSurfaceKHR surface, const ISize& size); - std::unique_ptr AcquireNextSurface(); +#ifdef FML_OS_ANDROID + [[nodiscard]] bool SetWindowSurface(ANativeWindow* window); +#endif // FML_OS_ANDROID + + std::shared_ptr AcquireNextSurface(); /// @brief Mark the current swapchain configuration as dirty, forcing it to be /// recreated on the next frame. @@ -80,10 +84,6 @@ class SurfaceContextVK : public Context, void InitializeCommonlyUsedShadersIfNeeded() const override; -#ifdef FML_OS_ANDROID - vk::UniqueSurfaceKHR CreateAndroidSurface(ANativeWindow* window) const; -#endif // FML_OS_ANDROID - const vk::Device& GetDevice() const; private: diff --git a/impeller/renderer/backend/vulkan/surface_vk.h b/impeller/renderer/backend/vulkan/surface_vk.h deleted file mode 100644 index ea4203135324c..0000000000000 --- a/impeller/renderer/backend/vulkan/surface_vk.h +++ /dev/null @@ -1,45 +0,0 @@ -// 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. - -#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SURFACE_VK_H_ -#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SURFACE_VK_H_ - -#include - -#include "flutter/fml/macros.h" -#include "impeller/renderer/backend/vulkan/context_vk.h" -#include "impeller/renderer/backend/vulkan/swapchain_image_vk.h" -#include "impeller/renderer/surface.h" - -namespace impeller { - -class SurfaceVK final : public Surface { - public: - using SwapCallback = std::function; - - static std::unique_ptr WrapSwapchainImage( - const std::shared_ptr& context, - std::shared_ptr& swapchain_image, - SwapCallback swap_callback, - bool enable_msaa = true); - - // |Surface| - ~SurfaceVK() override; - - private: - SwapCallback swap_callback_; - - SurfaceVK(const RenderTarget& target, SwapCallback swap_callback); - - // |Surface| - bool Present() const override; - - SurfaceVK(const SurfaceVK&) = delete; - - SurfaceVK& operator=(const SurfaceVK&) = delete; -}; - -} // namespace impeller - -#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SURFACE_VK_H_ diff --git a/impeller/renderer/backend/vulkan/swapchain/ahb/README.md b/impeller/renderer/backend/vulkan/swapchain/ahb/README.md new file mode 100644 index 0000000000000..de922c292765c --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain/ahb/README.md @@ -0,0 +1,4 @@ +Android Hardware Buffer Backed Swapchain +======================================== + +Swapchain implementation used on Android API versions above 29. diff --git a/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.cc b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.cc new file mode 100644 index 0000000000000..6f311d8b6d973 --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.cc @@ -0,0 +1,87 @@ +// 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/swapchain/ahb/ahb_surface_vk.h" + +#include "impeller/core/texture.h" +#include "impeller/renderer/backend/vulkan/texture_vk.h" + +namespace impeller { + +std::shared_ptr AHBSurfaceVK::WrapSwapchainImage( + const std::shared_ptr& context, + std::weak_ptr weak_swapchain, + std::shared_ptr swapchain_image) { + if (!swapchain_image || !swapchain_image->IsValid() || !context) { + VALIDATION_LOG << "Invalid swapchain image to wrap."; + return nullptr; + } + + TextureDescriptor msaa_tex_desc; + msaa_tex_desc.storage_mode = StorageMode::kDeviceTransient; + msaa_tex_desc.type = TextureType::kTexture2DMultisample; + msaa_tex_desc.sample_count = SampleCount::kCount4; + msaa_tex_desc.format = swapchain_image->GetTextureDescriptor().format; + msaa_tex_desc.size = swapchain_image->GetTextureDescriptor().size; + msaa_tex_desc.usage = static_cast(TextureUsage::kRenderTarget); + msaa_tex_desc.compression_type = CompressionType::kLossy; + + auto msaa_tex = context->GetResourceAllocator()->CreateTexture(msaa_tex_desc); + auto resolve_tex = std::make_shared(context, swapchain_image); + + if (!msaa_tex || !resolve_tex) { + return nullptr; + } + + ColorAttachment color0; + color0.clear_color = Color::DarkSlateGray(); + color0.load_action = LoadAction::kClear; + color0.texture = msaa_tex; + color0.resolve_texture = resolve_tex; + color0.store_action = StoreAction::kMultisampleResolve; + + RenderTarget render_target; + render_target.SetColorAttachment(color0, 0u); + + auto surface = std::shared_ptr(new AHBSurfaceVK( + render_target, // + std::move(weak_swapchain), // + std::move(swapchain_image) // + )); + if (!surface->IsValid()) { + VALIDATION_LOG << "Surface for wrapped swapchain image was invalid."; + return nullptr; + } + return surface; +} + +AHBSurfaceVK::AHBSurfaceVK(const RenderTarget& render_target, + std::weak_ptr weak_swapchain, + std::shared_ptr swapchain_image) + : Surface(render_target), + weak_swapchain_(std::move(weak_swapchain)), + swapchain_image_(std::move(swapchain_image)) {} + +AHBSurfaceVK::~AHBSurfaceVK() = default; + +// |Surface| +bool AHBSurfaceVK::Present() { + if (!swapchain_image_) { + VALIDATION_LOG << "Invalid swapchain image."; + return false; + } + auto swapchain = weak_swapchain_.lock(); + if (!swapchain) { + VALIDATION_LOG << "Swapchain died before presentation."; + return false; + } + return swapchain->PresentSurface(shared_from_this()); +} + +const std::shared_ptr& AHBSurfaceVK::GetTextureSource() + const { + return swapchain_image_; +} + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.h b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.h new file mode 100644 index 0000000000000..96e9e94c5bc80 --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.h @@ -0,0 +1,46 @@ +// 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. + +#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_AHB_SURFACE_VK_H_ +#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_AHB_SURFACE_VK_H_ + +#include "impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h" +#include "impeller/renderer/render_target.h" +#include "impeller/renderer/surface.h" + +namespace impeller { + +class AHBSurfaceVK final : public Surface, + public std::enable_shared_from_this { + public: + static std::shared_ptr WrapSwapchainImage( + const std::shared_ptr& context, + std::weak_ptr weak_swapchain, + std::shared_ptr swapchain_image); + + // |Surface| + ~AHBSurfaceVK() override; + + AHBSurfaceVK(const AHBSurfaceVK&) = delete; + + AHBSurfaceVK& operator=(const AHBSurfaceVK&) = delete; + + // |Surface| + bool Present() override; + + const std::shared_ptr& GetTextureSource() const; + + private: + std::weak_ptr weak_swapchain_; + std::shared_ptr swapchain_image_; + + AHBSurfaceVK(const RenderTarget& render_target, + std::weak_ptr weak_swapchain, + std::shared_ptr texture); +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_AHB_SURFACE_VK_H_ diff --git a/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc new file mode 100644 index 0000000000000..63d0a21f3d786 --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc @@ -0,0 +1,231 @@ +// 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/swapchain/ahb/ahb_swapchain_vk.h" + +#include "flutter/fml/closure.h" +#include "flutter/fml/trace_event.h" +#include "impeller/renderer/backend/vulkan/swapchain/ahb/ahb_surface_vk.h" +#include "impeller/toolkit/android/surface_transaction.h" + +namespace impeller { + +static constexpr vk::Format ToVKFormat(android::HardwareBufferFormat format) { + switch (format) { + case android::HardwareBufferFormat::kR8G8B8A8UNormInt: + return vk::Format::eR8G8B8A8Unorm; + } + FML_UNREACHABLE(); +} + +std::shared_ptr AHBSwapchainVK::Create( + const std::shared_ptr& context, + ANativeWindow* window, + size_t max_drawable_count) { + auto swapchain = std::shared_ptr( + new AHBSwapchainVK(context, window, max_drawable_count)); + if (!swapchain->IsValid()) { + VALIDATION_LOG << "Could not create valid AHB swapchain."; + return nullptr; + } + return swapchain; +} + +AHBSwapchainVK::AHBSwapchainVK(const std::shared_ptr& context, + ANativeWindow* window, + size_t max_drawable_count) + : context_(context), + native_window_(std::make_shared(window)), + drawable_count_sema_(max_drawable_count) { + if (!context || !drawable_count_sema_.IsValid()) { + return; + } + + if (!native_window_->IsValid()) { + VALIDATION_LOG << "Invalid window when creating a swapchain."; + return; + } + + auto surface_control = std::make_shared( + native_window_->GetHandle(), "FlutterImpellerVulkan"); + + if (!surface_control->IsValid()) { + VALIDATION_LOG << "Could not create surface control from window."; + return; + } + + desc_ = android::HardwareBufferDescriptor::MakeForSwapchainImage( + native_window_->GetSize()); + + if (!desc_.IsAllocatable()) { + VALIDATION_LOG << "Hardware buffer is not allocatable."; + return; + } + + ContextVK::Cast(*context).SetOffscreenFormat( + ToPixelFormat(ToVKFormat(desc_.format))); + + surface_control_ = std::move(surface_control); + is_valid_ = true; +} + +AHBSwapchainVK::~AHBSwapchainVK() = default; + +// |SwapchainVK| +bool AHBSwapchainVK::IsValid() const { + return is_valid_; +} + +// |SwapchainVK| +vk::Format AHBSwapchainVK::GetSurfaceFormat() const { + Lock lock(mutex_); + return ToVKFormat(desc_.format); +} + +// |SwapchainVK| +void AHBSwapchainVK::UpdateSurfaceSize(const ISize& size) { + TRACE_EVENT0("impeller", __FUNCTION__); + + Lock lock(mutex_); + + if (desc_.size == size) { + return; + } + + auto new_desc = desc_; + new_desc.size = size; + if (!new_desc.IsAllocatable()) { + VALIDATION_LOG << "New surface size is not allocatable."; + return; + } + + desc_ = new_desc; +} + +std::shared_ptr AHBSwapchainVK::CreateNewSurface() { + TRACE_EVENT0("impeller", __FUNCTION__); + + auto ahb = std::make_unique(desc_); + if (!ahb || !ahb->IsValid()) { + VALIDATION_LOG << "Could not create hardware buffer."; + return nullptr; + } + auto context = context_.lock(); + if (!context) { + VALIDATION_LOG << "Context died during image acquisition."; + return nullptr; + } + auto texture = std::make_shared(context, std::move(ahb)); + if (!texture->IsValid()) { + VALIDATION_LOG << "Could not wrap hardware buffer into a texture."; + return nullptr; + } + auto surface = AHBSurfaceVK::WrapSwapchainImage(context, weak_from_this(), + std::move(texture)); + if (!surface->IsValid()) { + VALIDATION_LOG << "Could not create surface with wrapped texture."; + return nullptr; + } + return surface; +} + +// |SwapchainVK| +std::shared_ptr AHBSwapchainVK::AcquireNextDrawable() { + TRACE_EVENT0("impeller", __FUNCTION__); + + { + TRACE_EVENT0("impeller", "CompositorBackpressure"); + // Accompanying signal is in the call to recycle the surface after the + // compositor is done using it. + if (!drawable_count_sema_.Wait()) { + VALIDATION_LOG << "Failed waiting for drawable acquisition."; + return nullptr; + } + } + + Lock lock(mutex_); + + if (auto surface = PopRecyclable()) { + FML_LOG(IMPORTANT) << "Recycled surface."; + return surface; + } + + if (auto surface = CreateNewSurface()) { + FML_LOG(IMPORTANT) << "Created surface."; + return surface; + } + + return nullptr; +} + +bool AHBSwapchainVK::PresentSurface( + const std::shared_ptr& surface) { + // We must signal the drawables semaphore in all cases. Otherwise, new + // drawable acquisitions may wait forever. In case we fail before the + // compositor even attempts to use the surface, recycle it. + fml::ScopedCleanupClosure recycle_on_fail( + [&]() { OnSurfaceDidCompleteBeingUsedByCompositor(surface); }); + + if (!surface) { + return false; + } + + auto texture = surface->GetTextureSource(); + + if (!texture || !IsValid()) { + VALIDATION_LOG << "Invalid texture to present."; + return false; + } + + android::SurfaceTransaction transaction; + if (!transaction.SetContents(surface_control_.get(), + texture->GetHardwareBuffer().get())) { + VALIDATION_LOG << "Could not set surface contents."; + return false; + } + + if (!transaction.Apply([surface, weak = weak_from_this()]() { + auto thiz = weak.lock(); + if (!thiz) { + return; + } + thiz->OnSurfaceDidCompleteBeingUsedByCompositor(surface); + })) { + VALIDATION_LOG << "Could not apply surface transaction."; + return false; + } + + // The compositor owns our surface now and will recycle the texture in the + // completion callback. + recycle_on_fail.Release(); + return true; +} + +void AHBSwapchainVK::OnSurfaceDidCompleteBeingUsedByCompositor( + const std::shared_ptr& surface) { + { + Lock lock(mutex_); + PushRecyclable(surface); + } + drawable_count_sema_.Signal(); +} + +void AHBSwapchainVK::PushRecyclable( + const std::shared_ptr& surface) { + // recyclable_.push_back(Recyclable{std::move(surface)}); + // FML_LOG(IMPORTANT) << "There are " << recyclable_.size() << " + // recyclables."; +} + +std::shared_ptr AHBSwapchainVK::PopRecyclable() { + return nullptr; + // if (recyclable_.empty()) { + // return nullptr; + // } + // auto surface = recyclable_.back().surface; + // recyclable_.pop_back(); + // return surface; +} + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h new file mode 100644 index 0000000000000..e4e40f913a080 --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h @@ -0,0 +1,91 @@ +// 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. + +#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_AHB_SWAPCHAIN_VK_H_ +#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_AHB_SWAPCHAIN_VK_H_ + +#include +#include + +#include "flutter/fml/synchronization/semaphore.h" +#include "impeller/base/thread.h" +#include "impeller/base/timing.h" +#include "impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain_vk.h" +#include "impeller/renderer/backend/vulkan/texture_vk.h" +#include "impeller/toolkit/android/hardware_buffer.h" +#include "impeller/toolkit/android/native_window.h" +#include "impeller/toolkit/android/surface_control.h" + +namespace impeller { + +class AHBSurfaceVK; + +class AHBSwapchainVK final + : public SwapchainVK, + public std::enable_shared_from_this { + public: + static std::shared_ptr Create( + const std::shared_ptr& context, + ANativeWindow* window, + size_t max_drawable_count = 3u); + + // |SwapchainVK| + ~AHBSwapchainVK() override; + + AHBSwapchainVK(const AHBSwapchainVK&) = delete; + + AHBSwapchainVK& operator=(const AHBSwapchainVK&) = delete; + + // |SwapchainVK| + bool IsValid() const override; + + // |SwapchainVK| + vk::Format GetSurfaceFormat() const override; + + // |SwapchainVK| + std::shared_ptr AcquireNextDrawable() override; + + // |SwapchainVK| + void UpdateSurfaceSize(const ISize& size) override; + + bool PresentSurface(const std::shared_ptr& surface); + + private: + struct Recyclable { + TimePoint last_use; + std::shared_ptr surface; + + explicit Recyclable(std::shared_ptr p_surface) + : last_use(Clock::now()), surface(std::move(p_surface)) {} + }; + + std::weak_ptr context_; + std::shared_ptr native_window_; + std::shared_ptr surface_control_; + fml::Semaphore drawable_count_sema_; + mutable Mutex mutex_; + android::HardwareBufferDescriptor desc_ IPLR_GUARDED_BY(mutex_); + std::deque recyclable_ IPLR_GUARDED_BY(mutex_); + bool is_valid_ = false; + + AHBSwapchainVK(const std::shared_ptr& context, + ANativeWindow* window, + size_t max_drawable_count); + + void OnSurfaceDidCompleteBeingUsedByCompositor( + const std::shared_ptr& surface); + + std::shared_ptr CreateNewSurface() IPLR_REQUIRES(mutex_); + + void PushRecyclable(const std::shared_ptr& surface) + IPLR_REQUIRES(mutex_); + + std::shared_ptr PopRecyclable() IPLR_REQUIRES(mutex_); +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_AHB_SWAPCHAIN_VK_H_ diff --git a/impeller/renderer/backend/vulkan/swapchain/khr/README.md b/impeller/renderer/backend/vulkan/swapchain/khr/README.md new file mode 100644 index 0000000000000..d9fa22bf7cd93 --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain/khr/README.md @@ -0,0 +1,4 @@ +VK_KHR_surface based Swapchain +============================== + +Used on all platforms [except Android](../ahb/README.md). diff --git a/impeller/renderer/backend/vulkan/surface_vk.cc b/impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.cc similarity index 83% rename from impeller/renderer/backend/vulkan/surface_vk.cc rename to impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.cc index c5700a7783949..0dc8ce841d2e5 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.cc @@ -2,18 +2,18 @@ // 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_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.h" #include "impeller/core/formats.h" -#include "impeller/renderer/backend/vulkan/swapchain_image_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" #include "impeller/renderer/surface.h" namespace impeller { -std::unique_ptr SurfaceVK::WrapSwapchainImage( +std::unique_ptr KHRSurfaceVK::WrapSwapchainImage( const std::shared_ptr& context, - std::shared_ptr& swapchain_image, + std::shared_ptr& swapchain_image, SwapCallback swap_callback, bool enable_msaa) { if (!context || !swapchain_image || !swap_callback) { @@ -79,16 +79,17 @@ std::unique_ptr SurfaceVK::WrapSwapchainImage( render_target_desc.SetColorAttachment(color0, 0u); // The constructor is private. So make_unique may not be used. - return std::unique_ptr( - new SurfaceVK(render_target_desc, std::move(swap_callback))); + return std::unique_ptr( + new KHRSurfaceVK(render_target_desc, std::move(swap_callback))); } -SurfaceVK::SurfaceVK(const RenderTarget& target, SwapCallback swap_callback) +KHRSurfaceVK::KHRSurfaceVK(const RenderTarget& target, + SwapCallback swap_callback) : Surface(target), swap_callback_(std::move(swap_callback)) {} -SurfaceVK::~SurfaceVK() = default; +KHRSurfaceVK::~KHRSurfaceVK() = default; -bool SurfaceVK::Present() const { +bool KHRSurfaceVK::Present() { return swap_callback_ ? swap_callback_() : false; } diff --git a/impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.h b/impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.h new file mode 100644 index 0000000000000..3b9398458ef05 --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.h @@ -0,0 +1,45 @@ +// 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. + +#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SURFACE_VK_H_ +#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SURFACE_VK_H_ + +#include + +#include "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h" +#include "impeller/renderer/surface.h" + +namespace impeller { + +class KHRSurfaceVK final : public Surface { + public: + using SwapCallback = std::function; + + static std::unique_ptr WrapSwapchainImage( + const std::shared_ptr& context, + std::shared_ptr& swapchain_image, + SwapCallback swap_callback, + bool enable_msaa = true); + + // |Surface| + ~KHRSurfaceVK() override; + + private: + SwapCallback swap_callback_; + + KHRSurfaceVK(const RenderTarget& target, SwapCallback swap_callback); + + // |Surface| + bool Present() override; + + KHRSurfaceVK(const KHRSurfaceVK&) = delete; + + KHRSurfaceVK& operator=(const KHRSurfaceVK&) = delete; +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SURFACE_VK_H_ diff --git a/impeller/renderer/backend/vulkan/swapchain_image_vk.cc b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.cc similarity index 59% rename from impeller/renderer/backend/vulkan/swapchain_image_vk.cc rename to impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.cc index c6fc383a4c2e9..a537138a359bd 100644 --- a/impeller/renderer/backend/vulkan/swapchain_image_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.cc @@ -2,13 +2,13 @@ // 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/swapchain_image_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h" namespace impeller { -SwapchainImageVK::SwapchainImageVK(TextureDescriptor desc, - const vk::Device& device, - vk::Image image) +KHRSwapchainImageVK::KHRSwapchainImageVK(TextureDescriptor desc, + const vk::Device& device, + vk::Image image) : TextureSourceVK(desc), image_(image) { vk::ImageViewCreateInfo view_info; view_info.image = image_; @@ -29,44 +29,44 @@ SwapchainImageVK::SwapchainImageVK(TextureDescriptor desc, is_valid_ = true; } -SwapchainImageVK::~SwapchainImageVK() = default; +KHRSwapchainImageVK::~KHRSwapchainImageVK() = default; -bool SwapchainImageVK::IsValid() const { +bool KHRSwapchainImageVK::IsValid() const { return is_valid_; } -std::shared_ptr SwapchainImageVK::GetMSAATexture() const { +std::shared_ptr KHRSwapchainImageVK::GetMSAATexture() const { return msaa_tex_; } -bool SwapchainImageVK::HasMSAATexture() const { +bool KHRSwapchainImageVK::HasMSAATexture() const { return msaa_tex_ != nullptr; } -void SwapchainImageVK::SetMSAATexture(std::shared_ptr msaa_tex) { +void KHRSwapchainImageVK::SetMSAATexture(std::shared_ptr msaa_tex) { msaa_tex_ = std::move(msaa_tex); } -PixelFormat SwapchainImageVK::GetPixelFormat() const { +PixelFormat KHRSwapchainImageVK::GetPixelFormat() const { return desc_.format; } -ISize SwapchainImageVK::GetSize() const { +ISize KHRSwapchainImageVK::GetSize() const { return desc_.size; } // |TextureSourceVK| -vk::Image SwapchainImageVK::GetImage() const { +vk::Image KHRSwapchainImageVK::GetImage() const { return image_; } // |TextureSourceVK| -vk::ImageView SwapchainImageVK::GetImageView() const { +vk::ImageView KHRSwapchainImageVK::GetImageView() const { return image_view_.get(); } // |TextureSourceVK| -vk::ImageView SwapchainImageVK::GetRenderTargetView() const { +vk::ImageView KHRSwapchainImageVK::GetRenderTargetView() const { return image_view_.get(); } diff --git a/impeller/renderer/backend/vulkan/swapchain_image_vk.h b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h similarity index 64% rename from impeller/renderer/backend/vulkan/swapchain_image_vk.h rename to impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h index 48673ebe4845d..f0db0bf352a3c 100644 --- a/impeller/renderer/backend/vulkan/swapchain_image_vk.h +++ b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_IMAGE_VK_H_ -#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_IMAGE_VK_H_ +#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SWAPCHAIN_IMAGE_VK_H_ +#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SWAPCHAIN_IMAGE_VK_H_ #include "impeller/geometry/size.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" @@ -13,14 +13,14 @@ namespace impeller { -class SwapchainImageVK final : public TextureSourceVK { +class KHRSwapchainImageVK final : public TextureSourceVK { public: - SwapchainImageVK(TextureDescriptor desc, - const vk::Device& device, - vk::Image image); + KHRSwapchainImageVK(TextureDescriptor desc, + const vk::Device& device, + vk::Image image); // |TextureSourceVK| - ~SwapchainImageVK() override; + ~KHRSwapchainImageVK() override; bool IsValid() const; @@ -50,11 +50,11 @@ class SwapchainImageVK final : public TextureSourceVK { std::shared_ptr msaa_tex_; bool is_valid_ = false; - SwapchainImageVK(const SwapchainImageVK&) = delete; + KHRSwapchainImageVK(const KHRSwapchainImageVK&) = delete; - SwapchainImageVK& operator=(const SwapchainImageVK&) = delete; + KHRSwapchainImageVK& operator=(const KHRSwapchainImageVK&) = delete; }; } // namespace impeller -#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_IMAGE_VK_H_ +#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SWAPCHAIN_IMAGE_VK_H_ diff --git a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc similarity index 89% rename from impeller/renderer/backend/vulkan/swapchain_impl_vk.cc rename to impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc index 76411732c004a..fa45c44212f41 100644 --- a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc @@ -2,7 +2,7 @@ // 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/swapchain_impl_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h" #include "fml/synchronization/semaphore.h" #include "impeller/base/validation.h" @@ -11,8 +11,8 @@ #include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/gpu_tracer_vk.h" -#include "impeller/renderer/backend/vulkan/surface_vk.h" -#include "impeller/renderer/backend/vulkan/swapchain_image_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain/khr/khr_surface_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h" #include "impeller/renderer/context.h" #include "vulkan/vulkan_structs.hpp" @@ -115,21 +115,21 @@ static std::optional ChooseAlphaCompositionMode( return std::nullopt; } -std::shared_ptr SwapchainImplVK::Create( +std::shared_ptr KHRSwapchainImplVK::Create( const std::shared_ptr& context, vk::UniqueSurfaceKHR surface, const ISize& size, bool enable_msaa, vk::SwapchainKHR old_swapchain) { - return std::shared_ptr(new SwapchainImplVK( + return std::shared_ptr(new KHRSwapchainImplVK( context, std::move(surface), size, enable_msaa, old_swapchain)); } -SwapchainImplVK::SwapchainImplVK(const std::shared_ptr& context, - vk::UniqueSurfaceKHR surface, - const ISize& size, - bool enable_msaa, - vk::SwapchainKHR old_swapchain) { +KHRSwapchainImplVK::KHRSwapchainImplVK(const std::shared_ptr& context, + vk::UniqueSurfaceKHR surface, + const ISize& size, + bool enable_msaa, + vk::SwapchainKHR old_swapchain) { if (!context) { VALIDATION_LOG << "Cannot create a swapchain without a context."; return; @@ -228,13 +228,13 @@ SwapchainImplVK::SwapchainImplVK(const std::shared_ptr& context, texture_desc.size = ISize::MakeWH(swapchain_info.imageExtent.width, swapchain_info.imageExtent.height); - std::vector> swapchain_images; + std::vector> swapchain_images; for (const auto& image : images) { - auto swapchain_image = - std::make_shared(texture_desc, // texture descriptor - vk_context.GetDevice(), // device - image // image - ); + auto swapchain_image = std::make_shared( + texture_desc, // texture descriptor + vk_context.GetDevice(), // device + image // image + ); if (!swapchain_image->IsValid()) { VALIDATION_LOG << "Could not create swapchain image."; return; @@ -273,19 +273,19 @@ SwapchainImplVK::SwapchainImplVK(const std::shared_ptr& context, is_valid_ = true; } -SwapchainImplVK::~SwapchainImplVK() { +KHRSwapchainImplVK::~KHRSwapchainImplVK() { DestroySwapchain(); } -const ISize& SwapchainImplVK::GetSize() const { +const ISize& KHRSwapchainImplVK::GetSize() const { return size_; } -bool SwapchainImplVK::IsValid() const { +bool KHRSwapchainImplVK::IsValid() const { return is_valid_; } -void SwapchainImplVK::WaitIdle() const { +void KHRSwapchainImplVK::WaitIdle() const { if (auto context = context_.lock()) { [[maybe_unused]] auto result = ContextVK::Cast(*context).GetDevice().waitIdle(); @@ -293,7 +293,7 @@ void SwapchainImplVK::WaitIdle() const { } std::pair -SwapchainImplVK::DestroySwapchain() { +KHRSwapchainImplVK::DestroySwapchain() { WaitIdle(); is_valid_ = false; synchronizers_.clear(); @@ -302,18 +302,18 @@ SwapchainImplVK::DestroySwapchain() { return {std::move(surface_), std::move(swapchain_)}; } -vk::Format SwapchainImplVK::GetSurfaceFormat() const { +vk::Format KHRSwapchainImplVK::GetSurfaceFormat() const { return surface_format_; } -std::shared_ptr SwapchainImplVK::GetContext() const { +std::shared_ptr KHRSwapchainImplVK::GetContext() const { return context_.lock(); } -SwapchainImplVK::AcquireResult SwapchainImplVK::AcquireNextDrawable() { +KHRSwapchainImplVK::AcquireResult KHRSwapchainImplVK::AcquireNextDrawable() { auto context_strong = context_.lock(); if (!context_strong) { - return SwapchainImplVK::AcquireResult{}; + return KHRSwapchainImplVK::AcquireResult{}; } const auto& context = ContextVK::Cast(*context_strong); @@ -327,7 +327,7 @@ SwapchainImplVK::AcquireResult SwapchainImplVK::AcquireNextDrawable() { /// if (!sync->WaitForFence(context.GetDevice())) { VALIDATION_LOG << "Could not wait for fence."; - return SwapchainImplVK::AcquireResult{}; + return KHRSwapchainImplVK::AcquireResult{}; } //---------------------------------------------------------------------------- @@ -358,7 +358,7 @@ SwapchainImplVK::AcquireResult SwapchainImplVK::AcquireNextDrawable() { if (index >= images_.size()) { VALIDATION_LOG << "Swapchain returned an invalid image index."; - return SwapchainImplVK::AcquireResult{}; + return KHRSwapchainImplVK::AcquireResult{}; } /// Record all subsequent cmd buffers as part of the current frame. @@ -366,7 +366,7 @@ SwapchainImplVK::AcquireResult SwapchainImplVK::AcquireNextDrawable() { auto image = images_[index % images_.size()]; uint32_t image_index = index; - return AcquireResult{SurfaceVK::WrapSwapchainImage( + return AcquireResult{KHRSurfaceVK::WrapSwapchainImage( context_strong, // context image, // swapchain image [weak_swapchain = weak_from_this(), image, image_index]() -> bool { @@ -380,8 +380,9 @@ SwapchainImplVK::AcquireResult SwapchainImplVK::AcquireNextDrawable() { )}; } -bool SwapchainImplVK::Present(const std::shared_ptr& image, - uint32_t index) { +bool KHRSwapchainImplVK::Present( + const std::shared_ptr& image, + uint32_t index) { auto context_strong = context_.lock(); if (!context_strong) { return false; diff --git a/impeller/renderer/backend/vulkan/swapchain_impl_vk.h b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h similarity index 67% rename from impeller/renderer/backend/vulkan/swapchain_impl_vk.h rename to impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h index 06f9d37610d52..72c16eaa5b995 100644 --- a/impeller/renderer/backend/vulkan/swapchain_impl_vk.h +++ b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_IMPL_VK_H_ -#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_IMPL_VK_H_ +#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SWAPCHAIN_IMPL_VK_H_ +#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SWAPCHAIN_IMPL_VK_H_ #include #include @@ -16,7 +16,7 @@ namespace impeller { class Context; -class SwapchainImageVK; +class KHRSwapchainImageVK; class Surface; struct FrameSynchronizer; @@ -28,17 +28,17 @@ struct FrameSynchronizer; /// the caller must recreate another instance by optionally /// stealing this implementations guts. /// -class SwapchainImplVK final - : public std::enable_shared_from_this { +class KHRSwapchainImplVK final + : public std::enable_shared_from_this { public: - static std::shared_ptr Create( + static std::shared_ptr Create( const std::shared_ptr& context, vk::UniqueSurfaceKHR surface, const ISize& size, bool enable_msaa = true, vk::SwapchainKHR old_swapchain = VK_NULL_HANDLE); - ~SwapchainImplVK(); + ~KHRSwapchainImplVK(); bool IsValid() const; @@ -68,28 +68,29 @@ class SwapchainImplVK final vk::UniqueSurfaceKHR surface_; vk::Format surface_format_ = vk::Format::eUndefined; vk::UniqueSwapchainKHR swapchain_; - std::vector> images_; + std::vector> images_; std::vector> synchronizers_; size_t current_frame_ = 0u; ISize size_; bool enable_msaa_ = true; bool is_valid_ = false; - SwapchainImplVK(const std::shared_ptr& context, - vk::UniqueSurfaceKHR surface, - const ISize& size, - bool enable_msaa, - vk::SwapchainKHR old_swapchain); + KHRSwapchainImplVK(const std::shared_ptr& context, + vk::UniqueSurfaceKHR surface, + const ISize& size, + bool enable_msaa, + vk::SwapchainKHR old_swapchain); - bool Present(const std::shared_ptr& image, uint32_t index); + bool Present(const std::shared_ptr& image, + uint32_t index); void WaitIdle() const; - SwapchainImplVK(const SwapchainImplVK&) = delete; + KHRSwapchainImplVK(const KHRSwapchainImplVK&) = delete; - SwapchainImplVK& operator=(const SwapchainImplVK&) = delete; + KHRSwapchainImplVK& operator=(const KHRSwapchainImplVK&) = delete; }; } // namespace impeller -#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_IMPL_VK_H_ +#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SWAPCHAIN_IMPL_VK_H_ diff --git a/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.cc b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.cc new file mode 100644 index 0000000000000..a3ec1284786f1 --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.cc @@ -0,0 +1,89 @@ +// 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/swapchain/khr/khr_swapchain_vk.h" + +#include "flutter/fml/trace_event.h" +#include "impeller/base/validation.h" +#include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.h" + +namespace impeller { + +std::shared_ptr KHRSwapchainVK::Create( + const std::shared_ptr& context, + vk::UniqueSurfaceKHR surface, + const ISize& size, + bool enable_msaa) { + auto impl = KHRSwapchainImplVK::Create(context, std::move(surface), size, + enable_msaa); + if (!impl || !impl->IsValid()) { + VALIDATION_LOG << "Failed to create SwapchainVK implementation."; + return nullptr; + } + return std::shared_ptr( + new KHRSwapchainVK(std::move(impl), size, enable_msaa)); +} + +KHRSwapchainVK::KHRSwapchainVK(std::shared_ptr impl, + const ISize& size, + bool enable_msaa) + : impl_(std::move(impl)), size_(size), enable_msaa_(enable_msaa) {} + +KHRSwapchainVK::~KHRSwapchainVK() = default; + +bool KHRSwapchainVK::IsValid() const { + return impl_ ? impl_->IsValid() : false; +} + +void KHRSwapchainVK::UpdateSurfaceSize(const ISize& size) { + // Update the size of the swapchain. On the next acquired drawable, + // the sizes may no longer match, forcing the swapchain to be recreated. + size_ = size; +} + +std::shared_ptr KHRSwapchainVK::AcquireNextDrawable() { + if (!IsValid()) { + return nullptr; + } + + TRACE_EVENT0("impeller", __FUNCTION__); + + auto result = impl_->AcquireNextDrawable(); + if (!result.out_of_date && size_ == impl_->GetSize()) { + return std::move(result.surface); + } + + TRACE_EVENT0("impeller", "RecreateSwapchain"); + + // This swapchain implementation indicates that it is out of date. Tear it + // down and make a new one. + auto context = impl_->GetContext(); + auto [surface, old_swapchain] = impl_->DestroySwapchain(); + + auto new_impl = KHRSwapchainImplVK::Create(context, // + std::move(surface), // + size_, // + enable_msaa_, // + *old_swapchain // + ); + if (!new_impl || !new_impl->IsValid()) { + VALIDATION_LOG << "Could not update swapchain."; + // The old swapchain is dead because we took its surface. This is + // unrecoverable. + impl_.reset(); + return nullptr; + } + impl_ = std::move(new_impl); + + //---------------------------------------------------------------------------- + /// We managed to recreate the swapchain in the new configuration. Try again. + /// + return AcquireNextDrawable(); +} + +vk::Format KHRSwapchainVK::GetSurfaceFormat() const { + return IsValid() ? impl_->GetSurfaceFormat() : vk::Format::eUndefined; +} + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h new file mode 100644 index 0000000000000..0d7031aca6489 --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h @@ -0,0 +1,65 @@ +// 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. + +#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SWAPCHAIN_VK_H_ +#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SWAPCHAIN_VK_H_ + +#include + +#include "impeller/geometry/size.h" +#include "impeller/renderer/backend/vulkan/swapchain_vk.h" +#include "impeller/renderer/backend/vulkan/vk.h" +#include "impeller/renderer/context.h" +#include "impeller/renderer/surface.h" + +namespace impeller { + +class KHRSwapchainImplVK; + +//------------------------------------------------------------------------------ +/// @brief A swapchain that adapts to the underlying surface going out of +/// date. If the caller cannot acquire the next drawable, it is due +/// to an unrecoverable error and the swapchain must be recreated +/// with a new surface. +/// +class KHRSwapchainVK final : public SwapchainVK { + public: + static std::shared_ptr Create( + const std::shared_ptr& context, + vk::UniqueSurfaceKHR surface, + const ISize& size, + bool enable_msaa = true); + + // |SwapchainVK| + ~KHRSwapchainVK() override; + + // |SwapchainVK| + bool IsValid() const override; + + // |SwapchainVK| + vk::Format GetSurfaceFormat() const override; + + // |SwapchainVK| + std::shared_ptr AcquireNextDrawable() override; + + // |SwapchainVK| + void UpdateSurfaceSize(const ISize& size) override; + + private: + std::shared_ptr impl_; + ISize size_; + const bool enable_msaa_; + + KHRSwapchainVK(std::shared_ptr impl, + const ISize& size, + bool enable_msaa); + + KHRSwapchainVK(const KHRSwapchainVK&) = delete; + + KHRSwapchainVK& operator=(const KHRSwapchainVK&) = delete; +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_KHR_KHR_SWAPCHAIN_VK_H_ diff --git a/impeller/renderer/backend/vulkan/swapchain_vk.cc b/impeller/renderer/backend/vulkan/swapchain_vk.cc index 22dc195ebfdb8..2fd945eae9e21 100644 --- a/impeller/renderer/backend/vulkan/swapchain_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain_vk.cc @@ -4,86 +4,10 @@ #include "impeller/renderer/backend/vulkan/swapchain_vk.h" -#include "flutter/fml/trace_event.h" -#include "impeller/base/validation.h" -#include "impeller/renderer/backend/vulkan/swapchain_impl_vk.h" - namespace impeller { -std::shared_ptr SwapchainVK::Create( - const std::shared_ptr& context, - vk::UniqueSurfaceKHR surface, - const ISize& size, - bool enable_msaa) { - auto impl = - SwapchainImplVK::Create(context, std::move(surface), size, enable_msaa); - if (!impl || !impl->IsValid()) { - VALIDATION_LOG << "Failed to create SwapchainVK implementation."; - return nullptr; - } - return std::shared_ptr( - new SwapchainVK(std::move(impl), size, enable_msaa)); -} - -SwapchainVK::SwapchainVK(std::shared_ptr impl, - const ISize& size, - bool enable_msaa) - : impl_(std::move(impl)), size_(size), enable_msaa_(enable_msaa) {} +SwapchainVK::SwapchainVK() = default; SwapchainVK::~SwapchainVK() = default; -bool SwapchainVK::IsValid() const { - return impl_ ? impl_->IsValid() : false; -} - -void SwapchainVK::UpdateSurfaceSize(const ISize& size) { - // Update the size of the swapchain. On the next acquired drawable, - // the sizes may no longer match, forcing the swapchain to be recreated. - size_ = size; -} - -std::unique_ptr SwapchainVK::AcquireNextDrawable() { - if (!IsValid()) { - return nullptr; - } - - TRACE_EVENT0("impeller", __FUNCTION__); - - auto result = impl_->AcquireNextDrawable(); - if (!result.out_of_date && size_ == impl_->GetSize()) { - return std::move(result.surface); - } - - TRACE_EVENT0("impeller", "RecreateSwapchain"); - - // This swapchain implementation indicates that it is out of date. Tear it - // down and make a new one. - auto context = impl_->GetContext(); - auto [surface, old_swapchain] = impl_->DestroySwapchain(); - - auto new_impl = SwapchainImplVK::Create(context, // - std::move(surface), // - size_, // - enable_msaa_, // - *old_swapchain // - ); - if (!new_impl || !new_impl->IsValid()) { - VALIDATION_LOG << "Could not update swapchain."; - // The old swapchain is dead because we took its surface. This is - // unrecoverable. - impl_.reset(); - return nullptr; - } - impl_ = std::move(new_impl); - - //---------------------------------------------------------------------------- - /// We managed to recreate the swapchain in the new configuration. Try again. - /// - return AcquireNextDrawable(); -} - -vk::Format SwapchainVK::GetSurfaceFormat() const { - return IsValid() ? impl_->GetSurfaceFormat() : vk::Format::eUndefined; -} - } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/swapchain_vk.h b/impeller/renderer/backend/vulkan/swapchain_vk.h index 1f02f1cd606dd..1d5074ae947b0 100644 --- a/impeller/renderer/backend/vulkan/swapchain_vk.h +++ b/impeller/renderer/backend/vulkan/swapchain_vk.h @@ -5,55 +5,59 @@ #ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_VK_H_ #define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_VK_H_ -#include - -#include "impeller/geometry/size.h" #include "impeller/renderer/backend/vulkan/vk.h" -#include "impeller/renderer/context.h" #include "impeller/renderer/surface.h" namespace impeller { -class SwapchainImplVK; - //------------------------------------------------------------------------------ -/// @brief A swapchain that adapts to the underlying surface going out of -/// date. If the caller cannot acquire the next drawable, it is due -/// to an unrecoverable error and the swapchain must be recreated -/// with a new surface. +/// @brief A collection of surfaces shared with the system compositor to +/// present images in the windowing system on the target platform. /// class SwapchainVK { public: - static std::shared_ptr Create( - const std::shared_ptr& context, - vk::UniqueSurfaceKHR surface, - const ISize& size, - bool enable_msaa = true); - - ~SwapchainVK(); - - bool IsValid() const; - - std::unique_ptr AcquireNextDrawable(); + SwapchainVK(); - vk::Format GetSurfaceFormat() const; - - /// @brief Mark the current swapchain configuration as dirty, forcing it to be - /// recreated on the next frame. - void UpdateSurfaceSize(const ISize& size); - - private: - std::shared_ptr impl_; - ISize size_; - const bool enable_msaa_; - - SwapchainVK(std::shared_ptr impl, - const ISize& size, - bool enable_msaa); + virtual ~SwapchainVK(); SwapchainVK(const SwapchainVK&) = delete; SwapchainVK& operator=(const SwapchainVK&) = delete; + + //---------------------------------------------------------------------------- + /// @brief If this instance of the swapchain is currently valid or must + /// be discarded. + /// + /// @return True if valid, False otherwise. + /// + virtual bool IsValid() const = 0; + + //---------------------------------------------------------------------------- + /// @brief The format of the images in this swapchain. + /// + /// @return The format. + /// + virtual vk::Format GetSurfaceFormat() const = 0; + + //---------------------------------------------------------------------------- + /// @brief Acquire the next swapchain image as a fully configured surface + /// to draw into. + /// + /// This might be a blocking call as the swapchain may need to + /// wait for the image to become available after the compositor is + /// done using it. + /// + /// @return The next swapchain image. + /// + virtual std::shared_ptr AcquireNextDrawable() = 0; + + //---------------------------------------------------------------------------- + /// @brief Mark the current swapchain configuration as dirty, forcing it + /// to be recreated on the next frame. + /// + /// @param[in] size The new surface size in pixels + /// + virtual void UpdateSurfaceSize(const ISize& size) = 0; }; } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/test/swapchain_unittests.cc b/impeller/renderer/backend/vulkan/test/swapchain_unittests.cc index a78d3187b58df..4b89f01d845d0 100644 --- a/impeller/renderer/backend/vulkan/test/swapchain_unittests.cc +++ b/impeller/renderer/backend/vulkan/test/swapchain_unittests.cc @@ -4,7 +4,7 @@ #include "flutter/testing/testing.h" // IWYU pragma: keep #include "gtest/gtest.h" -#include "impeller/renderer/backend/vulkan/swapchain_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h" #include "impeller/renderer/backend/vulkan/test/mock_vulkan.h" #include "vulkan/vulkan_enums.hpp" @@ -28,7 +28,7 @@ TEST(SwapchainTest, CanCreateSwapchain) { auto surface = CreateSurface(*context); auto swapchain = - SwapchainVK::Create(context, std::move(surface), ISize{1, 1}); + KHRSwapchainVK::Create(context, std::move(surface), ISize{1, 1}); EXPECT_TRUE(swapchain->IsValid()); } @@ -38,8 +38,9 @@ TEST(SwapchainTest, RecreateSwapchainWhenSizeChanges) { auto surface = CreateSurface(*context); SetSwapchainImageSize(ISize{1, 1}); - auto swapchain = SwapchainVK::Create(context, std::move(surface), ISize{1, 1}, - /*enable_msaa=*/false); + auto swapchain = + KHRSwapchainVK::Create(context, std::move(surface), ISize{1, 1}, + /*enable_msaa=*/false); auto image = swapchain->AcquireNextDrawable(); auto expected_size = ISize{1, 1}; EXPECT_EQ(image->GetSize(), expected_size); diff --git a/impeller/renderer/renderer.cc b/impeller/renderer/renderer.cc index abc5dc2b7ce75..0dd2e3d1d4e93 100644 --- a/impeller/renderer/renderer.cc +++ b/impeller/renderer/renderer.cc @@ -30,7 +30,7 @@ bool Renderer::IsValid() const { return is_valid_; } -bool Renderer::Render(std::unique_ptr surface, +bool Renderer::Render(const std::shared_ptr& surface, const RenderCallback& render_callback) const { TRACE_EVENT0("impeller", "Renderer::Render"); if (!IsValid()) { diff --git a/impeller/renderer/renderer.h b/impeller/renderer/renderer.h index 1a07e59dcd02f..0709a21c12cf6 100644 --- a/impeller/renderer/renderer.h +++ b/impeller/renderer/renderer.h @@ -29,7 +29,7 @@ class Renderer { bool IsValid() const; - bool Render(std::unique_ptr surface, + bool Render(const std::shared_ptr& surface, const RenderCallback& callback) const; std::shared_ptr GetContext() const; diff --git a/impeller/renderer/surface.cc b/impeller/renderer/surface.cc index ce38697f4726a..2c6b01015b4e7 100644 --- a/impeller/renderer/surface.cc +++ b/impeller/renderer/surface.cc @@ -34,7 +34,7 @@ const RenderTarget& Surface::GetTargetRenderPassDescriptor() const { return desc_; } -bool Surface::Present() const { +bool Surface::Present() { return false; }; diff --git a/impeller/renderer/surface.h b/impeller/renderer/surface.h index e0e4abe5faa5f..b2e7801cffb53 100644 --- a/impeller/renderer/surface.h +++ b/impeller/renderer/surface.h @@ -29,7 +29,7 @@ class Surface { const RenderTarget& GetTargetRenderPassDescriptor() const; - virtual bool Present() const; + virtual bool Present(); private: RenderTarget desc_; diff --git a/impeller/toolkit/android/BUILD.gn b/impeller/toolkit/android/BUILD.gn new file mode 100644 index 0000000000000..b04f3e6c75504 --- /dev/null +++ b/impeller/toolkit/android/BUILD.gn @@ -0,0 +1,26 @@ +# 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. + +import("../../tools/impeller.gni") + +impeller_component("android") { + sources = [ + "hardware_buffer.cc", + "hardware_buffer.h", + "native_window.cc", + "native_window.h", + "proc_table.cc", + "proc_table.h", + "surface_control.cc", + "surface_control.h", + "surface_transaction.cc", + "surface_transaction.h", + ] + + public_deps = [ + "../../base", + "../../geometry", + "//flutter/fml", + ] +} diff --git a/impeller/toolkit/android/hardware_buffer.cc b/impeller/toolkit/android/hardware_buffer.cc new file mode 100644 index 0000000000000..78f12309c7678 --- /dev/null +++ b/impeller/toolkit/android/hardware_buffer.cc @@ -0,0 +1,100 @@ +// 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/toolkit/android/hardware_buffer.h" + +#include "impeller/base/validation.h" + +namespace impeller::android { + +static AHardwareBuffer_Format ToAHardwareBufferFormat( + HardwareBufferFormat format) { + switch (format) { + case HardwareBufferFormat::kR8G8B8A8UNormInt: + return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; + } + FML_UNREACHABLE(); +} + +static AHardwareBuffer_Desc ToAHardwareBufferDesc( + const HardwareBufferDescriptor& desc) { + AHardwareBuffer_Desc ahb_desc = {}; + ahb_desc.width = desc.size.width; + ahb_desc.height = desc.size.height; + ahb_desc.format = ToAHardwareBufferFormat(desc.format); + ahb_desc.layers = 1u; + if (desc.usage & static_cast( + HardwareBufferUsageFlags::kFrameBufferAttachment)) { + ahb_desc.usage |= AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER; + } + if (desc.usage & static_cast( + HardwareBufferUsageFlags::kCompositorOverlay)) { + ahb_desc.usage |= AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY; + } + if (desc.usage & static_cast( + HardwareBufferUsageFlags::kSampledImage)) { + ahb_desc.usage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; + } + return ahb_desc; +} + +bool HardwareBufferDescriptor::IsAllocatable() const { + const auto desc = ToAHardwareBufferDesc(*this); + return GetProcTable().AHardwareBuffer_isSupported(&desc) != 0u; +} + +HardwareBuffer::HardwareBuffer(HardwareBufferDescriptor descriptor) + : descriptor_(descriptor), + android_descriptor_(ToAHardwareBufferDesc(descriptor_)) { + if (!descriptor_.IsAllocatable()) { + VALIDATION_LOG << "The hardware buffer descriptor is not allocatable."; + return; + } + const auto& proc_table = GetProcTable(); + + AHardwareBuffer* buffer = nullptr; + if (auto result = + proc_table.AHardwareBuffer_allocate(&android_descriptor_, &buffer); + result != 0 || buffer == nullptr) { + VALIDATION_LOG << "Could not allocate hardware buffer. Error: " << result; + return; + } + buffer_.reset(buffer); + is_valid_ = true; +} + +HardwareBuffer::~HardwareBuffer() = default; + +bool HardwareBuffer::IsValid() const { + return is_valid_; +} + +AHardwareBuffer* HardwareBuffer::GetHandle() const { + return buffer_.get(); +} + +HardwareBufferDescriptor HardwareBufferDescriptor::MakeForSwapchainImage( + ISize size) { + HardwareBufferDescriptor desc; + desc.format = HardwareBufferFormat::kR8G8B8A8UNormInt; + // Zero sized hardware buffers cannot be allocated. + desc.size = size.Max(ISize{1u, 1u}); + desc.usage = + static_cast( + HardwareBufferUsageFlags::kFrameBufferAttachment) | + static_cast( + HardwareBufferUsageFlags::kCompositorOverlay) | + static_cast(HardwareBufferUsageFlags::kSampledImage); + return desc; +} + +const HardwareBufferDescriptor& HardwareBuffer::GetDescriptor() const { + return descriptor_; +} + +const AHardwareBuffer_Desc& HardwareBuffer::GetAndroidDescriptor() const { + return android_descriptor_; +} + +} // namespace impeller::android diff --git a/impeller/toolkit/android/hardware_buffer.h b/impeller/toolkit/android/hardware_buffer.h new file mode 100644 index 0000000000000..46d44cf67b344 --- /dev/null +++ b/impeller/toolkit/android/hardware_buffer.h @@ -0,0 +1,98 @@ +// 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. + +#ifndef FLUTTER_IMPELLER_TOOLKIT_ANDROID_HARDWARE_BUFFER_H_ +#define FLUTTER_IMPELLER_TOOLKIT_ANDROID_HARDWARE_BUFFER_H_ + +#include "flutter/fml/unique_object.h" +#include "impeller/geometry/size.h" +#include "impeller/toolkit/android/proc_table.h" + +namespace impeller::android { + +enum class HardwareBufferFormat { + //---------------------------------------------------------------------------- + /// This format is guaranteed to be supported on all versions of Android. + /// + /// Why have many format when one format do trick. + /// + kR8G8B8A8UNormInt, +}; + +using HardwareBufferUsage = uint8_t; + +enum class HardwareBufferUsageFlags : HardwareBufferUsage { + kFrameBufferAttachment = 1u << 0u, + kCompositorOverlay = 1u << 1u, + kSampledImage = 1u << 2u, +}; + +struct HardwareBufferDescriptor { + HardwareBufferFormat format = HardwareBufferFormat::kR8G8B8A8UNormInt; + ISize size; + HardwareBufferUsage usage = 0u; + + static HardwareBufferDescriptor MakeForSwapchainImage(ISize size); + + bool IsAllocatable() const; + + constexpr bool operator==(const HardwareBufferDescriptor& o) const { + return format == o.format && size == o.size && usage == o.usage; + } + + constexpr bool operator!=(const HardwareBufferDescriptor& o) const { + return !(*this == o); + } +}; + +//------------------------------------------------------------------------------ +/// @brief A wrapper for AHardwareBuffer +/// https://developer.android.com/ndk/reference/group/a-hardware-buffer +/// +/// This wrapper creates and owns a handle to a managed hardware +/// buffer. That is, there is no ability to take a reference to an +/// externally created hardware buffer. +/// +/// This wrapper is only available on Android API 29 and above. +/// +class HardwareBuffer { + public: + explicit HardwareBuffer(HardwareBufferDescriptor descriptor); + + ~HardwareBuffer(); + + HardwareBuffer(const HardwareBuffer&) = delete; + + HardwareBuffer& operator=(const HardwareBuffer&) = delete; + + bool IsValid() const; + + AHardwareBuffer* GetHandle() const; + + const HardwareBufferDescriptor& GetDescriptor() const; + + const AHardwareBuffer_Desc& GetAndroidDescriptor() const; + + private: + struct UniqueAHardwareBufferTraits { + static AHardwareBuffer* InvalidValue() { return nullptr; } + + static bool IsValid(AHardwareBuffer* value) { + return value != InvalidValue(); + } + + static void Free(AHardwareBuffer* value) { + GetProcTable().AHardwareBuffer_release(value); + } + }; + + const HardwareBufferDescriptor descriptor_; + const AHardwareBuffer_Desc android_descriptor_; + fml::UniqueObject buffer_; + bool is_valid_ = false; +}; + +} // namespace impeller::android + +#endif // FLUTTER_IMPELLER_TOOLKIT_ANDROID_HARDWARE_BUFFER_H_ diff --git a/impeller/toolkit/android/native_window.cc b/impeller/toolkit/android/native_window.cc new file mode 100644 index 0000000000000..663a482f624a3 --- /dev/null +++ b/impeller/toolkit/android/native_window.cc @@ -0,0 +1,34 @@ +// 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/toolkit/android/native_window.h" + +namespace impeller::android { + +NativeWindow::NativeWindow(ANativeWindow* window) : window_(window) { + if (window_.get()) { + GetProcTable().ANativeWindow_acquire(window_.get()); + } +} + +NativeWindow::~NativeWindow() = default; + +bool NativeWindow::IsValid() const { + return window_.is_valid(); +} + +ISize NativeWindow::GetSize() const { + if (!IsValid()) { + return {}; + } + const int32_t width = ANativeWindow_getWidth(window_.get()); + const int32_t height = ANativeWindow_getHeight(window_.get()); + return ISize::MakeWH(std::max(width, 0), std::max(height, 0)); +} + +ANativeWindow* NativeWindow::GetHandle() const { + return window_.get(); +} + +} // namespace impeller::android diff --git a/impeller/toolkit/android/native_window.h b/impeller/toolkit/android/native_window.h new file mode 100644 index 0000000000000..44b1c648b7580 --- /dev/null +++ b/impeller/toolkit/android/native_window.h @@ -0,0 +1,57 @@ +// 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. + +#ifndef FLUTTER_IMPELLER_TOOLKIT_ANDROID_NATIVE_WINDOW_H_ +#define FLUTTER_IMPELLER_TOOLKIT_ANDROID_NATIVE_WINDOW_H_ + +#include "flutter/fml/unique_object.h" +#include "impeller/geometry/size.h" +#include "impeller/toolkit/android/proc_table.h" + +namespace impeller::android { + +//------------------------------------------------------------------------------ +/// @brief A wrapper for ANativeWindow +/// https://developer.android.com/ndk/reference/group/a-native-window +/// +/// This wrapper is only available on Android. +/// +class NativeWindow { + public: + explicit NativeWindow(ANativeWindow* window); + + ~NativeWindow(); + + NativeWindow(const NativeWindow&) = delete; + + NativeWindow& operator=(const NativeWindow&) = delete; + + bool IsValid() const; + + //---------------------------------------------------------------------------- + /// @return The current of the native window. + /// + ISize GetSize() const; + + ANativeWindow* GetHandle() const; + + private: + struct UniqueANativeWindowTraits { + static ANativeWindow* InvalidValue() { return nullptr; } + + static bool IsValid(ANativeWindow* value) { + return value != InvalidValue(); + } + + static void Free(ANativeWindow* value) { + GetProcTable().ANativeWindow_release(value); + } + }; + + fml::UniqueObject window_; +}; + +} // namespace impeller::android + +#endif // FLUTTER_IMPELLER_TOOLKIT_ANDROID_NATIVE_WINDOW_H_ diff --git a/impeller/toolkit/android/proc_table.cc b/impeller/toolkit/android/proc_table.cc new file mode 100644 index 0000000000000..f56c7100cce10 --- /dev/null +++ b/impeller/toolkit/android/proc_table.cc @@ -0,0 +1,46 @@ +// 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 "flutter/impeller/toolkit/android/proc_table.h" + +#include "impeller/base/validation.h" + +namespace impeller::android { + +const ProcTable& GetProcTable() { + static ProcTable gProcTable; + return gProcTable; +} + +ProcTable::ProcTable() + : lib_android_(fml::NativeLibrary::Create("libandroid.so")) { + if (!lib_android_) { + VALIDATION_LOG << "Could not open libandroid.so"; + return; + } + +#define RESOLVE_PROC(table_member, api) \ + { \ + auto resolved = \ + lib_android_->ResolveFunction( \ + table_member.proc_name); \ + if (!resolved.has_value()) { \ + VALIDATION_LOG << "Could not resolve function: " \ + << table_member.proc_name; \ + return; \ + } \ + table_member.proc = resolved.value(); \ + } + FOR_EACH_ANDROID_PROC(RESOLVE_PROC); +#undef RESOLVE_PROC + is_valid_ = true; +} + +ProcTable::~ProcTable() = default; + +bool ProcTable::IsValid() { + return is_valid_; +} + +} // namespace impeller::android diff --git a/impeller/toolkit/android/proc_table.h b/impeller/toolkit/android/proc_table.h new file mode 100644 index 0000000000000..b64feb8be0c20 --- /dev/null +++ b/impeller/toolkit/android/proc_table.h @@ -0,0 +1,79 @@ +// 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. + +#ifndef FLUTTER_IMPELLER_TOOLKIT_ANDROID_PROC_TABLE_H_ +#define FLUTTER_IMPELLER_TOOLKIT_ANDROID_PROC_TABLE_H_ + +#include +#include + +#include + +#include "flutter/fml/native_library.h" + +namespace impeller::android { + +#define FOR_EACH_ANDROID_PROC(INVOKE) \ + INVOKE(AHardwareBuffer_allocate, 26) \ + INVOKE(AHardwareBuffer_acquire, 26) \ + INVOKE(AHardwareBuffer_release, 26) \ + INVOKE(AHardwareBuffer_isSupported, 29) \ + INVOKE(AHardwareBuffer_describe, 26) \ + INVOKE(ANativeWindow_acquire, 0) \ + INVOKE(ANativeWindow_release, 0) \ + INVOKE(ANativeWindow_getWidth, 0) \ + INVOKE(ANativeWindow_getHeight, 0) \ + INVOKE(ASurfaceControl_createFromWindow, 29) \ + INVOKE(ASurfaceControl_release, 29) \ + INVOKE(ASurfaceTransaction_create, 29) \ + INVOKE(ASurfaceTransaction_delete, 29) \ + INVOKE(ASurfaceTransaction_apply, 29) \ + INVOKE(ASurfaceTransaction_setOnComplete, 29) \ + INVOKE(ASurfaceTransaction_reparent, 29) \ + INVOKE(ASurfaceTransaction_setBuffer, 29) \ + INVOKE(ASurfaceTransaction_setColor, 29) + +template +struct AndroidProc { + using AndroidProcType = T; + + const char* proc_name = nullptr; + + size_t api_availability = 0; + + AndroidProcType* proc = nullptr; + + template + auto operator()(Args&&... args) const { + return proc(std::forward(args)...); + } +}; + +struct ProcTable { +#define DEFINE_PROC(name, api) \ + AndroidProc name = {.proc_name = #name, \ + .api_availability = api}; + FOR_EACH_ANDROID_PROC(DEFINE_PROC); +#undef DEFINE_PROC + + ProcTable(); + + ~ProcTable(); + + ProcTable(const ProcTable&) = delete; + + ProcTable& operator=(const ProcTable&) = delete; + + bool IsValid(); + + private: + fml::RefPtr lib_android_; + bool is_valid_ = false; +}; + +const ProcTable& GetProcTable(); + +} // namespace impeller::android + +#endif // FLUTTER_IMPELLER_TOOLKIT_ANDROID_PROC_TABLE_H_ diff --git a/impeller/toolkit/android/surface_control.cc b/impeller/toolkit/android/surface_control.cc new file mode 100644 index 0000000000000..af173ead8da52 --- /dev/null +++ b/impeller/toolkit/android/surface_control.cc @@ -0,0 +1,43 @@ +// 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/toolkit/android/surface_control.h" + +#include "impeller/base/validation.h" +#include "impeller/toolkit/android/surface_transaction.h" + +namespace impeller::android { + +SurfaceControl::SurfaceControl(ANativeWindow* window, const char* debug_name) + : control_(GetProcTable().ASurfaceControl_createFromWindow( + window, + debug_name == nullptr ? "Impeller Layer" : debug_name)) {} + +SurfaceControl::~SurfaceControl() { + if (!RemoveFromParent()) { + VALIDATION_LOG << "Surface control could not be removed from its parent. " + "Expect a leak."; + } +} + +bool SurfaceControl::IsValid() const { + return control_.is_valid(); +} + +ASurfaceControl* SurfaceControl::GetHandle() const { + return control_.get(); +} + +bool SurfaceControl::RemoveFromParent() const { + if (!IsValid()) { + return false; + } + SurfaceTransaction transaction; + if (!transaction.SetParent(*this, nullptr)) { + return false; + } + return transaction.Apply(); +} + +} // namespace impeller::android diff --git a/impeller/toolkit/android/surface_control.h b/impeller/toolkit/android/surface_control.h new file mode 100644 index 0000000000000..88800260bcff0 --- /dev/null +++ b/impeller/toolkit/android/surface_control.h @@ -0,0 +1,80 @@ +// 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. + +#ifndef FLUTTER_IMPELLER_TOOLKIT_ANDROID_SURFACE_CONTROL_H_ +#define FLUTTER_IMPELLER_TOOLKIT_ANDROID_SURFACE_CONTROL_H_ + +#include "flutter/fml/unique_object.h" +#include "impeller/toolkit/android/proc_table.h" + +namespace impeller::android { + +//------------------------------------------------------------------------------ +/// @brief A wrapper for ASurfaceControl. +/// https://developer.android.com/ndk/reference/group/native-activity#asurfacecontrol +/// +/// Instances of this class represent a node in the hierarchy of +/// surfaces sent to the system compositor for final composition. +/// +/// This wrapper is only available on Android API 29 and above. +/// +class SurfaceControl { + public: + //---------------------------------------------------------------------------- + /// @brief Creates a new surface control and adds it as a child of the + /// given window. + /// + /// @param window The window + /// @param[in] debug_name A debug name. See it using + /// `adb shell dumpsys SurfaceFlinger` along with + /// other control properties. If no debug name is + /// specified, the value "Impeller Layer" is used. + /// + explicit SurfaceControl(ANativeWindow* window, + const char* debug_name = nullptr); + + //---------------------------------------------------------------------------- + /// @brief Removes the surface control from the presentation hierarchy + /// managed by the system compositor and release the client side + /// reference to the control. At this point, it may be collected + /// when the compositor is also done using it. + /// + ~SurfaceControl(); + + SurfaceControl(const SurfaceControl&) = delete; + + SurfaceControl& operator=(const SurfaceControl&) = delete; + + bool IsValid() const; + + ASurfaceControl* GetHandle() const; + + //---------------------------------------------------------------------------- + /// @brief Remove the surface control from the hierarchy of nodes + /// presented by the system compositor. + /// + /// @return `true` If the control will be removed from the hierarchy of + /// nodes presented by the system compositor. + /// + bool RemoveFromParent() const; + + private: + struct UniqueASurfaceControlTraits { + static ASurfaceControl* InvalidValue() { return nullptr; } + + static bool IsValid(ASurfaceControl* value) { + return value != InvalidValue(); + } + + static void Free(ASurfaceControl* value) { + GetProcTable().ASurfaceControl_release(value); + } + }; + + fml::UniqueObject control_; +}; + +} // namespace impeller::android + +#endif // FLUTTER_IMPELLER_TOOLKIT_ANDROID_SURFACE_CONTROL_H_ diff --git a/impeller/toolkit/android/surface_transaction.cc b/impeller/toolkit/android/surface_transaction.cc new file mode 100644 index 0000000000000..e5dcc39ec0108 --- /dev/null +++ b/impeller/toolkit/android/surface_transaction.cc @@ -0,0 +1,99 @@ +// 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 "flutter/impeller/toolkit/android/surface_transaction.h" + +#include "flutter/impeller/toolkit/android/hardware_buffer.h" +#include "flutter/impeller/toolkit/android/surface_control.h" +#include "impeller/base/validation.h" + +namespace impeller::android { + +SurfaceTransaction::SurfaceTransaction() + : transaction_(GetProcTable().ASurfaceTransaction_create()) {} + +SurfaceTransaction::~SurfaceTransaction() = default; + +bool SurfaceTransaction::IsValid() const { + return transaction_.is_valid(); +} + +struct TransactionInFlightData { + SurfaceTransaction::OnCompleteCallback callback; +}; + +bool SurfaceTransaction::Apply(OnCompleteCallback callback) { + if (!IsValid()) { + return false; + } + + if (!callback) { + callback = []() {}; + } + + const auto& proc_table = GetProcTable(); + + auto data = std::make_unique(); + data->callback = callback; + proc_table.ASurfaceTransaction_setOnComplete( + transaction_.get(), // + data.release(), // + [](void* context, ASurfaceTransactionStats* stats) -> void { + auto data = reinterpret_cast(context); + data->callback(); + delete data; + }); + proc_table.ASurfaceTransaction_apply(transaction_.get()); + + // Transactions may not be applied over and over. + transaction_.reset(); + return true; +} + +bool SurfaceTransaction::SetContents(const SurfaceControl* control, + const HardwareBuffer* buffer) { + if (control == nullptr || buffer == nullptr) { + VALIDATION_LOG << "Invalid control or buffer."; + return false; + } + GetProcTable().ASurfaceTransaction_setBuffer(transaction_.get(), // + control->GetHandle(), // + buffer->GetHandle(), // + -1); + return true; +} + +bool SurfaceTransaction::SetBackgroundColor(const SurfaceControl& control, + const Color& color) { + if (!IsValid() || !control.IsValid()) { + return false; + } + GetProcTable().ASurfaceTransaction_setColor(transaction_.get(), // + control.GetHandle(), // + color.red, // + color.green, // + color.blue, // + color.alpha, // + ADATASPACE_SRGB_LINEAR // + ); + return true; +} + +bool SurfaceTransaction::SetParent(const SurfaceControl& control, + const SurfaceControl* new_parent) { + if (!IsValid() || !control.IsValid()) { + return false; + } + if (new_parent && !new_parent->IsValid()) { + return false; + } + GetProcTable().ASurfaceTransaction_reparent( + transaction_.get(), // + control.GetHandle(), // + new_parent == nullptr ? nullptr : new_parent->GetHandle() // + ); + return true; +} + +} // namespace impeller::android diff --git a/impeller/toolkit/android/surface_transaction.h b/impeller/toolkit/android/surface_transaction.h new file mode 100644 index 0000000000000..721e07a7adb3d --- /dev/null +++ b/impeller/toolkit/android/surface_transaction.h @@ -0,0 +1,125 @@ +// 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. + +#ifndef FLUTTER_IMPELLER_TOOLKIT_ANDROID_SURFACE_TRANSACTION_H_ +#define FLUTTER_IMPELLER_TOOLKIT_ANDROID_SURFACE_TRANSACTION_H_ + +#include +#include + +#include "flutter/fml/unique_object.h" +#include "impeller/geometry/color.h" +#include "impeller/toolkit/android/proc_table.h" + +namespace impeller::android { + +class SurfaceControl; +class HardwareBuffer; + +//------------------------------------------------------------------------------ +/// @brief A wrapper for ASurfaceTransaction. +/// https://developer.android.com/ndk/reference/group/native-activity#asurfacetransaction +/// +/// A surface transaction is a collection of updates to the +/// hierarchy of surfaces (represented by `ASurfaceControl` +/// instances) that are applied atomically in the compositor. +/// +/// This wrapper is only available on Android API 29 and above. +/// +class SurfaceTransaction { + public: + SurfaceTransaction(); + + ~SurfaceTransaction(); + + SurfaceTransaction(const SurfaceTransaction&) = delete; + + SurfaceTransaction& operator=(const SurfaceTransaction&) = delete; + + bool IsValid() const; + + //---------------------------------------------------------------------------- + /// @brief Encodes that the updated contents of a surface control are + /// specified by the given hardware buffer. The update will not be + /// committed till the call to `Apply` however. + /// + /// @see `SurfaceTransaction::Apply`. + /// + /// @param[in] control The control + /// @param[in] buffer The hardware buffer + /// + /// @return If the update was encoded in the transaction. + /// + [[nodiscard]] bool SetContents(const SurfaceControl* control, + const HardwareBuffer* buffer); + + //---------------------------------------------------------------------------- + /// @brief Encodes the updated background color of the surface control. + /// The update will not be committed till the call to `Apply` + /// however. + /// + /// @see `SurfaceTransaction::Apply`. + /// + /// @param[in] control The control + /// @param[in] color The color + /// + /// @return `true` if the background control will be set when transaction + /// is applied. + /// + [[nodiscard]] bool SetBackgroundColor(const SurfaceControl& control, + const Color& color); + + using OnCompleteCallback = std::function; + + //---------------------------------------------------------------------------- + /// @brief Applies the updated encoded in the transaction and invokes the + /// callback when the updated are complete. + /// + /// @warning The callback will be invoked on a system managed thread. + /// + /// @note It is fine to immediately destroy the transaction after the + /// call to apply. It is not necessary to wait for transaction + /// completion to collect the transaction handle. + /// + /// @param[in] callback The callback + /// + /// @return `true` if the surface transaction was applied. `true` does not + /// indicate the application was completed however. Only the + /// invocation of the callback denotes transaction completion. + /// + [[nodiscard]] bool Apply(OnCompleteCallback callback = nullptr); + + //---------------------------------------------------------------------------- + /// @brief Set the new parent control of the given control. If the new + /// parent is null, it is removed from the control hierarchy. + /// + /// @param[in] control The control + /// @param[in] new_parent The new parent + /// + /// @return `true` if the control will be re-parented when the transaction + /// is applied. + /// + [[nodiscard]] bool SetParent(const SurfaceControl& control, + const SurfaceControl* new_parent = nullptr); + + private: + struct UniqueASurfaceTransactionTraits { + static ASurfaceTransaction* InvalidValue() { return nullptr; } + + static bool IsValid(ASurfaceTransaction* value) { + return value != InvalidValue(); + } + + static void Free(ASurfaceTransaction* value) { + GetProcTable().ASurfaceTransaction_delete(value); + } + }; + + fml::UniqueObject + transaction_; +}; + +} // namespace impeller::android + +#endif // FLUTTER_IMPELLER_TOOLKIT_ANDROID_SURFACE_TRANSACTION_H_ diff --git a/shell/gpu/gpu_surface_vulkan_impeller.cc b/shell/gpu/gpu_surface_vulkan_impeller.cc index cf2733baab5ea..2620611e1a72e 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -58,7 +58,7 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( } auto& context_vk = impeller::SurfaceContextVK::Cast(*impeller_context_); - std::unique_ptr surface = context_vk.AcquireNextSurface(); + std::shared_ptr surface = context_vk.AcquireNextSurface(); if (!surface) { FML_LOG(ERROR) << "No surface available."; @@ -69,7 +69,7 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( fml::MakeCopyable([renderer = impeller_renderer_, // aiks_context = aiks_context_, // surface = std::move(surface) // - ](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool { + ](SurfaceFrame& surface_frame, DlCanvas* canvas) -> bool { if (!aiks_context) { return false; } @@ -90,13 +90,13 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( auto picture = impeller_dispatcher.EndRecordingAsPicture(); return renderer->Render( - std::move(surface), - fml::MakeCopyable( - [aiks_context, picture = std::move(picture)]( - impeller::RenderTarget& render_target) -> bool { - return aiks_context->Render(picture, render_target, - /*reset_host_buffer=*/true); - })); + surface, fml::MakeCopyable( + [aiks_context, picture = std::move(picture)]( + impeller::RenderTarget& render_target) -> bool { + return aiks_context->Render( + picture, render_target, + /*reset_host_buffer=*/true); + })); }); return std::make_unique( diff --git a/shell/platform/android/android_surface_vulkan_impeller.cc b/shell/platform/android/android_surface_vulkan_impeller.cc index 2082d7fef8489..4a76900bd56ee 100644 --- a/shell/platform/android/android_surface_vulkan_impeller.cc +++ b/shell/platform/android/android_surface_vulkan_impeller.cc @@ -72,22 +72,9 @@ bool AndroidSurfaceVulkanImpeller::ResourceContextClearCurrent() { bool AndroidSurfaceVulkanImpeller::SetNativeWindow( fml::RefPtr window) { native_window_ = std::move(window); - bool success = native_window_ && native_window_->IsValid(); - if (success) { - auto surface = - surface_context_vk_->CreateAndroidSurface(native_window_->handle()); - - if (!surface) { - FML_LOG(ERROR) << "Could not create a vulkan surface."; - return false; - } - auto size = native_window_->GetSize(); - return surface_context_vk_->SetWindowSurface( - std::move(surface), impeller::ISize{size.width(), size.height()}); - } - - native_window_ = nullptr; - return false; + return surface_context_vk_->SetWindowSurface( + (native_window_ && native_window_->IsValid()) ? native_window_->handle() + : nullptr); } std::shared_ptr diff --git a/shell/platform/android/image_external_texture_vk.cc b/shell/platform/android/image_external_texture_vk.cc index 906f4a5ee0561..c8b94fb72d37b 100644 --- a/shell/platform/android/image_external_texture_vk.cc +++ b/shell/platform/android/image_external_texture_vk.cc @@ -6,7 +6,7 @@ #include "flutter/impeller/core/formats.h" #include "flutter/impeller/core/texture_descriptor.h" #include "flutter/impeller/display_list/dl_image_impeller.h" -#include "flutter/impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.h" +#include "flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h" #include "flutter/impeller/renderer/backend/vulkan/command_buffer_vk.h" #include "flutter/impeller/renderer/backend/vulkan/command_encoder_vk.h" #include "flutter/impeller/renderer/backend/vulkan/texture_vk.h" @@ -54,9 +54,8 @@ void ImageExternalTextureVK::ProcessFrame(PaintContext& context, return; } - auto texture_source = - std::make_shared( - impeller_context_, latest_hardware_buffer, hb_desc); + auto texture_source = std::make_shared( + impeller_context_, latest_hardware_buffer, hb_desc); auto texture = std::make_shared(impeller_context_, texture_source); diff --git a/shell/platform/android/image_external_texture_vk.h b/shell/platform/android/image_external_texture_vk.h index e3d240145aacc..e702671fe84b3 100644 --- a/shell/platform/android/image_external_texture_vk.h +++ b/shell/platform/android/image_external_texture_vk.h @@ -9,7 +9,7 @@ #include #include "flutter/shell/platform/android/image_external_texture.h" -#include "flutter/impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.h" +#include "flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h" #include "flutter/impeller/renderer/backend/vulkan/context_vk.h" #include "flutter/impeller/renderer/backend/vulkan/vk.h" #include "flutter/shell/platform/android/android_context_vulkan_impeller.h"