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) {