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

Commit 55d882cf authored by Robert Carr's avatar Robert Carr
Browse files

WindowStateAnimator/ViewRoot: Move surface resizing to client

The bounds on the client surface are controlled by higher levels of
the hierarchy and so the client can use whatever Surface size it wants
on its node. We move the SurfaceControl setSize call to the client,
following 3 sort of ideas:

1. Project to make relayout window async, but currently it is used as a
sync point for resizing, resizing on client, one problem solved!
2. WM Shouldn't do what it doesnt have to for clients
3. Totally move management of lowest level Surface to client
   clean up lots of WM code (see WindowStateAnimator slimming project)

In the future maybe we don't need to set the SurfaceControl size at all
and the client can just set its buffer size, but it may produce some
differences in geometry handling on the server so I want to maintain
the old semantics for this CL.

Bug: 161937501
Test: Existing tests pass
Change-Id: Icebd94f8443fdbe9f0e6968bc35bbb0504a1520c
parent 0cf58183
Loading
Loading
Loading
Loading
+34 −9
Original line number Diff line number Diff line
@@ -1790,7 +1790,7 @@ public final class ViewRootImpl implements ViewParent,
                    .setParent(getRenderSurfaceControl())
                    .setCallsite("ViewRootImpl.getBoundsLayer")
                    .build();
            setBoundsLayerCrop();
            setBoundsLayerCrop(mTransaction);
            mTransaction.show(mBoundsLayer).apply();
        }
       return mBoundsLayer;
@@ -1818,25 +1818,41 @@ public final class ViewRootImpl implements ViewParent,
        return ret;
    }

    private void setBoundsLayerCrop() {
    private void setBoundsLayerCrop(Transaction t) {
        // mWinFrame is already adjusted for surface insets. So offset it and use it as
        // the cropping bounds.
        mTempBoundsRect.set(mWinFrame);
        mTempBoundsRect.offsetTo(mWindowAttributes.surfaceInsets.left,
                mWindowAttributes.surfaceInsets.top);
        mTransaction.setWindowCrop(mBoundsLayer, mTempBoundsRect);
        t.setWindowCrop(mBoundsLayer, mTempBoundsRect);
    }

    /**
     * Called after window layout to update the bounds surface. If the surface insets have changed
     * or the surface has resized, update the bounds surface.
     */
    private void updateBoundsLayer() {
    private boolean updateBoundsLayer(SurfaceControl.Transaction t) {
        if (mBoundsLayer != null) {
            setBoundsLayerCrop();
            mTransaction.deferTransactionUntil(mBoundsLayer,
                    getRenderSurfaceControl(), mSurface.getNextFrameNumber())
                    .apply();
            setBoundsLayerCrop(t);
            t.deferTransactionUntil(mBoundsLayer, getRenderSurfaceControl(),
                mSurface.getNextFrameNumber());
            return true;
        }
        return false;
    }

    private void prepareSurfaces(boolean sizeChanged) {
        final SurfaceControl.Transaction t = mTransaction;
        final SurfaceControl sc = getRenderSurfaceControl();
        if (!sc.isValid()) return;

        boolean applyTransaction = updateBoundsLayer(t);
        if (sizeChanged) {
            applyTransaction = true;
            t.setBufferSize(sc, mSurfaceSize.x, mSurfaceSize.y);
        }
        if (applyTransaction) {
            t.apply();
        }
    }

@@ -2927,7 +2943,16 @@ public final class ViewRootImpl implements ViewParent,
        }

        if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) {
            updateBoundsLayer();
            // If the surface has been replaced, there's a chance the bounds layer is not parented
            // to the new layer. When updating bounds layer, also reparent to the main VRI
            // SurfaceControl to ensure it's correctly placed in the hierarchy.
            //
            // This needs to be done on the client side since WMS won't reparent the children to the
            // new surface if it thinks the app is closing. WMS gets the signal that the app is
            // stopping, but on the client side it doesn't get stopped since it's restarted quick
            // enough. WMS doesn't want to keep around old children since they will leak when the
            // client creates new children.
            prepareSurfaces(surfaceSizeChanged);
        }

        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
+2 −2
Original line number Diff line number Diff line
@@ -2427,8 +2427,8 @@ public class WindowManagerService extends IWindowManager.Stub
                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            }
            if (winAnimator.mSurfaceController != null) {
                outSurfaceSize.set(winAnimator.mSurfaceController.getWidth(),
                                         winAnimator.mSurfaceController.getHeight());
                win.calculateSurfaceBounds(win.getAttrs(), mTmpRect);
                outSurfaceSize.set(mTmpRect.width(), mTmpRect.height());
            }
            getInsetsSourceControls(win, outActiveControls);
        }
