SF: Move/Refactor prepareFrame to CompositionEngine

This refactors both the SurfaceFlinger::prepareFrame() and
HWComposer::prepare() logic, moving things to to
compositionEngine::Output and compositionEngine::Display.

Along the way, the composition related state is moved out of HWComposer
up to compositionengine::OutputCompositionState.

As there were some subtleties, tests are also added to cover the
refactored logic.

Test: atest libsurfaceflinger_unittest libcompositionengine_test
Bug: 121291683

Change-Id: I2713e9e52751ca0523f6348ffdb51ead8bca5235
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index f0aea25..d0f79f2 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -24,33 +24,54 @@
 #include <compositionengine/mock/CompositionEngine.h>
 #include <compositionengine/mock/DisplayColorProfile.h>
 #include <compositionengine/mock/NativeWindow.h>
+#include <compositionengine/mock/OutputLayer.h>
 #include <compositionengine/mock/RenderSurface.h>
 #include <gtest/gtest.h>
 
+#include "MockHWC2.h"
 #include "MockHWComposer.h"
 
 namespace android::compositionengine {
 namespace {
 
 using testing::_;
+using testing::DoAll;
 using testing::Return;
 using testing::ReturnRef;
+using testing::Sequence;
+using testing::SetArgPointee;
 using testing::StrictMock;
 
 constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
 
-class DisplayTest : public testing::Test {
-public:
-    ~DisplayTest() override = default;
+struct DisplayTest : public testing::Test {
+    DisplayTest() {
+        EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+        EXPECT_CALL(*mLayer1, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer1));
+        EXPECT_CALL(*mLayer2, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer2));
+        EXPECT_CALL(*mLayer3, getHwcLayer()).WillRepeatedly(Return(nullptr));
+
+        std::vector<std::unique_ptr<OutputLayer>> layers;
+        layers.emplace_back(mLayer1);
+        layers.emplace_back(mLayer2);
+        layers.emplace_back(mLayer3);
+        mDisplay.setOutputLayersOrderedByZ(std::move(layers));
+    }
 
     StrictMock<android::mock::HWComposer> mHwComposer;
     StrictMock<mock::CompositionEngine> mCompositionEngine;
     sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
+    StrictMock<HWC2::mock::Layer> mHWC2Layer1;
+    StrictMock<HWC2::mock::Layer> mHWC2Layer2;
+    StrictMock<HWC2::mock::Layer> mHWC2LayerUnknown;
+    mock::OutputLayer* mLayer1 = new StrictMock<mock::OutputLayer>();
+    mock::OutputLayer* mLayer2 = new StrictMock<mock::OutputLayer>();
+    mock::OutputLayer* mLayer3 = new StrictMock<mock::OutputLayer>();
     impl::Display mDisplay{mCompositionEngine,
                            DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
 };
 
-/* ------------------------------------------------------------------------
+/*
  * Basic construction
  */
 
@@ -90,13 +111,11 @@
     }
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Display::disconnect()
  */
 
 TEST_F(DisplayTest, disconnectDisconnectsDisplay) {
-    EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
-
     // The first call to disconnect will disconnect the display with the HWC and
     // set mHwcId to -1.
     EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1);
@@ -109,7 +128,7 @@
     EXPECT_FALSE(mDisplay.getId());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Display::setColorTransform()
  */
 
@@ -117,8 +136,6 @@
     // Identity matrix sets an identity state value
     const mat4 identity;
 
-    EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
-
     EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, identity)).Times(1);
 
     mDisplay.setColorTransform(identity);
@@ -135,7 +152,7 @@
     EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mDisplay.getState().colorTransform);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Display::setColorMode()
  */
 
@@ -145,7 +162,6 @@
     mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
     mDisplay.setDisplayColorProfileForTest(std::unique_ptr<DisplayColorProfile>(colorProfile));
 
-    EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
     EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _))
             .WillRepeatedly(Return(ui::Dataspace::UNKNOWN));
 
@@ -202,7 +218,7 @@
     EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Display::createDisplayColorProfile()
  */
 
@@ -214,7 +230,7 @@
     EXPECT_TRUE(mDisplay.getDisplayColorProfile() != nullptr);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Display::createRenderSurface()
  */
 
