SF Bounds caching 2/3: Compute and cache layer bounds during invalidate stage

- Compute and cache:
   - effective transform - transform applied to source bounds to get the screen bounds,
     taking into account parent scaling and parent transforms.
   - source bounds - bounds of the layer before any transformation is applied and before
      it has been cropped by its parents.
   - bounds - bounds of the layer cropped to its own crop as well as its parents bounds.
   - screen bounds - bounds in screen space calculated by transforming the layer bounds.
- Rename existing computeBounds and computeScreenBounds to make switch easier in
  future patch.
- Update cached bounds when reparenting layers for screenshots.
Note: this change doesn't use the cached values.

Test: go/wm-smoke
Test: atest -a libinput_tests inputflinger_tests SurfaceFlinger_test libsurfaceflinger_unittest SurfaceParcelable_test libgui_test
Change-Id: I5d6ec6fd4acb0f955de27b713691ed99b029dcc2
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 63748bf..89eee6b 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -206,7 +206,7 @@
             memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
         }
 
-        const Rect win{computeBounds()};
+        const Rect win{getBounds()};
         const float bufferWidth = getBufferSize(s).getWidth();
         const float bufferHeight = getBufferSize(s).getHeight();
 
@@ -654,6 +654,38 @@
     return mCompositionLayer;
 }
 
+FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const {
+    const State& s(getDrawingState());
+
+    // If we have a sideband stream, or we are scaling the buffer then return the layer size since
+    // we cannot determine the buffer size.
+    if ((s.sidebandStream != nullptr) ||
+        (getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE)) {
+        return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s));
+    }
+
+    if (mActiveBuffer == nullptr) {
+        return parentBounds;
+    }
+
+    uint32_t bufWidth = mActiveBuffer->getWidth();
+    uint32_t bufHeight = mActiveBuffer->getHeight();
+
+    // Undo any transformations on the buffer and return the result.
+    if (mCurrentTransform & ui::Transform::ROT_90) {
+        std::swap(bufWidth, bufHeight);
+    }
+
+    if (getTransformToDisplayInverse()) {
+        uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+        if (invTransform & ui::Transform::ROT_90) {
+            std::swap(bufWidth, bufHeight);
+        }
+    }
+
+    return FloatRect(0, 0, bufWidth, bufHeight);
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index c118b78..0f8a350 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -191,6 +191,8 @@
     Rect getBufferSize(const State& s) const override;
 
     std::shared_ptr<compositionengine::Layer> mCompositionLayer;
+
+    FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index b95cd2e..45e3b6a 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -313,7 +313,7 @@
     // if the display frame is not defined, use the parent bounds as the buffer size.
     const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
-        Rect parentBounds = Rect(p->computeBounds(Region()));
+        Rect parentBounds = Rect(p->getBounds(Region()));
         if (!parentBounds.isEmpty()) {
             return parentBounds;
         }
@@ -325,6 +325,18 @@
     }
     return Rect::INVALID_RECT;
 }
+
+FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) const {
+    const State& s(getDrawingState());
+    // for buffer state layers we use the display frame size as the buffer size.
+    if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) {
+        return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s));
+    }
+
+    // if the display frame is not defined, use the parent bounds as the buffer size.
+    return parentBounds;
+}
+
 // -----------------------------------------------------------------------
 
 // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index ef287b9..3320c5b 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -88,6 +88,7 @@
                                       uint64_t /*frameNumber*/) override {}
 
     Rect getBufferSize(const State& s) const override;
+    FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
     // -----------------------------------------------------------------------
 
     // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 46e587d..8ff26e1 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -294,22 +294,75 @@
     return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
 }
 
-Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
+Rect Layer::getScreenBounds(bool reduceTransparentRegion) const {
     const State& s(getDrawingState());
     Region transparentRegion = reduceTransparentRegion ? getActiveTransparentRegion(s) : Region();
-    FloatRect bounds = computeBounds(transparentRegion);
+    FloatRect bounds = getBounds(transparentRegion);
     ui::Transform t = getTransform();
     // Transform to screen space.
     bounds = t.transform(bounds);
     return Rect{bounds};
 }
 
