Loading services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +4 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,10 @@ struct OutputLayerCompositionState { // 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; Loading services/surfaceflinger/CompositionEngine/src/Output.cpp +17 −5 Original line number Diff line number Diff line Loading @@ -50,6 +50,8 @@ #include "TracedOrdinal.h" using aidl::android::hardware::graphics::composer3::Composition; namespace android::compositionengine { Output::~Output() = default; Loading Loading @@ -529,11 +531,18 @@ void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE, /* * 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; Loading Loading @@ -674,6 +683,9 @@ void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE, 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&) { Loading services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -484,6 +484,14 @@ void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) 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; Loading services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +21 −1 Original line number Diff line number Diff line Loading @@ -846,7 +846,8 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { 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)); Loading @@ -855,6 +856,8 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { ? 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) { Loading Loading @@ -1278,6 +1281,23 @@ TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersPeekingThroughAllowsDeviceC 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() */ Loading services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +31 −1 Original line number Diff line number Diff line Loading @@ -1291,7 +1291,7 @@ struct OutputEnsureOutputLayerIfVisibleTest : public testing::Test { 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)); Loading @@ -1309,6 +1309,7 @@ struct OutputEnsureOutputLayerIfVisibleTest : public testing::Test { static const Region kRightHalfBoundsNoRotation; static const Region kLowerHalfBoundsNoRotation; static const Region kFullBounds90Rotation; static const Region kTransparentRegionHint; StrictMock<OutputPartialMock> mOutput; LayerFESet mGeomSnapshots; Loading @@ -1326,6 +1327,8 @@ const Region OutputEnsureOutputLayerIfVisibleTest::kLowerHalfBoundsNoRotation = 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)); Loading Loading @@ -1749,6 +1752,33 @@ TEST_F(OutputEnsureOutputLayerIfVisibleTest, takesNotSoEarlyOutifLayerWithShadow 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() */ Loading Loading
services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +4 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,10 @@ struct OutputLayerCompositionState { // 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; Loading
services/surfaceflinger/CompositionEngine/src/Output.cpp +17 −5 Original line number Diff line number Diff line Loading @@ -50,6 +50,8 @@ #include "TracedOrdinal.h" using aidl::android::hardware::graphics::composer3::Composition; namespace android::compositionengine { Output::~Output() = default; Loading Loading @@ -529,11 +531,18 @@ void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE, /* * 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; Loading Loading @@ -674,6 +683,9 @@ void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE, 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&) { Loading
services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -484,6 +484,14 @@ void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) 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; Loading
services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +21 −1 Original line number Diff line number Diff line Loading @@ -846,7 +846,8 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { 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)); Loading @@ -855,6 +856,8 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { ? 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) { Loading Loading @@ -1278,6 +1281,23 @@ TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersPeekingThroughAllowsDeviceC 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() */ Loading
services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +31 −1 Original line number Diff line number Diff line Loading @@ -1291,7 +1291,7 @@ struct OutputEnsureOutputLayerIfVisibleTest : public testing::Test { 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)); Loading @@ -1309,6 +1309,7 @@ struct OutputEnsureOutputLayerIfVisibleTest : public testing::Test { static const Region kRightHalfBoundsNoRotation; static const Region kLowerHalfBoundsNoRotation; static const Region kFullBounds90Rotation; static const Region kTransparentRegionHint; StrictMock<OutputPartialMock> mOutput; LayerFESet mGeomSnapshots; Loading @@ -1326,6 +1327,8 @@ const Region OutputEnsureOutputLayerIfVisibleTest::kLowerHalfBoundsNoRotation = 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)); Loading Loading @@ -1749,6 +1752,33 @@ TEST_F(OutputEnsureOutputLayerIfVisibleTest, takesNotSoEarlyOutifLayerWithShadow 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() */ Loading