SkiaPipelineTests.cpp revision 52771272f4f018f4fc6846224bf047497e784af1
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        mCanvas->ref();
210        return mCanvas;
211    }
212    sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override {
213        return sk_sp<SkSurface>();
214    }
215    sk_sp<SkImage> onNewImageSnapshot(SkBudgeted, SkCopyPixelsMode) override {
216        return sk_sp<SkImage>();
217    }
218    void onCopyOnWrite(ContentChangeMode) override {}
219    T* mCanvas;
220};
221}
222
223RENDERTHREAD_TEST(SkiaPipeline, deferRenderNodeScene) {
224    class DeferTestCanvas : public SkCanvas {
225    public:
226        DeferTestCanvas() : SkCanvas(800, 600) {}
227        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
228            SkMatrix expected;
229            switch (mDrawCounter++) {
230            case 0:
231                // background - left side
232                EXPECT_EQ(SkRect::MakeLTRB(600, 100, 700, 500), TestUtils::getClipBounds(this));
233                expected.setTranslate(100, 100);
234                break;
235            case 1:
236                // background - top side
237                EXPECT_EQ(SkRect::MakeLTRB(100, 400, 600, 500), TestUtils::getClipBounds(this));
238                expected.setTranslate(100, 100);
239                break;
240            case 2:
241                // content
242                EXPECT_EQ(SkRect::MakeLTRB(100, 100, 700, 500), TestUtils::getClipBounds(this));
243                expected.setTranslate(-50, -50);
244                break;
245            case 3:
246                // overlay
247                EXPECT_EQ(SkRect::MakeLTRB(0, 0, 800, 600), TestUtils::getClipBounds(this));
248                expected.reset();
249                break;
250            default:
251                ADD_FAILURE() << "Too many rects observed";
252            }
253            EXPECT_EQ(expected, getTotalMatrix());
254        }
255        int mDrawCounter = 0;
256    };
257
258    std::vector<sp<RenderNode>> nodes;
259    SkPaint transparentPaint;
260    transparentPaint.setAlpha(128);
261
262    // backdrop
263    nodes.push_back(TestUtils::createSkiaNode(100, 100, 700, 500, // 600x400
264            [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
265        canvas.drawRect(0, 0, 600, 400, transparentPaint);
266    }));
267
268    // content
269    android::uirenderer::Rect contentDrawBounds(150, 150, 650, 450); // 500x300
270    nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600,
271            [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
272        canvas.drawRect(0, 0, 800, 600, transparentPaint);
273    }));
274
275    // overlay
276    nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600,
277            [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
278        canvas.drawRect(0, 0, 800, 200, transparentPaint);
279    }));
280
281    LayerUpdateQueue layerUpdateQueue;
282    SkRect dirty = SkRect::MakeWH(800, 600);
283    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
284    sk_sp<DeferTestCanvas> canvas(new DeferTestCanvas());
285    sk_sp<SkSurface> surface(new DeferLayer<DeferTestCanvas>(canvas.get()));
286    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, contentDrawBounds, surface);
287    EXPECT_EQ(4, canvas->mDrawCounter);
288}
289
290RENDERTHREAD_TEST(SkiaPipeline, clipped) {
291    static const int CANVAS_WIDTH = 200;
292    static const int CANVAS_HEIGHT = 200;
293    class ClippedTestCanvas : public SkCanvas {
294    public:
295        ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {
296        }
297        void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
298            EXPECT_EQ(0, mDrawCounter++);
299            EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(this));
300            EXPECT_TRUE(getTotalMatrix().isIdentity());
301        }
302        int mDrawCounter = 0;
303    };
304
305    std::vector<sp<RenderNode>> nodes;
306    nodes.push_back(TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
307            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
308        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT));
309        canvas.drawBitmap(*bitmap, 0, 0, nullptr);
310    }));
311
312    LayerUpdateQueue layerUpdateQueue;
313    SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40);
314    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
315    sk_sp<ClippedTestCanvas> canvas(new ClippedTestCanvas());
316    sk_sp<SkSurface> surface(new DeferLayer<ClippedTestCanvas>(canvas.get()));
317    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
318            SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
319    EXPECT_EQ(1, canvas->mDrawCounter);
320}
321
322RENDERTHREAD_TEST(SkiaPipeline, clip_replace) {
323    static const int CANVAS_WIDTH = 50;
324    static const int CANVAS_HEIGHT = 50;
325    class ClipReplaceTestCanvas : public SkCanvas {
326    public:
327        ClipReplaceTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {
328        }
329        void onDrawPaint(const SkPaint&) {
330            EXPECT_EQ(0, mDrawCounter++);
331            //TODO: this unit test is failing on the commented check below, because of a missing
332            //feature. In Snapshot::applyClip HWUI is intersecting the clip with the clip root,
333            //even for kReplace_Op clips. We need to implement the same for Skia pipelines.
334            //EXPECT_EQ(SkRect::MakeLTRB(20, 10, 30, 40), TestUtils::getClipBounds(this)) //got instead 20 0 30 50
335            //        << "Expect resolved clip to be intersection of viewport clip and clip op";
336        }
337        int mDrawCounter = 0;
338    };
339
340    std::vector<sp<RenderNode>> nodes;
341    nodes.push_back(TestUtils::createSkiaNode(20, 20, 30, 30,
342            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
343        canvas.clipRect(0, -20, 10, 30, kReplace_SkClipOp);
344        canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
345    }));
346
347    LayerUpdateQueue layerUpdateQueue;
348    SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40);
349    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
350    sk_sp<ClipReplaceTestCanvas> canvas(new ClipReplaceTestCanvas());
351    sk_sp<SkSurface> surface(new DeferLayer<ClipReplaceTestCanvas>(canvas.get()));
352    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
353            SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
354    EXPECT_EQ(1, canvas->mDrawCounter);
355}
356