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

Commit 42473a6a authored by Patrick Williams's avatar Patrick Williams
Browse files

Implement stop layers

Implement stop layers within SurfaceFlinger. A follow up CL will add an interface for setting a stop layer when creating a mirrored hierarchy.

Bug: 403312802
Flag: com.android.graphics.surfaceflinger.flags.stop_layer
Test: LayerSnapshotTest
Change-Id: I24ab8abbc0715fd165e69c4f7f9b34848d9318b2
parent 441a7edd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -919,6 +919,7 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const {
    if (other.what & eLutsChanged) diff |= eLutsChanged;
    CHECK_DIFF(diff, ePictureProfileHandleChanged, other, pictureProfileHandle);
    CHECK_DIFF(diff, eAppContentPriorityChanged, other, appContentPriority);
    if (other.what & eStopLayerChanged) diff |= eStopLayerChanged;

    return diff;
}
+1 −0
Original line number Diff line number Diff line
@@ -254,6 +254,7 @@ struct layer_state_t {
        eClientDrawnCornerRadiusChanged = 0x200000'00000000,
        eBorderSettingsChanged = 0x400000'00000000,
        eBoxShadowSettingsChanged = 0x800000'00000000,
        eStopLayerChanged = 0x1000000'00000000,
    };

    layer_state_t();
+1 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ struct LayerCreationArgs {
    ui::LayerStack layerStackToMirror = ui::UNASSIGNED_LAYER_STACK;
    uint32_t parentId = UNASSIGNED_LAYER_ID;
    uint32_t layerIdToMirror = UNASSIGNED_LAYER_ID;
    uint32_t stopLayerId = UNASSIGNED_LAYER_ID;
    std::atomic<int32_t>* pendingBuffers = 0;
};

+100 −0
Original line number Diff line number Diff line
@@ -450,11 +450,17 @@ void LayerSnapshotBuilder::updateSnapshots(const Args& args) {
        LayerHierarchy::TraversalPath childPath =
                root.makeChild(args.root.getLayer()->id, LayerHierarchy::Variant::Attached);
        updateSnapshotsInHierarchy(args, args.root, childPath, rootSnapshot, /*depth=*/0);
        if (FlagManager::getInstance().stop_layer()) {
            applyStopLayers(args.root, childPath);
        }
    } else {
        for (auto& [childHierarchy, variant] : args.root.mChildren) {
            LayerHierarchy::TraversalPath childPath =
                    root.makeChild(childHierarchy->getLayer()->id, variant);
            updateSnapshotsInHierarchy(args, *childHierarchy, childPath, rootSnapshot, /*depth=*/0);
            if (FlagManager::getInstance().stop_layer()) {
                applyStopLayers(*childHierarchy, childPath);
            }
        }
    }

@@ -1397,4 +1403,98 @@ void LayerSnapshotBuilder::updateTouchableRegionCrop(const Args& args) {
    }
}

// Apply stop layers to the hierarchy.
//
// If layer X specifies stop layer Y, then any layer within X's subhierarchy that is z-ordered
// above Y is hidden. The stop layer itself, layer Y, is also hidden.
//
// This works by traversing the hierarchy in z-order. When a layer that specifies a stop layer is
// encountered, the specified stop layer is pushed to the stopLayer stack, the subhierarchy is
// traversed, then the stop layer is popped from the stack. If a layer whose id is stored in the
// stop layer stack is encountered during traversal, it is added to the activeStopLayers set. Any
// layer visited while the activeStopLayer set is non-empty is hidden. When an element is popped
// from the stopLayer stack, any active stop layers that are no longer in the stopLayer stack are
// removed from the activeStopLayers set.
void LayerSnapshotBuilder::applyStopLayers(const LayerHierarchy& hierarchy,
                                           const LayerHierarchy::TraversalPath& traversalPath) {
    ftl::SmallVector<uint32_t, 5> stopLayers;
    ftl::SmallVector<uint32_t, 5> activeStopLayers;
    applyStopLayersInternal(hierarchy, traversalPath, stopLayers, activeStopLayers);
}

