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
27 using namespace android;
28 using namespace android::uirenderer;
29 using namespace android::uirenderer::renderthread;
30 using namespace android::uirenderer::skiapipeline;
31
TEST(SkiaDisplayList,create)32 TEST(SkiaDisplayList, create) {
33 SkiaDisplayList skiaDL;
34 ASSERT_TRUE(skiaDL.isEmpty());
35 ASSERT_FALSE(skiaDL.mProjectionReceiver);
36 }
37
TEST(SkiaDisplayList,reset)38 TEST(SkiaDisplayList, reset) {
39 SkiaDisplayList skiaDL;
40
41 SkCanvas dummyCanvas;
42 RenderNodeDrawable drawable(nullptr, &dummyCanvas);
43 skiaDL.mChildNodes.emplace_back(nullptr, &dummyCanvas);
44 skiaDL.mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas);
45 skiaDL.mMutableImages.push_back(nullptr);
46 skiaDL.mVectorDrawables.push_back(nullptr);
47 skiaDL.mDisplayList.drawAnnotation(SkRect::MakeWH(200, 200), "testAnnotation", nullptr);
48 skiaDL.mProjectionReceiver = &drawable;
49
50 ASSERT_FALSE(skiaDL.mChildNodes.empty());
51 ASSERT_FALSE(skiaDL.mChildFunctors.empty());
52 ASSERT_FALSE(skiaDL.mMutableImages.empty());
53 ASSERT_FALSE(skiaDL.mVectorDrawables.empty());
54 ASSERT_FALSE(skiaDL.isEmpty());
55 ASSERT_TRUE(skiaDL.mProjectionReceiver);
56
57 skiaDL.reset();
58
59 ASSERT_TRUE(skiaDL.mChildNodes.empty());
60 ASSERT_TRUE(skiaDL.mChildFunctors.empty());
61 ASSERT_TRUE(skiaDL.mMutableImages.empty());
62 ASSERT_TRUE(skiaDL.mVectorDrawables.empty());
63 ASSERT_TRUE(skiaDL.isEmpty());
64 ASSERT_FALSE(skiaDL.mProjectionReceiver);
65 }
66
TEST(SkiaDisplayList,reuseDisplayList)67 TEST(SkiaDisplayList, reuseDisplayList) {
68 sp<RenderNode> renderNode = new RenderNode();
69 std::unique_ptr<SkiaDisplayList> availableList;
70
71 // no list has been attached so it should return a nullptr
72 availableList = renderNode->detachAvailableList();
73 ASSERT_EQ(availableList.get(), nullptr);
74
75 // attach a displayList for reuse
76 SkiaDisplayList skiaDL;
77 ASSERT_TRUE(skiaDL.reuseDisplayList(renderNode.get(), nullptr));
78
79 // detach the list that you just attempted to reuse
80 availableList = renderNode->detachAvailableList();
81 ASSERT_EQ(availableList.get(), &skiaDL);
82 availableList.release(); // prevents an invalid free since our DL is stack allocated
83
84 // after detaching there should return no available list
85 availableList = renderNode->detachAvailableList();
86 ASSERT_EQ(availableList.get(), nullptr);
87 }
88
TEST(SkiaDisplayList,syncContexts)89 TEST(SkiaDisplayList, syncContexts) {
90 SkiaDisplayList skiaDL;
91
92 SkCanvas dummyCanvas;
93 TestUtils::MockFunctor functor;
94 skiaDL.mChildFunctors.emplace_back(&functor, nullptr, &dummyCanvas);
95
96 SkRect bounds = SkRect::MakeWH(200, 200);
97 VectorDrawableRoot vectorDrawable(new VectorDrawable::Group());
98 vectorDrawable.mutateStagingProperties()->setBounds(bounds);
99 skiaDL.mVectorDrawables.push_back(&vectorDrawable);
100
101 // ensure that the functor and vectorDrawable are properly synced
102 skiaDL.syncContents();
103
104 ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeSync);
105 ASSERT_EQ(vectorDrawable.mutateProperties()->getBounds(), bounds);
106 }
107
108 class ContextFactory : public IContextFactory {
109 public:
createAnimationContext(renderthread::TimeLord & clock)110 virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
111 return new AnimationContext(clock);
112 }
113 };
114
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList,prepareListAndChildren)115 RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
116 auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
117 ContextFactory contextFactory;
118 std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
119 renderThread, false, rootNode.get(), &contextFactory));
120 TreeInfo info(TreeInfo::MODE_FULL, *canvasContext.get());
121 DamageAccumulator damageAccumulator;
122 info.damageAccumulator = &damageAccumulator;
123
124 SkiaDisplayList skiaDL;
125
126 // prepare with a clean VD
127 VectorDrawableRoot cleanVD(new VectorDrawable::Group());
128 skiaDL.mVectorDrawables.push_back(&cleanVD);
129 cleanVD.getBitmapUpdateIfDirty(); // this clears the dirty bit
130
131 ASSERT_FALSE(cleanVD.isDirty());
132 ASSERT_FALSE(cleanVD.getPropertyChangeWillBeConsumed());
133 TestUtils::MockTreeObserver observer;
134 ASSERT_FALSE(skiaDL.prepareListAndChildren(observer, info, false,
135 [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
136 ASSERT_TRUE(cleanVD.getPropertyChangeWillBeConsumed());
137
138 // prepare again this time adding a dirty VD
139 VectorDrawableRoot dirtyVD(new VectorDrawable::Group());
140 skiaDL.mVectorDrawables.push_back(&dirtyVD);
141
142 ASSERT_TRUE(dirtyVD.isDirty());
143 ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed());
144 ASSERT_TRUE(skiaDL.prepareListAndChildren(observer, info, false,
145 [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
146 ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed());
147
148 // prepare again this time adding a RenderNode and a callback
149 sp<RenderNode> renderNode = new RenderNode();
150 TreeInfo* infoPtr = &info;
151 SkCanvas dummyCanvas;
152 skiaDL.mChildNodes.emplace_back(renderNode.get(), &dummyCanvas);
153 bool hasRun = false;
154 ASSERT_TRUE(skiaDL.prepareListAndChildren(observer, info, false,
155 [&hasRun, renderNode, infoPtr](RenderNode* n, TreeObserver& observer, TreeInfo& i, bool r) {
156 hasRun = true;
157 ASSERT_EQ(renderNode.get(), n);
158 ASSERT_EQ(infoPtr, &i);
159 ASSERT_FALSE(r);
160 }));
161 ASSERT_TRUE(hasRun);
162
163 canvasContext->destroy();
164 }
165
TEST(SkiaDisplayList,updateChildren)166 TEST(SkiaDisplayList, updateChildren) {
167 SkiaDisplayList skiaDL;
168
169 sp<RenderNode> renderNode = new RenderNode();
170 SkCanvas dummyCanvas;
171 skiaDL.mChildNodes.emplace_back(renderNode.get(), &dummyCanvas);
172 skiaDL.updateChildren([renderNode](RenderNode* n) {
173 ASSERT_EQ(renderNode.get(), n);
174 });
175 }
176