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: 35 android::uirenderer::AnimationContext* createAnimationContext( 36 android::uirenderer::renderthread::TimeLord& clock) override { 37 return new android::uirenderer::AnimationContext(clock); 38 } 39 }; 40 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 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 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 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 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? 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