void LayerSnapshotBuilder::applyStopLayersInternal(
        const LayerHierarchy& hierarchy, const LayerHierarchy::TraversalPath& traversalPath,
        ftl::SmallVector<uint32_t, 5>& stopLayers,
        ftl::SmallVector<uint32_t, 5>& activeStopLayers) {
    const RequestedLayerState* layer = hierarchy.getLayer();

    // Push to the stopLayer stack.
    if (layer->stopLayerId != UNASSIGNED_LAYER_ID) {
        stopLayers.push_back(layer->stopLayerId);
    }

    // Hide this layer if the activeStopLayers set is non-empty.
    if (!activeStopLayers.empty()) {
        LayerSnapshot* snapshot = getSnapshot(traversalPath);
        snapshot->isHiddenByPolicyFromParent = true;
    }

    // Traverse z-ordered below children before potentially activating this layer as a stop layer.
    auto childIt = hierarchy.mChildren.begin();
    while (childIt != hierarchy.mChildren.end()) {
        auto& [childHierarchy, childVariant] = *childIt;
        if (childHierarchy->getLayer()->z >= 0) {
            break;
        }
        childIt++;

        LayerHierarchy::TraversalPath childTraversalPath =
                traversalPath.makeChild(childHierarchy->getLayer()->id, childVariant);
        if (childTraversalPath.detached) {
            continue;
        }

        applyStopLayersInternal(*childHierarchy, childTraversalPath, stopLayers, activeStopLayers);
    }

    // Activate this layer as a stop layer if it's in the stopLayers stack.
    bool isStopLayer =
            std::find(stopLayers.begin(), stopLayers.end(), layer->id) != stopLayers.end();
    if (isStopLayer) {
        activeStopLayers.push_back(layer->id);
        LayerSnapshot* snapshot = getSnapshot(traversalPath);
        snapshot->isHiddenByPolicyFromParent = true;
    }

    // Traverse z-ordered above children.
    while (childIt != hierarchy.mChildren.end()) {
        auto& [childHierarchy, childVariant] = *childIt++;

        LayerHierarchy::TraversalPath childTraversalPath =
                traversalPath.makeChild(childHierarchy->getLayer()->id, childVariant);
        if (childTraversalPath.detached) {
            continue;
        }

        applyStopLayersInternal(*childHierarchy, childTraversalPath, stopLayers, activeStopLayers);
    }

    // Pop from the stopLayer stack and remove active stop layers from the activeStopLayers set
    // if necessary.
    if (layer->stopLayerId != UNASSIGNED_LAYER_ID) {
        stopLayers.pop_back();

        auto it = activeStopLayers.begin();
        while (it != activeStopLayers.end()) {
            bool stopLayerNoLongerActive =
                    std::find(stopLayers.begin(), stopLayers.end(), *it) == stopLayers.end();
            if (stopLayerNoLongerActive) {
                activeStopLayers.unstable_erase(it);
            } else {
                it++;
            }
        }
    }
}

} // namespace android::surfaceflinger::frontend
+5 −0
Original line number Diff line number Diff line
@@ -139,6 +139,11 @@ private:
                                          const Args& args, bool* outChildHasValidFrameRate);
    void updateTouchableRegionCrop(const Args& args);

    void applyStopLayers(const LayerHierarchy&, const LayerHierarchy::TraversalPath&);
    void applyStopLayersInternal(const LayerHierarchy&, const LayerHierarchy::TraversalPath&,
                                 ftl::SmallVector<uint32_t, 5>& stopLayers,
                                 ftl::SmallVector<uint32_t, 5>& activeStopLayers);

    std::unordered_map<LayerHierarchy::TraversalPath, LayerSnapshot*,
                       LayerHierarchy::TraversalPathHash>
            mPathToSnapshot;
Loading