diff options
author | Leon Scroggins <scroggo@google.com> | 2019-04-16 12:15:16 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-04-16 12:15:16 +0000 |
commit | 949305fe52816c6a51454cc8aee56fee8486eeac (patch) | |
tree | 7d8917b4823809584d316d9ab115b92e9eb1ce0d /libs/hwui/tests | |
parent | 083190633a61edd861de7255fe43bc1570c84d25 (diff) | |
parent | 6c5864c098aa72e88cb8512255d3c01a449a372e (diff) |
Merge "Do not cache AVDs that are off screen" into qt-dev
Diffstat (limited to 'libs/hwui/tests')
-rw-r--r-- | libs/hwui/tests/unit/SkiaDisplayListTests.cpp | 184 |
1 files changed, 177 insertions, 7 deletions
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp index 1b4cf7e144bd..6fb164a99ae4 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -23,6 +23,7 @@ #include "pipeline/skia/GLFunctorDrawable.h" #include "pipeline/skia/SkiaDisplayList.h" #include "renderthread/CanvasContext.h" +#include "tests/common/TestContext.h" #include "tests/common/TestUtils.h" using namespace android; @@ -50,13 +51,13 @@ TEST(SkiaDisplayList, reset) { GLFunctorDrawable functorDrawable(nullptr, nullptr, &dummyCanvas); skiaDL->mChildFunctors.push_back(&functorDrawable); skiaDL->mMutableImages.push_back(nullptr); - skiaDL->mVectorDrawables.push_back(nullptr); + skiaDL->appendVD(nullptr); skiaDL->mProjectionReceiver = &drawable; ASSERT_FALSE(skiaDL->mChildNodes.empty()); ASSERT_FALSE(skiaDL->mChildFunctors.empty()); ASSERT_FALSE(skiaDL->mMutableImages.empty()); - ASSERT_FALSE(skiaDL->mVectorDrawables.empty()); + ASSERT_TRUE(skiaDL->hasVectorDrawables()); ASSERT_FALSE(skiaDL->isEmpty()); ASSERT_TRUE(skiaDL->mProjectionReceiver); @@ -65,7 +66,7 @@ TEST(SkiaDisplayList, reset) { ASSERT_TRUE(skiaDL->mChildNodes.empty()); ASSERT_TRUE(skiaDL->mChildFunctors.empty()); ASSERT_TRUE(skiaDL->mMutableImages.empty()); - ASSERT_TRUE(skiaDL->mVectorDrawables.empty()); + ASSERT_FALSE(skiaDL->hasVectorDrawables()); ASSERT_TRUE(skiaDL->isEmpty()); ASSERT_FALSE(skiaDL->mProjectionReceiver); } @@ -110,7 +111,7 @@ TEST(SkiaDisplayList, syncContexts) { SkRect bounds = SkRect::MakeWH(200, 200); VectorDrawableRoot vectorDrawable(new VectorDrawable::Group()); vectorDrawable.mutateStagingProperties()->setBounds(bounds); - skiaDL.mVectorDrawables.push_back(&vectorDrawable); + skiaDL.appendVD(&vectorDrawable); // ensure that the functor and vectorDrawable are properly synced TestUtils::runOnRenderThread([&](auto&) { @@ -149,9 +150,14 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) { SkiaDisplayList skiaDL; + // The VectorDrawableRoot needs to have bounds on screen (and therefore not + // empty) in order to have PropertyChangeWillBeConsumed set. + const auto bounds = SkRect::MakeIWH(100, 100); + // prepare with a clean VD VectorDrawableRoot cleanVD(new VectorDrawable::Group()); - skiaDL.mVectorDrawables.push_back(&cleanVD); + cleanVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&cleanVD); cleanVD.getBitmapUpdateIfDirty(); // this clears the dirty bit ASSERT_FALSE(cleanVD.isDirty()); @@ -159,11 +165,12 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) { TestUtils::MockTreeObserver observer; ASSERT_FALSE(skiaDL.prepareListAndChildren(observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); - ASSERT_TRUE(cleanVD.getPropertyChangeWillBeConsumed()); + ASSERT_FALSE(cleanVD.getPropertyChangeWillBeConsumed()); // prepare again this time adding a dirty VD VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); - skiaDL.mVectorDrawables.push_back(&dirtyVD); + dirtyVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&dirtyVD); ASSERT_TRUE(dirtyVD.isDirty()); ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); @@ -191,6 +198,169 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) { canvasContext->destroy(); } +RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren_vdOffscreen) { + auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr); + ContextFactory contextFactory; + std::unique_ptr<CanvasContext> canvasContext( + CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory)); + + // Set up a Surface so that we can position the VectorDrawable offscreen. + test::TestContext testContext; + testContext.setRenderOffscreen(true); + auto surface = testContext.surface(); + int width, height; + surface->query(NATIVE_WINDOW_WIDTH, &width); + surface->query(NATIVE_WINDOW_HEIGHT, &height); + canvasContext->setSurface(std::move(surface)); + + TreeInfo info(TreeInfo::MODE_FULL, *canvasContext.get()); + DamageAccumulator damageAccumulator; + info.damageAccumulator = &damageAccumulator; + + // The VectorDrawableRoot needs to have bounds on screen (and therefore not + // empty) in order to have PropertyChangeWillBeConsumed set. + const auto bounds = SkRect::MakeIWH(100, 100); + + for (const SkRect b : {bounds.makeOffset(width, 0), + bounds.makeOffset(0, height), + bounds.makeOffset(-bounds.width(), 0), + bounds.makeOffset(0, -bounds.height())}) { + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(b); + skiaDL.appendVD(&dirtyVD); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + } + + // The DamageAccumulator's transform can also result in the + // VectorDrawableRoot being offscreen. + for (const SkISize translate : { SkISize{width, 0}, + SkISize{0, height}, + SkISize{-width, 0}, + SkISize{0, -height}}) { + Matrix4 mat4; + mat4.translate(translate.fWidth, translate.fHeight); + damageAccumulator.pushTransform(&mat4); + + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&dirtyVD); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + damageAccumulator.popTransform(); + } + + // Another way to be offscreen: a matrix from the draw call. + for (const SkMatrix translate : { SkMatrix::MakeTrans(width, 0), + SkMatrix::MakeTrans(0, height), + SkMatrix::MakeTrans(-width, 0), + SkMatrix::MakeTrans(0, -height)}) { + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&dirtyVD, translate); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + } + + // Verify that the matrices are combined in the right order. + { + // Rotate and then translate, so the VD is offscreen. + Matrix4 mat4; + mat4.loadRotate(180); + damageAccumulator.pushTransform(&mat4); + + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + SkMatrix translate = SkMatrix::MakeTrans(50, 50); + skiaDL.appendVD(&dirtyVD, translate); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + damageAccumulator.popTransform(); + } + { + // Switch the order of rotate and translate, so it is on screen. + Matrix4 mat4; + mat4.translate(50, 50); + damageAccumulator.pushTransform(&mat4); + + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + SkMatrix rotate; + rotate.setRotate(180); + skiaDL.appendVD(&dirtyVD, rotate); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_TRUE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed()); + damageAccumulator.popTransform(); + } + { + // An AVD that is larger than the screen. + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(SkRect::MakeLTRB(-1, -1, width + 1, height + 1)); + skiaDL.appendVD(&dirtyVD); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_TRUE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed()); + } + { + // An AVD whose bounds are not a rectangle after applying a matrix. + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + SkMatrix mat; + mat.setRotate(45, 50, 50); + skiaDL.appendVD(&dirtyVD, mat); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_TRUE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed()); + } +} + TEST(SkiaDisplayList, updateChildren) { SkiaDisplayList skiaDL; |