ProjectionSpace fixes for caching:

* When feeding back into client composition, feed back the framebuffer
projection space instead of a projection space using mBounds as the
content rectangle. Otherwise, this tries to project the entire cached
set onto the entirety of the display, which is incorrect. Instead, the
cached set needs to be projected onto the displayFrame for the
overridden layer.
* When rendering the cached set and computing the physicalDisplay
rectangle, instead of passing in the framebuffer space bounds offset by
mBounds, pass in the framebuffer space content offset by mBounds.
Otherwise, this breaks simulated secondary displays: simulated secondary
displays works by projecting the layer stack onto a rectangle in the
middle of surface that is much narrower than the surface bounds. If the
framebuffer bounds are used to compute the physicalDisplay rectangle and
the cached set covers the entire secondary display, then when offset by
mBounds the cached set goes offscreen. The correct rectangle to use is
the framebuffer content rectangle.

Bug: 185398025
Test: libcompositionengine_test
Test: Simulated secondary displays
Test: Wallpaper picker doesn't suddenly resize when pulling down the
notification shade

Change-Id: Ie7119bc42db4887b448673c0ab11fee24db664c5
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
index 7ca91d8..58bb41a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
@@ -96,6 +96,11 @@
         // physical translation and finally rotate to the physical orientation.
         return rotationTransform * destTranslation * scale * sourceTranslation;
     }
+
+    bool operator==(const ProjectionSpace& other) const {
+        return bounds == other.bounds && content == other.content &&
+                orientation == other.orientation;
+    }
 };
 
 } // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 5f26817..4cf83d9 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -158,11 +158,12 @@
     const ui::Dataspace& outputDataspace = outputState.dataspace;
     const ui::Transform::RotationFlags orientation =
             ui::Transform::toRotationFlags(outputState.framebufferSpace.orientation);
+
     renderengine::DisplaySettings displaySettings{
-            .physicalDisplay =
-                    Rect(-mBounds.left, -mBounds.top,
-                         -mBounds.left + outputState.framebufferSpace.content.getWidth(),
-                         -mBounds.top + outputState.framebufferSpace.content.getHeight()),
+            .physicalDisplay = Rect(-mBounds.left + outputState.framebufferSpace.content.left,
+                                    -mBounds.top + outputState.framebufferSpace.content.top,
+                                    -mBounds.left + outputState.framebufferSpace.content.right,
+                                    -mBounds.top + outputState.framebufferSpace.content.bottom),
             .clip = viewport,
             .outputDataspace = outputDataspace,
             .orientation = orientation,
@@ -249,9 +250,7 @@
 
     if (result == NO_ERROR) {
         mDrawFence = new Fence(drawFence.release());
-        mOutputSpace = ProjectionSpace(ui::Size(outputState.framebufferSpace.bounds.getWidth(),
-                                                outputState.framebufferSpace.bounds.getHeight()),
-                                       mBounds);
+        mOutputSpace = outputState.framebufferSpace;
         mTexture = std::move(texture);
         mOutputSpace.orientation = outputState.framebufferSpace.orientation;
         mOutputDataspace = outputDataspace;
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 2f2c670..8884711 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -325,10 +325,55 @@
     cachedSet.render(mRenderEngine, mOutputState);
     expectReadyBuffer(cachedSet);
 
-    EXPECT_EQ(Rect(1, 1, 3, 3), cachedSet.getOutputSpace().content);
-    EXPECT_EQ(Rect(mOutputState.framebufferSpace.bounds.getWidth(),
-                   mOutputState.framebufferSpace.bounds.getHeight()),
-              cachedSet.getOutputSpace().bounds);
+    EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
+
+    // Now check that appending a new cached set properly cleans up RenderEngine resources.
+    CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+    cachedSet.append(CachedSet(layer3));
+}
+
+TEST_F(CachedSetTest, rendersWithOffsetFramebufferContent) {
+    // Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0)
+    CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get();
+    sp<mock::LayerFE> layerFE1 = mTestLayers[1]->layerFE;
+    CachedSet::Layer& layer2 = *mTestLayers[2]->cachedSetLayer.get();
+    sp<mock::LayerFE> layerFE2 = mTestLayers[2]->layerFE;
+
+    CachedSet cachedSet(layer1);
+    cachedSet.append(CachedSet(layer2));
+
+    std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1;
+    clientCompList1.push_back({});
+    clientCompList1[0].alpha = 0.5f;
+
+    std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2;
+    clientCompList2.push_back({});
+    clientCompList2[0].alpha = 0.75f;
+
+    mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(2, 3, 10, 5));
+
+    const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
+                                const std::vector<const renderengine::LayerSettings*>& layers,
+                                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+                                base::unique_fd&&, base::unique_fd*) -> size_t {
+        EXPECT_EQ(Rect(1, 2, 9, 4), displaySettings.physicalDisplay);
+        EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
+        EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
+                  displaySettings.orientation);
+        EXPECT_EQ(0.5f, layers[0]->alpha);
+        EXPECT_EQ(0.75f, layers[1]->alpha);
+        EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
+
+        return NO_ERROR;
+    };
+
+    EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
+    EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
+    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+    cachedSet.render(mRenderEngine, mOutputState);
+    expectReadyBuffer(cachedSet);
+
+    EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
 
     // Now check that appending a new cached set properly cleans up RenderEngine resources.
     CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index c528087..373b895 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -275,11 +275,7 @@
     mTime += 200ms;
     expectAllLayersFlattened(layers);
 
-    EXPECT_EQ(overrideDisplaySpace.bounds,
-              Rect(mOutputState.framebufferSpace.bounds.getWidth(),
-                   mOutputState.framebufferSpace.bounds.getHeight()));
-    EXPECT_EQ(overrideDisplaySpace.content, Rect(0, 0, 2, 2));
-    EXPECT_EQ(overrideDisplaySpace.orientation, mOutputState.framebufferSpace.orientation);
+    EXPECT_EQ(overrideDisplaySpace, mOutputState.framebufferSpace);
 }
 
 TEST_F(FlattenerTest, flattenLayers_FlattenedLayersSetsDamageRegions) {