@@ -225,5 +241,227 @@
     EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr);
 }
 
+/*
+ * Display::chooseCompositionStrategy()
+ */
+
+struct DisplayChooseCompositionStrategyTest : public testing::Test {
+    struct DisplayPartialMock : public impl::Display {
+        DisplayPartialMock(const compositionengine::CompositionEngine& compositionEngine,
+                           compositionengine::DisplayCreationArgs&& args)
+              : impl::Display(compositionEngine, std::move(args)) {}
+
+        // Sets up the helper functions called by chooseCompositionStrategy to
+        // use a mock implementations.
+        MOCK_CONST_METHOD0(anyLayersRequireClientComposition, bool());
+        MOCK_CONST_METHOD0(allLayersRequireClientComposition, bool());
+        MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&));
+        MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&));
+        MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&));
+    };
+
+    DisplayChooseCompositionStrategyTest() {
+        EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+    }
+
+    StrictMock<android::mock::HWComposer> mHwComposer;
+    StrictMock<mock::CompositionEngine> mCompositionEngine;
+    StrictMock<DisplayPartialMock>
+            mDisplay{mCompositionEngine,
+                     DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+};
+
+TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) {
+    impl::Display nonHwcDisplay{mCompositionEngine, DisplayCreationArgsBuilder().build()};
+    EXPECT_FALSE(nonHwcDisplay.getId());
+
+    nonHwcDisplay.chooseCompositionStrategy();
+
+    auto& state = nonHwcDisplay.getState();
+    EXPECT_TRUE(state.usesClientComposition);
+    EXPECT_FALSE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) {
+    EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false));
+    EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, false, _))
+            .WillOnce(Return(INVALID_OPERATION));
+
+    mDisplay.chooseCompositionStrategy();
+
+    auto& state = mDisplay.getState();
+    EXPECT_TRUE(state.usesClientComposition);
+    EXPECT_FALSE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) {
+    // 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.
+    Sequence s;
+    EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true));
+    EXPECT_CALL(mDisplay, anyLayersRequireClientComposition())
+            .InSequence(s)
+            .WillOnce(Return(false));
+
+    EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _))
+            .WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+    mDisplay.chooseCompositionStrategy();
+
+    auto& state = mDisplay.getState();
+    EXPECT_FALSE(state.usesClientComposition);
+    EXPECT_TRUE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
+    android::HWComposer::DeviceRequestedChanges changes{
+            {{nullptr, HWC2::Composition::Client}},
+            HWC2::DisplayRequest::FlipClientTarget,
+            {{nullptr, HWC2::LayerRequest::ClearClientTarget}},
+    };
+
+    // 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.
+    Sequence s;
+    EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true));
+    EXPECT_CALL(mDisplay, anyLayersRequireClientComposition())
+            .InSequence(s)
+            .WillOnce(Return(false));
+
+    EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _))
+            .WillOnce(DoAll(SetArgPointee<2>(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);
+    EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+    mDisplay.chooseCompositionStrategy();
+
+    auto& state = mDisplay.getState();
+    EXPECT_FALSE(state.usesClientComposition);
+    EXPECT_TRUE(state.usesDeviceComposition);
+}
+
+/*
+ * Display::anyLayersRequireClientComposition()
+ */
+
+TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsFalse) {
+    EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
+    EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
+    EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(false));
+
+    EXPECT_FALSE(mDisplay.anyLayersRequireClientComposition());
+}
+
+TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) {
+    EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
+    EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
+
+    EXPECT_TRUE(mDisplay.anyLayersRequireClientComposition());
+}
+
+/*
+ * Display::allLayersRequireClientComposition()
+ */
+
+TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsTrue) {
+    EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
+    EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
+    EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(true));
+
+    EXPECT_TRUE(mDisplay.allLayersRequireClientComposition());
+}
+
+TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) {
+    EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
+    EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
+
+    EXPECT_FALSE(mDisplay.allLayersRequireClientComposition());
+}
+
+/*
+ * Display::applyChangedTypesToLayers()
+ */
+
+TEST_F(DisplayTest, applyChangedTypesToLayersTakesEarlyOutIfNoChangedLayers) {
+    mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes());
+}
+
+TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) {
+    EXPECT_CALL(*mLayer1,
+                applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT))
+            .Times(1);
+    EXPECT_CALL(*mLayer2,
+                applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::DEVICE))
+            .Times(1);
+
+    mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes{
+            {&mHWC2Layer1, HWC2::Composition::Client},
+            {&mHWC2Layer2, HWC2::Composition::Device},
+            {&mHWC2LayerUnknown, HWC2::Composition::SolidColor},
+    });
+}
+
+/*
+ * Display::applyDisplayRequests()
+ */
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesNoRequests) {
+    mDisplay.applyDisplayRequests(static_cast<HWC2::DisplayRequest>(0));
+
+    auto& state = mDisplay.getState();
+    EXPECT_FALSE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesFlipClientTarget) {
+    mDisplay.applyDisplayRequests(HWC2::DisplayRequest::FlipClientTarget);
+
+    auto& state = mDisplay.getState();
+    EXPECT_TRUE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesWriteClientTargetToOutput) {
+    mDisplay.applyDisplayRequests(HWC2::DisplayRequest::WriteClientTargetToOutput);
+
+    auto& state = mDisplay.getState();
+    EXPECT_FALSE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesAllRequestFlagsSet) {
+    mDisplay.applyDisplayRequests(static_cast<HWC2::DisplayRequest>(~0));
+
+    auto& state = mDisplay.getState();
+    EXPECT_TRUE(state.flipClientTarget);
+}
+
+/*
+ * Display::applyLayerRequestsToLayers()
+ */
+
+TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) {
+    EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
+    EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
+    EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+
+    mDisplay.applyLayerRequestsToLayers(impl::Display::LayerRequests());
+}
+
+TEST_F(DisplayTest, applyLayerRequestsToLayers2) {
+    EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
+    EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
+    EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+
+    EXPECT_CALL(*mLayer1,
+                applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET))
+            .Times(1);
+
+    mDisplay.applyLayerRequestsToLayers(impl::Display::LayerRequests{
+            {&mHWC2Layer1, HWC2::LayerRequest::ClearClientTarget},
+            {&mHWC2LayerUnknown, HWC2::LayerRequest::ClearClientTarget},
+    });
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 94349de..5cfec77 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -40,7 +40,9 @@
                  std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
     MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
     MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
-    MOCK_METHOD2(prepare, status_t(DisplayId, const compositionengine::Output&));
+    MOCK_METHOD3(getDeviceCompositionChanges,
+                 status_t(DisplayId, bool,
+                          std::optional<android::HWComposer::DeviceRequestedChanges>*));
     MOCK_METHOD5(setClientTarget,
                  status_t(DisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
                           ui::Dataspace));
@@ -50,8 +52,6 @@
     MOCK_METHOD2(setColorTransform, status_t(DisplayId, const mat4&));
     MOCK_METHOD1(disconnectDisplay, void(DisplayId));
     MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional<DisplayId>&));
-    MOCK_CONST_METHOD1(hasFlipClientTargetRequest, bool(const std::optional<DisplayId>&));
-    MOCK_CONST_METHOD1(hasClientComposition, bool(const std::optional<DisplayId>&));
     MOCK_CONST_METHOD1(getPresentFence, sp<Fence>(DisplayId));
     MOCK_CONST_METHOD2(getLayerReleaseFence, sp<Fence>(DisplayId, HWC2::Layer*));
     MOCK_METHOD3(setOutputBuffer, status_t(DisplayId, const sp<Fence>&, const sp<GraphicBuffer>&));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 7b9528b..a5428ad 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -56,8 +56,7 @@
     return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a;
 }
 
