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

Commit cd60f99a authored by Mathias Agopian's avatar Mathias Agopian
Browse files

refactor compositing code to avoid multiple eglMakeCurrent() calls

when multiple displays are connected, we ended-up having to
call eglMakeCurrent() twice per display due to a limitation
in EGL. this fixes that.

Change-Id: I11e4584df50f8c24bbecee74e37b28b3ee031d2f
parent 5f20e2d4
Loading
Loading
Loading
Loading
+12 −0
Original line number Original line Diff line number Diff line
@@ -218,6 +218,18 @@ bool DisplayDevice::getSecureLayerVisible() const {
    return mSecureLayerVisible;
    return mSecureLayerVisible;
}
}


Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
    Region dirty;
    const Transform& planeTransform(mGlobalTransform);
    if (repaintEverything) {
        dirty.set(getBounds());
    } else {
        dirty = planeTransform.transform(this->dirtyRegion);
        dirty.andSelf(getBounds());
    }
    return dirty;
}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------


bool DisplayDevice::canDraw() const {
bool DisplayDevice::canDraw() const {
+1 −0
Original line number Original line Diff line number Diff line
@@ -87,6 +87,7 @@ public:
    void                    setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers);
    void                    setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers);
    Vector< sp<LayerBase> > getVisibleLayersSortedByZ() const;
    Vector< sp<LayerBase> > getVisibleLayersSortedByZ() const;
    bool                    getSecureLayerVisible() const;
    bool                    getSecureLayerVisible() const;
    Region                  getDirtyRegion(bool repaintEverything) const;


    status_t                setOrientation(int orientation);
    status_t                setOrientation(int orientation);
    void                    setLayerStack(uint32_t stack);
    void                    setLayerStack(uint32_t stack);
+141 −150
Original line number Original line Diff line number Diff line
@@ -649,20 +649,101 @@ void SurfaceFlinger::handleMessageTransaction() {
}
}


void SurfaceFlinger::handleMessageInvalidate() {
void SurfaceFlinger::handleMessageInvalidate() {
    ATRACE_CALL();
    handlePageFlip();
    handlePageFlip();
}
}


void SurfaceFlinger::handleMessageRefresh() {
void SurfaceFlinger::handleMessageRefresh() {
    handleRefresh();
    ATRACE_CALL();
    preComposition();
    rebuildLayerStacks();
    setUpHWComposer();
    doDebugFlashRegions();
    doComposition();
    postComposition();
}


void SurfaceFlinger::doDebugFlashRegions()
{
    // is debugging enabled
    if (CC_LIKELY(!mDebugRegion))
        return;

    const bool repaintEverything = mRepaintEverything;
    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
        const sp<DisplayDevice>& hw(mDisplays[dpy]);
        if (hw->canDraw()) {
            // transform the dirty region into this screen's coordinate space
            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
            if (!dirtyRegion.isEmpty()) {
                // redraw the whole screen
                doComposeSurfaces(hw, Region(hw->bounds()));

                // and draw the dirty region
                glDisable(GL_TEXTURE_EXTERNAL_OES);
                glDisable(GL_TEXTURE_2D);
                glDisable(GL_BLEND);
                glColor4f(1, 0, 1, 1);
                const int32_t height = hw->getHeight();
                Region::const_iterator it = dirtyRegion.begin();
                Region::const_iterator const end = dirtyRegion.end();
                while (it != end) {
                    const Rect& r = *it++;
                    GLfloat vertices[][2] = {
                            { r.left,  height - r.top },
                            { r.left,  height - r.bottom },
                            { r.right, height - r.bottom },
                            { r.right, height - r.top }
                    };
                    glVertexPointer(2, GL_FLOAT, 0, vertices);
                    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
                }
                hw->compositionComplete();
                // FIXME
                if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) {
                    eglSwapBuffers(mEGLDisplay, hw->getEGLSurface());
                }
            }
        }
    }

    postFramebuffer();

    if (mDebugRegion > 1) {
        usleep(mDebugRegion * 1000);
    }
}

void SurfaceFlinger::preComposition()
{
    bool needExtraInvalidate = false;
    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
    const size_t count = currentLayers.size();
    for (size_t i=0 ; i<count ; i++) {
        if (currentLayers[i]->onPreComposition()) {
            needExtraInvalidate = true;
        }
    }
    if (needExtraInvalidate) {
        signalLayerUpdate();
    }
}

