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

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

Merge "Add z-reordering support to OpReorderer"

parents a00acdd1 161f54b2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1398,6 +1398,7 @@ class DrawRenderNodeOp : public DrawBoundedOp {
    friend class RenderNode; // grant RenderNode access to info of child
    friend class DisplayList; // grant DisplayList access to info of child
    friend class DisplayListCanvas;
    friend class TestUtils;
public:
    DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent, bool clipIsSimple)
            : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr)
+106 −8
Original line number Diff line number Diff line
@@ -16,12 +16,14 @@

#include "OpReorderer.h"

#include "utils/PaintUtils.h"
#include "RenderNode.h"
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
#include "utils/FatVector.h"
#include "utils/PaintUtils.h"

#include "SkCanvas.h"
#include "utils/Trace.h"
#include <SkCanvas.h>
#include <utils/Trace.h>
#include <utils/TypeHelpers.h>

namespace android {
namespace uirenderer {
@@ -375,6 +377,93 @@ void OpReorderer::deferNodePropsAndOps(RenderNode& node) {
    }
}

typedef key_value_pair_t<float, const RenderNodeOp*> ZRenderNodeOpPair;

template <typename V>
static void buildZSortedChildList(V* zTranslatedNodes,
        const DisplayList& displayList, const DisplayList::Chunk& chunk) {
    if (chunk.beginChildIndex == chunk.endChildIndex) return;

    for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
        RenderNodeOp* childOp = displayList.getChildren()[i];
        RenderNode* child = childOp->renderNode;
        float childZ = child->properties().getZ();

        if (!MathUtils::isZero(childZ) && chunk.reorderChildren) {
            zTranslatedNodes->push_back(ZRenderNodeOpPair(childZ, childOp));
            childOp->skipInOrderDraw = true;
        } else if (!child->properties().getProjectBackwards()) {
            // regular, in order drawing DisplayList
            childOp->skipInOrderDraw = false;
        }
    }

    // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order)
    std::stable_sort(zTranslatedNodes->begin(), zTranslatedNodes->end());
}

template <typename V>
static size_t findNonNegativeIndex(const V& zTranslatedNodes) {
    for (size_t i = 0; i < zTranslatedNodes.size(); i++) {
        if (zTranslatedNodes[i].key >= 0.0f) return i;
    }
    return zTranslatedNodes.size();
}

template <typename V>
void OpReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) {
    const int size = zTranslatedNodes.size();
    if (size == 0
            || (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f)
            || (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) {
        // no 3d children to draw
        return;
    }

    /**
     * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
     * with very similar Z heights to draw together.
     *
     * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are
     * underneath both, and neither's shadow is drawn on top of the other.
     */
    const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes);
    size_t drawIndex, shadowIndex, endIndex;
    if (mode == ChildrenSelectMode::Negative) {
        drawIndex = 0;
        endIndex = nonNegativeIndex;
        shadowIndex = endIndex; // draw no shadows
    } else {
        drawIndex = nonNegativeIndex;
        endIndex = size;
        shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
    }

    float lastCasterZ = 0.0f;
    while (shadowIndex < endIndex || drawIndex < endIndex) {
        if (shadowIndex < endIndex) {
            const RenderNodeOp* casterNodeOp = zTranslatedNodes[shadowIndex].value;
            const float casterZ = zTranslatedNodes[shadowIndex].key;
            // 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 < 0.1f) {
                deferShadow(*casterNodeOp);

                lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
                shadowIndex++;
                continue;
            }
        }

        const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value;
        deferRenderNodeOp(*childOp);
        drawIndex++;
    }
}

void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) {
    // TODO
}
/**
 * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods.
 *
@@ -388,17 +477,20 @@ void OpReorderer::deferImpl(const DisplayList& displayList) {
        MAP_OPS(OP_RECEIVER)
    };
    for (const DisplayList::Chunk& chunk : displayList.getChunks()) {
        FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes;
        buildZSortedChildList(&zTranslatedNodes, displayList, chunk);

        defer3dChildren(ChildrenSelectMode::Negative, zTranslatedNodes);
        for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
            const RecordedOp* op = displayList.getOps()[opIndex];
            receivers[op->opId](*this, *op);
        }
        defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes);
    }
}

void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) {
    if (op.renderNode->nothingToDraw()) {
        return;
    }
void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) {
    if (op.renderNode->nothingToDraw()) return;
    int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);

    // apply state from RecordedOp
@@ -412,6 +504,12 @@ void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) {
    mCanvasState.restoreToCount(count);
}

void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) {
    if (!op.skipInOrderDraw) {
        deferRenderNodeOp(op);
    }
}

static batchid_t tessellatedBatchId(const SkPaint& paint) {
    return paint.getPathEffect()
            ? OpBatchType::AlphaMaskTexture
+11 −0
Original line number Diff line number Diff line
@@ -182,6 +182,10 @@ public:
    virtual GLuint getTargetFbo() const override { return 0; }

private:
    enum class ChildrenSelectMode {
        Negative,
        Positive
    };
    void saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
            const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
    void restoreForLayer();
@@ -195,8 +199,15 @@ private:
    // should always be surrounded by a save/restore pair
    void deferNodePropsAndOps(RenderNode& node);

    void deferShadow(const RenderNodeOp& casterOp);

    void deferImpl(const DisplayList& displayList);

    template <typename V>
    void defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes);

    void deferRenderNodeOp(const RenderNodeOp& op);

    void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers);

    /**
+1 −0
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ struct RenderNodeOp : RecordedOp {
            : SUPER_PAINTLESS(RenderNodeOp)
            , renderNode(renderNode) {}
    RenderNode * renderNode; // not const, since drawing modifies it (somehow...)
    bool skipInOrderDraw = false;
};

struct BitmapOp : RecordedOp {
+4 −4
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ void RecordingCanvas::reset(int width, int height) {

    mState.initializeSaveStack(width, height, 0, 0, width, height, Vector3());

    mDeferredBarrierType = kBarrier_InOrder;
    mDeferredBarrierType = DeferredBarrierType::InOrder;
    mState.setDirtyClip(false);
    mRestoreSaveCount = -1;
}
@@ -432,17 +432,17 @@ size_t RecordingCanvas::addOp(RecordedOp* op) {
    // TODO: validate if "addDrawOp" quickrejection logic is useful before adding
    int insertIndex = mDisplayList->ops.size();
    mDisplayList->ops.push_back(op);
    if (mDeferredBarrierType != kBarrier_None) {
    if (mDeferredBarrierType != DeferredBarrierType::None) {
        // op is first in new chunk
        mDisplayList->chunks.emplace_back();
        DisplayList::Chunk& newChunk = mDisplayList->chunks.back();
        newChunk.beginOpIndex = insertIndex;
        newChunk.endOpIndex = insertIndex + 1;
        newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder);
        newChunk.reorderChildren = (mDeferredBarrierType == DeferredBarrierType::OutOfOrder);

        int nextChildIndex = mDisplayList->children.size();
        newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex;
        mDeferredBarrierType = kBarrier_None;
        mDeferredBarrierType = DeferredBarrierType::None;
    } else {
        // standard case - append to existing chunk
        mDisplayList->chunks.back().endOpIndex = insertIndex + 1;
Loading