-class OutputLayerTest : public testing::Test {
-public:
+struct OutputLayerTest : public testing::Test {
     OutputLayerTest() {
         EXPECT_CALL(*mLayerFE, getDebugName()).WillRepeatedly(Return("Test LayerFE"));
         EXPECT_CALL(mOutput, getName()).WillRepeatedly(ReturnRef(kOutputName));
@@ -66,8 +65,6 @@
         EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
     }
 
-    ~OutputLayerTest() override = default;
-
     compositionengine::mock::Output mOutput;
     std::shared_ptr<compositionengine::mock::Layer> mLayer{
             new StrictMock<compositionengine::mock::Layer>()};
@@ -784,5 +781,99 @@
     mOutputLayer.writeStateToHWC(false);
 }
 
+/*
+ * OutputLayer::getHwcLayer()
+ */
+
+TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcState) {
+    mOutputLayer.editState().hwc.reset();
+
+    EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr);
+}
+
+TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcLayer) {
+    mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+
+    EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr);
+}
+
+TEST_F(OutputLayerTest, getHwcLayerReturnsHwcLayer) {
+    auto hwcLayer = std::make_shared<StrictMock<HWC2::mock::Layer>>();
+    mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{hwcLayer};
+
+    EXPECT_EQ(hwcLayer.get(), mOutputLayer.getHwcLayer());
+}
+
+/*
+ * OutputLayer::requiresClientComposition()
+ */
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfNoHWC2State) {
+    mOutputLayer.editState().hwc.reset();
+
+    EXPECT_TRUE(mOutputLayer.requiresClientComposition());
+}
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfSetToClientComposition) {
+    mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+    mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
+
+    EXPECT_TRUE(mOutputLayer.requiresClientComposition());
+}
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsFalseIfSetToDeviceComposition) {
+    mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+    mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+    EXPECT_FALSE(mOutputLayer.requiresClientComposition());
+}
+
+/*
+ * OutputLayer::applyDeviceCompositionTypeChange()
+ */
+
+TEST_F(OutputLayerTest, applyDeviceCompositionTypeChangeSetsNewType) {
+    mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+    mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+    mOutputLayer.applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT);
+
+    ASSERT_TRUE(mOutputLayer.getState().hwc);
+    EXPECT_EQ(Hwc2::IComposerClient::Composition::CLIENT,
+              mOutputLayer.getState().hwc->hwcCompositionType);
+}
+
+/*
+ * OutputLayer::prepareForDeviceLayerRequests()
+ */
+
+TEST_F(OutputLayerTest, prepareForDeviceLayerRequestsResetsRequestState) {
+    mOutputLayer.editState().clearClientTarget = true;
+
+    mOutputLayer.prepareForDeviceLayerRequests();
+
+    EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
+}
+
+/*
+ * OutputLayer::applyDeviceLayerRequest()
+ */
+
+TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesClearClientTarget) {
+    mOutputLayer.editState().clearClientTarget = false;
+
+    mOutputLayer.applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET);
+
+    EXPECT_TRUE(mOutputLayer.getState().clearClientTarget);
+}
+
+TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesUnknownRequest) {
+    mOutputLayer.editState().clearClientTarget = false;
+
+    mOutputLayer.applyDeviceLayerRequest(static_cast<Hwc2::IComposerClient::LayerRequest>(0));
+
+    EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 6f087d9..aa35d25 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -17,6 +17,7 @@
 #include <cmath>
 
 #include <compositionengine/impl/Output.h>
+#include <compositionengine/impl/OutputCompositionState.h>
 #include <compositionengine/mock/CompositionEngine.h>
 #include <compositionengine/mock/DisplayColorProfile.h>
 #include <compositionengine/mock/Layer.h>
@@ -37,8 +38,7 @@
 using testing::ReturnRef;
 using testing::StrictMock;
 
-class OutputTest : public testing::Test {
-public:
+struct OutputTest : public testing::Test {
     OutputTest() {
         mOutput.setDisplayColorProfileForTest(
                 std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
@@ -46,7 +46,6 @@
 
         mOutput.editState().bounds = kDefaultDisplaySize;
     }
-    ~OutputTest() override = default;
 
     static const Rect kDefaultDisplaySize;
 
@@ -58,7 +57,7 @@
 
 const Rect OutputTest::kDefaultDisplaySize{100, 200};
 
-/* ------------------------------------------------------------------------
+/*
  * Basic construction
  */
 
@@ -77,7 +76,7 @@
     EXPECT_FALSE(mOutput.isValid());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setCompositionEnabled()
  */
 
@@ -108,7 +107,7 @@
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setProjection()
  */
 
@@ -130,7 +129,7 @@
     EXPECT_EQ(needsFiltering, mOutput.getState().needsFiltering);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setBounds()
  */
 
@@ -147,7 +146,7 @@
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setLayerStackFilter()
  */
 
@@ -161,7 +160,7 @@
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setColorTransform
  */
 
@@ -200,7 +199,7 @@
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setColorMode
  */
 
@@ -239,7 +238,7 @@
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setRenderSurface()
  */
 
@@ -254,7 +253,7 @@
     EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::getDirtyRegion()
  */
 
@@ -283,7 +282,7 @@
     }
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::belongsInOutput()
  */
 
@@ -310,7 +309,7 @@
     EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::getOutputLayerForLayer()
  */
 
@@ -342,7 +341,7 @@
     EXPECT_EQ(nullptr, mOutput.getOutputLayerForLayer(&layer));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::getOrCreateOutputLayer()
  */
 
@@ -389,5 +388,63 @@
     }
 }
 
+/*
+ * Output::prepareFrame()
+ */
+
+struct OutputPrepareFrameTest : public testing::Test {
+    struct OutputPartialMock : public impl::Output {
+        OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine)
+              : impl::Output(compositionEngine) {}
+
+        // Sets up the helper functions called by prepareFrame to use a mock
+        // implementations.
+        MOCK_METHOD0(chooseCompositionStrategy, void());
+    };
+
+    OutputPrepareFrameTest() {
+        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};
+};
+
+TEST_F(OutputPrepareFrameTest, takesEarlyOutIfNotEnabled) {
+    mOutput.editState().isEnabled = false;
+
+    mOutput.prepareFrame();
+}
+
+TEST_F(OutputPrepareFrameTest, delegatesToChooseCompositionStrategyAndRenderSurface) {
+    mOutput.editState().isEnabled = true;
+    mOutput.editState().usesClientComposition = false;
+    mOutput.editState().usesDeviceComposition = true;
+
+    EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1);
+    EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
+
+    mOutput.prepareFrame();
+}
+
+// Note: Use OutputTest and not OutputPrepareFrameTest, so the real
+// base chooseCompositionStrategy() is invoked.
+TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) {
+    mOutput.editState().isEnabled = true;
+    mOutput.editState().usesClientComposition = false;
+    mOutput.editState().usesDeviceComposition = true;
+
+    EXPECT_CALL(*mRenderSurface, prepareFrame(true, false));
+
+    mOutput.prepareFrame();
+
+    EXPECT_TRUE(mOutput.getState().usesClientComposition);
+    EXPECT_FALSE(mOutput.getState().usesDeviceComposition);
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 87419ea..da3f4fb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -18,6 +18,7 @@
 #include <cstdint>
 
 #include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/OutputCompositionState.h>
 #include <compositionengine/impl/RenderSurface.h>
 #include <compositionengine/mock/CompositionEngine.h>
 #include <compositionengine/mock/Display.h>
@@ -27,15 +28,9 @@
 #include <gtest/gtest.h>
 #include <renderengine/mock/RenderEngine.h>
 
-#include "MockHWComposer.h"
-
 namespace android::compositionengine {
 namespace {
 
-/* ------------------------------------------------------------------------
- * RenderSurfaceTest
- */
-
 constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
 constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
 constexpr std::optional<DisplayId> DEFAULT_DISPLAY_ID = std::make_optional(DisplayId{123u});
@@ -55,14 +50,11 @@
     RenderSurfaceTest() {
         EXPECT_CALL(mDisplay, getId()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_ID));
         EXPECT_CALL(mDisplay, getName()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_NAME));
-        EXPECT_CALL(mCompositionEngine, getHwComposer).WillRepeatedly(ReturnRef(mHwComposer));
         EXPECT_CALL(mCompositionEngine, getRenderEngine).WillRepeatedly(ReturnRef(mRenderEngine));
         EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL))
                 .WillRepeatedly(Return(NO_ERROR));
     }
