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

Commit b265e2ca authored by Chris Craik's avatar Chris Craik
Browse files

Support shadows on the root RenderNode

bug:13211941

Cleans up some of the RenderNode method naming

Also removes unnecessary clip/save/restores, clipping shadows
predictably, as drawn by the parent, before drawing (and clipping,
etc.) the shadow casting child.

Change-Id: I795115e1fb869bbbdd7be43e279b97490fecc7e0
parent 08c96b55
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -1499,13 +1499,13 @@ public:
    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
            bool useQuickReject) {
            bool useQuickReject) {
        if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
        if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
            mDisplayList->defer(deferStruct, level + 1);
            mDisplayList->deferNodeInParent(deferStruct, level + 1);
        }
        }
    }
    }
    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
            bool useQuickReject) {
            bool useQuickReject) {
        if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
        if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
            mDisplayList->replay(replayStruct, level + 1);
            mDisplayList->replayNodeInParent(replayStruct, level + 1);
        }
        }
    }
    }


+1 −1
Original line number Original line Diff line number Diff line
@@ -209,7 +209,7 @@ void Layer::defer() {
            dirtyRect.right, dirtyRect.bottom, !isBlend());
            dirtyRect.right, dirtyRect.bottom, !isBlend());


    displayList->computeOrdering();
    displayList->computeOrdering();
    displayList->defer(deferredState, 0);
    displayList->deferNodeTree(deferredState);


    deferredUpdateScheduled = false;
    deferredUpdateScheduled = false;
}
}
+2 −2
Original line number Original line Diff line number Diff line
@@ -1924,14 +1924,14 @@ status_t OpenGLRenderer::drawDisplayList(RenderNode* displayList, Rect& dirty,
        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
            status = startFrame();
            status = startFrame();
            ReplayStateStruct replayStruct(*this, dirty, replayFlags);
            ReplayStateStruct replayStruct(*this, dirty, replayFlags);
            displayList->replay(replayStruct, 0);
            displayList->replayNodeTree(replayStruct);
            return status | replayStruct.mDrawGlStatus;
            return status | replayStruct.mDrawGlStatus;
        }
        }


        bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs!
        bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs!
        DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw);
        DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw);
        DeferStateStruct deferStruct(deferredList, *this, replayFlags);
        DeferStateStruct deferStruct(deferredList, *this, replayFlags);
        displayList->defer(deferStruct, 0);
        displayList->deferNodeTree(deferStruct);


        flushLayers();
        flushLayers();
        status = startFrame();
        status = startFrame();
+77 −65
Original line number Original line Diff line number Diff line
@@ -132,10 +132,9 @@ bool RenderNode::hasFunctors() {
#define PROPERTY_SAVECOUNT 0
#define PROPERTY_SAVECOUNT 0


template <class T>
template <class T>
void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler,
void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) {
        const int level) {
#if DEBUG_DISPLAY_LIST
#if DEBUG_DISPLAY_LIST
    properties().debugOutputProperties(level);
    properties().debugOutputProperties(handler.level() + 1);
#endif
#endif
    if (properties().getLeft() != 0 || properties().getTop() != 0) {
    if (properties().getLeft() != 0 || properties().getTop() != 0) {
        renderer.translate(properties().getLeft(), properties().getTop());
        renderer.translate(properties().getLeft(), properties().getTop());
@@ -302,7 +301,6 @@ void RenderNode::computeOrderingImpl(
            child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
            child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
        }
        }
    }
    }

}
}


class DeferOperationHandler {
class DeferOperationHandler {
@@ -313,15 +311,25 @@ public:
        operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
        operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
    }
    }
    inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
    inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
    inline void startMark(const char* name) {} // do nothing
    inline void endMark() {}
    inline int level() { return mLevel; }
    inline int replayFlags() { return mDeferStruct.mReplayFlags; }


private:
private:
    DeferStateStruct& mDeferStruct;
    DeferStateStruct& mDeferStruct;
    const int mLevel;
    const int mLevel;
};
};


