Merge "Use blast sync for 180 degrees rotation" into udc-dev

This commit is contained in:
Riddle Hsu
2023-03-13 06:16:25 +00:00
committed by Android (Google) Code Review
8 changed files with 59 additions and 48 deletions

View File

@@ -93,6 +93,9 @@ class AsyncRotationController extends FadeAnimationController implements Consume
/** Whether the start transaction of the transition is committed (by shell). */
private boolean mIsStartTransactionCommitted;
/** Whether all windows should wait for the start transaction. */
private boolean mAlwaysWaitForStartTransaction;
/** Whether the target windows have been requested to sync their draw transactions. */
private boolean mIsSyncDrawRequested;
@@ -144,6 +147,15 @@ class AsyncRotationController extends FadeAnimationController implements Consume
if (mTransitionOp == OP_LEGACY) {
mIsStartTransactionCommitted = true;
} else if (displayContent.mTransitionController.isCollecting(displayContent)) {
final Transition transition =
mDisplayContent.mTransitionController.getCollectingTransition();
if (transition != null) {
final BLASTSyncEngine.SyncGroup syncGroup =
mDisplayContent.mWmService.mSyncEngine.getSyncSet(transition.getSyncId());
if (syncGroup != null && syncGroup.mSyncMethod == BLASTSyncEngine.METHOD_BLAST) {
mAlwaysWaitForStartTransaction = true;
}
}
keepAppearanceInPreviousRotation();
}
}
@@ -202,7 +214,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
// target windows. But the windows still need to use sync transaction to keep the appearance
// in previous rotation, so request a no-op sync to keep the state.
for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
if (mTargetWindowTokens.valueAt(i).canDrawBeforeStartTransaction()) {
if (canDrawBeforeStartTransaction(mTargetWindowTokens.valueAt(i))) {
// Expect a screenshot layer will cover the non seamless windows.
continue;
}
@@ -521,7 +533,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
if (op == null) return false;
if (DEBUG) Slog.d(TAG, "handleFinishDrawing " + w);
if (postDrawTransaction == null || !mIsSyncDrawRequested
|| op.canDrawBeforeStartTransaction()) {
|| canDrawBeforeStartTransaction(op)) {
mDisplayContent.finishAsyncRotation(w.mToken);
return false;
}
@@ -563,6 +575,14 @@ class AsyncRotationController extends FadeAnimationController implements Consume
return super.getFadeOutAnimation();
}
/**
* Returns {@code true} if the corresponding window can draw its latest content before the
* start transaction of rotation transition is applied.
*/
private boolean canDrawBeforeStartTransaction(Operation op) {
return !mAlwaysWaitForStartTransaction && op.mAction != Operation.ACTION_SEAMLESS;
}
/** The operation to control the rotation appearance associated with window token. */
private static class Operation {
@Retention(RetentionPolicy.SOURCE)
@@ -588,14 +608,5 @@ class AsyncRotationController extends FadeAnimationController implements Consume
Operation(@Action int action) {
mAction = action;
}
/**
* Returns {@code true} if the corresponding window can draw its latest content before the
* start transaction of rotation transition is applied.
*/
boolean canDrawBeforeStartTransaction() {
return TransitionController.SYNC_METHOD != BLASTSyncEngine.METHOD_BLAST
&& mAction != ACTION_SEAMLESS;
}
}
}

View File

