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
This commit is contained in:
Stan Iliev
2018-02-07 14:07:30 -05:00
parent bc48bd8f61
commit 65e678fdb1
4 changed files with 56 additions and 10 deletions

View File

@@ -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();
}

View File

@@ -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.

View File

@@ -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) {

View File

@@ -1143,4 +1143,47 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
RenderNodeDrawable drawable(parent.get(), &canvas, false);
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);
}