SF: Move doComposeSurfaces to CompositionEngine

Test: atest libsurfaceflinger_unittest libcompositionengine_test
Bug: 121291683
Change-Id: Iae3377a5ea018f9ec53c5a76ed6a86620f39b731
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 87bec11..13c748f 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -167,7 +167,7 @@
         }
         return std::nullopt;
     }
-    bool blackOutLayer = (isProtected() && !targetSettings.supportProtectedContent) ||
+    bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
             (isSecure() && !targetSettings.isSecure);
     const State& s(getDrawingState());
     auto& layer = *result;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 6f076ad..ae6bdbc 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -94,6 +94,7 @@
         "tests/LayerTest.cpp",
         "tests/MockHWC2.cpp",
         "tests/MockHWComposer.cpp",
+        "tests/MockPowerAdvisor.cpp",
         "tests/OutputTest.cpp",
         "tests/OutputLayerTest.cpp",
         "tests/RenderSurfaceTest.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 0b6b4e4..0778936 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -20,6 +20,7 @@
 #include <optional>
 
 #include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/PowerAdvisor.h"
 
 namespace android::compositionengine {
 
@@ -37,6 +38,10 @@
 
     // Identifies the display to the HWC, if composition is supported by it
     std::optional<DisplayId> displayId;
+
+    // Optional pointer to the power advisor interface, if one is needed for
+    // this display.
+    Hwc2::PowerAdvisor* powerAdvisor = nullptr;
 };
 
 /**
@@ -68,6 +73,10 @@
         mArgs.displayId = displayId;
         return *this;
     }
+    DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
+        mArgs.powerAdvisor = powerAdvisor;
+        return *this;
+    }
 
 private:
     DisplayCreationArgs mArgs;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 94fab1f..2a901ae 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -59,7 +59,7 @@
         const bool isSecure;
 
         // If set to true, the target buffer has protected content support.
-        const bool supportProtectedContent;
+        const bool supportsProtectedContent;
 
         // Modified by each call to prepareClientComposition to indicate the
         // region of the target buffer that should be cleared.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index d96d58c..d5763d5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -116,6 +116,12 @@
     // The color transform
     mat4 colorTransform;
     bool colorTransformIsIdentity{true};
+
+    // True if the layer is completely opaque
+    bool isOpaque{true};
+
+    // True if the layer has protected content
+    bool hasProtectedContent{false};
 };
 
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 4dfcfa4..f73304d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -22,6 +22,7 @@
 #include <unordered_map>
 
 #include <math/mat4.h>
+#include <renderengine/LayerSettings.h>
 #include <ui/Fence.h>
 #include <ui/GraphicTypes.h>
 #include <ui/Region.h>
@@ -156,6 +157,12 @@
     // Prepares a frame for display
     virtual void prepareFrame() = 0;
 
+    // Performs client composition as needed for layers on the output. The
+    // output fence is set to a fence to signal when client composition is
+    // finished.
+    // Returns false if client composition cannot be performed.
+    virtual bool composeSurfaces(const Region& debugFence, base::unique_fd* outReadyFence) = 0;
+
     // Posts the new frame, and sets release fences.
     virtual void postFramebuffer() = 0;
 
@@ -163,7 +170,14 @@
     virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
     virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
     virtual void chooseCompositionStrategy() = 0;
+    virtual bool getSkipColorTransform() const = 0;
     virtual FrameFences presentAndGetFrameFences() = 0;
+    virtual std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+            bool supportsProtectedContent, Region& clearRegion) = 0;
+    virtual void appendRegionFlashRequests(
+            const Region& flashRegion,
+            std::vector<renderengine::LayerSettings>& clientCompositionLayers) = 0;
+    virtual void setExpensiveRenderingExpected(bool enabled) = 0;
 };
 
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index d7f00a9..5f62b32c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -93,6 +93,9 @@
     // Applies a HWC device layer request
     virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0;
 
+    // Returns true if the composition settings scale pixels
+    virtual bool needsFiltering() const = 0;
+
     // Debugging
     virtual void dump(std::string& result) const = 0;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 795061a..36e4aac 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -23,6 +23,7 @@
 
 #include "DisplayHardware/DisplayIdentification.h"
 #include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
 
 namespace android::compositionengine {
 
@@ -42,7 +43,9 @@
     void setColorTransform(const mat4&) override;
     void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
     void chooseCompositionStrategy() override;
+    bool getSkipColorTransform() const override;
     compositionengine::Output::FrameFences presentAndGetFrameFences() override;
+    void setExpensiveRenderingExpected(bool) override;
 
     // compositionengine::Display overrides
     const std::optional<DisplayId>& getId() const override;
@@ -65,9 +68,11 @@
 private:
     const bool mIsVirtual;
     std::optional<DisplayId> mId;
+    Hwc2::PowerAdvisor* const mPowerAdvisor{nullptr};
 };
 
 std::shared_ptr<Display> createDisplay(const compositionengine::CompositionEngine&,
                                        compositionengine::DisplayCreationArgs&&);
+
 } // namespace impl
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 5f4a764..3972f2b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -77,6 +77,7 @@
 
     void beginFrame() override;
     void prepareFrame() override;
+    bool composeSurfaces(const Region&, base::unique_fd*) override;
     void postFramebuffer() override;
 
     // Testing
@@ -86,7 +87,13 @@
 protected:
     const CompositionEngine& getCompositionEngine() const;
     void chooseCompositionStrategy() override;
+    bool getSkipColorTransform() const override;
     compositionengine::Output::FrameFences presentAndGetFrameFences() override;
+    std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+            bool supportsProtectedContent, Region& clearRegion) override;
+    void appendRegionFlashRequests(const Region&,
+                                   std::vector<renderengine::LayerSettings>&) override;
+    void setExpensiveRenderingExpected(bool enabled) override;
     void dumpBase(std::string&) const;
 
 private:
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index d8ad02a..4c3f935 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -55,6 +55,7 @@
     void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override;
     void prepareForDeviceLayerRequests() override;
     void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
+    bool needsFiltering() const override;
 
     void dump(std::string& result) const override;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d494413..c944bec 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -77,8 +77,17 @@
     MOCK_METHOD0(prepareFrame, void());
     MOCK_METHOD0(chooseCompositionStrategy, void());
 
+    MOCK_METHOD2(composeSurfaces, bool(const Region&, base::unique_fd*));
+    MOCK_CONST_METHOD0(getSkipColorTransform, bool());
+
     MOCK_METHOD0(postFramebuffer, void());
     MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences());
+
+    MOCK_METHOD2(generateClientCompositionRequests,
+                 std::vector<renderengine::LayerSettings>(bool, Region&));
+    MOCK_METHOD2(appendRegionFlashRequests,
+                 void(const Region&, std::vector<renderengine::LayerSettings>&));
+    MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 195648f..d8d637d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -46,6 +46,7 @@
     MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition));
     MOCK_METHOD0(prepareForDeviceLayerRequests, void());
     MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request));
+    MOCK_CONST_METHOD0(needsFiltering, bool());
 
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 6831901..6cd392e 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -26,6 +26,7 @@
 #include <utils/Trace.h>
 
 #include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
 
 namespace android::compositionengine::impl {
 
@@ -38,7 +39,8 @@
 Display::Display(const CompositionEngine& compositionEngine, DisplayCreationArgs&& args)
       : compositionengine::impl::Output(compositionEngine),
         mIsVirtual(args.isVirtual),
-        mId(args.displayId) {
+        mId(args.displayId),
+        mPowerAdvisor(args.powerAdvisor) {
     editState().isSecure = args.isSecure;
 }
 
@@ -160,6 +162,15 @@
     state.usesDeviceComposition = !allLayersRequireClientComposition();
 }
 
+bool Display::getSkipColorTransform() const {
+    if (!mId) {
+        return false;
+    }
+
+    auto& hwc = getCompositionEngine().getHwComposer();
+    return hwc.hasDisplayCapability(*mId, HWC2::DisplayCapability::SkipClientColorTransform);
+}
+
 bool Display::anyLayersRequireClientComposition() const {
     const auto& layers = getOutputLayersOrderedByZ();
     return std::any_of(layers.cbegin(), layers.cend(),
@@ -240,4 +251,12 @@
     return result;
 }
 
+void Display::setExpensiveRenderingExpected(bool enabled) {
+    Output::setExpensiveRenderingExpected(enabled);
+
+    if (mPowerAdvisor && mId) {
+        mPowerAdvisor->setExpensiveRenderingExpected(*mId, enabled);
+    }
+}
+
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
index 37d6eaa..0dc4bf1 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
@@ -71,6 +71,8 @@
     dumpVal(out, "color", state.color);
 
     out.append("\n      ");
+    dumpVal(out, "isOpaque", state.isOpaque);
+    dumpVal(out, "hasProtectedContent", state.hasProtectedContent);
     dumpVal(out, "isColorspaceAgnostic", state.isColorspaceAgnostic);
     dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace);
     dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6878e99..fb576e0 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -17,13 +17,20 @@
 #include <android-base/stringprintf.h>
 #include <compositionengine/CompositionEngine.h>
 #include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Layer.h>
 #include <compositionengine/LayerFE.h>
 #include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/LayerCompositionState.h>
 #include <compositionengine/impl/Output.h>
 #include <compositionengine/impl/OutputLayer.h>
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/RenderEngine.h>
 #include <ui/DebugUtils.h>
+#include <ui/HdrCapabilities.h>
 #include <utils/Trace.h>
 
+#include "TracedOrdinal.h"
+
 namespace android::compositionengine {
 
 Output::~Output() = default;
@@ -73,10 +80,10 @@
     dirtyEntireOutput();
 }
 
-// TODO(lpique): Rename setSize() once more is moved.
+// TODO(b/121291683): Rename setSize() once more is moved.
 void Output::setBounds(const ui::Size& size) {
     mRenderSurface->setDisplaySize(size);
-    // TODO(lpique): Rename mState.size once more is moved.
+    // TODO(b/121291683): Rename mState.size once more is moved.
     mState.bounds = Rect(mRenderSurface->getSize());
 
     dirtyEntireOutput();
@@ -292,6 +299,179 @@
     mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition);
 }
 
+bool Output::composeSurfaces(const Region& debugRegion, base::unique_fd* readyFence) {
+    ATRACE_CALL();
+    ALOGV(__FUNCTION__);
+
+    const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+                                                      mState.usesClientComposition};
+    if (!hasClientComposition) {
+        return true;
+    }
+
+    ALOGV("hasClientComposition");
+
+    auto& renderEngine = mCompositionEngine.getRenderEngine();
+    const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
+
+    renderengine::DisplaySettings clientCompositionDisplay;
+    clientCompositionDisplay.physicalDisplay = mState.frame;
+    clientCompositionDisplay.clip = mState.scissor;
+    clientCompositionDisplay.globalTransform = mState.transform.asMatrix4();
+    clientCompositionDisplay.orientation = mState.orientation;
+    clientCompositionDisplay.outputDataspace =
+            mDisplayColorProfile->hasWideColorGamut() ? mState.dataspace : ui::Dataspace::UNKNOWN;
+    clientCompositionDisplay.maxLuminance =
+            mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
+
+    // Compute the global color transform matrix.
+    if (!mState.usesDeviceComposition && !getSkipColorTransform()) {
+        clientCompositionDisplay.colorTransform = mState.colorTransformMat;
+    }
+
+    // Note: Updated by generateClientCompositionRequests
+    clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
+
+    // Generate the client composition requests for the layers on this output.
+    std::vector<renderengine::LayerSettings> clientCompositionLayers =
+            generateClientCompositionRequests(supportsProtectedContent,
+                                              clientCompositionDisplay.clearRegion);
+    appendRegionFlashRequests(debugRegion, clientCompositionLayers);
+
+    // If we the display is secure, protected content support is enabled, and at
+    // least one layer has protected content, we need to use a secure back
+    // buffer.
+    if (mState.isSecure && supportsProtectedContent) {
+        bool needsProtected =
+                std::any_of(mOutputLayersOrderedByZ.begin(), mOutputLayersOrderedByZ.end(),
+                            [](auto& layer) {
+                                return layer->getLayer().getState().frontEnd.hasProtectedContent;
+                            });
+        if (needsProtected != renderEngine.isProtected()) {
+            renderEngine.useProtectedContext(needsProtected);
+        }
+        if (needsProtected != mRenderSurface->isProtected() &&
+            needsProtected == renderEngine.isProtected()) {
+            mRenderSurface->setProtected(needsProtected);
+        }
+    }
+
+    base::unique_fd fd;
+    sp<GraphicBuffer> buf = mRenderSurface->dequeueBuffer(&fd);
+    if (buf == nullptr) {
+        ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
+              "client composition for this frame",
+              mName.c_str());
+        return false;
+    }
+
+    // We boost GPU frequency here because there will be color spaces conversion
+    // and it's expensive. We boost the GPU frequency so that GPU composition can
+    // finish in time. We must reset GPU frequency afterwards, because high frequency
+    // consumes extra battery.
+    const bool expensiveRenderingExpected =
+            clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3;
+    if (expensiveRenderingExpected) {
+        setExpensiveRenderingExpected(true);
+    }
+
+    renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
+                            buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
+                            readyFence);
+
+    if (expensiveRenderingExpected) {
+        setExpensiveRenderingExpected(false);
+    }
+
+    return true;
+}
+
+std::vector<renderengine::LayerSettings> Output::generateClientCompositionRequests(
+        bool supportsProtectedContent, Region& clearRegion) {
+    std::vector<renderengine::LayerSettings> clientCompositionLayers;
+    ALOGV("Rendering client layers");
+
+    const Region viewportRegion(mState.viewport);
+    const bool useIdentityTransform = false;
+    bool firstLayer = true;
+    // Used when a layer clears part of the buffer.
+    Region dummyRegion;
+
+    for (auto& layer : mOutputLayersOrderedByZ) {
+        const auto& layerState = layer->getState();
+        const auto& layerFEState = layer->getLayer().getState().frontEnd;
+        auto& layerFE = layer->getLayerFE();
+
+        const Region clip(viewportRegion.intersect(layer->getState().visibleRegion));
+        ALOGV("Layer: %s", layerFE.getDebugName());
+        if (clip.isEmpty()) {
+            ALOGV("  Skipping for empty clip");
+            firstLayer = false;
+            continue;
+        }
+
+        bool clientComposition = layer->requiresClientComposition();
+
+        // We clear the client target for non-client composed layers if
+        // requested by the HWC. We skip this if the layer is not an opaque
+        // rectangle, as by definition the layer must blend with whatever is
+        // underneath. We also skip the first layer as the buffer target is
+        // guaranteed to start out cleared.
+        bool clearClientComposition =
+                layerState.clearClientTarget && layerFEState.isOpaque && !firstLayer;
+
+        ALOGV("  Composition type: client %d clear %d", clientComposition, clearClientComposition);
+
+        if (clientComposition || clearClientComposition) {
+            compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+                    clip,
+                    useIdentityTransform,
+                    layer->needsFiltering() || mState.needsFiltering,
+                    mState.isSecure,
+                    supportsProtectedContent,
+                    clientComposition ? clearRegion : dummyRegion,
+            };
+            if (auto result = layerFE.prepareClientComposition(targetSettings)) {
+                if (clearClientComposition) {
+                    auto& layerSettings = *result;
+                    layerSettings.source.buffer.buffer = nullptr;
+                    layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
+                    layerSettings.alpha = half(0.0);
+                    layerSettings.disableBlending = true;
+                }
+
+                clientCompositionLayers.push_back(*result);
+            }
+        }
+
+        firstLayer = false;
+    }
+
+    return clientCompositionLayers;
+}
+
+void Output::appendRegionFlashRequests(
+        const Region& flashRegion,
+        std::vector<renderengine::LayerSettings>& clientCompositionLayers) {
+    if (flashRegion.isEmpty()) {
+        return;
+    }
+
+    renderengine::LayerSettings layerSettings;
+    layerSettings.source.buffer.buffer = nullptr;
+    layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
+    layerSettings.alpha = half(1.0);
+
+    for (const auto& rect : flashRegion) {
+        layerSettings.geometry.boundaries = rect.toFloatRect();
+        clientCompositionLayers.push_back(layerSettings);
+    }
+}
+
+void Output::setExpensiveRenderingExpected(bool) {
+    // The base class does nothing with this call.
+}
+
 void Output::postFramebuffer() {
     ATRACE_CALL();
     ALOGV(__FUNCTION__);
@@ -353,6 +533,10 @@
     mState.usesDeviceComposition = false;
 }
 
+bool Output::getSkipColorTransform() const {
+    return true;
+}
+
 compositionengine::Output::FrameFences Output::presentAndGetFrameFences() {
     compositionengine::Output::FrameFences result;
     if (mState.usesClientComposition) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 6e744b9..e721cf5 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -614,6 +614,13 @@
     }
 }
 
+bool OutputLayer::needsFiltering() const {
+    const auto& displayFrame = mState.displayFrame;
+    const auto& sourceCrop = mState.sourceCrop;
+    return sourceCrop.getHeight() != displayFrame.getHeight() ||
+            sourceCrop.getWidth() != displayFrame.getWidth();
+}
+
 void OutputLayer::dump(std::string& out) const {
     using android::base::StringAppendF;
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index e3be0d7..743da82 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -30,6 +30,7 @@
 
 #include "MockHWC2.h"
 #include "MockHWComposer.h"
+#include "MockPowerAdvisor.h"
 
 namespace android::compositionengine {
 namespace {
@@ -59,6 +60,7 @@
     }
 
     StrictMock<android::mock::HWComposer> mHwComposer;
+    StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor;
     StrictMock<mock::CompositionEngine> mCompositionEngine;
     sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
     StrictMock<HWC2::mock::Layer> mHWC2Layer1;
@@ -68,7 +70,10 @@
     mock::OutputLayer* mLayer2 = new StrictMock<mock::OutputLayer>();
     mock::OutputLayer* mLayer3 = new StrictMock<mock::OutputLayer>();
     impl::Display mDisplay{mCompositionEngine,
-                           DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+                           DisplayCreationArgsBuilder()
+                                   .setDisplayId(DEFAULT_DISPLAY_ID)
+                                   .setPowerAdvisor(&mPowerAdvisor)
+                                   .build()};
 };
 
 /*
@@ -344,6 +349,24 @@
 }
 
 /*
+ * Display::getSkipColorTransform()
+ */
+
+TEST_F(DisplayTest, getSkipColorTransformDoesNothingIfNonHwcDisplay) {
+    auto nonHwcDisplay{
+            impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+    EXPECT_FALSE(nonHwcDisplay->getSkipColorTransform());
+}
+
+TEST_F(DisplayTest, getSkipColorTransformChecksHwcCapability) {
+    EXPECT_CALL(mHwComposer,
+                hasDisplayCapability(std::make_optional(DEFAULT_DISPLAY_ID),
+                                     HWC2::DisplayCapability::SkipClientColorTransform))
+            .WillOnce(Return(true));
+    EXPECT_TRUE(mDisplay.getSkipColorTransform());
+}
+
+/*
  * Display::anyLayersRequireClientComposition()
  */
 
@@ -502,5 +525,17 @@
     EXPECT_EQ(layer2Fence, result.layerFences[&mHWC2Layer2]);
 }
 