-FloatRect Layer::computeBounds() const {
+FloatRect Layer::getBounds() const {
     const State& s(getDrawingState());
-    return computeBounds(getActiveTransparentRegion(s));
+    return getBounds(getActiveTransparentRegion(s));
 }
 
-FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
+ui::Transform Layer::getTransformWithScale() const {
+    // If the layer is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g.
+    // it isFixedSize) then there may be additional scaling not accounted
+    // for in the transform. We need to mirror this scaling to child surfaces
+    // or we will break the contract where WM can treat child surfaces as
+    // pixels in the parent surface.
+    if (!isFixedSize() || !getBE().compositionInfo.mBuffer) {
+        return mEffectiveTransform;
+    }
+
+    int bufferWidth;
+    int bufferHeight;
+    if ((mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
+        bufferWidth = getBE().compositionInfo.mBuffer->getWidth();
+        bufferHeight = getBE().compositionInfo.mBuffer->getHeight();
+    } else {
+        bufferHeight = getBE().compositionInfo.mBuffer->getWidth();
+        bufferWidth = getBE().compositionInfo.mBuffer->getHeight();
+    }
+    float sx = getActiveWidth(getDrawingState()) / static_cast<float>(bufferWidth);
+    float sy = getActiveHeight(getDrawingState()) / static_cast<float>(bufferHeight);
+    ui::Transform extraParentScaling;
+    extraParentScaling.set(sx, 0, 0, sy);
+    return mEffectiveTransform * extraParentScaling;
+}
+
+void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform) {
+    const State& s(getDrawingState());
+
+    // Calculate effective layer transform
+    mEffectiveTransform = parentTransform * getActiveTransform(s);
+
+    // Transform parent bounds to layer space
+    parentBounds = getActiveTransform(s).inverse().transform(parentBounds);
+
+    // Calculate display frame
+    mSourceBounds = computeSourceBounds(parentBounds);
+
+    // Calculate bounds by croping diplay frame with layer crop and parent bounds
+    FloatRect bounds = mSourceBounds;
+    const Rect layerCrop = getCrop(s);
+    if (!layerCrop.isEmpty()) {
+        bounds = mSourceBounds.intersect(layerCrop.toFloatRect());
+    }
+    bounds = bounds.intersect(parentBounds);
+
+    mBounds = bounds;
+    mScreenBounds = mEffectiveTransform.transform(mBounds);
+    for (const sp<Layer>& child : mDrawingChildren) {
+        child->computeBounds(mBounds, getTransformWithScale());
+    }
+}
+
+FloatRect Layer::getBounds(const Region& activeTransparentRegion) const {
     const State& s(getDrawingState());
     Rect bounds = getCroppedBufferSize(s);
     FloatRect floatBounds = bounds.toFloatRect();
@@ -334,7 +387,7 @@
             // parent's perspective we pass in the transparent region to reduce buffer allocation
             // size. When computing the parent bounds from the child's perspective, we pass in an
             // empty transparent region in order to extend into the the parent bounds.
-            floatBounds = p->computeBounds(Region());
+            floatBounds = p->getBounds(Region());
             // Transform back to layer space.
             floatBounds = t.inverse().transform(floatBounds);
         }
@@ -389,7 +442,7 @@
     // if there are no window scaling involved, this operation will map to full
     // pixels in the buffer.
 
-    FloatRect activeCropFloat = computeBounds();
+    FloatRect activeCropFloat = getBounds();
     ui::Transform t = getTransform();
     // Transform to screen space.
     activeCropFloat = t.transform(activeCropFloat);
@@ -550,9 +603,9 @@
                 Rect(activeCrop.right, activeCrop.top, bufferSize.getWidth(), activeCrop.bottom));
     }
 
-    // computeBounds returns a FloatRect to provide more accuracy during the
+    // getBounds returns a FloatRect to provide more accuracy during the
     // transformation. We then round upon constructing 'frame'.
-    Rect frame{t.transform(computeBounds(activeTransparentRegion))};
+    Rect frame{t.transform(getBounds(activeTransparentRegion))};
     if (!frame.intersect(display->getViewport(), &frame)) {
         frame.clear();
     }
