RenderNodeDrawableTests.cpp revision 021693b967a2c5556dddd183eb0247df4079e1ad
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 "renderthread/CanvasContext.h"
26#include "tests/common/TestUtils.h"
27#include "SkiaCanvas.h"
28#include <SkLiteRecorder.h>
29#include <string.h>
30
31
32using namespace android;
33using namespace android::uirenderer;
34using namespace android::uirenderer::renderthread;
35using namespace android::uirenderer::skiapipeline;
36
37static sp<RenderNode> createSkiaNode(int left, int top, int right, int bottom,
38        std::function<void(RenderProperties& props, SkiaRecordingCanvas& canvas)> setup,
39        const char* name = nullptr, SkiaDisplayList* displayList = nullptr) {
40#if HWUI_NULL_GPU
41    // if RenderNodes are being sync'd/used, device info will be needed, since
42    // DeviceInfo::maxTextureSize() affects layer property
43    DeviceInfo::initialize();
44#endif
45    sp<RenderNode> node = new RenderNode();
46    if (name) {
47        node->setName(name);
48    }
49    RenderProperties& props = node->mutateStagingProperties();
50    props.setLeftTopRightBottom(left, top, right, bottom);
51    if (displayList) {
52        node->setStagingDisplayList(displayList, nullptr);
53    }
54    if (setup) {
55        std::unique_ptr<SkiaRecordingCanvas> canvas(new SkiaRecordingCanvas(nullptr,
56            props.getWidth(), props.getHeight()));
57        setup(props, *canvas.get());
58        node->setStagingDisplayList(canvas->finishRecording(), nullptr);
59    }
60    node->setPropertyFieldsDirty(0xFFFFFFFF);
61    TestUtils::syncHierarchyPropertiesAndDisplayList(node);
62    return node;
63}
64
65TEST(RenderNodeDrawable, create) {
66    auto rootNode = TestUtils::createNode(0, 0, 200, 400,
67            [](RenderProperties& props, Canvas& canvas) {
68                canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
69            });
70
71    auto skLiteDL = SkLiteDL::New(SkRect::MakeWH(1, 1));
72    SkLiteRecorder canvas;
73    canvas.reset(skLiteDL.get());
74    canvas.translate(100, 100);
75    RenderNodeDrawable drawable(rootNode.get(), &canvas);
76
77    ASSERT_EQ(drawable.getRenderNode(), rootNode.get());
78    ASSERT_EQ(&drawable.getNodeProperties(), &rootNode->properties());
79    ASSERT_EQ(drawable.getRecordedMatrix(), canvas.getTotalMatrix());
80}
81
82TEST(RenderNodeDrawable, drawContent) {
83    auto surface = SkSurface::MakeRasterN32Premul(1, 1);
84    SkCanvas& canvas = *surface->getCanvas();
85    canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
86    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
87
88    //create a RenderNodeDrawable backed by a RenderNode backed by a SkLiteRecorder
89    auto rootNode = createSkiaNode(0, 0, 1, 1,
90        [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
91            recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
92        });
93    RenderNodeDrawable drawable(rootNode.get(), &canvas, false);
94
95    //negative and positive Z order are drawn out of order
96    rootNode->animatorProperties().setElevation(10.0f);
97    canvas.drawDrawable(&drawable);
98    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
99    rootNode->animatorProperties().setElevation(-10.0f);
100    canvas.drawDrawable(&drawable);
101    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
102
103    //zero Z are drawn immediately
104    rootNode->animatorProperties().setElevation(0.0f);
105    canvas.drawDrawable(&drawable);
106    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
107}
108
109//TODO: another test that verifies equal z values are drawn in order, and barriers prevent Z
110//intermixing (model after FrameBuilder zReorder)
111TEST(RenderNodeDrawable, drawAndReorder) {
112    //this test exercises StartReorderBarrierDrawable, EndReorderBarrierDrawable and
113    //SkiaRecordingCanvas
114    auto surface = SkSurface::MakeRasterN32Premul(4, 4);
115    SkCanvas& canvas = *surface->getCanvas();
116
117    canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
118    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
119
120    //-z draws to all 4 pixels (RED)
121    auto redNode = createSkiaNode(0, 0, 4, 4,
122        [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
123            redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
124            props.setElevation(-10.0f);
125        }, "redNode");
126
127    //0z draws to bottom 2 pixels (GREEN)
128    auto bottomHalfGreenNode = createSkiaNode(0, 0, 4, 4,
129            [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
130                SkPaint greenPaint;
131                greenPaint.setColor(SK_ColorGREEN);
132                greenPaint.setStyle(SkPaint::kFill_Style);
133                bottomHalfGreenCanvas.drawRect(0, 2, 4, 4, greenPaint);
134                props.setElevation(0.0f);
135            }, "bottomHalfGreenNode");
136
137    //+z draws to right 2 pixels (BLUE)
138    auto rightHalfBlueNode = createSkiaNode(0, 0, 4, 4,
139        [](RenderProperties& props, SkiaRecordingCanvas& rightHalfBlueCanvas) {
140            SkPaint bluePaint;
141            bluePaint.setColor(SK_ColorBLUE);
142            bluePaint.setStyle(SkPaint::kFill_Style);
143            rightHalfBlueCanvas.drawRect(2, 0, 4, 4, bluePaint);
144            props.setElevation(10.0f);
145        }, "rightHalfBlueNode");
146
147    auto rootNode = createSkiaNode(0, 0, 4, 4,
148            [&](RenderProperties& props, SkiaRecordingCanvas& rootRecorder) {
149                rootRecorder.insertReorderBarrier(true);
150                //draw in reverse Z order, so Z alters draw order
151                rootRecorder.drawRenderNode(rightHalfBlueNode.get());
152                rootRecorder.drawRenderNode(bottomHalfGreenNode.get());
153                rootRecorder.drawRenderNode(redNode.get());
154            }, "rootNode");
155
156    RenderNodeDrawable drawable3(rootNode.get(), &canvas, false);
157    canvas.drawDrawable(&drawable3);
158    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
159    ASSERT_EQ(TestUtils::getColor(surface, 0, 3), SK_ColorGREEN);
160    ASSERT_EQ(TestUtils::getColor(surface, 3, 3), SK_ColorBLUE);
161}
162
163TEST(RenderNodeDrawable, composeOnLayer)
164{
165    auto surface = SkSurface::MakeRasterN32Premul(1, 1);
166    SkCanvas& canvas = *surface->getCanvas();
167    canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
168    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
169
170    auto rootNode = createSkiaNode(0, 0, 1, 1,
171        [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
172            recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
173        });
174
175    //attach a layer to the render node
176    auto surfaceLayer = SkSurface::MakeRasterN32Premul(1, 1);
177    auto canvas2 = surfaceLayer->getCanvas();
178    canvas2->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
179    rootNode->setLayerSurface( surfaceLayer  );
180
181    RenderNodeDrawable drawable1(rootNode.get(), &canvas, false);
182    canvas.drawDrawable(&drawable1);
183    ASSERT_EQ(SK_ColorRED, TestUtils::getColor(surface, 0, 0));
184
185    RenderNodeDrawable drawable2(rootNode.get(), &canvas, true);
186    canvas.drawDrawable(&drawable2);
187    ASSERT_EQ(SK_ColorWHITE, TestUtils::getColor(surface, 0, 0));
188
189    RenderNodeDrawable drawable3(rootNode.get(), &canvas, false);
190    canvas.drawDrawable(&drawable3);
191    ASSERT_EQ(SK_ColorRED, TestUtils::getColor(surface, 0, 0));
192
193    rootNode->setLayerSurface( sk_sp<SkSurface>()  );
194}
195
196//TODO: refactor to cover test cases from FrameBuilderTests_projectionReorder
197//validate with bounds and projection path mask.
198//TODO: research if we could hook in and mock/validate different aspects of the drawing,
199//instead of validating pixels
200TEST(RenderNodeDrawable, projectDraw) {
201    auto surface = SkSurface::MakeRasterN32Premul(1, 1);
202    SkCanvas& canvas = *surface->getCanvas();
203    canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
204    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
205
206    auto redNode = createSkiaNode(0, 0, 1, 1,
207        [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
208            redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
209        }, "redNode");
210
211    auto greenNodeWithRedChild = createSkiaNode(0, 0, 1, 1,
212        [&](RenderProperties& props, SkiaRecordingCanvas& greenCanvasWithRedChild) {
213            greenCanvasWithRedChild.drawRenderNode(redNode.get());
214            greenCanvasWithRedChild.drawColor(SK_ColorGREEN, SkBlendMode::kSrcOver);
215        }, "greenNodeWithRedChild");
216
217    auto rootNode = createSkiaNode(0, 0, 1, 1,
218        [&](RenderProperties& props, SkiaRecordingCanvas& rootCanvas) {
219            rootCanvas.drawRenderNode(greenNodeWithRedChild.get());
220        }, "rootNode");
221    SkiaDisplayList* rootDisplayList = static_cast<SkiaDisplayList*>(
222        (const_cast<DisplayList*>(rootNode->getDisplayList())));
223
224    RenderNodeDrawable rootDrawable(rootNode.get(), &canvas, false);
225    canvas.drawDrawable(&rootDrawable);
226    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorGREEN);
227
228    //project redNode on rootNode, which will change the test outcome,
229    //because redNode will draw after greenNodeWithRedChild
230    rootDisplayList->mIsProjectionReceiver = true;
231    redNode->animatorProperties().setProjectBackwards(true);
232    canvas.drawDrawable(&rootDrawable);
233    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
234}
235