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
42namespace WebCore {
43
44// Used for testing simple cases for tree painting, drawing, swapping
45class TestLayer : public Layer {
46public:
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
82class TestLayerAndroid : public LayerAndroid {
83public:
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
111class TreeManagerTest : public testing::Test {
112protected:
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
150TEST_F(TreeManagerTest, EmptyTree_DoesntRedraw) {
151    TreeManager manager;
152
153    drawGL(manager, false);
154}
155
156TEST_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
183TEST_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
205TEST_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
278TEST_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
295TEST_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