void SurfaceFlinger::postComposition()
{
    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
    const size_t count = currentLayers.size();
    for (size_t i=0 ; i<count ; i++) {
        currentLayers[i]->onPostComposition();
    }
}

void SurfaceFlinger::rebuildLayerStacks() {
    // rebuild the visible layer list per screen
    if (CC_UNLIKELY(mVisibleRegionsDirty)) {
    if (CC_UNLIKELY(mVisibleRegionsDirty)) {
        ATRACE_CALL();
        mVisibleRegionsDirty = false;
        mVisibleRegionsDirty = false;
        invalidateHwcGeometry();
        invalidateHwcGeometry();

        /*
         *  rebuild the visible layer list per screen
         */

        const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
        const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            const sp<DisplayDevice>& hw(mDisplays[dpy]);
            const sp<DisplayDevice>& hw(mDisplays[dpy]);
@@ -684,10 +765,13 @@ void SurfaceFlinger::handleMessageRefresh() {
            }
            }
            hw->setVisibleLayersSortedByZ(layersSortedByZ);
            hw->setVisibleLayersSortedByZ(layersSortedByZ);
            hw->undefinedRegion.set(hw->getBounds());
            hw->undefinedRegion.set(hw->getBounds());
            hw->undefinedRegion.subtractSelf(hw->getTransform().transform(opaqueRegion));
            hw->undefinedRegion.subtractSelf(
                    hw->getTransform().transform(opaqueRegion));
        }
    }
    }
}
}


void SurfaceFlinger::setUpHWComposer() {
    HWComposer& hwc(getHwComposer());
    HWComposer& hwc(getHwComposer());
    if (hwc.initCheck() == NO_ERROR) {
    if (hwc.initCheck() == NO_ERROR) {
        // build the h/w work list
        // build the h/w work list
@@ -695,7 +779,8 @@ void SurfaceFlinger::handleMessageRefresh() {
        mHwWorkListDirty = false;
        mHwWorkListDirty = false;
        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            sp<const DisplayDevice> hw(mDisplays[dpy]);
            sp<const DisplayDevice> hw(mDisplays[dpy]);
            const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
            const Vector< sp<LayerBase> >& currentLayers(
                    hw->getVisibleLayersSortedByZ());
            const size_t count = currentLayers.size();
            const size_t count = currentLayers.size();


            const int32_t id = hw->getDisplayId();
            const int32_t id = hw->getDisplayId();
@@ -723,32 +808,27 @@ void SurfaceFlinger::handleMessageRefresh() {
        status_t err = hwc.prepare();
        status_t err = hwc.prepare();
        ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
        ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
    }
    }
}


void SurfaceFlinger::doComposition() {
    ATRACE_CALL();
    const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
    const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
        const sp<DisplayDevice>& hw(mDisplays[dpy]);
        const sp<DisplayDevice>& hw(mDisplays[dpy]);

        if (hw->canDraw()) {
            // transform the dirty region into this screen's coordinate space
            // transform the dirty region into this screen's coordinate space
        const Transform& planeTransform(hw->getTransform());
            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
        Region dirtyRegion;
        if (repaintEverything) {
            dirtyRegion.set(hw->bounds());
        } else {
            dirtyRegion = planeTransform.transform(hw->dirtyRegion);
            dirtyRegion.andSelf(hw->bounds());
        }
        hw->dirtyRegion.clear();

            if (!dirtyRegion.isEmpty()) {
            if (!dirtyRegion.isEmpty()) {
            if (hw->canDraw()) {
                // repaint the framebuffer (if needed)
                // repaint the framebuffer (if needed)
                handleRepaint(hw, dirtyRegion);
                doDisplayComposition(hw, dirtyRegion);
            }
            }
            hw->dirtyRegion.clear();
            hw->flip(hw->swapRegion);
            hw->swapRegion.clear();
        }
        }
        // inform the h/w that we're done compositing
        // inform the h/w that we're done compositing
        hw->compositionComplete();
        hw->compositionComplete();
    }
    }

    postFramebuffer();
    postFramebuffer();
}
}


