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

Commit 345c3099 authored by John Reck's avatar John Reck Committed by Android (Google) Code Review
Browse files

Merge "Fix layers lifecycle issues"

parents 85702567 dcba6725
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -13625,9 +13625,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * @hide
     */
    protected void destroyHardwareResources() {
        // Intentionally empty. RenderNode's lifecycle is now fully managed
        // by the hardware renderer.
        // However some subclasses (eg, WebView, TextureView) still need this signal
        // Although the Layer will be destroyed by RenderNode, we want to release
        // the staging display list, which is also a signal to RenderNode that it's
        // safe to free its copy of the display list as it knows that we will
        // push an updated DisplayList if we try to draw again
        resetDisplayList();
    }
    /**
+54 −26
Original line number Diff line number Diff line
@@ -63,11 +63,12 @@ RenderNode::RenderNode()
        , mDisplayListData(0)
        , mStagingDisplayListData(0)
        , mAnimatorManager(*this)
        , mLayer(0) {
        , mLayer(0)
        , mParentCount(0) {
}

RenderNode::~RenderNode() {
    delete mDisplayListData;
    deleteDisplayListData();
    delete mStagingDisplayListData;
    LayerRenderer::destroyLayerDeferred(mLayer);
}
@@ -196,27 +197,12 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
void RenderNode::prepareTreeImpl(TreeInfo& info) {
    info.damageAccumulator->pushTransform(this);

    switch (info.mode) {
    case TreeInfo::MODE_FULL:
        pushStagingPropertiesChanges(info);
        mAnimatorManager.animate(info);
        break;
    case TreeInfo::MODE_MAYBE_DETACHING:
    if (info.mode == TreeInfo::MODE_FULL) {
        pushStagingPropertiesChanges(info);
        break;
    case TreeInfo::MODE_RT_ONLY:
        mAnimatorManager.animate(info);
        break;
    case TreeInfo::MODE_DESTROY_RESOURCES:
        // This will also release the hardware layer if we have one as
        // isRenderable() will return false, thus causing pushLayerUpdate
        // to recycle the hardware layer
        setStagingDisplayList(NULL);
        break;
    }

    mAnimatorManager.animate(info);
    prepareLayer(info);
    if (info.mode == TreeInfo::MODE_FULL || info.mode == TreeInfo::MODE_DESTROY_RESOURCES) {
    if (info.mode == TreeInfo::MODE_FULL) {
        pushStagingDisplayListChanges(info);
    }
    prepareSubTree(info, mDisplayListData);
@@ -258,17 +244,30 @@ void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) {
void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
    if (mNeedsDisplayListDataSync) {
        mNeedsDisplayListDataSync = false;
        // Do a push pass on the old tree to handle freeing DisplayListData
        // that are no longer used
        TreeInfo oldTreeInfo(TreeInfo::MODE_MAYBE_DETACHING, info);
        prepareSubTree(oldTreeInfo, mDisplayListData);
        delete mDisplayListData;
        // Make sure we inc first so that we don't fluctuate between 0 and 1,
        // which would thrash the layer cache
        if (mStagingDisplayListData) {
            for (size_t i = 0; i < mStagingDisplayListData->children().size(); i++) {
                mStagingDisplayListData->children()[i]->mRenderNode->incParentRefCount();
            }
        }
        deleteDisplayListData();
        mDisplayListData = mStagingDisplayListData;
        mStagingDisplayListData = 0;
        mStagingDisplayListData = NULL;
        damageSelf(info);
    }
}

void RenderNode::deleteDisplayListData() {
    if (mDisplayListData) {
        for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
            mDisplayListData->children()[i]->mRenderNode->decParentRefCount();
        }
    }
    delete mDisplayListData;
    mDisplayListData = NULL;
}

void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
    if (subtree) {
        TextureCache& cache = Caches::getInstance().textureCache;
@@ -291,6 +290,35 @@ void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
    }
}

void RenderNode::destroyHardwareResources() {
    if (mLayer) {
        LayerRenderer::destroyLayer(mLayer);
        mLayer = NULL;
    }
    if (mDisplayListData) {
        for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
            mDisplayListData->children()[i]->mRenderNode->destroyHardwareResources();
        }
        if (mNeedsDisplayListDataSync) {
            // Next prepare tree we are going to push a new display list, so we can
            // drop our current one now
            deleteDisplayListData();
        }
    }
}

void RenderNode::decParentRefCount() {
    LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
    mParentCount--;
    if (!mParentCount) {
        // If a child of ours is being attached to our parent then this will incorrectly
        // destroy its hardware resources. However, this situation is highly unlikely
        // and the failure is "just" that the layer is re-created, so this should
        // be safe enough
        destroyHardwareResources();
    }
}

/*
 * For property operations, we pass a savecount of 0, since the operations aren't part of the
 * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
+14 −0
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ public:
    }

    ANDROID_API virtual void prepareTree(TreeInfo& info);
    void destroyHardwareResources();

    // UI thread only!
    ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
@@ -248,6 +249,10 @@ private:
    void applyLayerPropertiesToLayer(TreeInfo& info);
    void prepareLayer(TreeInfo& info);
    void pushLayerUpdate(TreeInfo& info);
    void deleteDisplayListData();

    void incParentRefCount() { mParentCount++; }
    void decParentRefCount();

    String8 mName;

@@ -256,6 +261,7 @@ private:
    RenderProperties mStagingProperties;

    bool mNeedsDisplayListDataSync;
    // WARNING: Do not delete this directly, you must go through deleteDisplayListData()!
    DisplayListData* mDisplayListData;
    DisplayListData* mStagingDisplayListData;

@@ -272,6 +278,14 @@ private:

    // for projection surfaces, contains a list of all children items
    Vector<DrawRenderNodeOp*> mProjectedNodes;

    // How many references our parent(s) have to us. Typically this should alternate
    // between 2 and 1 (when a staging push happens we inc first then dec)
    // When this hits 0 we are no longer in the tree, so any hardware resources
    // (specifically Layers) should be released.
    // This is *NOT* thread-safe, and should therefore only be tracking
    // mDisplayListData, not mStagingDisplayListData.
    uint32_t mParentCount;
}; // class RenderNode

} /* namespace uirenderer */
+0 −9
Original line number Diff line number Diff line
@@ -58,15 +58,6 @@ public:
        // animators, but potentially things like SurfaceTexture updates
        // could be handled by this as well if there are no listeners
        MODE_RT_ONLY,
        // The subtree is being detached. Maybe. If the RenderNode is present
        // in both the old and new display list's children then it will get a
        // MODE_MAYBE_DETACHING followed shortly by a MODE_FULL.
        // Push any pending display list changes in case it is detached,
        // but don't evaluate animators and such as if it isn't detached as a
        // MODE_FULL will follow shortly.
        MODE_MAYBE_DETACHING,
        // Destroy all hardware resources, including DisplayListData, in the tree.
        MODE_DESTROY_RESOURCES,
    };

    explicit TreeInfo(TraversalMode mode, RenderState& renderState)
+1 −2
Original line number Diff line number Diff line
@@ -250,8 +250,7 @@ void CanvasContext::destroyHardwareResources() {
    stopDrawing();
    if (mEglManager.hasEglContext()) {
        requireGlContext();
        TreeInfo info(TreeInfo::MODE_DESTROY_RESOURCES, mRenderThread.renderState());
        mRootRenderNode->prepareTree(info);
        mRootRenderNode->destroyHardwareResources();
        Caches::getInstance().flush(Caches::kFlushMode_Layers);
    }
}