void RenderNode::defer(DeferStateStruct& deferStruct, const int level) {
void RenderNode::deferNodeTree(DeferStateStruct& deferStruct) {
    DeferOperationHandler handler(deferStruct, 0);
    if (properties().getTranslationZ() > 0.0f) issueDrawShadowOperation(Matrix4::identity(), handler);
    issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
}

void RenderNode::deferNodeInParent(DeferStateStruct& deferStruct, const int level) {
    DeferOperationHandler handler(deferStruct, level);
    DeferOperationHandler handler(deferStruct, level);
    iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
    issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
}
}


class ReplayOperationHandler {
class ReplayOperationHandler {
@@ -335,21 +343,31 @@ public:
        operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
        operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
    }
    }
    inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
    inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
    inline void startMark(const char* name) {
        mReplayStruct.mRenderer.startMark(name);
    }
    inline void endMark() {
        mReplayStruct.mRenderer.endMark();
        DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
                mReplayStruct.mDrawGlStatus);
    }
    inline int level() { return mLevel; }
    inline int replayFlags() { return mReplayStruct.mReplayFlags; }


private:
private:
    ReplayStateStruct& mReplayStruct;
    ReplayStateStruct& mReplayStruct;
    const int mLevel;
    const int mLevel;
};
};


void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) {
void RenderNode::replayNodeTree(ReplayStateStruct& replayStruct) {
    ReplayOperationHandler handler(replayStruct, level);
    ReplayOperationHandler handler(replayStruct, 0);

    if (properties().getTranslationZ() > 0.0f) issueDrawShadowOperation(Matrix4::identity(), handler);
    replayStruct.mRenderer.startMark(mName.string());
    issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
    iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
}
    replayStruct.mRenderer.endMark();


    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
void RenderNode::replayNodeInParent(ReplayStateStruct& replayStruct, const int level) {
            replayStruct.mDrawGlStatus);
    ReplayOperationHandler handler(replayStruct, level);
    issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
}
}


void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) {
void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) {
@@ -373,10 +391,42 @@ void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslat
    std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end());
    std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end());
}
}


template <class T>
void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler) {
    if (properties().getAlpha() <= 0.0f) return;

    mat4 shadowMatrixXY(transformFromParent);
    applyViewPropertyTransforms(shadowMatrixXY);

    // Z matrix needs actual 3d transformation, so mapped z values will be correct
    mat4 shadowMatrixZ(transformFromParent);
    applyViewPropertyTransforms(shadowMatrixZ, true);

    const SkPath* outlinePath = properties().getOutline().getPath();
    const RevealClip& revealClip = properties().getRevealClip();
    const SkPath* revealClipPath = revealClip.hasConvexClip()
            ?  revealClip.getPath() : NULL; // only pass the reveal clip's path if it's convex

    /**
     * The drawing area of the caster is always the same as the its perimeter (which
     * the shadow system uses) *except* in the inverse clip case. Inform the shadow
     * system that the caster's drawing area (as opposed to its perimeter) has been
     * clipped, so that it knows the caster can't be opaque.
     */
    bool casterUnclipped = !revealClip.willClip() || revealClip.hasConvexClip();

    DisplayListOp* shadowOp  = new (handler.allocator()) DrawShadowOp(
            shadowMatrixXY, shadowMatrixZ,
            properties().getAlpha(), casterUnclipped,
            properties().getWidth(), properties().getHeight(),
            outlinePath, revealClipPath);
    handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
}

#define SHADOW_DELTA 0.1f
#define SHADOW_DELTA 0.1f


