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 "RenderNode.h"
24 #include "TreeInfo.h"
25 #include "renderthread/CanvasContext.h"
26 #include "tests/common/TestUtils.h"
27 #include "utils/Color.h"
28
29 using namespace android;
30 using namespace android::uirenderer;
31 using namespace android::uirenderer::renderthread;
32
33 class ContextFactory : public android::uirenderer::IContextFactory {
34 public:
createAnimationContext(android::uirenderer::renderthread::TimeLord & clock)35 android::uirenderer::AnimationContext* createAnimationContext
36 (android::uirenderer::renderthread::TimeLord& clock) override {
37 return new android::uirenderer::AnimationContext(clock);
38 }
39 };
40
TEST(RenderNode,hasParents)41 TEST(RenderNode, hasParents) {
42 auto child = TestUtils::createNode(0, 0, 200, 400,
43 [](RenderProperties& props, Canvas& canvas) {
44 canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
45 });
46 auto parent = TestUtils::createNode(0, 0, 200, 400,
47 [&child](RenderProperties& props, Canvas& canvas) {
48 canvas.drawRenderNode(child.get());
49 });
50
51 TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
52
53 EXPECT_TRUE(child->hasParents()) << "Child node has no parent";
54 EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
55
56 TestUtils::recordNode(*parent, [](Canvas& canvas) {
57 canvas.drawColor(Color::Amber_500, SkBlendMode::kSrcOver);
58 });
59
60 EXPECT_TRUE(child->hasParents()) << "Child should still have a parent";
61 EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
62
63 TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
64
65 EXPECT_FALSE(child->hasParents()) << "Child should be removed";
66 EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
67 }
68
TEST(RenderNode,validity)69 TEST(RenderNode, validity) {
70 auto child = TestUtils::createNode(0, 0, 200, 400,
71 [](RenderProperties& props, Canvas& canvas) {
72 canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
73 });
74 auto parent = TestUtils::createNode(0, 0, 200, 400,
75 [&child](RenderProperties& props, Canvas& canvas) {
76 canvas.drawRenderNode(child.get());
77 });
78
79 EXPECT_TRUE(child->isValid());
80 EXPECT_TRUE(parent->isValid());
81 EXPECT_TRUE(child->nothingToDraw());
82 EXPECT_TRUE(parent->nothingToDraw());
83
84 TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
85
86 EXPECT_TRUE(child->isValid());
87 EXPECT_TRUE(parent->isValid());
88 EXPECT_FALSE(child->nothingToDraw());
89 EXPECT_FALSE(parent->nothingToDraw());
90
91 TestUtils::recordNode(*parent, [](Canvas& canvas) {
92 canvas.drawColor(Color::Amber_500, SkBlendMode::kSrcOver);
93 });
94
95 EXPECT_TRUE(child->isValid());
96 EXPECT_TRUE(parent->isValid());
97 EXPECT_FALSE(child->nothingToDraw());
98 EXPECT_FALSE(parent->nothingToDraw());
99
100 TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
101
102 EXPECT_FALSE(child->isValid());
103 EXPECT_TRUE(parent->isValid());
104 EXPECT_TRUE(child->nothingToDraw());
105 EXPECT_FALSE(parent->nothingToDraw());
106
107 TestUtils::recordNode(*child, [](Canvas& canvas) {
108 canvas.drawColor(Color::Amber_500, SkBlendMode::kSrcOver);
109 });
110
111 EXPECT_TRUE(child->isValid());
112 EXPECT_TRUE(child->nothingToDraw());
113
114 TestUtils::recordNode(*parent, [&child](Canvas& canvas) {
115 canvas.drawRenderNode(child.get());
116 });
117
118 TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
119
120 EXPECT_TRUE(child->isValid());
121 EXPECT_TRUE(parent->isValid());
122 EXPECT_FALSE(child->nothingToDraw());
123 EXPECT_FALSE(parent->nothingToDraw());
124
125 parent->destroyHardwareResources();
126
127 EXPECT_FALSE(child->isValid());
128 EXPECT_FALSE(parent->isValid());
129 EXPECT_TRUE(child->nothingToDraw());
130 EXPECT_TRUE(parent->nothingToDraw());
131 }
132
TEST(RenderNode,multiTreeValidity)133 TEST(RenderNode, multiTreeValidity) {
134 auto child = TestUtils::createNode(0, 0, 200, 400,
135 [](RenderProperties& props, Canvas& canvas) {
136 canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
137 });
138 auto parent1 = TestUtils::createNode(0, 0, 200, 400,
139 [&child](RenderProperties& props, Canvas& canvas) {
140 canvas.drawRenderNode(child.get());
141 });
142 auto parent2 = TestUtils::createNode(0, 0, 200, 400,
143 [&child](RenderProperties& props, Canvas& canvas) {
144 canvas.drawRenderNode(child.get());
145 });
146
147 EXPECT_TRUE(child->isValid());
148 EXPECT_TRUE(parent1->isValid());
149 EXPECT_TRUE(parent2->isValid());
150 EXPECT_TRUE(child->nothingToDraw());
151 EXPECT_TRUE(parent1->nothingToDraw());
152 EXPECT_TRUE(parent2->nothingToDraw());
153
154 TestUtils::syncHierarchyPropertiesAndDisplayList(parent1);
155
156 EXPECT_TRUE(child->isValid());
157 EXPECT_TRUE(parent1->isValid());
158 EXPECT_TRUE(parent2->isValid());
159 EXPECT_FALSE(child->nothingToDraw());
160 EXPECT_FALSE(parent1->nothingToDraw());
161 EXPECT_TRUE(parent2->nothingToDraw());
162
163 TestUtils::syncHierarchyPropertiesAndDisplayList(parent2);
164
165 EXPECT_TRUE(child->isValid());
166 EXPECT_TRUE(parent1->isValid());
167 EXPECT_TRUE(parent2->isValid());
168 EXPECT_FALSE(child->nothingToDraw());
169 EXPECT_FALSE(parent1->nothingToDraw());
170 EXPECT_FALSE(parent2->nothingToDraw());
171
172 TestUtils::recordNode(*parent1, [](Canvas& canvas) {
173 canvas.drawColor(Color::Amber_500, SkBlendMode::kSrcOver);
174 });
175
176 TestUtils::syncHierarchyPropertiesAndDisplayList(parent1);
177
178 EXPECT_TRUE(child->isValid());
179 EXPECT_TRUE(parent1->isValid());
180 EXPECT_TRUE(parent2->isValid());
181 EXPECT_FALSE(child->nothingToDraw());
182 EXPECT_FALSE(parent1->nothingToDraw());
183 EXPECT_FALSE(parent2->nothingToDraw());
184
185 TestUtils::recordNode(*parent2, [](Canvas& canvas) {
186 canvas.drawColor(Color::Amber_500, SkBlendMode::kSrcOver);
187 });
188
189 TestUtils::syncHierarchyPropertiesAndDisplayList(parent2);
190
191 EXPECT_FALSE(child->isValid());
192 EXPECT_TRUE(parent1->isValid());
193 EXPECT_TRUE(parent2->isValid());
194 EXPECT_TRUE(child->nothingToDraw());
195 EXPECT_FALSE(parent1->nothingToDraw());
196 EXPECT_FALSE(parent2->nothingToDraw());
197
198 TestUtils::recordNode(*child, [](Canvas& canvas) {
199 canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
200 });
201 TestUtils::syncHierarchyPropertiesAndDisplayList(child);
202
203 TestUtils::recordNode(*parent1, [&child](Canvas& canvas) {
204 canvas.drawRenderNode(child.get());
205 });
206 TestUtils::syncHierarchyPropertiesAndDisplayList(parent1);
207
208 TestUtils::recordNode(*parent2, [&child](Canvas& canvas) {
209 canvas.drawRenderNode(child.get());
210 });
211 TestUtils::syncHierarchyPropertiesAndDisplayList(parent2);
212
213 EXPECT_TRUE(child->isValid());
214 EXPECT_TRUE(parent1->isValid());
215 EXPECT_TRUE(parent2->isValid());
216 EXPECT_FALSE(child->nothingToDraw());
217 EXPECT_FALSE(parent1->nothingToDraw());
218 EXPECT_FALSE(parent2->nothingToDraw());
219
220 parent1->destroyHardwareResources();
221
222 EXPECT_TRUE(child->isValid());
223 EXPECT_FALSE(parent1->isValid());
224 EXPECT_TRUE(parent2->isValid());
225 EXPECT_FALSE(child->nothingToDraw());
226 EXPECT_TRUE(parent1->nothingToDraw());
227 EXPECT_FALSE(parent2->nothingToDraw());
228
229 parent2->destroyHardwareResources();
230
231 EXPECT_FALSE(child->isValid());
232 EXPECT_FALSE(parent1->isValid());
233 EXPECT_FALSE(parent2->isValid());
234 EXPECT_TRUE(child->nothingToDraw());
235 EXPECT_TRUE(parent1->nothingToDraw());
236 EXPECT_TRUE(parent2->nothingToDraw());
237 }
238
TEST(RenderNode,releasedCallback)239 TEST(RenderNode, releasedCallback) {
240 class DecRefOnReleased : public GlFunctorLifecycleListener {
241 public:
242 explicit DecRefOnReleased(int* refcnt) : mRefCnt(refcnt) {}
243 void onGlFunctorReleased(Functor* functor) override {
244 *mRefCnt -= 1;
245 }
246 private:
247 int* mRefCnt;
248 };
249
250 int refcnt = 0;
251 sp<DecRefOnReleased> listener(new DecRefOnReleased(&refcnt));
252 Functor noopFunctor;
253
254 auto node = TestUtils::createNode(0, 0, 200, 400,
255 [&](RenderProperties& props, Canvas& canvas) {
256 refcnt++;
257 canvas.callDrawGLFunction(&noopFunctor, listener.get());
258 });
259 TestUtils::syncHierarchyPropertiesAndDisplayList(node);
260 EXPECT_EQ(1, refcnt);
261
262 TestUtils::recordNode(*node, [&](Canvas& canvas) {
263 refcnt++;
264 canvas.callDrawGLFunction(&noopFunctor, listener.get());
265 });
266 EXPECT_EQ(2, refcnt);
267
268 TestUtils::syncHierarchyPropertiesAndDisplayList(node);
269 EXPECT_EQ(1, refcnt);
270
271 TestUtils::recordNode(*node, [](Canvas& canvas) {});
272 EXPECT_EQ(1, refcnt);
273 TestUtils::syncHierarchyPropertiesAndDisplayList(node);
274 EXPECT_EQ(0, refcnt);
275 }
276
RENDERTHREAD_TEST(RenderNode,prepareTree_nullableDisplayList)277 RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) {
278 auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
279 ContextFactory contextFactory;
280 std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
281 renderThread, false, rootNode.get(), &contextFactory));
282 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
283 DamageAccumulator damageAccumulator;
284 info.damageAccumulator = &damageAccumulator;
285
286 {
287 auto nonNullDLNode = TestUtils::createNode(0, 0, 200, 400,
288 [](RenderProperties& props, Canvas& canvas) {
289 canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
290 });
291 TestUtils::syncHierarchyPropertiesAndDisplayList(nonNullDLNode);
292 EXPECT_TRUE(nonNullDLNode->getDisplayList());
293 nonNullDLNode->prepareTree(info);
294 }
295
296 {
297 auto nullDLNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
298 TestUtils::syncHierarchyPropertiesAndDisplayList(nullDLNode);
299 EXPECT_FALSE(nullDLNode->getDisplayList());
300 nullDLNode->prepareTree(info);
301 }
302
303 canvasContext->destroy();
304 }
305
RENDERTHREAD_TEST(RenderNode,prepareTree_HwLayer_AVD_enqueueDamage)306 RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) {
307
308 VectorDrawable::Group* group = new VectorDrawable::Group();
309 sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
310
311 auto rootNode = TestUtils::createNode(0, 0, 200, 400,
312 [&](RenderProperties& props, Canvas& canvas) {
313 canvas.drawVectorDrawable(vectorDrawable.get());
314 });
315 ContextFactory contextFactory;
316 std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
317 renderThread, false, rootNode.get(), &contextFactory));
318 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
319 DamageAccumulator damageAccumulator;
320 LayerUpdateQueue layerUpdateQueue;
321 info.damageAccumulator = &damageAccumulator;
322 info.layerUpdateQueue = &layerUpdateQueue;
323
324 // Put node on HW layer
325 rootNode->mutateStagingProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
326
327 TestUtils::syncHierarchyPropertiesAndDisplayList(rootNode);
328 rootNode->prepareTree(info);
329
330 // Check that the VD is in the dislay list, and the layer update queue contains the correct
331 // damage rect.
332 EXPECT_TRUE(rootNode->getDisplayList()->hasVectorDrawables());
333 EXPECT_FALSE(info.layerUpdateQueue->entries().empty());
334 EXPECT_EQ(rootNode.get(), info.layerUpdateQueue->entries().at(0).renderNode.get());
335 EXPECT_EQ(uirenderer::Rect(0, 0, 200, 400), info.layerUpdateQueue->entries().at(0).damage);
336 canvasContext->destroy();
337 }
338