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

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

Surfaces are now destroyed properly in SurfaceFlinger.

First, the window manager tells us when a surface is no longer needed. At this point, several things happen:
- the surface is removed from the active/visible list
- it is added to a purgatory list, where it waits for all clients to release their reference
- it destroys all data/state that can be spared

Later, when all clients are done, the remains of the Surface are disposed off: it is removed from the purgatory and destroyed.
In particular its gralloc buffers are destroyed at that point (when we're sure nobody is using them anymore).
parent 6ead5d9f
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -60,16 +60,24 @@ Layer::Layer(SurfaceFlinger* flinger, DisplayID display, Client* c, int32_t i)
}
}


Layer::~Layer()
Layer::~Layer()
{
    destroy();
    // the actual buffers will be destroyed here
}

void Layer::destroy()
{
{
    for (int i=0 ; i<NUM_BUFFERS ; i++) {
    for (int i=0 ; i<NUM_BUFFERS ; i++) {
        if (mTextures[i].name != -1U) {
        if (mTextures[i].name != -1U) {
            // FIXME: this was originally to work-around a bug in the
            // FIXME: this was originally to work-around a bug in the
            // adreno driver. this should be fixed now.
            // adreno driver. this should be fixed now.
            deletedTextures.add(mTextures[i].name);
            deletedTextures.add(mTextures[i].name);
            mTextures[i].name = -1U;
        }
        }
        if (mTextures[i].image != EGL_NO_IMAGE_KHR) {
        if (mTextures[i].image != EGL_NO_IMAGE_KHR) {
            EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
            EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
            eglDestroyImageKHR(dpy, mTextures[i].image);
            eglDestroyImageKHR(dpy, mTextures[i].image);
            mTextures[i].image = EGL_NO_IMAGE_KHR;
        }
        }
    }
    }
}
}
@@ -89,7 +97,9 @@ sp<LayerBaseClient::Surface> Layer::createSurface() const


status_t Layer::ditch()
status_t Layer::ditch()
{
{
    // the layer is not on screen anymore. free as much resources as possible
    mSurface.clear();
    mSurface.clear();
    destroy();
    return NO_ERROR;
    return NO_ERROR;
}
}


+2 −1
Original line number Original line Diff line number Diff line
@@ -104,6 +104,7 @@ private:
    status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what);
    status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what);
    Region post(uint32_t* oldState, bool& recomputeVisibleRegions);
    Region post(uint32_t* oldState, bool& recomputeVisibleRegions);
    sp<SurfaceBuffer> peekBuffer();
    sp<SurfaceBuffer> peekBuffer();
    void destroy();


    
    
    class SurfaceLayer : public LayerBaseClient::Surface
    class SurfaceLayer : public LayerBaseClient::Surface
+2 −1
Original line number Original line Diff line number Diff line
@@ -207,7 +207,8 @@ public:
     */
     */
    virtual bool isSecure() const       { return false; }
    virtual bool isSecure() const       { return false; }


    /** signal this layer that it's not needed any longer */
    /** signal this layer that it's not needed any longer. called from the 
     * main thread */
    virtual status_t ditch() { return NO_ERROR; }
    virtual status_t ditch() { return NO_ERROR; }


    
    
+3 −2
Original line number Original line Diff line number Diff line
@@ -148,7 +148,8 @@ public:
    uint32_t    what;
    uint32_t    what;
    int32_t     arg0;    
    int32_t     arg0;    


    MessageBase(uint32_t what=0, int32_t arg0=0)
    MessageBase() : when(0), what(0), arg0(0) { }
    MessageBase(uint32_t what, int32_t arg0=0)
        : when(0), what(what), arg0(arg0) { }
        : when(0), what(what), arg0(arg0) { }
    
    
    // return true if message has a handler
    // return true if message has a handler
