SF: Move/Refactor Layer::setGeometry() to compositionengine::OutputLayer

The front-end Layer now implements only a small bit of functionality
to compute the geometry state of the layer, traversing the parent
hierarchy as needed. The geometry is written to data added to
LayerFECompositionState.

compositionengine::OutputLayer then computes the actual state for the output
the layer is on, storing the result in OutputLayerCompositionState. A
second new function then takes the output-specific layer state (and
output-independent layer state) and sends it to the HWC layer.

Implements partial tests for the new functions.

Test: atest libsurfaceflinger_unittest libcompositionengine_test
Bug: 121291683
Change-Id: Idc770e6c84d046555cc11d75d53fa22c4be4ae58
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index f7dcf6f..2060c5a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -23,16 +23,37 @@
 
 #include "MockHWC2.h"
 #include "MockHWComposer.h"
+#include "RectMatcher.h"
 
 namespace android::compositionengine {
 namespace {
 
+using testing::_;
+using testing::Return;
+using testing::ReturnRef;
 using testing::StrictMock;
 
 constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
 
+constexpr auto TR_IDENT = 0u;
+constexpr auto TR_FLP_H = HAL_TRANSFORM_FLIP_H;
+constexpr auto TR_FLP_V = HAL_TRANSFORM_FLIP_V;
+constexpr auto TR_ROT_90 = HAL_TRANSFORM_ROT_90;
+constexpr auto TR_ROT_180 = TR_FLP_H | TR_FLP_V;
+constexpr auto TR_ROT_270 = TR_ROT_90 | TR_ROT_180;
+
+const std::string kOutputName{"Test Output"};
+
 class OutputLayerTest : public testing::Test {
 public:
+    OutputLayerTest() {
+        EXPECT_CALL(*mLayerFE, getDebugName()).WillRepeatedly(Return("Test LayerFE"));
+        EXPECT_CALL(mOutput, getName()).WillRepeatedly(ReturnRef(kOutputName));
+
+        EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState));
+        EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
+    }
+
     ~OutputLayerTest() override = default;
 
     compositionengine::mock::Output mOutput;
@@ -41,15 +62,18 @@
     sp<compositionengine::mock::LayerFE> mLayerFE{
             new StrictMock<compositionengine::mock::LayerFE>()};
     impl::OutputLayer mOutputLayer{mOutput, mLayer, mLayerFE};
+
+    impl::LayerCompositionState mLayerState;
+    impl::OutputCompositionState mOutputState;
 };
 
-/* ------------------------------------------------------------------------
+/*
  * Basic construction
  */
 
 TEST_F(OutputLayerTest, canInstantiateOutputLayer) {}
 
-/* ------------------------------------------------------------------------
+/*
  * OutputLayer::initialize()
  */
 
@@ -71,15 +95,220 @@
 
     mOutputLayer.initialize(compositionEngine, DEFAULT_DISPLAY_ID);
 
-    const auto& state = mOutputLayer.getState();
-    ASSERT_TRUE(state.hwc);
+    const auto& outputLayerState = mOutputLayer.getState();
+    ASSERT_TRUE(outputLayerState.hwc);
 
-    const auto& hwcState = *state.hwc;
+    const auto& hwcState = *outputLayerState.hwc;
     EXPECT_EQ(&hwcLayer, hwcState.hwcLayer.get());
 
     EXPECT_CALL(hwc, destroyLayer(DEFAULT_DISPLAY_ID, &hwcLayer));
     mOutputLayer.editState().hwc.reset();
 }
 
+/*
+ * OutputLayer::calculateOutputDisplayFrame()
+ */
+
+struct OutputLayerDisplayFrameTest : public OutputLayerTest {
+    OutputLayerDisplayFrameTest() {
+        // Set reasonable default values for a simple case. Each test will
+        // set one specific value to something different.
+
+        mLayerState.frontEnd.geomActiveTransparentRegion = Region{};
+        mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT};
+        mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080};
+        mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = false;
+        mLayerState.frontEnd.geomCrop = Rect{0, 0, 1920, 1080};
+        mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f};
+
+        mOutputState.viewport = Rect{0, 0, 1920, 1080};
+        mOutputState.transform = ui::Transform{TR_IDENT};
+    }
+
+    Rect calculateOutputDisplayFrame() {
+        mLayerState.frontEnd.geomInverseLayerTransform =
+                mLayerState.frontEnd.geomLayerTransform.inverse();
+
+        return mOutputLayer.calculateOutputDisplayFrame();
+    }
+};
+
+TEST_F(OutputLayerDisplayFrameTest, correctForSimpleDefaultCase) {
+    const Rect expected{0, 0, 1920, 1080};
+    EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+}
+
+TEST_F(OutputLayerDisplayFrameTest, fullActiveTransparentRegionReturnsEmptyFrame) {
+    mLayerState.frontEnd.geomActiveTransparentRegion = Region{Rect{0, 0, 1920, 1080}};
+    const Rect expected{0, 0, 0, 0};
+    EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+}
+
+TEST_F(OutputLayerDisplayFrameTest, cropAffectsDisplayFrame) {
+    mLayerState.frontEnd.geomCrop = Rect{100, 200, 300, 500};
+    const Rect expected{100, 200, 300, 500};
+    EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+}
+
+TEST_F(OutputLayerDisplayFrameTest, cropAffectsDisplayFrameRotated) {
+    mLayerState.frontEnd.geomCrop = Rect{100, 200, 300, 500};
+    mLayerState.frontEnd.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080);
+    const Rect expected{1420, 100, 1720, 300};
+    EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+}
+
+TEST_F(OutputLayerDisplayFrameTest, emptyGeomCropIsNotUsedToComputeFrame) {
+    mLayerState.frontEnd.geomCrop = Rect{};
+    const Rect expected{0, 0, 1920, 1080};
+    EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+}
+
+TEST_F(OutputLayerDisplayFrameTest, geomLayerSnapToBoundsAffectsFrame) {
+    mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f};
+    const Rect expected{0, 0, 960, 540};
+    EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+}
+
+TEST_F(OutputLayerDisplayFrameTest, viewportAffectsFrame) {
+    mOutputState.viewport = Rect{0, 0, 960, 540};
+    const Rect expected{0, 0, 960, 540};
+    EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+}
+
+TEST_F(OutputLayerDisplayFrameTest, outputTransformAffectsDisplayFrame) {
+    mOutputState.transform = ui::Transform{HAL_TRANSFORM_ROT_90};
+    const Rect expected{-1080, 0, 0, 1920};
+    EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
+}
+
+/*
+ * OutputLayer::calculateOutputRelativeBufferTransform()
+ */
+
+TEST_F(OutputLayerTest, calculateOutputRelativeBufferTransformTestsNeeded) {
+    mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = false;
+
+    struct Entry {
+        uint32_t layer;
+        uint32_t buffer;
+        uint32_t display;
+        uint32_t expected;
+    };
+    // Not an exhaustive list of cases, but hopefully enough.
+    const std::array<Entry, 24> testData = {
+            // clang-format off
+            //             layer       buffer      display     expected
+            /*  0 */ Entry{TR_IDENT,   TR_IDENT,   TR_IDENT,   TR_IDENT},
+            /*  1 */ Entry{TR_IDENT,   TR_IDENT,   TR_ROT_90,  TR_ROT_90},
+            /*  2 */ Entry{TR_IDENT,   TR_IDENT,   TR_ROT_180, TR_ROT_180},
+            /*  3 */ Entry{TR_IDENT,   TR_IDENT,   TR_ROT_270, TR_ROT_270},
+
+            /*  4 */ Entry{TR_IDENT,   TR_FLP_H,   TR_IDENT,   TR_FLP_H ^ TR_IDENT},
+            /*  5 */ Entry{TR_IDENT,   TR_FLP_H,   TR_ROT_90,  TR_FLP_H ^ TR_ROT_90},
+            /*  6 */ Entry{TR_IDENT,   TR_FLP_H,   TR_ROT_180, TR_FLP_H ^ TR_ROT_180},
+            /*  7 */ Entry{TR_IDENT,   TR_FLP_H,   TR_ROT_270, TR_FLP_H ^ TR_ROT_270},
+
+            /*  8 */ Entry{TR_IDENT,   TR_FLP_V,   TR_IDENT,   TR_FLP_V},
+            /*  9 */ Entry{TR_IDENT,   TR_ROT_90,  TR_ROT_90,  TR_ROT_180},
+            /* 10 */ Entry{TR_IDENT,   TR_ROT_180, TR_ROT_180, TR_IDENT},
+            /* 11 */ Entry{TR_IDENT,   TR_ROT_270, TR_ROT_270, TR_ROT_180},
+
+            /* 12 */ Entry{TR_ROT_90,  TR_IDENT,   TR_IDENT,   TR_IDENT ^ TR_ROT_90},
+            /* 13 */ Entry{TR_ROT_90,  TR_FLP_H,   TR_ROT_90,  TR_FLP_H ^ TR_ROT_180},
+            /* 14 */ Entry{TR_ROT_90,  TR_IDENT,   TR_ROT_180, TR_IDENT ^ TR_ROT_270},
+            /* 15 */ Entry{TR_ROT_90,  TR_FLP_H,   TR_ROT_270, TR_FLP_H ^ TR_IDENT},
+
+            /* 16 */ Entry{TR_ROT_180, TR_FLP_H,   TR_IDENT,   TR_FLP_H ^ TR_ROT_180},
+            /* 17 */ Entry{TR_ROT_180, TR_IDENT,   TR_ROT_90,  TR_IDENT ^ TR_ROT_270},
+            /* 18 */ Entry{TR_ROT_180, TR_FLP_H,   TR_ROT_180, TR_FLP_H ^ TR_IDENT},
+            /* 19 */ Entry{TR_ROT_180, TR_IDENT,   TR_ROT_270, TR_IDENT ^ TR_ROT_90},
+
+            /* 20 */ Entry{TR_ROT_270, TR_IDENT,   TR_IDENT,   TR_IDENT ^ TR_ROT_270},
+            /* 21 */ Entry{TR_ROT_270, TR_FLP_H,   TR_ROT_90,  TR_FLP_H ^ TR_IDENT},
+            /* 22 */ Entry{TR_ROT_270, TR_FLP_H,   TR_ROT_180, TR_FLP_H ^ TR_ROT_90},
+            /* 23 */ Entry{TR_ROT_270, TR_IDENT,   TR_ROT_270, TR_IDENT ^ TR_ROT_180},
+            // clang-format on
+    };
+
+    for (size_t i = 0; i < testData.size(); i++) {
+        const auto& entry = testData[i];
+
+        mLayerState.frontEnd.geomLayerTransform.set(entry.layer, 1920, 1080);
+        mLayerState.frontEnd.geomBufferTransform = entry.buffer;
+        mOutputState.orientation = entry.display;
+
+        auto actual = mOutputLayer.calculateOutputRelativeBufferTransform();
+        EXPECT_EQ(entry.expected, actual) << "entry " << i;
+    }
+}
+
+/*
+ * OutputLayer::writeStateToHWC()
+ */
+
+struct OutputLayerWriteStateToHWCTest : public OutputLayerTest {
+    static constexpr HWC2::Error kError = HWC2::Error::Unsupported;
+    static constexpr FloatRect kSourceCrop{11.f, 12.f, 13.f, 14.f};
+    static constexpr uint32_t kZOrder = 21u;
+    static constexpr Hwc2::Transform kBufferTransform = static_cast<Hwc2::Transform>(31);
+    static constexpr Hwc2::IComposerClient::BlendMode kBlendMode =
+            static_cast<Hwc2::IComposerClient::BlendMode>(41);
+    static constexpr float kAlpha = 51.f;
+    static constexpr uint32_t kType = 61u;
+    static constexpr uint32_t kAppId = 62u;
+
+    static const Rect kDisplayFrame;
+
+    OutputLayerWriteStateToHWCTest() {
+        auto& outputLayerState = mOutputLayer.editState();
+        outputLayerState.hwc = impl::OutputLayerCompositionState::Hwc(mHwcLayer);
+
+        outputLayerState.displayFrame = kDisplayFrame;
+        outputLayerState.sourceCrop = kSourceCrop;
+        outputLayerState.z = kZOrder;
+        outputLayerState.bufferTransform = static_cast<Hwc2::Transform>(kBufferTransform);
+
+        mLayerState.frontEnd.blendMode = kBlendMode;
+        mLayerState.frontEnd.alpha = kAlpha;
+        mLayerState.frontEnd.type = kType;
+        mLayerState.frontEnd.appId = kAppId;
+    }
+
+    void expectGeometryCommonCalls() {
+        EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError));
+        EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError));
+        EXPECT_CALL(*mHwcLayer, setZOrder(kZOrder)).WillOnce(Return(kError));
+        EXPECT_CALL(*mHwcLayer, setTransform(static_cast<HWC2::Transform>(kBufferTransform)))
+                .WillOnce(Return(kError));
+
+        EXPECT_CALL(*mHwcLayer, setBlendMode(static_cast<HWC2::BlendMode>(kBlendMode)))
+                .WillOnce(Return(kError));
+        EXPECT_CALL(*mHwcLayer, setPlaneAlpha(kAlpha)).WillOnce(Return(kError));
+        EXPECT_CALL(*mHwcLayer, setInfo(kType, kAppId)).WillOnce(Return(kError));
+    }
+
+    std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
+};
+
+const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
+
+TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) {
+    mOutputLayer.editState().hwc.reset();
+
+    mOutputLayer.writeStateToHWC(true);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCLayer) {
+    mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc(nullptr);
+
+    mOutputLayer.writeStateToHWC(true);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetsAllState) {
+    expectGeometryCommonCalls();
+
+    mOutputLayer.writeStateToHWC(true);
+}
+
 } // namespace
 } // namespace android::compositionengine