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

Commit 10c357b7 authored by Ady Abraham's avatar Ady Abraham Committed by Automerger Merge Worker
Browse files

Merge "SF: fix frame rate for layer tree" into sc-dev am: 3871daf5

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/15463251

Change-Id: I93aefc2c400cb51738de7f27ff0290faa658a838
parents 9c7441f5 3871daf5
Loading
Loading
Loading
Loading
+60 −66
Original line number Diff line number Diff line
@@ -1117,46 +1117,59 @@ StretchEffect Layer::getStretchEffect() const {
    return StretchEffect{};
}

void Layer::updateTreeHasFrameRateVote() {
    const auto traverseTree = [&](const LayerVector::Visitor& visitor) {
        auto parent = getParent();
        while (parent) {
            visitor(parent.get());
            parent = parent->getParent();
bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded) {
    // The frame rate for layer tree is this layer's frame rate if present, or the parent frame rate
    const auto frameRate = [&] {
        if (mDrawingState.frameRate.rate.isValid() ||
            mDrawingState.frameRate.type == FrameRateCompatibility::NoVote) {
            return mDrawingState.frameRate;
        }

        traverse(LayerVector::StateSet::Current, visitor);
    };
        return parentFrameRate;
    }();

    // update parents and children about the vote
    // First traverse the tree and count how many layers has votes.
    int layersWithVote = 0;
    traverseTree([&layersWithVote](Layer* layer) {
    *transactionNeeded |= setFrameRateForLayerTree(frameRate);

    // The frame rate is propagated to the children
    bool childrenHaveFrameRate = false;
    for (const sp<Layer>& child : mCurrentChildren) {
        childrenHaveFrameRate |=
                child->propagateFrameRateForLayerTree(frameRate, transactionNeeded);
    }

    // If we don't have a valid frame rate, but the children do, we set this
    // layer as NoVote to allow the children to control the refresh rate
    if (!frameRate.rate.isValid() && frameRate.type != FrameRateCompatibility::NoVote &&
        childrenHaveFrameRate) {
        *transactionNeeded |=
                setFrameRateForLayerTree(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote));
    }

    // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for
    // the same reason we are allowing touch boost for those layers. See
    // RefreshRateConfigs::getBestRefreshRate for more details.
    const auto layerVotedWithDefaultCompatibility =
                layer->mDrawingState.frameRate.rate.isValid() &&
                layer->mDrawingState.frameRate.type == FrameRateCompatibility::Default;
        const auto layerVotedWithNoVote =
                layer->mDrawingState.frameRate.type == FrameRateCompatibility::NoVote;
            frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Default;
    const auto layerVotedWithNoVote = frameRate.type == FrameRateCompatibility::NoVote;
    const auto layerVotedWithExactCompatibility =
                layer->mDrawingState.frameRate.type == FrameRateCompatibility::Exact;
            frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Exact;
    return layerVotedWithDefaultCompatibility || layerVotedWithNoVote ||
            layerVotedWithExactCompatibility || childrenHaveFrameRate;
}

        // We do not count layers that are ExactOrMultiple for the same reason
        // we are allowing touch boost for those layers. See
        // RefreshRateConfigs::getBestRefreshRate for more details.
        if (layerVotedWithDefaultCompatibility || layerVotedWithNoVote ||
            layerVotedWithExactCompatibility) {
            layersWithVote++;
void Layer::updateTreeHasFrameRateVote() {
    const auto root = [&]() -> sp<Layer> {
        sp<Layer> layer = this;
        while (auto parent = layer->getParent()) {
            layer = parent;
        }
    });
        return layer;
    }();

    // Now we can update the tree frame rate vote for each layer in the tree
    const bool treeHasFrameRateVote = layersWithVote > 0;
    bool transactionNeeded = false;
    root->propagateFrameRateForLayerTree({}, &transactionNeeded);

    traverseTree([treeHasFrameRateVote, &transactionNeeded](Layer* layer) {
        transactionNeeded = layer->updateFrameRateForLayerTree(treeHasFrameRateVote);
    });

    // TODO(b/195668952): we probably don't need eTraversalNeeded here
    if (transactionNeeded) {
        mFlinger->setTransactionFlags(eTraversalNeeded);
    }
@@ -1283,13 +1296,15 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForBuffer(
    return surfaceFrame;
}

bool Layer::updateFrameRateForLayerTree(bool treeHasFrameRateVote) {
    const auto updateDrawingState = [&](FrameRate frameRate) {
bool Layer::setFrameRateForLayerTree(FrameRate frameRate) {
    if (mDrawingState.frameRateForLayerTree == frameRate) {
        return false;
    }

    mDrawingState.frameRateForLayerTree = frameRate;

    // TODO(b/195668952): we probably don't need to dirty visible regions here
    // or even store frameRateForLayerTree in mDrawingState
    mDrawingState.sequence++;
    mDrawingState.modified = true;
    setTransactionFlags(eTransactionNeeded);
@@ -1298,27 +1313,6 @@ bool Layer::updateFrameRateForLayerTree(bool treeHasFrameRateVote) {
                                             LayerHistory::LayerUpdateType::SetFrameRate);

    return true;
    };

    const auto frameRate = mDrawingState.frameRate;
    if (frameRate.rate.isValid() || frameRate.type == FrameRateCompatibility::NoVote) {
        return updateDrawingState(frameRate);
    }

    // This layer doesn't have a frame rate. Check if its ancestors have a vote
    for (sp<Layer> parent = getParent(); parent; parent = parent->getParent()) {
        if (parent->mDrawingState.frameRate.rate.isValid()) {
            return updateDrawingState(parent->mDrawingState.frameRate);
        }
    }

    // This layer and its ancestors don't have a frame rate. If one of successors
    // has a vote, return a NoVote for successors to set the vote
    if (treeHasFrameRateVote) {
        return updateDrawingState(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote));
    }

    return updateDrawingState(frameRate);
}

Layer::FrameRate Layer::getFrameRateForLayerTree() const {
+2 −2
Original line number Diff line number Diff line
@@ -1053,6 +1053,8 @@ private:
                                          const std::vector<Layer*>& layersInTree);

    void updateTreeHasFrameRateVote();
    bool propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded);
    bool setFrameRateForLayerTree(FrameRate);
    void setZOrderRelativeOf(const wp<Layer>& relativeOf);
    bool isTrustedOverlay() const;

@@ -1071,8 +1073,6 @@ private:
    // Fills in the frame and transform info for the InputWindowInfo
    void fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay);

    bool updateFrameRateForLayerTree(bool treeHasFrameRateVote);

    // Cached properties computed from drawing state
    // Effective transform taking into account parent transforms and any parent scaling, which is
    // a transform from the current layer coordinate space to display(screen) coordinate space.
+35 −0
Original line number Diff line number Diff line
@@ -485,5 +485,40 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) {
    EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[1].desiredRefreshRate));
}

TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) {
    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);

    const auto& layerFactory = GetParam();

    const auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
    const auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
    const auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
    const auto childOfChild1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));

    addChild(parent, child1);
    addChild(child1, childOfChild1);

    childOfChild1->setFrameRate(FRAME_RATE_VOTE1);
    commitTransaction();
    EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
    EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree());
    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());

    addChild(parent, child2);
    commitTransaction();
    EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
    EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree());
    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());

    childOfChild1->setFrameRate(FRAME_RATE_NO_VOTE);
    commitTransaction();
    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
    EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
    EXPECT_EQ(FRAME_RATE_NO_VOTE, childOfChild1->getFrameRateForLayerTree());
    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
}

} // namespace
} // namespace android