@@ -721,7 +774,7 @@
 bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
                                bool useIdentityTransform, Region& /*clearRegion*/,
                                renderengine::LayerSettings& layer) {
-    FloatRect bounds = computeBounds();
+    FloatRect bounds = getBounds();
     half alpha = getAlpha();
     layer.geometry.boundaries = bounds;
     if (useIdentityTransform) {
@@ -841,7 +894,7 @@
                             renderengine::Mesh& mesh,
                             bool useIdentityTransform) const {
     const ui::Transform renderAreaTransform(renderArea.getTransform());
-    FloatRect win = computeBounds();
+    FloatRect win = getBounds();
 
     vec2 lt = vec2(win.left, win.top);
     vec2 lb = vec2(win.left, win.bottom);
@@ -1680,6 +1733,7 @@
 void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
     for (const sp<Layer>& child : mDrawingChildren) {
         child->mDrawingParent = newParent;
+        child->computeBounds(newParent->mBounds, newParent->getTransformWithScale());
     }
 }
 
@@ -2066,7 +2120,7 @@
         }
     }
     const float radius = getDrawingState().cornerRadius;
-    return radius > 0 ? RoundedCornerState(computeBounds(), radius) : RoundedCornerState();
+    return radius > 0 ? RoundedCornerState(getBounds(), radius) : RoundedCornerState();
 }
 
 void Layer::commitChildList() {
@@ -2181,6 +2235,10 @@
     for (const auto& entry : state.metadata.mMap) {
         (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
     }
+    LayerProtoHelper::writeToProto(mEffectiveTransform, layerInfo->mutable_effective_transform());
+    LayerProtoHelper::writeToProto(mSourceBounds, layerInfo->mutable_source_bounds());
+    LayerProtoHelper::writeToProto(mScreenBounds, layerInfo->mutable_screen_bounds());
+    LayerProtoHelper::writeToProto(mBounds, layerInfo->mutable_bounds());
 }
 
 void Layer::writeToProto(LayerProto* layerInfo, DisplayId displayId) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8b6d4c7..83954a3 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -349,8 +349,15 @@
 
     void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh,
                          bool useIdentityTransform) const;
-    FloatRect computeBounds(const Region& activeTransparentRegion) const;
-    FloatRect computeBounds() const;
+    FloatRect getBounds(const Region& activeTransparentRegion) const;
+    FloatRect getBounds() const;
+
+    // Compute bounds for the layer and cache the results.
+    void computeBounds(FloatRect parentBounds, ui::Transform parentTransform);
+
+    // Get effective layer transform, taking into account all its parent transform with any
+    // scaling if the parent scaling more is not NATIVE_WINDOW_SCALING_MODE_FREEZE.
+    ui::Transform getTransformWithScale() const;
 
     int32_t getSequence() const { return sequence; }
 
@@ -643,7 +650,7 @@
     ssize_t removeChild(const sp<Layer>& layer);
     sp<Layer> getParent() const { return mCurrentParent.promote(); }
     bool hasParent() const { return getParent() != nullptr; }
-    Rect computeScreenBounds(bool reduceTransparentRegion = true) const;
+    Rect getScreenBounds(bool reduceTransparentRegion = true) const;
     bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
     bool setChildRelativeLayer(const sp<Layer>& childLayer,
             const sp<IBinder>& relativeToHandle, int32_t relativeZ);
@@ -660,6 +667,15 @@
      */
     virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; }
 
+    /**
+     * Returns the source bounds. If the bounds are not defined, it is inferred from the
+     * buffer size. Failing that, the bounds are determined from the passed in parent bounds.
+     * For the root layer, this is the display viewport size.
+     */
+    virtual FloatRect computeSourceBounds(const FloatRect& parentBounds) const {
+        return parentBounds;
+    }
+
 protected:
     // constant
     sp<SurfaceFlinger> mFlinger;
@@ -892,6 +908,21 @@
      * bounds are constrained by its parent bounds.
      */
     Rect getCroppedBufferSize(const Layer::State& s) const;
