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

This commit is contained in:
Chavi Weingarten
2022-03-18 21:18:26 +00:00
committed by Android (Google) Code Review
4 changed files with 254 additions and 326 deletions

View File

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

View File

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

View File

@@ -583,11 +583,15 @@ public final class ViewRootImpl implements ViewParent,
boolean mReportNextDraw;
/**
* 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.
* 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.
*/
boolean mNextDrawUseBlastSync;
private boolean mSyncBuffer = true;
boolean mFullRedrawNeeded;
boolean mNewSurfaceNeeded;
@@ -808,6 +812,10 @@ 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.
@@ -2880,8 +2888,6 @@ public final class ViewRootImpl implements ViewParent,
mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance);
}
}
final boolean wasReportNextDraw = mReportNextDraw;
boolean useBlastSync = mNextDrawUseBlastSync;
if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
|| mForceNextWindowRelayout) {
@@ -2923,9 +2929,6 @@ public final class ViewRootImpl implements ViewParent,
Log.d(mTag, "Relayout called with blastSync");
}
reportNextDraw();
if (isHardwareEnabled()) {
useBlastSync = true;
}
}
final boolean surfaceControlChanged =
@@ -3164,7 +3167,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 || wasReportNextDraw) {
if (!mStopped || mReportNextDraw) {
if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
|| dispatchApplyInsets || updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
@@ -3233,7 +3236,7 @@ public final class ViewRootImpl implements ViewParent,
prepareSurfaces();
}
final boolean didLayout = layoutRequested && (!mStopped || wasReportNextDraw);
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
@@ -3426,51 +3429,40 @@ public final class ViewRootImpl implements ViewParent,
mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
// Remember if we must report the next draw.
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
// 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) {
reportNextDraw();
mSyncBuffer = false;
}
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
if (mBLASTDrawConsumer != null) {
useBlastSync = true;
boolean cancelAndRedraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
if (!cancelAndRedraw) {
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) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
}
mPendingTransitions.clear();
}
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;
}
}
performDraw();
}
if (mAttachInfo.mContentCaptureEvents != null) {
@@ -3479,6 +3471,46 @@ 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<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() {
@@ -4092,54 +4124,10 @@ 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");
Log.d(mTag, "reportDrawFinished " + Debug.getCallers(5));
}
mDrawsNeededToReport = 0;
try {
mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, Integer.MAX_VALUE);
@@ -4158,6 +4146,14 @@ 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;
@@ -4188,188 +4184,81 @@ 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
private FrameDrawingCallback createFrameDrawingCallbackIfNeeded(boolean useBlastSync,
boolean reportNextDraw) {
private void registerFrameDrawingCallbackForBlur() {
if (!isHardwareEnabled()) {
return null;
return;
}
final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates();
final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions();
if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw && !mHasPendingTransactions) {
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);
if (!needsCallbackForBlur) {
return;
}
final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame =
needsCallbackForBlur ? mBlurRegionAggregator.getBlurRegionsCopyForRT() : null;
final boolean hasPendingTransactions = mHasPendingTransactions;
mHasPendingTransactions = false;
mBlurRegionAggregator.getBlurRegionsCopyForRT();
// 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
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) {
return;
} else if (mView == null) {
return;
}
final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw || useBlastSync;
final boolean fullRedrawNeeded = mFullRedrawNeeded || mSyncBufferCallback != null;
mFullRedrawNeeded = false;
mIsDrawing = true;
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
FrameDrawingCallback frameDrawingCallback = createFrameDrawingCallbackIfNeeded(useBlastSync,
mReportNextDraw);
if (frameDrawingCallback != null) {
mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frameDrawingCallback);
}
registerFrameDrawingCallbackForBlur();
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 {
boolean canUseAsync = draw(fullRedrawNeeded);
if (usingAsyncReport && !canUseAsync) {
mAttachInfo.mThreadedRenderer.setFrameCallback(null);
usingAsyncReport = false;
mAttachInfo.mThreadedRenderer.unregisterRtFrameCallback(frameDrawingCallback);
}
} finally {
mIsDrawing = false;
@@ -4387,7 +4276,6 @@ 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) {
@@ -4408,7 +4296,11 @@ public final class ViewRootImpl implements ViewParent,
}
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();
sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
@@ -4416,9 +4308,11 @@ public final class ViewRootImpl implements ViewParent,
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mThreadedRenderer.fence();
}
pendingDrawFinished();
}
}
if (mSyncBufferCallback != null && !usingAsyncReport) {
mSyncBufferCallback.onBufferReady(null);
}
if (mPerformContentCapture) {
performContentCaptureInitialReport();
}
@@ -5427,7 +5321,6 @@ 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;
@@ -5490,8 +5383,6 @@ 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:
@@ -5724,9 +5615,6 @@ 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;
@@ -9908,8 +9796,8 @@ public final class ViewRootImpl implements ViewParent,
}
private void reportNextDraw() {
if (mReportNextDraw == false) {
drawPending();
if (DEBUG_BLAST) {
Log.d(mTag, "reportNextDraw " + Debug.getCallers(5));
}
mReportNextDraw = true;
}
@@ -9920,9 +9808,14 @@ 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() {
public void setReportNextDraw(boolean syncBuffer) {
mSyncBuffer = syncBuffer;
reportNextDraw();
invalidate();
}
@@ -10948,14 +10841,15 @@ public final class ViewRootImpl implements ViewParent,
return mWindowSession;
}
private void registerCallbacksForSync(
private void registerCallbacksForSync(boolean syncBuffer,
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) {
@@ -10984,7 +10878,9 @@ public final class ViewRootImpl implements ViewParent,
Log.d(mTag, "Setting up sync and frameCommitCallback");
}
mBlastBufferQueue.syncNextTransaction(t -> syncBufferCallback.onBufferReady(t));
if (syncBuffer) {
mBlastBufferQueue.syncNextTransaction(syncBufferCallback::onBufferReady);
}
return didProduceBuffer -> {
if (DEBUG_BLAST) {
@@ -10998,18 +10894,40 @@ 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 =
syncBufferCallback -> registerCallbacksForSync(syncBufferCallback);
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();
}
}
}

View File

@@ -2347,7 +2347,8 @@ 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();
mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw(
false /* syncBuffer */);
mScreenOnCoordinator.setWakeAndUnlocking(false);
}