diff options
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 108 | ||||
| -rw-r--r-- | core/jni/android_graphics_BLASTBufferQueue.cpp | 65 | ||||
| -rw-r--r-- | graphics/java/android/graphics/BLASTBufferQueue.java | 23 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/WindowManagerService.java | 2 |
4 files changed, 180 insertions, 18 deletions
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 52ce5e709990..ecba6156df57 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -239,6 +239,7 @@ public final class ViewRootImpl implements ViewParent, private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV; private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV; private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV; + private static final boolean DEBUG_BLAST = false || LOCAL_LOGV; /** * Set to false if we do not want to use the multi threaded renderer even though @@ -722,6 +723,11 @@ public final class ViewRootImpl implements ViewParent, // (e.g. SurfaceView) private boolean mSendNextFrameToWm = false; + // Keeps track of whether a traverse was triggered while the UI thread was paused. This can + // occur when the client is waiting on another process to submit the transaction that contains + // the buffer. The UI thread needs to wait on the callback before it can submit another buffer. + private boolean mRequestedTraverseWhilePaused = false; + private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks; /** @@ -1527,7 +1533,7 @@ public final class ViewRootImpl implements ViewParent, mForceNextWindowRelayout = forceNextWindowRelayout; mPendingAlwaysConsumeSystemBars = args.argi2 != 0; - if (msg == MSG_RESIZED_REPORT) { + if (msg == MSG_RESIZED_REPORT && !mSendNextFrameToWm) { reportNextDraw(); } @@ -2405,8 +2411,26 @@ public final class ViewRootImpl implements ViewParent, host.debug(); } - if (host == null || !mAdded) + if (host == null || !mAdded) { return; + } + + // This is to ensure we don't end up queueing new frames while waiting on a previous frame + // to get latched. This can happen when there's been a sync request for this window. The + // frame could be in a transaction that's passed to different processes to ensure + // synchronization. It continues to block until ViewRootImpl receives a callback that the + // transaction containing the buffer has been sent to SurfaceFlinger. Once we receive, that + // signal, we know it's safe to start queuing new buffers. + // + // When the callback is invoked, it will trigger a traversal request if + // mRequestedTraverseWhilePaused is set so there's no need to attempt a retry here. + if (mSendNextFrameToWm) { + if (DEBUG_BLAST) { + Log.w(mTag, "Can't perform draw while waiting for a transaction complete"); + } + mRequestedTraverseWhilePaused = true; + return; + } mIsInTraversal = true; mWillDrawSoon = true; @@ -3148,6 +3172,9 @@ public final class ViewRootImpl implements ViewParent, reportNextDraw(); } if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC) != 0) { + if (DEBUG_BLAST) { + Log.d(mTag, "Relayout called with blastSync"); + } reportNextDraw(); setUseBLASTSyncTransaction(); mSendNextFrameToWm = true; @@ -3813,6 +3840,9 @@ public final class ViewRootImpl implements ViewParent, mDrawsNeededToReport--; if (mDrawsNeededToReport == 0) { reportDrawFinished(); + } else if (DEBUG_BLAST) { + Log.d(mTag, "pendingDrawFinished. Waiting on draw reported mDrawsNeededToReport=" + + mDrawsNeededToReport); } } @@ -3822,6 +3852,9 @@ public final class ViewRootImpl implements ViewParent, private void reportDrawFinished() { try { + if (DEBUG_BLAST) { + Log.d(mTag, "reportDrawFinished"); + } mDrawsNeededToReport = 0; mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction); } catch (RemoteException e) { @@ -3837,6 +3870,9 @@ public final class ViewRootImpl implements ViewParent, return frameNr -> { mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frameNr); + if (DEBUG_BLAST) { + Log.d(mTag, "Received frameCompleteCallback frameNum=" + frameNr); + } // Use a new transaction here since mRtBLASTSyncTransaction can only be accessed by // the render thread and mSurfaceChangedTransaction can only be accessed by the UI // thread. The temporary transaction is used so mRtBLASTSyncTransaction can be merged @@ -3870,6 +3906,13 @@ public final class ViewRootImpl implements ViewParent, || (commitCallbacks != null && commitCallbacks.size() > 0) || mBlurRegionAggregator.hasRegions(); if (needFrameCompleteCallback) { + if (DEBUG_BLAST) { + Log.d(mTag, "Creating frameCompleteCallback" + + " mNextDrawUseBLASTSyncTransaction=" + mNextDrawUseBLASTSyncTransaction + + " mReportNextDraw=" + mReportNextDraw + + " commitCallbacks size=" + + (commitCallbacks == null ? 0 : commitCallbacks.size())); + } mAttachInfo.mThreadedRenderer.setFrameCompleteCallback( createFrameCompleteCallback(mAttachInfo.mHandler, mReportNextDraw, commitCallbacks)); @@ -3881,27 +3924,61 @@ public final class ViewRootImpl implements ViewParent, /** * The callback will run on a worker thread pool from the render thread. */ - private HardwareRenderer.FrameDrawingCallback createFrameDrawingCallback() { + private HardwareRenderer.FrameDrawingCallback createFrameDrawingCallback( + boolean addTransactionComplete) { return frame -> { + if (DEBUG_BLAST) { + Log.d(mTag, "Received frameDrawingCallback frameNum=" + frame + "." + + " Creating transactionCompleteCallback=" + addTransactionComplete); + } mRtNextFrameReportedConsumeWithBlast = true; - if (mBlastBufferQueue != null) { - // We don't need to synchronize mRtBLASTSyncTransaction here since it's not - // being modified and only sent to BlastBufferQueue. - mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction); + if (mBlastBufferQueue == null) { + return; } + + // We don't need to synchronize mRtBLASTSyncTransaction here since it's not + // being modified and only sent to BlastBufferQueue. + mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction); + if (!addTransactionComplete) { + return; + } + + mBlastBufferQueue.setTransactionCompleteCallback(frame, frameNumber -> { + if (DEBUG_BLAST) { + Log.d(mTag, "Received transactionCompleteCallback frameNum=" + frame); + } + mHandler.postAtFrontOfQueue(() -> { + mSendNextFrameToWm = false; + if (DEBUG_BLAST) { + Log.d(mTag, "Scheduling a traversal=" + mRequestedTraverseWhilePaused + + " due to a previous skipped traversal."); + } + if (mRequestedTraverseWhilePaused) { + mRequestedTraverseWhilePaused = false; + scheduleTraversals(); + } + }); + }); }; } private void addFrameCallbackIfNeeded() { - // Frame callbacks will always occur after submitting draw requests and before - // the draw actually occurs. This will ensure that we set the next transaction - // for the frame that's about to get drawn and not on a previous frame that. - // - // This is thread safe since mRtNextFrameReportConsumeWithBlast will only be - // modified in onFrameDraw and then again in onFrameComplete. This is to ensure the - // next frame completed should be reported with the blast sync transaction. + if (DEBUG_BLAST) { + if (mNextDrawUseBLASTSyncTransaction || mReportNextDraw) { + Log.d(mTag, "Creating frameDrawingCallback mNextDrawUseBLASTSyncTransaction=" + + mNextDrawUseBLASTSyncTransaction + " mReportNextDraw=" + mReportNextDraw); + } + } + if (mNextDrawUseBLASTSyncTransaction) { - registerRtFrameCallback(createFrameDrawingCallback()); + // Frame callbacks will always occur after submitting draw requests and before + // the draw actually occurs. This will ensure that we set the next transaction + // for the frame that's about to get drawn and not on a previous frame that. + // + // This is thread safe since mRtNextFrameReportConsumeWithBlast will only be + // modified in onFrameDraw and then again in onFrameComplete. This is to ensure the + // next frame completed should be reported with the blast sync transaction. + registerRtFrameCallback(createFrameDrawingCallback(mSendNextFrameToWm)); mNextDrawUseBLASTSyncTransaction = false; } else if (mReportNextDraw) { registerRtFrameCallback(frame -> { @@ -9956,7 +10033,6 @@ public final class ViewRootImpl implements ViewParent, private void finishBLASTSyncOnRT(boolean apply, Transaction t) { // This is safe to modify on the render thread since the only other place it's modified // is on the UI thread when the render thread is paused. - mSendNextFrameToWm = false; if (mRtNextFrameReportedConsumeWithBlast) { mRtNextFrameReportedConsumeWithBlast = false; diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp index 3e87cb5003f6..66a17c390828 100644 --- a/core/jni/android_graphics_BLASTBufferQueue.cpp +++ b/core/jni/android_graphics_BLASTBufferQueue.cpp @@ -26,9 +26,47 @@ #include <gui/BLASTBufferQueue.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> +#include "core_jni_helpers.h" namespace android { +struct { + jmethodID onTransactionComplete; +} gTransactionCompleteCallback; + +class TransactionCompleteCallbackWrapper : public LightRefBase<TransactionCompleteCallbackWrapper> { +public: + explicit TransactionCompleteCallbackWrapper(JNIEnv* env, jobject jobject) { + env->GetJavaVM(&mVm); + mTransactionCompleteObject = env->NewGlobalRef(jobject); + LOG_ALWAYS_FATAL_IF(!mTransactionCompleteObject, "Failed to make global ref"); + } + + ~TransactionCompleteCallbackWrapper() { + if (mTransactionCompleteObject) { + getenv()->DeleteGlobalRef(mTransactionCompleteObject); + mTransactionCompleteObject = nullptr; + } + } + + void onTransactionComplete(int64_t frameNr) { + if (mTransactionCompleteObject) { + getenv()->CallVoidMethod(mTransactionCompleteObject, + gTransactionCompleteCallback.onTransactionComplete, frameNr); + } + } + +private: + JavaVM* mVm; + jobject mTransactionCompleteObject; + + JNIEnv* getenv() { + JNIEnv* env; + mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); + return env; + } +}; + static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName, jlong surfaceControl, jlong width, jlong height, jboolean enableTripleBuffering) { String8 str8; @@ -76,20 +114,45 @@ static void nativeFlushShadowQueue(JNIEnv* env, jclass clazz, jlong ptr) { queue->flushShadowQueue(); } +static void nativeSetTransactionCompleteCallback(JNIEnv* env, jclass clazz, jlong ptr, + jlong frameNumber, + jobject transactionCompleteCallback) { + sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr); + if (transactionCompleteCallback == nullptr) { + queue->setTransactionCompleteCallback(frameNumber, nullptr); + } else { + sp<TransactionCompleteCallbackWrapper> wrapper = + new TransactionCompleteCallbackWrapper{env, transactionCompleteCallback}; + queue->setTransactionCompleteCallback(frameNumber, [wrapper](int64_t frameNr) { + wrapper->onTransactionComplete(frameNr); + }); + } +} + static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ + // clang-format off {"nativeCreate", "(Ljava/lang/String;JJJZ)J", (void*)nativeCreate}, {"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface}, {"nativeDestroy", "(J)V", (void*)nativeDestroy}, {"nativeSetNextTransaction", "(JJ)V", (void*)nativeSetNextTransaction}, {"nativeUpdate", "(JJJJ)V", (void*)nativeUpdate}, - {"nativeFlushShadowQueue", "(J)V", (void*)nativeFlushShadowQueue}}; + {"nativeFlushShadowQueue", "(J)V", (void*)nativeFlushShadowQueue}, + {"nativeSetTransactionCompleteCallback", + "(JJLandroid/graphics/BLASTBufferQueue$TransactionCompleteCallback;)V", + (void*)nativeSetTransactionCompleteCallback} + // clang-format on +}; 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 transactionCompleteClass = + FindClassOrDie(env, "android/graphics/BLASTBufferQueue$TransactionCompleteCallback"); + gTransactionCompleteCallback.onTransactionComplete = + GetMethodIDOrDie(env, transactionCompleteClass, "onTransactionComplete", "(J)V"); return 0; } diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java index 4309ab24cc22..be40dc61ce67 100644 --- a/graphics/java/android/graphics/BLASTBufferQueue.java +++ b/graphics/java/android/graphics/BLASTBufferQueue.java @@ -34,6 +34,19 @@ public final class BLASTBufferQueue { private static native void nativeSetNextTransaction(long ptr, long transactionPtr); private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height); private static native void nativeFlushShadowQueue(long ptr); + private static native void nativeSetTransactionCompleteCallback(long ptr, long frameNumber, + TransactionCompleteCallback callback); + + /** + * Callback sent to {@link #setTransactionCompleteCallback(long, TransactionCompleteCallback)} + */ + public interface TransactionCompleteCallback { + /** + * Invoked when the transaction has completed. + * @param frameNumber The frame number of the buffer that was in that transaction + */ + void onTransactionComplete(long frameNumber); + } /** Create a new connection with the surface flinger. */ public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height, @@ -74,6 +87,16 @@ public final class BLASTBufferQueue { nativeUpdate(mNativeObject, sc.mNativeObject, width, height); } + /** + * Set a callback when the transaction with the frame number has been completed. + * @param frameNumber The frame number to get the transaction complete callback for + * @param completeCallback The callback that should be invoked. + */ + public void setTransactionCompleteCallback(long frameNumber, + @Nullable TransactionCompleteCallback completeCallback) { + nativeSetTransactionCompleteCallback(mNativeObject, frameNumber, completeCallback); + } + @Override protected void finalize() throws Throwable { try { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7e52467631e7..7794f2399cb2 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2202,7 +2202,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mPendingPositionChanged = null; } - if (mUseBLASTSync && win.useBLASTSync()) { + if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE) { result |= RELAYOUT_RES_BLAST_SYNC; } |