From 3464f717da71bfd5fd67ec03f0dcb042825909de Mon Sep 17 00:00:00 2001 From: "auto-submit[bot]" Date: Fri, 15 Mar 2024 21:34:41 +0000 Subject: [PATCH] Revert "[Impeller] A toolkit for managed handles to Android NDK vended objects. (#51334)" This reverts commit f086ec486044db4062fdab4c8bb46b54250c3d29. --- BUILD.gn | 6 +- ci/builders/linux_android_emulator.json | 2 - .../linux_android_emulator_api_33.json | 1 - ci/builders/linux_android_emulator_skia.json | 1 - ci/licenses_golden/excluded_files | 3 +- ci/licenses_golden/licenses_flutter | 29 +- fml/BUILD.gn | 2 + fml/platform/android/ndk_helpers.cc | 264 ++++++++++++++++++ fml/platform/android/ndk_helpers.h | 100 +++++++ fml/platform/android/ndk_helpers_unittests.cc | 135 +++++++++ impeller/toolkit/android/BUILD.gn | 54 ---- impeller/toolkit/android/README.md | 7 - impeller/toolkit/android/choreographer.cc | 84 ------ impeller/toolkit/android/choreographer.h | 84 ------ impeller/toolkit/android/hardware_buffer.cc | 131 --------- impeller/toolkit/android/hardware_buffer.h | 149 ---------- impeller/toolkit/android/native_window.cc | 34 --- impeller/toolkit/android/native_window.h | 57 ---- impeller/toolkit/android/proc_table.cc | 68 ----- impeller/toolkit/android/proc_table.h | 129 --------- impeller/toolkit/android/surface_control.cc | 55 ---- impeller/toolkit/android/surface_control.h | 86 ------ .../toolkit/android/surface_transaction.cc | 104 ------- .../toolkit/android/surface_transaction.h | 135 --------- .../android/toolkit_android_unittests.cc | 108 ------- shell/platform/android/BUILD.gn | 2 +- shell/platform/android/flutter_main.cc | 5 +- .../android/image_external_texture.cc | 7 +- .../android/image_external_texture_gl.cc | 8 +- .../android/image_external_texture_gl.h | 2 + .../android/image_external_texture_vk.cc | 18 +- shell/platform/android/image_lru.h | 3 +- shell/platform/android/library_loader.cc | 4 + .../android/platform_view_android_jni_impl.cc | 1 + .../platform/android/vsync_waiter_android.cc | 64 +++-- shell/platform/android/vsync_waiter_android.h | 3 + testing/run_tests.py | 13 +- 37 files changed, 577 insertions(+), 1381 deletions(-) create mode 100644 fml/platform/android/ndk_helpers.cc create mode 100644 fml/platform/android/ndk_helpers.h create mode 100644 fml/platform/android/ndk_helpers_unittests.cc delete mode 100644 impeller/toolkit/android/BUILD.gn delete mode 100644 impeller/toolkit/android/README.md delete mode 100644 impeller/toolkit/android/choreographer.cc delete mode 100644 impeller/toolkit/android/choreographer.h delete mode 100644 impeller/toolkit/android/hardware_buffer.cc delete mode 100644 impeller/toolkit/android/hardware_buffer.h delete mode 100644 impeller/toolkit/android/native_window.cc delete mode 100644 impeller/toolkit/android/native_window.h delete mode 100644 impeller/toolkit/android/proc_table.cc delete mode 100644 impeller/toolkit/android/proc_table.h delete mode 100644 impeller/toolkit/android/surface_control.cc delete mode 100644 impeller/toolkit/android/surface_control.h delete mode 100644 impeller/toolkit/android/surface_transaction.cc delete mode 100644 impeller/toolkit/android/surface_transaction.h delete mode 100644 impeller/toolkit/android/toolkit_android_unittests.cc diff --git a/BUILD.gn b/BUILD.gn index 86c63580228e3..d9b7d40b14449 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -167,10 +167,8 @@ group("unittests") { public_deps = [] if (is_android) { - public_deps += [ - "//flutter/impeller/toolkit/android:unittests", - "//flutter/shell/platform/android:flutter_shell_native_unittests", - ] + public_deps += + [ "//flutter/shell/platform/android:flutter_shell_native_unittests" ] } if (is_ios) { diff --git a/ci/builders/linux_android_emulator.json b/ci/builders/linux_android_emulator.json index 2340fe3921b64..918c8e6178b16 100644 --- a/ci/builders/linux_android_emulator.json +++ b/ci/builders/linux_android_emulator.json @@ -29,7 +29,6 @@ "ninja": { "config": "android_emulator_debug_x64", "targets": [ - "flutter/impeller/toolkit/android:unittests", "flutter/shell/platform/android:flutter_shell_native_unittests", "flutter/testing/scenario_app" ] @@ -121,7 +120,6 @@ "ninja": { "config": "android_emulator_debug_x86", "targets": [ - "flutter/impeller/toolkit/android:unittests", "flutter/shell/platform/android:flutter_shell_native_unittests", "flutter/testing/scenario_app" ] diff --git a/ci/builders/linux_android_emulator_api_33.json b/ci/builders/linux_android_emulator_api_33.json index b955dd19e4d6f..dfb70d49ce2d3 100644 --- a/ci/builders/linux_android_emulator_api_33.json +++ b/ci/builders/linux_android_emulator_api_33.json @@ -29,7 +29,6 @@ "ninja": { "config": "android_debug_api33_x64", "targets": [ - "flutter/impeller/toolkit/android:unittests", "flutter/shell/platform/android:flutter_shell_native_unittests", "flutter/testing/scenario_app" ] diff --git a/ci/builders/linux_android_emulator_skia.json b/ci/builders/linux_android_emulator_skia.json index f2a5f97aec2c8..32fcbc96ac174 100644 --- a/ci/builders/linux_android_emulator_skia.json +++ b/ci/builders/linux_android_emulator_skia.json @@ -29,7 +29,6 @@ "ninja": { "config": "android_emulator_skia_debug_x64", "targets": [ - "flutter/impeller/toolkit/android:unittests", "flutter/shell/platform/android:flutter_shell_native_unittests", "flutter/testing/scenario_app" ] diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index c7177d6563a98..8caa6c425f992 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -101,6 +101,7 @@ ../../../flutter/fml/message_loop_task_queues_unittests.cc ../../../flutter/fml/message_loop_unittests.cc ../../../flutter/fml/paths_unittests.cc +../../../flutter/fml/platform/android/ndk_helpers_unittests.cc ../../../flutter/fml/platform/darwin/cf_utils_unittests.mm ../../../flutter/fml/platform/darwin/scoped_nsobject_arc_unittests.mm ../../../flutter/fml/platform/darwin/scoped_nsobject_unittests.mm @@ -199,8 +200,6 @@ ../../../flutter/impeller/tessellator/dart/pubspec.lock ../../../flutter/impeller/tessellator/dart/pubspec.yaml ../../../flutter/impeller/tessellator/tessellator_unittests.cc -../../../flutter/impeller/toolkit/android/README.md -../../../flutter/impeller/toolkit/android/toolkit_android_unittests.cc ../../../flutter/impeller/tools/build_metal_library.py ../../../flutter/impeller/tools/check_licenses.py ../../../flutter/impeller/tools/malioc_cores.py diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 477bd20564f91..c50c6ab586b4b 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -39364,6 +39364,8 @@ ORIGIN: ../../../flutter/fml/platform/android/jni_weak_ref.cc + ../../../flutter ORIGIN: ../../../flutter/fml/platform/android/jni_weak_ref.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/android/message_loop_android.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/android/message_loop_android.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/fml/platform/android/ndk_helpers.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/fml/platform/android/ndk_helpers.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/android/paths_android.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/android/paths_android.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/android/scoped_java_ref.cc + ../../../flutter/LICENSE @@ -40149,18 +40151,6 @@ 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/choreographer.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/toolkit/android/choreographer.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 @@ -40884,7 +40874,6 @@ ORIGIN: ../../../flutter/shell/platform/android/flutter_main.h + ../../../flutte ORIGIN: ../../../flutter/shell/platform/android/image_external_texture.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/image_external_texture_gl.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/image_external_texture_gl.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/android/image_external_texture_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/image_external_texture_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/image_lru.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/image_lru.h + ../../../flutter/LICENSE @@ -42231,6 +42220,8 @@ FILE: ../../../flutter/fml/platform/android/jni_weak_ref.cc FILE: ../../../flutter/fml/platform/android/jni_weak_ref.h FILE: ../../../flutter/fml/platform/android/message_loop_android.cc FILE: ../../../flutter/fml/platform/android/message_loop_android.h +FILE: ../../../flutter/fml/platform/android/ndk_helpers.cc +FILE: ../../../flutter/fml/platform/android/ndk_helpers.h FILE: ../../../flutter/fml/platform/android/paths_android.cc FILE: ../../../flutter/fml/platform/android/paths_android.h FILE: ../../../flutter/fml/platform/android/scoped_java_ref.cc @@ -43017,18 +43008,6 @@ 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/choreographer.cc -FILE: ../../../flutter/impeller/toolkit/android/choreographer.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/fml/BUILD.gn b/fml/BUILD.gn index d2d4a165c7686..9e60ba9f8d9f0 100644 --- a/fml/BUILD.gn +++ b/fml/BUILD.gn @@ -188,6 +188,8 @@ source_set("fml") { "platform/android/jni_weak_ref.h", "platform/android/message_loop_android.cc", "platform/android/message_loop_android.h", + "platform/android/ndk_helpers.cc", + "platform/android/ndk_helpers.h", "platform/android/paths_android.cc", "platform/android/paths_android.h", "platform/android/scoped_java_ref.cc", diff --git a/fml/platform/android/ndk_helpers.cc b/fml/platform/android/ndk_helpers.cc new file mode 100644 index 0000000000000..1fcc49b0146b9 --- /dev/null +++ b/fml/platform/android/ndk_helpers.cc @@ -0,0 +1,264 @@ +// 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 "fml/platform/android/ndk_helpers.h" + +#include "fml/logging.h" +#include "fml/native_library.h" + +#include +#include + +namespace flutter { + +namespace { + +#define DECLARE_TYPES(ret, name, args) \ + typedef ret(*fp_##name) args; \ + ret(*_##name) args = nullptr + +DECLARE_TYPES(int, + AHardwareBuffer_allocate, + (const AHardwareBuffer_Desc* desc, AHardwareBuffer** outBuffer)); +DECLARE_TYPES(int, + AHardwareBuffer_isSupported, + (const AHardwareBuffer_Desc* desc)); +DECLARE_TYPES(AHardwareBuffer*, + AHardwareBuffer_fromHardwareBuffer, + (JNIEnv * env, jobject hardwareBufferObj)); +DECLARE_TYPES(void, AHardwareBuffer_release, (AHardwareBuffer * buffer)); +DECLARE_TYPES(void, + AHardwareBuffer_describe, + (AHardwareBuffer * buffer, AHardwareBuffer_Desc* desc)); +DECLARE_TYPES(int, + AHardwareBuffer_getId, + (AHardwareBuffer * buffer, uint64_t* outId)); + +DECLARE_TYPES(bool, ATrace_isEnabled, (void)); + +DECLARE_TYPES(ASurfaceControl*, + ASurfaceControl_createFromWindow, + (ANativeWindow * parent, const char* debug_name)); +DECLARE_TYPES(void, + ASurfaceControl_release, + (ASurfaceControl * surface_control)); +DECLARE_TYPES(ASurfaceTransaction*, ASurfaceTransaction_create, (void)); +DECLARE_TYPES(void, + ASurfaceTransaction_delete, + (ASurfaceTransaction * surface_transaction)); +DECLARE_TYPES(void, + ASurfaceTransaction_apply, + (ASurfaceTransaction * surface_transaction)); +DECLARE_TYPES(void, + ASurfaceTransaction_setBuffer, + (ASurfaceTransaction * transaction, + ASurfaceControl* surface_control, + AHardwareBuffer* buffer, + int acquire_fence_fd)); + +DECLARE_TYPES(AChoreographer*, AChoreographer_getInstance, (void)); +DECLARE_TYPES(void, + AChoreographer_postFrameCallback, + (AChoreographer * choreographer, + AChoreographer_frameCallback callbackk, + void* data)); +DECLARE_TYPES(void, + AChoreographer_postFrameCallback64, + (AChoreographer * choreographer, + AChoreographer_frameCallback64 callbackk, + void* data)); + +DECLARE_TYPES(EGLClientBuffer, + eglGetNativeClientBufferANDROID, + (AHardwareBuffer * buffer)); + +#undef DECLARE_TYPES + +std::once_flag init_once; + +void InitOnceCallback() { + static fml::RefPtr android = + fml::NativeLibrary::Create("libandroid.so"); + FML_CHECK(android.get() != nullptr); + static fml::RefPtr egl = + fml::NativeLibrary::Create("libEGL.so"); + FML_CHECK(egl.get() != nullptr); + +#define LOOKUP(lib, func) \ + _##func = lib->ResolveFunction(#func).value_or(nullptr) + + LOOKUP(egl, eglGetNativeClientBufferANDROID); + + LOOKUP(android, AHardwareBuffer_fromHardwareBuffer); + LOOKUP(android, AHardwareBuffer_release); + LOOKUP(android, AHardwareBuffer_getId); + LOOKUP(android, AHardwareBuffer_describe); + LOOKUP(android, AHardwareBuffer_allocate); + LOOKUP(android, AHardwareBuffer_isSupported); + LOOKUP(android, ATrace_isEnabled); + LOOKUP(android, AChoreographer_getInstance); + if (_AChoreographer_getInstance) { + LOOKUP(android, AChoreographer_postFrameCallback64); +// See discussion at +// https://github.com/flutter/engine/pull/31859#discussion_r822072987 +// This method is not suitable for Flutter's use cases on 32 bit architectures, +// and we should fall back to the Java based Choreographer. +#if FML_ARCH_CPU_64_BITS + if (!_AChoreographer_postFrameCallback64) { + LOOKUP(android, AChoreographer_postFrameCallback); + } +#endif + } + + LOOKUP(android, ASurfaceControl_createFromWindow); + LOOKUP(android, ASurfaceControl_release); + LOOKUP(android, ASurfaceTransaction_apply); + LOOKUP(android, ASurfaceTransaction_create); + LOOKUP(android, ASurfaceTransaction_delete); + LOOKUP(android, ASurfaceTransaction_setBuffer); +#undef LOOKUP +} + +} // namespace + +void NDKHelpers::Init() { + std::call_once(init_once, InitOnceCallback); +} + +bool NDKHelpers::ATrace_isEnabled() { + if (_ATrace_isEnabled) { + return _ATrace_isEnabled(); + } + return false; +} + +ChoreographerSupportStatus NDKHelpers::ChoreographerSupported() { + if (_AChoreographer_postFrameCallback64) { + return ChoreographerSupportStatus::kSupported64; + } + if (_AChoreographer_postFrameCallback) { + return ChoreographerSupportStatus::kSupported32; + } + return ChoreographerSupportStatus::kUnsupported; +} + +AChoreographer* NDKHelpers::AChoreographer_getInstance() { + FML_CHECK(_AChoreographer_getInstance); + return _AChoreographer_getInstance(); +} + +void NDKHelpers::AChoreographer_postFrameCallback( + AChoreographer* choreographer, + AChoreographer_frameCallback callback, + void* data) { + FML_CHECK(_AChoreographer_postFrameCallback); + return _AChoreographer_postFrameCallback(choreographer, callback, data); +} + +void NDKHelpers::AChoreographer_postFrameCallback64( + AChoreographer* choreographer, + AChoreographer_frameCallback64 callback, + void* data) { + FML_CHECK(_AChoreographer_postFrameCallback64); + return _AChoreographer_postFrameCallback64(choreographer, callback, data); +} + +bool NDKHelpers::HardwareBufferSupported() { + const bool r = _AHardwareBuffer_fromHardwareBuffer != nullptr; + return r; +} + +AHardwareBuffer* NDKHelpers::AHardwareBuffer_fromHardwareBuffer( + JNIEnv* env, + jobject hardwareBufferObj) { + FML_CHECK(_AHardwareBuffer_fromHardwareBuffer != nullptr); + return _AHardwareBuffer_fromHardwareBuffer(env, hardwareBufferObj); +} + +void NDKHelpers::AHardwareBuffer_release(AHardwareBuffer* buffer) { + FML_CHECK(_AHardwareBuffer_release != nullptr); + _AHardwareBuffer_release(buffer); +} + +void NDKHelpers::AHardwareBuffer_describe(AHardwareBuffer* buffer, + AHardwareBuffer_Desc* desc) { + FML_CHECK(_AHardwareBuffer_describe != nullptr); + _AHardwareBuffer_describe(buffer, desc); +} + +std::optional NDKHelpers::AHardwareBuffer_getId( + AHardwareBuffer* buffer) { + if (_AHardwareBuffer_getId == nullptr) { + return std::nullopt; + } + HardwareBufferKey outId; + int result = _AHardwareBuffer_getId(buffer, &outId); + if (result == 0) { + return outId; + } + return std::nullopt; +} + +EGLClientBuffer NDKHelpers::eglGetNativeClientBufferANDROID( + AHardwareBuffer* buffer) { + FML_CHECK(_eglGetNativeClientBufferANDROID != nullptr); + return _eglGetNativeClientBufferANDROID(buffer); +} + +bool NDKHelpers::SurfaceControlAndTransactionSupported() { + return _ASurfaceControl_createFromWindow && _ASurfaceControl_release && + _ASurfaceTransaction_create && _ASurfaceTransaction_apply && + _ASurfaceTransaction_delete && _ASurfaceTransaction_setBuffer; +} + +ASurfaceControl* NDKHelpers::ASurfaceControl_createFromWindow( + ANativeWindow* parent, + const char* debug_name) { + FML_CHECK(_ASurfaceControl_createFromWindow); + return _ASurfaceControl_createFromWindow(parent, debug_name); +} + +void NDKHelpers::ASurfaceControl_release(ASurfaceControl* surface_control) { + FML_CHECK(_ASurfaceControl_release); + return _ASurfaceControl_release(surface_control); +} + +ASurfaceTransaction* NDKHelpers::ASurfaceTransaction_create() { + FML_CHECK(_ASurfaceTransaction_create); + return _ASurfaceTransaction_create(); +} + +void NDKHelpers::ASurfaceTransaction_delete( + ASurfaceTransaction* surface_transaction) { + FML_CHECK(_ASurfaceTransaction_delete); + _ASurfaceTransaction_delete(surface_transaction); +} + +void NDKHelpers::ASurfaceTransaction_apply( + ASurfaceTransaction* surface_transaction) { + FML_CHECK(_ASurfaceTransaction_apply); + _ASurfaceTransaction_apply(surface_transaction); +} + +void NDKHelpers::ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction, + ASurfaceControl* surface_control, + AHardwareBuffer* buffer, + int acquire_fence_fd) { + FML_CHECK(_ASurfaceTransaction_setBuffer); + _ASurfaceTransaction_setBuffer(transaction, surface_control, buffer, + acquire_fence_fd); +} + +int NDKHelpers::AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) { + FML_CHECK(_AHardwareBuffer_isSupported); + return _AHardwareBuffer_isSupported(desc); +} + +int NDKHelpers::AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, + AHardwareBuffer** outBuffer) { + FML_CHECK(_AHardwareBuffer_allocate); + return _AHardwareBuffer_allocate(desc, outBuffer); +} + +} // namespace flutter diff --git a/fml/platform/android/ndk_helpers.h b/fml/platform/android/ndk_helpers.h new file mode 100644 index 0000000000000..9299776e3e691 --- /dev/null +++ b/fml/platform/android/ndk_helpers.h @@ -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. + +#ifndef FLUTTER_FML_PLATFORM_ANDROID_NDK_HELPERS_H_ +#define FLUTTER_FML_PLATFORM_ANDROID_NDK_HELPERS_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace flutter { + +using HardwareBufferKey = uint64_t; + +enum class ChoreographerSupportStatus { + // Unavailable, API level < 24. + kUnsupported, + // Available, but only with postFrameCallback. + kSupported32, + // Available, but only with postFrameCallback64. + kSupported64, +}; + +// A collection of NDK functions that are available depending on the version of +// the Android SDK we are linked with at runtime. +class NDKHelpers { + public: + // Safe to call multiple times. + // Normally called from JNI_OnLoad. + static void Init(); + + // API Version 23 + static bool ATrace_isEnabled(); + + // API Version 24 + static ChoreographerSupportStatus ChoreographerSupported(); + static AChoreographer* _Nullable AChoreographer_getInstance(); + // Deprecated in 29, available since 24. + static void AChoreographer_postFrameCallback( + AChoreographer* _Nonnull choreographer, + AChoreographer_frameCallback _Nonnull callback, + void* _Nullable data); + + // API Version 26 + static bool HardwareBufferSupported(); + static AHardwareBuffer* _Nonnull AHardwareBuffer_fromHardwareBuffer( + JNIEnv* _Nonnull env, + jobject _Nonnull hardwareBufferObj); + static void AHardwareBuffer_release(AHardwareBuffer* _Nonnull buffer); + static void AHardwareBuffer_describe(AHardwareBuffer* _Nonnull buffer, + AHardwareBuffer_Desc* _Nullable desc); + static int AHardwareBuffer_allocate( + const AHardwareBuffer_Desc* _Nonnull desc, + AHardwareBuffer* _Nullable* _Nullable outBuffer); + static EGLClientBuffer _Nonnull eglGetNativeClientBufferANDROID( + AHardwareBuffer* _Nonnull buffer); + + // API Version 29 + static int AHardwareBuffer_isSupported( + const AHardwareBuffer_Desc* _Nonnull desc); + + static void AChoreographer_postFrameCallback64( + AChoreographer* _Nonnull choreographer, + AChoreographer_frameCallback64 _Nonnull callback, + void* _Nullable data); + + static bool SurfaceControlAndTransactionSupported(); + + static ASurfaceControl* _Nonnull ASurfaceControl_createFromWindow( + ANativeWindow* _Nonnull parent, + const char* _Nullable debug_name); + static void ASurfaceControl_release( + ASurfaceControl* _Nonnull surface_control); + + static ASurfaceTransaction* _Nonnull ASurfaceTransaction_create(); + static void ASurfaceTransaction_delete( + ASurfaceTransaction* _Nonnull surface_transaction); + static void ASurfaceTransaction_apply( + ASurfaceTransaction* _Nonnull surface_transaction); + static void ASurfaceTransaction_setBuffer( + ASurfaceTransaction* _Nonnull transaction, + ASurfaceControl* _Nonnull surface_control, + AHardwareBuffer* _Nonnull buffer, + int acquire_fence_fd); + + // API Version 31 + + // Returns std::nullopt on API version 26 - 30. + static std::optional AHardwareBuffer_getId( + AHardwareBuffer* _Nonnull buffer); +}; + +} // namespace flutter + +#endif // FLUTTER_FML_PLATFORM_ANDROID_NDK_HELPERS_H_ diff --git a/fml/platform/android/ndk_helpers_unittests.cc b/fml/platform/android/ndk_helpers_unittests.cc new file mode 100644 index 0000000000000..dfcd528d9072a --- /dev/null +++ b/fml/platform/android/ndk_helpers_unittests.cc @@ -0,0 +1,135 @@ +// 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 "fml/message_loop.h" +#include "fml/platform/android/ndk_helpers.h" + +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { +namespace android { + +class NdkHelpersTest : public ::testing::Test { + public: + void SetUp() override { NDKHelpers::Init(); } + + static void OnVsync(int64_t frame_nanos, void* data) {} + static void OnVsync32( + long frame_nanos, // NOLINT - compat for deprecated call + void* data) {} +}; + +TEST_F(NdkHelpersTest, ATrace) { + ASSERT_GT(android_get_device_api_level(), 22); + EXPECT_FALSE(NDKHelpers::ATrace_isEnabled()); +} + +#if FML_ARCH_CPU_64_BITS +TEST_F(NdkHelpersTest, AChoreographer32) { + if (android_get_device_api_level() >= 29) { + GTEST_SKIP() << "This test is for less than API 29."; + } + + EXPECT_EQ(NDKHelpers::ChoreographerSupported(), + ChoreographerSupportStatus::kSupported32); + + EXPECT_FALSE(NDKHelpers::AChoreographer_getInstance()); + + fml::MessageLoop::EnsureInitializedForCurrentThread(); + + EXPECT_TRUE(NDKHelpers::AChoreographer_getInstance()); + + NDKHelpers::AChoreographer_postFrameCallback( + NDKHelpers::AChoreographer_getInstance(), &OnVsync32, nullptr); +} +#else +TEST_F(NdkHelpersTest, AChoreographer32NotSupported) { + if (android_get_device_api_level() >= 29) { + GTEST_SKIP() << "This test is for less than API 29."; + } + + // The 32 bit framecallback on 32 bit architectures does not deliver + // sufficient resolution. See + // https://github.com/flutter/engine/pull/31859#discussion_r822072987 + EXPECT_EQ(NDKHelpers::ChoreographerSupported(), + ChoreographerSupportStatus::kUnsupported); +} +#endif // FML_ARCH_CPU_64_BITS + +TEST_F(NdkHelpersTest, AChoreographer64) { + if (android_get_device_api_level() < 29) { + GTEST_SKIP() << "This test is for API 29 and above."; + } + + EXPECT_EQ(NDKHelpers::ChoreographerSupported(), + ChoreographerSupportStatus::kSupported64); + + EXPECT_FALSE(NDKHelpers::AChoreographer_getInstance()); + + fml::MessageLoop::EnsureInitializedForCurrentThread(); + + EXPECT_TRUE(NDKHelpers::AChoreographer_getInstance()); + + NDKHelpers::AChoreographer_postFrameCallback64( + NDKHelpers::AChoreographer_getInstance(), &OnVsync, nullptr); +} + +TEST_F(NdkHelpersTest, HardwareBuffer) { + if (android_get_device_api_level() < 26) { + GTEST_SKIP() << "Test requires at least API 26."; + } + + ASSERT_TRUE(NDKHelpers::HardwareBufferSupported()); + + AHardwareBuffer_Desc desc{ + .width = 4, + .height = 4, + .layers = 1, + .format = AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + }; + if (android_get_device_api_level() >= 29) { + EXPECT_TRUE(NDKHelpers::AHardwareBuffer_isSupported(&desc)); + } + + AHardwareBuffer* buffer = nullptr; + // AHardwareBuffer_allocate returns 0 on success. + EXPECT_EQ(NDKHelpers::AHardwareBuffer_allocate(&desc, &buffer), 0); + EXPECT_TRUE(buffer); + + AHardwareBuffer_Desc out_desc = {}; + NDKHelpers::AHardwareBuffer_describe(buffer, &out_desc); + EXPECT_EQ(desc.width, out_desc.width); + EXPECT_EQ(desc.height, out_desc.height); + EXPECT_EQ(desc.layers, out_desc.layers); + EXPECT_EQ(desc.format, out_desc.format); + + auto id = NDKHelpers::AHardwareBuffer_getId(buffer); + if (android_get_device_api_level() >= 31) { + EXPECT_TRUE(id.has_value()); + } else { + EXPECT_FALSE(id.has_value()); + } + + NDKHelpers::AHardwareBuffer_release(buffer); +} + +TEST_F(NdkHelpersTest, SurfaceTransaction) { + if (android_get_device_api_level() < 29) { + GTEST_SKIP() << "Test requires at least API 29."; + } + EXPECT_TRUE(NDKHelpers::SurfaceControlAndTransactionSupported()); + + // Need ANativeWindow to create ASurfaceControl and set a buffer to the + // transaction. Just create/apply/delete as a smoke test. + + ASurfaceTransaction* transaction = NDKHelpers::ASurfaceTransaction_create(); + EXPECT_TRUE(transaction); + NDKHelpers::ASurfaceTransaction_apply(transaction); + NDKHelpers::ASurfaceTransaction_delete(transaction); +} + +} // namespace android +} // namespace testing +} // namespace flutter diff --git a/impeller/toolkit/android/BUILD.gn b/impeller/toolkit/android/BUILD.gn deleted file mode 100644 index fd0dde36bd9bf..0000000000000 --- a/impeller/toolkit/android/BUILD.gn +++ /dev/null @@ -1,54 +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. - -import("../../tools/impeller.gni") - -config("public_android_config") { - defines = [ "__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__" ] -} - -impeller_component("android") { - sources = [ - "choreographer.cc", - "choreographer.h", - "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", - ] - - public_configs = [ ":public_android_config" ] -} - -test_fixtures("unittests_fixtures") { - fixtures = [] -} - -executable("unittests") { - assert(is_android) - - testonly = true - - output_name = "impeller_toolkit_android_unittests" - - sources = [ "toolkit_android_unittests.cc" ] - - deps = [ - ":android", - ":unittests_fixtures", - "//flutter/testing", - ] -} diff --git a/impeller/toolkit/android/README.md b/impeller/toolkit/android/README.md deleted file mode 100644 index b52d8f6ea8f7f..0000000000000 --- a/impeller/toolkit/android/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Android Toolkit -=============== - -Type-safe managed wrappers around Android objects vended by the NDK. Does not -require linking to libandroid.so. The symbols are resolved via dynamic runtime -lookup so that the toolkit can be built with an older NDK but still run on -modern Android versions and use the latest features. diff --git a/impeller/toolkit/android/choreographer.cc b/impeller/toolkit/android/choreographer.cc deleted file mode 100644 index f723e3e62fc07..0000000000000 --- a/impeller/toolkit/android/choreographer.cc +++ /dev/null @@ -1,84 +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. - -#include "flutter/impeller/toolkit/android/choreographer.h" - -#include "flutter/fml/message_loop.h" - -namespace impeller::android { - -Choreographer& Choreographer::GetInstance() { - static thread_local Choreographer tChoreographer; - return tChoreographer; -} - -Choreographer::Choreographer() { - if (!IsAvailableOnPlatform()) { - return; - } - - // We need a message loop on the current thread for the choreographer to - // schedule callbacks for us on. - fml::MessageLoop::EnsureInitializedForCurrentThread(); - instance_ = GetProcTable().AChoreographer_getInstance(); -} - -Choreographer::~Choreographer() = default; - -bool Choreographer::IsValid() const { - return !!instance_; -} - -static Choreographer::FrameTimePoint ClockMonotonicNanosToFrameTimePoint( - int64_t p_nanos) { - return Choreographer::FrameTimePoint{std::chrono::nanoseconds(p_nanos)}; -} - -bool Choreographer::PostFrameCallback(FrameCallback callback) const { - if (!callback || !IsValid()) { - return false; - } - - struct InFlightData { - FrameCallback callback; - }; - - auto data = std::make_unique(); - data->callback = std::move(callback); - - const auto& table = GetProcTable(); - if (table.AChoreographer_postFrameCallback64) { - table.AChoreographer_postFrameCallback64( - const_cast(instance_), - [](int64_t nanos, void* p_data) { - auto data = reinterpret_cast(p_data); - data->callback(ClockMonotonicNanosToFrameTimePoint(nanos)); - delete data; - }, - data.release()); - return true; - } else if (table.AChoreographer_postFrameCallback) { - table.AChoreographer_postFrameCallback( - const_cast(instance_), - [](long /*NOLINT*/ nanos, void* p_data) { - auto data = reinterpret_cast(p_data); - data->callback(ClockMonotonicNanosToFrameTimePoint(nanos)); - delete data; - }, - data.release()); - return true; - } - - // The validity check should have tripped by now. - FML_UNREACHABLE(); - return false; -} - -bool Choreographer::IsAvailableOnPlatform() { - return GetProcTable().AChoreographer_getInstance || - GetProcTable().AChoreographer_postFrameCallback64 || - GetProcTable().AChoreographer_postFrameCallback; -} - -} // namespace impeller::android diff --git a/impeller/toolkit/android/choreographer.h b/impeller/toolkit/android/choreographer.h deleted file mode 100644 index a4b781df8535f..0000000000000 --- a/impeller/toolkit/android/choreographer.h +++ /dev/null @@ -1,84 +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_TOOLKIT_ANDROID_CHOREOGRAPHER_H_ -#define FLUTTER_IMPELLER_TOOLKIT_ANDROID_CHOREOGRAPHER_H_ - -#include "impeller/toolkit/android/proc_table.h" - -#include -#include - -namespace impeller::android { - -//------------------------------------------------------------------------------ -/// @brief This class describes access to the choreographer instance for -/// the current thread. Choreographers are only available on API -/// levels above 24. On levels below 24, an invalid choreographer -/// will be returned. -/// -/// Since choreographer need an event loop on the current thread, -/// one will be setup if it doesn't already exist. -/// -class Choreographer { - public: - static bool IsAvailableOnPlatform(); - - //---------------------------------------------------------------------------- - /// @brief Create or get the thread local instance of a choreographer. A - /// message loop will be setup on the calling thread if none - /// exists. - /// - /// @warning Choreographers are only available on API levels 24 and above. - /// Below this level, this will return an invalid instance. - /// Availability can also be checked via the - /// `IsAvailableOnPlatform` call. - /// - /// @return The thread local choreographer instance. If none can be setup, - /// an invalid object reference will be returned. See `IsValid`. - /// - static Choreographer& GetInstance(); - - ~Choreographer(); - - Choreographer(const Choreographer&) = delete; - - Choreographer& operator=(const Choreographer&) = delete; - - bool IsValid() const; - - //---------------------------------------------------------------------------- - /// A monotonic system clock. - /// - using FrameClock = std::chrono::steady_clock; - - //---------------------------------------------------------------------------- - /// A timepoint on a monotonic system clock. - /// - using FrameTimePoint = std::chrono::time_point; - using FrameCallback = std::function; - - //---------------------------------------------------------------------------- - /// @brief Posts a frame callback. The time that the frame is being - /// rendered will be available in the callback as an argument. - /// Multiple frame callbacks within the same frame interval will - /// receive the same argument. - /// - /// @param[in] callback The callback - /// - /// @return `true` if the frame callback could be posted. This may return - /// `false` if choreographers are not available on the platform. - /// See `IsAvailableOnPlatform`. - /// - bool PostFrameCallback(FrameCallback callback) const; - - private: - AChoreographer* instance_ = nullptr; - - explicit Choreographer(); -}; - -} // namespace impeller::android - -#endif // FLUTTER_IMPELLER_TOOLKIT_ANDROID_CHOREOGRAPHER_H_ diff --git a/impeller/toolkit/android/hardware_buffer.cc b/impeller/toolkit/android/hardware_buffer.cc deleted file mode 100644 index bfa52a2063cb6..0000000000000 --- a/impeller/toolkit/android/hardware_buffer.cc +++ /dev/null @@ -1,131 +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. - -#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( - const 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_; -} - -bool HardwareBuffer::IsAvailableOnPlatform() { - return GetProcTable().IsValid() && - GetProcTable().AHardwareBuffer_allocate.IsAvailable(); -} - -std::optional HardwareBuffer::GetSystemUniqueID() const { - return GetSystemUniqueID(GetHandle()); -} - -std::optional HardwareBuffer::GetSystemUniqueID( - AHardwareBuffer* buffer) { - if (!GetProcTable().AHardwareBuffer_getId) { - return false; - } - uint64_t out_id = 0u; - if (GetProcTable().AHardwareBuffer_getId(buffer, &out_id) != 0) { - return std::nullopt; - } - return out_id; -} - -std::optional HardwareBuffer::Describe( - AHardwareBuffer* buffer) { - if (!buffer || !GetProcTable().AHardwareBuffer_describe) { - return std::nullopt; - } - AHardwareBuffer_Desc desc = {}; - GetProcTable().AHardwareBuffer_describe(buffer, &desc); - return desc; -} - -} // namespace impeller::android diff --git a/impeller/toolkit/android/hardware_buffer.h b/impeller/toolkit/android/hardware_buffer.h deleted file mode 100644 index 02b99b1013674..0000000000000 --- a/impeller/toolkit/android/hardware_buffer.h +++ /dev/null @@ -1,149 +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_TOOLKIT_ANDROID_HARDWARE_BUFFER_H_ -#define FLUTTER_IMPELLER_TOOLKIT_ANDROID_HARDWARE_BUFFER_H_ - -#include - -#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. This - /// format can also be converted to an Impeller and Vulkan format. - /// - /// @see Vulkan Format: VK_FORMAT_R8G8B8A8_UNORM - /// @see OpenGL ES Format: GL_RGBA8 - /// - /// 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, -}; - -//------------------------------------------------------------------------------ -/// @brief A descriptor use to specify hardware buffer allocations. -/// -struct HardwareBufferDescriptor { - HardwareBufferFormat format = HardwareBufferFormat::kR8G8B8A8UNormInt; - ISize size; - HardwareBufferUsage usage = 0u; - - //---------------------------------------------------------------------------- - /// @brief Create a descriptor of the given size that is suitable for use - /// as a swapchain image. - /// - /// @warning Descriptors of zero size are not allocatable. The next best - /// valid size is picked. So make sure to check the actual size of - /// the descriptor after this call is made to determine the size - /// of the allocated hardware buffer. - /// - /// @param[in] size The size. See the restrictions about valid sizes above. - /// - /// @return The hardware buffer descriptor. - /// - static HardwareBufferDescriptor MakeForSwapchainImage(const ISize& size); - - //---------------------------------------------------------------------------- - /// @brief If hardware buffers can be created using this descriptor. - /// Allocatable descriptors may still cause failing allocations in - /// case of resource exhaustion. - /// - /// @return `true` if allocatable (unless resource exhaustion). - /// - 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: - static bool IsAvailableOnPlatform(); - - 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; - - static std::optional Describe(AHardwareBuffer* buffer); - - //---------------------------------------------------------------------------- - /// @brief Get the system wide unique ID of the hardware buffer if - /// possible. This is only available on Android API 31 and above. - /// Within the process, the handle are unique. - /// - /// @return The system unique id if one can be obtained. - /// - std::optional GetSystemUniqueID() const; - - //---------------------------------------------------------------------------- - /// @brief Get the system wide unique ID of the hardware buffer if - /// possible. This is only available on Android API 31 and above. - /// Within the process, the handle are unique. - /// - /// @return The system unique id if one can be obtained. - /// - static std::optional GetSystemUniqueID(AHardwareBuffer* buffer); - - 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 deleted file mode 100644 index 663a482f624a3..0000000000000 --- a/impeller/toolkit/android/native_window.cc +++ /dev/null @@ -1,34 +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. - -#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 deleted file mode 100644 index 8af6cfb4ba5a6..0000000000000 --- a/impeller/toolkit/android/native_window.h +++ /dev/null @@ -1,57 +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_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 size 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 deleted file mode 100644 index 71e6ce5c4d14d..0000000000000 --- a/impeller/toolkit/android/proc_table.cc +++ /dev/null @@ -1,68 +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. - -#include "flutter/impeller/toolkit/android/proc_table.h" - -#include "flutter/fml/build_config.h" -#include "impeller/base/validation.h" - -namespace impeller::android { - -const ProcTable& GetProcTable() { - static ProcTable gProcTable; - return gProcTable; -} - -template -void ResolveAndroidProc( - AndroidProc& proc, - const std::vector>& libs) { - for (const auto& lib : libs) { - proc.proc = lib->ResolveFunction(proc.proc_name).value_or(nullptr); - if (proc.proc) { - break; - } - } -} - -ProcTable::ProcTable() { - auto lib_android = fml::NativeLibrary::Create("libandroid.so"); - auto lib_egl = fml::NativeLibrary::Create("libEGL.so"); - - if (!lib_android || !lib_egl) { - VALIDATION_LOG << "Could not open Android libraries."; - return; - } - - libraries_.push_back(std::move(lib_android)); - libraries_.push_back(std::move(lib_egl)); - -#define RESOLVE_PROC(proc, api) ResolveAndroidProc(proc, libraries_); - FOR_EACH_ANDROID_PROC(RESOLVE_PROC); -#undef RESOLVE_PROC - - if (AChoreographer_postFrameCallback64) { - AChoreographer_postFrameCallback.Reset(); - } - -#if FML_ARCH_CPU_32_BITS - // On 32-bit platforms, the nanosecond resolution timestamp causes overflow on - // the argument in the callback. Don't use it on those platforms. - AChoreographer_postFrameCallback.Reset(); -#endif // FML_ARCH_CPU_32_BITS - - is_valid_ = true; -} - -ProcTable::~ProcTable() = default; - -bool ProcTable::IsValid() const { - return is_valid_; -} - -bool ProcTable::TraceIsEnabled() const { - return this->ATrace_isEnabled ? this->ATrace_isEnabled() : false; -} - -} // namespace impeller::android diff --git a/impeller/toolkit/android/proc_table.h b/impeller/toolkit/android/proc_table.h deleted file mode 100644 index 83b38a1293c79..0000000000000 --- a/impeller/toolkit/android/proc_table.h +++ /dev/null @@ -1,129 +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_TOOLKIT_ANDROID_PROC_TABLE_H_ -#define FLUTTER_IMPELLER_TOOLKIT_ANDROID_PROC_TABLE_H_ - -#include -#define EGL_EGLEXT_PROTOTYPES -#include -#include -#include -#include -#include -#include - -#include - -#include "flutter/fml/logging.h" -#include "flutter/fml/native_library.h" - -namespace impeller::android { - -//------------------------------------------------------------------------------ -/// @brief The Android procs along with the device API level on which these -/// will be available. There is no checking of the actual API level -/// however (because getting the API level is itself only possible -/// on API levels 29 and above). -/// -/// Take care to explicitly check for the availability of these APIs -/// at runtime before invoking them. -/// -/// Typically, you'll never have to deal with the proc. table -/// directly. Instead, rely on the handle wrappers (`Choreographer`, -/// `HardwareBuffer`, etc..). -/// -#define FOR_EACH_ANDROID_PROC(INVOKE) \ - INVOKE(AChoreographer_getInstance, 24) \ - INVOKE(AChoreographer_postFrameCallback, 24) \ - INVOKE(AChoreographer_postFrameCallback64, 29) \ - INVOKE(AHardwareBuffer_acquire, 26) \ - INVOKE(AHardwareBuffer_allocate, 26) \ - INVOKE(AHardwareBuffer_describe, 26) \ - INVOKE(AHardwareBuffer_fromHardwareBuffer, 26) \ - INVOKE(AHardwareBuffer_getId, 31) \ - INVOKE(AHardwareBuffer_isSupported, 29) \ - INVOKE(AHardwareBuffer_release, 26) \ - INVOKE(ANativeWindow_acquire, 0) \ - INVOKE(ANativeWindow_getHeight, 0) \ - INVOKE(ANativeWindow_getWidth, 0) \ - INVOKE(ANativeWindow_release, 0) \ - INVOKE(ASurfaceControl_createFromWindow, 29) \ - INVOKE(ASurfaceControl_release, 29) \ - INVOKE(ASurfaceTransaction_apply, 29) \ - INVOKE(ASurfaceTransaction_create, 29) \ - INVOKE(ASurfaceTransaction_delete, 29) \ - INVOKE(ASurfaceTransaction_reparent, 29) \ - INVOKE(ASurfaceTransaction_setBuffer, 29) \ - INVOKE(ASurfaceTransaction_setColor, 29) \ - INVOKE(ASurfaceTransaction_setOnComplete, 29) \ - INVOKE(ATrace_isEnabled, 23) \ - INVOKE(eglGetNativeClientBufferANDROID, 0) - -template -struct AndroidProc { - using AndroidProcType = T; - - const char* proc_name = nullptr; - - AndroidProcType* proc = nullptr; - - constexpr bool IsAvailable() const { return proc != nullptr; } - - explicit constexpr operator bool() const { return IsAvailable(); } - - template - auto operator()(Args&&... args) const { - FML_DCHECK(IsAvailable()) - << "Android method " << proc_name - << " is not available on this device. Missing check."; - return proc(std::forward(args)...); - } - - void Reset() { proc = nullptr; } -}; - -//------------------------------------------------------------------------------ -/// @brief The table of Android procs that are resolved dynamically. -/// -struct ProcTable { - ProcTable(); - - ~ProcTable(); - - ProcTable(const ProcTable&) = delete; - - ProcTable& operator=(const ProcTable&) = delete; - - //---------------------------------------------------------------------------- - /// @brief If a valid proc table could be setup. This may fail in case of - /// setup on non-Android platforms. - /// - /// @return `true` if valid. - /// - bool IsValid() const; - - //---------------------------------------------------------------------------- - /// @brief Check if tracing in enabled in the process. This call can be - /// made at any API level. - /// - /// @return If tracing is enabled. - /// - bool TraceIsEnabled() const; - -#define DEFINE_PROC(name, api) \ - AndroidProc name = {.proc_name = #name}; - FOR_EACH_ANDROID_PROC(DEFINE_PROC); -#undef DEFINE_PROC - - private: - std::vector> libraries_; - 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 deleted file mode 100644 index 71282e7ccc981..0000000000000 --- a/impeller/toolkit/android/surface_control.cc +++ /dev/null @@ -1,55 +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. - -#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) { - if (window == nullptr) { - VALIDATION_LOG << "Parent window of surface was null."; - return; - } - if (debug_name == nullptr) { - debug_name = "Impeller Layer"; - } - control_.reset( - GetProcTable().ASurfaceControl_createFromWindow(window, debug_name)); -} - -SurfaceControl::~SurfaceControl() { - if (IsValid() && !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(); -} - -bool SurfaceControl::IsAvailableOnPlatform() { - return GetProcTable().IsValid() && - GetProcTable().ASurfaceControl_createFromWindow.IsAvailable(); -} - -} // namespace impeller::android diff --git a/impeller/toolkit/android/surface_control.h b/impeller/toolkit/android/surface_control.h deleted file mode 100644 index af51a4bc5b748..0000000000000 --- a/impeller/toolkit/android/surface_control.h +++ /dev/null @@ -1,86 +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_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: - //---------------------------------------------------------------------------- - /// @return `true` if any surface controls can be created on this - /// platform. - /// - static bool IsAvailableOnPlatform(); - - //---------------------------------------------------------------------------- - /// @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 deleted file mode 100644 index a96eef6a26a57..0000000000000 --- a/impeller/toolkit/android/surface_transaction.cc +++ /dev/null @@ -1,104 +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. - -#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; -} - -bool SurfaceTransaction::IsAvailableOnPlatform() { - return GetProcTable().IsValid() && - GetProcTable().ASurfaceTransaction_create.IsAvailable(); -} - -} // namespace impeller::android diff --git a/impeller/toolkit/android/surface_transaction.h b/impeller/toolkit/android/surface_transaction.h deleted file mode 100644 index b9460f35e0978..0000000000000 --- a/impeller/toolkit/android/surface_transaction.h +++ /dev/null @@ -1,135 +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_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. -/// -/// @note Transactions should be short lived objects (create, apply, -/// collect). But, if these are used on multiple threads, they must -/// be externally synchronized. -/// -class SurfaceTransaction { - public: - //---------------------------------------------------------------------------- - /// @return `true` if any surface transactions can be created on this - /// platform. - /// - static bool IsAvailableOnPlatform(); - - 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/impeller/toolkit/android/toolkit_android_unittests.cc b/impeller/toolkit/android/toolkit_android_unittests.cc deleted file mode 100644 index ff3a7df9daae2..0000000000000 --- a/impeller/toolkit/android/toolkit_android_unittests.cc +++ /dev/null @@ -1,108 +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. - -#include "flutter/fml/synchronization/waitable_event.h" -#include "flutter/testing/testing.h" -#include "impeller/toolkit/android/choreographer.h" -#include "impeller/toolkit/android/hardware_buffer.h" -#include "impeller/toolkit/android/proc_table.h" -#include "impeller/toolkit/android/surface_control.h" -#include "impeller/toolkit/android/surface_transaction.h" - -namespace impeller::android::testing { - -class ToolkitAndroidTest : public ::testing::Test { - public: - void SetUp() override { - // The toolkit is only available on Android API levels over 29. Skip these - // tests everywhere else. - if (__builtin_available(android 29, *)) { - } else { - GTEST_SKIP() << "Platform too old for this test."; - } - } -}; - -TEST_F(ToolkitAndroidTest, CanCreateProcTable) { - ProcTable proc_table; - ASSERT_TRUE(proc_table.IsValid()); -} - -TEST_F(ToolkitAndroidTest, GuardsAgainstZeroSizedDescriptors) { - auto desc = HardwareBufferDescriptor::MakeForSwapchainImage({0, 0}); - ASSERT_GT(desc.size.width, 0u); - ASSERT_GT(desc.size.height, 0u); -} - -TEST_F(ToolkitAndroidTest, CanCreateHardwareBuffer) { - ASSERT_TRUE(HardwareBuffer::IsAvailableOnPlatform()); - auto desc = HardwareBufferDescriptor::MakeForSwapchainImage({100, 100}); - ASSERT_TRUE(desc.IsAllocatable()); - HardwareBuffer buffer(desc); - ASSERT_TRUE(buffer.IsValid()); -} - -TEST_F(ToolkitAndroidTest, CanGetHardwareBufferIDs) { - ASSERT_TRUE(HardwareBuffer::IsAvailableOnPlatform()); - if (!GetProcTable().AHardwareBuffer_getId.IsAvailable()) { - GTEST_SKIP() << "Hardware buffer IDs are not available on this platform."; - } - auto desc = HardwareBufferDescriptor::MakeForSwapchainImage({100, 100}); - ASSERT_TRUE(desc.IsAllocatable()); - HardwareBuffer buffer(desc); - ASSERT_TRUE(buffer.IsValid()); - ASSERT_TRUE(buffer.GetSystemUniqueID().has_value()); -} - -TEST_F(ToolkitAndroidTest, CanDescribeHardwareBufferHandles) { - ASSERT_TRUE(HardwareBuffer::IsAvailableOnPlatform()); - auto desc = HardwareBufferDescriptor::MakeForSwapchainImage({100, 100}); - ASSERT_TRUE(desc.IsAllocatable()); - HardwareBuffer buffer(desc); - ASSERT_TRUE(buffer.IsValid()); - auto a_desc = HardwareBuffer::Describe(buffer.GetHandle()); - ASSERT_TRUE(a_desc.has_value()); - ASSERT_EQ(a_desc->width, 100u); // NOLINT - ASSERT_EQ(a_desc->height, 100u); // NOLINT -} - -TEST_F(ToolkitAndroidTest, CanApplySurfaceTransaction) { - ASSERT_TRUE(SurfaceTransaction::IsAvailableOnPlatform()); - SurfaceTransaction transaction; - ASSERT_TRUE(transaction.IsValid()); - fml::AutoResetWaitableEvent event; - ASSERT_TRUE(transaction.Apply([&event]() { event.Signal(); })); - event.Wait(); -} - -TEST_F(ToolkitAndroidTest, SurfacControlsAreAvailable) { - ASSERT_TRUE(SurfaceControl::IsAvailableOnPlatform()); -} - -TEST_F(ToolkitAndroidTest, ChoreographerIsAvailable) { - ASSERT_TRUE(Choreographer::IsAvailableOnPlatform()); -} - -TEST_F(ToolkitAndroidTest, CanPostAndNotWaitForFrameCallbacks) { - const auto& choreographer = Choreographer::GetInstance(); - ASSERT_TRUE(choreographer.IsValid()); - ASSERT_TRUE(choreographer.PostFrameCallback([](auto) {})); -} - -TEST_F(ToolkitAndroidTest, CanPostAndWaitForFrameCallbacks) { - if ((true)) { - GTEST_SKIP() - << "Disabled till the test harness is in an Android activity. " - "Running it without one will hang because the choreographer " - "frame callback will never execute."; - } - const auto& choreographer = Choreographer::GetInstance(); - ASSERT_TRUE(choreographer.IsValid()); - fml::AutoResetWaitableEvent event; - ASSERT_TRUE(choreographer.PostFrameCallback( - [&event](auto point) { event.Signal(); })); - event.Wait(); -} - -} // namespace impeller::android::testing diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 3025fabbbbbec..1500fb90e0639 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -42,6 +42,7 @@ executable("flutter_shell_native_unittests") { visibility = [ "*" ] testonly = true sources = [ + "//flutter/fml/platform/android/ndk_helpers_unittests.cc", "android_context_gl_impeller_unittests.cc", "android_context_gl_unittests.cc", "android_shell_holder_unittests.cc", @@ -142,7 +143,6 @@ source_set("flutter_shell_native_src") { "//flutter/flow", "//flutter/fml", "//flutter/impeller", - "//flutter/impeller/toolkit/android", "//flutter/impeller/toolkit/egl", "//flutter/impeller/toolkit/gles", "//flutter/lib/ui", diff --git a/shell/platform/android/flutter_main.cc b/shell/platform/android/flutter_main.cc index 9c9c58e66abe6..298fd3aff870e 100644 --- a/shell/platform/android/flutter_main.cc +++ b/shell/platform/android/flutter_main.cc @@ -17,6 +17,7 @@ #include "flutter/fml/native_library.h" #include "flutter/fml/paths.h" #include "flutter/fml/platform/android/jni_util.h" +#include "flutter/fml/platform/android/ndk_helpers.h" #include "flutter/fml/platform/android/paths_android.h" #include "flutter/fml/size.h" #include "flutter/lib/ui/plugins/callback_cache.h" @@ -26,7 +27,6 @@ #include "flutter/shell/platform/android/android_context_vulkan_impeller.h" #include "flutter/shell/platform/android/flutter_main.h" #include "impeller/base/validation.h" -#include "impeller/toolkit/android/proc_table.h" #include "third_party/dart/runtime/include/dart_tools_api.h" #include "txt/platform.h" @@ -85,8 +85,7 @@ void FlutterMain::Init(JNIEnv* env, // Turn systracing on if ATrace_isEnabled is true and the user did not already // request systracing if (!settings.trace_systrace) { - settings.trace_systrace = - impeller::android::GetProcTable().TraceIsEnabled(); + settings.trace_systrace = NDKHelpers::ATrace_isEnabled(); if (settings.trace_systrace) { __android_log_print( ANDROID_LOG_INFO, "Flutter", diff --git a/shell/platform/android/image_external_texture.cc b/shell/platform/android/image_external_texture.cc index b2df3c91de3de..90d78291c988f 100644 --- a/shell/platform/android/image_external_texture.cc +++ b/shell/platform/android/image_external_texture.cc @@ -5,7 +5,7 @@ #include #include "flutter/fml/platform/android/jni_util.h" -#include "flutter/impeller/toolkit/android/proc_table.h" +#include "flutter/fml/platform/android/ndk_helpers.h" #include "flutter/shell/platform/android/jni/platform_view_android_jni.h" namespace flutter { @@ -107,9 +107,8 @@ AHardwareBuffer* ImageExternalTexture::AHardwareBufferFor( const fml::jni::JavaRef& hardware_buffer) { JNIEnv* env = fml::jni::AttachCurrentThread(); FML_CHECK(env != nullptr); - const auto& proc = - impeller::android::GetProcTable().AHardwareBuffer_fromHardwareBuffer; - return proc ? proc(env, hardware_buffer.obj()) : nullptr; + return NDKHelpers::AHardwareBuffer_fromHardwareBuffer(env, + hardware_buffer.obj()); } } // namespace flutter diff --git a/shell/platform/android/image_external_texture_gl.cc b/shell/platform/android/image_external_texture_gl.cc index 92743654d0289..8ac28e46a7470 100644 --- a/shell/platform/android/image_external_texture_gl.cc +++ b/shell/platform/android/image_external_texture_gl.cc @@ -8,9 +8,9 @@ #include #include "flutter/common/graphics/texture.h" +#include "flutter/fml/platform/android/ndk_helpers.h" #include "flutter/impeller/core/formats.h" #include "flutter/impeller/display_list/dl_image_impeller.h" -#include "flutter/impeller/toolkit/android/hardware_buffer.h" #include "flutter/impeller/toolkit/egl/image.h" #include "flutter/impeller/toolkit/gles/texture.h" #include "third_party/skia/include/core/SkAlphaType.h" @@ -45,8 +45,7 @@ void ImageExternalTextureGL::UpdateImage(JavaLocalRef& hardware_buffer, PaintContext& context) { AHardwareBuffer* latest_hardware_buffer = AHardwareBufferFor(hardware_buffer); std::optional key = - impeller::android::HardwareBuffer::GetSystemUniqueID( - latest_hardware_buffer); + flutter::NDKHelpers::AHardwareBuffer_getId(latest_hardware_buffer); auto existing_image = image_lru_.FindImage(key); if (existing_image != nullptr) { dl_image_ = existing_image; @@ -90,8 +89,7 @@ impeller::UniqueEGLImageKHR ImageExternalTextureGL::CreateEGLImage( FML_CHECK(display != EGL_NO_DISPLAY); EGLClientBuffer client_buffer = - impeller::android::GetProcTable().eglGetNativeClientBufferANDROID( - hardware_buffer); + NDKHelpers::eglGetNativeClientBufferANDROID(hardware_buffer); FML_DCHECK(client_buffer != nullptr); if (client_buffer == nullptr) { FML_LOG(ERROR) << "eglGetNativeClientBufferAndroid returned null."; diff --git a/shell/platform/android/image_external_texture_gl.h b/shell/platform/android/image_external_texture_gl.h index 995592c7787f5..6a132237dbe3d 100644 --- a/shell/platform/android/image_external_texture_gl.h +++ b/shell/platform/android/image_external_texture_gl.h @@ -16,6 +16,8 @@ #include "flutter/impeller/toolkit/egl/egl.h" #include "flutter/impeller/toolkit/egl/image.h" #include "flutter/impeller/toolkit/gles/texture.h" + +#include "flutter/fml/platform/android/ndk_helpers.h" #include "flutter/shell/platform/android/android_context_gl_skia.h" namespace flutter { diff --git a/shell/platform/android/image_external_texture_vk.cc b/shell/platform/android/image_external_texture_vk.cc index 88574548d6c11..ad00687b555ba 100644 --- a/shell/platform/android/image_external_texture_vk.cc +++ b/shell/platform/android/image_external_texture_vk.cc @@ -1,11 +1,8 @@ -// 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/shell/platform/android/image_external_texture_vk.h" - #include +#include "flutter/fml/platform/android/ndk_helpers.h" #include "flutter/impeller/core/formats.h" #include "flutter/impeller/core/texture_descriptor.h" #include "flutter/impeller/display_list/dl_image_impeller.h" @@ -13,7 +10,6 @@ #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" -#include "flutter/impeller/toolkit/android/hardware_buffer.h" namespace flutter { @@ -45,13 +41,13 @@ void ImageExternalTextureVK::ProcessFrame(PaintContext& context, JavaLocalRef hardware_buffer = HardwareBufferFor(image); AHardwareBuffer* latest_hardware_buffer = AHardwareBufferFor(hardware_buffer); - auto hb_desc = - impeller::android::HardwareBuffer::Describe(latest_hardware_buffer); + AHardwareBuffer_Desc hb_desc = {}; + flutter::NDKHelpers::AHardwareBuffer_describe(latest_hardware_buffer, + &hb_desc); std::optional key = - impeller::android::HardwareBuffer::GetSystemUniqueID( - latest_hardware_buffer); + flutter::NDKHelpers::AHardwareBuffer_getId(latest_hardware_buffer); auto existing_image = image_lru_.FindImage(key); - if (existing_image != nullptr || !hb_desc.has_value()) { + if (existing_image != nullptr) { dl_image_ = existing_image; CloseHardwareBuffer(hardware_buffer); @@ -59,7 +55,7 @@ void ImageExternalTextureVK::ProcessFrame(PaintContext& context, } auto texture_source = std::make_shared( - impeller_context_, latest_hardware_buffer, hb_desc.value()); + impeller_context_, latest_hardware_buffer, hb_desc); if (!texture_source->IsValid()) { CloseHardwareBuffer(hardware_buffer); return; diff --git a/shell/platform/android/image_lru.h b/shell/platform/android/image_lru.h index 63829efb970ac..28a31cd2bf842 100644 --- a/shell/platform/android/image_lru.h +++ b/shell/platform/android/image_lru.h @@ -9,6 +9,7 @@ #include #include "display_list/image/dl_image.h" +#include "fml/platform/android/ndk_helpers.h" namespace flutter { @@ -19,8 +20,6 @@ namespace flutter { // necessary. static constexpr size_t kImageReaderSwapchainSize = 6u; -using HardwareBufferKey = uint64_t; - class ImageLRU { public: ImageLRU() = default; diff --git a/shell/platform/android/library_loader.cc b/shell/platform/android/library_loader.cc index 644bd5de3b8ec..9f3691d818512 100644 --- a/shell/platform/android/library_loader.cc +++ b/shell/platform/android/library_loader.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flutter/fml/platform/android/jni_util.h" +#include "flutter/fml/platform/android/ndk_helpers.h" #include "flutter/shell/platform/android/android_image_generator.h" #include "flutter/shell/platform/android/flutter_main.h" #include "flutter/shell/platform/android/platform_view_android.h" @@ -13,6 +14,9 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { // Initialize the Java VM. fml::jni::InitJavaVM(vm); + // Registery dlsym lookups for NDK functions + flutter::NDKHelpers::Init(); + JNIEnv* env = fml::jni::AttachCurrentThread(); bool result = false; diff --git a/shell/platform/android/platform_view_android_jni_impl.cc b/shell/platform/android/platform_view_android_jni_impl.cc index 0b4ed2ca1fead..b6d5dfc2f504f 100644 --- a/shell/platform/android/platform_view_android_jni_impl.cc +++ b/shell/platform/android/platform_view_android_jni_impl.cc @@ -12,6 +12,7 @@ #include #include +#include "flutter/fml/platform/android/ndk_helpers.h" #include "include/android/SkImageAndroid.h" #include "unicode/uchar.h" diff --git a/shell/platform/android/vsync_waiter_android.cc b/shell/platform/android/vsync_waiter_android.cc index bfced030f5fe5..d0a8db383a0ce 100644 --- a/shell/platform/android/vsync_waiter_android.cc +++ b/shell/platform/android/vsync_waiter_android.cc @@ -10,10 +10,10 @@ #include "flutter/common/task_runners.h" #include "flutter/fml/logging.h" #include "flutter/fml/platform/android/jni_util.h" +#include "flutter/fml/platform/android/ndk_helpers.h" #include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/fml/size.h" #include "flutter/fml/trace_event.h" -#include "impeller/toolkit/android/choreographer.h" namespace flutter { @@ -28,35 +28,47 @@ VsyncWaiterAndroid::~VsyncWaiterAndroid() = default; // |VsyncWaiter| void VsyncWaiterAndroid::AwaitVSync() { - if (impeller::android::Choreographer::IsAvailableOnPlatform()) { - auto* weak_this = new std::weak_ptr(shared_from_this()); - fml::TaskRunner::RunNowOrPostTask( - task_runners_.GetUITaskRunner(), [weak_this]() { - const auto& choreographer = - impeller::android::Choreographer::GetInstance(); - choreographer.PostFrameCallback([weak_this](auto time) { - auto time_ns = - std::chrono::time_point_cast(time) - .time_since_epoch() - .count(); - OnVsyncFromNDK(time_ns, weak_this); + switch (NDKHelpers::ChoreographerSupported()) { + case ChoreographerSupportStatus::kSupported32: { + auto* weak_this = new std::weak_ptr(shared_from_this()); + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetUITaskRunner(), [weak_this]() { + NDKHelpers::AChoreographer_postFrameCallback( + NDKHelpers::AChoreographer_getInstance(), &OnVsyncFromNDK32, + weak_this); }); - }); - } else { - // TODO(99798): Remove it when we drop support for API level < 29 and 32-bit - // devices. - auto* weak_this = new std::weak_ptr(shared_from_this()); - jlong java_baton = reinterpret_cast(weak_this); - task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() { - JNIEnv* env = fml::jni::AttachCurrentThread(); - env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), // - g_async_wait_for_vsync_method_, // - java_baton // - ); - }); + } break; + case ChoreographerSupportStatus::kSupported64: { + auto* weak_this = new std::weak_ptr(shared_from_this()); + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetUITaskRunner(), [weak_this]() { + NDKHelpers::AChoreographer_postFrameCallback64( + NDKHelpers::AChoreographer_getInstance(), &OnVsyncFromNDK, + weak_this); + }); + } break; + case ChoreographerSupportStatus::kUnsupported: { + // TODO(99798): Remove it when we drop support for API level < 29. + auto* weak_this = new std::weak_ptr(shared_from_this()); + jlong java_baton = reinterpret_cast(weak_this); + task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), // + g_async_wait_for_vsync_method_, // + java_baton // + ); + }); + } break; } } +// static +void VsyncWaiterAndroid::OnVsyncFromNDK32( + long frame_nanos, // NOLINT to match a deprecated NDK interface. + void* data) { + OnVsyncFromNDK(frame_nanos, data); +} + // static void VsyncWaiterAndroid::OnVsyncFromNDK(int64_t frame_nanos, void* data) { auto frame_time = fml::TimePoint::FromEpochDelta( diff --git a/shell/platform/android/vsync_waiter_android.h b/shell/platform/android/vsync_waiter_android.h index 7129bb94305e2..69c3ad912839c 100644 --- a/shell/platform/android/vsync_waiter_android.h +++ b/shell/platform/android/vsync_waiter_android.h @@ -29,6 +29,9 @@ class VsyncWaiterAndroid final : public VsyncWaiter { void AwaitVSync() override; static void OnVsyncFromNDK(int64_t frame_nanos, void* data); + // This needs to match a deprecated NDK interface. + static void OnVsyncFromNDK32(long frame_nanos, // NOLINT + void* data); static void OnVsyncFromJava(JNIEnv* env, jclass jcaller, diff --git a/testing/run_tests.py b/testing/run_tests.py index d51ad01f2b1c5..d91ec5de3a629 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -729,20 +729,15 @@ def run_java_tests(executable_filter, android_variant='android_debug_unopt'): run_cmd(command, cwd=test_runner_dir, env=env) -def run_android_unittest(test_runner_name, android_variant, adb_path): +def run_android_tests(android_variant='android_debug_unopt', adb_path=None): + test_runner_name = 'flutter_shell_native_unittests' tests_path = os.path.join(OUT_DIR, android_variant, test_runner_name) remote_path = '/data/local/tmp' remote_tests_path = os.path.join(remote_path, test_runner_name) - run_cmd([adb_path, 'push', tests_path, remote_path], cwd=BUILDROOT_DIR) - run_cmd([adb_path, 'shell', remote_tests_path]) - - -def run_android_tests(android_variant='android_debug_unopt', adb_path=None): if adb_path is None: adb_path = 'adb' - - run_android_unittest('flutter_shell_native_unittests', android_variant, adb_path) - run_android_unittest('impeller_toolkit_android_unittests', android_variant, adb_path) + run_cmd([adb_path, 'push', tests_path, remote_path], cwd=BUILDROOT_DIR) + run_cmd([adb_path, 'shell', remote_tests_path]) systrace_test = os.path.join(BUILDROOT_DIR, 'flutter', 'testing', 'android_systrace_test.py') scenario_apk = os.path.join(OUT_DIR, android_variant, 'firebase_apks', 'scenario_app.apk')