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

Commit 83161dcd authored by John Reck's avatar John Reck
Browse files

Delete VectorDrawableAtlas

Poking around in a few apps it doesn't appear that
the VectorDrawableAtlas is achieving sufficient
utilization to justify its existence. The potential for
draw call merging doesn't seem warranted for the
RAM cost of the atlas.

Bug: 137853925
Test: builds
Change-Id: Id2419bc6dccb6316636d50c568f8fac75a2d563f
parent 781630e4
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -219,7 +219,6 @@ cc_defaults {
                "pipeline/skia/SkiaPipeline.cpp",
                "pipeline/skia/SkiaProfileRenderer.cpp",
                "pipeline/skia/SkiaVulkanPipeline.cpp",
                "pipeline/skia/VectorDrawableAtlas.cpp",
                "pipeline/skia/VkFunctorDrawable.cpp",
                "pipeline/skia/VkInteropFunctorDrawable.cpp",
                "renderstate/RenderState.cpp",
@@ -345,7 +344,6 @@ cc_test {
        "tests/unit/ThreadBaseTests.cpp",
        "tests/unit/TypefaceTests.cpp",
        "tests/unit/VectorDrawableTests.cpp",
        "tests/unit/VectorDrawableAtlasTests.cpp",
        "tests/unit/WebViewFunctorManagerTests.cpp",
    ],
}
+7 −113
Original line number Diff line number Diff line
@@ -496,87 +496,6 @@ Bitmap& Tree::getBitmapUpdateIfDirty() {
    return *mCache.bitmap;
}

void Tree::updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext* context) {
#ifdef __ANDROID__  // Layoutlib does not support hardware acceleration
    SkRect dst;
    sk_sp<SkSurface> surface = mCache.getSurface(&dst);
    bool canReuseSurface = surface && dst.width() >= mProperties.getScaledWidth() &&
                           dst.height() >= mProperties.getScaledHeight();
    if (!canReuseSurface) {
        int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
        int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
        auto atlasEntry = atlas->requestNewEntry(scaledWidth, scaledHeight, context);
        if (INVALID_ATLAS_KEY != atlasEntry.key) {
            dst = atlasEntry.rect;
            surface = atlasEntry.surface;
            mCache.setAtlas(atlas, atlasEntry.key);
        } else {
            // don't draw, if we failed to allocate an offscreen buffer
            mCache.clear();
            surface.reset();
        }
    }
    if (!canReuseSurface || mCache.dirty) {
        if (surface) {
            Bitmap& bitmap = getBitmapUpdateIfDirty();
            SkBitmap skiaBitmap;
            bitmap.getSkBitmap(&skiaBitmap);
            surface->writePixels(skiaBitmap, dst.fLeft, dst.fTop);
        }
        mCache.dirty = false;
    }
#endif
}

void Tree::Cache::setAtlas(sp<skiapipeline::VectorDrawableAtlas> newAtlas,
                           skiapipeline::AtlasKey newAtlasKey) {
    LOG_ALWAYS_FATAL_IF(newAtlasKey == INVALID_ATLAS_KEY);
    clear();
    mAtlas = newAtlas;
    mAtlasKey = newAtlasKey;
}

sk_sp<SkSurface> Tree::Cache::getSurface(SkRect* bounds) {
    sk_sp<SkSurface> surface;
#ifdef __ANDROID__  // Layoutlib does not support hardware acceleration
    sp<skiapipeline::VectorDrawableAtlas> atlas = mAtlas.promote();
    if (atlas.get() && mAtlasKey != INVALID_ATLAS_KEY) {
        auto atlasEntry = atlas->getEntry(mAtlasKey);
        *bounds = atlasEntry.rect;
        surface = atlasEntry.surface;
        mAtlasKey = atlasEntry.key;
    }
#endif

    return surface;
}

void Tree::Cache::clear() {
#ifdef __ANDROID__  // Layoutlib does not support hardware acceleration
    if (mAtlasKey != INVALID_ATLAS_KEY) {
        if (renderthread::RenderThread::isCurrent()) {
            sp<skiapipeline::VectorDrawableAtlas> lockAtlas = mAtlas.promote();
            if (lockAtlas.get()) {
                lockAtlas->releaseEntry(mAtlasKey);
            }
        } else {
            // VectorDrawableAtlas can be accessed only on RenderThread.
            // Use by-copy capture of the current Cache variables, because "this" may not be valid
            // by the time the lambda is evaluated on RenderThread.
            renderthread::RenderThread::getInstance().queue().post(
                    [atlas = mAtlas, atlasKey = mAtlasKey]() {
                        sp<skiapipeline::VectorDrawableAtlas> lockAtlas = atlas.promote();
                        if (lockAtlas.get()) {
                            lockAtlas->releaseEntry(atlasKey);
                        }
                    });
        }
        mAtlasKey = INVALID_ATLAS_KEY;
    }
    mAtlas = nullptr;
#endif
}

