blob: 231192444caf86f8ecaecd85858a1365c23b4e9f [file] [log] [blame]
John Reck013127b2020-10-29 20:53:51 -04001/*
2 * Copyright (C) 2020 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
19#include <canvas/CanvasOpBuffer.h>
20#include <canvas/CanvasOps.h>
21#include <canvas/CanvasOpRasterizer.h>
22
23#include <tests/common/CallCountingCanvas.h>
24
Nader Jawadde3ce842020-11-06 16:54:48 -080025#include "SkColor.h"
26#include "pipeline/skia/AnimatedDrawables.h"
27
John Reck013127b2020-10-29 20:53:51 -040028using namespace android;
29using namespace android::uirenderer;
30using namespace android::uirenderer::test;
31
32// We lazy
33using Op = CanvasOpType;
34
35enum MockTypes {
36 Lifecycle,
37 COUNT
38};
39
40template<MockTypes T>
41struct MockOp;
42
43template<MockTypes T>
44struct MockOpContainer {
45 OpBufferItemHeader<MockTypes> header;
46 MockOp<T> impl;
47};
48
49struct LifecycleTracker {
50 int ctor_count = 0;
51 int dtor_count = 0;
52
53 int alive() { return ctor_count - dtor_count; }
54};
55
56template<>
57struct MockOp<MockTypes::Lifecycle> {
58 MockOp() = delete;
59 void operator=(const MockOp&) = delete;
60
61 MockOp(LifecycleTracker* tracker) : tracker(tracker) {
62 tracker->ctor_count += 1;
63 }
64
65 MockOp(const MockOp& other) {
66 tracker = other.tracker;
67 tracker->ctor_count += 1;
68 }
69
70 ~MockOp() {
71 tracker->dtor_count += 1;
72 }
73
74 LifecycleTracker* tracker = nullptr;
75};
76
77using MockBuffer = OpBuffer<MockTypes, MockOpContainer>;
78
79template<typename T>
80static int countItems(const T& t) {
81 int count = 0;
82 t.for_each([&](auto i) {
83 count++;
84 });
85 return count;
86}
87
88TEST(CanvasOp, lifecycleCheck) {
89 LifecycleTracker tracker;
90 {
91 MockBuffer buffer;
92 buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
93 .impl = MockOp<MockTypes::Lifecycle>{&tracker}
94 });
95 EXPECT_EQ(tracker.alive(), 1);
96 buffer.clear();
97 EXPECT_EQ(tracker.alive(), 0);
98 }
99 EXPECT_EQ(tracker.alive(), 0);
100}
101
102TEST(CanvasOp, lifecycleCheckMove) {
103 LifecycleTracker tracker;
104 {
105 MockBuffer buffer;
106 buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
107 .impl = MockOp<MockTypes::Lifecycle>{&tracker}
108 });
109 EXPECT_EQ(tracker.alive(), 1);
110 {
111 MockBuffer other(std::move(buffer));
112 EXPECT_EQ(tracker.alive(), 1);
113 EXPECT_EQ(buffer.size(), 0);
114 EXPECT_GT(other.size(), 0);
115 EXPECT_EQ(1, countItems(other));
116 EXPECT_EQ(0, countItems(buffer));
117
118 other.push_container(MockOpContainer<MockTypes::Lifecycle> {
119 .impl = MockOp<MockTypes::Lifecycle>{&tracker}
120 });
121
122 EXPECT_EQ(2, countItems(other));
123 EXPECT_EQ(2, tracker.alive());
124
125 buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
126 .impl = MockOp<MockTypes::Lifecycle>{&tracker}
127 });
128 EXPECT_EQ(1, countItems(buffer));
129 EXPECT_EQ(3, tracker.alive());
130
131 buffer = std::move(other);
132 EXPECT_EQ(2, countItems(buffer));
133 EXPECT_EQ(2, tracker.alive());
134 }
135 EXPECT_EQ(2, countItems(buffer));
136 EXPECT_EQ(2, tracker.alive());
137 buffer.clear();
138 EXPECT_EQ(0, countItems(buffer));
139 EXPECT_EQ(0, tracker.alive());
140 }
141 EXPECT_EQ(tracker.alive(), 0);
142}
143
144TEST(CanvasOp, simplePush) {
145 CanvasOpBuffer buffer;
146 EXPECT_EQ(buffer.size(), 0);
147 buffer.push<Op::Save>({});
148 buffer.push<Op::Save>({});
149 buffer.push<Op::Restore>({});
150 EXPECT_GT(buffer.size(), 0);
151
152 int saveCount = 0;
153 int restoreCount = 0;
154 int otherCount = 0;
155
156 buffer.for_each([&](auto op) {
157 switch (op->type()) {
158 case Op::Save:
159 saveCount++;
160 break;
161 case Op::Restore:
162 restoreCount++;
163 break;
164 default:
165 otherCount++;
166 break;
167 }
168 });
169
170 EXPECT_EQ(saveCount, 2);
171 EXPECT_EQ(restoreCount, 1);
172 EXPECT_EQ(otherCount, 0);
173
174 buffer.clear();
175 int itemCount = 0;
176 buffer.for_each([&](auto op) {
177 itemCount++;
178 });
179 EXPECT_EQ(itemCount, 0);
180 buffer.resize(0);
181 EXPECT_EQ(buffer.size(), 0);
182}
183
Nader Jawadde3ce842020-11-06 16:54:48 -0800184TEST(CanvasOp, simpleDrawPaint) {
185 CanvasOpBuffer buffer;
186 EXPECT_EQ(buffer.size(), 0);
187 buffer.push(CanvasOp<Op::DrawColor> {
188 .color = SkColor4f{1, 1, 1, 1},
189 .mode = SkBlendMode::kSrcIn
190 });
191
192 CallCountingCanvas canvas;
193 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
194 rasterizeCanvasBuffer(buffer, &canvas);
195 EXPECT_EQ(1, canvas.drawPaintCount);
196 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
197}
198
John Reck013127b2020-10-29 20:53:51 -0400199TEST(CanvasOp, simpleDrawRect) {
200 CanvasOpBuffer buffer;
201 EXPECT_EQ(buffer.size(), 0);
202 buffer.push(CanvasOp<Op::DrawRect> {
203 .paint = SkPaint{},
204 .rect = SkRect::MakeEmpty()
205 });
206
207 CallCountingCanvas canvas;
208 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
209 rasterizeCanvasBuffer(buffer, &canvas);
210 EXPECT_EQ(1, canvas.drawRectCount);
211 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
212}
213
Nader Jawadd5c2b6d2020-11-05 19:12:29 -0800214TEST(CanvasOp, simpleDrawRoundRect) {
215 CanvasOpBuffer buffer;
216 EXPECT_EQ(buffer.size(), 0);
217 buffer.push(CanvasOp<Op::DrawRoundRect> {
218 .paint = SkPaint{},
219 .rect = SkRect::MakeEmpty(),
220 .rx = 10,
221 .ry = 10
222 });
223
224 CallCountingCanvas canvas;
225 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
226 rasterizeCanvasBuffer(buffer, &canvas);
227 EXPECT_EQ(1, canvas.drawRRectCount);
228 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
229}
230
231TEST(CanvasOp, simpleDrawCircle) {
232 CanvasOpBuffer buffer;
233 EXPECT_EQ(buffer.size(), 0);
234 buffer.push(CanvasOp<Op::DrawCircle> {
235 .cx = 5,
236 .cy = 7,
237 .radius = 10,
238 .paint = SkPaint{}
239 });
240
241 CallCountingCanvas canvas;
242 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
243 rasterizeCanvasBuffer(buffer, &canvas);
244 EXPECT_EQ(1, canvas.drawOvalCount);
245 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
246}
247
248TEST(CanvasOp, simpleDrawOval) {
249 CanvasOpBuffer buffer;
250 EXPECT_EQ(buffer.size(), 0);
251 buffer.push(CanvasOp<Op::DrawOval> {
252 .oval = SkRect::MakeEmpty(),
253 .paint = SkPaint{}
254 });
255
256 CallCountingCanvas canvas;
257 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
258 rasterizeCanvasBuffer(buffer, &canvas);
259 EXPECT_EQ(1, canvas.drawOvalCount);
260 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
261}
262
263TEST(CanvasOp, simpleDrawArc) {
264 CanvasOpBuffer buffer;
265 EXPECT_EQ(buffer.size(), 0);
266 buffer.push(CanvasOp<Op::DrawArc> {
267 .oval = SkRect::MakeWH(100, 100),
268 .startAngle = 120,
269 .sweepAngle = 70,
270 .useCenter = true,
271 .paint = SkPaint{}
272 });
273
274 CallCountingCanvas canvas;
275 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
276 rasterizeCanvasBuffer(buffer, &canvas);
277 EXPECT_EQ(1, canvas.drawArcCount);
278 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
279}
280
Nader Jawadde3ce842020-11-06 16:54:48 -0800281TEST(CanvasOp, simpleDrawRoundRectProperty) {
282 CanvasOpBuffer buffer;
283 EXPECT_EQ(buffer.size(), 0);
284
285 auto left = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1));
286 auto top = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2));
287 auto right = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(3));
288 auto bottom = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(4));
289 auto radiusX = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5));
290 auto radiusY = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(6));
291 auto propertyPaint =
292 sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{}));
293
294 buffer.push(CanvasOp<Op::DrawRoundRectProperty> {
295 .left = left,
296 .top = top,
297 .right = right,
298 .bottom = bottom,
299 .rx = radiusX,
300 .ry = radiusY,
301 .paint = propertyPaint
302 });
303
304 CallCountingCanvas canvas;
305 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
306 rasterizeCanvasBuffer(buffer, &canvas);
307 EXPECT_EQ(1, canvas.drawRRectCount);
308 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
309}
310
311TEST(CanvasOp, simpleDrawCircleProperty) {
312 CanvasOpBuffer buffer;
313 EXPECT_EQ(buffer.size(), 0);
314
315 auto x = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1));
316 auto y = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2));
317 auto radius = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5));
318 auto propertyPaint =
319 sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{}));
320
321 buffer.push(CanvasOp<Op::DrawCircleProperty> {
322 .x = x,
323 .y = y,
324 .radius = radius,
325 .paint = propertyPaint
326 });
327
328 CallCountingCanvas canvas;
329 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
330 rasterizeCanvasBuffer(buffer, &canvas);
331 EXPECT_EQ(1, canvas.drawOvalCount);
332 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
333}
334
John Reck013127b2020-10-29 20:53:51 -0400335TEST(CanvasOp, immediateRendering) {
336 auto canvas = std::make_shared<CallCountingCanvas>();
337
338 EXPECT_EQ(0, canvas->sumTotalDrawCalls());
339 ImmediateModeRasterizer rasterizer{canvas};
340 auto op = CanvasOp<Op::DrawRect> {
341 .paint = SkPaint{},
342 .rect = SkRect::MakeEmpty()
343 };
344 EXPECT_TRUE(CanvasOpTraits::can_draw<decltype(op)>);
345 rasterizer.draw(op);
346 EXPECT_EQ(1, canvas->drawRectCount);
347 EXPECT_EQ(1, canvas->sumTotalDrawCalls());
348}