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

Commit 65e678fd authored by Stan Iliev's avatar Stan Iliev
Browse files

Cache VectorDrawable bounds at record time

Cache VectorDrawable bounds at record time, because the same
drawable object may be used several times with different bounds.

Bug: 71737362
Test: Wrote a new unit test, tried sample app attached to the bug
Change-Id: If7be934acf0c16b328cb0f95d849e463dcd3b88b
parent bc48bd8f
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -557,13 +557,12 @@ void Tree::Cache::clear() {
    mAtlasKey = INVALID_ATLAS_KEY;
}

void Tree::draw(SkCanvas* canvas) {
void Tree::draw(SkCanvas* canvas, const SkRect& bounds) {
    SkRect src;
    sk_sp<SkSurface> vdSurface = mCache.getSurface(&src);
    if (vdSurface) {
        canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src,
                              mutateProperties()->getBounds(), getPaint(),
                              SkCanvas::kFast_SrcRectConstraint);
                bounds, getPaint(), 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
@@ -575,8 +574,7 @@ void Tree::draw(SkCanvas* canvas) {
        int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
        int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
        canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight),
                               mutateProperties()->getBounds(), getPaint(),
                               SkCanvas::kFast_SrcRectConstraint);
                bounds, getPaint(), SkCanvas::kFast_SrcRectConstraint);
        mCache.clear();
        markDirty();
    }
+1 −1
Original line number Diff line number Diff line
@@ -644,7 +644,7 @@ public:
     * Draws VD cache into a canvas. This should always be called from RT and it works with Skia
     * pipelines only.
     */
    void draw(SkCanvas* canvas);
    void draw(SkCanvas* canvas, const SkRect& bounds);

    /**
     * Draws VD into a GPU backed surface.
+8 −3
Original line number Diff line number Diff line
@@ -124,14 +124,19 @@ void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,

class VectorDrawable : public SkDrawable {
public:
    VectorDrawable(VectorDrawableRoot* tree) : mRoot(tree) {}
    VectorDrawable(VectorDrawableRoot* tree)
            : mRoot(tree)
            , mBounds(tree->stagingProperties()->getBounds()) {}

protected:
    virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
    virtual void onDraw(SkCanvas* canvas) override { mRoot->draw(canvas); }
    virtual SkRect onGetBounds() override { return mBounds; }
    virtual void onDraw(SkCanvas* canvas) override {
        mRoot->draw(canvas, mBounds);
    }

private:
    sp<VectorDrawableRoot> mRoot;
    SkRect mBounds;
};

void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
+44 −1
Original line number Diff line number Diff line
@@ -1144,3 +1144,46 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
    canvas.drawDrawable(&drawable);
    EXPECT_EQ(6, canvas.getIndex());
}

// Draw a vector drawable twice but with different bounds and verify correct bounds are used.
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
    static const int CANVAS_WIDTH = 100;
    static const int CANVAS_HEIGHT = 200;
    class VectorDrawableTestCanvas : public TestCanvasBase {
    public:
        VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
        void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
                const SkPaint* paint, SrcRectConstraint constraint) override {
            const int index = mDrawCounter++;
            switch (index) {
                case 0:
                    EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT));
                    break;
                case 1:
                    EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH/2, CANVAS_HEIGHT));
                    break;
                default:
                    ADD_FAILURE();
            }
        }
    };

    VectorDrawable::Group* group = new VectorDrawable::Group();
    sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
    vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH/10, CANVAS_HEIGHT/10);

    auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
            [&](RenderProperties& props, SkiaRecordingCanvas& canvas) {
                vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH,
                        CANVAS_HEIGHT));
                canvas.drawVectorDrawable(vectorDrawable.get());
                vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH/2,
                        CANVAS_HEIGHT));
                canvas.drawVectorDrawable(vectorDrawable.get());
            });

    VectorDrawableTestCanvas canvas;
    RenderNodeDrawable drawable(node.get(), &canvas, true);
    canvas.drawDrawable(&drawable);
    EXPECT_EQ(2, canvas.mDrawCounter);
}