+/*
+ * Display::setExpensiveRenderingExpected()
+ */
+
+TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) {
+    EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, true)).Times(1);
+    mDisplay.setExpensiveRenderingExpected(true);
+
+    EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, false)).Times(1);
+    mDisplay.setExpensiveRenderingExpected(false);
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
new file mode 100644
index 0000000..85b9403
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockPowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+
+// This will go away once PowerAdvisor is moved into the "backend" library
+PowerAdvisor::~PowerAdvisor() = default;
+
+namespace mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+PowerAdvisor::PowerAdvisor() = default;
+PowerAdvisor::~PowerAdvisor() = default;
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
new file mode 100644
index 0000000..c5a73f2
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "DisplayHardware/PowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+namespace mock {
+
+class PowerAdvisor : public android::Hwc2::PowerAdvisor {
+public:
+    PowerAdvisor();
+    ~PowerAdvisor() override;
+
+    MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
+};
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index a5428ad..c83cae6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -875,5 +875,23 @@
     EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
 }
 
+/*
+ * OutputLayer::needsFiltering()
+ */
+
+TEST_F(OutputLayerTest, needsFilteringReturnsFalseIfDisplaySizeSameAsSourceSize) {
+    mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200);
+    mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.f, 100.f};
+
+    EXPECT_FALSE(mOutputLayer.needsFiltering());
+}
+
+TEST_F(OutputLayerTest, needsFilteringReturnsTrueIfDisplaySizeDifferentFromSourceSize) {
+    mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200);
+    mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.1f, 100.1f};
+
+    EXPECT_TRUE(mOutputLayer.needsFiltering());
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index d136562..b6d79d4 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -60,7 +60,7 @@
         mDisplayInstallOrientation(args.displayInstallOrientation),
         mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
                 compositionengine::DisplayCreationArgs{args.isSecure, args.isVirtual,
-                                                       args.displayId})},
+                                                       args.displayId, args.powerAdvisor})},
         mIsVirtual(args.isVirtual),
         mOrientation(),
         mActiveConfig(0),
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 8bc19d4..4321e3d 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -40,6 +40,7 @@
 #include <utils/Timers.h>
 
 #include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/PowerAdvisor.h"
 #include "RenderArea.h"
 
 namespace android {
@@ -241,6 +242,7 @@
     std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
     int initialPowerMode{HWC_POWER_MODE_NORMAL};
     bool isPrimary{false};
+    Hwc2::PowerAdvisor* powerAdvisor{nullptr};
 };
 
 class DisplayRenderArea : public RenderArea {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e7fbfe9..a2ee763 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -440,6 +440,7 @@
 }
 
 void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compositionState) const {
+    const auto& drawingState{getDrawingState()};
     compositionState.forceClientComposition = false;
 
     // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
@@ -451,9 +452,14 @@
     compositionState.colorTransform = getColorTransform();
     compositionState.colorTransformIsIdentity = !hasColorTransform();
     compositionState.surfaceDamage = surfaceDamageRegion;
+    compositionState.hasProtectedContent = isProtected();
+
+    const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
+    compositionState.isOpaque =
+            isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
 
     // Force client composition for special cases known only to the front-end.
-    if (isHdrY410() || getRoundedCornerState().radius > 0.0f) {
+    if (isHdrY410() || usesRoundedCorners) {
         compositionState.forceClientComposition = true;
     }
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d2d9ea5..af4fa98 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1943,7 +1943,7 @@
         if (!dirtyRegion.isEmpty()) {
             base::unique_fd readyFence;
             // redraw the whole screen
-            doComposeSurfaces(displayDevice, dirtyRegion, &readyFence);
+            display->composeSurfaces(dirtyRegion, &readyFence);
 
             display->getRenderSurface()->queueBuffer(std::move(readyFence));
         }
@@ -2488,6 +2488,7 @@
     creationArgs.displaySurface = dispSurface;
     creationArgs.hasWideColorGamut = false;
     creationArgs.supportedPerFrameMetadata = 0;
+    creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr;
 
     const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
     creationArgs.isPrimary = isInternalDisplay;
@@ -3228,201 +3229,12 @@
 
     ALOGV("doDisplayComposition");
     base::unique_fd readyFence;
-    if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return;
+    if (!display->composeSurfaces(Region::INVALID_REGION, &readyFence)) return;
 
     // swap buffers (presentation)
     display->getRenderSurface()->queueBuffer(std::move(readyFence));
 }
 
-bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice,
-                                       const Region& debugRegion, base::unique_fd* readyFence) {
-    ATRACE_CALL();
-    ALOGV("doComposeSurfaces");
-
-    auto display = displayDevice->getCompositionDisplay();
-    const auto& displayState = display->getState();
-    const auto displayId = display->getId();
-    auto& renderEngine = getRenderEngine();
-    const bool supportProtectedContent = renderEngine.supportsProtectedContent();
-
-    const Region bounds(displayState.bounds);
-    const DisplayRenderArea renderArea(displayDevice);
-    const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
-                                                      displayState.usesClientComposition};
-    bool applyColorMatrix = false;
-
-    renderengine::DisplaySettings clientCompositionDisplay;
-    std::vector<renderengine::LayerSettings> clientCompositionLayers;
-    sp<GraphicBuffer> buf;
-    base::unique_fd fd;
-
-    if (hasClientComposition) {
-        ALOGV("hasClientComposition");
-
-        if (displayDevice->isPrimary() && supportProtectedContent) {
-            bool needsProtected = false;
-            for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-                // If the layer is a protected layer, mark protected context is needed.
-                if (layer->isProtected()) {
-                    needsProtected = true;
-                    break;
-                }
-            }
-            if (needsProtected != renderEngine.isProtected()) {
-                renderEngine.useProtectedContext(needsProtected);
-            }
-            if (needsProtected != display->getRenderSurface()->isProtected() &&
-                needsProtected == renderEngine.isProtected()) {
-                display->getRenderSurface()->setProtected(needsProtected);
-            }
-        }
-
-        buf = display->getRenderSurface()->dequeueBuffer(&fd);
-
-        if (buf == nullptr) {
-            ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
-                  "client composition for this frame",
-                  displayDevice->getDisplayName().c_str());
-            return false;
-        }
-
-        clientCompositionDisplay.physicalDisplay = displayState.scissor;
-        clientCompositionDisplay.clip = displayState.scissor;
-        const ui::Transform& displayTransform = displayState.transform;
-        clientCompositionDisplay.globalTransform = displayTransform.asMatrix4();
-        clientCompositionDisplay.orientation = displayState.orientation;
-
-        const auto* profile = display->getDisplayColorProfile();
-        Dataspace outputDataspace = Dataspace::UNKNOWN;
-        if (profile->hasWideColorGamut()) {
-            outputDataspace = displayState.dataspace;
-        }
-        clientCompositionDisplay.outputDataspace = outputDataspace;
-        clientCompositionDisplay.maxLuminance =
-                profile->getHdrCapabilities().getDesiredMaxLuminance();
-
-        const bool hasDeviceComposition = displayState.usesDeviceComposition;
-        const bool skipClientColorTransform =
-                getHwComposer()
-                        .hasDisplayCapability(displayId,
-                                              HWC2::DisplayCapability::SkipClientColorTransform);
-
-        // Compute the global color transform matrix.
-        applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
-        if (applyColorMatrix) {
-            clientCompositionDisplay.colorTransform = displayState.colorTransformMat;
-        }
-    }
-
-    /*
-     * and then, render the layers targeted at the framebuffer
-     */
-
-    ALOGV("Rendering client layers");
-    const bool useIdentityTransform = false;
-    bool firstLayer = true;
-    Region clearRegion = Region::INVALID_REGION;
-    for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-        const Region viewportRegion(displayState.viewport);
-        const Region clip(viewportRegion.intersect(layer->visibleRegion));
-        ALOGV("Layer: %s", layer->getName().string());
-        ALOGV("  Composition type: %s", toString(layer->getCompositionType(displayDevice)).c_str());
-        if (!clip.isEmpty()) {
-            switch (layer->getCompositionType(displayDevice)) {
-                case Hwc2::IComposerClient::Composition::CURSOR:
-                case Hwc2::IComposerClient::Composition::DEVICE:
-                case Hwc2::IComposerClient::Composition::SIDEBAND:
-                case Hwc2::IComposerClient::Composition::SOLID_COLOR: {
-                    LOG_ALWAYS_FATAL_IF(!displayId);
-                    const Layer::State& state(layer->getDrawingState());
-                    if (layer->getClearClientTarget(displayDevice) && !firstLayer &&
-                        layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
-                        layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
-                        // never clear the very first layer since we're
-                        // guaranteed the FB is already cleared
-                        Region dummyRegion;
-                        compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
-                                clip,
-                                useIdentityTransform,
-                                layer->needsFiltering(renderArea.getDisplayDevice()) ||
-                                        renderArea.needsFiltering(),
-                                renderArea.isSecure(),
-                                supportProtectedContent,
-                                dummyRegion,
-                        };
-                        auto result = layer->prepareClientComposition(targetSettings);
-
-                        if (result) {
-                            auto& layerSettings = *result;
-                            layerSettings.source.buffer.buffer = nullptr;
-                            layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
-                            layerSettings.alpha = half(0.0);
-                            layerSettings.disableBlending = true;
-                            clientCompositionLayers.push_back(layerSettings);
-                        }
-                    }
-                    break;
-                }
-                case Hwc2::IComposerClient::Composition::CLIENT: {
-                    compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
-                            clip,
-                            useIdentityTransform,
-                            layer->needsFiltering(renderArea.getDisplayDevice()) ||
-                                    renderArea.needsFiltering(),
-                            renderArea.isSecure(),
-                            supportProtectedContent,
-                            clearRegion,
-                    };
-                    auto result = layer->prepareClientComposition(targetSettings);
-                    if (result) {
-                        clientCompositionLayers.push_back(*result);
-                    }
-                    break;
-                }
-                default:
-                    break;
-            }
-        } else {
-            ALOGV("  Skipping for empty clip");
-        }
-        firstLayer = false;
-    }
-
-    // Perform some cleanup steps if we used client composition.
-    if (hasClientComposition) {
-        clientCompositionDisplay.clearRegion = clearRegion;
-
-        // We boost GPU frequency here because there will be color spaces conversion
-        // and it's expensive. We boost the GPU frequency so that GPU composition can
-        // finish in time. We must reset GPU frequency afterwards, because high frequency
-        // consumes extra battery.
-        const bool expensiveRenderingExpected =
-                clientCompositionDisplay.outputDataspace == Dataspace::DISPLAY_P3;
-        if (expensiveRenderingExpected && displayId) {
-            mPowerAdvisor.setExpensiveRenderingExpected(*displayId, true);
-        }
-        if (!debugRegion.isEmpty()) {
-            Region::const_iterator it = debugRegion.begin();
-            Region::const_iterator end = debugRegion.end();
-            while (it != end) {
-                const Rect& rect = *it++;
-                renderengine::LayerSettings layerSettings;
-                layerSettings.source.buffer.buffer = nullptr;
-                layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
-                layerSettings.geometry.boundaries = rect.toFloatRect();
-                layerSettings.alpha = half(1.0);
-                clientCompositionLayers.push_back(layerSettings);
-            }
-        }
-        renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
-                                buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
-                                readyFence);
-    } else if (displayId) {
-        mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
-    }
-    return true;
-}
-
 status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
                                         const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
                                         const sp<IBinder>& parentHandle,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 64e87b1..ef096f8 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -768,12 +768,6 @@
     void logLayerStats();
     void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
 
-    // This fails if using GL and the surface has been destroyed. readyFence
-    // will be populated if using GL and native fence sync is supported, to
-    // signal when drawing has completed.
-    bool doComposeSurfaces(const sp<DisplayDevice>& display, const Region& debugRegionm,
-                           base::unique_fd* readyFence);
-
     void postFrame();
 
     /* ------------------------------------------------------------------------