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

Commit be67195c authored by John Reck's avatar John Reck
Browse files

Convert DisplayList to a value-type wrapper

Make DisplayList its own type instead of an alias,
pushing the Skia aspect behind it mostly. Removes a bunch
of manual memory management and opens the door to DisplayList
being a union type with multiple implementations

Test: builds (somehow), boots, hwuiunit passes, CtsUiRendering passes
Change-Id: I1d7806aa3afc5d9ece08b06959920078a5814c59
parent 844516c4
Loading
Loading
Loading
Loading
+115 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@

#include "pipeline/skia/SkiaDisplayList.h"

#include <memory>

namespace android {
namespace uirenderer {

@@ -29,7 +31,119 @@ typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot;
/**
 * Data structure that holds the list of commands used in display list stream
 */
using DisplayList = skiapipeline::SkiaDisplayList;
//using DisplayList = skiapipeline::SkiaDisplayList;
class DisplayList {
public:
    // Constructs an empty (invalid) DisplayList
    explicit DisplayList() {}

    // Constructs a DisplayList from a SkiaDisplayList
    explicit DisplayList(std::unique_ptr<skiapipeline::SkiaDisplayList> impl)
        : mImpl(std::move(impl)) {}

    // Move support
    DisplayList(DisplayList&& other) : mImpl(std::move(other.mImpl)) {}
    DisplayList& operator=(DisplayList&& other) {
        mImpl = std::move(other.mImpl);
        return *this;
    }

    // No copy support
    DisplayList(const DisplayList& other) = delete;
    DisplayList& operator=(const DisplayList&) = delete;

    void updateChildren(std::function<void(RenderNode*)> updateFn) {
        mImpl->updateChildren(std::move(updateFn));
    }

    [[nodiscard]] explicit operator bool() const {
        return mImpl.get() != nullptr;
    }

    // If true this DisplayList contains a backing content, even if that content is empty
    // If false, there this DisplayList is in an "empty" state
    [[nodiscard]] bool isValid() const {
        return mImpl.get() != nullptr;
    }

    [[nodiscard]] bool isEmpty() const {
        return !hasContent();
    }

    [[nodiscard]] bool hasContent() const {
        return mImpl && !(mImpl->isEmpty());
    }

    [[nodiscard]] bool containsProjectionReceiver() const {
        return mImpl && mImpl->containsProjectionReceiver();
    }

    [[nodiscard]] skiapipeline::SkiaDisplayList* asSkiaDl() {
        return mImpl.get();
    }

    [[nodiscard]] const skiapipeline::SkiaDisplayList* asSkiaDl() const {
        return mImpl.get();
    }

    [[nodiscard]] bool hasVectorDrawables() const {
        return mImpl && mImpl->hasVectorDrawables();
    }

    void clear(RenderNode* owningNode = nullptr) {
        if (mImpl && owningNode && mImpl->reuseDisplayList(owningNode)) {
            // TODO: This is a bit sketchy to have a unique_ptr temporarily owned twice
            // Do something to cleanup reuseDisplayList passing itself to the RenderNode
            mImpl.release();
        } else {
            mImpl = nullptr;
        }
    }

    [[nodiscard]] size_t getUsedSize() const {
        return mImpl ? mImpl->getUsedSize() : 0;
    }

    [[nodiscard]] size_t getAllocatedSize() const {
        return mImpl ? mImpl->getAllocatedSize() : 0;
    }

    void output(std::ostream& output, uint32_t level) const {
        if (mImpl) {
            mImpl->output(output, level);
        }
    }

    [[nodiscard]] bool hasFunctor() const {
        return mImpl && mImpl->hasFunctor();
    }

    bool prepareListAndChildren(
            TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
            std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
        return mImpl && mImpl->prepareListAndChildren(
                observer, info, functorsNeedLayer, std::move(childFn));
    }

    void syncContents(const WebViewSyncData& data) {
        if (mImpl) {
            mImpl->syncContents(data);
        }
    }

    [[nodiscard]] bool hasText() const {
        return mImpl && mImpl->hasText();
    }

    void applyColorTransform(ColorTransform transform) {
        if (mImpl) {
            mImpl->mDisplayList.applyColorTransform(transform);
        }
    }

private:
    std::unique_ptr<skiapipeline::SkiaDisplayList> mImpl;
};

}  // namespace uirenderer
}  // namespace android
+0 −1
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@
#include "SkPaint.h"
#include "SkPath.h"
#include "SkRect.h"
#include "SkTemplates.h"

#include <vector>

+28 −41
Original line number Diff line number Diff line
@@ -70,19 +70,17 @@ RenderNode::RenderNode()
RenderNode::~RenderNode() {
    ImmediateRemoved observer(nullptr);
    deleteDisplayList(observer);
    delete mStagingDisplayList;
    LOG_ALWAYS_FATAL_IF(hasLayer(), "layer missed detachment!");
}