template <class T>
template <class T>
void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
void RenderNode::issueOperationsOf3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
        ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) {
        ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) {
    const int size = zTranslatedNodes.size();
    const int size = zTranslatedNodes.size();
    if (size == 0
    if (size == 0
@@ -386,12 +436,6 @@ void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTransl
        return;
        return;
    }
    }


    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
    LinearAllocator& alloc = handler.allocator();
    ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().getWidth(), properties().getHeight(),
            SkRegion::kIntersect_Op); // clip to 3d root bounds
    handler(clipOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());

    /**
    /**
     * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
     * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
     * with very similar Z heights to draw together.
     * with very similar Z heights to draw together.
@@ -419,35 +463,7 @@ void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTransl
            // attempt to render the shadow if the caster about to be drawn is its caster,
            // attempt to render the shadow if the caster about to be drawn is its caster,
            // OR if its caster's Z value is similar to the previous potential caster
            // OR if its caster's Z value is similar to the previous potential caster
            if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {
            if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {

                caster->issueDrawShadowOperation(casterOp->mTransformFromParent, handler);
                if (caster->properties().getAlpha() > 0.0f) {
                    mat4 shadowMatrixXY(casterOp->mTransformFromParent);
                    caster->applyViewPropertyTransforms(shadowMatrixXY);

                    // Z matrix needs actual 3d transformation, so mapped z values will be correct
                    mat4 shadowMatrixZ(casterOp->mTransformFromParent);
                    caster->applyViewPropertyTransforms(shadowMatrixZ, true);

                    const SkPath* outlinePath = caster->properties().getOutline().getPath();
                    const RevealClip& revealClip = caster->properties().getRevealClip();
                    const SkPath* revealClipPath = revealClip.hasConvexClip()
                            ?  revealClip.getPath() : NULL; // only pass the reveal clip's path if it's convex

                    /**
                     * The drawing area of the caster is always the same as the its perimeter (which
                     * the shadow system uses) *except* in the inverse clip case. Inform the shadow
                     * system that the caster's drawing area (as opposed to its perimeter) has been
                     * clipped, so that it knows the caster can't be opaque.
                     */
                    bool casterUnclipped = !revealClip.willClip() || revealClip.hasConvexClip();

                    DisplayListOp* shadowOp  = new (alloc) DrawShadowOp(
                            shadowMatrixXY, shadowMatrixZ,
                            caster->properties().getAlpha(), casterUnclipped,
                            caster->properties().getWidth(), caster->properties().getHeight(),
                            outlinePath, revealClipPath);
                    handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
                }


                lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
                lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
                shadowIndex++;
                shadowIndex++;
@@ -470,17 +486,10 @@ void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTransl
        renderer.restoreToCount(restoreTo);
        renderer.restoreToCount(restoreTo);
        drawIndex++;
        drawIndex++;
    }
    }
    handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().getClipToBounds());
}
}


template <class T>
template <class T>
void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) {
    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
    LinearAllocator& alloc = handler.allocator();
    ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().getWidth(), properties().getHeight(),
            SkRegion::kReplace_Op); // clip to projection surface root bounds
    handler(clipOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());

    for (size_t i = 0; i < mProjectedNodes.size(); i++) {
    for (size_t i = 0; i < mProjectedNodes.size(); i++) {
        DrawDisplayListOp* childOp = mProjectedNodes[i];
        DrawDisplayListOp* childOp = mProjectedNodes[i];


@@ -492,7 +501,6 @@ void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler,
        childOp->mSkipInOrderDraw = true;
        childOp->mSkipInOrderDraw = true;
        renderer.restoreToCount(restoreTo);
        renderer.restoreToCount(restoreTo);
    }
    }
    handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().getClipToBounds());
}
}


/**
/**
@@ -505,7 +513,8 @@ void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler,
 * defer vs replay logic, per operation
 * defer vs replay logic, per operation
 */
 */
template <class T>
template <class T>
void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
    const int level = handler.level();
    if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
    if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
        ALOGW("Error: %s is drawing after destruction", mName.string());
        ALOGW("Error: %s is drawing after destruction", mName.string());
        CRASH();
        CRASH();
@@ -515,6 +524,8 @@ void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level)
        return;
        return;
    }
    }


    handler.startMark(mName.string());

