Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4c6c3b6 authored by Evan Rosky's avatar Evan Rosky
Browse files

Shortcut double-relayout under specific conditions

Under specific conditions, WM and VRI can coordinate to
avoid making a second sync-relayout when they "know" that
the second relayout will produce the same frames.

The specific conditions, in this case, are system windows
which fill the screen. In this situation, relayout ignores
configuration-dependent parameters, so even if there is a
pending configuration, we can be pretty sure that a
subsequent relayout call will produce the same frames. In
this way, we can allow the client to draw a frame early.

Bug: 439963876
Bug: 385976595
Test: Existing tests
Flag: com.android.window.flags.always_seq_id_layout
Change-Id: I92049d1582570a340f533e630ee41f500bd1c41a
parent 80166f36
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -776,6 +776,16 @@ public final class ViewRootImpl implements ViewParent,
    int mSyncSeqId = 0;
    int mLastSyncSeqId = 0;
    /**
     * Specific optimization where a sync relayout (WM) has determined that the results of a
     * relayout are likely-valid despite this client providing parameters based on an out-dated
     * configuration. In this case, relayout will provide a (later) seqId (this one) which it
     * believes doesn't require another sync relayout and then will NOT cancel. This allows the
     * VRI to assume the frames are already correct, layout/draw immediately, and then skip the
     * next sync relayout.
     */
    int mNonSyncEarlySeqId = 0;
    /** @hide */
    public static final class NoPreloadHolder {
        public static final boolean sAlwaysSeqId;
@@ -9609,7 +9619,9 @@ public final class ViewRootImpl implements ViewParent,
        if ((mViewFrameInfo.flags & FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED) == 0
                && mWindowAttributes.type != TYPE_APPLICATION_STARTING
                && mSyncSeqId <= mLastSyncSeqId
                && (mSeqId <= mLastSeqId || !NoPreloadHolder.sAlwaysSeqId)
                && (!NoPreloadHolder.sAlwaysSeqId
                    || mSeqId <= mLastSeqId
                    || mSeqId <= mNonSyncEarlySeqId)
                && winConfigFromAm.diff(winConfigFromWm, false /* compareUndefined */) == 0) {
            final InsetsState state = mInsetsController.getState();
            final Rect displayCutoutSafe = mTempRect;
@@ -9700,9 +9712,13 @@ public final class ViewRootImpl implements ViewParent,
                    mPendingActivityWindowInfo.set(outInfo);
                }
            }
            final int maybeSyncSeqId = mRelayoutResult.syncSeqId;
            if (maybeSyncSeqId > (NoPreloadHolder.sAlwaysSeqId ? mSyncSeqId : 0)) {
                mSyncSeqId = maybeSyncSeqId;
            if (NoPreloadHolder.sAlwaysSeqId) {
                // mRelayoutResult.syncSeqId is a legacy name. In practice, with sAlwaysSeqId, it
                // has been repurposed to be "the highest (non-sync) seqId that this relayout
                // result is valid for". See docstring on mNonSyncEarlySeqId for more info.
                mNonSyncEarlySeqId = Math.max(mRelayoutResult.syncSeqId, mNonSyncEarlySeqId);
            } else if (mRelayoutResult.syncSeqId > 0) {
                mSyncSeqId = mRelayoutResult.syncSeqId;
            }
            mWinFrameInScreen.set(mTmpFrames.frame);
+40 −4
Original line number Diff line number Diff line
@@ -141,6 +141,7 @@ import static com.android.server.wm.SensitiveContentPackages.PackageInfo;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.SYNC_STATE_WAITING_FOR_DRAW;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
@@ -2431,7 +2432,12 @@ public class WindowManagerService extends IWindowManager.Stub
                return false;
            }

            return win.cancelAndRedraw(seqId);
            final boolean cancel = win.cancelAndRedraw(seqId);
            if (cancel && Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                Trace.instant(TRACE_TAG_WINDOW_MANAGER, "cancelDraw clientSeqId=" + seqId
                        + " serverSeqId=" + win.mSyncSeqId + " bufferSeqId=" + win.mBufferSeqId);
            }
            return cancel;
        }
    }

