blob: 60c8628ea966d4aaa1a1db4a6e04985d35b74778 [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
Nader Jawadfb1e7f12020-11-06 22:49:42 -0800199TEST(CanvasOp, simpleDrawPoint) {
200 CanvasOpBuffer buffer;
201 EXPECT_EQ(buffer.size(), 0);
202 buffer.push(CanvasOp<Op::DrawPoint> {
203 .x = 12,
204 .y = 42,
205 .paint = SkPaint{}
206 });
207
208 CallCountingCanvas canvas;
209 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
210 rasterizeCanvasBuffer(buffer, &canvas);
211 EXPECT_EQ(1, canvas.drawPoints);
212 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
213}
214
215TEST(CanvasOp, simpleDrawLine) {
216 CanvasOpBuffer buffer;
217 EXPECT_EQ(buffer.size(), 0);
218 buffer.push(CanvasOp<Op::DrawLine> {
219 .startX = 16,
220 .startY = 28,
221 .endX = 12,
222 .endY = 30,
223 .paint = SkPaint{}
224 });
225
226 CallCountingCanvas canvas;
227 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
228 rasterizeCanvasBuffer(buffer, &canvas);
229 EXPECT_EQ(1, canvas.drawPoints);
230 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
231}
232
John Reck013127b2020-10-29 20:53:51 -0400233TEST(CanvasOp, simpleDrawRect) {
234 CanvasOpBuffer buffer;
235 EXPECT_EQ(buffer.size(), 0);
236 buffer.push(CanvasOp<Op::DrawRect> {
237 .paint = SkPaint{},
238 .rect = SkRect::MakeEmpty()
239 });
240
241 CallCountingCanvas canvas;
242 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
243 rasterizeCanvasBuffer(buffer, &canvas);
244 EXPECT_EQ(1, canvas.drawRectCount);
245 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
246}
247
Nader Jawadfb1e7f12020-11-06 22:49:42 -0800248TEST(CanvasOp, simpleDrawRegionRect) {
249 CanvasOpBuffer buffer;
250 EXPECT_EQ(buffer.size(), 0);
251 SkRegion region;
252 region.setRect(SkIRect::MakeWH(12, 50));
253 buffer.push(CanvasOp<Op::DrawRegion> {
254 .paint = SkPaint{},
255 .region = region
256 });
257
258 CallCountingCanvas canvas;
259 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
260 rasterizeCanvasBuffer(buffer, &canvas);
261 // If the region is a rectangle, drawRegion calls into drawRect as a fast path
262 EXPECT_EQ(1, canvas.drawRectCount);
263 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
264}
265
266TEST(CanvasOp, simpleDrawRegionPath) {
267 CanvasOpBuffer buffer;
268 EXPECT_EQ(buffer.size(), 0);
269 SkPath path;
270 path.addCircle(50, 50, 50);
271 SkRegion clip;
272 clip.setRect(SkIRect::MakeWH(100, 100));
273 SkRegion region;
274 region.setPath(path, clip);
275 buffer.push(CanvasOp<Op::DrawRegion> {
276 .paint = SkPaint{},
277 .region = region
278 });
279
280 CallCountingCanvas canvas;
281 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
282 rasterizeCanvasBuffer(buffer, &canvas);
283 EXPECT_EQ(1, canvas.drawRegionCount);
284 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
285}
286
Nader Jawadd5c2b6d2020-11-05 19:12:29 -0800287TEST(CanvasOp, simpleDrawRoundRect) {
288 CanvasOpBuffer buffer;
289 EXPECT_EQ(buffer.size(), 0);
290 buffer.push(CanvasOp<Op::DrawRoundRect> {
291 .paint = SkPaint{},
292 .rect = SkRect::MakeEmpty(),
293 .rx = 10,
294 .ry = 10
295 });
296
297 CallCountingCanvas canvas;
298 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
299 rasterizeCanvasBuffer(buffer, &canvas);
300 EXPECT_EQ(1, canvas.drawRRectCount);
301 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
302}
303
Nader Jawadfb1e7f12020-11-06 22:49:42 -0800304TEST(CanvasOp, simpleDrawDoubleRoundRect) {
305 CanvasOpBuffer buffer;
306 EXPECT_EQ(buffer.size(), 0);
307 SkRect outer = SkRect::MakeLTRB(0, 0, 100, 100);
308 SkRect inner = SkRect::MakeLTRB(20, 20, 80, 80);
309
310 const int numPts = 4;
311 SkRRect outerRRect;
312
313 auto outerPts = std::make_unique<SkVector[]>(numPts);
314 outerPts[0].set(32, 16);
315 outerPts[1].set(48, 48);
316 outerPts[2].set(16, 32);
317 outerPts[3].set(20, 20);
318 outerRRect.setRectRadii(outer, outerPts.get());
319 outerRRect.setRect(outer);
320
321 SkRRect innerRRect;
322 auto innerPts = std::make_unique<SkVector[]>(numPts);
323 innerPts[0].set(16, 8);
324 innerPts[1].set(24, 24);
325 innerPts[2].set(8, 16);
326 innerPts[3].set(10, 10);
327 innerRRect.setRectRadii(inner, innerPts.get());
328
329 buffer.push(CanvasOp<Op::DrawDoubleRoundRect> {
330 .outer = outerRRect,
331 .inner = innerRRect,
332 .paint = SkPaint{}
333 });
334
335 CallCountingCanvas canvas;
336 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
337 rasterizeCanvasBuffer(buffer, &canvas);
338 EXPECT_EQ(1, canvas.drawDRRectCount);
339 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
340}
341
Nader Jawadd5c2b6d2020-11-05 19:12:29 -0800342TEST(CanvasOp, simpleDrawCircle) {
343 CanvasOpBuffer buffer;
344 EXPECT_EQ(buffer.size(), 0);
345 buffer.push(CanvasOp<Op::DrawCircle> {
346 .cx = 5,
347 .cy = 7,
348 .radius = 10,
349 .paint = SkPaint{}
350 });
351
352 CallCountingCanvas canvas;
353 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
354 rasterizeCanvasBuffer(buffer, &canvas);
355 EXPECT_EQ(1, canvas.drawOvalCount);
356 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
357}
358
359TEST(CanvasOp, simpleDrawOval) {
360 CanvasOpBuffer buffer;
361 EXPECT_EQ(buffer.size(), 0);
362 buffer.push(CanvasOp<Op::DrawOval> {
363 .oval = SkRect::MakeEmpty(),
364 .paint = SkPaint{}
365 });
366
367 CallCountingCanvas canvas;
368 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
369 rasterizeCanvasBuffer(buffer, &canvas);
370 EXPECT_EQ(1, canvas.drawOvalCount);
371 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
372}
373
374TEST(CanvasOp, simpleDrawArc) {
375 CanvasOpBuffer buffer;
376 EXPECT_EQ(buffer.size(), 0);
377 buffer.push(CanvasOp<Op::DrawArc> {
378 .oval = SkRect::MakeWH(100, 100),
379 .startAngle = 120,
380 .sweepAngle = 70,
381 .useCenter = true,
382 .paint = SkPaint{}
383 });
384
385 CallCountingCanvas canvas;
386 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
387 rasterizeCanvasBuffer(buffer, &canvas);
388 EXPECT_EQ(1, canvas.drawArcCount);
389 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
390}
391
Nader Jawadfb1e7f12020-11-06 22:49:42 -0800392TEST(CanvasOp, simpleDrawPath) {
393 CanvasOpBuffer buffer;
394 EXPECT_EQ(buffer.size(), 0);
395 SkPath path;
396 path.addCircle(50, 50, 30);
397 buffer.push(CanvasOp<Op::DrawPath> {
398 .path = path,
399 .paint = SkPaint{}
400 });
401
402 CallCountingCanvas canvas;
403 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
404 rasterizeCanvasBuffer(buffer, &canvas);
405 EXPECT_EQ(1, canvas.drawPathCount);
406 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
407}
408
Nader Jawadde3ce842020-11-06 16:54:48 -0800409TEST(CanvasOp, simpleDrawRoundRectProperty) {
410 CanvasOpBuffer buffer;
411 EXPECT_EQ(buffer.size(), 0);
412
413 auto left = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1));
414 auto top = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2));
415 auto right = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(3));
416 auto bottom = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(4));
417 auto radiusX = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5));
418 auto radiusY = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(6));
419 auto propertyPaint =
420 sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{}));
421
422 buffer.push(CanvasOp<Op::DrawRoundRectProperty> {
423 .left = left,
424 .top = top,
425 .right = right,
426 .bottom = bottom,
427 .rx = radiusX,
428 .ry = radiusY,
429 .paint = propertyPaint
430 });
431
432 CallCountingCanvas canvas;
433 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
434 rasterizeCanvasBuffer(buffer, &canvas);
435 EXPECT_EQ(1, canvas.drawRRectCount);
436 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
437}
438
439TEST(CanvasOp, simpleDrawCircleProperty) {
440 CanvasOpBuffer buffer;
441 EXPECT_EQ(buffer.size(), 0);
442
443 auto x = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1));
444 auto y = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2));
445 auto radius = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5));
446 auto propertyPaint =
447 sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{}));
448
449 buffer.push(CanvasOp<Op::DrawCircleProperty> {
450 .x = x,
451 .y = y,
452 .radius = radius,
453 .paint = propertyPaint
454 });
455
456 CallCountingCanvas canvas;
457 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
458 rasterizeCanvasBuffer(buffer, &canvas);
459 EXPECT_EQ(1, canvas.drawOvalCount);
460 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
461}
462
Nader Jawadfb1e7f12020-11-06 22:49:42 -0800463TEST(CanvasOp, simpleDrawVertices) {
464 CanvasOpBuffer buffer;
465 EXPECT_EQ(buffer.size(), 0);
466
467 SkPoint pts[3] = {{64, 32}, {0, 224}, {128, 224}};
468 SkColor colors[3] = {SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN};
469 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, 3, pts,
470 nullptr, colors);
471 buffer.push(CanvasOp<Op::DrawVertices> {
472 .vertices = vertices,
473 .mode = SkBlendMode::kSrcOver,
474 .paint = SkPaint{}
475 });
476
477 CallCountingCanvas canvas;
478 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
479 rasterizeCanvasBuffer(buffer, &canvas);
480 EXPECT_EQ(1, canvas.drawVerticesCount);
481 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
482}
483
John Reck013127b2020-10-29 20:53:51 -0400484TEST(CanvasOp, immediateRendering) {
485 auto canvas = std::make_shared<CallCountingCanvas>();
486
487 EXPECT_EQ(0, canvas->sumTotalDrawCalls());
488 ImmediateModeRasterizer rasterizer{canvas};
489 auto op = CanvasOp<Op::DrawRect> {
490 .paint = SkPaint{},
491 .rect = SkRect::MakeEmpty()
492 };
493 EXPECT_TRUE(CanvasOpTraits::can_draw<decltype(op)>);
494 rasterizer.draw(op);
495 EXPECT_EQ(1, canvas->drawRectCount);
496 EXPECT_EQ(1, canvas->sumTotalDrawCalls());
497}