@@ -760,30 +840,13 @@ void SurfaceFlinger::postFramebuffer()
    mDebugInSwapBuffers = now;
    mDebugInSwapBuffers = now;


    HWComposer& hwc(getHwComposer());
    HWComposer& hwc(getHwComposer());

    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
        const sp<DisplayDevice>& hw(mDisplays[dpy]);
        if (hwc.initCheck() == NO_ERROR) {
            const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
            const size_t count = currentLayers.size();
            const int32_t id = hw->getDisplayId();
            HWComposer::LayerListIterator cur = hwc.begin(id);
            const HWComposer::LayerListIterator end = hwc.end(id);
            for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
                const sp<LayerBase>& layer(currentLayers[i]);
                layer->setAcquireFence(hw, *cur);
            }
        }
        hw->flip(hw->swapRegion);
        hw->swapRegion.clear();
    }

    if (hwc.initCheck() == NO_ERROR) {
    if (hwc.initCheck() == NO_ERROR) {
        // FIXME: eventually commit() won't take arguments
        // FIXME: eventually commit() won't take arguments
        // FIXME: EGL spec says:
        // FIXME: EGL spec says:
        //   "surface must be bound to the calling thread's current context,
        //   "surface must be bound to the calling thread's current context,
        //    for the current rendering API."
        //    for the current rendering API."
        DisplayDevice::makeCurrent(getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext);
        DisplayDevice::makeCurrent(
                getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext);
        hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface());
        hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface());
    }
    }


@@ -798,18 +861,7 @@ void SurfaceFlinger::postFramebuffer()
            for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
            for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
                currentLayers[i]->onLayerDisplayed(hw, &*cur);
                currentLayers[i]->onLayerDisplayed(hw, &*cur);
            }
            }
        }
        } else {

        // FIXME: we need to call eglSwapBuffers() on displays that have
        // GL composition and only on those.
        // however, currently hwc.commit() already does that for the main
        // display and never for the other ones
        if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) {
            // FIXME: EGL spec says:
            //   "surface must be bound to the calling thread's current context,
            //    for the current rendering API."
            DisplayDevice::makeCurrent(hw, mEGLContext);
            eglSwapBuffers(mEGLDisplay, hw->getEGLSurface());
            for (size_t i = 0; i < count; i++) {
            for (size_t i = 0; i < count; i++) {
                currentLayers[i]->onLayerDisplayed(hw, NULL);
                currentLayers[i]->onLayerDisplayed(hw, NULL);
            }
            }
@@ -944,7 +996,8 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
     * Perform our own transaction if needed
     * Perform our own transaction if needed
     */
     */


    if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
    const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
    if (currentLayers.size() > previousLayers.size()) {
        // layers have been added
        // layers have been added
        mVisibleRegionsDirty = true;
        mVisibleRegionsDirty = true;
    }
    }
@@ -954,7 +1007,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
    if (mLayersRemoved) {
    if (mLayersRemoved) {
        mLayersRemoved = false;
        mLayersRemoved = false;
        mVisibleRegionsDirty = true;
        mVisibleRegionsDirty = true;
        const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
        const size_t count = previousLayers.size();
        const size_t count = previousLayers.size();
        for (size_t i=0 ; i<count ; i++) {
        for (size_t i=0 ; i<count ; i++) {
            const sp<LayerBase>& layer(previousLayers[i]);
            const sp<LayerBase>& layer(previousLayers[i]);
@@ -1130,16 +1182,13 @@ void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,


void SurfaceFlinger::handlePageFlip()
void SurfaceFlinger::handlePageFlip()
{
{
    ATRACE_CALL();
    Region dirtyRegion;
    Region dirtyRegion;


    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);

    bool visibleRegions = false;
    bool visibleRegions = false;
    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
    const size_t count = currentLayers.size();
    const size_t count = currentLayers.size();
    sp<LayerBase> const* layers = currentLayers.array();
    for (size_t i=0 ; i<count ; i++) {
    for (size_t i=0 ; i<count ; i++) {
        const sp<LayerBase>& layer(layers[i]);
        const sp<LayerBase>& layer(currentLayers[i]);
        const Region dirty(layer->latchBuffer(visibleRegions));
        const Region dirty(layer->latchBuffer(visibleRegions));
        Layer::State s(layer->drawingState());
        Layer::State s(layer->drawingState());
        invalidateLayerStack(s.layerStack, dirty);
        invalidateLayerStack(s.layerStack, dirty);
@@ -1153,36 +1202,15 @@ void SurfaceFlinger::invalidateHwcGeometry()
    mHwWorkListDirty = true;
    mHwWorkListDirty = true;
}
}


void SurfaceFlinger::handleRefresh()
{
    bool needInvalidate = false;
    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
    const size_t count = currentLayers.size();
    for (size_t i=0 ; i<count ; i++) {
        const sp<LayerBase>& layer(currentLayers[i]);
        if (layer->onPreComposition()) {
            needInvalidate = true;
        }
    }
    if (needInvalidate) {
        signalLayerUpdate();
    }
}


void SurfaceFlinger::handleRepaint(const sp<const DisplayDevice>& hw,
void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
        const Region& inDirtyRegion)
        const Region& inDirtyRegion)
{
{
    ATRACE_CALL();

    Region dirtyRegion(inDirtyRegion);
    Region dirtyRegion(inDirtyRegion);


    // compute the invalid region
    // compute the invalid region
    hw->swapRegion.orSelf(dirtyRegion);
    hw->swapRegion.orSelf(dirtyRegion);


    if (CC_UNLIKELY(mDebugRegion)) {
        debugFlashRegions(hw, dirtyRegion);
    }

    uint32_t flags = hw->getFlags();
    uint32_t flags = hw->getFlags();
    if (flags & DisplayDevice::SWAP_RECTANGLE) {
    if (flags & DisplayDevice::SWAP_RECTANGLE) {
        // we can redraw only what's dirty, but since SWAP_RECTANGLE only
        // we can redraw only what's dirty, but since SWAP_RECTANGLE only
@@ -1203,19 +1231,24 @@ void SurfaceFlinger::handleRepaint(const sp<const DisplayDevice>& hw,
        }
        }
    }
    }


    composeSurfaces(hw, dirtyRegion);
    doComposeSurfaces(hw, dirtyRegion);


    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
    // FIXME: we need to call eglSwapBuffers() on displays that have
    const size_t count = currentLayers.size();
    // GL composition and only on those.
    for (size_t i=0 ; i<count ; i++) {
    // however, currently hwc.commit() already does that for the main
        currentLayers[i]->onPostComposition();
    // display and never for the other ones
    if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) {
        // FIXME: EGL spec says:
        //   "surface must be bound to the calling thread's current context,
        //    for the current rendering API."
        eglSwapBuffers(mEGLDisplay, hw->getEGLSurface());
    }
    }


    // update the swap region and clear the dirty region
    // update the swap region and clear the dirty region
    hw->swapRegion.orSelf(dirtyRegion);
    hw->swapRegion.orSelf(dirtyRegion);
}
}


void SurfaceFlinger::composeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
{
{
    HWComposer& hwc(getHwComposer());
    HWComposer& hwc(getHwComposer());
    int32_t id = hw->getDisplayId();
    int32_t id = hw->getDisplayId();
@@ -1259,72 +1292,30 @@ void SurfaceFlinger::composeSurfaces(const sp<const DisplayDevice>& hw, const Re
        for (size_t i=0 ; i<count ; ++i) {
        for (size_t i=0 ; i<count ; ++i) {
            const sp<LayerBase>& layer(layers[i]);
            const sp<LayerBase>& layer(layers[i]);
            const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
            const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
            if (cur != end) {
                // we're using h/w composer
                if (!clip.isEmpty()) {
                if (!clip.isEmpty()) {
                if (cur != end && cur->getCompositionType() == HWC_OVERLAY) {
                    if (cur->getCompositionType() == HWC_OVERLAY) {
                        if (i && (cur->getHints() & HWC_HINT_CLEAR_FB)
                        if (i && (cur->getHints() & HWC_HINT_CLEAR_FB)
                                && layer->isOpaque()) {
                                && layer->isOpaque()) {
                            // never clear the very first layer since we're
                            // never clear the very first layer since we're
                            // guaranteed the FB is already cleared
                            // guaranteed the FB is already cleared
                            layer->clearWithOpenGL(hw, clip);
                            layer->clearWithOpenGL(hw, clip);
                        }
                        }
                    ++cur;
                    } else {
                    continue;
                }
                // render the layer
                        layer->draw(hw, clip);
                        layer->draw(hw, clip);
                    }
                    }
            if (cur != end) {
                    layer->setAcquireFence(hw, *cur);
                ++cur;
            }
        }
    }
                }
                }

                ++cur;
void SurfaceFlinger::debugFlashRegions(const sp<const DisplayDevice>& hw,
            } else {
        const Region& dirtyRegion)
                // we're not using h/w composer
{
                if (!clip.isEmpty()) {
    const uint32_t flags = hw->getFlags();
                    layer->draw(hw, clip);
    const int32_t height = hw->getHeight();
    if (hw->swapRegion.isEmpty()) {
        return;
                }
                }

    if (!(flags & DisplayDevice::SWAP_RECTANGLE)) {
        const Region repaint((flags & DisplayDevice::PARTIAL_UPDATES) ?
                dirtyRegion.bounds() : hw->bounds());
        composeSurfaces(hw, repaint);
            }
            }

    glDisable(GL_TEXTURE_EXTERNAL_OES);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);

    static int toggle = 0;
    toggle = 1 - toggle;
    if (toggle) {
        glColor4f(1, 0, 1, 1);
    } else {
        glColor4f(1, 1, 0, 1);
        }
        }

    Region::const_iterator it = dirtyRegion.begin();
    Region::const_iterator const end = dirtyRegion.end();
    while (it != end) {
        const Rect& r = *it++;
        GLfloat vertices[][2] = {
                { r.left,  height - r.top },
                { r.left,  height - r.bottom },
                { r.right, height - r.bottom },
                { r.right, height - r.top }
        };
        glVertexPointer(2, GL_FLOAT, 0, vertices);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    }
    }

    hw->flip(hw->swapRegion);

    if (mDebugRegion > 1)
        usleep(mDebugRegion * 1000);
}
}