@@ -95,7 +95,7 @@ class BLASTSyncEngine {
*/
class SyncGroup {
final int mSyncId;
final int mSyncMethod;
int mSyncMethod = METHOD_BLAST;
final TransactionReadyListener mListener;
final Runnable mOnTimeout;
boolean mReady = false;
@@ -103,9 +103,8 @@ class BLASTSyncEngine {
private SurfaceControl.Transaction mOrphanTransaction = null;
private String mTraceName;
private SyncGroup(TransactionReadyListener listener, int id, String name, int method) {
private SyncGroup(TransactionReadyListener listener, int id, String name) {
mSyncId = id;
mSyncMethod = method;
mListener = listener;
mOnTimeout = () -> {
Slog.w(TAG, "Sync group " + mSyncId + " timeout");
@@ -288,13 +287,12 @@ class BLASTSyncEngine {
* Prepares a {@link SyncGroup} that is not active yet. Caller must call {@link #startSyncSet}
* before calling {@link #addToSyncSet(int, WindowContainer)} on any {@link WindowContainer}.
*/
SyncGroup prepareSyncSet(TransactionReadyListener listener, String name, int method) {
return new SyncGroup(listener, mNextSyncId++, name, method);
SyncGroup prepareSyncSet(TransactionReadyListener listener, String name) {
return new SyncGroup(listener, mNextSyncId++, name);
}
int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name,
int method) {
final SyncGroup s = prepareSyncSet(listener, name, method);
int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name) {
final SyncGroup s = prepareSyncSet(listener, name);
startSyncSet(s, timeoutMs);
return s.mSyncId;
}
@@ -334,6 +332,15 @@ class BLASTSyncEngine {
getSyncGroup(id).addToSync(wc);
}
void setSyncMethod(int id, int method) {
final SyncGroup syncGroup = getSyncGroup(id);
if (!syncGroup.mRootMembers.isEmpty()) {
throw new IllegalStateException(
"Not allow to change sync method after adding group member, id=" + id);
}
syncGroup.mSyncMethod = method;
}
void setReady(int id, boolean ready) {
getSyncGroup(id).setReady(ready);
}

View File

@@ -369,7 +369,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
return mState;
}
@VisibleForTesting
int getSyncId() {
return mSyncId;
}
@@ -409,18 +408,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
return mState == STATE_FINISHED;
}
@VisibleForTesting
void startCollecting(long timeoutMs) {
startCollecting(timeoutMs, TransitionController.SYNC_METHOD);
}
/** Starts collecting phase. Once this starts, all relevant surface operations are sync. */
void startCollecting(long timeoutMs, int method) {
void startCollecting(long timeoutMs) {
if (mState != STATE_PENDING) {
throw new IllegalStateException("Attempting to re-use a transition");
}
mState = STATE_COLLECTING;
mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG, method);
mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG);
mSyncEngine.setSyncMethod(mSyncId, TransitionController.SYNC_METHOD);
mLogger.mSyncId = mSyncId;
mLogger.mCollectTimeNs = SystemClock.elapsedRealtimeNanos();

View File

@@ -51,7 +51,6 @@ import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.FgThread;
@@ -200,12 +199,6 @@ class TransitionController {
/** Starts Collecting */
void moveToCollecting(@NonNull Transition transition) {
moveToCollecting(transition, SYNC_METHOD);
}
/** Starts Collecting */
@VisibleForTesting
void moveToCollecting(@NonNull Transition transition, int method) {
if (mCollectingTransition != null) {
throw new IllegalStateException("Simultaneous transition collection not supported.");
}
@@ -219,7 +212,7 @@ class TransitionController {
// Distinguish change type because the response time is usually expected to be not too long.
final long timeoutMs =
transition.mType == TRANSIT_CHANGE ? CHANGE_TIMEOUT_MS : DEFAULT_TIMEOUT_MS;
mCollectingTransition.startCollecting(timeoutMs, method);
mCollectingTransition.startCollecting(timeoutMs);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Start collecting in Transition: %s",
mCollectingTransition);
dispatchLegacyAppTransitionPending();
@@ -492,6 +485,15 @@ class TransitionController {
} else {
newTransition = requestStartTransition(createTransition(type, flags),
trigger != null ? trigger.asTask() : null, remoteTransition, displayChange);
if (newTransition != null && displayChange != null && (displayChange.getStartRotation()
+ displayChange.getEndRotation()) % 2 == 0) {
// 180 degrees rotation change may not change screen size. So the clients may draw
// some frames before and after the display projection transaction is applied by the
// remote player. That may cause some buffers to show in different rotation. So use
// sync method to pause clients drawing until the projection transaction is applied.
mAtm.mWindowManager.mSyncEngine.setSyncMethod(newTransition.getSyncId(),
BLASTSyncEngine.METHOD_BLAST);
}
}
if (trigger != null) {
if (isExistenceType(type)) {

View File

@@ -1648,7 +1648,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
private BLASTSyncEngine.SyncGroup prepareSyncWithOrganizer(
IWindowContainerTransactionCallback callback) {
final BLASTSyncEngine.SyncGroup s = mService.mWindowManager.mSyncEngine
.prepareSyncSet(this, "", BLASTSyncEngine.METHOD_BLAST);
.prepareSyncSet(this, "Organizer");
mTransactionCallbacksByPendingSyncId.put(s.mSyncId, callback);
return s;
}

View File

@@ -22,7 +22,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.BLASTSyncEngine.METHOD_BLAST;
import static com.android.server.wm.BLASTSyncEngine.METHOD_NONE;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -363,7 +362,8 @@ public class SyncEngineTests extends WindowTestsBase {
BLASTSyncEngine.TransactionReadyListener listener = mock(
BLASTSyncEngine.TransactionReadyListener.class);
int id = startSyncSet(bse, listener, METHOD_NONE);
final int id = startSyncSet(bse, listener);
bse.setSyncMethod(id, METHOD_NONE);
bse.addToSyncSet(id, mAppWindow.mToken);
mAppWindow.prepareSync();
assertFalse(mAppWindow.shouldSyncWithBuffers());
@@ -373,12 +373,7 @@ public class SyncEngineTests extends WindowTestsBase {
static int startSyncSet(BLASTSyncEngine engine,
BLASTSyncEngine.TransactionReadyListener listener) {
return startSyncSet(engine, listener, METHOD_BLAST);
}
static int startSyncSet(BLASTSyncEngine engine,
BLASTSyncEngine.TransactionReadyListener listener, int method) {
return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "", method);
return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "Test");
}
static class TestWindowContainer extends WindowContainer {

View File

@@ -1704,7 +1704,8 @@ public class TransitionTests extends WindowTestsBase {
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
final Transition transition = new Transition(TRANSIT_OPEN, 0 /* flags */,
app.mTransitionController, mWm.mSyncEngine);
app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE);
app.mTransitionController.moveToCollecting(transition);
mWm.mSyncEngine.setSyncMethod(transition.getSyncId(), BLASTSyncEngine.METHOD_NONE);
final ArrayList<WindowContainer> freezeCalls = new ArrayList<>();
transition.setContainerFreezer(new Transition.IContainerFreezer() {
@Override
@@ -1755,7 +1756,8 @@ public class TransitionTests extends WindowTestsBase {
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */,
app.mTransitionController, mWm.mSyncEngine);
app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE);
app.mTransitionController.moveToCollecting(transition);
mWm.mSyncEngine.setSyncMethod(transition.getSyncId(), BLASTSyncEngine.METHOD_NONE);
final SurfaceControl mockSnapshot = mock(SurfaceControl.class);
transition.setContainerFreezer(new Transition.IContainerFreezer() {
@Override

View File

@@ -42,7 +42,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.BLASTSyncEngine.METHOD_BLAST;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowContainer.SYNC_STATE_READY;
import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION;
@@ -1001,7 +1000,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
BLASTSyncEngine.TransactionReadyListener transactionListener =
mock(BLASTSyncEngine.TransactionReadyListener.class);
int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "", METHOD_BLAST);
final int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "Test");
bse.addToSyncSet(id, task);
bse.setReady(id);
bse.onSurfacePlacement();