[CE] Separate framebuffer space from display space

Some devices have limited GPU capabilities and they
cannot perform client composition at the resolution
of the active display mode. For this reason the
framebuffer size can be limited with the sysrops
ro.surface_flinger.max_graphics_height|width.

As the framebuffer size can differ from the display
size, in this CL we separate the concepts for
framebuffer space and display space so we properly
render.

Bug: 161793589
Bug: 168788659
Test: atest libsurfaceflinger_unittest libcompositionengine_test
Test: 1. adb shell service call SurfaceFlinger 1008 i32 1
      2. make sure content is rendered properly
      3. adb shell service call SurfaceFlinger 1008 i32 0
      4. make sure content is rendered properly
Test: play YouTube video

Change-Id: I17d54ef8c85773c072f0c38f576f3f3be504d6ec
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index fc1adcc..d590f23 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -166,7 +166,7 @@
     virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
                                const Rect& orientedDisplaySpaceRect) = 0;
     // Sets the bounds to use
-    virtual void setDisplaySpaceSize(const ui::Size&) = 0;
+    virtual void setDisplaySize(const ui::Size&) = 0;
 
     // Sets the layer stack filtering settings for this output. See
     // belongsInOutput for full details.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 6fe93bf..5b832a5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -40,7 +40,7 @@
     void setCompositionEnabled(bool) override;
     void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
                        const Rect& orientedDisplaySpaceRect) override;
-    void setDisplaySpaceSize(const ui::Size&) override;
+    void setDisplaySize(const ui::Size&) override;
     void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
 
     void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index f4d2b56..06e6a6f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -39,7 +39,7 @@
 namespace compositionengine::impl {
 
 struct OutputCompositionState {
-    // If false, composition will not per performed for this display
+    // If false, composition will not be performed for this display
     bool isEnabled{false};
 
     // If false, this output is not considered secure
@@ -71,6 +71,11 @@
     // match the orientation of layerStackSpace. The orientation of this space is always ROTATION_0.
     ProjectionSpace orientedDisplaySpace;
 
+    // The space of the framebuffer. Its bounds match the size of the framebuffer and its
+    // orientation matches the orientation of the display. Typically the framebuffer space will
+    // be identical to the physical display space.
+    ProjectionSpace framebufferSpace;
+
     // The space of the physical display. It is as big as the currently active display mode. The
     // content in this space can be rotated.
     ProjectionSpace displaySpace;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 19025c1..d6fbd7f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -37,7 +37,7 @@
 
     MOCK_METHOD1(setCompositionEnabled, void(bool));
     MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
-    MOCK_METHOD1(setDisplaySpaceSize, void(const ui::Size&));
+    MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
     MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
 
     MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index d201104..5459861 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -55,6 +55,7 @@
     mPowerAdvisor = args.powerAdvisor;
 
     editState().isSecure = args.isSecure;
+    editState().displaySpace.bounds = Rect(args.pixels);
 
     setLayerStackFilter(args.layerStackId,
                         args.physical ? args.physical->type == DisplayConnectionType::Internal
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index abb8769..44edb6e 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -69,6 +69,19 @@
     return Reversed<T>(c);
 }
 
+struct ScaleVector {
+    float x;
+    float y;
+};
+
+// Returns a ScaleVector (x, y) such that from.scale(x, y) = to',
+// where to' will have the same size as "to". In the case where "from" and "to"
+// start at the origin to'=to.
+ScaleVector getScale(const Rect& from, const Rect& to) {
+    return {.x = static_cast<float>(to.width()) / from.width(),
+            .y = static_cast<float>(to.height()) / from.height()};
+}
+
 } // namespace
 
 std::shared_ptr<Output> createOutput(
@@ -110,9 +123,10 @@
     auto& outputState = editState();
 
     outputState.displaySpace.orientation = orientation;
-    // outputState.displaySpace.bounds should be already set from setDisplaySpaceSize().
+    LOG_FATAL_IF(outputState.displaySpace.bounds == Rect::INVALID_RECT,
+                 "The display bounds are unknown.");
 
-    // Compute the orientedDisplaySpace bounds
+    // Compute orientedDisplaySpace
     ui::Size orientedSize = outputState.displaySpace.bounds.getSize();
     if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
         std::swap(orientedSize.width, orientedSize.height);
@@ -129,17 +143,51 @@
     }
     outputState.displaySpace.content = rotation.transform(orientedDisplaySpaceRect);
 
+    // Compute framebufferSpace
+    outputState.framebufferSpace.orientation = orientation;
+    LOG_FATAL_IF(outputState.framebufferSpace.bounds == Rect::INVALID_RECT,
+                 "The framebuffer bounds are unknown.");
+    const auto scale =
+            getScale(outputState.framebufferSpace.bounds, outputState.displaySpace.bounds);
+    outputState.framebufferSpace.content = outputState.displaySpace.content.scale(scale.x, scale.y);
+
+    // Compute layerStackSpace
     outputState.layerStackSpace.content = layerStackSpaceRect;
     outputState.layerStackSpace.bounds = layerStackSpaceRect;
+
     outputState.transform = outputState.layerStackSpace.getTransform(outputState.displaySpace);
     outputState.needsFiltering = outputState.transform.needsBilinearFiltering();
-
     dirtyEntireOutput();
 }
 
