SkiaPipelineTests.cpp revision 66b9d4486abb9e6d1edc624cd9ff522b12acece0
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 <gtest/gtest.h>
18#include <VectorDrawable.h>
19
20#include "AnimationContext.h"
21#include "DamageAccumulator.h"
22#include "IContextFactory.h"
23#include "pipeline/skia/SkiaDisplayList.h"
24#include "pipeline/skia/SkiaRecordingCanvas.h"
25#include "pipeline/skia/SkiaOpenGLPipeline.h"
26#include "renderthread/CanvasContext.h"
27#include "tests/common/TestUtils.h"
28#include "SkiaCanvas.h"
29#include <SkClipStack.h>
30#include <SkLiteRecorder.h>
31#include <SkSurface_Base.h>
32#include <string.h>
33
34using namespace android;
35using namespace android::uirenderer;
36using namespace android::uirenderer::renderthread;
37using namespace android::uirenderer::skiapipeline;
38
39RENDERTHREAD_TEST(SkiaPipeline, renderFrame) {
40    auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
41        [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
42            redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
43        });
44    LayerUpdateQueue layerUpdateQueue;
45    SkRect dirty = SkRect::MakeLargest();
46    std::vector<sp<RenderNode>> renderNodes;
47    renderNodes.push_back(redNode);
48    bool opaque = true;
49    android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
50    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
51    auto surface = SkSurface::MakeRasterN32Premul(1, 1);
52    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
53    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
54    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
55    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
56}
57
58RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckOpaque) {
59    auto halfGreenNode = TestUtils::createSkiaNode(0, 0, 2, 2,
60        [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
61            SkPaint greenPaint;
62            greenPaint.setColor(SK_ColorGREEN);
63            greenPaint.setStyle(SkPaint::kFill_Style);
64            bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint);
65        });
66    LayerUpdateQueue layerUpdateQueue;
67    SkRect dirty = SkRect::MakeLargest();
68    std::vector<sp<RenderNode>> renderNodes;
69    renderNodes.push_back(halfGreenNode);
70    android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2);
71    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
72    auto surface = SkSurface::MakeRasterN32Premul(2, 2);
73    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
74    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
75    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface);
76    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
77    ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
78    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, surface);
79    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT);
80    ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
81}
82
83RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
84    auto redNode = TestUtils::createSkiaNode(0, 0, 2, 2,
85        [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
86            redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
87        });
88    LayerUpdateQueue layerUpdateQueue;
89    SkRect dirty = SkRect::MakeXYWH(0, 1, 2, 1);
90    std::vector<sp<RenderNode>> renderNodes;
91    renderNodes.push_back(redNode);
92    android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2);
93    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
94    auto surface = SkSurface::MakeRasterN32Premul(2, 2);
95    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
96    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
97    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface);
98    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
99    ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE);
100    ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorRED);
101    ASSERT_EQ(TestUtils::getColor(surface, 1, 1), SK_ColorRED);
102}
103
104RENDERTHREAD_TEST(SkiaPipeline, renderLayer) {
105    auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
106        [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
107            redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
108        });
109    auto surfaceLayer1 = SkSurface::MakeRasterN32Premul(1, 1);
110    surfaceLayer1->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
111    ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorWHITE);
112    redNode->setLayerSurface(surfaceLayer1);
113
114    //create a 2nd 2x2 layer and add it to the queue as well.
115    //make the layer's dirty area one half of the layer and verify only the dirty half is updated.
116    auto blueNode = TestUtils::createSkiaNode(0, 0, 2, 2,
117        [](RenderProperties& props, SkiaRecordingCanvas& blueCanvas) {
118            blueCanvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
119        });
120    auto surfaceLayer2 = SkSurface::MakeRasterN32Premul(2, 2);
121    surfaceLayer2->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
122    ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorWHITE);
123    blueNode->setLayerSurface(surfaceLayer2);
124
125    //attach both layers to the update queue
126    LayerUpdateQueue layerUpdateQueue;
127    SkRect dirty = SkRect::MakeLargest();
128    layerUpdateQueue.enqueueLayerWithDamage(redNode.get(), dirty);
129    layerUpdateQueue.enqueueLayerWithDamage(blueNode.get(), SkRect::MakeWH(2, 1));
130    ASSERT_EQ(layerUpdateQueue.entries().size(), 2UL);
131
132    bool opaque = true;
133    FrameBuilder::LightGeometry lightGeometry;
134    lightGeometry.radius = 1.0f;
135    lightGeometry.center = { 0.0f, 0.0f, 0.0f };
136    BakedOpRenderer::LightInfo lightInfo;
137    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
138    pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, lightInfo);
139    ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorRED);
140    ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorBLUE);
141    ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 1), SK_ColorWHITE);
142    ASSERT_TRUE(layerUpdateQueue.entries().empty());
143    redNode->setLayerSurface(sk_sp<SkSurface>());
144    blueNode->setLayerSurface(sk_sp<SkSurface>());
145}
146
147RENDERTHREAD_TEST(SkiaPipeline, renderOverdraw) {
148    ScopedProperty<bool> prop(Properties::debugOverdraw, true);
149
150    auto whiteNode = TestUtils::createSkiaNode(0, 0, 1, 1,
151        [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
152            canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
153        });
154    LayerUpdateQueue layerUpdateQueue;
155    SkRect dirty = SkRect::MakeXYWH(0, 0, 1, 1);
156    std::vector<sp<RenderNode>> renderNodes;
157    renderNodes.push_back(whiteNode);
158    bool opaque = true;
159    //empty contentDrawBounds is avoiding backdrop/content logic, which would lead to less overdraw
160    android::uirenderer::Rect contentDrawBounds(0, 0, 0, 0);
161    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
162    auto surface = SkSurface::MakeRasterN32Premul(1, 1);
163
164    // Initialize the canvas to blue.
165    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
166    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
167
168    // Single draw, should be white.
169    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
170    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
171
172    // 1 Overdraw, should be blue blended onto white.
173    renderNodes.push_back(whiteNode); //this is the "content" node
174    renderNodes.push_back(whiteNode); //the "content" node above does not cause an overdraw, because
175    //it clips the first "background" node
176    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
177    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0d0ff);
178
179    // 2 Overdraw, should be green blended onto white
180    renderNodes.push_back(whiteNode);
181    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
182    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0ffd0);
183
184    // 3 Overdraw, should be pink blended onto white.
185    renderNodes.push_back(whiteNode);
186    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
187    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffffc0c0);
188
189    // 4 Overdraw, should be red blended onto white.
190    renderNodes.push_back(whiteNode);
191    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
192    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
193
194    // 5 Overdraw, should be red blended onto white.
195    renderNodes.push_back(whiteNode);
196    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
197    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
198}
199
200namespace {
201template <typename T>
202class DeferLayer : public SkSurface_Base {
203public:
204    DeferLayer(T *canvas)
205        : SkSurface_Base(canvas->imageInfo(), nullptr)
206        , mCanvas(canvas) {
207    }
208    SkCanvas* onNewCanvas() override {
209        return mCanvas;
210    }
211    sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override {
212        return sk_sp<SkSurface>();
213    }
214    sk_sp<SkImage> onNewImageSnapshot(SkBudgeted, SkCopyPixelsMode) override {
215        return sk_sp<SkImage>();
216    }
217    void onCopyOnWrite(ContentChangeMode) override {}
218    T* mCanvas;  // bare pointer, not owned/ref'd
219};
220}
221
222RENDERTHREAD_TEST(SkiaPipeline, deferRenderNodeScene) {
223    class DeferTestCanvas : public SkCanvas {
224    public:
225        DeferTestCanvas() : SkCanvas(800, 600) {}
226        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
227            SkMatrix expected;
228            switch (mDrawCounter++) {
229            case 0:
230                // background - left side
231                EXPECT_EQ(SkRect::MakeLTRB(600, 100, 700, 500), TestUtils::getClipBounds(this));
232                expected.setTranslate(100, 100);
233                break;
234            case 1:
235                // background - top side
236                EXPECT_EQ(SkRect::MakeLTRB(100, 400, 600, 500), TestUtils::getClipBounds(this));
237                expected.setTranslate(100, 100);
238                break;
239            case 2:
240                // content
241                EXPECT_EQ(SkRect::MakeLTRB(100, 100, 700, 500), TestUtils::getClipBounds(this));
242                expected.setTranslate(-50, -50);
243                break;
244            case 3:
245                // overlay
246                EXPECT_EQ(SkRect::MakeLTRB(0, 0, 800, 600), TestUtils::getClipBounds(this));
247                expected.reset();
248                break;
249            default:
250                ADD_FAILURE() << "Too many rects observed";
251            }
252            EXPECT_EQ(expected, getTotalMatrix());
253        }
254        int mDrawCounter = 0;
255    };
256
257    std::vector<sp<RenderNode>> nodes;
258    SkPaint transparentPaint;
259    transparentPaint.setAlpha(128);
260
261    // backdrop
262    nodes.push_back(TestUtils::createSkiaNode(100, 100, 700, 500, // 600x400
263            [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
264        canvas.drawRect(0, 0, 600, 400, transparentPaint);
265    }));
266
267    // content
268    android::uirenderer::Rect contentDrawBounds(150, 150, 650, 450); // 500x300
269    nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600,
270            [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
271        canvas.drawRect(0, 0, 800, 600, transparentPaint);
272    }));
273
274    // overlay
275    nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600,
276            [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
277        canvas.drawRect(0, 0, 800, 200, transparentPaint);
278    }));
279
280    LayerUpdateQueue layerUpdateQueue;
281    SkRect dirty = SkRect::MakeWH(800, 600);
282    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
283    DeferTestCanvas canvas;
284    sk_sp<SkSurface> surface(new DeferLayer<DeferTestCanvas>(&canvas));
285    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, contentDrawBounds, surface);
286    EXPECT_EQ(4, canvas.mDrawCounter);
287}
288
289RENDERTHREAD_TEST(SkiaPipeline, clipped) {
290    static const int CANVAS_WIDTH = 200;
291    static const int CANVAS_HEIGHT = 200;
292    class ClippedTestCanvas : public SkCanvas {
293    public:
294        ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {
295        }
296        void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
297            EXPECT_EQ(0, mDrawCounter++);
298            EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(this));
299            EXPECT_TRUE(getTotalMatrix().isIdentity());
300        }
301        int mDrawCounter = 0;
302    };
303
304    std::vector<sp<RenderNode>> nodes;
305    nodes.push_back(TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
306            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
307        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT));
308        canvas.drawBitmap(*bitmap, 0, 0, nullptr);
309    }));
310
311    LayerUpdateQueue layerUpdateQueue;
312    SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40);
313    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
314    ClippedTestCanvas canvas;
315    sk_sp<SkSurface> surface(new DeferLayer<ClippedTestCanvas>(&canvas));
316    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
317            SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
318    EXPECT_EQ(1, canvas.mDrawCounter);
319}
320
321RENDERTHREAD_TEST(SkiaPipeline, clip_replace) {
322    static const int CANVAS_WIDTH = 50;
323    static const int CANVAS_HEIGHT = 50;
324    class ClipReplaceTestCanvas : public SkCanvas {
325    public:
326        ClipReplaceTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {
327        }
328        void onDrawPaint(const SkPaint&) {
329            EXPECT_EQ(0, mDrawCounter++);
330            //TODO: this unit test is failing on the commented check below, because of a missing
331            //feature. In Snapshot::applyClip HWUI is intersecting the clip with the clip root,
332            //even for kReplace_Op clips. We need to implement the same for Skia pipelines.
333            //EXPECT_EQ(SkRect::MakeLTRB(20, 10, 30, 40), TestUtils::getClipBounds(this)) //got instead 20 0 30 50
334            //        << "Expect resolved clip to be intersection of viewport clip and clip op";
335        }
336        int mDrawCounter = 0;
337    };
338
339    std::vector<sp<RenderNode>> nodes;
340    nodes.push_back(TestUtils::createSkiaNode(20, 20, 30, 30,
341            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
342        canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace);
343        canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
344    }));
345
346    LayerUpdateQueue layerUpdateQueue;
347    SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40);
348    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
349    ClipReplaceTestCanvas canvas;
350    sk_sp<SkSurface> surface(new DeferLayer<ClipReplaceTestCanvas>(&canvas));
351    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
352            SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
353    EXPECT_EQ(1, canvas.mDrawCounter);
354}
355