blob: 19c311c7e1826d949fa248f128e3751b876c0408 [file] [log] [blame]
Stan Iliev021693b2016-10-17 16:26:15 -04001/*
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}