void RenderNode::setStagingDisplayList(DisplayList* displayList) {
    mValid = (displayList != nullptr);
void RenderNode::setStagingDisplayList(DisplayList&& newData) {
    mValid = newData.isValid();
    mNeedsDisplayListSync = true;
    delete mStagingDisplayList;
    mStagingDisplayList = displayList;
    mStagingDisplayList = std::move(newData);
}

void RenderNode::discardStagingDisplayList() {
    setStagingDisplayList(nullptr);
    setStagingDisplayList(DisplayList());
}

/**
@@ -105,32 +103,22 @@ void RenderNode::output(std::ostream& output, uint32_t level) {

    properties().debugOutputProperties(output, level + 1);

    if (mDisplayList) {
        mDisplayList->output(output, level);
    }
    mDisplayList.output(output, level);
    output << std::string(level * 2, ' ') << "/RenderNode(" << getName() << " " << this << ")";
    output << std::endl;
}

int RenderNode::getUsageSize() {
    int size = sizeof(RenderNode);
    if (mStagingDisplayList) {
        size += mStagingDisplayList->getUsedSize();
    }
    if (mDisplayList && mDisplayList != mStagingDisplayList) {
        size += mDisplayList->getUsedSize();
    }
    size += mStagingDisplayList.getUsedSize();
    size += mDisplayList.getUsedSize();
    return size;
}

int RenderNode::getAllocatedSize() {
    int size = sizeof(RenderNode);
    if (mStagingDisplayList) {
        size += mStagingDisplayList->getAllocatedSize();
    }
    if (mDisplayList && mDisplayList != mStagingDisplayList) {
        size += mDisplayList->getAllocatedSize();
    }
    size += mStagingDisplayList.getAllocatedSize();
    size += mDisplayList.getAllocatedSize();
    return size;
}

@@ -246,9 +234,9 @@ void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool fu

    bool willHaveFunctor = false;
    if (info.mode == TreeInfo::MODE_FULL && mStagingDisplayList) {
        willHaveFunctor = mStagingDisplayList->hasFunctor();
        willHaveFunctor = mStagingDisplayList.hasFunctor();
    } else if (mDisplayList) {
        willHaveFunctor = mDisplayList->hasFunctor();
        willHaveFunctor = mDisplayList.hasFunctor();
    }
    bool childFunctorsNeedLayer =
            mProperties.prepareForFunctorPresence(willHaveFunctor, functorsNeedLayer);
@@ -263,8 +251,8 @@ void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool fu
    }

    if (mDisplayList) {
        info.out.hasFunctors |= mDisplayList->hasFunctor();
        bool isDirty = mDisplayList->prepareListAndChildren(
        info.out.hasFunctors |= mDisplayList.hasFunctor();
        bool isDirty = mDisplayList.prepareListAndChildren(
                observer, info, childFunctorsNeedLayer,
                [](RenderNode* child, TreeObserver& observer, TreeInfo& info,
                   bool functorsNeedLayer) {
@@ -318,16 +306,15 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) {
    // Make sure we inc first so that we don't fluctuate between 0 and 1,
    // which would thrash the layer cache
    if (mStagingDisplayList) {
        mStagingDisplayList->updateChildren([](RenderNode* child) { child->incParentRefCount(); });
        mStagingDisplayList.updateChildren([](RenderNode* child) { child->incParentRefCount(); });
    }
    deleteDisplayList(observer, info);
    mDisplayList = mStagingDisplayList;
    mStagingDisplayList = nullptr;
    mDisplayList = std::move(mStagingDisplayList);
    if (mDisplayList) {
        WebViewSyncData syncData {
            .applyForceDark = info && !info->disableForceDark
        };
        mDisplayList->syncContents(syncData);
        mDisplayList.syncContents(syncData);
        handleForceDark(info);
    }
}
@@ -337,15 +324,18 @@ void RenderNode::handleForceDark(android::uirenderer::TreeInfo *info) {
        return;
    }
    auto usage = usageHint();
    const auto& children = mDisplayList->mChildNodes;
    if (mDisplayList->hasText()) {
    FatVector<RenderNode*, 6> children;
    mDisplayList.updateChildren([&children](RenderNode* node) {
        children.push_back(node);
    });
    if (mDisplayList.hasText()) {
        usage = UsageHint::Foreground;
    }
    if (usage == UsageHint::Unknown) {
        if (children.size() > 1) {
            usage = UsageHint::Background;
        } else if (children.size() == 1 &&
                children.front().getRenderNode()->usageHint() !=
                children.front()->usageHint() !=
                        UsageHint::Background) {
            usage = UsageHint::Background;
        }
@@ -354,7 +344,7 @@ void RenderNode::handleForceDark(android::uirenderer::TreeInfo *info) {
        // Crude overlap check
        SkRect drawn = SkRect::MakeEmpty();
        for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
            const auto& child = iter->getRenderNode();
            const auto& child = *iter;
            // We use stagingProperties here because we haven't yet sync'd the children
            SkRect bounds = SkRect::MakeXYWH(child->stagingProperties().getX(), child->stagingProperties().getY(),
                    child->stagingProperties().getWidth(), child->stagingProperties().getHeight());
@@ -365,7 +355,7 @@ void RenderNode::handleForceDark(android::uirenderer::TreeInfo *info) {
            drawn.join(bounds);
        }
    }
    mDisplayList->mDisplayList.applyColorTransform(
    mDisplayList.applyColorTransform(
            usage == UsageHint::Background ? ColorTransform::Dark : ColorTransform::Light);
}

@@ -382,20 +372,17 @@ void RenderNode::pushStagingDisplayListChanges(TreeObserver& observer, TreeInfo&

void RenderNode::deleteDisplayList(TreeObserver& observer, TreeInfo* info) {
    if (mDisplayList) {
        mDisplayList->updateChildren(
        mDisplayList.updateChildren(
                [&observer, info](RenderNode* child) { child->decParentRefCount(observer, info); });
        if (!mDisplayList->reuseDisplayList(this)) {
            delete mDisplayList;
        }
        mDisplayList.clear(this);
    }
    mDisplayList = nullptr;
}

void RenderNode::destroyHardwareResources(TreeInfo* info) {
    if (hasLayer()) {
        this->setLayerSurface(nullptr);
    }
    setStagingDisplayList(nullptr);
    discardStagingDisplayList();

    ImmediateRemoved observer(info);
    deleteDisplayList(observer, info);
@@ -406,7 +393,7 @@ void RenderNode::destroyLayers() {
        this->setLayerSurface(nullptr);
    }
    if (mDisplayList) {
        mDisplayList->updateChildren([](RenderNode* child) { child->destroyLayers(); });
        mDisplayList.updateChildren([](RenderNode* child) { child->destroyLayers(); });
    }
}

+9 −7
Original line number Diff line number Diff line
@@ -100,17 +100,17 @@ public:
    // See flags defined in DisplayList.java
    enum ReplayFlag { kReplayFlag_ClipChildren = 0x1 };

    void setStagingDisplayList(DisplayList* newData);
    void setStagingDisplayList(DisplayList&& newData);
    void discardStagingDisplayList();

    void output();
    int getUsageSize();
    int getAllocatedSize();

    bool isRenderable() const { return mDisplayList && !mDisplayList->isEmpty(); }
    bool isRenderable() const { return mDisplayList.hasContent(); }

    bool hasProjectionReceiver() const {
        return mDisplayList && mDisplayList->containsProjectionReceiver();
        return mDisplayList.containsProjectionReceiver();
    }

    const char* getName() const { return mName.string(); }
@@ -169,12 +169,14 @@ public:

    bool nothingToDraw() const {
        const Outline& outline = properties().getOutline();
        return mDisplayList == nullptr || properties().getAlpha() <= 0 ||
        return !mDisplayList.isValid() || properties().getAlpha() <= 0 ||
               (outline.getShouldClip() && outline.isEmpty()) || properties().getScaleX() == 0 ||
               properties().getScaleY() == 0;
    }

    const DisplayList* getDisplayList() const { return mDisplayList; }
    const DisplayList& getDisplayList() const { return mDisplayList; }
    // TODO: can this be cleaned up?
    DisplayList& getDisplayList() { return mDisplayList; }

    // Note: The position callbacks are relying on the listener using
    // the frameNumber to appropriately batch/synchronize these transactions.
@@ -253,8 +255,8 @@ private:

    bool mNeedsDisplayListSync;
    // WARNING: Do not delete this directly, you must go through deleteDisplayList()!
    DisplayList* mDisplayList;
    DisplayList* mStagingDisplayList;
    DisplayList mDisplayList;
    DisplayList mStagingDisplayList;

    int64_t mDamageGenerationId;

+2 −2
Original line number Diff line number Diff line
@@ -53,9 +53,9 @@ public:
        LOG_ALWAYS_FATAL("SkiaCanvas cannot be reset as a recording canvas");
    }

    virtual uirenderer::DisplayList* finishRecording() override {
    virtual uirenderer::DisplayList finishRecording() override {
        LOG_ALWAYS_FATAL("SkiaCanvas does not produce a DisplayList");
        return nullptr;
        return uirenderer::DisplayList();
    }
    virtual void enableZ(bool enableZ) override {
        LOG_ALWAYS_FATAL("SkiaCanvas does not support enableZ");
Loading