Merge changes from topic "release_buffer_cache_id" into tm-dev

* changes:
  Async BLAST Sync[3/N]: Push sync-id around
  Replace VRI and SV sync logic with SurfaceSyncer
This commit is contained in:
Rob Carr
2022-03-24 18:06:21 +00:00
committed by Android (Google) Code Review
5 changed files with 269 additions and 336 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(); mViewRoot.setReportNextDraw(true /* syncBuffer */);
mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback); mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback);
} }

View File

@@ -50,6 +50,7 @@ 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;
@@ -203,19 +204,12 @@ 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
@@ -391,31 +385,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
} }
} }
private void performDrawFinished(@Nullable Transaction t) { private void performDrawFinished() {
if (t != null) { mDrawFinished = true;
mSyncTransaction.merge(t); if (mAttachedToWindow) {
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
@@ -438,10 +413,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mGlobalListenersAdded = false; mGlobalListenersAdded = false;
} }
while (mPendingReportDraws > 0) {
notifyDrawFinished();
}
mRequestedVisible = false; mRequestedVisible = false;
updateSurface(); updateSurface();
@@ -993,10 +964,17 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
return; return;
} }
final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction);
final boolean redrawNeeded = sizeChanged || creating || hintChanged final boolean redrawNeeded = sizeChanged || creating || hintChanged
|| (mVisible && !mDrawFinished); || (mVisible && !mDrawFinished);
final TransactionCallback transactionCallback =
redrawNeeded ? new TransactionCallback() : null;
if (redrawNeeded && viewRoot.wasRelayoutRequested() && viewRoot.isInSync()) {
mBlastBufferQueue.syncNextTransaction(
false /* acquireSingleBuffer */,
transactionCallback::onTransactionReady);
}
final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction);
try { try {
SurfaceHolder.Callback[] callbacks = null; SurfaceHolder.Callback[] callbacks = null;
@@ -1015,9 +993,7 @@ 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");
if (callbacks == null) { callbacks = getSurfaceCallbacks();
callbacks = getSurfaceCallbacks();
}
for (SurfaceHolder.Callback c : callbacks) { for (SurfaceHolder.Callback c : callbacks) {
c.surfaceCreated(mSurfaceHolder); c.surfaceCreated(mSurfaceHolder);
} }
@@ -1035,32 +1011,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
} }
} }
if (redrawNeeded) { if (redrawNeeded) {
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " redrawNeeded(callbacks, transactionCallback);
+ "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 {
@@ -1079,6 +1030,64 @@ 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.
* *
@@ -1189,13 +1198,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat); mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat);
} }
private void onDrawFinished(@Nullable Transaction t) { private void onDrawFinished() {
if (DEBUG) { if (DEBUG) {
Log.i(TAG, System.identityHashCode(this) + " " Log.i(TAG, System.identityHashCode(this) + " "
+ "finishedDrawing"); + "finishedDrawing");
} }
runOnUiThread(() -> performDrawFinished(t)); runOnUiThread(this::performDrawFinished);
} }
/** /**

View File

@@ -587,11 +587,16 @@ public final class ViewRootImpl implements ViewParent,
boolean mReportNextDraw; boolean mReportNextDraw;
/** /**
* Set whether the draw should use blast sync. This is in case the draw is canceled, * Set whether the draw should send the buffer to system server. When set to true, VRI will
* but will be rescheduled. We still want the next draw to be sync. * 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.
*/ */
boolean mNextDrawUseBlastSync; private boolean mSyncBuffer = false;
int mSyncSeqId = 0;
int mLastSyncSeqId = 0;
boolean mFullRedrawNeeded; boolean mFullRedrawNeeded;
boolean mNewSurfaceNeeded; boolean mNewSurfaceNeeded;
@@ -812,6 +817,10 @@ 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.
@@ -849,8 +858,6 @@ public final class ViewRootImpl implements ViewParent,
* integer back over relayout. * integer back over relayout.
*/ */
private Bundle mRelayoutBundle = new Bundle(); private Bundle mRelayoutBundle = new Bundle();
private int mSyncSeqId = 0;
private int mLastSyncSeqId = 0;
private String mTag = TAG; private String mTag = TAG;
@@ -2654,7 +2661,6 @@ public final class ViewRootImpl implements ViewParent,
private void performTraversals() { private void performTraversals() {
// cache mView since it is used so much below... // cache mView since it is used so much below...
final View host = mView; final View host = mView;
if (DBG) { if (DBG) {
System.out.println("======================================"); System.out.println("======================================");
System.out.println("performTraversals"); System.out.println("performTraversals");
@@ -2899,8 +2905,6 @@ 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) {
@@ -2939,9 +2943,7 @@ public final class ViewRootImpl implements ViewParent,
Log.d(mTag, "Relayout called with blastSync"); Log.d(mTag, "Relayout called with blastSync");
} }
reportNextDraw(); reportNextDraw();
if (isHardwareEnabled()) { mSyncBuffer = true;
useBlastSync = true;
}
} }
final boolean surfaceControlChanged = final boolean surfaceControlChanged =
@@ -3177,7 +3179,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 || wasReportNextDraw) { if (!mStopped || mReportNextDraw) {
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,
@@ -3246,7 +3248,7 @@ public final class ViewRootImpl implements ViewParent,
prepareSurfaces(); prepareSurfaces();
} }
final boolean didLayout = layoutRequested && (!mStopped || wasReportNextDraw); final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes; || mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) { if (didLayout) {
@@ -3439,51 +3441,37 @@ public final class ViewRootImpl implements ViewParent,
mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes); mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
// Remember if we must report the next draw.
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
reportNextDraw(); reportNextDraw();
} }
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; boolean cancelAndRedraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
if (mBLASTDrawConsumer != null) { if (!cancelAndRedraw) {
useBlastSync = true; createSyncIfNeeded();
} }
if (!cancelDraw) { 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 (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(useBlastSync); performDraw();
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) {
@@ -3492,6 +3480,48 @@ public final class ViewRootImpl implements ViewParent,
mIsInTraversal = false; mIsInTraversal = false;
mRelayoutRequested = false; mRelayoutRequested = false;
if (!cancelAndRedraw) {
mReportNextDraw = false;
mSyncBufferCallback = null;
mSyncBuffer = false;
if (mLastSyncId != -1) {
mSurfaceSyncer.markSyncReady(mLastSyncId);
mLastSyncId = -1;
}
}
}
private void createSyncIfNeeded() {
// Started a sync already.
if (mLastSyncId != -1) {
return;
}
Consumer<Transaction> syncConsumer = null;
final int seqId = mSyncSeqId;
if (mBLASTDrawConsumer != null) {
syncConsumer = mBLASTDrawConsumer;
mBLASTDrawConsumer = null;
} else if (mReportNextDraw) {
syncConsumer = transaction -> {
mSurfaceChangedTransaction.merge(transaction);
reportDrawFinished(seqId);
};
}
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() {
@@ -4105,57 +4135,13 @@ public final class ViewRootImpl implements ViewParent,
} }
} }
/** private void reportDrawFinished(int seqId) {
* 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) { if (DEBUG_BLAST) {
Log.d(mTag, "reportDrawFinished"); Log.d(mTag, "reportDrawFinished " + Debug.getCallers(5));
} }
mDrawsNeededToReport = 0;
try { try {
mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, Integer.MAX_VALUE); mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, seqId);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(mTag, "Unable to report draw finished", e); Log.e(mTag, "Unable to report draw finished", e);
mSurfaceChangedTransaction.apply(); mSurfaceChangedTransaction.apply();
@@ -4171,6 +4157,19 @@ 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;
}
public boolean isInSync() {
return mLastSyncId != -1;
}
private void addFrameCommitCallbackIfNeeded() { private void addFrameCommitCallbackIfNeeded() {
if (!isHardwareEnabled()) { if (!isHardwareEnabled()) {
return; return;
@@ -4201,188 +4200,82 @@ 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 FrameDrawingCallback createFrameDrawingCallbackIfNeeded(boolean useBlastSync, private void registerFrameDrawingCallbackForBlur() {
boolean reportNextDraw) {
if (!isHardwareEnabled()) { if (!isHardwareEnabled()) {
return null; return;
} }
final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates(); final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates();
final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions(); final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions();
if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw && !mHasPendingTransactions) { if (!needsCallbackForBlur) {
return null; return;
}
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 =
needsCallbackForBlur ? mBlurRegionAggregator.getBlurRegionsCopyForRT() : null; mBlurRegionAggregator.getBlurRegionsCopyForRT();
final boolean hasPendingTransactions = mHasPendingTransactions;
mHasPendingTransactions = false;
// The callback will run on the render thread. // The callback will run on the render thread.
return new FrameDrawingCallback() { 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);
}
};
}
@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(boolean useBlastSync) { private void performDraw() {
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 || mReportNextDraw || useBlastSync; final boolean fullRedrawNeeded = mFullRedrawNeeded || mSyncBufferCallback != null;
mFullRedrawNeeded = false; mFullRedrawNeeded = false;
mIsDrawing = true; mIsDrawing = true;
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw"); Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
FrameDrawingCallback frameDrawingCallback = createFrameDrawingCallbackIfNeeded(useBlastSync, registerFrameDrawingCallbackForBlur();
mReportNextDraw);
if (frameDrawingCallback != null) {
mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frameDrawingCallback);
}
addFrameCommitCallbackIfNeeded(); addFrameCommitCallbackIfNeeded();
boolean usingAsyncReport = isHardwareEnabled() && (useBlastSync || mReportNextDraw);
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();
}
mHasPendingTransactions = false;
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;
@@ -4400,7 +4293,6 @@ 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) {
@@ -4421,7 +4313,11 @@ public final class ViewRootImpl implements ViewParent,
} }
if (mSurfaceHolder != null && mSurface.isValid()) { if (mSurfaceHolder != null && mSurface.isValid()) {
SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished); final SurfaceSyncer.SyncBufferCallback syncBufferCallback = mSyncBufferCallback;
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);
@@ -4429,9 +4325,11 @@ 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();
} }
@@ -5440,7 +5338,6 @@ 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;
@@ -5503,8 +5400,6 @@ 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:
@@ -5735,9 +5630,6 @@ 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;
@@ -8066,7 +7958,6 @@ public final class ViewRootImpl implements ViewParent,
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException { boolean insetsPending) throws RemoteException {
mRelayoutRequested = true; mRelayoutRequested = true;
float appScale = mAttachInfo.mApplicationScale; float appScale = mAttachInfo.mApplicationScale;
boolean restore = false; boolean restore = false;
@@ -8639,7 +8530,8 @@ public final class ViewRootImpl implements ViewParent,
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private void dispatchResized(ClientWindowFrames frames, boolean reportDraw, private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout, MergedConfiguration mergedConfiguration, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) { boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) {
Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED); Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
SomeArgs args = SomeArgs.obtain(); SomeArgs args = SomeArgs.obtain();
final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid()); final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
@@ -8649,8 +8541,9 @@ public final class ViewRootImpl implements ViewParent,
args.argi1 = forceLayout ? 1 : 0; args.argi1 = forceLayout ? 1 : 0;
args.argi2 = alwaysConsumeSystemBars ? 1 : 0; args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
args.argi3 = displayId; args.argi3 = displayId;
args.argi4 = seqId; args.argi4 = syncSeqId;
args.argi5 = resizeMode; args.argi5 = resizeMode;
msg.obj = args; msg.obj = args;
mHandler.sendMessage(msg); mHandler.sendMessage(msg);
} }
@@ -9942,8 +9835,8 @@ public final class ViewRootImpl implements ViewParent,
} }
private void reportNextDraw() { private void reportNextDraw() {
if (mReportNextDraw == false) { if (DEBUG_BLAST) {
drawPending(); Log.d(mTag, "reportNextDraw " + Debug.getCallers(5));
} }
mReportNextDraw = true; mReportNextDraw = true;
} }
@@ -9954,9 +9847,14 @@ 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() { public void setReportNextDraw(boolean syncBuffer) {
mSyncBuffer = syncBuffer;
reportNextDraw(); reportNextDraw();
invalidate(); invalidate();
} }
@@ -10035,11 +9933,11 @@ public final class ViewRootImpl implements ViewParent,
@Override @Override
public void resized(ClientWindowFrames frames, boolean reportDraw, public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout, MergedConfiguration mergedConfiguration, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) { boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) {
final ViewRootImpl viewAncestor = mViewAncestor.get(); final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) { if (viewAncestor != null) {
viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, forceLayout, viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, forceLayout,
alwaysConsumeSystemBars, displayId, seqId, resizeMode); alwaysConsumeSystemBars, displayId, syncSeqId, resizeMode);
} }
} }
@@ -10982,14 +10880,15 @@ public final class ViewRootImpl implements ViewParent,
return mWindowSession; return mWindowSession;
} }
private void registerCallbacksForSync( private void registerCallbacksForSync(boolean syncBuffer,
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) {
@@ -11018,7 +10917,9 @@ public final class ViewRootImpl implements ViewParent,
Log.d(mTag, "Setting up sync and frameCommitCallback"); Log.d(mTag, "Setting up sync and frameCommitCallback");
} }
mBlastBufferQueue.syncNextTransaction(t -> syncBufferCallback.onBufferReady(t)); if (syncBuffer) {
mBlastBufferQueue.syncNextTransaction(syncBufferCallback::onBufferReady);
}
return didProduceBuffer -> { return didProduceBuffer -> {
if (DEBUG_BLAST) { if (DEBUG_BLAST) {
@@ -11032,18 +10933,40 @@ 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 = public final SurfaceSyncer.SyncTarget mSyncTarget = this::readyToSync;
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

@@ -2373,7 +2373,8 @@ 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);
} }

View File

@@ -3962,8 +3962,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
try { try {
mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration, mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,
forceRelayout, alwaysConsumeSystemBars, displayId, Integer.MAX_VALUE, forceRelayout, alwaysConsumeSystemBars, displayId, mSyncSeqId, resizeMode);
resizeMode);
if (drawPending && reportOrientation && mOrientationChanging) { if (drawPending && reportOrientation && mOrientationChanging) {
mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime(); mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime();
ProtoLog.v(WM_DEBUG_ORIENTATION, ProtoLog.v(WM_DEBUG_ORIENTATION,