+33 −0
Original line number Diff line number Diff line
@@ -5940,4 +5940,37 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
    void requestRedrawForSync() {
        mRedrawForSyncReported = false;
    }

    void calculateSurfaceBounds(WindowManager.LayoutParams attrs, Rect outSize) {
        outSize.setEmpty();
        if ((attrs.flags & FLAG_SCALED) != 0) {
            // For a scaled surface, we always want the requested size.
            outSize.right = mRequestedWidth;
            outSize.bottom = mRequestedHeight;
        } else {
            // When we're doing a drag-resizing, request a surface that's fullscreen size,
            // so that we don't need to reallocate during the process. This also prevents
            // buffer drops due to size mismatch.
            if (isDragResizing()) {
                final DisplayInfo displayInfo = getDisplayInfo();
                outSize.right = displayInfo.logicalWidth;
                outSize.bottom = displayInfo.logicalHeight;
            } else {
                getCompatFrameSize(outSize);
            }
        }

        // This doesn't necessarily mean that there is an error in the system. The sizes might be
        // incorrect, because it is before the first layout or draw.
        if (outSize.width() < 1) {
            outSize.right = 1;
        }
        if (outSize.height() < 1) {
            outSize.bottom = 1;
        }

        // Adjust for surface insets.
        outSize.inset(-attrs.surfaceInsets.left, -attrs.surfaceInsets.top,
                -attrs.surfaceInsets.right, -attrs.surfaceInsets.bottom);
    }
}
+7 −49
Original line number Diff line number Diff line
@@ -456,7 +456,8 @@ class WindowStateAnimator {
            flags |= SurfaceControl.SKIP_SCREENSHOT;
        }

        calculateSurfaceBounds(w, attrs, mTmpSize);
        w.calculateSurfaceBounds(attrs, mTmpSize);

        final int width = mTmpSize.width();
        final int height = mTmpSize.height();

@@ -532,40 +533,6 @@ class WindowStateAnimator {
        return mSurfaceController;
    }

    private void calculateSurfaceBounds(WindowState w, LayoutParams attrs, Rect outSize) {
        outSize.setEmpty();
        if ((attrs.flags & FLAG_SCALED) != 0) {
            // For a scaled surface, we always want the requested size.
            outSize.right = w.mRequestedWidth;
            outSize.bottom = w.mRequestedHeight;
        } else {
            // When we're doing a drag-resizing, request a surface that's fullscreen size,
            // so that we don't need to reallocate during the process. This also prevents
            // buffer drops due to size mismatch.
            if (w.isDragResizing()) {
                final DisplayInfo displayInfo = w.getDisplayInfo();
                outSize.right = displayInfo.logicalWidth;
                outSize.bottom = displayInfo.logicalHeight;
            } else {
                w.getCompatFrameSize(outSize);
            }
        }

        // Something is wrong and SurfaceFlinger will not like this, try to revert to reasonable
        // values. This doesn't necessarily mean that there is an error in the system. The sizes
        // might be incorrect, because it is before the first layout or draw.
        if (outSize.width() < 1) {
            outSize.right = 1;
        }
        if (outSize.height() < 1) {
            outSize.bottom = 1;
        }

        // Adjust for surface insets.
        outSize.inset(-attrs.surfaceInsets.left, -attrs.surfaceInsets.top,
                -attrs.surfaceInsets.right, -attrs.surfaceInsets.bottom);
    }

    boolean hasSurface() {
        return mSurfaceController != null && mSurfaceController.hasSurface();
    }
@@ -771,20 +738,6 @@ class WindowStateAnimator {
        final LayoutParams attrs = mWin.getAttrs();
        final Task task = w.getTask();

        calculateSurfaceBounds(w, attrs, mTmpSize);

        // Once relayout has been called at least once, we need to make sure
        // we only resize the client surface during calls to relayout. For
        // clients which use indeterminate measure specs (MATCH_PARENT),
        // we may try and change their window size without a call to relayout.
        // However, this would be unsafe, as the client may be in the middle
        // of producing a frame at the old size, having just completed layout
        // to find the surface size changed underneath it.
        final boolean relayout = !w.mRelayoutCalled || w.mInRelayout;
        if (relayout) {
            mSurfaceController.setBufferSizeInTransaction(
                    mTmpSize.width(), mTmpSize.height(), recoveringMemory);
        }
        // If we are undergoing seamless rotation, the surface has already
        // been set up to persist at it's old location. We need to freeze
        // updates until a resize occurs.
@@ -808,6 +761,11 @@ class WindowStateAnimator {

        final Rect insets = attrs.surfaceInsets;

        // getFrameNumber is only valid in the call-stack of relayoutWindow
        // as this is the only-time we know the client renderer
        // is paused.
        final boolean relayout = !w.mRelayoutCalled || w.mInRelayout;

        if (!w.mSeamlesslyRotated) {
            // Used to offset the WSA when stack position changes before a resize.
            int xOffset = mXOffset;