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()
*/