-    ~RenderSurfaceTest() override = default;
 
-    StrictMock<android::mock::HWComposer> mHwComposer;
     StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
     StrictMock<mock::CompositionEngine> mCompositionEngine;
     StrictMock<mock::Display> mDisplay;
@@ -74,7 +66,7 @@
                                                            mDisplaySurface}};
 };
 
-/* ------------------------------------------------------------------------
+/*
  * Basic construction
  */
 
@@ -82,7 +74,7 @@
     EXPECT_TRUE(mSurface.isValid());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::initialize()
  */
 
@@ -95,7 +87,7 @@
     mSurface.initialize();
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::getSize()
  */
 
@@ -105,7 +97,7 @@
     EXPECT_EQ(expected, mSurface.getSize());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::getClientTargetAcquireFence()
  */
 
@@ -117,7 +109,7 @@
     EXPECT_EQ(fence.get(), mSurface.getClientTargetAcquireFence().get());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::setDisplaySize()
  */
 
@@ -127,7 +119,7 @@
     mSurface.setDisplaySize(ui::Size(640, 480));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::setBufferDataspace()
  */
 
@@ -138,7 +130,7 @@
     mSurface.setBufferDataspace(ui::Dataspace::DISPLAY_P3);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::setProtected()
  */
 
@@ -179,7 +171,7 @@
     EXPECT_FALSE(mSurface.isProtected());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::beginFrame()
  */
 