void Tree::draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& inPaint) {
    if (canvas->quickReject(bounds)) {
        // The RenderNode is on screen, but the AVD is not.
@@ -587,8 +506,6 @@ void Tree::draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& inPaint)
    SkPaint paint = inPaint;
    paint.setAlpha(mProperties.getRootAlpha() * 255);

    if (canvas->getGrContext() == nullptr) {
        // Recording to picture, don't use the SkSurface which won't work off of renderthread.
    Bitmap& bitmap = getBitmapUpdateIfDirty();
    SkBitmap skiaBitmap;
    bitmap.getSkBitmap(&skiaBitmap);
@@ -597,29 +514,6 @@ void Tree::draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& inPaint)
    int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
    canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
                           &paint, SkCanvas::kFast_SrcRectConstraint);
        return;
    }

    SkRect src;
    sk_sp<SkSurface> vdSurface = mCache.getSurface(&src);
    if (vdSurface) {
        canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src, bounds, &paint,
                              SkCanvas::kFast_SrcRectConstraint);
    } else {
        // Handle the case when VectorDrawableAtlas has been destroyed, because of memory pressure.
        // We render the VD into a temporary standalone buffer and mark the frame as dirty. Next
        // frame will be cached into the atlas.
        Bitmap& bitmap = getBitmapUpdateIfDirty();
        SkBitmap skiaBitmap;
        bitmap.getSkBitmap(&skiaBitmap);

        int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
        int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
        canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
                               &paint, SkCanvas::kFast_SrcRectConstraint);
        mCache.clear();
        markDirty();
    }
}

void Tree::updateBitmapCache(Bitmap& bitmap, bool useStagingData) {
+0 −33
Original line number Diff line number Diff line
@@ -651,46 +651,13 @@ public:
    void getPaintFor(SkPaint* outPaint, const TreeProperties &props) const;
    BitmapPalette computePalette();

    /**
     * Draws VD into a GPU backed surface.
     * This should always be called from RT and it works with Skia pipeline only.
     */
    void updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext* context);

    void setAntiAlias(bool aa) { mRootNode->setAntiAlias(aa); }

private:
    class Cache {
    public:
        sk_sp<Bitmap> bitmap;  // used by HWUI pipeline and software
        // TODO: use surface instead of bitmap when drawing in software canvas
        bool dirty = true;

        // the rest of the code in Cache is used by Skia pipelines only

        ~Cache() { clear(); }

        /**
         * Stores a weak pointer to the atlas and a key.
         */
        void setAtlas(sp<skiapipeline::VectorDrawableAtlas> atlas,
                      skiapipeline::AtlasKey newAtlasKey);

        /**
         * Gets a surface and bounds from the atlas.
         *
         * @return nullptr if the altas has been deleted.
         */
        sk_sp<SkSurface> getSurface(SkRect* bounds);

        /**
         * Releases atlas key from the atlas, which makes it available for reuse.
         */
        void clear();

    private:
        wp<skiapipeline::VectorDrawableAtlas> mAtlas;
        skiapipeline::AtlasKey mAtlasKey = INVALID_ATLAS_KEY;
    };

    bool allocateBitmapIfNeeded(Cache& cache, int width, int height);
+0 −5
Original line number Diff line number Diff line
@@ -150,12 +150,7 @@ bool SkiaDisplayList::prepareListAndChildren(
            const SkRect& bounds = vectorDrawable->properties().getBounds();
            if (intersects(info.screenSize, totalMatrix, bounds)) {
                isDirty = true;
#ifdef __ANDROID__ // Layoutlib does not support CanvasContext
                static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline())
                        ->getVectorDrawables()
                        ->push_back(vectorDrawable);
                vectorDrawable->setPropertyChangeWillBeConsumed(true);
#endif
            }
        }
    }
+0 −23
Original line number Diff line number Diff line
@@ -43,7 +43,6 @@ namespace uirenderer {
namespace skiapipeline {

SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
    mVectorDrawables.reserve(30);
}

SkiaPipeline::~SkiaPipeline() {
@@ -73,18 +72,11 @@ void SkiaPipeline::unpinImages() {
    mPinnedImages.clear();
}

void SkiaPipeline::onPrepareTree() {
    // The only time mVectorDrawables is not empty is if prepare tree was called 2 times without
    // a renderFrame in the middle.
    mVectorDrawables.clear();
}

void SkiaPipeline::renderLayers(const LightGeometry& lightGeometry,
                                LayerUpdateQueue* layerUpdateQueue, bool opaque,
                                const LightInfo& lightInfo) {
    LightingInfo::updateLighting(lightGeometry, lightInfo);
    ATRACE_NAME("draw layers");
    renderVectorDrawableCache();
    renderLayersImpl(*layerUpdateQueue, opaque);
    layerUpdateQueue->clear();
}
@@ -213,19 +205,6 @@ void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
    }
}

void SkiaPipeline::renderVectorDrawableCache() {
    if (!mVectorDrawables.empty()) {
        sp<VectorDrawableAtlas> atlas = mRenderThread.cacheManager().acquireVectorDrawableAtlas();
        auto grContext = mRenderThread.getGrContext();
        atlas->prepareForDraw(grContext);
        ATRACE_NAME("Update VectorDrawables");
        for (auto vd : mVectorDrawables) {
            vd->updateCache(atlas, grContext);
        }
        mVectorDrawables.clear();
    }
}

static void savePictureAsync(const sk_sp<SkData>& data, const std::string& filename) {
    CommonPool::post([data, filename] {
        if (0 == access(filename.c_str(), F_OK)) {
@@ -380,8 +359,6 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli
        Properties::skpCaptureEnabled = true;
    }

    renderVectorDrawableCache();

    // draw all layers up front
    renderLayersImpl(layers, opaque);

Loading