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

Commit 0a2c43c7 authored by Robert Carr's avatar Robert Carr Committed by Rob Carr
Browse files

Composition strategy prediction: Make broader predictions.

As of recently we have begun speculating on the composition
strategy in cases where we expect GL composition to be present.
This enables us to gain back main thread time by running
chooseCompositionStrategy (sometimes a long call to HWC)
in parallel with GL composition itself. Currently this is only
enabled when no geometry changes. Unfortunately this doesn't
help us a lot, since most of the cases where we have jank
and issues with SF runtime are around animations. In this
CL we try and expand the heuristic to cover more cases,
including app launch. Now we expect that if we are sending the
same output layers to HWC in the same order, and all we have
changed is geometry, then the composition strategy will remain
stable. We implement by hashing a subset of the values
sent to HWC and detecting changes.

Test: Existing tests pass. Play with phone lots, no mispredictions
Merged-In: I1f41e2cc67b1b55780e1bf6e837d766b4c186161
Bug: 230617082
Change-Id: I1f41e2cc67b1b55780e1bf6e837d766b4c186161
parent f7f5aac0
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -164,6 +164,9 @@ struct OutputCompositionState {

    bool treat170mAsSrgb = false;

    uint64_t lastOutputLayerHash = 0;
    uint64_t outputLayerHash = 0;

    // Debugging
    void dump(std::string& result) const;
};
+22 −6
Original line number Diff line number Diff line
@@ -763,6 +763,7 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr
    bool includeGeometry = refreshArgs.updatingGeometryThisFrame;
    uint32_t z = 0;
    bool overrideZ = false;
    uint64_t outputLayerHash = 0;
    for (auto* layer : getOutputLayersOrderedByZ()) {
        if (layer == peekThroughLayer) {
            // No longer needed, although it should not show up again, so
@@ -789,6 +790,10 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr
                    constexpr bool isPeekingThrough = true;
                    peekThroughLayer->writeStateToHWC(includeGeometry, false, z++, overrideZ,
                                                      isPeekingThrough);
                    outputLayerHash ^= android::hashCombine(
                            reinterpret_cast<uint64_t>(&peekThroughLayer->getLayerFE()),
                            z, includeGeometry, overrideZ, isPeekingThrough,
                            peekThroughLayer->requiresClientComposition());
                }

                previousOverride = overrideInfo.buffer->getBuffer();
@@ -797,8 +802,15 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr

        constexpr bool isPeekingThrough = false;
        layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough);
        if (!skipLayer) {
            outputLayerHash ^= android::hashCombine(
                    reinterpret_cast<uint64_t>(&layer->getLayerFE()),
                    z, includeGeometry, overrideZ, isPeekingThrough,
                    layer->requiresClientComposition());
        }
    }
    editState().outputLayerHash = outputLayerHash;
}

compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
    compositionengine::OutputLayer* layerRequestingBgComposition = nullptr;
@@ -1493,6 +1505,10 @@ void Output::setTreat170mAsSrgb(bool enable) {
}

bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) {
    uint64_t lastOutputLayerHash = getState().lastOutputLayerHash;
    uint64_t outputLayerHash = getState().outputLayerHash;
    editState().lastOutputLayerHash = outputLayerHash;

    if (!getState().isEnabled || !mHwComposerAsyncWorker) {
        ALOGV("canPredictCompositionStrategy disabled");
        return false;
@@ -1513,6 +1529,11 @@ bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refresh
        return false;
    }

    if (lastOutputLayerHash != outputLayerHash) {
        ALOGV("canPredictCompositionStrategy output layers changed");
        return false;
    }

    // If no layer uses clientComposition, then don't predict composition strategy
    // because we have less work to do in parallel.
    if (!anyLayersRequireClientComposition()) {
@@ -1520,14 +1541,9 @@ bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refresh
        return false;
    }

    if (!refreshArgs.updatingOutputGeometryThisFrame) {
    return true;
}

    ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame");
    return false;
}

bool Output::anyLayersRequireClientComposition() const {
    const auto layers = getOutputLayersOrderedByZ();
    return std::any_of(layers.begin(), layers.end(),
+45 −0
Original line number Diff line number Diff line
@@ -850,14 +850,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerContentForAllLayers
    EXPECT_CALL(*layer1.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
    EXPECT_CALL(*layer2.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
    EXPECT_CALL(*layer3.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));

    injectOutputLayer(layer1);
    injectOutputLayer(layer2);
@@ -884,14 +890,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerGeometryAndContentF
    EXPECT_CALL(*layer1.outputLayer,
                writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
    EXPECT_CALL(*layer2.outputLayer,
                writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
    EXPECT_CALL(*layer3.outputLayer,
                writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));

    injectOutputLayer(layer1);
    injectOutputLayer(layer2);
@@ -917,14 +929,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, forcesClientCompositionForAllLa
    EXPECT_CALL(*layer1.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
    EXPECT_CALL(*layer2.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
    EXPECT_CALL(*layer3.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));

    injectOutputLayer(layer1);
    injectOutputLayer(layer2);
@@ -950,6 +968,8 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) {
    InSequence seq;
    EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
    EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
        EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
                .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
    EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));

@@ -957,6 +977,9 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) {
    EXPECT_CALL(*layer0.outputLayer,
                writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer0.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));


    // After calling planComposition (which clears overrideInfo), this test sets
    // layer3 to be the peekThroughLayer for layer1 and layer2. As a result, it
@@ -966,12 +989,18 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) {
                writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ true, /*isPeekingThrough*/
                                true));
    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer1.outputLayer,
                writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ true, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer2.outputLayer,
                writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, z++,
                                /*zIsOverridden*/ true, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));

    injectOutputLayer(layer0);
    injectOutputLayer(layer1);
@@ -4799,10 +4828,14 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, noBackgroundBlurWhenOpaque) {
    EXPECT_CALL(*layer1.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
    EXPECT_CALL(*layer2.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));

    layer2.layerFEState.backgroundBlurRadius = 10;
    layer2.layerFEState.isOpaque = true;
@@ -4831,14 +4864,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests)
    EXPECT_CALL(*layer1.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
    EXPECT_CALL(*layer2.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
    EXPECT_CALL(*layer3.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));

    layer2.layerFEState.backgroundBlurRadius = 10;
    layer2.layerFEState.isOpaque = false;
@@ -4868,14 +4907,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) {
    EXPECT_CALL(*layer1.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
    EXPECT_CALL(*layer2.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));
    EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
    EXPECT_CALL(*layer3.outputLayer,
                writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
            .WillRepeatedly(Return(false));

    BlurRegion region;
    layer2.layerFEState.blurRegions.push_back(region);