void SurfaceFlinger::drawWormhole(const Region& region) const
void SurfaceFlinger::drawWormhole(const Region& region) const
+12 −5
Original line number Original line Diff line number Diff line
@@ -248,9 +248,6 @@ private:
     */
     */
    void handlePageFlip();
    void handlePageFlip();


    void handleRefresh();
    void handleRepaint(const sp<const DisplayDevice>& hw, const Region& dirtyRegion);

    /* ------------------------------------------------------------------------
    /* ------------------------------------------------------------------------
     * Transactions
     * Transactions
     */
     */
@@ -348,8 +345,19 @@ private:
    void computeVisibleRegions(const LayerVector& currentLayers,
    void computeVisibleRegions(const LayerVector& currentLayers,
            uint32_t layerStack,
            uint32_t layerStack,
            Region& dirtyRegion, Region& opaqueRegion);
            Region& dirtyRegion, Region& opaqueRegion);

    void preComposition();
    void postComposition();
    void rebuildLayerStacks();
    void setUpHWComposer();
    void doComposition();
    void doDebugFlashRegions();
    void doDisplayComposition(const sp<const DisplayDevice>& hw,
            const Region& dirtyRegion);
    void doComposeSurfaces(const sp<const DisplayDevice>& hw,
            const Region& dirty);

    void postFramebuffer();
    void postFramebuffer();
    void composeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty);
    void drawWormhole(const Region& region) const;
    void drawWormhole(const Region& region) const;
    GLuint getProtectedTexName() const {
    GLuint getProtectedTexName() const {
        return mProtectedTexName;
        return mProtectedTexName;
@@ -358,7 +366,6 @@ private:
    /* ------------------------------------------------------------------------
    /* ------------------------------------------------------------------------
     * Debugging & dumpsys
     * Debugging & dumpsys
     */
     */
    void debugFlashRegions(const sp<const DisplayDevice>& hw, const Region& dirtyReg);
    void listLayersLocked(const Vector<String16>& args, size_t& index,
    void listLayersLocked(const Vector<String16>& args, size_t& index,
        String8& result, char* buffer, size_t SIZE) const;
        String8& result, char* buffer, size_t SIZE) const;
    void dumpStatsLocked(const Vector<String16>& args, size_t& index,
    void dumpStatsLocked(const Vector<String16>& args, size_t& index,