Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a0afda7 authored by Leon Scroggins III's avatar Leon Scroggins III
Browse files

Set blockingRegion for DISPLAY_DECORATION layers

Devices that have support for DISPLAY_DECORATION layers may also have
support for a blockingRegion, which will allow the DPU to skip regions
that are known to be transparent, in order to save power.

Use the transparentRegionHint to compute the blockingRegion. It may not
be accurate for all layers, which is why it is only used for
DISPLAY_DECORATION layers.

Add tests.

Bug: 212736475
Test: libcompositionengine_test
Change-Id: I6c5d29614dc8d65d8481150ce717a440192083a0
parent 70162527
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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;
+17 −5
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@

#include "TracedOrdinal.h"

using aidl::android::hardware::graphics::composer3::Composition;

namespace android::compositionengine {

Output::~Output() = default;
@@ -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;

@@ -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&) {
+8 −0
Original line number Diff line number Diff line
@@ -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;
+21 −1
Original line number Diff line number Diff line
@@ -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));
@@ -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) {
@@ -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()
 */
+31 −1
Original line number Diff line number Diff line
@@ -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));
@@ -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;
@@ -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));
@@ -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()
 */