+34 −43
Original line number Original line Diff line number Diff line
@@ -639,16 +639,26 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
            mFreezeDisplay = mCurrentState.freezeDisplay;
            mFreezeDisplay = mCurrentState.freezeDisplay;
        }
        }


        if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
            // layers have been added
            mVisibleRegionsDirty = true;
        }

        // some layers might have been removed, so
        // some layers might have been removed, so
        // we need to update the regions they're exposing.
        // we need to update the regions they're exposing.
        if (mLayersRemoved) {
        if (mLayersRemoved) {
            mVisibleRegionsDirty = true;
            mVisibleRegionsDirty = true;
            const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
            const ssize_t count = previousLayers.size();
            for (ssize_t i=0 ; i<count ; i++) {
                const sp<LayerBase>& layer(previousLayers[i]);
                if (currentLayers.indexOf( layer ) < 0) {
                    // this layer is not visible anymore
                    // FIXME: would be better to call without the lock held
                    //LOGD("ditching layer %p", layer.get());
                    layer->ditch();
                }
            }
            }

        const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
        if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
            // layers have been added
            mVisibleRegionsDirty = true;
        }
        }


        // get rid of all resources we don't need anymore
        // get rid of all resources we don't need anymore
@@ -1275,28 +1285,18 @@ status_t SurfaceFlinger::removeSurface(SurfaceID index)
    /*
    /*
     * called by the window manager, when a surface should be marked for
     * called by the window manager, when a surface should be marked for
     * destruction.
     * destruction.
     * 
     * The surface is removed from the current and drawing lists, but placed
     * in the purgatory queue, so it's not destroyed right-away (we need
     * to wait for all client's references to go away first).
     */
     */


    // TODO: here we should make the surface disappear from the screen
    // and mark it for removal. however, we can't free anything until all
    // client are done. All operations on this surface should return errors.
    
    status_t err = NAME_NOT_FOUND;
    sp<LayerBaseClient> layer;
    
    { // scope for the lock
    Mutex::Autolock _l(mStateLock);
    Mutex::Autolock _l(mStateLock);
        layer = getLayerUser_l(index);
    sp<LayerBaseClient> layer = getLayerUser_l(index);
        err = purgatorizeLayer_l(layer);
    status_t err = purgatorizeLayer_l(layer);
    if (err == NO_ERROR) {
    if (err == NO_ERROR) {
        setTransactionFlags(eTransactionNeeded);
        setTransactionFlags(eTransactionNeeded);
    }
    }
    }

    if (layer != 0) {
        // do this outside of mStateLock
        layer->ditch();
    }
    return err;
    return err;
}
}


@@ -1304,35 +1304,26 @@ status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
{
{
    /*
    /*
     * called by ~ISurface() when all references are gone
     * called by ~ISurface() when all references are gone
     */
     * 

     * the surface must be removed from purgatory from the main thread
    /* FIXME: 
     * since its dtor must run from there (b/c of OpenGL ES).
     * - ideally we want to release as much GL state as possible after
     * purgatorizeLayer_l() has been called and the surface is not in any
     * active list.
     */
     */
    
    
    class MessageDestroySurface : public MessageBase {
    class MessageDestroySurface : public MessageBase {
        sp<SurfaceFlinger> flinger;
        SurfaceFlinger* flinger;
        sp<LayerBaseClient> layer;
        sp<LayerBaseClient> layer;
    public:
    public:
        MessageDestroySurface(const sp<SurfaceFlinger>& flinger,
        MessageDestroySurface(
                const sp<LayerBaseClient>& layer)
                SurfaceFlinger* flinger, const sp<LayerBaseClient>& layer)
            : MessageBase(0), flinger(flinger), layer(layer) {
            : flinger(flinger), layer(layer) { }
        }
        ~MessageDestroySurface() {
            //LOGD("~MessageDestroySurface, layer=%p", layer.get());
        }
        virtual bool handler() {
        virtual bool handler() {
            //LOGD("MessageDestroySurface handler, layer=%p", layer.get());
            Mutex::Autolock _l(flinger->mStateLock);
            Mutex::Autolock _l(flinger->mStateLock);
            flinger->mLayerPurgatory.remove(layer);
            ssize_t idx = flinger->mLayerPurgatory.remove(layer);
            LOGE_IF(idx<0, "layer=%p is not in the purgatory list", layer.get());
            return true;
            return true;
        }
        }
    };
    };

    mEventQueue.postMessage( new MessageDestroySurface(this, layer) );
    mEventQueue.postMessage( new MessageDestroySurface(this, layer) );
    
    return NO_ERROR;
    return NO_ERROR;
}
}