diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 406281d4cade4..a13579d0acad1 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -401,7 +401,7 @@ public class SurfaceControlViewHost { public void relayout(WindowManager.LayoutParams attrs, WindowlessWindowManager.ResizeCompleteCallback callback) { mViewRoot.setLayoutParams(attrs, false); - mViewRoot.setReportNextDraw(true /* syncBuffer */); + mViewRoot.setReportNextDraw(); mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback); } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 22ccaae9e3c3c..413855639d09a 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -50,7 +50,6 @@ import android.view.accessibility.IAccessibilityEmbeddedConnection; import com.android.internal.view.SurfaceCallbackHelper; import java.util.ArrayList; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; @@ -204,12 +203,19 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall private int mSurfaceFlags = SurfaceControl.HIDDEN; + private int mPendingReportDraws; + /** * Transaction that should be used from the render thread. This transaction is only thread safe * with other calls directly from the render thread. */ 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 @@ -385,12 +391,31 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } - private void performDrawFinished() { - mDrawFinished = true; - if (mAttachedToWindow) { - mParent.requestTransparentRegion(SurfaceView.this); - invalidate(); + private void performDrawFinished(@Nullable Transaction t) { + if (t != null) { + mSyncTransaction.merge(t); } + + if (mPendingReportDraws > 0) { + mDrawFinished = true; + if (mAttachedToWindow) { + mParent.requestTransparentRegion(SurfaceView.this); + notifyDrawFinished(); + invalidate(); + } + } else { + Log.e(TAG, System.identityHashCode(this) + "finished drawing" + + " but no pending report draw (extra call" + + " to draw completion runnable?)"); + } + } + + void notifyDrawFinished() { + ViewRootImpl viewRoot = getViewRootImpl(); + if (viewRoot != null) { + viewRoot.pendingDrawFinished(mSyncTransaction); + } + mPendingReportDraws--; } @Override @@ -413,6 +438,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mGlobalListenersAdded = false; } + while (mPendingReportDraws > 0) { + notifyDrawFinished(); + } + mRequestedVisible = false; updateSurface(); @@ -964,17 +993,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall return; } - final boolean redrawNeeded = sizeChanged || creating || hintChanged - || (mVisible && !mDrawFinished); - final TransactionCallback transactionCallback = - redrawNeeded ? new TransactionCallback() : null; - if (redrawNeeded && viewRoot.wasRelayoutRequested()) { - mBlastBufferQueue.syncNextTransaction( - false /* acquireSingleBuffer */, - transactionCallback::onTransactionReady); - } final boolean realSizeChanged = performSurfaceTransaction(viewRoot, translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction); + final boolean redrawNeeded = sizeChanged || creating || hintChanged + || (mVisible && !mDrawFinished); try { SurfaceHolder.Callback[] callbacks = null; @@ -993,7 +1015,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mIsCreating = true; if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "visibleChanged -- surfaceCreated"); - callbacks = getSurfaceCallbacks(); + if (callbacks == null) { + callbacks = getSurfaceCallbacks(); + } for (SurfaceHolder.Callback c : callbacks) { c.surfaceCreated(mSurfaceHolder); } @@ -1011,7 +1035,32 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } if (redrawNeeded) { - redrawNeeded(callbacks, transactionCallback); + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + + "surfaceRedrawNeeded"); + if (callbacks == null) { + callbacks = getSurfaceCallbacks(); + } + + final boolean wasRelayoutRequested = viewRoot.wasRelayoutRequested(); + if (wasRelayoutRequested && (mBlastBufferQueue != null)) { + mBlastBufferQueue.syncNextTransaction( + false /* acquireSingleBuffer */, + this::onDrawFinished); + } + mPendingReportDraws++; + viewRoot.drawPending(); + SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> { + if (mBlastBufferQueue != null) { + mBlastBufferQueue.stopContinuousSyncTransaction(); + } + // If relayout was requested, then a callback from BBQ will + // be invoked with the sync transaction. onDrawFinished will be + // called in there + if (!wasRelayoutRequested) { + onDrawFinished(null); + } + }); + sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); } } } finally { @@ -1030,64 +1079,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } - private void redrawNeeded(SurfaceHolder.Callback[] callbacks, - @Nullable TransactionCallback transactionCallback) { - if (DEBUG) { - Log.i(TAG, System.identityHashCode(this) + " surfaceRedrawNeeded"); - } - final SurfaceHolder.Callback[] capturedCallbacks = - callbacks == null ? getSurfaceCallbacks() : callbacks; - - ViewRootImpl viewRoot = getViewRootImpl(); - boolean isVriSync = viewRoot.addToSync(syncBufferCallback -> - redrawNeededAsync(capturedCallbacks, () -> { - if (mBlastBufferQueue != null) { - mBlastBufferQueue.stopContinuousSyncTransaction(); - } - - Transaction t = null; - if (transactionCallback != null && mBlastBufferQueue != null) { - t = transactionCallback.waitForTransaction(); - } - // If relayout was requested, then a callback from BBQ will - // be invoked with the sync transaction. onDrawFinished will be - // called in there - syncBufferCallback.onBufferReady(t); - onDrawFinished(); - })); - - // If isVriSync, then everything was setup in the addToSync. - if (isVriSync) { - return; - } - - redrawNeededAsync(capturedCallbacks, this::onDrawFinished); - } - - private void redrawNeededAsync(SurfaceHolder.Callback[] callbacks, - Runnable callbacksCollected) { - SurfaceCallbackHelper sch = new SurfaceCallbackHelper(callbacksCollected); - sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); - } - - private static class TransactionCallback { - private final CountDownLatch mCountDownLatch = new CountDownLatch(1); - private Transaction mTransaction; - - Transaction waitForTransaction() { - try { - mCountDownLatch.await(); - } catch (InterruptedException e) { - } - return mTransaction; - } - - void onTransactionReady(Transaction t) { - mTransaction = t; - mCountDownLatch.countDown(); - } - } - /** * Copy the Surface from the SurfaceControl or the blast adapter. * @@ -1198,13 +1189,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat); } - private void onDrawFinished() { + private void onDrawFinished(@Nullable 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 d15b2a457bfb1..76d360cc9b2ca 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -582,15 +582,11 @@ public final class ViewRootImpl implements ViewParent, boolean mReportNextDraw; - /** - * Set whether the draw should send the buffer to system server. When set to true, VRI will - * create a sync transaction with BBQ and send the resulting buffer to system server. If false, - * VRI will not try to sync a buffer in BBQ, but still report when a draw occurred. - * - * Default is true since we normally want to sync the buffer. + * Set whether the draw should use blast sync. This is in case the draw is canceled, + * but will be rescheduled. We still want the next draw to be sync. */ - private boolean mSyncBuffer = true; + boolean mNextDrawUseBlastSync; boolean mFullRedrawNeeded; boolean mNewSurfaceNeeded; @@ -811,10 +807,6 @@ public final class ViewRootImpl implements ViewParent, return mHandwritingInitiator; } - private final SurfaceSyncer mSurfaceSyncer = new SurfaceSyncer(); - private int mLastSyncId = -1; - private SurfaceSyncer.SyncBufferCallback mSyncBufferCallback; - /** * Keeps track of the last frame number that was attempted to draw. Should only be accessed on * the RenderThread. @@ -2893,6 +2885,8 @@ public final class ViewRootImpl implements ViewParent, mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance); } } + final boolean wasReportNextDraw = mReportNextDraw; + boolean useBlastSync = mNextDrawUseBlastSync; if (mFirst || windowShouldResize || viewVisibilityChanged || params != null || mForceNextWindowRelayout) { @@ -2931,6 +2925,9 @@ public final class ViewRootImpl implements ViewParent, Log.d(mTag, "Relayout called with blastSync"); } reportNextDraw(); + if (isHardwareEnabled()) { + useBlastSync = true; + } } final boolean surfaceControlChanged = @@ -3166,7 +3163,7 @@ public final class ViewRootImpl implements ViewParent, // done to achieve a more hermetic fix for S, but it's entirely // possible that checking the most recent value is actually more // correct here. - if (!mStopped || mReportNextDraw) { + if (!mStopped || wasReportNextDraw) { if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight() || dispatchApplyInsets || updatedConfiguration) { int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width, @@ -3235,7 +3232,7 @@ public final class ViewRootImpl implements ViewParent, prepareSurfaces(); } - final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); + final boolean didLayout = layoutRequested && (!mStopped || wasReportNextDraw); boolean triggerGlobalLayoutListener = didLayout || mAttachInfo.mRecomputeGlobalAttributes; if (didLayout) { @@ -3428,40 +3425,51 @@ public final class ViewRootImpl implements ViewParent, mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes); - // If we already got a request for blast sync, then we don't want to unset mSyncBuffer - if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0 - && !mReportNextDraw) { + // Remember if we must report the next draw. + if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { reportNextDraw(); - mSyncBuffer = false; } - boolean cancelAndRedraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw(); - if (!cancelAndRedraw) { - createSyncIfNeeded(); + boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; + if (mBLASTDrawConsumer != null) { + useBlastSync = true; } - if (!isViewVisible) { - if (mPendingTransitions != null && mPendingTransitions.size() > 0) { - for (int i = 0; i < mPendingTransitions.size(); ++i) { - mPendingTransitions.get(i).endChangingAnimations(); - } - mPendingTransitions.clear(); - } - - if (mSyncBufferCallback != null) { - mSyncBufferCallback.onBufferReady(null); - } - } else if (cancelAndRedraw) { - // Try again - scheduleTraversals(); - } else { + if (!cancelDraw) { if (mPendingTransitions != null && mPendingTransitions.size() > 0) { for (int i = 0; i < mPendingTransitions.size(); ++i) { mPendingTransitions.get(i).startChangingAnimations(); } mPendingTransitions.clear(); } - performDraw(); + performDraw(useBlastSync); + mNextDrawUseBlastSync = false; + } else { + if (isViewVisible) { + // Try again + mNextDrawUseBlastSync = useBlastSync; + scheduleTraversals(); + } else { + if (mPendingTransitions != null && mPendingTransitions.size() > 0) { + for (int i = 0; i < mPendingTransitions.size(); ++i) { + mPendingTransitions.get(i).endChangingAnimations(); + } + mPendingTransitions.clear(); + } + + // We may never draw since it's not visible. Report back that we're finished + // drawing. + if (!wasReportNextDraw && mReportNextDraw) { + mReportNextDraw = false; + pendingDrawFinished(); + } + + // Make sure the consumer is not waiting if the view root was just made invisible. + if (mBLASTDrawConsumer != null) { + mBLASTDrawConsumer.accept(null); + mBLASTDrawConsumer = null; + } + } } if (mAttachInfo.mContentCaptureEvents != null) { @@ -3470,46 +3478,6 @@ public final class ViewRootImpl implements ViewParent, mIsInTraversal = false; mRelayoutRequested = false; - - if (!cancelAndRedraw) { - mReportNextDraw = false; - mSyncBufferCallback = null; - mSyncBuffer = true; - if (mLastSyncId != -1) { - mSurfaceSyncer.markSyncReady(mLastSyncId); - mLastSyncId = -1; - } - } - } - - private void createSyncIfNeeded() { - // Started a sync already. - if (mLastSyncId != -1) { - return; - } - - Consumer syncConsumer = null; - if (mBLASTDrawConsumer != null) { - syncConsumer = mBLASTDrawConsumer; - mBLASTDrawConsumer = null; - } else if (mReportNextDraw) { - syncConsumer = transaction -> { - mSurfaceChangedTransaction.merge(transaction); - reportDrawFinished(); - }; - } - - if (syncConsumer != null) { - final Consumer capturedSyncConsumer = syncConsumer; - mLastSyncId = mSurfaceSyncer.setupSync(transaction -> { - // Callback will be invoked on executor thread so post to main thread. - mHandler.postAtFrontOfQueue(() -> capturedSyncConsumer.accept(transaction)); - }); - if (DEBUG_BLAST) { - Log.d(mTag, "Setup new sync id=" + mLastSyncId); - } - mSurfaceSyncer.addToSync(mLastSyncId, mSyncTarget); - } } private void notifyContentCatpureEvents() { @@ -4123,10 +4091,54 @@ public final class ViewRootImpl implements ViewParent, } } + /** + * A count of the number of calls to pendingDrawFinished we + * require to notify the WM drawing is complete. + */ + int mDrawsNeededToReport = 0; + + /** + * Delay notifying WM of draw finished until + * a balanced call to pendingDrawFinished. + */ + void drawPending() { + mDrawsNeededToReport++; + } + + 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(); + } else if (DEBUG_BLAST) { + Log.d(mTag, "pendingDrawFinished. Waiting on draw reported mDrawsNeededToReport=" + + mDrawsNeededToReport); + } + } + + void pendingDrawFinished() { + pendingDrawFinished(null); + } + + private void postDrawFinished() { + mHandler.sendEmptyMessage(MSG_DRAW_FINISHED); + } + private void reportDrawFinished() { if (DEBUG_BLAST) { - Log.d(mTag, "reportDrawFinished " + Debug.getCallers(5)); + Log.d(mTag, "reportDrawFinished"); } + mDrawsNeededToReport = 0; try { mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, Integer.MAX_VALUE); @@ -4145,14 +4157,6 @@ public final class ViewRootImpl implements ViewParent, return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled(); } - boolean addToSync(SurfaceSyncer.SyncTarget syncable) { - if (mLastSyncId == -1) { - return false; - } - mSurfaceSyncer.addToSync(mLastSyncId, syncable); - return true; - } - private void addFrameCommitCallbackIfNeeded() { if (!isHardwareEnabled()) { return; @@ -4183,81 +4187,188 @@ public final class ViewRootImpl implements ViewParent, }); } + private HardwareRenderer.FrameCommitCallback createFrameCommitCallbackForSync( + boolean useBlastSync, boolean reportNextDraw, Consumer blastSyncConsumer) { + return didProduceBuffer -> { + if (DEBUG_BLAST) { + Log.d(mTag, "Received frameCommittedCallback " + + " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum + + " didProduceBuffer=" + didProduceBuffer); + } + + // 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. + final Transaction pendingTransactions; + if (!didProduceBuffer) { + mBlastBufferQueue.syncNextTransaction(null); + // 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. + pendingTransactions = mBlastBufferQueue.gatherPendingTransactions( + mRtLastAttemptedDrawFrameNum); + if (!useBlastSync && !reportNextDraw) { + pendingTransactions.apply(); + } + } else { + pendingTransactions = null; + } + // 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 + // deadlock. UI thread would wait on RT, but RT would be blocked waiting for a free + // buffer. + mHandler.postAtFrontOfQueue(() -> { + if (!didProduceBuffer && useBlastSync) { + mSurfaceChangedTransaction.merge(pendingTransactions); + if (blastSyncConsumer != null) { + blastSyncConsumer.accept(mSurfaceChangedTransaction); + } + } + + // This is to ensure pendingDrawFinished is only called exactly one time per draw + // attempt when reportNextDraw is true. Since, we sometimes create a sync + // transaction callback, the callback will handle calling pendingDrawFinished. + // However, there are cases where the transaction callback may not be called. + // 1. If useBlastSync is false, then we know that a sync transaction callback was + // not created so we won't invoke pendingDrawFinished there. + // 2. If the draw didn't produce a frame, didProduceBuffer == false, then we know + // the sync transaction callback will not be invoked even if one was set up. + if (reportNextDraw && (!didProduceBuffer || !useBlastSync)) { + pendingDrawFinished(); + } + }); + + }; + } + @Nullable - private void registerFrameDrawingCallbackForBlur() { + private FrameDrawingCallback createFrameDrawingCallbackIfNeeded(boolean useBlastSync, + boolean reportNextDraw) { if (!isHardwareEnabled()) { - return; + return null; } final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates(); final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions(); - if (!needsCallbackForBlur) { - return; + if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw && !mHasPendingTransactions) { + return null; + } + + final Consumer blastSyncConsumer = mBLASTDrawConsumer; + mBLASTDrawConsumer = null; + + if (DEBUG_BLAST) { + Log.d(mTag, "Creating frameDrawingCallback" + + " nextDrawUseBlastSync=" + useBlastSync + + " reportNextDraw=" + reportNextDraw + + " hasBlurUpdates=" + hasBlurUpdates + + " hasBlastSyncConsumer=" + (blastSyncConsumer != null) + + " mHasPendingTransactions=" + mHasPendingTransactions); } final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame = - mBlurRegionAggregator.getBlurRegionsCopyForRT(); + needsCallbackForBlur ? mBlurRegionAggregator.getBlurRegionsCopyForRT() : null; + final boolean hasPendingTransactions = mHasPendingTransactions; + mHasPendingTransactions = false; + // The callback will run on the render thread. - registerRtFrameCallback((frame) -> mBlurRegionAggregator - .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates)); - } - - private void registerCallbackForPendingTransactions() { - registerRtFrameCallback(new FrameDrawingCallback() { - @Override - public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { - if ((syncResult - & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) { - mBlastBufferQueue.applyPendingTransactions(frame); - return null; - } - - return didProduceBuffer -> { - if (!didProduceBuffer) { - mBlastBufferQueue.applyPendingTransactions(frame); - } - }; - - } - + return new FrameDrawingCallback() { @Override public void onFrameDraw(long frame) { } - }); + + @Override + public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { + if (DEBUG_BLAST) { + Log.d(mTag, + "Received frameDrawingCallback syncResult=" + syncResult + " frameNum=" + + frame + "."); + } + + mRtLastAttemptedDrawFrameNum = frame; + + if (needsCallbackForBlur) { + mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame, + blurRegionsForFrame, hasBlurUpdates); + } + + if (mBlastBufferQueue == null) { + return null; + } + + if (!useBlastSync && !reportNextDraw && !hasPendingTransactions) { + return null; + } + + // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or + // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up + // any blast sync or commit callback, and the code should directly call + // pendingDrawFinished. + if ((syncResult + & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) { + if (reportNextDraw) { + mHandler.postAtFrontOfQueue(() -> pendingDrawFinished()); + } + return null; + } + + if (DEBUG_BLAST) { + Log.d(mTag, "Setting up sync and frameCommitCallback"); + } + + if (useBlastSync) { + // 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. + mBlastBufferQueue.syncNextTransaction( + t -> { + mHandler.postAtFrontOfQueue(() -> { + mSurfaceChangedTransaction.merge(t); + if (blastSyncConsumer != null) { + blastSyncConsumer.accept(mSurfaceChangedTransaction); + } + + if (reportNextDraw) { + pendingDrawFinished(); + } + }); + }); + } + + return createFrameCommitCallbackForSync(useBlastSync, reportNextDraw, + blastSyncConsumer); + } + }; } - private void performDraw() { + private void performDraw(boolean useBlastSync) { if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) { return; } else if (mView == null) { return; } - final boolean fullRedrawNeeded = mFullRedrawNeeded || mSyncBufferCallback != null; + final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw || useBlastSync; mFullRedrawNeeded = false; mIsDrawing = true; Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw"); - registerFrameDrawingCallbackForBlur(); - addFrameCommitCallbackIfNeeded(); - - boolean usingAsyncReport = isHardwareEnabled() && mSyncBufferCallback != null; - if (usingAsyncReport) { - registerCallbacksForSync(mSyncBuffer, mSyncBufferCallback); - } else if (mHasPendingTransactions) { - // These callbacks are only needed if there's no sync involved and there were calls to - // applyTransactionOnDraw. These callbacks check if the draw failed for any reason and - // apply those transactions directly so they don't get stuck forever. - registerCallbackForPendingTransactions(); + FrameDrawingCallback frameDrawingCallback = createFrameDrawingCallbackIfNeeded(useBlastSync, + mReportNextDraw); + if (frameDrawingCallback != null) { + mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frameDrawingCallback); } - mHasPendingTransactions = false; + addFrameCommitCallbackIfNeeded(); + boolean usingAsyncReport = isHardwareEnabled() && (useBlastSync || mReportNextDraw); try { boolean canUseAsync = draw(fullRedrawNeeded); if (usingAsyncReport && !canUseAsync) { mAttachInfo.mThreadedRenderer.setFrameCallback(null); usingAsyncReport = false; + mAttachInfo.mThreadedRenderer.unregisterRtFrameCallback(frameDrawingCallback); } } finally { mIsDrawing = false; @@ -4275,6 +4386,7 @@ public final class ViewRootImpl implements ViewParent, } if (mReportNextDraw) { + mReportNextDraw = false; // if we're using multi-thread renderer, wait for the window frame draws if (mWindowDrawCountDown != null) { @@ -4295,11 +4407,7 @@ public final class ViewRootImpl implements ViewParent, } if (mSurfaceHolder != null && mSurface.isValid()) { - final SurfaceSyncer.SyncBufferCallback syncBufferCallback = mSyncBufferCallback; - SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> - mHandler.post(() -> syncBufferCallback.onBufferReady(null))); - mSyncBufferCallback = null; - + SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); @@ -4307,11 +4415,9 @@ public final class ViewRootImpl implements ViewParent, if (mAttachInfo.mThreadedRenderer != null) { mAttachInfo.mThreadedRenderer.fence(); } + pendingDrawFinished(); } } - if (mSyncBufferCallback != null && !usingAsyncReport) { - mSyncBufferCallback.onBufferReady(null); - } if (mPerformContentCapture) { performContentCaptureInitialReport(); } @@ -5320,6 +5426,7 @@ public final class ViewRootImpl implements ViewParent, private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26; private static final int MSG_UPDATE_POINTER_ICON = 27; private static final int MSG_POINTER_CAPTURE_CHANGED = 28; + private static final int MSG_DRAW_FINISHED = 29; private static final int MSG_INSETS_CHANGED = 30; private static final int MSG_INSETS_CONTROL_CHANGED = 31; private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 32; @@ -5382,6 +5489,8 @@ public final class ViewRootImpl implements ViewParent, return "MSG_UPDATE_POINTER_ICON"; case MSG_POINTER_CAPTURE_CHANGED: return "MSG_POINTER_CAPTURE_CHANGED"; + case MSG_DRAW_FINISHED: + return "MSG_DRAW_FINISHED"; case MSG_INSETS_CHANGED: return "MSG_INSETS_CHANGED"; case MSG_INSETS_CONTROL_CHANGED: @@ -5614,6 +5723,9 @@ public final class ViewRootImpl implements ViewParent, final boolean hasCapture = msg.arg1 != 0; handlePointerCaptureChanged(hasCapture); } break; + case MSG_DRAW_FINISHED: { + pendingDrawFinished(); + } break; case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: { systemGestureExclusionChanged(); } break; @@ -9795,8 +9907,8 @@ public final class ViewRootImpl implements ViewParent, } private void reportNextDraw() { - if (DEBUG_BLAST) { - Log.d(mTag, "reportNextDraw " + Debug.getCallers(5)); + if (mReportNextDraw == false) { + drawPending(); } mReportNextDraw = true; } @@ -9807,14 +9919,9 @@ public final class ViewRootImpl implements ViewParent, * This method is only supposed to be used to speed up the interaction from SystemUI and window * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE * unless you fully understand this interaction. - * - * @param syncBuffer If true, the transaction that contains the buffer from the draw should be - * sent to system to be synced. If false, VRI will not try to sync the buffer, - * but only report back that a buffer was drawn. * @hide */ - public void setReportNextDraw(boolean syncBuffer) { - mSyncBuffer = syncBuffer; + public void setReportNextDraw() { reportNextDraw(); invalidate(); } @@ -10840,15 +10947,14 @@ public final class ViewRootImpl implements ViewParent, return mWindowSession; } - private void registerCallbacksForSync(boolean syncBuffer, + private void registerCallbacksForSync( final SurfaceSyncer.SyncBufferCallback syncBufferCallback) { if (!isHardwareEnabled()) { + // TODO: correctly handle when hardware disabled + syncBufferCallback.onBufferReady(null); return; } - if (DEBUG_BLAST) { - Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer); - } mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() { @Override public void onFrameDraw(long frame) { @@ -10877,9 +10983,7 @@ public final class ViewRootImpl implements ViewParent, Log.d(mTag, "Setting up sync and frameCommitCallback"); } - if (syncBuffer) { - mBlastBufferQueue.syncNextTransaction(syncBufferCallback::onBufferReady); - } + mBlastBufferQueue.syncNextTransaction(t -> syncBufferCallback.onBufferReady(t)); return didProduceBuffer -> { if (DEBUG_BLAST) { @@ -10893,40 +10997,18 @@ public final class ViewRootImpl implements ViewParent, // were only set for the current draw attempt. if (!didProduceBuffer) { mBlastBufferQueue.syncNextTransaction(null); - // Gather 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. syncBufferCallback.onBufferReady( mBlastBufferQueue.gatherPendingTransactions(frame)); - return; - } - - // If we didn't request to sync a buffer, then we won't get the - // syncNextTransaction callback. Instead, just report back to the Syncer so it - // knows that this sync request is complete. - if (!syncBuffer) { - syncBufferCallback.onBufferReady(null); } }; } }); } - public final SurfaceSyncer.SyncTarget mSyncTarget = this::readyToSync; - - private void readyToSync(SurfaceSyncer.SyncBufferCallback syncBufferCallback) { - if (mSyncBufferCallback != null) { - Log.d(mTag, "Already set sync for the next draw."); - mSyncBufferCallback.onBufferReady(null); - } - if (DEBUG_BLAST) { - Log.d(mTag, "Setting syncFrameCallback"); - } - mSyncBufferCallback = syncBufferCallback; - if (!mIsInTraversal && !mTraversalScheduled) { - scheduleTraversals(); - } - } + public final SurfaceSyncer.SyncTarget mSyncTarget = + syncBufferCallback -> registerCallbacksForSync(syncBufferCallback); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index bf464ecdec989..acad30b4276f0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -2347,8 +2347,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, // Hack level over 9000: To speed up wake-and-unlock sequence, force it to report // the next draw from here, so we don't have to wait for window manager to signal // this to our ViewRootImpl. - mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw( - false /* syncBuffer */); + mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw(); mScreenOnCoordinator.setWakeAndUnlocking(false); }