Merge "Ensure overlapping draws won't break BLAST sync"
This commit is contained in:
committed by
Android (Google) Code Review
commit
3c99024fdb
@@ -420,8 +420,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
|
||||
final boolean useBLAST = viewRoot.useBLAST();
|
||||
viewRoot.registerRtFrameCallback(frame -> {
|
||||
try {
|
||||
final SurfaceControl.Transaction t = useBLAST ?
|
||||
viewRoot.getBLASTSyncTransaction() : new SurfaceControl.Transaction();
|
||||
synchronized (mSurfaceControlLock) {
|
||||
if (!parent.isValid()) {
|
||||
if (DEBUG) {
|
||||
@@ -443,16 +441,22 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
|
||||
Log.d(TAG, System.identityHashCode(this)
|
||||
+ " updateSurfaceAlpha RT: set alpha=" + alpha);
|
||||
}
|
||||
t.setAlpha(mSurfaceControl, alpha);
|
||||
if (!useBLAST) {
|
||||
if (useBLAST) {
|
||||
synchronized (viewRoot.getBlastTransactionLock()) {
|
||||
viewRoot.getBLASTSyncTransaction()
|
||||
.setAlpha(mSurfaceControl, alpha);
|
||||
}
|
||||
} else {
|
||||
Transaction t = new SurfaceControl.Transaction();
|
||||
t.setAlpha(mSurfaceControl, alpha);
|
||||
t.deferTransactionUntil(mSurfaceControl,
|
||||
viewRoot.getRenderSurfaceControl(), frame);
|
||||
t.apply();
|
||||
}
|
||||
}
|
||||
// It's possible that mSurfaceControl is released in the UI thread before
|
||||
// the transaction completes. If that happens, an exception is thrown, which
|
||||
// must be caught immediately.
|
||||
t.apply();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, System.identityHashCode(this)
|
||||
+ "updateSurfaceAlpha RT: Exception during surface transaction", e);
|
||||
@@ -793,23 +797,26 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
|
||||
final boolean useBLAST = viewRoot.useBLAST();
|
||||
viewRoot.registerRtFrameCallback(frame -> {
|
||||
try {
|
||||
final SurfaceControl.Transaction t = useBLAST
|
||||
? viewRoot.getBLASTSyncTransaction()
|
||||
: new SurfaceControl.Transaction();
|
||||
synchronized (mSurfaceControlLock) {
|
||||
if (!parent.isValid() || mSurfaceControl == null) {
|
||||
return;
|
||||
}
|
||||
updateRelativeZ(t);
|
||||
if (!useBLAST) {
|
||||
|
||||
if (useBLAST) {
|
||||
synchronized (viewRoot.getBlastTransactionLock()) {
|
||||
updateRelativeZ(viewRoot.getBLASTSyncTransaction());
|
||||
}
|
||||
} else {
|
||||
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||
updateRelativeZ(t);
|
||||
t.deferTransactionUntil(mSurfaceControl,
|
||||
viewRoot.getRenderSurfaceControl(), frame);
|
||||
t.apply();
|
||||
}
|
||||
}
|
||||
// It's possible that mSurfaceControl is released in the UI thread before
|
||||
// the transaction completes. If that happens, an exception is thrown, which
|
||||
// must be caught immediately.
|
||||
t.apply();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, System.identityHashCode(this)
|
||||
+ "setZOrderOnTop RT: Exception during surface transaction", e);
|
||||
@@ -1252,7 +1259,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
|
||||
private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
|
||||
Rect position, long frameNumber) {
|
||||
final ViewRootImpl viewRoot = getViewRootImpl();
|
||||
if (frameNumber > 0 && viewRoot != null && !viewRoot.isDrawingToBLASTTransaction()) {
|
||||
if (frameNumber > 0 && viewRoot != null && !viewRoot.useBLAST()) {
|
||||
t.deferTransactionUntil(surface, viewRoot.getRenderSurfaceControl(),
|
||||
frameNumber);
|
||||
}
|
||||
@@ -1277,19 +1284,23 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
|
||||
return mRTLastReportedPosition;
|
||||
}
|
||||
|
||||
private void setParentSpaceRectangle(Transaction t, Rect position, long frameNumber) {
|
||||
final ViewRootImpl viewRoot = getViewRootImpl();
|
||||
applySurfaceTransforms(mSurfaceControl, t, position, frameNumber);
|
||||
applyChildSurfaceTransaction_renderWorker(t, viewRoot.mSurface, frameNumber);
|
||||
}
|
||||
|
||||
private void setParentSpaceRectangle(Rect position, long frameNumber) {
|
||||
final ViewRootImpl viewRoot = getViewRootImpl();
|
||||
final boolean useBLAST = viewRoot.isDrawingToBLASTTransaction();
|
||||
final SurfaceControl.Transaction t = useBLAST ? viewRoot.getBLASTSyncTransaction() :
|
||||
mRtTransaction;
|
||||
final boolean useBLAST = viewRoot.useBLAST();
|
||||
|
||||
applySurfaceTransforms(mSurfaceControl, t, position, frameNumber);
|
||||
|
||||
applyChildSurfaceTransaction_renderWorker(t, viewRoot.mSurface,
|
||||
frameNumber);
|
||||
|
||||
if (!useBLAST) {
|
||||
t.apply();
|
||||
if (useBLAST) {
|
||||
synchronized (viewRoot.getBlastTransactionLock()) {
|
||||
setParentSpaceRectangle(viewRoot.getBLASTSyncTransaction(), position, frameNumber);
|
||||
}
|
||||
} else {
|
||||
setParentSpaceRectangle(mRtTransaction, position, frameNumber);
|
||||
mRtTransaction.apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1337,10 +1348,20 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseSurfaces(Transaction t) {
|
||||
if (mRtReleaseSurfaces) {
|
||||
mRtReleaseSurfaces = false;
|
||||
t.remove(mSurfaceControl);
|
||||
t.remove(mBackgroundControl);
|
||||
mSurfaceControl = null;
|
||||
mBackgroundControl = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void positionLost(long frameNumber) {
|
||||
final ViewRootImpl viewRoot = getViewRootImpl();
|
||||
boolean useBLAST = viewRoot != null && viewRoot.isDrawingToBLASTTransaction();
|
||||
boolean useBLAST = viewRoot != null && viewRoot.useBLAST();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
|
||||
System.identityHashCode(this), frameNumber));
|
||||
@@ -1351,38 +1372,31 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
|
||||
return;
|
||||
}
|
||||
|
||||
final SurfaceControl.Transaction t = useBLAST ?
|
||||
(viewRoot != null ? viewRoot.getBLASTSyncTransaction() : mRtTransaction) :
|
||||
mRtTransaction;
|
||||
|
||||
/**
|
||||
* positionLost can be called while UI thread is un-paused so we
|
||||
* need to hold the lock here.
|
||||
*/
|
||||
synchronized (mSurfaceControlLock) {
|
||||
if (frameNumber > 0 && viewRoot != null && !useBLAST) {
|
||||
if (viewRoot.mSurface.isValid()) {
|
||||
if (useBLAST) {
|
||||
synchronized (viewRoot.getBlastTransactionLock()) {
|
||||
viewRoot.getBLASTSyncTransaction().hide(mSurfaceControl);
|
||||
releaseSurfaces(viewRoot.getBLASTSyncTransaction());
|
||||
}
|
||||
} else {
|
||||
if (frameNumber > 0 && viewRoot != null && viewRoot.mSurface.isValid()) {
|
||||
mRtTransaction.deferTransactionUntil(mSurfaceControl,
|
||||
viewRoot.getRenderSurfaceControl(), frameNumber);
|
||||
}
|
||||
}
|
||||
t.hide(mSurfaceControl);
|
||||
|
||||
if (mRtReleaseSurfaces) {
|
||||
mRtReleaseSurfaces = false;
|
||||
mRtTransaction.remove(mSurfaceControl);
|
||||
mRtTransaction.remove(mBackgroundControl);
|
||||
mSurfaceControl = null;
|
||||
mBackgroundControl = null;
|
||||
mRtTransaction.hide(mSurfaceControl);
|
||||
releaseSurfaces(mRtTransaction);
|
||||
// If we aren't using BLAST, we apply the transaction locally, otherwise we let
|
||||
// the ViewRoot apply it for us.
|
||||
// If the ViewRoot is null, we behave as if we aren't using BLAST so we need to
|
||||
// apply the transaction.
|
||||
mRtTransaction.apply();
|
||||
}
|
||||
mRtHandlingPositionUpdates = false;
|
||||
}
|
||||
|
||||
// If we aren't using BLAST, we apply the transaction locally, otherise we let the ViewRoot apply it for us.
|
||||
// If the ViewRoot is null, we behave as if we aren't using BLAST so we need to apply the transaction.
|
||||
if (!useBLAST || viewRoot == null) {
|
||||
mRtTransaction.apply();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -654,26 +654,25 @@ public final class ViewRootImpl implements ViewParent,
|
||||
int localChanges;
|
||||
}
|
||||
|
||||
// If set, ViewRootImpl will call BLASTBufferQueue::setNextTransaction with
|
||||
// mRtBLASTSyncTransaction, prior to invoking draw. This provides a way
|
||||
// to redirect the buffers in to transactions.
|
||||
// If set, ViewRootImpl will request a callback from HWRender when it's ready to render the next
|
||||
// frame. This will allow VRI to call BLASTBufferQueue::setNextTransaction with
|
||||
// mRtBLASTSyncTransaction, so the next frame submitted will be added to the
|
||||
// mRtBLASTSyncTransaction instead of getting applied.
|
||||
private boolean mNextDrawUseBLASTSyncTransaction;
|
||||
// Set when calling setNextTransaction, we can't just reuse mNextDrawUseBLASTSyncTransaction
|
||||
// because, imagine this scenario:
|
||||
// 1. First draw is using BLAST, mNextDrawUseBLAST = true
|
||||
// 2. We call perform draw and are waiting on the callback
|
||||
// 3. After the first perform draw but before the first callback and the
|
||||
// second perform draw, a second draw sets mNextDrawUseBLAST = true (it already was)
|
||||
// 4. At this point the callback fires and we set mNextDrawUseBLAST = false;
|
||||
// 5. We get to performDraw and fail to sync as we intended because mNextDrawUseBLAST
|
||||
// is now false.
|
||||
// This is why we use a two-step latch with the two booleans, one consumed from
|
||||
// performDraw and one consumed from finishBLASTSync()
|
||||
private boolean mNextReportConsumeBLAST;
|
||||
// Be very careful with the threading here. This is used from the render thread while
|
||||
// the UI thread is paused and then applied and cleared from the UI thread right after
|
||||
// draw returns.
|
||||
private SurfaceControl.Transaction mRtBLASTSyncTransaction = new SurfaceControl.Transaction();
|
||||
|
||||
// This is used to signal if the mRtBLASTSyncTransaction should be applied/merged. When true,
|
||||
// it indicates mRtBLASTSyncTransaction was sent to BLASTBufferQueue::setNextTransaction.
|
||||
// Therefore, in onFrameComplete, if mRtNextFrameReportConsumeWithBlast is true, that means
|
||||
// mRtBLASTSyncTransaction now contains the next buffer frame to be applied.
|
||||
private boolean mRtNextFrameReportedConsumeWithBlast;
|
||||
|
||||
// Be very careful with the threading here. This is used from a thread pool generated by the
|
||||
// render thread. Therefore, it needs to be locked when updating from the thread pool since
|
||||
// multiple threads can be accessing it. It does not need to be locked when applied or merged
|
||||
// since that can only happen from the frame complete callback after the other callbacks have
|
||||
// been invoked.
|
||||
private final SurfaceControl.Transaction mRtBLASTSyncTransaction =
|
||||
new SurfaceControl.Transaction();
|
||||
|
||||
// Keeps track of whether the WM requested us to use BLAST Sync when calling relayout.
|
||||
// We use this to make sure we don't send the WM transactions from an internal BLAST sync
|
||||
@@ -3783,26 +3782,29 @@ public final class ViewRootImpl implements ViewParent,
|
||||
commitCallbacks.get(i).run();
|
||||
}
|
||||
}
|
||||
});});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (mNextDrawUseBLASTSyncTransaction) {
|
||||
// TODO(b/149747443)
|
||||
// We aren't prepared to handle overlapping use of mRtBLASTSyncTransaction
|
||||
// so if we are BLAST syncing we make sure the previous draw has
|
||||
// totally finished.
|
||||
if (mAttachInfo.mThreadedRenderer != null) {
|
||||
mAttachInfo.mThreadedRenderer.pause();
|
||||
}
|
||||
|
||||
mNextReportConsumeBLAST = true;
|
||||
// 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 that.
|
||||
//
|
||||
// This is thread safe since mRtNextFrameReportConsumeWithBlast will only be
|
||||
// modified in onFrameDraw and then again in onFrameComplete. This is to ensure the
|
||||
// next frame completed should be reported with the blast sync transaction.
|
||||
registerRtFrameCallback(frame -> {
|
||||
mRtNextFrameReportedConsumeWithBlast = true;
|
||||
if (mBlastBufferQueue != null) {
|
||||
// We don't need to synchronize mRtBLASTSyncTransaction here since it's not
|
||||
// being modified and only sent to BlastBufferQueue.
|
||||
mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
|
||||
}
|
||||
});
|
||||
mNextDrawUseBLASTSyncTransaction = false;
|
||||
|
||||
if (mBlastBufferQueue != null) {
|
||||
mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
|
||||
}
|
||||
}
|
||||
boolean canUseAsync = draw(fullRedrawNeeded);
|
||||
if (usingAsyncReport && !canUseAsync) {
|
||||
@@ -9757,9 +9759,12 @@ public final class ViewRootImpl implements ViewParent,
|
||||
|
||||
private void finishBLASTSync(boolean apply) {
|
||||
mSendNextFrameToWm = false;
|
||||
if (mNextReportConsumeBLAST) {
|
||||
mNextReportConsumeBLAST = false;
|
||||
if (mRtNextFrameReportedConsumeWithBlast) {
|
||||
mRtNextFrameReportedConsumeWithBlast = false;
|
||||
|
||||
// We don't need to synchronize mRtBLASTSyncTransaction here we're guaranteed that this
|
||||
// is called after all onFrameDraw and after callbacks to PositionUpdateListener.
|
||||
// Therefore, no one should be modifying this object until the next vsync.
|
||||
if (apply) {
|
||||
mRtBLASTSyncTransaction.apply();
|
||||
} else {
|
||||
@@ -9772,6 +9777,10 @@ public final class ViewRootImpl implements ViewParent,
|
||||
return mRtBLASTSyncTransaction;
|
||||
}
|
||||
|
||||
Object getBlastTransactionLock() {
|
||||
return mRtBLASTSyncTransaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -9799,12 +9808,4 @@ public final class ViewRootImpl implements ViewParent,
|
||||
boolean useBLAST() {
|
||||
return mUseBLASTAdapter && !mForceDisableBLAST;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if we are about to or currently processing a draw directed
|
||||
* in to a BLAST transaction.
|
||||
*/
|
||||
boolean isDrawingToBLASTTransaction() {
|
||||
return mNextReportConsumeBLAST;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user