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