Merge "Replace VRI and SV sync logic with SurfaceSyncer" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ef3f71bfa8
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user