#if DEBUG_DISPLAY_LIST
#if DEBUG_DISPLAY_LIST
    Rect* clipRect = renderer.getClipRect();
    Rect* clipRect = renderer.getClipRect();
    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
@@ -530,7 +541,7 @@ void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level)
    DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
    DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);


    setViewProperties<T>(renderer, handler, level + 1);
    setViewProperties<T>(renderer, handler);


    bool quickRejected = properties().getClipToBounds()
    bool quickRejected = properties().getClipToBounds()
            && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
            && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
@@ -539,7 +550,7 @@ void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level)
        buildZSortedChildList(zTranslatedNodes);
        buildZSortedChildList(zTranslatedNodes);


        // for 3d root, draw children with negative z values
        // for 3d root, draw children with negative z values
        iterate3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
        issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);


        DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
        DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
        const int saveCountOffset = renderer.getSaveCount() - 1;
        const int saveCountOffset = renderer.getSaveCount() - 1;
@@ -550,23 +561,24 @@ void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level)
#if DEBUG_DISPLAY_LIST
#if DEBUG_DISPLAY_LIST
            op->output(level + 1);
            op->output(level + 1);
#endif
#endif

            logBuffer.writeCommand(level, op->name());
            logBuffer.writeCommand(level, op->name());
            handler(op, saveCountOffset, properties().getClipToBounds());
            handler(op, saveCountOffset, properties().getClipToBounds());


            if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
            if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
                iterateProjectedChildren(renderer, handler, level);
                issueOperationsOfProjectedChildren(renderer, handler);
            }
            }
        }
        }


        // for 3d root, draw children with positive z values
        // for 3d root, draw children with positive z values
        iterate3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
        issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
    }
    }


    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
    handler(new (alloc) RestoreToCountOp(restoreTo),
    handler(new (alloc) RestoreToCountOp(restoreTo),
            PROPERTY_SAVECOUNT, properties().getClipToBounds());
            PROPERTY_SAVECOUNT, properties().getClipToBounds());
    renderer.setOverrideLayerAlpha(1.0f);
    renderer.setOverrideLayerAlpha(1.0f);

    handler.endMark();
}
}


} /* namespace uirenderer */
} /* namespace uirenderer */
+17 −6
Original line number Original line Diff line number Diff line
@@ -92,8 +92,12 @@ public:
    ANDROID_API void setData(DisplayListData* newData);
    ANDROID_API void setData(DisplayListData* newData);


    void computeOrdering();
    void computeOrdering();
    void defer(DeferStateStruct& deferStruct, const int level);

    void replay(ReplayStateStruct& replayStruct, const int level);
    void deferNodeTree(DeferStateStruct& deferStruct);
    void deferNodeInParent(DeferStateStruct& deferStruct, const int level);

    void replayNodeTree(ReplayStateStruct& replayStruct);
    void replayNodeInParent(ReplayStateStruct& replayStruct, const int level);


    ANDROID_API void output(uint32_t level = 1);
    ANDROID_API void output(uint32_t level = 1);


@@ -164,19 +168,26 @@ private:
            const mat4* transformFromProjectionSurface);
            const mat4* transformFromProjectionSurface);


    template <class T>
    template <class T>
    inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level);
    inline void setViewProperties(OpenGLRenderer& renderer, T& handler);


    void buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes);
    void buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes);


    template<class T>
    template<class T>
    inline void iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
    inline void issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler);

    template <class T>
    inline void issueOperationsOf3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
            ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler);
            ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler);


    template <class T>
    template <class T>
    inline void iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level);
    inline void issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler);


    /**
     * Issue the RenderNode's operations into a handler, recursing for subtrees through
     * DrawDisplayListOp's defer() or replay() methods
     */
    template <class T>
    template <class T>
    inline void iterate(OpenGLRenderer& renderer, T& handler, const int level);
    inline void issueOperations(OpenGLRenderer& renderer, T& handler);


    class TextContainer {
    class TextContainer {
    public:
    public: