SF: Move doComposeSurfaces to CompositionEngine

Test: atest libsurfaceflinger_unittest libcompositionengine_test
Bug: 121291683
Change-Id: Iae3377a5ea018f9ec53c5a76ed6a86620f39b731
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) {