+
+    // Cached properties computed from drawing state
+    // Effective transform taking into account parent transforms and any parent scaling.
+    ui::Transform mEffectiveTransform;
+
+    // Bounds of the layer before any transformation is applied and before it has been cropped
+    // by its parents.
+    FloatRect mSourceBounds;
+
+    // Bounds of the layer in layer space. This is the mSourceBounds cropped by its layer crop and
+    // its parent bounds.
+    FloatRect mBounds;
+
+    // Layer bounds in screen space.
+    FloatRect mScreenBounds;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5f8de83..ae2d4aa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1752,9 +1752,13 @@
     ATRACE_CALL();
     bool refreshNeeded = handlePageFlip();
 
+    if (mVisibleRegionsDirty) {
+        computeLayerBounds();
+    }
+
     for (auto& layer : mLayersPendingRefresh) {
         Region visibleReg;
-        visibleReg.set(layer->computeScreenBounds());
+        visibleReg.set(layer->getScreenBounds());
         invalidateLayerStack(layer, visibleReg);
     }
     mLayersPendingRefresh.clear();
@@ -2233,6 +2237,21 @@
 }
 #pragma clang optimize on // b/119477596
 
+void SurfaceFlinger::computeLayerBounds() {
+    for (const auto& pair : mDisplays) {
+        const auto& displayDevice = pair.second;
+        const auto display = displayDevice->getCompositionDisplay();
+        for (const auto& layer : mDrawingState.layersSortedByZ) {
+            // only consider the layers on the given layer stack
+            if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+                return;
+            }
+
+            layer->computeBounds(displayDevice->getViewport().toFloatRect(), ui::Transform());
+        }
+    }
+}
+
 void SurfaceFlinger::rebuildLayerStacks() {
     ATRACE_CALL();
     ALOGV("rebuildLayerStacks");
@@ -2977,7 +2996,7 @@
                 //       compute the actual visible region
                 // TODO: we could cache the transformed region
                 Region visibleReg;
-                visibleReg.set(layer->computeScreenBounds());
+                visibleReg.set(layer->getScreenBounds());
                 invalidateLayerStack(layer, visibleReg);
             }
         });
@@ -3141,7 +3160,7 @@
         // handle hidden surfaces by setting the visible region to empty
         if (CC_LIKELY(layer->isVisible())) {
             const bool translucent = !layer->isOpaque(s);
-            Rect bounds(layer->computeScreenBounds());
+            Rect bounds(layer->getScreenBounds());
 
             visibleRegion.set(bounds);
             ui::Transform tr = layer->getTransform();
@@ -5438,11 +5457,14 @@
             const sp<Layer>& oldParent;
             const sp<Layer>& newParent;
 
-            ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent)
+            ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent,
+                               const Rect& drawingBounds)
                   : oldParent(oldParent), newParent(newParent) {
+                // Compute and cache the bounds for the new parent layer.
+                newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform());
                 oldParent->setChildrenDrawingParent(newParent);
             }
-            ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
+            ~ReparentForDrawing() { newParent->setChildrenDrawingParent(oldParent); }
         };
 
         void render(std::function<void()> drawLayers) override {
@@ -5460,7 +5482,7 @@
                         LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
                                           bounds.getWidth(), bounds.getHeight(), 0));
 
-                ReparentForDrawing reparent(mLayer, screenshotParentLayer);
+                ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
                 drawLayers();
             }
         }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6546973..ca5954c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -591,6 +591,9 @@
             const sp<Layer>& parent,
             bool addToCurrentState);
 
+    // Traverse through all the layers and compute and cache its bounds.
+    void computeLayerBounds();
+
     /* ------------------------------------------------------------------------
      * Boot animation, on/off animations and screen capture
      */
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 4c756d9..72cbfac 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -91,6 +91,11 @@
   optional float corner_radius = 41;
   // Metadata map. May be empty.
   map<int32, bytes> metadata = 42;
+
+  optional TransformProto effective_transform = 43;
+  optional FloatRectProto source_bounds = 44;
+  optional FloatRectProto bounds = 45;
+  optional FloatRectProto screen_bounds = 46;
 }
 
 message PositionProto {
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index ee79c18..3fb8708 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -746,7 +746,7 @@
         layerDrawingState.active.h = 100;
         layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
                                         LayerProperties::COLOR[2], LayerProperties::COLOR[3]);
-
+        layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform());
         layer->setVisibleRegion(Region(Rect(0, 0, 100, 100)));
 
         return layer;