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

Commit f9fc8eed authored by Chia-I Wu's avatar Chia-I Wu
Browse files

surfaceflinger: fix fencing when layers become invisible

A layer always holds on to a buffer (after the first one is
acquired).  When a new buffer comes in, and the layer is visible, it
will

 - acquire the new buffer
 - present the new buffer to HWC
 - get the release fence from HWC
 - associate the old buffer with the release fence and release it

But if the layer happens to be becoming invisible, it will go
through

 - acquire the new buffer
 - destroy the HWC layer and present
 - release the old buffer without any fence

The problem here is that the old buffer is still on screen until the
present takes effect (e.g., on next HW vsync).  Rendering artifacts
may be seen on screen.

This commit changes the acquire/release process for layer becoming
invisible to

 - acquire the new buffer
 - destroy the HWC layer and present
 - get a fence from HWC
 - associate the old buffer with the fence and release it

We do not require HWC getReleaseFences to return fences for
destroyed layers.  We can only use the next best fence, the present
fence.

Bug: 68490054
Test: manual
Merged-In: I68bbf392a6681c6512fc0be68a7d17df122f7308
Change-Id: I68bbf392a6681c6512fc0be68a7d17df122f7308
parent 42ddbb44
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -399,6 +399,14 @@ const Vector< sp<Layer> >& DisplayDevice::getVisibleLayersSortedByZ() const {
    return mVisibleLayersSortedByZ;
}

void DisplayDevice::setLayersNeedingFences(const Vector< sp<Layer> >& layers) {
    mLayersNeedingFences = layers;
}

const Vector< sp<Layer> >& DisplayDevice::getLayersNeedingFences() const {
    return mLayersNeedingFences;
}

Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
    Region dirty;
    if (repaintEverything) {
+4 −0
Original line number Diff line number Diff line
@@ -124,6 +124,8 @@ public:

    void                    setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
    const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
    void                    setLayersNeedingFences(const Vector< sp<Layer> >& layers);
    const Vector< sp<Layer> >& getLayersNeedingFences() const;
    Region                  getDirtyRegion(bool repaintEverything) const;

    void                    setLayerStack(uint32_t stack);
@@ -241,6 +243,8 @@ private:

    // list of visible layers on that display
    Vector< sp<Layer> > mVisibleLayersSortedByZ;
    // list of layers needing fences
    Vector< sp<Layer> > mLayersNeedingFences;

    /*
     * Transaction state
+0 −3
Original line number Diff line number Diff line
@@ -208,9 +208,6 @@ Layer::~Layer() {

#ifdef USE_HWC2
void Layer::onLayerDisplayed(const sp<Fence>& releaseFence) {
    if (mHwcLayers.empty()) {
        return;
    }
    mSurfaceFlingerConsumer->setReleaseFence(releaseFence);
}
#else
+29 −0
Original line number Diff line number Diff line
@@ -1674,6 +1674,7 @@ void SurfaceFlinger::rebuildLayerStacks() {
            Region opaqueRegion;
            Region dirtyRegion;
            Vector<sp<Layer>> layersSortedByZ;
            Vector<sp<Layer>> layersNeedingFences;
            const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
            const Transform& tr(displayDevice->getTransform());
            const Rect bounds(displayDevice->getBounds());
@@ -1681,6 +1682,7 @@ void SurfaceFlinger::rebuildLayerStacks() {
                computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);

                mDrawingState.traverseInZOrder([&](Layer* layer) {
                    bool hwcLayerDestroyed = false;
                    if (layer->belongsToDisplay(displayDevice->getLayerStack(),
                                displayDevice->isPrimary())) {
                        Region drawRegion(tr.transform(
@@ -1691,6 +1693,8 @@ void SurfaceFlinger::rebuildLayerStacks() {
                        } else {
                            // Clear out the HWC layer if this layer was
                            // previously visible, but no longer is
                            hwcLayerDestroyed = layer->hasHwcLayer(
                                    displayDevice->getHwcDisplayId());
                            layer->setHwcLayer(displayDevice->getHwcDisplayId(),
                                    nullptr);
                        }
@@ -1698,12 +1702,26 @@ void SurfaceFlinger::rebuildLayerStacks() {
                        // WM changes displayDevice->layerStack upon sleep/awake.
                        // Here we make sure we delete the HWC layers even if
                        // WM changed their layer stack.
                        hwcLayerDestroyed = layer->hasHwcLayer(displayDevice->getHwcDisplayId());
                        layer->setHwcLayer(displayDevice->getHwcDisplayId(),
                                nullptr);
                    }

                    // If a layer is not going to get a release fence because
                    // it is invisible, but it is also going to release its
                    // old buffer, add it to the list of layers needing
                    // fences.
                    if (hwcLayerDestroyed) {
                        auto found = std::find(mLayersWithQueuedFrames.cbegin(),
                                mLayersWithQueuedFrames.cend(), layer);
                        if (found != mLayersWithQueuedFrames.cend()) {
                            layersNeedingFences.add(layer);
                        }
                    }
                });
            }
            displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
            displayDevice->setLayersNeedingFences(layersNeedingFences);
            displayDevice->undefinedRegion.set(bounds);
            displayDevice->undefinedRegion.subtractSelf(
                    tr.transform(opaqueRegion));
@@ -1942,6 +1960,17 @@ void SurfaceFlinger::postFramebuffer()

            layer->onLayerDisplayed(releaseFence);
        }

        // We've got a list of layers needing fences, that are disjoint with
        // displayDevice->getVisibleLayersSortedByZ.  The best we can do is to
        // supply them with the present fence.
        if (!displayDevice->getLayersNeedingFences().isEmpty()) {
            sp<Fence> presentFence = mHwc->getPresentFence(hwcId);
            for (auto& layer : displayDevice->getLayersNeedingFences()) {
                layer->onLayerDisplayed(presentFence);
            }
        }

        if (hwcId >= 0) {
            mHwc->clearReleaseFences(hwcId);
        }