@@ -189,73 +181,39 @@
     EXPECT_EQ(NO_ERROR, mSurface.beginFrame(true));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::prepareFrame()
  */
 
-TEST_F(RenderSurfaceTest, prepareFramePassesOutputLayersToHwc) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(INVALID_OPERATION));
-
-    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
-}
-
-TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(INVALID_OPERATION));
-
-    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
-}
-
 TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(NO_ERROR));
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
-            .WillOnce(Return(INVALID_OPERATION));
+            .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
+    mSurface.prepareFrame(true, true);
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(NO_ERROR));
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+    mSurface.prepareFrame(true, false);
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(NO_ERROR));
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+    mSurface.prepareFrame(false, true);
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(NO_ERROR));
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+    mSurface.prepareFrame(false, false);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::dequeueBuffer()
  */
 
@@ -272,7 +230,7 @@
     EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::queueBuffer()
  */
 
@@ -280,9 +238,11 @@
     sp<GraphicBuffer> buffer = new GraphicBuffer();
     mSurface.mutableGraphicBufferForTest() = buffer;
 
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-    EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID))
-            .WillOnce(Return(false));
+    impl::OutputCompositionState state;
+    state.usesClientComposition = false;
+    state.flipClientTarget = false;
+
+    EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
     EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
 
     mSurface.queueBuffer(base::unique_fd());
@@ -294,7 +254,11 @@
     sp<GraphicBuffer> buffer = new GraphicBuffer();
     mSurface.mutableGraphicBufferForTest() = buffer;
 
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    impl::OutputCompositionState state;
+    state.usesClientComposition = true;
+    state.flipClientTarget = false;
+
+    EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
     EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
             .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
@@ -308,8 +272,11 @@
     sp<GraphicBuffer> buffer = new GraphicBuffer();
     mSurface.mutableGraphicBufferForTest() = buffer;
 
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-    EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    impl::OutputCompositionState state;
+    state.usesClientComposition = false;
+    state.flipClientTarget = true;
+
+    EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
     EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
             .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
@@ -322,8 +289,11 @@
 TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
     sp<GraphicBuffer> buffer = new GraphicBuffer();
 
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-    EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    impl::OutputCompositionState state;
+    state.usesClientComposition = false;
+    state.flipClientTarget = true;
+
+    EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
     EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
             .WillOnce(
                     DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
@@ -340,7 +310,10 @@
     sp<GraphicBuffer> buffer = new GraphicBuffer();
     mSurface.mutableGraphicBufferForTest() = buffer;
 
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    impl::OutputCompositionState state;
+    state.usesClientComposition = true;
+
+    EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
     EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
             .WillOnce(Return(INVALID_OPERATION));
     EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true));
@@ -353,7 +326,7 @@
     EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::onPresentDisplayCompleted()
  */
 
@@ -363,7 +336,7 @@
     mSurface.onPresentDisplayCompleted();
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::flip()
  */