Home | History | Annotate | Download | only in tests
      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