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

Commit 5db60e0e authored by Chris Craik's avatar Chris Craik Committed by Android (Google) Code Review
Browse files

Merge "Support shadows on the root RenderNode"

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

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

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

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

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

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

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

}

class DeferOperationHandler {
@@ -313,15 +311,25 @@ public:
        operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
    }
    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:
    DeferStateStruct& mDeferStruct;
    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);
    iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
    issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
}

class ReplayOperationHandler {
@@ -335,21 +343,31 @@ public:
        operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
    }
    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:
    ReplayStateStruct& mReplayStruct;
    const int mLevel;
};

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

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

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

void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) {
@@ -373,10 +391,42 @@ void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslat
    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

template <class T>
void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
void RenderNode::issueOperationsOf3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
        ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) {
    const int size = zTranslatedNodes.size();
    if (size == 0
@@ -386,12 +436,6 @@ void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTransl
        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
     * 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,
            // OR if its caster's Z value is similar to the previous potential caster
            if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {

                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());
                }
                caster->issueDrawShadowOperation(casterOp->mTransformFromParent, handler);

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

template <class T>
void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
    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());

void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) {
    for (size_t i = 0; i < mProjectedNodes.size(); i++) {
        DrawDisplayListOp* childOp = mProjectedNodes[i];

@@ -492,7 +501,6 @@ void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler,
        childOp->mSkipInOrderDraw = true;
        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
 */
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
        ALOGW("Error: %s is drawing after destruction", mName.string());
        CRASH();
@@ -515,6 +524,8 @@ void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level)
        return;
    }

    handler.startMark(mName.string());

#if DEBUG_DISPLAY_LIST
    Rect* clipRect = renderer.getClipRect();
    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, "",
            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);

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

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

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

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

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

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

        // 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);
    handler(new (alloc) RestoreToCountOp(restoreTo),
            PROPERTY_SAVECOUNT, properties().getClipToBounds());
    renderer.setOverrideLayerAlpha(1.0f);

    handler.endMark();
}

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

    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);

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

    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);

    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);

    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>
    inline void iterate(OpenGLRenderer& renderer, T& handler, const int level);
    inline void issueOperations(OpenGLRenderer& renderer, T& handler);

    class TextContainer {
    public: