Merge "SF: Fix layer outside of viewport test"
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 55fdacd..e4404bf 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -402,7 +402,7 @@
         const auto& layerFEState = layer->getLayer().getState().frontEnd;
         auto& layerFE = layer->getLayerFE();
 
-        const Region clip(viewportRegion.intersect(layer->getState().visibleRegion));
+        const Region clip(viewportRegion.intersect(layerFEState.geomVisibleRegion));
         ALOGV("Layer: %s", layerFE.getDebugName());
         if (clip.isEmpty()) {
             ALOGV("  Skipping for empty clip");
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index aa35d25..318818a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -16,8 +16,10 @@
 
 #include <cmath>
 
+#include <compositionengine/impl/LayerCompositionState.h>
 #include <compositionengine/impl/Output.h>
 #include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <compositionengine/mock/CompositionEngine.h>
 #include <compositionengine/mock/DisplayColorProfile.h>
 #include <compositionengine/mock/Layer.h>
@@ -25,6 +27,7 @@
 #include <compositionengine/mock/OutputLayer.h>
 #include <compositionengine/mock/RenderSurface.h>
 #include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
@@ -34,10 +37,14 @@
 namespace android::compositionengine {
 namespace {
 
+using testing::_;
 using testing::Return;
 using testing::ReturnRef;
 using testing::StrictMock;
 
+constexpr auto TR_IDENT = 0u;
+constexpr auto TR_ROT_90 = HAL_TRANSFORM_ROT_90;
+
 struct OutputTest : public testing::Test {
     OutputTest() {
         mOutput.setDisplayColorProfileForTest(
@@ -446,5 +453,269 @@
     EXPECT_FALSE(mOutput.getState().usesDeviceComposition);
 }
 
+/*
+ * Output::composeSurfaces()
+ */
+
+struct OutputComposeSurfacesTest : public testing::Test {
+    static constexpr uint32_t kDefaultOutputOrientation = TR_IDENT;
+    static constexpr ui::Dataspace kDefaultOutputDataspace = ui::Dataspace::DISPLAY_P3;
+
+    static const Rect kDefaultOutputFrame;
+    static const Rect kDefaultOutputViewport;
+    static const Rect kDefaultOutputScissor;
+    static const mat4 kDefaultColorTransformMat;
+
+    struct OutputPartialMock : public impl::Output {
+        OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine)
+              : impl::Output(compositionEngine) {}
+
+        // Sets up the helper functions called by composeSurfaces to use a mock
+        // implementations.
+        MOCK_CONST_METHOD0(getSkipColorTransform, bool());
+        MOCK_METHOD2(generateClientCompositionRequests,
+                     std::vector<renderengine::LayerSettings>(bool, Region&));
+        MOCK_METHOD2(appendRegionFlashRequests,
+                     void(const Region&, std::vector<renderengine::LayerSettings>&));
+        MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
+    };
+
+    OutputComposeSurfacesTest() {
+        mOutput.setDisplayColorProfileForTest(
+                std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+        mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+
+        Output::OutputLayers outputLayers;
+        outputLayers.emplace_back(std::unique_ptr<OutputLayer>(mOutputLayer1));
+        outputLayers.emplace_back(std::unique_ptr<OutputLayer>(mOutputLayer2));
+        mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
+
+        mOutput.editState().frame = kDefaultOutputFrame;
+        mOutput.editState().viewport = kDefaultOutputViewport;
+        mOutput.editState().scissor = kDefaultOutputScissor;
+        mOutput.editState().transform = ui::Transform{kDefaultOutputOrientation};
+        mOutput.editState().orientation = kDefaultOutputOrientation;
+        mOutput.editState().dataspace = kDefaultOutputDataspace;
+        mOutput.editState().colorTransformMat = kDefaultColorTransformMat;
+        mOutput.editState().isSecure = true;
+        mOutput.editState().needsFiltering = false;
+        mOutput.editState().usesClientComposition = true;
+        mOutput.editState().usesDeviceComposition = false;
+
+        EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
+    }
+
+    StrictMock<mock::CompositionEngine> mCompositionEngine;
+    StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
+    mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+    mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+    mock::OutputLayer* mOutputLayer1 = new StrictMock<mock::OutputLayer>();
+    mock::OutputLayer* mOutputLayer2 = new StrictMock<mock::OutputLayer>();
+    StrictMock<OutputPartialMock> mOutput{mCompositionEngine};
+    sp<GraphicBuffer> mOutputBuffer = new GraphicBuffer();
+};
+
+const Rect OutputComposeSurfacesTest::kDefaultOutputFrame{1001, 1002, 1003, 1004};
+const Rect OutputComposeSurfacesTest::kDefaultOutputViewport{1005, 1006, 1007, 1008};
+const Rect OutputComposeSurfacesTest::kDefaultOutputScissor{1009, 1010, 1011, 1012};
+const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5};
+
+// TODO(b/121291683): Expand unit test coverage for composeSurfaces beyond these
+// basic tests.
+
+TEST_F(OutputComposeSurfacesTest, doesNothingIfNoClientComposition) {
+    mOutput.editState().usesClientComposition = false;
+
+    Region debugRegion;
+    base::unique_fd readyFence;
+    EXPECT_EQ(true, mOutput.composeSurfaces(debugRegion, &readyFence));
+}
+
+TEST_F(OutputComposeSurfacesTest, worksIfNoClientLayersQueued) {
+    const Region kDebugRegion{Rect{100, 101, 102, 103}};
+
+    constexpr float kDefaultMaxLuminance = 1.0f;
+    constexpr float kDefaultAvgLuminance = 0.7f;
+    constexpr float kDefaultMinLuminance = 0.1f;
+    HdrCapabilities HdrCapabilities{{},
+                                    kDefaultMaxLuminance,
+                                    kDefaultAvgLuminance,
+                                    kDefaultMinLuminance};
+
+    EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillOnce(Return(false));
+    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _)).Times(1);
+
+    EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillOnce(Return(true));
+    EXPECT_CALL(*mDisplayColorProfile, getHdrCapabilities()).WillOnce(ReturnRef(HdrCapabilities));
+
+    EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(mOutputBuffer));
+
+    EXPECT_CALL(mOutput, getSkipColorTransform()).WillOnce(Return(false));
+    EXPECT_CALL(mOutput, generateClientCompositionRequests(false, _)).Times(1);
+    EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _)).Times(1);
+    EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(1);
+    EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false)).Times(1);
+
+    base::unique_fd readyFence;
+    EXPECT_EQ(true, mOutput.composeSurfaces(kDebugRegion, &readyFence));
+}
+
+/*
+ * Output::generateClientCompositionRequests()
+ */
+
+struct GenerateClientCompositionRequestsTest : public testing::Test {
+    struct OutputPartialMock : public impl::Output {
+        OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine)
+              : impl::Output(compositionEngine) {}
+
+        std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+                bool supportsProtectedContent, Region& clearRegion) override {
+            return impl::Output::generateClientCompositionRequests(supportsProtectedContent,
+                                                                   clearRegion);
+        }
+    };
+
+    GenerateClientCompositionRequestsTest() {
+        mOutput.setDisplayColorProfileForTest(
+                std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+        mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+    }
+
+    StrictMock<mock::CompositionEngine> mCompositionEngine;
+    mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+    mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+    StrictMock<OutputPartialMock> mOutput{mCompositionEngine};
+};
+
+// TODO(b/121291683): Add more unit test coverage for generateClientCompositionRequests
+
+TEST_F(GenerateClientCompositionRequestsTest, worksForLandscapeModeSplitScreen) {
+    // In split-screen landscape mode, the screen is rotated 90 degrees, with
+    // one layer on the left covering the left side of the output, and one layer
+    // on the right covering that side of the output.
+
+    mock::OutputLayer* leftOutputLayer = new StrictMock<mock::OutputLayer>();
+    mock::OutputLayer* rightOutputLayer = new StrictMock<mock::OutputLayer>();
+
+    StrictMock<mock::Layer> leftLayer;
+    StrictMock<mock::LayerFE> leftLayerFE;
+    StrictMock<mock::Layer> rightLayer;
+    StrictMock<mock::LayerFE> rightLayerFE;
+
+    impl::OutputLayerCompositionState leftOutputLayerState;
+    leftOutputLayerState.clearClientTarget = false;
+
+    impl::LayerCompositionState leftLayerState;
+    leftLayerState.frontEnd.geomVisibleRegion = Region{Rect{0, 0, 1000, 1000}};
+    leftLayerState.frontEnd.isOpaque = true;
+
+    const half3 leftLayerColor{1.f, 0.f, 0.f};
+    renderengine::LayerSettings leftLayerRESettings;
+    leftLayerRESettings.source.solidColor = leftLayerColor;
+
+    impl::OutputLayerCompositionState rightOutputLayerState;
+    rightOutputLayerState.clearClientTarget = false;
+
+    impl::LayerCompositionState rightLayerState;
+    rightLayerState.frontEnd.geomVisibleRegion = Region{Rect{1000, 0, 2000, 1000}};
+    rightLayerState.frontEnd.isOpaque = true;
+
+    const half3 rightLayerColor{0.f, 1.f, 0.f};
+    renderengine::LayerSettings rightLayerRESettings;
+    rightLayerRESettings.source.solidColor = rightLayerColor;
+
+    EXPECT_CALL(*leftOutputLayer, getState()).WillRepeatedly(ReturnRef(leftOutputLayerState));
+    EXPECT_CALL(*leftOutputLayer, getLayer()).WillRepeatedly(ReturnRef(leftLayer));
+    EXPECT_CALL(*leftOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(leftLayerFE));
+    EXPECT_CALL(*leftOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*leftOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
+    EXPECT_CALL(leftLayer, getState()).WillRepeatedly(ReturnRef(leftLayerState));
+    EXPECT_CALL(leftLayerFE, prepareClientComposition(_)).WillOnce(Return(leftLayerRESettings));
+
+    EXPECT_CALL(*rightOutputLayer, getState()).WillRepeatedly(ReturnRef(rightOutputLayerState));
+    EXPECT_CALL(*rightOutputLayer, getLayer()).WillRepeatedly(ReturnRef(rightLayer));
+    EXPECT_CALL(*rightOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(rightLayerFE));
+    EXPECT_CALL(*rightOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*rightOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
+    EXPECT_CALL(rightLayer, getState()).WillRepeatedly(ReturnRef(rightLayerState));
+    EXPECT_CALL(rightLayerFE, prepareClientComposition(_)).WillOnce(Return(rightLayerRESettings));
+
+    Output::OutputLayers outputLayers;
+    outputLayers.emplace_back(std::unique_ptr<OutputLayer>(leftOutputLayer));
+    outputLayers.emplace_back(std::unique_ptr<OutputLayer>(rightOutputLayer));
+    mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
+
+    const Rect kPortraitFrame(0, 0, 1000, 2000);
+    const Rect kPortraitViewport(0, 0, 2000, 1000);
+    const Rect kPortraitScissor(0, 0, 1000, 2000);
+    const uint32_t kPortraitOrientation = TR_ROT_90;
+
+    mOutput.editState().frame = kPortraitFrame;
+    mOutput.editState().viewport = kPortraitViewport;
+    mOutput.editState().scissor = kPortraitScissor;
+    mOutput.editState().transform = ui::Transform{kPortraitOrientation};
+    mOutput.editState().orientation = kPortraitOrientation;
+    mOutput.editState().needsFiltering = true;
+    mOutput.editState().isSecure = false;
+
+    constexpr bool supportsProtectedContent = false;
+    Region clearRegion;
+    auto requests =
+            mOutput.generateClientCompositionRequests(supportsProtectedContent, clearRegion);
+
+    ASSERT_EQ(2u, requests.size());
+    EXPECT_EQ(leftLayerColor, requests[0].source.solidColor);
+    EXPECT_EQ(rightLayerColor, requests[1].source.solidColor);
+}
+
+TEST_F(GenerateClientCompositionRequestsTest, ignoresLayersThatDoNotIntersectWithViewport) {
+    // Layers whose visible region does not intersect with the viewport will be
+    // skipped when generating client composition request state.
+
+    mock::OutputLayer* outputLayer = new StrictMock<mock::OutputLayer>();
+    StrictMock<mock::Layer> layer;
+    StrictMock<mock::LayerFE> layerFE;
+
+    impl::OutputLayerCompositionState outputLayerState;
+    outputLayerState.clearClientTarget = false;
+
+    impl::LayerCompositionState layerState;
+    layerState.frontEnd.geomVisibleRegion = Region{Rect{3000, 0, 4000, 1000}};
+    layerState.frontEnd.isOpaque = true;
+
+    EXPECT_CALL(*outputLayer, getState()).WillRepeatedly(ReturnRef(outputLayerState));
+    EXPECT_CALL(*outputLayer, getLayer()).WillRepeatedly(ReturnRef(layer));
+    EXPECT_CALL(*outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(layerFE));
+    EXPECT_CALL(*outputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*outputLayer, needsFiltering()).WillRepeatedly(Return(false));
+    EXPECT_CALL(layer, getState()).WillRepeatedly(ReturnRef(layerState));
+    EXPECT_CALL(layerFE, prepareClientComposition(_)).Times(0);
+
+    Output::OutputLayers outputLayers;
+    outputLayers.emplace_back(std::unique_ptr<OutputLayer>(outputLayer));
+    mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
+
+    const Rect kPortraitFrame(0, 0, 1000, 2000);
+    const Rect kPortraitViewport(0, 0, 2000, 1000);
+    const Rect kPortraitScissor(0, 0, 1000, 2000);
+    const uint32_t kPortraitOrientation = TR_ROT_90;
+
+    mOutput.editState().frame = kPortraitFrame;
+    mOutput.editState().viewport = kPortraitViewport;
+    mOutput.editState().scissor = kPortraitScissor;
+    mOutput.editState().transform = ui::Transform{kPortraitOrientation};
+    mOutput.editState().orientation = kPortraitOrientation;
+    mOutput.editState().needsFiltering = true;
+    mOutput.editState().isSecure = false;
+
+    constexpr bool supportsProtectedContent = false;
+    Region clearRegion;
+    auto requests =
+            mOutput.generateClientCompositionRequests(supportsProtectedContent, clearRegion);
+
+    EXPECT_EQ(0u, requests.size());
+}
+
 } // namespace
 } // namespace android::compositionengine