diff --git a/engine/src/flutter/impeller/toolkit/android/proc_table.h b/engine/src/flutter/impeller/toolkit/android/proc_table.h index 9e639603b9..6e90b7fe86 100644 --- a/engine/src/flutter/impeller/toolkit/android/proc_table.h +++ b/engine/src/flutter/impeller/toolkit/android/proc_table.h @@ -21,6 +21,9 @@ namespace impeller::android { +ASurfaceTransaction* ASurfaceTransaction_fromJava(JNIEnv* env, + jobject transaction); + //------------------------------------------------------------------------------ /// @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 @@ -61,6 +64,7 @@ namespace impeller::android { INVOKE(ASurfaceTransaction_setColor, 29) \ INVOKE(ASurfaceTransaction_setOnComplete, 29) \ INVOKE(ASurfaceTransactionStats_getPreviousReleaseFenceFd, 29) \ + INVOKE(ASurfaceTransaction_fromJava, 34) \ INVOKE(ATrace_isEnabled, 23) \ INVOKE(eglGetNativeClientBufferANDROID, 0) diff --git a/engine/src/flutter/impeller/toolkit/android/surface_transaction.cc b/engine/src/flutter/impeller/toolkit/android/surface_transaction.cc index 557dedb3cb..0e1b035296 100644 --- a/engine/src/flutter/impeller/toolkit/android/surface_transaction.cc +++ b/engine/src/flutter/impeller/toolkit/android/surface_transaction.cc @@ -11,7 +11,12 @@ namespace impeller::android { SurfaceTransaction::SurfaceTransaction() - : transaction_(GetProcTable().ASurfaceTransaction_create()) {} + : transaction_( + WrappedSurfaceTransaction{GetProcTable().ASurfaceTransaction_create(), + /*owned=*/true}) {} + +SurfaceTransaction::SurfaceTransaction(ASurfaceTransaction* transaction) + : transaction_(WrappedSurfaceTransaction{transaction, /*owned=*/false}) {} SurfaceTransaction::~SurfaceTransaction() = default; @@ -37,14 +42,22 @@ bool SurfaceTransaction::Apply(OnCompleteCallback callback) { auto data = std::make_unique(); data->callback = callback; proc_table.ASurfaceTransaction_setOnComplete( - transaction_.get(), // - data.release(), // + transaction_.get().tx, // + data.release(), // [](void* context, ASurfaceTransactionStats* stats) -> void { auto data = reinterpret_cast(context); data->callback(stats); delete data; }); - proc_table.ASurfaceTransaction_apply(transaction_.get()); + // If the transaction was created in Java, then it must be applied in + // the Java PlatformViewController and not as a part of the engine render + // loop. + if (!transaction_.get().owned) { + transaction_.reset(); + return true; + } + + proc_table.ASurfaceTransaction_apply(transaction_.get().tx); // Transactions may not be applied over and over. transaction_.reset(); @@ -59,7 +72,7 @@ bool SurfaceTransaction::SetContents(const SurfaceControl* control, return false; } GetProcTable().ASurfaceTransaction_setBuffer( - transaction_.get(), // + transaction_.get().tx, // control->GetHandle(), // buffer->GetHandle(), // acquire_fence.is_valid() ? acquire_fence.release() : -1 // @@ -72,7 +85,7 @@ bool SurfaceTransaction::SetBackgroundColor(const SurfaceControl& control, if (!IsValid() || !control.IsValid()) { return false; } - GetProcTable().ASurfaceTransaction_setColor(transaction_.get(), // + GetProcTable().ASurfaceTransaction_setColor(transaction_.get().tx, // control.GetHandle(), // color.red, // color.green, // @@ -92,7 +105,7 @@ bool SurfaceTransaction::SetParent(const SurfaceControl& control, return false; } GetProcTable().ASurfaceTransaction_reparent( - transaction_.get(), // + transaction_.get().tx, // control.GetHandle(), // new_parent == nullptr ? nullptr : new_parent->GetHandle() // ); diff --git a/engine/src/flutter/impeller/toolkit/android/surface_transaction.h b/engine/src/flutter/impeller/toolkit/android/surface_transaction.h index 83bb09ce19..85fcdcfacd 100644 --- a/engine/src/flutter/impeller/toolkit/android/surface_transaction.h +++ b/engine/src/flutter/impeller/toolkit/android/surface_transaction.h @@ -18,6 +18,25 @@ namespace impeller::android { class SurfaceControl; class HardwareBuffer; +/// @brief A wrapper class that indicates whether a SurfaceTransaction was +/// created by the flutter engine or was borrowed from Java for platform +/// interop. +struct WrappedSurfaceTransaction { + ASurfaceTransaction* tx = nullptr; + + /// Whether this SurfaceTransaction was created by the engine or imported from + /// Java. + bool owned = true; + + constexpr bool operator==(const WrappedSurfaceTransaction& other) const { + return other.tx == tx; + } + + constexpr bool operator!=(const WrappedSurfaceTransaction& other) const { + return !(*this == other); + } +}; + //------------------------------------------------------------------------------ /// @brief A wrapper for ASurfaceTransaction. /// https://developer.android.com/ndk/reference/group/native-activity#asurfacetransaction @@ -48,6 +67,8 @@ class SurfaceTransaction { SurfaceTransaction& operator=(const SurfaceTransaction&) = delete; + explicit SurfaceTransaction(ASurfaceTransaction* transaction); + bool IsValid() const; //---------------------------------------------------------------------------- @@ -119,18 +140,20 @@ class SurfaceTransaction { private: struct UniqueASurfaceTransactionTraits { - static ASurfaceTransaction* InvalidValue() { return nullptr; } + static WrappedSurfaceTransaction InvalidValue() { return {}; } - static bool IsValid(ASurfaceTransaction* value) { - return value != InvalidValue(); + static bool IsValid(const WrappedSurfaceTransaction& value) { + return value.tx != nullptr; } - static void Free(ASurfaceTransaction* value) { - GetProcTable().ASurfaceTransaction_delete(value); + static void Free(const WrappedSurfaceTransaction& value) { + if (value.owned && value.tx) { + GetProcTable().ASurfaceTransaction_delete(value.tx); + } } }; - fml::UniqueObject + fml::UniqueObject transaction_; };