-void Output::setDisplaySpaceSize(const ui::Size& size) {
+void Output::setDisplaySize(const ui::Size& size) {
     mRenderSurface->setDisplaySize(size);
-    editState().displaySpace.bounds = Rect(mRenderSurface->getSize());
+
+    auto& state = editState();
+
+    // Update framebuffer space
+    const Rect newBounds(size);
+    ScaleVector scale;
+    scale = getScale(state.framebufferSpace.bounds, newBounds);
+    state.framebufferSpace.bounds = newBounds;
+    state.framebufferSpace.content.scaleSelf(scale.x, scale.y);
+
+    // Update display space
+    scale = getScale(state.displaySpace.bounds, newBounds);
+    state.displaySpace.bounds = newBounds;
+    state.displaySpace.content.scaleSelf(scale.x, scale.y);
+    state.transform = state.layerStackSpace.getTransform(state.displaySpace);
+
+    // Update oriented display space
+    const auto orientation = state.displaySpace.orientation;
+    ui::Size orientedSize = size;
+    if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
+        std::swap(orientedSize.width, orientedSize.height);
+    }
+    const Rect newOrientedBounds(orientedSize);
+    scale = getScale(state.orientedDisplaySpace.bounds, newOrientedBounds);
+    state.orientedDisplaySpace.bounds = newOrientedBounds;
+    state.orientedDisplaySpace.content.scaleSelf(scale.x, scale.y);
 
     dirtyEntireOutput();
 }
@@ -247,8 +295,7 @@
 
 void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
     mRenderSurface = std::move(surface);
-    editState().displaySpace.bounds = Rect(mRenderSurface->getSize());
-
+    editState().framebufferSpace.bounds = Rect(mRenderSurface->getSize());
     dirtyEntireOutput();
 }
 
@@ -877,7 +924,7 @@
     ALOGV("hasClientComposition");
 
     renderengine::DisplaySettings clientCompositionDisplay;
-    clientCompositionDisplay.physicalDisplay = outputState.displaySpace.content;
+    clientCompositionDisplay.physicalDisplay = outputState.framebufferSpace.content;
     clientCompositionDisplay.clip = outputState.layerStackSpace.content;
     clientCompositionDisplay.orientation =
             ui::Transform::toRotationFlags(outputState.displaySpace.orientation);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 776fdde..ee30ad8 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -39,6 +39,8 @@
     out.append("\n   ");
     dumpVal(out, "layerStackSpace", to_string(layerStackSpace));
     out.append("\n   ");
+    dumpVal(out, "framebufferSpace", to_string(framebufferSpace));
+    out.append("\n   ");
     dumpVal(out, "orientedDisplaySpace", to_string(orientedDisplaySpace));
     out.append("\n   ");
     dumpVal(out, "displaySpace", to_string(displaySpace));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index c01f3e0..57b399a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -248,20 +248,46 @@
 }
 
 /*
- * Output::setDisplaySpaceSize()
+ * Output::setDisplaySize()
  */
 
-TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
-    const ui::Size displaySize{200, 400};
+TEST_F(OutputTest, setDisplaySpaceSizeUpdatesOutputStateAndDirtiesEntireOutput) {
+    mOutput->editState().layerStackSpace.content = Rect(0, 0, 2000, 1000);
+    mOutput->editState().layerStackSpace.bounds = Rect(0, 0, 2000, 1000);
+    mOutput->editState().orientedDisplaySpace.content = Rect(0, 0, 1800, 900);
+    mOutput->editState().orientedDisplaySpace.bounds = Rect(0, 0, 2000, 1000);
+    mOutput->editState().framebufferSpace.content = Rect(0, 0, 900, 1800);
+    mOutput->editState().framebufferSpace.bounds = Rect(0, 0, 1000, 2000);
+    mOutput->editState().framebufferSpace.orientation = ui::ROTATION_90;
+    mOutput->editState().displaySpace.content = Rect(0, 0, 900, 1800);
+    mOutput->editState().displaySpace.bounds = Rect(0, 0, 1000, 2000);
+    mOutput->editState().displaySpace.orientation = ui::ROTATION_90;
 
-    EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
-    EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
+    const ui::Size newDisplaySize{500, 1000};
 
-    mOutput->setDisplaySpaceSize(displaySize);
+    EXPECT_CALL(*mRenderSurface, setDisplaySize(newDisplaySize)).Times(1);
 
-    EXPECT_EQ(Rect(displaySize), mOutput->getState().displaySpace.bounds);
+    mOutput->setDisplaySize(newDisplaySize);
 
-    EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
+    const auto state = mOutput->getState();
+
+    const Rect displayRect(newDisplaySize);
+    EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.orientation);
+    EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.content);
+    EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.bounds);
+    EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.orientation);
+    EXPECT_EQ(Rect(0, 0, 900, 450), state.orientedDisplaySpace.content);
+    EXPECT_EQ(Rect(0, 0, 1000, 500), state.orientedDisplaySpace.bounds);
+    EXPECT_EQ(displayRect, state.displaySpace.bounds);
+    EXPECT_EQ(Rect(0, 0, 450, 900), state.displaySpace.content);
+    EXPECT_EQ(ui::ROTATION_90, state.displaySpace.orientation);
+    EXPECT_EQ(displayRect, state.framebufferSpace.bounds);
+    EXPECT_EQ(Rect(0, 0, 450, 900), state.framebufferSpace.content);
+    EXPECT_EQ(ui::ROTATION_90, state.framebufferSpace.orientation);
+
+    EXPECT_EQ(state.displaySpace.content, state.transform.transform(state.layerStackSpace.content));
+
+    EXPECT_THAT(state.dirtyRegion, RegionEq(Region(displayRect)));
 }
 
 /*
@@ -422,7 +448,7 @@
 
     mOutput->setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
 
-    EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().displaySpace.bounds);
+    EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().framebufferSpace.bounds);
 }
 
 /*
@@ -2778,9 +2804,10 @@
 
         mOutput.mState.orientedDisplaySpace.content = kDefaultOutputFrame;
         mOutput.mState.layerStackSpace.content = kDefaultOutputViewport;
+        mOutput.mState.framebufferSpace.content = kDefaultOutputDestinationClip;
         mOutput.mState.displaySpace.content = kDefaultOutputDestinationClip;
-        mOutput.mState.transform = ui::Transform{kDefaultOutputOrientationFlags};
         mOutput.mState.displaySpace.orientation = kDefaultOutputOrientation;
+        mOutput.mState.transform = ui::Transform{kDefaultOutputOrientationFlags};
         mOutput.mState.dataspace = kDefaultOutputDataspace;
         mOutput.mState.colorTransformMatrix = kDefaultColorTransformMat;
         mOutput.mState.isSecure = false;