Merge "Set blockingRegion for DISPLAY_DECORATION layers"
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 49cb912..08cfaa6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -90,6 +90,10 @@
     // The dataspace for this layer
     ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
 
+    // A hint to the HWC that this region is transparent and may be skipped in
+    // order to save power.
+    Region outputSpaceBlockingRegionHint;
+
     // Overrides the buffer, acquire fence, and display frame stored in LayerFECompositionState
     struct {
         std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 162d84e..65f9731 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -50,6 +50,8 @@
 
 #include "TracedOrdinal.h"
 
+using aidl::android::hardware::graphics::composer3::Composition;
+
 namespace android::compositionengine {
 
 Output::~Output() = default;
@@ -529,11 +531,18 @@
 
     /*
      * transparentRegion: area of a surface that is hinted to be completely
-     * transparent. This is only used to tell when the layer has no visible non-
-     * transparent regions and can be removed from the layer list. It does not
-     * affect the visibleRegion of this layer or any layers beneath it. The hint
-     * may not be correct if apps don't respect the SurfaceView restrictions
-     * (which, sadly, some don't).
+     * transparent.
+     * This is used to tell when the layer has no visible non-transparent
+     * regions and can be removed from the layer list. It does not affect the
+     * visibleRegion of this layer or any layers beneath it. The hint may not
+     * be correct if apps don't respect the SurfaceView restrictions (which,
+     * sadly, some don't).
+     *
+     * In addition, it is used on DISPLAY_DECORATION layers to specify the
+     * blockingRegion, allowing the DPU to skip it to save power. Once we have
+     * hardware that supports a blockingRegion on frames with AFBC, it may be
+     * useful to use this for other layers, too, so long as we can prevent
+     * regressions on b/7179570.
      */
     Region transparentRegion;
 
@@ -674,6 +683,9 @@
     outputLayerState.outputSpaceVisibleRegion = outputState.transform.transform(
             visibleNonShadowRegion.intersect(outputState.layerStackSpace.getContent()));
     outputLayerState.shadowRegion = shadowRegion;
+    outputLayerState.outputSpaceBlockingRegionHint =
+            layerFEState->compositionType == Composition::DISPLAY_DECORATION ? transparentRegion
+                                                                             : Region();
 }
 
 void Output::setReleasedLayers(const compositionengine::CompositionRefreshArgs&) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 95cc5a8..4ccf11f 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -484,6 +484,14 @@
         visibleRegion.dump(LOG_TAG);
     }
 
+    if (auto error =
+                hwcLayer->setBlockingRegion(outputDependentState.outputSpaceBlockingRegionHint);
+        error != hal::Error::NONE) {
+        ALOGE("[%s] Failed to set blocking region: %s (%d)", getLayerFE().getDebugName(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+        outputDependentState.outputSpaceBlockingRegionHint.dump(LOG_TAG);
+    }
+
     const auto dataspace = outputDependentState.overrideInfo.buffer
             ? outputDependentState.overrideInfo.dataspace
             : outputDependentState.dataspace;
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 132ac02..0b123b1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -846,7 +846,8 @@
                                    ui::Dataspace dataspace = kDataspace,
                                    const Region& visibleRegion = kOutputSpaceVisibleRegion,
                                    const Region& surfaceDamage = kSurfaceDamage,
-                                   float whitePointNits = kWhitePointNits) {
+                                   float whitePointNits = kWhitePointNits,
+                                   const Region& blockingRegion = Region()) {
         EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(visibleRegion))).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setDataspace(dataspace)).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setWhitePointNits(whitePointNits)).WillOnce(Return(kError));
@@ -855,6 +856,8 @@
                                          ? hal::Error::UNSUPPORTED
                                          : hal::Error::NONE));
         EXPECT_CALL(*mHwcLayer, setSurfaceDamage(RegionEq(surfaceDamage))).WillOnce(Return(kError));
+        EXPECT_CALL(*mHwcLayer, setBlockingRegion(RegionEq(blockingRegion)))
+                .WillOnce(Return(kError));
     }
 
     void expectSetCompositionTypeCall(Composition compositionType) {
@@ -1278,6 +1281,23 @@
     EXPECT_EQ(Composition::DEVICE, mOutputLayer.getState().hwc->hwcCompositionType);
 }
 
+TEST_F(OutputLayerWriteStateToHWCTest, setBlockingRegion) {
+    mLayerFEState.compositionType = Composition::DISPLAY_DECORATION;
+    const auto blockingRegion = Region(Rect(0, 0, 1000, 1000));
+    mOutputLayer.editState().outputSpaceBlockingRegionHint = blockingRegion;
+
+    expectGeometryCommonCalls();
+    expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion,
+                              kSurfaceDamage, kWhitePointNits, blockingRegion);
+    expectSetHdrMetadataAndBufferCalls();
+    EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+    expectSetCompositionTypeCall(Composition::DISPLAY_DECORATION);
+
+    mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+                                 /*zIsOverridden*/ false, /*isPeekingThrough*/
+                                 false);
+}
+
 /*
  * OutputLayer::writeCursorPositionToHWC()
  */
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 655db4b..f7d5991 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -1291,7 +1291,7 @@
         mLayer.layerFEState.contentDirty = true;
         mLayer.layerFEState.geomLayerBounds = FloatRect{0, 0, 100, 200};
         mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
-        mLayer.layerFEState.transparentRegionHint = Region(Rect(0, 0, 100, 100));
+        mLayer.layerFEState.transparentRegionHint = kTransparentRegionHint;
 
         mLayer.outputLayerState.visibleRegion = Region(Rect(0, 0, 50, 200));
         mLayer.outputLayerState.coveredRegion = Region(Rect(50, 0, 100, 200));
@@ -1309,6 +1309,7 @@
     static const Region kRightHalfBoundsNoRotation;
     static const Region kLowerHalfBoundsNoRotation;
     static const Region kFullBounds90Rotation;
+    static const Region kTransparentRegionHint;
 
     StrictMock<OutputPartialMock> mOutput;
     LayerFESet mGeomSnapshots;
@@ -1326,6 +1327,8 @@
         Region(Rect(50, 0, 100, 200));
 const Region OutputEnsureOutputLayerIfVisibleTest::kFullBounds90Rotation =
         Region(Rect(0, 0, 200, 100));
+const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHint =
+        Region(Rect(0, 0, 100, 100));
 
 TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) {
     EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
@@ -1749,6 +1752,33 @@
     ensureOutputLayerIfVisible();
 }
 
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, displayDecorSetsBlockingFromTransparentRegion) {
+    mLayer.layerFEState.isOpaque = false;
+    mLayer.layerFEState.contentDirty = true;
+    mLayer.layerFEState.compositionType =
+            aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
+
+    EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
+    EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer.layerFE)))
+            .WillOnce(Return(&mLayer.outputLayer));
+    ensureOutputLayerIfVisible();
+
+    EXPECT_THAT(mLayer.outputLayerState.outputSpaceBlockingRegionHint,
+                RegionEq(kTransparentRegionHint));
+}
+
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, normalLayersDoNotSetBlockingRegion) {
+    mLayer.layerFEState.isOpaque = false;
+    mLayer.layerFEState.contentDirty = true;
+
+    EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
+    EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer.layerFE)))
+            .WillOnce(Return(&mLayer.outputLayer));
+    ensureOutputLayerIfVisible();
+
+    EXPECT_THAT(mLayer.outputLayerState.outputSpaceBlockingRegionHint, RegionEq(Region()));
+}
+
 /*
  * Output::present()
  */