SkiaDisplayListTests.cpp revision 2de950d5a8b47c7b4648ada1b1260ce4b7342798
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gtest/gtest.h>
18#include <VectorDrawable.h>
19
20#include "AnimationContext.h"
21#include "DamageAccumulator.h"
22#include "IContextFactory.h"
23#include "pipeline/skia/SkiaDisplayList.h"
24#include "renderthread/CanvasContext.h"
25#include "tests/common/TestUtils.h"
26
27using namespace android;
28using namespace android::uirenderer;
29using namespace android::uirenderer::renderthread;
30using namespace android::uirenderer::skiapipeline;
31
32TEST(SkiaDisplayList, create) {
33    SkRect bounds = SkRect::MakeWH(200, 200);
34    SkiaDisplayList skiaDL(bounds);
35    ASSERT_TRUE(skiaDL.isEmpty());
36    ASSERT_FALSE(skiaDL.mProjectionReceiver);
37    ASSERT_EQ(skiaDL.mDrawable->getBounds(), bounds);
38}
39
40TEST(SkiaDisplayList, reset) {
41    SkRect bounds = SkRect::MakeWH(200, 200);
42    SkiaDisplayList skiaDL(bounds);
43
44    SkCanvas dummyCanvas;
45    RenderNodeDrawable drawable(nullptr, &dummyCanvas);
46    skiaDL.mChildNodes.emplace_back(nullptr, &dummyCanvas);
47    skiaDL.mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas);
48    skiaDL.mMutableImages.push_back(nullptr);
49    skiaDL.mVectorDrawables.push_back(nullptr);
50    skiaDL.mDrawable->drawAnnotation(bounds, "testAnnotation", nullptr);
51    skiaDL.mProjectionReceiver = &drawable;
52
53    ASSERT_EQ(skiaDL.mDrawable->getBounds(), bounds);
54    ASSERT_FALSE(skiaDL.mChildNodes.empty());
55    ASSERT_FALSE(skiaDL.mChildFunctors.empty());
56    ASSERT_FALSE(skiaDL.mMutableImages.empty());
57    ASSERT_FALSE(skiaDL.mVectorDrawables.empty());
58    ASSERT_FALSE(skiaDL.isEmpty());
59    ASSERT_TRUE(skiaDL.mProjectionReceiver);
60
61    bounds = SkRect::MakeWH(100, 100);
62    skiaDL.reset(bounds);
63
64    ASSERT_EQ(skiaDL.mDrawable->getBounds(), bounds);
65    ASSERT_TRUE(skiaDL.mChildNodes.empty());
66    ASSERT_TRUE(skiaDL.mChildFunctors.empty());
67    ASSERT_TRUE(skiaDL.mMutableImages.empty());
68    ASSERT_TRUE(skiaDL.mVectorDrawables.empty());
69    ASSERT_TRUE(skiaDL.isEmpty());
70    ASSERT_FALSE(skiaDL.mProjectionReceiver);
71}
72
73TEST(SkiaDisplayList, reuseDisplayList) {
74    sp<RenderNode> renderNode = new RenderNode();
75    std::unique_ptr<SkiaDisplayList> availableList;
76
77    // no list has been attached so it should return a nullptr
78    availableList = renderNode->detachAvailableList();
79    ASSERT_EQ(availableList.get(), nullptr);
80
81    // attach a displayList for reuse
82    SkiaDisplayList skiaDL(SkRect::MakeWH(200, 200));
83    ASSERT_TRUE(skiaDL.reuseDisplayList(renderNode.get(), nullptr));
84
85    // detach the list that you just attempted to reuse
86    availableList = renderNode->detachAvailableList();
87    ASSERT_EQ(availableList.get(), &skiaDL);
88    availableList.release(); // prevents an invalid free since our DL is stack allocated
89
90    // after detaching there should return no available list
91    availableList = renderNode->detachAvailableList();
92    ASSERT_EQ(availableList.get(), nullptr);
93}
94
95TEST(SkiaDisplayList, syncContexts) {
96    SkRect bounds = SkRect::MakeWH(200, 200);
97    SkiaDisplayList skiaDL(bounds);
98
99    SkCanvas dummyCanvas;
100    TestUtils::MockFunctor functor;
101    skiaDL.mChildFunctors.emplace_back(&functor, nullptr, &dummyCanvas);
102
103    VectorDrawableRoot vectorDrawable(new VectorDrawable::Group());
104    vectorDrawable.mutateStagingProperties()->setBounds(bounds);
105    skiaDL.mVectorDrawables.push_back(&vectorDrawable);
106
107    // ensure that the functor and vectorDrawable are properly synced
108    skiaDL.syncContents();
109
110    ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeSync);
111    ASSERT_EQ(vectorDrawable.mutateProperties()->getBounds(), bounds);
112}
113
114class ContextFactory : public IContextFactory {
115public:
116    virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
117        return new AnimationContext(clock);
118    }
119};
120
121RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
122    auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
123    ContextFactory contextFactory;
124    std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
125            renderThread, false, rootNode.get(), &contextFactory));
126    TreeInfo info(TreeInfo::MODE_FULL, *canvasContext.get());
127    DamageAccumulator damageAccumulator;
128    info.damageAccumulator = &damageAccumulator;
129
130    SkiaDisplayList skiaDL(SkRect::MakeWH(200, 200));
131
132    // prepare with a clean VD
133    VectorDrawableRoot cleanVD(new VectorDrawable::Group());
134    skiaDL.mVectorDrawables.push_back(&cleanVD);
135    cleanVD.getBitmapUpdateIfDirty(); // this clears the dirty bit
136
137    ASSERT_FALSE(cleanVD.isDirty());
138    ASSERT_FALSE(cleanVD.getPropertyChangeWillBeConsumed());
139    TestUtils::MockTreeObserver observer;
140    ASSERT_FALSE(skiaDL.prepareListAndChildren(observer, info, false,
141            [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
142    ASSERT_TRUE(cleanVD.getPropertyChangeWillBeConsumed());
143
144    // prepare again this time adding a dirty VD
145    VectorDrawableRoot dirtyVD(new VectorDrawable::Group());
146    skiaDL.mVectorDrawables.push_back(&dirtyVD);
147
148    ASSERT_TRUE(dirtyVD.isDirty());
149    ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed());
150    ASSERT_TRUE(skiaDL.prepareListAndChildren(observer, info, false,
151            [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
152    ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed());
153
154    // prepare again this time adding a RenderNode and a callback
155    sp<RenderNode> renderNode = new RenderNode();
156    TreeInfo* infoPtr = &info;
157    SkCanvas dummyCanvas;
158    skiaDL.mChildNodes.emplace_back(renderNode.get(), &dummyCanvas);
159    bool hasRun = false;
160    ASSERT_TRUE(skiaDL.prepareListAndChildren(observer, info, false,
161            [&hasRun, renderNode, infoPtr](RenderNode* n, TreeObserver& observer, TreeInfo& i, bool r) {
162        hasRun = true;
163        ASSERT_EQ(renderNode.get(), n);
164        ASSERT_EQ(infoPtr, &i);
165        ASSERT_FALSE(r);
166    }));
167    ASSERT_TRUE(hasRun);
168
169    canvasContext->destroy();
170}
171
172TEST(SkiaDisplayList, updateChildren) {
173    SkRect bounds = SkRect::MakeWH(200, 200);
174    SkiaDisplayList skiaDL(bounds);
175
176    sp<RenderNode> renderNode = new RenderNode();
177    SkCanvas dummyCanvas;
178    skiaDL.mChildNodes.emplace_back(renderNode.get(), &dummyCanvas);
179    skiaDL.updateChildren([renderNode](RenderNode* n) {
180        ASSERT_EQ(renderNode.get(), n);
181    });
182}
183