Merge "Revert "Replace VRI and SV sync logic with SurfaceSyncer"" into tm-dev

This commit is contained in:
Greg Kaiser
2022-03-21 20:00:42 +00:00
committed by Android (Google) Code Review
4 changed files with 326 additions and 254 deletions

View File

@@ -401,7 +401,7 @@ public class SurfaceControlViewHost {
public void relayout(WindowManager.LayoutParams attrs, public void relayout(WindowManager.LayoutParams attrs,
WindowlessWindowManager.ResizeCompleteCallback callback) { WindowlessWindowManager.ResizeCompleteCallback callback) {
mViewRoot.setLayoutParams(attrs, false); mViewRoot.setLayoutParams(attrs, false);
mViewRoot.setReportNextDraw(true /* syncBuffer */); mViewRoot.setReportNextDraw();
mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback); mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback);
} }

View File

@@ -50,7 +50,6 @@ import android.view.accessibility.IAccessibilityEmbeddedConnection;
import com.android.internal.view.SurfaceCallbackHelper; import com.android.internal.view.SurfaceCallbackHelper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -204,12 +203,19 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private int mSurfaceFlags = SurfaceControl.HIDDEN; private int mSurfaceFlags = SurfaceControl.HIDDEN;
private int mPendingReportDraws;
/** /**
* Transaction that should be used from the render thread. This transaction is only thread safe * Transaction that should be used from the render thread. This transaction is only thread safe
* with other calls directly from the render thread. * with other calls directly from the render thread.
*/ */
private final SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction(); 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 * Transaction that should be used whe
* {@link HardwareRenderer.FrameDrawingCallback#onFrameDraw} is invoked. All * {@link HardwareRenderer.FrameDrawingCallback#onFrameDraw} is invoked. All
@@ -385,12 +391,31 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
} }
} }
private void performDrawFinished() { private void performDrawFinished(@Nullable Transaction t) {
mDrawFinished = true; if (t != null) {
if (mAttachedToWindow) { mSyncTransaction.merge(t);
mParent.requestTransparentRegion(SurfaceView.this);
invalidate();
} }
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 @Override
@@ -413,6 +438,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mGlobalListenersAdded = false; mGlobalListenersAdded = false;
} }
while (mPendingReportDraws > 0) {
notifyDrawFinished();
}
mRequestedVisible = false; mRequestedVisible = false;
updateSurface(); updateSurface();
@@ -964,17 +993,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
return; 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, final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction); translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction);
final boolean redrawNeeded = sizeChanged || creating || hintChanged
|| (mVisible && !mDrawFinished);
try { try {
SurfaceHolder.Callback[] callbacks = null; SurfaceHolder.Callback[] callbacks = null;
@@ -993,7 +1015,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mIsCreating = true; mIsCreating = true;
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "visibleChanged -- surfaceCreated"); + "visibleChanged -- surfaceCreated");
callbacks = getSurfaceCallbacks(); if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
for (SurfaceHolder.Callback c : callbacks) { for (SurfaceHolder.Callback c : callbacks) {
c.surfaceCreated(mSurfaceHolder); c.surfaceCreated(mSurfaceHolder);
} }
@@ -1011,7 +1035,32 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
} }
} }
if (redrawNeeded) { 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 { } 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. * 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); mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat);
} }
private void onDrawFinished() { private void onDrawFinished(@Nullable Transaction t) {
if (DEBUG) { if (DEBUG) {
Log.i(TAG, System.identityHashCode(this) + " " Log.i(TAG, System.identityHashCode(this) + " "
+ "finishedDrawing"); + "finishedDrawing");
} }
runOnUiThread(this::performDrawFinished); runOnUiThread(() -> performDrawFinished(t));
} }
/** /**

View File

@@ -582,15 +582,11 @@ public final class ViewRootImpl implements ViewParent,
boolean mReportNextDraw; boolean mReportNextDraw;
/** /**
* Set whether the draw should send the buffer to system server. When set to true, VRI will * Set whether the draw should use blast sync. This is in case the draw is canceled,
* create a sync transaction with BBQ and send the resulting buffer to system server. If false, * but will be rescheduled. We still want the next draw to be sync.
* 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.
*/ */
private boolean mSyncBuffer = true; boolean mNextDrawUseBlastSync;
boolean mFullRedrawNeeded; boolean mFullRedrawNeeded;
boolean mNewSurfaceNeeded; boolean mNewSurfaceNeeded;
@@ -811,10 +807,6 @@ public final class ViewRootImpl implements ViewParent,
return mHandwritingInitiator; 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 * Keeps track of the last frame number that was attempted to draw. Should only be accessed on
* the RenderThread. * the RenderThread.
@@ -2893,6 +2885,8 @@ public final class ViewRootImpl implements ViewParent,
mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance); mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance);
} }
} }
final boolean wasReportNextDraw = mReportNextDraw;
boolean useBlastSync = mNextDrawUseBlastSync;
if (mFirst || windowShouldResize || viewVisibilityChanged || params != null if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
|| mForceNextWindowRelayout) { || mForceNextWindowRelayout) {
@@ -2931,6 +2925,9 @@ public final class ViewRootImpl implements ViewParent,
Log.d(mTag, "Relayout called with blastSync"); Log.d(mTag, "Relayout called with blastSync");
} }
reportNextDraw(); reportNextDraw();
if (isHardwareEnabled()) {
useBlastSync = true;
}
} }
final boolean surfaceControlChanged = 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 // done to achieve a more hermetic fix for S, but it's entirely
// possible that checking the most recent value is actually more // possible that checking the most recent value is actually more
// correct here. // correct here.
if (!mStopped || mReportNextDraw) { if (!mStopped || wasReportNextDraw) {
if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight() if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
|| dispatchApplyInsets || updatedConfiguration) { || dispatchApplyInsets || updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width, int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
@@ -3235,7 +3232,7 @@ public final class ViewRootImpl implements ViewParent,
prepareSurfaces(); prepareSurfaces();
} }
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); final boolean didLayout = layoutRequested && (!mStopped || wasReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes; || mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) { if (didLayout) {
@@ -3428,40 +3425,51 @@ public final class ViewRootImpl implements ViewParent,
mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes); mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
// If we already got a request for blast sync, then we don't want to unset mSyncBuffer // Remember if we must report the next draw.
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
&& !mReportNextDraw) {
reportNextDraw(); reportNextDraw();
mSyncBuffer = false;
} }
boolean cancelAndRedraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw(); boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
if (!cancelAndRedraw) { if (mBLASTDrawConsumer != null) {
createSyncIfNeeded(); useBlastSync = true;
} }
if (!isViewVisible) { if (!cancelDraw) {
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 (mPendingTransitions != null && mPendingTransitions.size() > 0) { if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) { for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations(); mPendingTransitions.get(i).startChangingAnimations();
} }
mPendingTransitions.clear(); 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) { if (mAttachInfo.mContentCaptureEvents != null) {
@@ -3470,46 +3478,6 @@ public final class ViewRootImpl implements ViewParent,
mIsInTraversal = false; mIsInTraversal = false;
mRelayoutRequested = 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<Transaction> syncConsumer = null;
if (mBLASTDrawConsumer != null) {
syncConsumer = mBLASTDrawConsumer;
mBLASTDrawConsumer = null;
} else if (mReportNextDraw) {
syncConsumer = transaction -> {
mSurfaceChangedTransaction.merge(transaction);
reportDrawFinished();
};
}
if (syncConsumer != null) {
final Consumer<Transaction> 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() { 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() { private void reportDrawFinished() {
if (DEBUG_BLAST) { if (DEBUG_BLAST) {
Log.d(mTag, "reportDrawFinished " + Debug.getCallers(5)); Log.d(mTag, "reportDrawFinished");
} }
mDrawsNeededToReport = 0;
try { try {
mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, Integer.MAX_VALUE); mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, Integer.MAX_VALUE);
@@ -4145,14 +4157,6 @@ public final class ViewRootImpl implements ViewParent,
return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled(); 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() { private void addFrameCommitCallbackIfNeeded() {
if (!isHardwareEnabled()) { if (!isHardwareEnabled()) {
return; return;
@@ -4183,81 +4187,188 @@ public final class ViewRootImpl implements ViewParent,
}); });
} }
private HardwareRenderer.FrameCommitCallback createFrameCommitCallbackForSync(
boolean useBlastSync, boolean reportNextDraw, Consumer<Transaction> 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 @Nullable
private void registerFrameDrawingCallbackForBlur() { private FrameDrawingCallback createFrameDrawingCallbackIfNeeded(boolean useBlastSync,
boolean reportNextDraw) {
if (!isHardwareEnabled()) { if (!isHardwareEnabled()) {
return; return null;
} }
final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates(); final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates();
final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions(); final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions();
if (!needsCallbackForBlur) { if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw && !mHasPendingTransactions) {
return; return null;
}
final Consumer<SurfaceControl.Transaction> 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 = final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame =
mBlurRegionAggregator.getBlurRegionsCopyForRT(); needsCallbackForBlur ? mBlurRegionAggregator.getBlurRegionsCopyForRT() : null;
final boolean hasPendingTransactions = mHasPendingTransactions;
mHasPendingTransactions = false;
// The callback will run on the render thread. // The callback will run on the render thread.
registerRtFrameCallback((frame) -> mBlurRegionAggregator return new FrameDrawingCallback() {
.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);
}
};
}
@Override @Override
public void onFrameDraw(long frame) { 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) { if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
return; return;
} else if (mView == null) { } else if (mView == null) {
return; return;
} }
final boolean fullRedrawNeeded = mFullRedrawNeeded || mSyncBufferCallback != null; final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw || useBlastSync;
mFullRedrawNeeded = false; mFullRedrawNeeded = false;
mIsDrawing = true; mIsDrawing = true;
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw"); Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
registerFrameDrawingCallbackForBlur(); FrameDrawingCallback frameDrawingCallback = createFrameDrawingCallbackIfNeeded(useBlastSync,
addFrameCommitCallbackIfNeeded(); mReportNextDraw);
if (frameDrawingCallback != null) {
boolean usingAsyncReport = isHardwareEnabled() && mSyncBufferCallback != null; mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frameDrawingCallback);
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();
} }
mHasPendingTransactions = false; addFrameCommitCallbackIfNeeded();
boolean usingAsyncReport = isHardwareEnabled() && (useBlastSync || mReportNextDraw);
try { try {
boolean canUseAsync = draw(fullRedrawNeeded); boolean canUseAsync = draw(fullRedrawNeeded);
if (usingAsyncReport && !canUseAsync) { if (usingAsyncReport && !canUseAsync) {
mAttachInfo.mThreadedRenderer.setFrameCallback(null); mAttachInfo.mThreadedRenderer.setFrameCallback(null);
usingAsyncReport = false; usingAsyncReport = false;
mAttachInfo.mThreadedRenderer.unregisterRtFrameCallback(frameDrawingCallback);
} }
} finally { } finally {
mIsDrawing = false; mIsDrawing = false;
@@ -4275,6 +4386,7 @@ public final class ViewRootImpl implements ViewParent,
} }
if (mReportNextDraw) { if (mReportNextDraw) {
mReportNextDraw = false;
// if we're using multi-thread renderer, wait for the window frame draws // if we're using multi-thread renderer, wait for the window frame draws
if (mWindowDrawCountDown != null) { if (mWindowDrawCountDown != null) {
@@ -4295,11 +4407,7 @@ public final class ViewRootImpl implements ViewParent,
} }
if (mSurfaceHolder != null && mSurface.isValid()) { if (mSurfaceHolder != null && mSurface.isValid()) {
final SurfaceSyncer.SyncBufferCallback syncBufferCallback = mSyncBufferCallback; SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished);
SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() ->
mHandler.post(() -> syncBufferCallback.onBufferReady(null)));
mSyncBufferCallback = null;
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
@@ -4307,11 +4415,9 @@ public final class ViewRootImpl implements ViewParent,
if (mAttachInfo.mThreadedRenderer != null) { if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mThreadedRenderer.fence(); mAttachInfo.mThreadedRenderer.fence();
} }
pendingDrawFinished();
} }
} }
if (mSyncBufferCallback != null && !usingAsyncReport) {
mSyncBufferCallback.onBufferReady(null);
}
if (mPerformContentCapture) { if (mPerformContentCapture) {
performContentCaptureInitialReport(); 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_REQUEST_KEYBOARD_SHORTCUTS = 26;
private static final int MSG_UPDATE_POINTER_ICON = 27; private static final int MSG_UPDATE_POINTER_ICON = 27;
private static final int MSG_POINTER_CAPTURE_CHANGED = 28; 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_CHANGED = 30;
private static final int MSG_INSETS_CONTROL_CHANGED = 31; private static final int MSG_INSETS_CONTROL_CHANGED = 31;
private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 32; 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"; return "MSG_UPDATE_POINTER_ICON";
case MSG_POINTER_CAPTURE_CHANGED: case MSG_POINTER_CAPTURE_CHANGED:
return "MSG_POINTER_CAPTURE_CHANGED"; return "MSG_POINTER_CAPTURE_CHANGED";
case MSG_DRAW_FINISHED:
return "MSG_DRAW_FINISHED";
case MSG_INSETS_CHANGED: case MSG_INSETS_CHANGED:
return "MSG_INSETS_CHANGED"; return "MSG_INSETS_CHANGED";
case MSG_INSETS_CONTROL_CHANGED: case MSG_INSETS_CONTROL_CHANGED:
@@ -5614,6 +5723,9 @@ public final class ViewRootImpl implements ViewParent,
final boolean hasCapture = msg.arg1 != 0; final boolean hasCapture = msg.arg1 != 0;
handlePointerCaptureChanged(hasCapture); handlePointerCaptureChanged(hasCapture);
} break; } break;
case MSG_DRAW_FINISHED: {
pendingDrawFinished();
} break;
case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: { case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: {
systemGestureExclusionChanged(); systemGestureExclusionChanged();
} break; } break;
@@ -9795,8 +9907,8 @@ public final class ViewRootImpl implements ViewParent,
} }
private void reportNextDraw() { private void reportNextDraw() {
if (DEBUG_BLAST) { if (mReportNextDraw == false) {
Log.d(mTag, "reportNextDraw " + Debug.getCallers(5)); drawPending();
} }
mReportNextDraw = true; 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 * 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 * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
* unless you fully understand this interaction. * 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 * @hide
*/ */
public void setReportNextDraw(boolean syncBuffer) { public void setReportNextDraw() {
mSyncBuffer = syncBuffer;
reportNextDraw(); reportNextDraw();
invalidate(); invalidate();
} }
@@ -10840,15 +10947,14 @@ public final class ViewRootImpl implements ViewParent,
return mWindowSession; return mWindowSession;
} }
private void registerCallbacksForSync(boolean syncBuffer, private void registerCallbacksForSync(
final SurfaceSyncer.SyncBufferCallback syncBufferCallback) { final SurfaceSyncer.SyncBufferCallback syncBufferCallback) {
if (!isHardwareEnabled()) { if (!isHardwareEnabled()) {
// TODO: correctly handle when hardware disabled
syncBufferCallback.onBufferReady(null);
return; return;
} }
if (DEBUG_BLAST) {
Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer);
}
mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() { mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
@Override @Override
public void onFrameDraw(long frame) { public void onFrameDraw(long frame) {
@@ -10877,9 +10983,7 @@ public final class ViewRootImpl implements ViewParent,
Log.d(mTag, "Setting up sync and frameCommitCallback"); Log.d(mTag, "Setting up sync and frameCommitCallback");
} }
if (syncBuffer) { mBlastBufferQueue.syncNextTransaction(t -> syncBufferCallback.onBufferReady(t));
mBlastBufferQueue.syncNextTransaction(syncBufferCallback::onBufferReady);
}
return didProduceBuffer -> { return didProduceBuffer -> {
if (DEBUG_BLAST) { if (DEBUG_BLAST) {
@@ -10893,40 +10997,18 @@ public final class ViewRootImpl implements ViewParent,
// were only set for the current draw attempt. // were only set for the current draw attempt.
if (!didProduceBuffer) { if (!didProduceBuffer) {
mBlastBufferQueue.syncNextTransaction(null); mBlastBufferQueue.syncNextTransaction(null);
// Gather the transactions that were sent to mergeWithNextTransaction // Gather the transactions that were sent to mergeWithNextTransaction
// since the frame didn't draw on this vsync. It's possible the frame will // 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 // draw later, but it's better to not be sync than to block on a frame that
// may never come. // may never come.
syncBufferCallback.onBufferReady( syncBufferCallback.onBufferReady(
mBlastBufferQueue.gatherPendingTransactions(frame)); 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; public final SurfaceSyncer.SyncTarget mSyncTarget =
syncBufferCallback -> registerCallbacksForSync(syncBufferCallback);
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();
}
}
} }

View File

@@ -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 // 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 // the next draw from here, so we don't have to wait for window manager to signal
// this to our ViewRootImpl. // this to our ViewRootImpl.
mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw( mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw();
false /* syncBuffer */);
mScreenOnCoordinator.setWakeAndUnlocking(false); mScreenOnCoordinator.setWakeAndUnlocking(false);
} }