@@ -2480,6 +2486,11 @@ public class WindowManagerService extends IWindowManager.Stub
                // The client has reported the sync draw, but we haven't finished it yet.
                // Don't let the client perform a non-sync draw at this time.
                result |= RELAYOUT_RES_CANCEL_AND_REDRAW;
                if (mAlwaysSeqId && Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                    Trace.instant(TRACE_TAG_WINDOW_MANAGER, "earlyCancelDraw clientSeqId="
                            + syncSeqId + " serverSeqId=" + win.mSyncSeqId
                            + " bufferSeqId=" + win.mBufferSeqId);
                }
            }

            final DisplayContent displayContent = win.getDisplayContent();
@@ -2854,12 +2865,37 @@ public class WindowManagerService extends IWindowManager.Stub
                            : -1;
                    win.markRedrawForSyncReported();
                } else {
                    if (mAlwaysSeqId && win.cancelAndRedraw(syncSeqId)) {
                    outRelayoutResult.syncSeqId = -1;
                    if (mAlwaysSeqId && (result & RELAYOUT_RES_CANCEL_AND_REDRAW) == 0
                            && win.cancelAndRedraw(syncSeqId)) {
                        // Surface-placement has resulted in a new configuration or a new sync,
                        // so this current layout is invalid until subsequent reportResized.

                        // However, make a targeted optimization to let the client draw early if the
                        // relayout result won't change even after the client receives the new
                        // configuration. If there is an explicit sync, though, the user-perceived
                        // latency will be worse due to the client drawing content that won't be
                        // presented; so, don't "optimize" in that case.
                        final boolean inExplicitSync = syncSeqId <= win.mBufferSeqId
                                || win.mSyncState == SYNC_STATE_WAITING_FOR_DRAW;
                        if (!inExplicitSync && win.layoutIgnoresClientConfig()) {
                            // Returning a seqId indicates, to the client, that it can use this
                            // result even though it's configuration is out-dated.
                            outRelayoutResult.syncSeqId = win.mSyncSeqId;
                            if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                                Trace.instant(TRACE_TAG_WINDOW_MANAGER, "ignoreCancelDraw seqId="
                                        + win.mSyncSeqId);
                            }
                        } else {
                            result |= RELAYOUT_RES_CANCEL_AND_REDRAW;
                            if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                                Trace.instant(TRACE_TAG_WINDOW_MANAGER, "lateCancelDraw "
                                        + " clientSeqId=" + syncSeqId
                                        + " serverSeqId=" + win.mSyncSeqId
                                        + " bufferSeqId=" + win.mBufferSeqId);
                            }
                        }
                    }
                    outRelayoutResult.syncSeqId = -1;
                }
            }

+19 −6
Original line number Diff line number Diff line
@@ -6138,12 +6138,25 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        if (!mWmService.mAlwaysSeqId) {
            return mPrepareSyncSeqId > 0;
        }
        final boolean cancel = Math.max(mSyncSeqId, mBufferSeqId) > seqId;
        if (cancel) {
            Trace.instant(TRACE_TAG_WINDOW_MANAGER, "cancelDraw clientSeqId=" + seqId
                    + " serverSeqId=" + mSyncSeqId + " bufferSeqId=" + mBufferSeqId);
        return Math.max(mSyncSeqId, mBufferSeqId) > seqId;
    }
        return cancel;

    /**
     * Normally, if the client hasn't received the latest configuration yet, we can't assume that
     * the layout parameters are accurate (since they can depend on the configuration).
     *
     * However, there are specific situations where layout logic ignores configuration-dependent
     * layout params AND where we are confident that those layout params aren't, themselves,
     * configuration-dependent. We can use this information for certain optimizations.
     *
     * @return {@code true} if this window's client configuration is irrelevant to layout.
     */
    boolean layoutIgnoresClientConfig() {
        // We are only confident that fullscreen system-ui windows remain fullscreen regardless of
        // of configuration.
        return mActivityRecord == null && !mIsWallpaper
                && mAttrs.width == WindowManager.LayoutParams.MATCH_PARENT
                && mAttrs.height == WindowManager.LayoutParams.MATCH_PARENT;
    }

    public boolean isActivityWindow() {