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

Commit b7a0549c authored by Jesse Hall's avatar Jesse Hall
Browse files

surfaceflinger: skip composition for empty frames

By not committing the results of composition for empty frames, we
avoid spitting out series of black frames for virtual displays that
don't have visible layers. We still draw one black frame when going
from having layers to not having any. In particular, this avoids
having a series of empty frames due to re-compositing the primary
display in the period between creating the virtual display and adding
layers to it.

Bug: 16786752
Change-Id: I7e9b2ed2e407d8d49c7af736b447d4c6181b0ad8
parent e3d37a7b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -59,7 +59,8 @@ DisplayDevice::DisplayDevice(
        const sp<DisplaySurface>& displaySurface,
        const sp<IGraphicBufferProducer>& producer,
        EGLConfig config)
    : mFlinger(flinger),
    : lastCompositionHadVisibleLayers(false),
      mFlinger(flinger),
      mType(type), mHwcDisplayId(hwcId),
      mDisplayToken(displayToken),
      mDisplaySurface(displaySurface),
+1 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ public:
    mutable Region swapRegion;
    // region in screen space
    Region undefinedRegion;
    bool lastCompositionHadVisibleLayers;

    enum DisplayType {
        DISPLAY_ID_INVALID = -1,
+25 −2
Original line number Diff line number Diff line
@@ -881,9 +881,32 @@ void SurfaceFlinger::rebuildLayerStacks() {

void SurfaceFlinger::setUpHWComposer() {
    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
        bool mustRecompose =
                !(mDisplays[dpy]->getDirtyRegion(false).isEmpty());
        bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
        bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
        bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;

        // If nothing has changed (!dirty), don't recompose.
        // If something changed, but we don't currently have any visible layers,
        //   and didn't when we last did a composition, then skip it this time.
        // The second rule does two things:
        // - When all layers are removed from a display, we'll emit one black
        //   frame, then nothing more until we get new layers.
        // - When a display is created with a private layer stack, we won't
        //   emit any black frames until a layer is added to the layer stack.
        bool mustRecompose = dirty && !(empty && wasEmpty);

        ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
                "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy,
                mustRecompose ? "doing" : "skipping",
                dirty ? "+" : "-",
                empty ? "+" : "-",
                wasEmpty ? "+" : "-");

        mDisplays[dpy]->beginFrame(mustRecompose);

        if (mustRecompose) {
            mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
        }
    }

    HWComposer& hwc(getHwComposer());