SF: Predict HWC composition strategy

Asynchronously run ValidateDisplay to determine client composition
strategy. If we can predict that the composition strategy will not
change from frame to frame (for example by looking at whether
the geometry of the layers is changing), the hwc call is run
asynchronously with the gpu composition. If the result of the call is
incorrectly predicted, the gpu composition is rerun.

ValidateDisplay can take multiple milliseconds to complete and by
making it non-blocking in cases where we can predict the strategy
chosen by the hardware, we can jump start the client composition
and shave valuable milliseconds from the frame time.

This feature is disabled by default.

Test: perfetto traces
Bug: 220031739

Change-Id: Ib4dcc0e055d5272c89cfff853211edac73aa449b
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index cd03235..36b04d9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -30,7 +30,9 @@
 #include <compositionengine/mock/OutputLayer.h>
 #include <compositionengine/mock/RenderSurface.h>
 #include <gtest/gtest.h>
+#include <renderengine/mock/FakeExternalTexture.h>
 #include <renderengine/mock/RenderEngine.h>
+
 #include <ui/Rect.h>
 #include <ui/StaticDisplayInfo.h>
 
@@ -198,6 +200,22 @@
     std::shared_ptr<Display> mDisplay =
             createPartialMockDisplay<Display>(mCompositionEngine,
                                               getDisplayCreationArgsForPhysicalDisplay());
+
+    android::HWComposer::DeviceRequestedChanges mDeviceRequestedChanges{
+            {{nullptr, Composition::CLIENT}},
+            hal::DisplayRequest::FLIP_CLIENT_TARGET,
+            {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
+            {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN},
+            -1.f,
+    };
+
+    void chooseCompositionStrategy(Display* display) {
+        std::optional<android::HWComposer::DeviceRequestedChanges> changes =
+                display->chooseCompositionStrategy();
+        if (changes) {
+            display->applyCompositionStrategy(changes);
+        }
+    }
 };
 
 struct FullDisplayImplTestCommon : public DisplayTestCommon {
@@ -214,6 +232,11 @@
                 std::unique_ptr<compositionengine::OutputLayer>(mLayer2.outputLayer));
         mDisplay->injectOutputLayerForTest(
                 std::unique_ptr<compositionengine::OutputLayer>(mLayer3.outputLayer));
+        mResultWithBuffer.buffer = std::make_shared<
+                renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+                                                         1ULL /* bufferId */,
+                                                         HAL_PIXEL_FORMAT_RGBA_8888,
+                                                         0ULL /*usage*/);
     }
 
     Layer mLayer1;
@@ -222,6 +245,8 @@
     StrictMock<HWC2::mock::Layer> hwc2LayerUnknown;
     std::shared_ptr<Display> mDisplay =
             createDisplay<Display>(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay());
+    impl::GpuCompositionResult mResultWithBuffer;
+    impl::GpuCompositionResult mResultWithoutBuffer;
 };
 
 /*
@@ -554,7 +579,7 @@
             createPartialMockDisplay<Display>(mCompositionEngine, args);
     EXPECT_TRUE(GpuVirtualDisplayId::tryCast(gpuDisplay->getId()));
 
-    gpuDisplay->chooseCompositionStrategy();
+    chooseCompositionStrategy(gpuDisplay.get());
 
     auto& state = gpuDisplay->getState();
     EXPECT_TRUE(state.usesClientComposition);
@@ -567,11 +592,12 @@
                 getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), false, _, _, _, _))
             .WillOnce(Return(INVALID_OPERATION));
 
-    mDisplay->chooseCompositionStrategy();
+    chooseCompositionStrategy(mDisplay.get());
 
     auto& state = mDisplay->getState();
     EXPECT_TRUE(state.usesClientComposition);
     EXPECT_FALSE(state.usesDeviceComposition);
+    EXPECT_FALSE(state.previousDeviceRequestedChanges.has_value());
 }
 
 TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) {
@@ -588,10 +614,16 @@
 
     EXPECT_CALL(mHwComposer,
                 getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
-            .WillOnce(Return(NO_ERROR));
+            .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges),
+                                     Return(NO_ERROR)));
+    EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
+            .Times(1);
+    EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
+    EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
+            .Times(1);
     EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
 
-    mDisplay->chooseCompositionStrategy();
+    chooseCompositionStrategy(mDisplay.get());
 
     auto& state = mDisplay->getState();
     EXPECT_FALSE(state.usesClientComposition);
@@ -618,11 +650,17 @@
 
     EXPECT_CALL(mHwComposer,
                 getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
-            .WillOnce(Return(NO_ERROR));
+            .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges),
+                                     Return(NO_ERROR)));
+    EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
+            .Times(1);
+    EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
+    EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
+            .Times(1);
     EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
 
     mDisplay->setNextBrightness(kDisplayBrightness);
-    mDisplay->chooseCompositionStrategy();
+    chooseCompositionStrategy(mDisplay.get());
 
     auto& state = mDisplay->getState();
     EXPECT_FALSE(state.usesClientComposition);
@@ -631,14 +669,6 @@
 }
 
 TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
-    android::HWComposer::DeviceRequestedChanges changes{
-            {{nullptr, Composition::CLIENT}},
-            hal::DisplayRequest::FLIP_CLIENT_TARGET,
-            {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
-            {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN},
-            -1.f,
-    };
-
     // Since two calls are made to anyLayersRequireClientComposition with different return
     // values, use a Sequence to control the matching so the values are returned in a known
     // order.
@@ -652,13 +682,15 @@
 
     EXPECT_CALL(mHwComposer,
                 getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
-            .WillOnce(DoAll(SetArgPointee<5>(changes), Return(NO_ERROR)));
-    EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1);
-    EXPECT_CALL(*mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1);
-    EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1);
+            .WillOnce(DoAll(SetArgPointee<5>(mDeviceRequestedChanges), Return(NO_ERROR)));
+    EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
+            .Times(1);
+    EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
+    EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
+            .Times(1);
     EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
 
-    mDisplay->chooseCompositionStrategy();
+    chooseCompositionStrategy(mDisplay.get());
 
     auto& state = mDisplay->getState();
     EXPECT_FALSE(state.usesClientComposition);
@@ -922,7 +954,7 @@
     mDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
     mDisplay->editState().dirtyRegion = Region::INVALID_REGION;
 
-    mDisplay->finishFrame({});
+    mDisplay->finishFrame({}, std::move(mResultWithBuffer));
 }
 
 TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) {
@@ -940,7 +972,7 @@
     gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
     gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
 
-    gpuDisplay->finishFrame({});
+    gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer));
 }
 
 TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) {
@@ -957,7 +989,7 @@
     gpuDisplay->editState().usesClientComposition = false;
     gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
     gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
-    gpuDisplay->finishFrame({});
+    gpuDisplay->finishFrame({}, std::move(mResultWithBuffer));
 }
 
 /*