diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 1ddb043153abc..ba436e16288e7 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -227,6 +227,11 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall */ private final SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction(); + /** + * Used on the main thread to set the transaction that will be synced with the main window. + */ + private final Transaction mSyncTransaction = new Transaction(); + /** * Transaction that should be used whe * {@link HardwareRenderer.FrameDrawingCallback#onFrameDraw} is invoked. All @@ -496,7 +501,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } - private void performDrawFinished() { + private void performDrawFinished(Transaction t) { + mSyncTransaction.merge(t); if (mDeferredDestroySurfaceControl != null) { synchronized (mSurfaceControlLock) { mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply(); @@ -521,7 +527,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall void notifyDrawFinished() { ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot != null) { - viewRoot.pendingDrawFinished(); + viewRoot.pendingDrawFinished(mSyncTransaction); } mPendingReportDraws--; } @@ -1202,10 +1208,17 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall callbacks = getSurfaceCallbacks(); } + final Transaction t = new Transaction(); + if (viewRoot.wasRelayoutRequested()) { + mBlastBufferQueue.setSyncTransaction(t, + false /* acquireSingleBuffer */); + } mPendingReportDraws++; viewRoot.drawPending(); - SurfaceCallbackHelper sch = - new SurfaceCallbackHelper(this::onDrawFinished); + SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> { + mBlastBufferQueue.setSyncTransaction(null); + onDrawFinished(t); + }); sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); } } @@ -1367,13 +1380,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mSurfaceHeight, mFormat); } - private void onDrawFinished() { + private void onDrawFinished(Transaction t) { if (DEBUG) { Log.i(TAG, System.identityHashCode(this) + " " + "finishedDrawing"); } - runOnUiThread(this::performDrawFinished); + runOnUiThread(() -> performDrawFinished(t)); } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 8f25902bd6424..1e2895d3de66d 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -532,6 +532,11 @@ public final class ViewRootImpl implements ViewParent, boolean mPerformContentCapture; boolean mReportNextDraw; + /** + * Set if the reportDraw was requested from WM. If just a local report draw was invoked, there's + * no need to report back to system server and can just apply immediately on the client. + */ + boolean mReportDrawToWm; boolean mFullRedrawNeeded; boolean mNewSurfaceNeeded; boolean mForceNextWindowRelayout; @@ -754,6 +759,8 @@ public final class ViewRootImpl implements ViewParent, */ private int mSurfaceSequenceId = 0; + private boolean mRelayoutRequested; + private String mTag = TAG; public ViewRootImpl(Context context, Display display) { @@ -3311,6 +3318,7 @@ public final class ViewRootImpl implements ViewParent, } mIsInTraversal = false; + mRelayoutRequested = false; } private void notifyContentCatpureEvents() { @@ -3941,10 +3949,18 @@ public final class ViewRootImpl implements ViewParent, mDrawsNeededToReport++; } - void pendingDrawFinished() { + void pendingDrawFinished(Transaction t) { if (mDrawsNeededToReport == 0) { throw new RuntimeException("Unbalanced drawPending/pendingDrawFinished calls"); } + + if (t != null) { + if (DEBUG_BLAST) { + Log.d(mTag, "Merging transaction into main window transaction"); + } + mSurfaceChangedTransaction.merge(t); + } + mDrawsNeededToReport--; if (mDrawsNeededToReport == 0) { reportDrawFinished(); @@ -3954,17 +3970,31 @@ public final class ViewRootImpl implements ViewParent, } } + void pendingDrawFinished() { + pendingDrawFinished(null); + } + private void postDrawFinished() { mHandler.sendEmptyMessage(MSG_DRAW_FINISHED); } private void reportDrawFinished() { - try { + if (DEBUG_BLAST) { + Log.d(mTag, "reportDrawFinished"); + } + mDrawsNeededToReport = 0; + + if (!mReportDrawToWm) { if (DEBUG_BLAST) { - Log.d(mTag, "reportDrawFinished"); + Log.d(mTag, "No need to report finishDrawing. Apply immediately"); } - mDrawsNeededToReport = 0; + mSurfaceChangedTransaction.apply(); + return; + } + + try { mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction); + mReportDrawToWm = false; } catch (RemoteException e) { Log.e(mTag, "Unable to report draw finished", e); mSurfaceChangedTransaction.apply(); @@ -7756,6 +7786,7 @@ public final class ViewRootImpl implements ViewParent, private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending) throws RemoteException { + mRelayoutRequested = true; float appScale = mAttachInfo.mApplicationScale; boolean restore = false; if (params != null && mTranslator != null) { @@ -9573,6 +9604,7 @@ public final class ViewRootImpl implements ViewParent, if (mReportNextDraw == false) { drawPending(); } + mReportDrawToWm = true; mReportNextDraw = true; } @@ -10501,4 +10533,8 @@ public final class ViewRootImpl implements ViewParent, mBLASTDrawConsumer = consume; return true; } + + boolean wasRelayoutRequested() { + return mRelayoutRequested; + } } diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp index e7b3fba961e6e..a059dd6e52e2e 100644 --- a/core/jni/android_graphics_BLASTBufferQueue.cpp +++ b/core/jni/android_graphics_BLASTBufferQueue.cpp @@ -61,10 +61,11 @@ static jobject nativeGetSurface(JNIEnv* env, jclass clazz, jlong ptr, queue->getSurface(includeSurfaceControlHandle)); } -static void nativeSetSyncTransaction(JNIEnv* env, jclass clazz, jlong ptr, jlong transactionPtr) { +static void nativeSetSyncTransaction(JNIEnv* env, jclass clazz, jlong ptr, jlong transactionPtr, + jboolean acquireSingleBuffer) { sp queue = reinterpret_cast(ptr); auto transaction = reinterpret_cast(transactionPtr); - queue->setSyncTransaction(transaction); + queue->setSyncTransaction(transaction, acquireSingleBuffer); } static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width, @@ -98,7 +99,7 @@ static const JNINativeMethod gMethods[] = { {"nativeCreate", "(Ljava/lang/String;JJJI)J", (void*)nativeCreate}, {"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface}, {"nativeDestroy", "(J)V", (void*)nativeDestroy}, - {"nativeSetSyncTransaction", "(JJ)V", (void*)nativeSetSyncTransaction}, + {"nativeSetSyncTransaction", "(JJZ)V", (void*)nativeSetSyncTransaction}, {"nativeUpdate", "(JJJJIJ)V", (void*)nativeUpdate}, {"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction}, {"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum}, diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java index 405f66dd5d561..8844370f9b4fb 100644 --- a/graphics/java/android/graphics/BLASTBufferQueue.java +++ b/graphics/java/android/graphics/BLASTBufferQueue.java @@ -31,7 +31,8 @@ public final class BLASTBufferQueue { long height, int format); private static native void nativeDestroy(long ptr); private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle); - private static native void nativeSetSyncTransaction(long ptr, long transactionPtr); + private static native void nativeSetSyncTransaction(long ptr, long transactionPtr, + boolean acquireSingleBuffer); private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height, int format, long transactionPtr); private static native void nativeMergeWithNextTransaction(long ptr, long transactionPtr, @@ -66,12 +67,25 @@ public final class BLASTBufferQueue { } /** - * Send the transaction to BBQ so the next frame can be added and not applied immediately. - * This gives the caller a chance to apply the transaction when it's ready. - * @param t The transaction to add the frame to. This can be null to clear the transaction. + * Send the transaction to BBQ so the next frame can be added and not applied immediately. This + * gives the caller a chance to apply the transaction when it's ready. + * + * @param t The transaction to add the frame to. This can be null to clear the + * transaction. + * @param acquireSingleBuffer If true, only acquire a single buffer when processing frames. The + * transaction will be cleared once a single buffer has been + * acquired. If false, continue to acquire all buffers into the + * transaction until setSyncTransaction is called again with a null + * transaction. */ + public void setSyncTransaction(@Nullable SurfaceControl.Transaction t, + boolean acquireSingleBuffer) { + nativeSetSyncTransaction(mNativeObject, t == null ? 0 : t.mNativeObject, + acquireSingleBuffer); + } + public void setSyncTransaction(@Nullable SurfaceControl.Transaction t) { - nativeSetSyncTransaction(mNativeObject, t == null ? 0 : t.mNativeObject); + setSyncTransaction(t, true /* acquireSingleBuffer */); } /**