1 /* 2 * Copyright 2011, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 28 #include <gtest/gtest.h> 29 30 #include "SkRefCnt.h" 31 #include "TransformationMatrix.h" 32 #include "IntRect.h" 33 #include "Layer.h" 34 #include "LayerAndroid.h" 35 #include "TreeManager.h" 36 #include "SkPicture.h" 37 38 #include <cutils/log.h> 39 #include <wtf/text/CString.h> 40 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TreeManager_test", __VA_ARGS__) 41 42 namespace WebCore { 43 44 // Used for testing simple cases for tree painting, drawing, swapping 45 class TestLayer : public Layer { 46 public: 47 TestLayer() 48 : m_isDrawing(false) 49 , m_isPainting(false) 50 , m_isDonePainting(false) 51 , m_drawCount(0) 52 {} 53 54 bool m_isDrawing; 55 bool m_isPainting; 56 bool m_isDonePainting; 57 double m_drawCount; 58 59 bool drawGL(WebCore::IntRect& viewRect, SkRect& visibleRect, float scale) { 60 m_drawCount++; 61 return false; 62 } 63 64 bool isReady() { 65 return m_isDonePainting; 66 } 67 68 void setIsDrawing(bool isDrawing) { 69 m_isDrawing = isDrawing; 70 if (isDrawing) 71 m_isPainting = false; 72 } 73 74 void setIsPainting(Layer* drawingTree) { 75 m_isPainting = true; 76 m_isDonePainting = false; 77 setIsDrawing(false); 78 } 79 }; 80 81 // Used for testing complex trees, and painted surfaces 82 class TestLayerAndroid : public LayerAndroid { 83 public: 84 TestLayerAndroid(SkPicture* picture) : LayerAndroid(picture) 85 , m_isDonePainting(false) 86 , m_drawCount(0) 87 {} 88 89 TestLayerAndroid(const TestLayerAndroid& testLayer) : LayerAndroid(testLayer) 90 , m_isDonePainting(testLayer.m_isDonePainting) 91 , m_drawCount(testLayer.m_drawCount) 92 { 93 XLOGC("copying TLA %p as %p", &testLayer, this); 94 } 95 96 bool m_isDonePainting; 97 double m_drawCount; 98 99 bool drawGL(WebCore::IntRect& viewRect, SkRect& visibleRect, float scale) { 100 m_drawCount++; 101 return false; 102 } 103 104 bool isReady() { 105 return m_isDonePainting; 106 } 107 108 LayerAndroid* copy() const { return new TestLayerAndroid(*this); } 109 }; 110 111 class TreeManagerTest : public testing::Test { 112 protected: 113 IntRect m_iRect; 114 SkRect m_sRect; 115 double m_scale; 116 117 void allocLayerWithPicture(bool useTestLayer, LayerAndroid** layerHandle, SkPicture** pictureHandle) { 118 SkPicture* p = new SkPicture(); 119 p->beginRecording(16,16, 0); 120 p->endRecording(); 121 122 LayerAndroid* l; 123 if (useTestLayer) 124 l = new TestLayerAndroid(p); 125 else 126 l = new LayerAndroid(p); 127 l->setSize(16, 16); 128 SkSafeUnref(p); // layer takes sole ownership of picture 129 130 if (layerHandle) 131 *layerHandle = l; 132 if (pictureHandle) 133 *pictureHandle = p; 134 } 135 136 bool drawGL(TreeManager& manager, bool* swappedPtr) { 137 // call draw gl here in one place, so that when its parameters change, 138 // the tests only have to be updated in one place 139 return manager.drawGL(0, m_iRect, m_sRect, m_scale, false, swappedPtr, 0); 140 } 141 142 virtual void SetUp() { 143 m_iRect = IntRect(0, 0, 1, 1); 144 m_sRect = SkRect::MakeWH(1, 1); 145 m_scale = 1.0; 146 } 147 virtual void TearDown() { } 148 }; 149 150 TEST_F(TreeManagerTest, EmptyTree_DoesntRedraw) { 151 TreeManager manager; 152 153 drawGL(manager, false); 154 } 155 156 TEST_F(TreeManagerTest, OneLayerTree_SingleTree_SwapCheck) { 157 TreeManager manager; 158 TestLayer layer; 159 160 // initialize with tree, should be painting 161 manager.updateWithTree(&layer, true); 162 163 ASSERT_TRUE(layer.m_isPainting); 164 ASSERT_FALSE(layer.m_isDrawing); 165 166 // should not call swap, and return true since content isn't done 167 for (int i = 1; i < 6; i++) { 168 bool swapped = false; 169 ASSERT_TRUE(drawGL(manager, &swapped)); 170 ASSERT_FALSE(swapped); 171 ASSERT_EQ(layer.m_drawCount, 0); 172 } 173 174 layer.m_isDonePainting = true; 175 176 // swap content, should return false since no new picture 177 bool swapped = false; 178 ASSERT_FALSE(drawGL(manager, &swapped)); 179 ASSERT_TRUE(swapped); 180 ASSERT_EQ(layer.m_drawCount, 1); // verify layer drawn 181 } 182 183 TEST_F(TreeManagerTest, OneLayerTree_SingleTree_RefCountCorrectly) { 184 TreeManager manager; 185 TestLayer* layer = new TestLayer(); 186 ASSERT_EQ(layer->getRefCnt(), 1); 187 188 // initialize with tree, should be painting 189 manager.updateWithTree(layer, true); 190 ASSERT_EQ(layer->getRefCnt(), 2); 191 192 layer->m_isDonePainting = true; 193 ASSERT_FALSE(drawGL(manager, 0)); 194 195 // should be drawing 196 ASSERT_EQ(layer->getRefCnt(), 2); 197 198 manager.updateWithTree(0, false); 199 200 // layer should be removed 201 ASSERT_EQ(layer->getRefCnt(), 1); 202 SkSafeUnref(layer); 203 } 204 205 TEST_F(TreeManagerTest, OneLayerTree_TwoTreeFlush_PaintDrawRefCheck) { 206 TreeManager manager; 207 TestLayer* firstLayer = new TestLayer(); 208 TestLayer* secondLayer = new TestLayer(); 209 ASSERT_EQ(firstLayer->getRefCnt(), 1); 210 ASSERT_EQ(secondLayer->getRefCnt(), 1); 211 212 ///// ENQUEUE 2 TREES 213 214 // first starts painting 215 manager.updateWithTree(firstLayer, true); 216 ASSERT_TRUE(firstLayer->m_isPainting); 217 ASSERT_FALSE(firstLayer->m_isDrawing); 218 219 // second is queued 220 manager.updateWithTree(secondLayer, false); 221 ASSERT_FALSE(secondLayer->m_isPainting); 222 ASSERT_FALSE(secondLayer->m_isDrawing); 223 224 // nothing changes 225 ASSERT_TRUE(drawGL(manager, 0)); 226 227 ////////// FIRST FINISHES PAINTING, SWAP THE TREES 228 229 firstLayer->m_isDonePainting = true; 230 bool swapped = false; 231 ASSERT_TRUE(drawGL(manager, &swapped)); 232 ASSERT_TRUE(swapped); 233 234 // first is drawing 235 ASSERT_EQ(firstLayer->m_drawCount, 1); 236 ASSERT_FALSE(firstLayer->m_isPainting); 237 ASSERT_TRUE(firstLayer->m_isDrawing); 238 ASSERT_EQ(firstLayer->getRefCnt(), 2); 239 240 // second is painting (and hasn't drawn) 241 ASSERT_EQ(secondLayer->m_drawCount, 0); 242 ASSERT_TRUE(secondLayer->m_isPainting); 243 ASSERT_FALSE(secondLayer->m_isDrawing); 244 ASSERT_EQ(secondLayer->getRefCnt(), 2); 245 246 ////////// SECOND FINISHES PAINTING, SWAP AGAIN 247 248 secondLayer->m_isDonePainting = true; 249 250 // draw again, swap, first should be deleted 251 swapped = false; 252 ASSERT_FALSE(drawGL(manager, &swapped)); // no painting layer 253 ASSERT_TRUE(swapped); 254 255 // first layer gone! 256 ASSERT_EQ(firstLayer->getRefCnt(), 1); 257 SkSafeUnref(firstLayer); 258 259 // second is drawing 260 ASSERT_EQ(secondLayer->m_drawCount, 1); 261 ASSERT_FALSE(secondLayer->m_isPainting); 262 ASSERT_TRUE(secondLayer->m_isDrawing); 263 ASSERT_EQ(secondLayer->getRefCnt(), 2); 264 265 ////////// INSERT NULL, BOTH TREES NOW REMOVED 266 267 // insert null tree, which should deref secondLayer immediately 268 manager.updateWithTree(0, false); 269 ASSERT_EQ(secondLayer->getRefCnt(), 1); 270 SkSafeUnref(secondLayer); 271 272 // nothing to draw or swap 273 swapped = false; 274 ASSERT_FALSE(drawGL(manager, &swapped)); 275 ASSERT_FALSE(swapped); 276 } 277 278 TEST_F(TreeManagerTest, LayerAndroidTree_PictureRefCount) { 279 RenderLayer* renderLayer = 0; 280 LayerAndroid* l; 281 SkPicture* p; 282 allocLayerWithPicture(false, &l, &p); 283 ASSERT_TRUE(l->needsTexture()); 284 SkSafeRef(p); // ref picture locally so it exists after layer (so we can see 285 // layer derefs it) 286 287 ASSERT_EQ(l->getRefCnt(), 1); 288 ASSERT_EQ(p->getRefCnt(), 2); 289 SkSafeUnref(l); 290 291 ASSERT_EQ(p->getRefCnt(), 1); 292 SkSafeUnref(p); 293 } 294 295 TEST_F(TreeManagerTest, LayerAndroidTree_PaintTreeWithPictures) { 296 XLOGC("STARTING PAINT TEST"); 297 298 TreeManager manager; 299 RenderLayer* renderLayer = 0; 300 LayerAndroid root(renderLayer); 301 LayerAndroid* noPaintChild = new LayerAndroid(renderLayer); 302 root.addChild(noPaintChild); 303 304 root.showLayer(0); 305 306 ASSERT_EQ(noPaintChild->getRefCnt(), 2); 307 308 309 LayerAndroid* copy = new LayerAndroid(root); 310 copy->showLayer(0); 311 manager.updateWithTree(copy, true); 312 313 314 // no painting layer, should swap immediately 315 bool swapped = false; 316 ASSERT_FALSE(drawGL(manager, &swapped)); 317 ASSERT_TRUE(swapped); 318 319 320 ////////// add 2 painting layers, push new tree copy into tree manager 321 322 LayerAndroid* paintChildA; 323 allocLayerWithPicture(true, &paintChildA, 0); 324 noPaintChild->addChild(paintChildA); 325 ASSERT_TRUE(paintChildA->needsTexture()); 326 327 LayerAndroid* paintChildB; 328 allocLayerWithPicture(true, &paintChildB, 0); 329 noPaintChild->addChild(paintChildB); 330 ASSERT_TRUE(paintChildB->needsTexture()); 331 332 LayerAndroid* copy1 = new LayerAndroid(root); 333 copy1->showLayer(0); 334 manager.updateWithTree(copy1, false); 335 336 swapped = false; 337 ASSERT_TRUE(drawGL(manager, &swapped)); 338 ASSERT_FALSE(swapped); // painting layers not ready 339 340 ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 2); 341 342 ////////// remove painting layer, add new painting layer, push new tree copy into tree manager 343 344 LayerAndroid* paintChildC; 345 allocLayerWithPicture(true, &paintChildC, 0); 346 noPaintChild->addChild(paintChildC); 347 ASSERT_TRUE(paintChildC->needsTexture()); 348 349 paintChildB->detachFromParent(); 350 ASSERT_EQ(paintChildB->getRefCnt(), 1); 351 SkSafeUnref(paintChildB); 352 353 LayerAndroid* copy2 = new LayerAndroid(root); 354 copy2->showLayer(0); 355 manager.updateWithTree(copy2, false); 356 357 swapped = false; 358 ASSERT_TRUE(drawGL(manager, &swapped)); 359 ASSERT_FALSE(swapped); // painting layers not ready 360 361 362 ////////// swap layers 363 364 static_cast<TestLayerAndroid*>(copy1->getChild(0)->getChild(0))->m_isDonePainting = true; 365 static_cast<TestLayerAndroid*>(copy1->getChild(0)->getChild(1))->m_isDonePainting = true; 366 367 XLOGC("painting should be %p, queued %p", copy1, copy2); 368 swapped = false; 369 ASSERT_TRUE(drawGL(manager, &swapped)); 370 ASSERT_TRUE(swapped); // paint complete, new layer tree to paint 371 XLOGC("drawing should be %p, painting %p", copy1, copy2); 372 373 374 ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 3); 375 376 377 ////////// swap layers again 378 379 static_cast<TestLayerAndroid*>(copy2->getChild(0)->getChild(0))->m_isDonePainting = true; 380 static_cast<TestLayerAndroid*>(copy2->getChild(0)->getChild(1))->m_isDonePainting = true; 381 382 swapped = false; 383 ASSERT_FALSE(drawGL(manager, &swapped)); 384 ASSERT_TRUE(swapped); // paint complete, no new layer tree to paint 385 386 ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 2); 387 388 ////////// remove all painting layers 389 390 paintChildA->detachFromParent(); 391 SkSafeUnref(paintChildA); 392 paintChildC->detachFromParent(); 393 SkSafeUnref(paintChildC); 394 395 396 copy = new LayerAndroid(root); 397 copy->showLayer(0); 398 manager.updateWithTree(copy, false); 399 400 swapped = false; 401 ASSERT_FALSE(drawGL(manager, &swapped)); 402 ASSERT_TRUE(swapped); // paint complete, no new layer tree to paint 403 404 ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 0); 405 } 406 407 } // namespace WebCore 408