From e12e51892aee86b3ca4e7e268afed63006215010 Mon Sep 17 00:00:00 2001 From: chaviw Date: Tue, 8 Feb 2022 11:19:37 -0600 Subject: [PATCH] Add gatherPendingTransactions in BBQ Instead of applying the pending transactions when a frame wasn't rendered, we gather the transactions and merge them with the transaction that will be used to sync. This is to ensure these frames are sent to the caller that requested the sync so they can ensure it's applied at the correct time. Test: Builds and run Bug: 200284684 Change-Id: I087c67138f31cc93e79df42c29464ab4f7989d52 --- core/java/android/view/SurfaceControl.java | 10 +++++++--- core/java/android/view/ViewRootImpl.java | 11 +++++++---- .../jni/android_graphics_BLASTBufferQueue.cpp | 19 +++++++++++++++++++ .../android/graphics/BLASTBufferQueue.java | 15 +++++++++++++++ 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 904d7c82959b7..2124b0c5c9b09 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -2730,9 +2730,13 @@ public final class SurfaceControl implements Parcelable { * is allowed as a convenience. */ public Transaction() { - mNativeObject = nativeCreateTransaction(); - mFreeNativeResources - = sRegistry.registerNativeAllocation(this, mNativeObject); + this(nativeCreateTransaction()); + } + + private Transaction(long nativeObject) { + mNativeObject = nativeObject; + mFreeNativeResources = + sRegistry.registerNativeAllocation(this, mNativeObject); } private Transaction(Parcel in) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 386b277156e34..fb4f6280de0b0 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -4159,19 +4159,22 @@ public final class ViewRootImpl implements ViewParent, + " didProduceBuffer=" + didProduceBuffer); } + Transaction tmpTransaction = new Transaction(); + tmpTransaction.merge(mRtBLASTSyncTransaction); + // If frame wasn't drawn, clear out the next transaction so it doesn't affect the next // draw attempt. The next transaction and transaction complete callback were only set // for the current draw attempt. if (!didProduceBuffer) { mBlastBufferQueue.setSyncTransaction(null); - // Apply the transactions that were sent to mergeWithNextTransaction since the + // Get the transactions that were sent to mergeWithNextTransaction since the // frame didn't draw on this vsync. It's possible the frame will draw later, but // it's better to not be sync than to block on a frame that may never come. - mBlastBufferQueue.applyPendingTransactions(mRtLastAttemptedDrawFrameNum); + Transaction pendingTransactions = mBlastBufferQueue.gatherPendingTransactions( + mRtLastAttemptedDrawFrameNum); + tmpTransaction.merge(pendingTransactions); } - Transaction tmpTransaction = new Transaction(); - tmpTransaction.merge(mRtBLASTSyncTransaction); // Post at front of queue so the buffer can be processed immediately and allow RT // to continue processing new buffers. If RT tries to process buffers before the sync // buffer is applied, the new buffers will not get acquired and could result in a diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp index 55f136997aad5..4f13a9cf257eb 100644 --- a/core/jni/android_graphics_BLASTBufferQueue.cpp +++ b/core/jni/android_graphics_BLASTBufferQueue.cpp @@ -30,6 +30,11 @@ namespace android { +static struct { + jclass clazz; + jmethodID ctor; +} gTransactionClassInfo; + static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName) { ScopedUtfChars name(env, jName); sp queue = new BLASTBufferQueue(name.c_str()); @@ -86,6 +91,14 @@ static bool nativeIsSameSurfaceControl(JNIEnv* env, jclass clazz, jlong ptr, jlo return queue->isSameSurfaceControl(reinterpret_cast(surfaceControl)); } +static jobject nativeGatherPendingTransactions(JNIEnv* env, jclass clazz, jlong ptr, + jlong frameNum) { + sp queue = reinterpret_cast(ptr); + SurfaceComposerClient::Transaction* transaction = queue->gatherPendingTransactions(frameNum); + return env->NewObject(gTransactionClassInfo.clazz, gTransactionClassInfo.ctor, + reinterpret_cast(transaction)); +} + static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ // clang-format off @@ -98,6 +111,7 @@ static const JNINativeMethod gMethods[] = { {"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum}, {"nativeApplyPendingTransactions", "(JJ)V", (void*)nativeApplyPendingTransactions}, {"nativeIsSameSurfaceControl", "(JJ)Z", (void*)nativeIsSameSurfaceControl}, + {"nativeGatherPendingTransactions", "(JJ)Landroid/view/SurfaceControl$Transaction;", (void*)nativeGatherPendingTransactions} // clang-format on }; @@ -105,6 +119,11 @@ int register_android_graphics_BLASTBufferQueue(JNIEnv* env) { int res = jniRegisterNativeMethods(env, "android/graphics/BLASTBufferQueue", gMethods, NELEM(gMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods."); + + jclass transactionClazz = FindClassOrDie(env, "android/view/SurfaceControl$Transaction"); + gTransactionClassInfo.clazz = MakeGlobalRefOrDie(env, transactionClazz); + gTransactionClassInfo.ctor = + GetMethodIDOrDie(env, gTransactionClassInfo.clazz, "", "(J)V"); return 0; } diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java index a9e730d58e65e..2678c79d14542 100644 --- a/graphics/java/android/graphics/BLASTBufferQueue.java +++ b/graphics/java/android/graphics/BLASTBufferQueue.java @@ -39,6 +39,8 @@ public final class BLASTBufferQueue { private static native long nativeGetLastAcquiredFrameNum(long ptr); private static native void nativeApplyPendingTransactions(long ptr, long frameNumber); private static native boolean nativeIsSameSurfaceControl(long ptr, long surfaceControlPtr); + private static native SurfaceControl.Transaction nativeGatherPendingTransactions(long ptr, + long frameNumber); /** Create a new connection with the surface flinger. */ public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height, @@ -159,4 +161,17 @@ public final class BLASTBufferQueue { public boolean isSameSurfaceControl(SurfaceControl sc) { return nativeIsSameSurfaceControl(mNativeObject, sc.mNativeObject); } + + /** + * Get any transactions that were passed to {@link #mergeWithNextTransaction} with the + * specified frameNumber. This is intended to ensure transactions don't get stuck as pending + * if the specified frameNumber is never drawn. + * + * @param frameNumber The frameNumber used to determine which transactions to apply. + * @return a Transaction that contains the merge of all the transactions that were sent to + * mergeWithNextTransaction + */ + public SurfaceControl.Transaction gatherPendingTransactions(long frameNumber) { + return nativeGatherPendingTransactions(mNativeObject, frameNumber); + } }