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

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

Merge "Fix DA bugs"

parents 0811cbee a447d29c
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -841,13 +841,6 @@ public class RenderNode {
        return nOffsetTopAndBottom(mNativeRenderNode, offset);
    }

    /**
     * Sets the scroll position, this is used for damage calculations
     */
    public void setScrollPosition(int x, int y) {
        nSetScrollPosition(mNativeRenderNode, x, y);
    }

    /**
     * Outputs the display list to the log. This method exists for use by
     * tools to output display lists for selected nodes to the log.
@@ -906,7 +899,6 @@ public class RenderNode {
    private static native boolean nSetRight(long renderNode, int right);
    private static native boolean nSetTop(long renderNode, int top);
    private static native boolean nSetLeft(long renderNode, int left);
    private static native void nSetScrollPosition(long renderNode, int scrollX, int scrollY);
    private static native boolean nSetCameraDistance(long renderNode, float distance);
    private static native boolean nSetPivotY(long renderNode, float pivotY);
    private static native boolean nSetPivotX(long renderNode, float pivotX);
+0 −1
Original line number Diff line number Diff line
@@ -13738,7 +13738,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            return;
        }
        renderNode.setScrollPosition(mScrollX, mScrollY);
        if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
                || !renderNode.isValid()
                || (!isLayer && mRecreateDisplayList)) {
+0 −8
Original line number Diff line number Diff line
@@ -275,13 +275,6 @@ static jboolean android_view_RenderNode_offsetTopAndBottom(JNIEnv* env,
    return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y);
}

static void android_view_RenderNode_setScrollPosition(JNIEnv* env,
        jobject clazz, jlong renderNodePtr, jint scrollX, jint scrollY) {
    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
    SET_AND_DIRTY(setScrollX, scrollX, RenderNode::GENERIC);
    SET_AND_DIRTY(setScrollY, scrollY, RenderNode::GENERIC);
}

// ----------------------------------------------------------------------------
// RenderProperties - getters
// ----------------------------------------------------------------------------
@@ -517,7 +510,6 @@ static JNINativeMethod gMethods[] = {
    { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
    { "nOffsetLeftAndRight",   "(JF)Z",  (void*) android_view_RenderNode_offsetLeftAndRight },
    { "nOffsetTopAndBottom",   "(JF)Z",  (void*) android_view_RenderNode_offsetTopAndBottom },
    { "nSetScrollPosition",    "(JII)V", (void*) android_view_RenderNode_setScrollPosition },

    { "nHasOverlappingRendering", "(J)Z",  (void*) android_view_RenderNode_hasOverlappingRendering },
    { "nGetClipToOutline",        "(J)Z",  (void*) android_view_RenderNode_getClipToOutline },
+121 −28
Original line number Diff line number Diff line
@@ -26,8 +26,23 @@
namespace android {
namespace uirenderer {

NullDamageAccumulator NullDamageAccumulator::sInstance;

NullDamageAccumulator* NullDamageAccumulator::instance() {
    return &sInstance;
}

enum TransformType {
    TransformRenderNode,
    TransformMatrix4,
};

struct DirtyStack {
    const RenderNode* node;
    TransformType type;
    union {
        const RenderNode* renderNode;
        const Matrix4* matrix4;
    };
    // When this frame is pop'd, this rect is mapped through the above transform
    // and applied to the previous (aka parent) frame
    SkRect pendingDirty;
@@ -42,7 +57,7 @@ DamageAccumulator::DamageAccumulator() {
    mHead->prev = mHead;
}

void DamageAccumulator::pushNode(const RenderNode* node) {
void DamageAccumulator::pushCommon() {
    if (!mHead->next) {
        DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
        nextFrame->next = 0;
@@ -50,42 +65,120 @@ void DamageAccumulator::pushNode(const RenderNode* node) {
        mHead->next = nextFrame;
    }
    mHead = mHead->next;
    mHead->node = node;
    mHead->pendingDirty.setEmpty();
}

void DamageAccumulator::popNode() {
void DamageAccumulator::pushTransform(const RenderNode* transform) {
    pushCommon();
    mHead->type = TransformRenderNode;
    mHead->renderNode = transform;
}

void DamageAccumulator::pushTransform(const Matrix4* transform) {
    pushCommon();
    mHead->type = TransformMatrix4;
    mHead->matrix4 = transform;
}

void DamageAccumulator::popTransform() {
    LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
    DirtyStack* dirtyFrame = mHead;
    mHead = mHead->prev;
    if (!dirtyFrame->pendingDirty.isEmpty()) {
        SkRect mappedDirty;
        const RenderProperties& props = dirtyFrame->node->properties();
    if (dirtyFrame->type == TransformRenderNode) {
        applyRenderNodeTransform(dirtyFrame);
    } else {
        applyMatrix4Transform(dirtyFrame);
    }
}

static inline void mapRect(const Matrix4* matrix, const SkRect& in, SkRect* out) {
    if (in.isEmpty()) return;
    Rect temp(in);
    matrix->mapRect(temp);
    out->join(RECT_ARGS(temp));
}

void DamageAccumulator::applyMatrix4Transform(DirtyStack* frame) {
    mapRect(frame->matrix4, frame->pendingDirty, &mHead->pendingDirty);
}

static inline void mapRect(const RenderProperties& props, const SkRect& in, SkRect* out) {
    if (in.isEmpty()) return;
    const SkMatrix* transform = props.getTransformMatrix();
    SkRect temp(in);
    if (transform && !transform->isIdentity()) {
            transform->mapRect(&mappedDirty, dirtyFrame->pendingDirty);
        transform->mapRect(&temp);
    }
    temp.offset(props.getLeft(), props.getTop());
    out->join(temp);
}

static DirtyStack* findParentRenderNode(DirtyStack* frame) {
    while (frame->prev != frame) {
        frame = frame->prev;
        if (frame->type == TransformRenderNode) {
            return frame;
        }
    }
    return NULL;
}

static DirtyStack* findProjectionReceiver(DirtyStack* frame) {
    if (frame) {
        while (frame->prev != frame) {
            frame = frame->prev;
            if (frame->type == TransformRenderNode
                    && frame->renderNode->hasProjectionReceiver()) {
                return frame;
            }
        }
    }
    return NULL;
}

static void applyTransforms(DirtyStack* frame, DirtyStack* end) {
    SkRect* rect = &frame->pendingDirty;
    while (frame != end) {
        if (frame->type == TransformRenderNode) {
            mapRect(frame->renderNode->properties(), *rect, rect);
        } else {
            mappedDirty = dirtyFrame->pendingDirty;
            mapRect(frame->matrix4, *rect, rect);
        }
        frame = frame->prev;
    }
        if (CC_LIKELY(mHead->node)) {
            const RenderProperties& parentProps = mHead->node->properties();
            mappedDirty.offset(props.getLeft() - parentProps.getScrollX(),
                    props.getTop() - parentProps.getScrollY());
            if (props.getClipToBounds()) {
                if (!mappedDirty.intersect(0, 0, parentProps.getWidth(), parentProps.getHeight())) {
                    mappedDirty.setEmpty();
}

void DamageAccumulator::applyRenderNodeTransform(DirtyStack* frame) {
    if (frame->pendingDirty.isEmpty()) {
        return;
    }
            if (CC_UNLIKELY(!MathUtils::isZero(props.getTranslationZ()))) {
                // TODO: Can we better bound the shadow damage area? For now
                // match the old damageShadowReceiver() path and just dirty
                // the entire parent bounds
                mappedDirty.join(0, 0, parentProps.getWidth(), parentProps.getHeight());

    const RenderProperties& props = frame->renderNode->properties();

    // Perform clipping
    if (props.getClipToBounds() && !frame->pendingDirty.isEmpty()) {
        if (!frame->pendingDirty.intersect(0, 0, props.getWidth(), props.getHeight())) {
            frame->pendingDirty.setEmpty();
        }
    }

    // apply all transforms
    mapRect(props, frame->pendingDirty, &mHead->pendingDirty);

    // project backwards if necessary
    if (props.getProjectBackwards() && !frame->pendingDirty.isEmpty()) {
        // First, find our parent RenderNode:
        DirtyStack* parentNode = findParentRenderNode(frame);
        // Find our parent's projection receiver, which is what we project onto
        DirtyStack* projectionReceiver = findProjectionReceiver(parentNode);
        if (projectionReceiver) {
            applyTransforms(frame, projectionReceiver);
            projectionReceiver->pendingDirty.join(frame->pendingDirty);
        } else {
            mappedDirty.offset(props.getLeft(), props.getTop());
            ALOGW("Failed to find projection receiver? Dropping on the floor...");
        }
        dirty(mappedDirty.fLeft, mappedDirty.fTop, mappedDirty.fRight, mappedDirty.fBottom);

        frame->pendingDirty.setEmpty();
    }
}

+42 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#ifndef DAMAGEACCUMULATOR_H
#define DAMAGEACCUMULATOR_H

#include <cutils/compiler.h>
#include <utils/LinearAllocator.h>

#include <SkMatrix.h>
@@ -28,8 +29,19 @@ namespace uirenderer {

struct DirtyStack;
class RenderNode;
class Matrix4;

class DamageAccumulator {
class IDamageAccumulator {
public:
    virtual void pushTransform(const RenderNode* transform) = 0;
    virtual void pushTransform(const Matrix4* transform) = 0;
    virtual void popTransform() = 0;
    virtual void dirty(float left, float top, float right, float bottom) = 0;
protected:
    virtual ~IDamageAccumulator() {}
};

class DamageAccumulator : public IDamageAccumulator {
    PREVENT_COPY_AND_ASSIGN(DamageAccumulator);
public:
    DamageAccumulator();
@@ -37,20 +49,44 @@ public:

    // Push a transform node onto the stack. This should be called prior
    // to any dirty() calls. Subsequent calls to dirty()
    // will be affected by the node's transform when popNode() is called.
    void pushNode(const RenderNode* node);
    // will be affected by the transform when popTransform() is called.
    virtual void pushTransform(const RenderNode* transform);
    virtual void pushTransform(const Matrix4* transform);

    // Pops a transform node from the stack, propagating the dirty rect
    // up to the parent node.
    void popNode();
    void dirty(float left, float top, float right, float bottom);
    // up to the parent node. Returns the IDamageTransform that was just applied
    virtual void popTransform();

    virtual void dirty(float left, float top, float right, float bottom);

    void finish(SkRect* totalDirty);

private:
    void pushCommon();
    void applyMatrix4Transform(DirtyStack* frame);
    void applyRenderNodeTransform(DirtyStack* frame);

    LinearAllocator mAllocator;
    DirtyStack* mHead;
};

class NullDamageAccumulator : public IDamageAccumulator {
    PREVENT_COPY_AND_ASSIGN(NullDamageAccumulator);
public:
    virtual void pushTransform(const RenderNode* transform) { }
    virtual void pushTransform(const Matrix4* transform) { }
    virtual void popTransform() { }
    virtual void dirty(float left, float top, float right, float bottom) { }

    ANDROID_API static NullDamageAccumulator* instance();

private:
    NullDamageAccumulator() {}
    ~NullDamageAccumulator() {}

    static NullDamageAccumulator sInstance;
};

} /* namespace uirenderer */
} /* namespace android */

Loading